rtl.def: Add unordered fp comparisions.

* rtl.def: Add unordered fp comparisions.
        * tree.def: Likewise.
	* tree.h: Add ISO C 9x unordered fp comparision builtins.

	* builtins.c (expand_tree_builtin): New function.
	* c-typeck.c (build_function_call): Use it.
	(build_binary_op): Support unordered compares.
	* c-common.c (c_common_nodes_and_builtins): Add unordered compares.

	* combine.c (known_cond): Handle reverse_condition returning UNKNOWN.
	(reversible_comparison_p): Allow UNORDERED/ORDERED to be reversed.
	* cse.c (fold_rtx): Check FLOAT_MODE_P before reversing.
	(record_jump_equiv): Handle reverse_condition returning UNKNOWN.
	* jump.c (reverse_condition): Don't abort for UNLE etc, but
	return UNKNOWN.
	(swap_condition): Handle unordered compares.
	(thread_jumps): Check can_reverse before reversing.
	* loop.c (get_condition): Likewise.  Allow UNORERED/ORDERED to be
	reversed for FP.

	* optabs.c (can_compare_p): New argument CODE.  Verify branch or
	setcc is present before acking for cmp_optab.  Update all callers.
	(prepare_float_lib_cmp, init_optabs): Handle UNORDERED.
	* expmed.c (do_cmp_and_jump): Update for can_compare_p.
	* expr.c (expand_expr): Likewise.  Support unordered compares.
	(do_jump, do_store_flag): Likewise.
	* expr.h (enum libfunc_index): Add unordered compares.

	* Makefile.in (FPBIT_FUNCS): Add _unord_sf.
	(DPBIT_FUNCS): Add _unord_df.
	* config/fp-bit.c (_unord_f2): New.
	* fp-test.c (main): Try unordered compare builtins.

	* alpha-protos.h (alpha_fp_comparison_operator): Declare.
	* alpha.c (alpha_comparison_operator): Check mode properly.
	(alpha_swapped_comparison_operator): Likewise.
	(signed_comparison_operator): Likewise.
	(alpha_fp_comparison_operator): New.
	(alpha_emit_conditional_branch): Handle unordered compares.
	* alpha.h (PREDICATE_CODES): Update.
	* alpha.md (fp compares): Use alpha_fp_comparison_operator.
	(bunordered, bordered): New.

	* cp/call.c (build_over_call): Use expand_tree_builtin.
	* cp/typeck.c (build_function_call_real): Likewise.
	(build_binary_op_nodefault): Handle unordered compares.

	* gcc.c-torture/execute/ieee/fp-cmp-4.c: New.

From-SVN: r31591
This commit is contained in:
Richard Henderson 2000-01-24 12:10:04 -08:00
parent d6cde8451a
commit 1eb8759b1b
27 changed files with 800 additions and 193 deletions

View File

@ -1,3 +1,48 @@
2000-01-24 Richard Henderson <rth@cygnus.com>
* rtl.def: Add unordered fp comparisions.
* tree.def: Likewise.
* tree.h: Add ISO C 9x unordered fp comparision builtins.
* builtins.c (expand_tree_builtin): New function.
* c-typeck.c (build_function_call): Use it.
(build_binary_op): Support unordered compares.
* c-common.c (c_common_nodes_and_builtins): Add unordered compares.
* combine.c (known_cond): Handle reverse_condition returning UNKNOWN.
(reversible_comparison_p): Allow UNORDERED/ORDERED to be reversed.
* cse.c (fold_rtx): Check FLOAT_MODE_P before reversing.
(record_jump_equiv): Handle reverse_condition returning UNKNOWN.
* jump.c (reverse_condition): Don't abort for UNLE etc, but
return UNKNOWN.
(swap_condition): Handle unordered compares.
(thread_jumps): Check can_reverse before reversing.
* loop.c (get_condition): Likewise. Allow UNORERED/ORDERED to be
reversed for FP.
* optabs.c (can_compare_p): New argument CODE. Verify branch or
setcc is present before acking for cmp_optab. Update all callers.
(prepare_float_lib_cmp, init_optabs): Handle UNORDERED.
* expmed.c (do_cmp_and_jump): Update for can_compare_p.
* expr.c (expand_expr): Likewise. Support unordered compares.
(do_jump, do_store_flag): Likewise.
* expr.h (enum libfunc_index): Add unordered compares.
* Makefile.in (FPBIT_FUNCS): Add _unord_sf.
(DPBIT_FUNCS): Add _unord_df.
* config/fp-bit.c (_unord_f2): New.
* fp-test.c (main): Try unordered compare builtins.
* alpha-protos.h (alpha_fp_comparison_operator): Declare.
* alpha.c (alpha_comparison_operator): Check mode properly.
(alpha_swapped_comparison_operator): Likewise.
(signed_comparison_operator): Likewise.
(alpha_fp_comparison_operator): New.
(alpha_emit_conditional_branch): Handle unordered compares.
* alpha.h (PREDICATE_CODES): Update.
* alpha.md (fp compares): Use alpha_fp_comparison_operator.
(bunordered, bordered): New.
2000-01-24 Richard Henderson <rth@cygnus.com>
* alpha.c (alpha_emit_xfloating_cvt): Thinko in operand manipulation.
@ -139,8 +184,8 @@ Mon Jan 24 16:50:08 MET 2000 Jan Hubicka <jh@suse.cz>
2000-01-22 Alan Modra <alan@SPRI.Levels.UniSA.Edu.Au>
* config/elfos.h (UNIQUE_SECTION): Restore uninitialised data
section naming to that prior to 2000-01-07 patch.
* config/elfos.h (UNIQUE_SECTION): Restore uninitialised data
section naming to that prior to 2000-01-07 patch.
* config/mips/elf.h (UNIQUE_SECTION): Ditto.
* config/mips/elf64.h (UNIQUE_SECTION): Ditto.
* config/mips/iris6gld.h (UNIQUE_SECTION): Ditto.
@ -188,18 +233,18 @@ Mon Jan 24 16:50:08 MET 2000 Jan Hubicka <jh@suse.cz>
2000-01-20 Zack Weinberg <zack@wolery.cumb.org>
* Makefile.in (fixinc.sh): Depend on specs.
* fixinc/Makefile.in: Add rule to create machname.h.
(fixlib.o): Depend on machname.h.
* fixinc/fixtests.c (machine_name): New test.
* fixinc/fixfixes.c (machine_name): New fix.
* fixinc/fixlib.c (mn_get_regexps): New helper function for
the machine_name test and fix.
* fixinc/fixlib.h: Prototype it.
* fixinc/inclhack.def (machine_name): Use the C test and fix.
* fixinc/Makefile.in: Add rule to create machname.h.
(fixlib.o): Depend on machname.h.
* fixinc/fixtests.c (machine_name): New test.
* fixinc/fixfixes.c (machine_name): New fix.
* fixinc/fixlib.c (mn_get_regexps): New helper function for
the machine_name test and fix.
* fixinc/fixlib.h: Prototype it.
* fixinc/inclhack.def (machine_name): Use the C test and fix.
* fixinc/fixincl.x, fixinc/inclhack.sh: Rebuild.
* gcc.c (do_spec_1) [case P]: Take care not to create
identifiers with three leading or trailing underscores.
* gcc.c (do_spec_1) [case P]: Take care not to create
identifiers with three leading or trailing underscores.
* fixinc/Makefile.in (FIXINC_DEFS): Add -DIN_GCC.
(fixincl): Don't specify libraries twice on link line.
@ -851,8 +896,8 @@ Sat Jan 15 15:41:14 EST 2000 John Wehle (john@feith.com)
2000-01-14 Clinton Popetz <cpopetz@cygnus.com>
* config/mips/mips.h (REGISTER_MOVE_COST): Remove redundant
case for moving from HI/LO/HI_LO_REG. This makes the behavior
match the comment for MIPS16.
case for moving from HI/LO/HI_LO_REG. This makes the behavior
match the comment for MIPS16.
Fri Jan 14 00:28:06 2000 Jeffrey A Law (law@cygnus.com)
@ -878,7 +923,7 @@ Thu Jan 13 23:44:03 2000 Richard Henderson <rth@cygnus.com>
Use emit_jump_insn for the return insn.
Thu Jan 13 14:46:03 2000 Jason Eckhardt <jle@cygnus.com>
Stan Cox <scox@cygnus.com>
Stan Cox <scox@cygnus.com>
* predict.c: New file. Preliminary infrastructure work for static
branch prediction and basic block reordering.
@ -1278,21 +1323,21 @@ Tue Jan 11 18:59:35 MET 2000 Jan Hubicka <jh@suse.cz>
2000-01-11 Clinton Popetz <cpopetz@cygnus.com>
* config/mips/mips.c (mips_va_arg): For EABI, emit the queued
integer vararg POSTINCREMENT before the destination of the jump
for the hard fp case.
(function_arg_pass_by_reference): Pass a copy of CUM to
* config/mips/mips.c (mips_va_arg): For EABI, emit the queued
integer vararg POSTINCREMENT before the destination of the jump
for the hard fp case.
(function_arg_pass_by_reference): Pass a copy of CUM to
FUNCTION_ARG.
* config/mips/mips.h (GO_IF_LEGITIMATE_ADDRESS): Move check
for CONSTANT_ADDRESS_P above while loop for subreg.
* config/mips/mips.h (GO_IF_LEGITIMATE_ADDRESS): Move check
for CONSTANT_ADDRESS_P above while loop for subreg.
2000-01-11 Clinton Popetz <cpopetz@cygnus.com>
* flow.c (propagate_block): When a prologue/epilogue insn
is marked dead, unconditionally clear libcall_is_dead and
insn_is_dead, and only dump rtl if warnings aren't being
suppressed.
is marked dead, unconditionally clear libcall_is_dead and
insn_is_dead, and only dump rtl if warnings aren't being
suppressed.
Tue Jan 11 16:26:47 MET 2000 Jan Hubicka <jh@suse.cz>
@ -1660,11 +1705,11 @@ Thu Jan 6 13:44:59 CET 2000 Jan Hubicka <jh@suse.cz>
* configure.in (m68*-*-rtemscoff*): New target, formal name for
old m68*-*-rtems*.
(m68*-*-rtemself*): New target.
(m68*-*-rtemself*): New target.
(mips64orion-*-rtems*): Remove duplicate definition of tm_file.
(sparc*-*-rtemsaout*): New target, formal name for old sparc*-*-rtems*.
(sparc*-*-rtemself*): New target.
(sparc*-*-rtems*): Now elf not a.out.
(sparc*-*-rtemself*): New target.
(sparc*-*-rtems*): Now elf not a.out.
* config/i386/rtems.h: Include config/rtems.h.
* config/i386/rtemself.h: Include config/rtems.h.
* config/i960/rtems.h: Include config/rtems.h.
@ -1956,7 +2001,7 @@ Fri Dec 31 19:10:31 1999 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
1999-12-30 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl>
* genrecog.c (change_state) Corrected typo.
* genrecog.c (change_state) Corrected typo.
1999-12-30 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>

View File

@ -730,12 +730,12 @@ LIB2FUNCS_EH = _eh
FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
_fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
_lt_sf _le_sf _si_to_sf _sf_to_si _negate_sf _make_sf \
_lt_sf _le_sf _unord_sf _si_to_sf _sf_to_si _negate_sf _make_sf \
_sf_to_df _thenan_sf _sf_to_usi _df_to_usi
DPBIT_FUNCS = _pack_df _unpack_df _addsub_df _mul_df _div_df \
_fpcmp_parts_df _compare_df _eq_df _ne_df _gt_df _ge_df \
_lt_df _le_df _si_to_df _df_to_si _negate_df _make_df \
_lt_df _le_df _unord_df _si_to_df _df_to_si _negate_df _make_df \
_df_to_sf _thenan_df _sf_to_usi _df_to_usi
# The files that "belong" in CONFIG_H are deliberately omitted

View File

@ -2520,3 +2520,100 @@ expand_builtin (exp, target, subtarget, mode, ignore)
to be called normally. */
return expand_call (exp, target, ignore);
}
/* Recognize certain built-in functions so we can make tree-codes
other than CALL_EXPR. We do this when it enables fold-const.c
to do something useful. */
tree
expand_tree_builtin (function, params, coerced_params)
tree function, params, coerced_params;
{
enum tree_code code;
if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
return NULL_TREE;
switch (DECL_FUNCTION_CODE (function))
{
case BUILT_IN_ABS:
case BUILT_IN_LABS:
case BUILT_IN_FABS:
if (coerced_params == 0)
return integer_zero_node;
return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
case BUILT_IN_ISGREATER:
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
code = UNLE_EXPR;
else
code = LE_EXPR;
goto unordered_cmp;
case BUILT_IN_ISGREATEREQUAL:
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
code = UNLT_EXPR;
else
code = LT_EXPR;
goto unordered_cmp;
case BUILT_IN_ISLESS:
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
code = UNGE_EXPR;
else
code = GE_EXPR;
goto unordered_cmp;
case BUILT_IN_ISLESSEQUAL:
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
code = UNGT_EXPR;
else
code = GT_EXPR;
goto unordered_cmp;
case BUILT_IN_ISLESSGREATER:
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
code = UNEQ_EXPR;
else
code = EQ_EXPR;
goto unordered_cmp;
case BUILT_IN_ISUNORDERED:
if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
return integer_zero_node;
code = UNORDERED_EXPR;
goto unordered_cmp;
unordered_cmp:
{
tree arg0, arg1;
if (params == 0
|| TREE_CHAIN (params) == 0)
{
error ("too few arguments to function `%s'",
IDENTIFIER_POINTER (DECL_NAME (function)));
return error_mark_node;
}
else if (TREE_CHAIN (TREE_CHAIN (params)) != 0)
{
error ("too many arguments to function `%s'",
IDENTIFIER_POINTER (DECL_NAME (function)));
return error_mark_node;
}
arg0 = TREE_VALUE (params);
arg1 = TREE_VALUE (TREE_CHAIN (params));
arg0 = build_binary_op (code, arg0, arg1, 0);
if (code != UNORDERED_EXPR)
arg0 = build_unary_op (TRUTH_NOT_EXPR, arg0, 0);
return arg0;
}
break;
default:
break;
}
return NULL_TREE;
}

View File

@ -3710,6 +3710,20 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins)
builtin_function ("__builtin_trap", void_ftype, BUILT_IN_TRAP,
BUILT_IN_NORMAL, NULL_PTR);
/* ISO C99 IEEE Unordered compares. */
builtin_function ("__builtin_isgreater", default_function_type,
BUILT_IN_ISGREATER, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("__builtin_isgreaterequal", default_function_type,
BUILT_IN_ISGREATEREQUAL, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("__builtin_isless", default_function_type,
BUILT_IN_ISLESS, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("__builtin_islessequal", default_function_type,
BUILT_IN_ISLESSEQUAL, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("__builtin_islessgreater", default_function_type,
BUILT_IN_ISLESSGREATER, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("__builtin_isunordered", default_function_type,
BUILT_IN_ISUNORDERED, BUILT_IN_NORMAL, NULL_PTR);
/* Untyped call and return. */
builtin_function ("__builtin_apply_args", ptr_ftype,
BUILT_IN_APPLY_ARGS, BUILT_IN_NORMAL, NULL_PTR);

View File

@ -1405,7 +1405,7 @@ build_function_call (function, params)
{
register tree fntype, fundecl = 0;
register tree coerced_params;
tree name = NULL_TREE, assembler_name = NULL_TREE;
tree name = NULL_TREE, assembler_name = NULL_TREE, result;
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (function);
@ -1460,30 +1460,21 @@ build_function_call (function, params)
if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (function, 0))
&& DECL_BUILT_IN_CLASS (TREE_OPERAND (function, 0)) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))
{
case BUILT_IN_ABS:
case BUILT_IN_LABS:
case BUILT_IN_FABS:
if (coerced_params == 0)
return integer_zero_node;
return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
default:
break;
}
&& DECL_BUILT_IN (TREE_OPERAND (function, 0)))
{
result = expand_tree_builtin (TREE_OPERAND (function, 0),
params, coerced_params);
if (result)
return result;
}
{
register tree result
= build (CALL_EXPR, TREE_TYPE (fntype),
function, coerced_params, NULL_TREE);
result = build (CALL_EXPR, TREE_TYPE (fntype),
function, coerced_params, NULL_TREE);
TREE_SIDE_EFFECTS (result) = 1;
if (TREE_TYPE (result) == void_type_node)
return result;
return require_complete_type (result);
}
TREE_SIDE_EFFECTS (result) = 1;
if (TREE_TYPE (result) == void_type_node)
return result;
return require_complete_type (result);
}
/* Convert the argument expressions in the list VALUES
@ -2233,7 +2224,24 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
pedwarn ("comparison between pointer and integer");
}
break;
case UNORDERED_EXPR:
case ORDERED_EXPR:
case UNLT_EXPR:
case UNLE_EXPR:
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
case UNNE_EXPR:
build_type = integer_type_node;
if (code0 != REAL_TYPE || code1 != REAL_TYPE)
{
error ("unordered comparison on non-floating point argument");
return error_mark_node;
}
common = 1;
break;
default:
break;
}

View File

@ -7313,11 +7313,17 @@ known_cond (x, cond, reg, val)
if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val))
{
if (GET_RTX_CLASS (code) == '<')
return (comparison_dominates_p (cond, code) ? const_true_rtx
: (comparison_dominates_p (cond,
reverse_condition (code))
? const0_rtx : x));
{
if (comparison_dominates_p (cond, code))
return const_true_rtx;
code = reverse_condition (code);
if (code != UNKNOWN
&& comparison_dominates_p (cond, code))
return const0_rtx;
else
return x;
}
else if (code == SMAX || code == SMIN
|| code == UMIN || code == UMAX)
{
@ -10852,7 +10858,8 @@ reversible_comparison_p (x)
{
if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| flag_fast_math
|| GET_CODE (x) == NE || GET_CODE (x) == EQ)
|| GET_CODE (x) == NE || GET_CODE (x) == EQ
|| GET_CODE (x) == UNORDERED || GET_CODE (x) == ORDERED)
return 1;
switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))))

View File

@ -58,6 +58,7 @@ extern int call_operand PARAMS ((rtx, enum machine_mode));
extern int alpha_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int alpha_swapped_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int signed_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int alpha_fp_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int divmod_operator PARAMS ((rtx, enum machine_mode));
extern int aligned_memory_operand PARAMS ((rtx, enum machine_mode));
extern int unaligned_memory_operand PARAMS ((rtx, enum machine_mode));

View File

@ -706,7 +706,7 @@ alpha_comparison_operator (op, mode)
{
enum rtx_code code = GET_CODE (op);
if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<')
if (mode != GET_MODE (op) && mode != VOIDmode)
return 0;
return (code == EQ || code == LE || code == LT
@ -722,7 +722,8 @@ alpha_swapped_comparison_operator (op, mode)
{
enum rtx_code code = GET_CODE (op);
if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<')
if ((mode != GET_MODE (op) && mode != VOIDmode)
|| GET_RTX_CLASS (code) != '<')
return 0;
code = swap_condition (code);
@ -737,16 +738,30 @@ signed_comparison_operator (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case EQ: case NE: case LE: case LT: case GE: case GT:
return 1;
enum rtx_code code = GET_CODE (op);
default:
break;
}
if (mode != GET_MODE (op) && mode != VOIDmode)
return 0;
return 0;
return (code == EQ || code == NE
|| code == LE || code == LT
|| code == GE || code == GT);
}
/* Return 1 if OP is a valid Alpha floating point comparison operator.
Here we know which comparisons are valid in which insn. */
int
alpha_fp_comparison_operator (op, mode)
register rtx op;
enum machine_mode mode;
{
enum rtx_code code = GET_CODE (op);
if (mode != GET_MODE (op) && mode != VOIDmode)
return 0;
return (code == EQ || code == LE || code == LT || code == UNORDERED);
}
/* Return 1 if this is a divide or modulus operator. */
@ -1484,13 +1499,15 @@ alpha_emit_conditional_branch (code)
switch (code)
{
case EQ: case LE: case LT: case LEU: case LTU:
case UNORDERED:
/* We have these compares: */
cmp_code = code, branch_code = NE;
break;
case NE:
/* This must be reversed. */
cmp_code = EQ, branch_code = EQ;
case ORDERED:
/* These must be reversed. */
cmp_code = reverse_condition (code), branch_code = EQ;
break;
case GE: case GT: case GEU: case GTU:
@ -3383,6 +3400,8 @@ print_operand (file, x, code)
fprintf (file, "ule");
else if (c == LTU)
fprintf (file, "ult");
else if (c == UNORDERED)
fprintf (file, "un");
else
fprintf (file, "%s", GET_RTX_NAME (c));
}

View File

@ -2311,6 +2311,7 @@ do { \
{"alpha_comparison_operator", {EQ, LE, LT, LEU, LTU}}, \
{"alpha_swapped_comparison_operator", {EQ, GE, GT, GEU, GTU}}, \
{"signed_comparison_operator", {EQ, NE, LE, LT, GE, GT}}, \
{"alpha_fp_comparison_operator", {EQ, LE, LT, UNORDERED}}, \
{"divmod_operator", {DIV, MOD, UDIV, UMOD}}, \
{"fp0_operand", {CONST_DOUBLE}}, \
{"current_file_function_operand", {SYMBOL_REF}}, \

View File

@ -2752,12 +2752,12 @@
"")
;; The following are the corresponding floating-point insns. Recall
;; we need to have variants that expand the arguments from SF mode
;; we need to have variants that expand the arguments from SFmode
;; to DFmode.
(define_insn ""
(define_insn "*cmpdf_tp"
[(set (match_operand:DF 0 "register_operand" "=&f")
(match_operator:DF 1 "alpha_comparison_operator"
(match_operator:DF 1 "alpha_fp_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
"TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
@ -2765,9 +2765,9 @@
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
(define_insn ""
(define_insn "*cmpdf_no_tp"
[(set (match_operand:DF 0 "register_operand" "=f")
(match_operator:DF 1 "alpha_comparison_operator"
(match_operator:DF 1 "alpha_fp_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
"TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
@ -2777,7 +2777,7 @@
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=&f")
(match_operator:DF 1 "alpha_comparison_operator"
(match_operator:DF 1 "alpha_fp_comparison_operator"
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
@ -2788,7 +2788,7 @@
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(match_operator:DF 1 "alpha_comparison_operator"
(match_operator:DF 1 "alpha_fp_comparison_operator"
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
@ -2799,7 +2799,7 @@
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=&f")
(match_operator:DF 1 "alpha_comparison_operator"
(match_operator:DF 1 "alpha_fp_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
@ -2810,7 +2810,7 @@
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(match_operator:DF 1 "alpha_comparison_operator"
(match_operator:DF 1 "alpha_fp_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
@ -2821,7 +2821,7 @@
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=&f")
(match_operator:DF 1 "alpha_comparison_operator"
(match_operator:DF 1 "alpha_fp_comparison_operator"
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(float_extend:DF
@ -2833,7 +2833,7 @@
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(match_operator:DF 1 "alpha_comparison_operator"
(match_operator:DF 1 "alpha_fp_comparison_operator"
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(float_extend:DF
@ -3126,6 +3126,22 @@
""
"{ operands[1] = alpha_emit_conditional_branch (GEU); }")
(define_expand "bunordered"
[(set (pc)
(if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"{ operands[1] = alpha_emit_conditional_branch (UNORDERED); }")
(define_expand "bordered"
[(set (pc)
(if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"{ operands[1] = alpha_emit_conditional_branch (ORDERED); }")
(define_expand "seq"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]

View File

@ -1,7 +1,7 @@
/* This is a software floating point library which can be used instead of
the floating point routines in libgcc1.c for targets without hardware
floating point.
Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Copyright (C) 1994-1998, 2000 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@ -78,6 +78,8 @@ Boston, MA 02111-1307, USA. */
#define L_lt_df
#define L_le_sf
#define L_le_df
#define L_unord_sf
#define L_unord_df
#define L_si_to_sf
#define L_si_to_df
#define L_sf_to_si
@ -268,6 +270,7 @@ typedef unsigned int UDItype __attribute__ ((mode (DI)));
# define _ge_f2 __gesf2
# define _lt_f2 __ltsf2
# define _le_f2 __lesf2
# define _unord_f2 __unordsf2
# define si_to_float __floatsisf
# define float_to_si __fixsfsi
# define float_to_usi __fixunssfsi
@ -285,6 +288,7 @@ typedef unsigned int UDItype __attribute__ ((mode (DI)));
# define _ge_f2 __gedf2
# define _lt_f2 __ltdf2
# define _le_f2 __ledf2
# define _unord_f2 __unorddf2
# define si_to_float __floatsidf
# define float_to_si __fixdfsi
# define float_to_usi __fixunsdfsi
@ -1370,6 +1374,24 @@ _le_f2 (FLO_type arg_a, FLO_type arg_b)
}
#endif
#if defined(L_unord_sf) || defined(L_unord_df)
CMPtype
_unord_f2 (FLO_type arg_a, FLO_type arg_b)
{
fp_number_type a;
fp_number_type b;
FLO_union_type au, bu;
au.value = arg_a;
bu.value = arg_b;
unpack_d (&au, &a);
unpack_d (&bu, &b);
return (isnan (&a) || isnan (&b);
}
#endif
#endif /* ! US_SOFTWARE_GOFAST */
#if defined(L_si_to_sf) || defined(L_si_to_df)

View File

@ -1,3 +1,9 @@
2000-01-24 Richard Henderson <rth@cygnus.com>
* call.c (build_over_call): Use expand_tree_builtin.
* typeck.c (build_function_call_real): Likewise.
(build_binary_op_nodefault): Handle unordered compares.
2000-01-24 Nathan Sidwell <sidwell@codesourcery.com>
* cp-tree.h (CPTI_BAD_CAST, CPTI_BAD_TYPEID, CPTI_DCAST): New
@ -111,10 +117,10 @@
2000-01-19 Gabriel Dos Reis <gdr@codesourcery.coom>
* typeck.c (build_unary_op): Use cp_pedwarn, not pedwarn.
* typeck.c (build_unary_op): Use cp_pedwarn, not pedwarn.
* typeck2.c (incomplete_type_error): Restore previous
cp_error and cp_error_at call sequence.
* typeck2.c (incomplete_type_error): Restore previous
cp_error and cp_error_at call sequence.
2000-01-20 Brad Lucier <lucier@math.purdue.edu>

View File

@ -4145,19 +4145,13 @@ build_over_call (cand, args, flags)
if (TREE_CODE (fn) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (fn, 0))
&& DECL_BUILT_IN_CLASS (TREE_OPERAND (fn, 0)) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (TREE_OPERAND (fn, 0)))
{
case BUILT_IN_ABS:
case BUILT_IN_LABS:
case BUILT_IN_FABS:
if (converted_args == 0)
return integer_zero_node;
return build_unary_op (ABS_EXPR, TREE_VALUE (converted_args), 0);
default:
break;
}
&& DECL_BUILT_IN (TREE_OPERAND (fn, 0)))
{
tree exp;
exp = expand_tree_builtin (TREE_OPERAND (fn, 0), args, converted_args);
if (exp)
return exp;
}
fn = build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args);
if (TREE_CODE (TREE_TYPE (fn)) == VOID_TYPE)

View File

@ -2926,6 +2926,7 @@ build_function_call_real (function, params, require_complete, flags)
register tree fntype, fndecl;
register tree value_type;
register tree coerced_params;
tree result;
tree name = NULL_TREE, assembler_name = NULL_TREE;
int is_method;
@ -3023,37 +3024,27 @@ build_function_call_real (function, params, require_complete, flags)
if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (function, 0))
&& DECL_BUILT_IN_CLASS (TREE_OPERAND (function, 0)) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))
{
case BUILT_IN_ABS:
case BUILT_IN_LABS:
case BUILT_IN_FABS:
if (coerced_params == 0)
return integer_zero_node;
return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
default:
break;
}
&& DECL_BUILT_IN (TREE_OPERAND (function, 0)))
{
result = expand_tree_builtin (TREE_OPERAND (function, 0),
params, coerced_params);
if (result)
return result;
}
/* C++ */
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
{
register tree result
= build_call (function, value_type, coerced_params);
result = build_call (function, value_type, coerced_params);
if (require_complete)
{
if (TREE_CODE (value_type) == VOID_TYPE)
return result;
result = require_complete_type (result);
}
if (IS_AGGR_TYPE (value_type))
result = build_cplus_new (value_type, result);
return convert_from_reference (result);
}
if (require_complete)
{
if (TREE_CODE (value_type) == VOID_TYPE)
return result;
result = require_complete_type (result);
}
if (IS_AGGR_TYPE (value_type))
result = build_cplus_new (value_type, result);
return convert_from_reference (result);
}
tree
@ -3792,6 +3783,23 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
}
break;
case UNORDERED_EXPR:
case ORDERED_EXPR:
case UNLT_EXPR:
case UNLE_EXPR:
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
case UNNE_EXPR:
build_type = integer_type_node;
if (code0 != REAL_TYPE || code1 != REAL_TYPE)
{
error ("unordered comparison on non-floating point argument");
return error_mark_node;
}
common = 1;
break;
default:
break;
}

View File

@ -3718,9 +3718,9 @@ fold_rtx (x, insn)
struct qty_table_elem *ent = &qty_table[qty];
if ((comparison_dominates_p (ent->comparison_code, code)
|| (comparison_dominates_p (ent->comparison_code,
reverse_condition (code))
&& ! FLOAT_MODE_P (mode_arg0)))
|| (! FLOAT_MODE_P (mode_arg0)
&& comparison_dominates_p (ent->comparison_code,
reverse_condition (code))))
&& (rtx_equal_p (ent->comparison_const, folded_arg1)
|| (const_arg1
&& rtx_equal_p (ent->comparison_const,
@ -4156,6 +4156,10 @@ record_jump_equiv (insn, taken)
{
reversed_nonequality = (code != EQ && code != NE);
code = reverse_condition (code);
/* Don't remember if we can't find the inverse. */
if (code == UNKNOWN)
return;
}
/* The mode is the mode of the non-constant. */

View File

@ -4561,7 +4561,8 @@ do_cmp_and_jump (arg1, arg2, op, mode, label)
/* If this mode is an integer too wide to compare properly,
compare word by word. Rely on cse to optimize constant cases. */
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode, ccp_jump))
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (op, mode, ccp_jump))
{
rtx label2 = gen_label_rtx ();

View File

@ -7537,7 +7537,8 @@ expand_expr (exp, target, tmode, modifier)
/* If this mode is an integer too wide to compare properly,
compare word by word. Rely on cse to optimize constant cases. */
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode, ccp_jump))
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (GE, mode, ccp_jump))
{
if (code == MAX_EXPR)
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
@ -7618,6 +7619,14 @@ expand_expr (exp, target, tmode, modifier)
case GE_EXPR:
case EQ_EXPR:
case NE_EXPR:
case UNORDERED_EXPR:
case ORDERED_EXPR:
case UNLT_EXPR:
case UNLE_EXPR:
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
case UNNE_EXPR:
preexpand_calls (exp);
temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
if (temp != 0)
@ -9413,7 +9422,7 @@ do_jump (exp, if_false_label, if_true_label)
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
&& !can_compare_p (TYPE_MODE (inner_type), ccp_jump))
&& !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump))
do_jump_by_parts_equality (exp, if_false_label, if_true_label);
else
do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
@ -9453,7 +9462,7 @@ do_jump (exp, if_false_label, if_true_label)
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
&& !can_compare_p (TYPE_MODE (inner_type), ccp_jump))
&& !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump))
do_jump_by_parts_equality (exp, if_true_label, if_false_label);
else
do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
@ -9463,7 +9472,7 @@ do_jump (exp, if_false_label, if_true_label)
case LT_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (mode, ccp_jump))
&& ! can_compare_p (LT, mode, ccp_jump))
do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
else
do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
@ -9472,7 +9481,7 @@ do_jump (exp, if_false_label, if_true_label)
case LE_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (mode, ccp_jump))
&& ! can_compare_p (LE, mode, ccp_jump))
do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
else
do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
@ -9481,7 +9490,7 @@ do_jump (exp, if_false_label, if_true_label)
case GT_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (mode, ccp_jump))
&& ! can_compare_p (GT, mode, ccp_jump))
do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
else
do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
@ -9490,12 +9499,87 @@ do_jump (exp, if_false_label, if_true_label)
case GE_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (mode, ccp_jump))
&& ! can_compare_p (GE, mode, ccp_jump))
do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
else
do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
break;
case UNORDERED_EXPR:
case ORDERED_EXPR:
{
enum rtx_code cmp, rcmp;
int do_rev;
if (code == UNORDERED_EXPR)
cmp = UNORDERED, rcmp = ORDERED;
else
cmp = ORDERED, rcmp = UNORDERED;
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
do_rev = 0;
if (! can_compare_p (cmp, mode, ccp_jump)
&& (can_compare_p (rcmp, mode, ccp_jump)
/* If the target doesn't provide either UNORDERED or ORDERED
comparisons, canonicalize on UNORDERED for the library. */
|| rcmp == UNORDERED))
do_rev = 1;
if (! do_rev)
do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label);
else
do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label);
}
break;
{
enum rtx_code rcode1;
enum tree_code tcode2;
case UNLT_EXPR:
rcode1 = UNLT;
tcode2 = LT_EXPR;
goto unordered_bcc;
case UNLE_EXPR:
rcode1 = UNLE;
tcode2 = LE_EXPR;
goto unordered_bcc;
case UNGT_EXPR:
rcode1 = UNGT;
tcode2 = GT_EXPR;
goto unordered_bcc;
case UNGE_EXPR:
rcode1 = UNGE;
tcode2 = GE_EXPR;
goto unordered_bcc;
case UNEQ_EXPR:
rcode1 = UNEQ;
tcode2 = EQ_EXPR;
goto unordered_bcc;
case UNNE_EXPR:
rcode1 = UNNE;
tcode2 = NE_EXPR;
unordered_bcc:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (can_compare_p (rcode1, mode, ccp_jump))
do_compare_and_jump (exp, rcode1, rcode1, if_false_label,
if_true_label);
else
{
tree op0 = save_expr (TREE_OPERAND (exp, 0));
tree op1 = save_expr (TREE_OPERAND (exp, 1));
tree cmp0, cmp1;
/* If the target doesn't support combined unordered
compares, decompose into UNORDERED + comparison. */
cmp0 = fold (build (UNORDERED_EXPR, TREE_TYPE (exp), op0, op1));
cmp1 = fold (build (tcode2, TREE_TYPE (exp), op0, op1));
exp = build (TRUTH_ORIF_EXPR, TREE_TYPE (exp), cmp0, cmp1);
do_jump (exp, if_false_label, if_true_label);
}
}
break;
default:
normal:
temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
@ -9519,7 +9603,7 @@ do_jump (exp, if_false_label, if_true_label)
emit_jump (target);
}
else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
&& ! can_compare_p (GET_MODE (temp), ccp_jump))
&& ! can_compare_p (NE, GET_MODE (temp), ccp_jump))
/* Note swapping the labels gives us not-equal. */
do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
else if (GET_MODE (temp) != VOIDmode)
@ -10059,6 +10143,32 @@ do_store_flag (exp, target, mode, only_cheap)
else
code = unsignedp ? GEU : GE;
break;
case UNORDERED_EXPR:
code = UNORDERED;
break;
case ORDERED_EXPR:
code = ORDERED;
break;
case UNLT_EXPR:
code = UNLT;
break;
case UNLE_EXPR:
code = UNLE;
break;
case UNGT_EXPR:
code = UNGT;
break;
case UNGE_EXPR:
code = UNGE;
break;
case UNEQ_EXPR:
code = UNEQ;
break;
case UNNE_EXPR:
code = UNNE;
break;
default:
abort ();
}
@ -10134,8 +10244,9 @@ do_store_flag (exp, target, mode, only_cheap)
}
/* Now see if we are likely to be able to do this. Return if not. */
if (! can_compare_p (operand_mode, ccp_store_flag))
if (! can_compare_p (code, operand_mode, ccp_store_flag))
return 0;
icode = setcc_gen_code[(int) code];
if (icode == CODE_FOR_nothing
|| (only_cheap && insn_data[(int) icode].operand[0].mode != mode))

View File

@ -499,6 +499,7 @@ enum libfunc_index
LTI_gehf2,
LTI_lthf2,
LTI_lehf2,
LTI_unordhf2,
LTI_eqsf2,
LTI_nesf2,
@ -506,6 +507,7 @@ enum libfunc_index
LTI_gesf2,
LTI_ltsf2,
LTI_lesf2,
LTI_unordsf2,
LTI_eqdf2,
LTI_nedf2,
@ -513,6 +515,7 @@ enum libfunc_index
LTI_gedf2,
LTI_ltdf2,
LTI_ledf2,
LTI_unorddf2,
LTI_eqxf2,
LTI_nexf2,
@ -520,6 +523,7 @@ enum libfunc_index
LTI_gexf2,
LTI_ltxf2,
LTI_lexf2,
LTI_unordxf2,
LTI_eqtf2,
LTI_netf2,
@ -527,6 +531,7 @@ enum libfunc_index
LTI_getf2,
LTI_lttf2,
LTI_letf2,
LTI_unordtf2,
LTI_floatsisf,
LTI_floatdisf,
@ -627,6 +632,7 @@ extern rtx libfunc_table[LTI_MAX];
#define gehf2_libfunc (libfunc_table[LTI_gehf2])
#define lthf2_libfunc (libfunc_table[LTI_lthf2])
#define lehf2_libfunc (libfunc_table[LTI_lehf2])
#define unordhf2_libfunc (libfunc_table[LTI_unordhf2])
#define eqsf2_libfunc (libfunc_table[LTI_eqsf2])
#define nesf2_libfunc (libfunc_table[LTI_nesf2])
@ -634,6 +640,7 @@ extern rtx libfunc_table[LTI_MAX];
#define gesf2_libfunc (libfunc_table[LTI_gesf2])
#define ltsf2_libfunc (libfunc_table[LTI_ltsf2])
#define lesf2_libfunc (libfunc_table[LTI_lesf2])
#define unordsf2_libfunc (libfunc_table[LTI_unordsf2])
#define eqdf2_libfunc (libfunc_table[LTI_eqdf2])
#define nedf2_libfunc (libfunc_table[LTI_nedf2])
@ -641,6 +648,7 @@ extern rtx libfunc_table[LTI_MAX];
#define gedf2_libfunc (libfunc_table[LTI_gedf2])
#define ltdf2_libfunc (libfunc_table[LTI_ltdf2])
#define ledf2_libfunc (libfunc_table[LTI_ledf2])
#define unorddf2_libfunc (libfunc_table[LTI_unorddf2])
#define eqxf2_libfunc (libfunc_table[LTI_eqxf2])
#define nexf2_libfunc (libfunc_table[LTI_nexf2])
@ -648,6 +656,7 @@ extern rtx libfunc_table[LTI_MAX];
#define gexf2_libfunc (libfunc_table[LTI_gexf2])
#define ltxf2_libfunc (libfunc_table[LTI_ltxf2])
#define lexf2_libfunc (libfunc_table[LTI_lexf2])
#define unordxf2_libfunc (libfunc_table[LTI_unordxf2])
#define eqtf2_libfunc (libfunc_table[LTI_eqtf2])
#define netf2_libfunc (libfunc_table[LTI_netf2])
@ -655,6 +664,7 @@ extern rtx libfunc_table[LTI_MAX];
#define getf2_libfunc (libfunc_table[LTI_getf2])
#define lttf2_libfunc (libfunc_table[LTI_lttf2])
#define letf2_libfunc (libfunc_table[LTI_letf2])
#define unordtf2_libfunc (libfunc_table[LTI_unordtf2])
#define floatsisf_libfunc (libfunc_table[LTI_floatsisf])
#define floatdisf_libfunc (libfunc_table[LTI_floatdisf])
@ -795,9 +805,11 @@ enum can_compare_purpose
ccp_cmov,
ccp_store_flag
};
/* Nonzero if a compare of mode MODE can be done straightforwardly
(without splitting it into pieces). */
extern int can_compare_p PARAMS ((enum machine_mode, enum can_compare_purpose));
extern int can_compare_p PARAMS ((enum rtx_code, enum machine_mode,
enum can_compare_purpose));
extern void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx,
enum machine_mode *, int *, int,
@ -885,6 +897,7 @@ extern rtx gen_cond_trap PARAMS ((enum rtx_code, rtx, rtx, rtx));
/* Functions from builtins.c: */
#ifdef TREE_CODE
extern rtx expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
extern tree expand_tree_builtin PARAMS ((tree, tree, tree));
extern void std_expand_builtin_va_start PARAMS ((int, tree, rtx));
extern rtx std_expand_builtin_va_arg PARAMS ((tree, tree));
extern rtx expand_builtin_va_arg PARAMS ((tree, tree));

View File

@ -1,23 +1,23 @@
/* fp-test.c - Check that all floating-point operations are available.
Copyright (C) 1995 Free Software Foundation, Inc.
Copyright (C) 1995, 2000 Free Software Foundation, Inc.
Contributed by Ronald F. Guilmette <rfg@monkeys.com>.
This file is part of GNU CC.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* This is a trivial test program which may be useful to people who are
porting the GCC or G++ compilers to a new system. The intent here is
@ -104,6 +104,13 @@ main ()
si = f1 >= f2;
si = f1 <= f2;
si = __builtin_isgreater (f1, f2);
si = __builtin_isgreaterequal (f1, f2);
si = __builtin_isless (f1, f2);
si = __builtin_islessequal (f1, f2);
si = __builtin_islessgreater (f1, f2);
si = __builtin_isunordered (f1, f2);
sc = f1;
uc = f1;
ss = f1;
@ -143,6 +150,13 @@ main ()
si = d1 >= d2;
si = d1 <= d2;
si = __builtin_isgreater (d1, d2);
si = __builtin_isgreaterequal (d1, d2);
si = __builtin_isless (d1, d2);
si = __builtin_islessequal (d1, d2);
si = __builtin_islessgreater (d1, d2);
si = __builtin_isunordered (d1, d2);
sc = d1;
uc = d1;
ss = d1;
@ -182,6 +196,13 @@ main ()
si = D1 >= D2;
si = D1 <= D2;
si = __builtin_isgreater (D1, D2);
si = __builtin_isgreaterequal (D1, D2);
si = __builtin_isless (D1, D2);
si = __builtin_islessequal (D1, D2);
si = __builtin_islessgreater (D1, D2);
si = __builtin_isunordered (D1, D2);
sc = D1;
uc = D1;
ss = D1;

View File

@ -3429,11 +3429,12 @@ can_reverse_comparison_p (comparison, insn)
&& GET_MODE_CLASS (GET_MODE (arg0)) != MODE_FLOAT));
}
/* Given an rtx-code for a comparison, return the code
for the negated comparison.
WATCH OUT! reverse_condition is not safe to use on a jump
that might be acting on the results of an IEEE floating point comparison,
because of the special treatment of non-signaling nans in comparisons.
/* Given an rtx-code for a comparison, return the code for the negated
comparison. If no such code exists, return UNKNOWN.
WATCH OUT! reverse_condition is not safe to use on a jump that might
be acting on the results of an IEEE floating point comparison, because
of the special treatment of non-signaling nans in comparisons.
Use can_reverse_comparison_p to be sure. */
enum rtx_code
@ -3444,37 +3445,39 @@ reverse_condition (code)
{
case EQ:
return NE;
case NE:
return EQ;
case GT:
return LE;
case GE:
return LT;
case LT:
return GE;
case LE:
return GT;
case GTU:
return LEU;
case GEU:
return LTU;
case LTU:
return GEU;
case LEU:
return GTU;
case UNORDERED:
return ORDERED;
case ORDERED:
return UNORDERED;
case UNLT:
case UNLE:
case UNGT:
case UNGE:
case UNEQ:
case UNNE:
return UNKNOWN;
default:
abort ();
return UNKNOWN;
}
}
@ -3489,35 +3492,40 @@ swap_condition (code)
{
case EQ:
case NE:
case UNORDERED:
case ORDERED:
case UNEQ:
case UNNE:
return code;
case GT:
return LT;
case GE:
return LE;
case LT:
return GT;
case LE:
return GE;
case GTU:
return LTU;
case GEU:
return LEU;
case LTU:
return GTU;
case LEU:
return GEU;
case UNLT:
return UNGT;
case UNLE:
return UNGE;
case UNGT:
return UNLT;
case UNGE:
return UNLE;
default:
abort ();
return UNKNOWN;
}
}
@ -5272,10 +5280,11 @@ thread_jumps (f, max_reg, flag_before_loop)
if (rtx_equal_for_thread_p (b1op0, b2op0, b2)
&& rtx_equal_for_thread_p (b1op1, b2op1, b2)
&& (comparison_dominates_p (code1, code2)
|| (comparison_dominates_p (code1, reverse_condition (code2))
&& can_reverse_comparison_p (XEXP (SET_SRC (PATTERN (b1)),
0),
b1))))
|| (can_reverse_comparison_p (XEXP (SET_SRC (PATTERN (b1)),
0),
b1)
&& comparison_dominates_p (code1, reverse_condition (code2)))))
{
t1 = prev_nonnote_insn (b1);
t2 = prev_nonnote_insn (b2);

View File

@ -9163,6 +9163,8 @@ get_condition (jump, earliest)
if (reverse_code)
{
code = reverse_condition (code);
if (code == UNKNOWN)
return 0;
did_reverse_condition ^= 1;
reverse_code = 0;
}
@ -9227,9 +9229,10 @@ get_condition (jump, earliest)
}
/* If this was floating-point and we reversed anything other than an
EQ or NE, return zero. */
EQ or NE or (UN)ORDERED, return zero. */
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
&& did_reverse_condition && code != NE && code != EQ
&& did_reverse_condition
&& code != NE && code != EQ && code != UNORDERED && code != ORDERED
&& ! flag_fast_math
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
return 0;

View File

@ -2325,7 +2325,8 @@ expand_abs (mode, op0, target, safe)
/* If this mode is an integer too wide to compare properly,
compare word by word. Rely on CSE to optimize constant cases. */
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode, ccp_jump))
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (GE, mode, ccp_jump))
do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
NULL_RTX, op1);
else
@ -2840,18 +2841,31 @@ emit_0_to_1_insn (x)
}
/* Nonzero if we can perform a comparison of mode MODE straightforwardly.
If FOR_JUMP is nonzero, we will be generating a jump based on this
comparison, otherwise a store-flags operation. */
PURPOSE describes how this comparison will be used. CODE is the rtx
comparison code we will be using.
??? Actually, CODE is slightly weaker than that. A target is still
required to implement all of the normal bcc operations, but not
required to implement all (or any) of the unordered bcc operations. */
int
can_compare_p (mode, purpose)
can_compare_p (code, mode, purpose)
enum rtx_code code;
enum machine_mode mode;
enum can_compare_purpose purpose;
{
do
{
if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
return 1;
{
if (purpose == ccp_jump)
return bcc_gen_fctn[(int)code] != NULL;
else if (purpose == ccp_store_flag)
return setcc_gen_code[(int)code] != CODE_FOR_nothing;
else
/* There's only one cmov entry point, and it's allowed to fail. */
return 1;
}
if (purpose == ccp_jump
&& cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
return 1;
@ -3016,7 +3030,7 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align,
*px = x;
*py = y;
if (can_compare_p (mode, purpose))
if (can_compare_p (*pcomparison, mode, purpose))
return;
/* Handle a lib call just for the mode we are using. */
@ -3267,6 +3281,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = lehf2_libfunc;
break;
case UNORDERED:
libfunc = unordhf2_libfunc;
break;
default:
break;
}
@ -3297,6 +3315,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = lesf2_libfunc;
break;
case UNORDERED:
libfunc = unordsf2_libfunc;
break;
default:
break;
}
@ -3327,6 +3349,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = ledf2_libfunc;
break;
case UNORDERED:
libfunc = unorddf2_libfunc;
break;
default:
break;
}
@ -3357,6 +3383,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = lexf2_libfunc;
break;
case UNORDERED:
libfunc = unordxf2_libfunc;
break;
default:
break;
}
@ -3387,6 +3417,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = letf2_libfunc;
break;
case UNORDERED:
libfunc = unordtf2_libfunc;
break;
default:
break;
}
@ -3415,8 +3449,7 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
if (libfunc == 0)
abort ();
emit_library_call (libfunc, 1,
word_mode, 2, x, mode, y, mode);
emit_library_call (libfunc, 1, word_mode, 2, x, mode, y, mode);
/* Immediately move the result of the libcall into a pseudo
register so reload doesn't clobber the value if it needs
@ -3426,8 +3459,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
*px = result;
*py = const0_rtx;
*pmode = word_mode;
if (comparison == UNORDERED)
*pcomparison = NE;
#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL
if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
*pcomparison = NE;
#endif
*punsignedp = 0;
@ -4650,6 +4685,7 @@ init_optabs ()
gehf2_libfunc = init_one_libfunc ("__gehf2");
lthf2_libfunc = init_one_libfunc ("__lthf2");
lehf2_libfunc = init_one_libfunc ("__lehf2");
unordhf2_libfunc = init_one_libfunc ("__unordhf2");
eqsf2_libfunc = init_one_libfunc ("__eqsf2");
nesf2_libfunc = init_one_libfunc ("__nesf2");
@ -4657,6 +4693,7 @@ init_optabs ()
gesf2_libfunc = init_one_libfunc ("__gesf2");
ltsf2_libfunc = init_one_libfunc ("__ltsf2");
lesf2_libfunc = init_one_libfunc ("__lesf2");
unordsf2_libfunc = init_one_libfunc ("__unordsf2");
eqdf2_libfunc = init_one_libfunc ("__eqdf2");
nedf2_libfunc = init_one_libfunc ("__nedf2");
@ -4664,6 +4701,7 @@ init_optabs ()
gedf2_libfunc = init_one_libfunc ("__gedf2");
ltdf2_libfunc = init_one_libfunc ("__ltdf2");
ledf2_libfunc = init_one_libfunc ("__ledf2");
unorddf2_libfunc = init_one_libfunc ("__unorddf2");
eqxf2_libfunc = init_one_libfunc ("__eqxf2");
nexf2_libfunc = init_one_libfunc ("__nexf2");
@ -4671,6 +4709,7 @@ init_optabs ()
gexf2_libfunc = init_one_libfunc ("__gexf2");
ltxf2_libfunc = init_one_libfunc ("__ltxf2");
lexf2_libfunc = init_one_libfunc ("__lexf2");
unordxf2_libfunc = init_one_libfunc ("__unordxf2");
eqtf2_libfunc = init_one_libfunc ("__eqtf2");
netf2_libfunc = init_one_libfunc ("__netf2");
@ -4678,6 +4717,7 @@ init_optabs ()
getf2_libfunc = init_one_libfunc ("__getf2");
lttf2_libfunc = init_one_libfunc ("__lttf2");
letf2_libfunc = init_one_libfunc ("__letf2");
unordtf2_libfunc = init_one_libfunc ("__unordtf2");
floatsisf_libfunc = init_one_libfunc ("__floatsisf");
floatdisf_libfunc = init_one_libfunc ("__floatdisf");

View File

@ -737,6 +737,18 @@ DEF_RTL_EXPR(GTU, "gtu", "ee", '<')
DEF_RTL_EXPR(LEU, "leu", "ee", '<')
DEF_RTL_EXPR(LTU, "ltu", "ee", '<')
/* Additional floating point unordered comparision flavors. */
DEF_RTL_EXPR(UNORDERED, "unordered", "ee", '<')
DEF_RTL_EXPR(ORDERED, "ordered", "ee", '<')
/* These are equivalent to unordered or ... */
DEF_RTL_EXPR(UNNE, "unne", "ee", '<')
DEF_RTL_EXPR(UNEQ, "uneq", "ee", '<')
DEF_RTL_EXPR(UNGE, "unge", "ee", '<')
DEF_RTL_EXPR(UNGT, "ungt", "ee", '<')
DEF_RTL_EXPR(UNLE, "unle", "ee", '<')
DEF_RTL_EXPR(UNLT, "unlt", "ee", '<')
/* Represents the result of sign-extending the sole operand.
The machine modes of the operand and of the SIGN_EXTEND expression
determine how much sign-extension is going on. */

View File

@ -1,3 +1,7 @@
2000-01-24 Richard Henderson <rth@cygnus.com>
* gcc.c-torture/execute/ieee/fp-cmp-4.c: New.
Thu Jan 20 12:34:48 2000 Jeffrey A Law (law@cygnus.com)
* gcc.c-torture/execute/20000120-2.c: New test.

View File

@ -0,0 +1,131 @@
void
test_isunordered(double x, double y, int true)
{
if (__builtin_isunordered(x, y))
{
if (! true)
abort ();
}
else
{
if (true)
abort ();
}
}
void
test_isless(double x, double y, int true)
{
if (__builtin_isless(x, y))
{
if (! true)
abort ();
}
else
{
if (true)
abort ();
}
}
void
test_islessequal(double x, double y, int true)
{
if (__builtin_islessequal(x, y))
{
if (! true)
abort ();
}
else
{
if (true)
abort ();
}
}
void
test_isgreater(double x, double y, int true)
{
if (__builtin_isgreater(x, y))
{
if (! true)
abort ();
}
else
{
if (true)
abort ();
}
}
void
test_isgreaterequal(double x, double y, int true)
{
if (__builtin_isgreaterequal(x, y))
{
if (! true)
abort ();
}
else
{
if (true)
abort ();
}
}
void
test_islessgreater(double x, double y, int true)
{
if (__builtin_islessgreater(x, y))
{
if (! true)
abort ();
}
else
{
if (true)
abort ();
}
}
#define NAN (0.0 / 0.0)
int
main()
{
struct try
{
double x, y;
unsigned unord : 1;
unsigned lt : 1;
unsigned le : 1;
unsigned gt : 1;
unsigned ge : 1;
unsigned lg : 1;
};
const struct try data[] =
{
{ NAN, NAN, 1, 0, 0, 0, 0, 0 },
{ 0.0, NAN, 1, 0, 0, 0, 0, 0 },
{ NAN, 0.0, 1, 0, 0, 0, 0, 0 },
{ 0.0, 0.0, 0, 0, 1, 0, 1, 0 },
{ 1.0, 2.0, 0, 1, 1, 0, 0, 1 },
{ 2.0, 1.0, 0, 0, 0, 1, 1, 1 },
};
const int n = sizeof(data) / sizeof(data[0]);
int i;
for (i = 0; i < n; ++i)
{
test_isunordered (data[i].x, data[i].y, data[i].unord);
test_isless (data[i].x, data[i].y, data[i].lt);
test_islessequal (data[i].x, data[i].y, data[i].le);
test_isgreater (data[i].x, data[i].y, data[i].gt);
test_isgreaterequal (data[i].x, data[i].y, data[i].ge);
test_islessgreater (data[i].x, data[i].y, data[i].lg);
}
exit (0);
}

View File

@ -641,6 +641,18 @@ DEFTREECODE (GE_EXPR, "ge_expr", '<', 2)
DEFTREECODE (EQ_EXPR, "eq_expr", '<', 2)
DEFTREECODE (NE_EXPR, "ne_expr", '<', 2)
/* Additional relational operators for floating point unordered. */
DEFTREECODE (UNORDERED_EXPR, "unordered_expr", '<', 2)
DEFTREECODE (ORDERED_EXPR, "ordered_expr", '<', 2)
/* These are equivalent to unordered or ... */
DEFTREECODE (UNLT_EXPR, "unlt_expr", '<', 2)
DEFTREECODE (UNLE_EXPR, "unle_expr", '<', 2)
DEFTREECODE (UNGT_EXPR, "ungt_expr", '<', 2)
DEFTREECODE (UNGE_EXPR, "unge_expr", '<', 2)
DEFTREECODE (UNEQ_EXPR, "uneq_expr", '<', 2)
DEFTREECODE (UNNE_EXPR, "unne_expr", '<', 2)
/* Operations for Pascal sets. Not used now. */
DEFTREECODE (IN_EXPR, "in_expr", '2', 2)
DEFTREECODE (SET_LE_EXPR, "set_le_expr", '<', 2)

View File

@ -116,6 +116,14 @@ enum built_in_function
BUILT_IN_LONGJMP,
BUILT_IN_TRAP,
/* ISO C99 floating point unordered comparisons. */
BUILT_IN_ISGREATER,
BUILT_IN_ISGREATEREQUAL,
BUILT_IN_ISLESS,
BUILT_IN_ISLESSEQUAL,
BUILT_IN_ISLESSGREATER,
BUILT_IN_ISUNORDERED,
/* Various hooks for the DWARF 2 __throw routine. */
BUILT_IN_UNWIND_INIT,
BUILT_IN_DWARF_CFA,