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> 2000-01-24 Richard Henderson <rth@cygnus.com>
* alpha.c (alpha_emit_xfloating_cvt): Thinko in operand manipulation. * 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> 2000-01-22 Alan Modra <alan@SPRI.Levels.UniSA.Edu.Au>
* config/elfos.h (UNIQUE_SECTION): Restore uninitialised data * config/elfos.h (UNIQUE_SECTION): Restore uninitialised data
section naming to that prior to 2000-01-07 patch. section naming to that prior to 2000-01-07 patch.
* config/mips/elf.h (UNIQUE_SECTION): Ditto. * config/mips/elf.h (UNIQUE_SECTION): Ditto.
* config/mips/elf64.h (UNIQUE_SECTION): Ditto. * config/mips/elf64.h (UNIQUE_SECTION): Ditto.
* config/mips/iris6gld.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> 2000-01-20 Zack Weinberg <zack@wolery.cumb.org>
* Makefile.in (fixinc.sh): Depend on specs. * Makefile.in (fixinc.sh): Depend on specs.
* fixinc/Makefile.in: Add rule to create machname.h. * fixinc/Makefile.in: Add rule to create machname.h.
(fixlib.o): Depend on machname.h. (fixlib.o): Depend on machname.h.
* fixinc/fixtests.c (machine_name): New test. * fixinc/fixtests.c (machine_name): New test.
* fixinc/fixfixes.c (machine_name): New fix. * fixinc/fixfixes.c (machine_name): New fix.
* fixinc/fixlib.c (mn_get_regexps): New helper function for * fixinc/fixlib.c (mn_get_regexps): New helper function for
the machine_name test and fix. the machine_name test and fix.
* fixinc/fixlib.h: Prototype it. * fixinc/fixlib.h: Prototype it.
* fixinc/inclhack.def (machine_name): Use the C test and fix. * fixinc/inclhack.def (machine_name): Use the C test and fix.
* fixinc/fixincl.x, fixinc/inclhack.sh: Rebuild. * fixinc/fixincl.x, fixinc/inclhack.sh: Rebuild.
* gcc.c (do_spec_1) [case P]: Take care not to create * gcc.c (do_spec_1) [case P]: Take care not to create
identifiers with three leading or trailing underscores. identifiers with three leading or trailing underscores.
* fixinc/Makefile.in (FIXINC_DEFS): Add -DIN_GCC. * fixinc/Makefile.in (FIXINC_DEFS): Add -DIN_GCC.
(fixincl): Don't specify libraries twice on link line. (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> 2000-01-14 Clinton Popetz <cpopetz@cygnus.com>
* config/mips/mips.h (REGISTER_MOVE_COST): Remove redundant * config/mips/mips.h (REGISTER_MOVE_COST): Remove redundant
case for moving from HI/LO/HI_LO_REG. This makes the behavior case for moving from HI/LO/HI_LO_REG. This makes the behavior
match the comment for MIPS16. match the comment for MIPS16.
Fri Jan 14 00:28:06 2000 Jeffrey A Law (law@cygnus.com) 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. Use emit_jump_insn for the return insn.
Thu Jan 13 14:46:03 2000 Jason Eckhardt <jle@cygnus.com> 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 * predict.c: New file. Preliminary infrastructure work for static
branch prediction and basic block reordering. 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> 2000-01-11 Clinton Popetz <cpopetz@cygnus.com>
* config/mips/mips.c (mips_va_arg): For EABI, emit the queued * config/mips/mips.c (mips_va_arg): For EABI, emit the queued
integer vararg POSTINCREMENT before the destination of the jump integer vararg POSTINCREMENT before the destination of the jump
for the hard fp case. for the hard fp case.
(function_arg_pass_by_reference): Pass a copy of CUM to (function_arg_pass_by_reference): Pass a copy of CUM to
FUNCTION_ARG. FUNCTION_ARG.
* config/mips/mips.h (GO_IF_LEGITIMATE_ADDRESS): Move check * config/mips/mips.h (GO_IF_LEGITIMATE_ADDRESS): Move check
for CONSTANT_ADDRESS_P above while loop for subreg. for CONSTANT_ADDRESS_P above while loop for subreg.
2000-01-11 Clinton Popetz <cpopetz@cygnus.com> 2000-01-11 Clinton Popetz <cpopetz@cygnus.com>
* flow.c (propagate_block): When a prologue/epilogue insn * flow.c (propagate_block): When a prologue/epilogue insn
is marked dead, unconditionally clear libcall_is_dead and is marked dead, unconditionally clear libcall_is_dead and
insn_is_dead, and only dump rtl if warnings aren't being insn_is_dead, and only dump rtl if warnings aren't being
suppressed. suppressed.
Tue Jan 11 16:26:47 MET 2000 Jan Hubicka <jh@suse.cz> 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 * configure.in (m68*-*-rtemscoff*): New target, formal name for
old m68*-*-rtems*. old m68*-*-rtems*.
(m68*-*-rtemself*): New target. (m68*-*-rtemself*): New target.
(mips64orion-*-rtems*): Remove duplicate definition of tm_file. (mips64orion-*-rtems*): Remove duplicate definition of tm_file.
(sparc*-*-rtemsaout*): New target, formal name for old sparc*-*-rtems*. (sparc*-*-rtemsaout*): New target, formal name for old sparc*-*-rtems*.
(sparc*-*-rtemself*): New target. (sparc*-*-rtemself*): New target.
(sparc*-*-rtems*): Now elf not a.out. (sparc*-*-rtems*): Now elf not a.out.
* config/i386/rtems.h: Include config/rtems.h. * config/i386/rtems.h: Include config/rtems.h.
* config/i386/rtemself.h: Include config/rtems.h. * config/i386/rtemself.h: Include config/rtems.h.
* config/i960/rtems.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> 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> 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 \ 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 \ _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 _sf_to_df _thenan_sf _sf_to_usi _df_to_usi
DPBIT_FUNCS = _pack_df _unpack_df _addsub_df _mul_df _div_df \ 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 \ _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 _df_to_sf _thenan_df _sf_to_usi _df_to_usi
# The files that "belong" in CONFIG_H are deliberately omitted # 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. */ to be called normally. */
return expand_call (exp, target, ignore); 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, builtin_function ("__builtin_trap", void_ftype, BUILT_IN_TRAP,
BUILT_IN_NORMAL, NULL_PTR); 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. */ /* Untyped call and return. */
builtin_function ("__builtin_apply_args", ptr_ftype, builtin_function ("__builtin_apply_args", ptr_ftype,
BUILT_IN_APPLY_ARGS, BUILT_IN_NORMAL, NULL_PTR); 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 fntype, fundecl = 0;
register tree coerced_params; 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 NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (function); STRIP_TYPE_NOPS (function);
@ -1460,30 +1460,21 @@ build_function_call (function, params)
if (TREE_CODE (function) == ADDR_EXPR if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (function, 0)) && 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))) result = expand_tree_builtin (TREE_OPERAND (function, 0),
{ params, coerced_params);
case BUILT_IN_ABS: if (result)
case BUILT_IN_LABS: return result;
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;
}
{ result = build (CALL_EXPR, TREE_TYPE (fntype),
register tree result function, coerced_params, NULL_TREE);
= build (CALL_EXPR, TREE_TYPE (fntype),
function, coerced_params, NULL_TREE);
TREE_SIDE_EFFECTS (result) = 1; TREE_SIDE_EFFECTS (result) = 1;
if (TREE_TYPE (result) == void_type_node) if (TREE_TYPE (result) == void_type_node)
return result; return result;
return require_complete_type (result); return require_complete_type (result);
}
} }
/* Convert the argument expressions in the list VALUES /* 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"); pedwarn ("comparison between pointer and integer");
} }
break; 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: default:
break; 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 (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val))
{ {
if (GET_RTX_CLASS (code) == '<') if (GET_RTX_CLASS (code) == '<')
return (comparison_dominates_p (cond, code) ? const_true_rtx {
: (comparison_dominates_p (cond, if (comparison_dominates_p (cond, code))
reverse_condition (code)) return const_true_rtx;
? const0_rtx : x));
code = reverse_condition (code);
if (code != UNKNOWN
&& comparison_dominates_p (cond, code))
return const0_rtx;
else
return x;
}
else if (code == SMAX || code == SMIN else if (code == SMAX || code == SMIN
|| code == UMIN || code == UMAX) || code == UMIN || code == UMAX)
{ {
@ -10852,7 +10858,8 @@ reversible_comparison_p (x)
{ {
if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| flag_fast_math || 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; return 1;
switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0)))) 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_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int alpha_swapped_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 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 divmod_operator PARAMS ((rtx, enum machine_mode));
extern int aligned_memory_operand 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)); 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); 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 0;
return (code == EQ || code == LE || code == LT return (code == EQ || code == LE || code == LT
@ -722,7 +722,8 @@ alpha_swapped_comparison_operator (op, mode)
{ {
enum rtx_code code = GET_CODE (op); 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; return 0;
code = swap_condition (code); code = swap_condition (code);
@ -737,16 +738,30 @@ signed_comparison_operator (op, mode)
register rtx op; register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED; enum machine_mode mode ATTRIBUTE_UNUSED;
{ {
switch (GET_CODE (op)) enum rtx_code code = GET_CODE (op);
{
case EQ: case NE: case LE: case LT: case GE: case GT:
return 1;
default: if (mode != GET_MODE (op) && mode != VOIDmode)
break; 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. */ /* Return 1 if this is a divide or modulus operator. */
@ -1484,13 +1499,15 @@ alpha_emit_conditional_branch (code)
switch (code) switch (code)
{ {
case EQ: case LE: case LT: case LEU: case LTU: case EQ: case LE: case LT: case LEU: case LTU:
case UNORDERED:
/* We have these compares: */ /* We have these compares: */
cmp_code = code, branch_code = NE; cmp_code = code, branch_code = NE;
break; break;
case NE: case NE:
/* This must be reversed. */ case ORDERED:
cmp_code = EQ, branch_code = EQ; /* These must be reversed. */
cmp_code = reverse_condition (code), branch_code = EQ;
break; break;
case GE: case GT: case GEU: case GTU: case GE: case GT: case GEU: case GTU:
@ -3383,6 +3400,8 @@ print_operand (file, x, code)
fprintf (file, "ule"); fprintf (file, "ule");
else if (c == LTU) else if (c == LTU)
fprintf (file, "ult"); fprintf (file, "ult");
else if (c == UNORDERED)
fprintf (file, "un");
else else
fprintf (file, "%s", GET_RTX_NAME (c)); fprintf (file, "%s", GET_RTX_NAME (c));
} }

View File

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

View File

@ -2752,12 +2752,12 @@
"") "")
;; The following are the corresponding floating-point insns. Recall ;; 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. ;; to DFmode.
(define_insn "" (define_insn "*cmpdf_tp"
[(set (match_operand:DF 0 "register_operand" "=&f") [(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 2 "reg_or_fp0_operand" "fG")
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))] (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
"TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
@ -2765,9 +2765,9 @@
[(set_attr "type" "fadd") [(set_attr "type" "fadd")
(set_attr "trap" "yes")]) (set_attr "trap" "yes")])
(define_insn "" (define_insn "*cmpdf_no_tp"
[(set (match_operand:DF 0 "register_operand" "=f") [(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 2 "reg_or_fp0_operand" "fG")
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))] (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
"TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
@ -2777,7 +2777,7 @@
(define_insn "" (define_insn ""
[(set (match_operand:DF 0 "register_operand" "=&f") [(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 [(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG")) (match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))] (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
@ -2788,7 +2788,7 @@
(define_insn "" (define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f") [(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 [(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG")) (match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))] (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
@ -2799,7 +2799,7 @@
(define_insn "" (define_insn ""
[(set (match_operand:DF 0 "register_operand" "=&f") [(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 2 "reg_or_fp0_operand" "fG")
(float_extend:DF (float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))] (match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
@ -2810,7 +2810,7 @@
(define_insn "" (define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f") [(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 2 "reg_or_fp0_operand" "fG")
(float_extend:DF (float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))] (match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
@ -2821,7 +2821,7 @@
(define_insn "" (define_insn ""
[(set (match_operand:DF 0 "register_operand" "=&f") [(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 [(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG")) (match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(float_extend:DF (float_extend:DF
@ -2833,7 +2833,7 @@
(define_insn "" (define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f") [(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 [(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG")) (match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(float_extend:DF (float_extend:DF
@ -3126,6 +3126,22 @@
"" ""
"{ operands[1] = alpha_emit_conditional_branch (GEU); }") "{ 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" (define_expand "seq"
[(set (match_operand:DI 0 "register_operand" "") [(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))] (match_dup 1))]

View File

@ -1,7 +1,7 @@
/* This is a software floating point library which can be used instead of /* This is a software floating point library which can be used instead of
the floating point routines in libgcc1.c for targets without hardware the floating point routines in libgcc1.c for targets without hardware
floating point. 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 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 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_lt_df
#define L_le_sf #define L_le_sf
#define L_le_df #define L_le_df
#define L_unord_sf
#define L_unord_df
#define L_si_to_sf #define L_si_to_sf
#define L_si_to_df #define L_si_to_df
#define L_sf_to_si #define L_sf_to_si
@ -268,6 +270,7 @@ typedef unsigned int UDItype __attribute__ ((mode (DI)));
# define _ge_f2 __gesf2 # define _ge_f2 __gesf2
# define _lt_f2 __ltsf2 # define _lt_f2 __ltsf2
# define _le_f2 __lesf2 # define _le_f2 __lesf2
# define _unord_f2 __unordsf2
# define si_to_float __floatsisf # define si_to_float __floatsisf
# define float_to_si __fixsfsi # define float_to_si __fixsfsi
# define float_to_usi __fixunssfsi # define float_to_usi __fixunssfsi
@ -285,6 +288,7 @@ typedef unsigned int UDItype __attribute__ ((mode (DI)));
# define _ge_f2 __gedf2 # define _ge_f2 __gedf2
# define _lt_f2 __ltdf2 # define _lt_f2 __ltdf2
# define _le_f2 __ledf2 # define _le_f2 __ledf2
# define _unord_f2 __unorddf2
# define si_to_float __floatsidf # define si_to_float __floatsidf
# define float_to_si __fixdfsi # define float_to_si __fixdfsi
# define float_to_usi __fixunsdfsi # define float_to_usi __fixunsdfsi
@ -1370,6 +1374,24 @@ _le_f2 (FLO_type arg_a, FLO_type arg_b)
} }
#endif #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 */ #endif /* ! US_SOFTWARE_GOFAST */
#if defined(L_si_to_sf) || defined(L_si_to_df) #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> 2000-01-24 Nathan Sidwell <sidwell@codesourcery.com>
* cp-tree.h (CPTI_BAD_CAST, CPTI_BAD_TYPEID, CPTI_DCAST): New * 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> 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 * typeck2.c (incomplete_type_error): Restore previous
cp_error and cp_error_at call sequence. cp_error and cp_error_at call sequence.
2000-01-20 Brad Lucier <lucier@math.purdue.edu> 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 if (TREE_CODE (fn) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (fn, 0)) && 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))) tree exp;
{ exp = expand_tree_builtin (TREE_OPERAND (fn, 0), args, converted_args);
case BUILT_IN_ABS: if (exp)
case BUILT_IN_LABS: return exp;
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;
}
fn = build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args); fn = build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args);
if (TREE_CODE (TREE_TYPE (fn)) == VOID_TYPE) 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 fntype, fndecl;
register tree value_type; register tree value_type;
register tree coerced_params; register tree coerced_params;
tree result;
tree name = NULL_TREE, assembler_name = NULL_TREE; tree name = NULL_TREE, assembler_name = NULL_TREE;
int is_method; int is_method;
@ -3023,37 +3024,27 @@ build_function_call_real (function, params, require_complete, flags)
if (TREE_CODE (function) == ADDR_EXPR if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (function, 0)) && 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))) result = expand_tree_builtin (TREE_OPERAND (function, 0),
{ params, coerced_params);
case BUILT_IN_ABS: if (result)
case BUILT_IN_LABS: return result;
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;
}
/* C++ */ /* C++ */
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node; value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
{ result = build_call (function, value_type, coerced_params);
register tree result
= build_call (function, value_type, coerced_params);
if (require_complete) if (require_complete)
{ {
if (TREE_CODE (value_type) == VOID_TYPE) if (TREE_CODE (value_type) == VOID_TYPE)
return result; return result;
result = require_complete_type (result); result = require_complete_type (result);
} }
if (IS_AGGR_TYPE (value_type)) if (IS_AGGR_TYPE (value_type))
result = build_cplus_new (value_type, result); result = build_cplus_new (value_type, result);
return convert_from_reference (result); return convert_from_reference (result);
}
} }
tree tree
@ -3792,6 +3783,23 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
} }
break; 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: default:
break; break;
} }

View File

@ -3718,9 +3718,9 @@ fold_rtx (x, insn)
struct qty_table_elem *ent = &qty_table[qty]; struct qty_table_elem *ent = &qty_table[qty];
if ((comparison_dominates_p (ent->comparison_code, code) if ((comparison_dominates_p (ent->comparison_code, code)
|| (comparison_dominates_p (ent->comparison_code, || (! FLOAT_MODE_P (mode_arg0)
reverse_condition (code)) && comparison_dominates_p (ent->comparison_code,
&& ! FLOAT_MODE_P (mode_arg0))) reverse_condition (code))))
&& (rtx_equal_p (ent->comparison_const, folded_arg1) && (rtx_equal_p (ent->comparison_const, folded_arg1)
|| (const_arg1 || (const_arg1
&& rtx_equal_p (ent->comparison_const, && rtx_equal_p (ent->comparison_const,
@ -4156,6 +4156,10 @@ record_jump_equiv (insn, taken)
{ {
reversed_nonequality = (code != EQ && code != NE); reversed_nonequality = (code != EQ && code != NE);
code = reverse_condition (code); 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. */ /* 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, /* If this mode is an integer too wide to compare properly,
compare word by word. Rely on cse to optimize constant cases. */ 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 (); 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, /* If this mode is an integer too wide to compare properly,
compare word by word. Rely on cse to optimize constant cases. */ 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) if (code == MAX_EXPR)
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type), do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
@ -7618,6 +7619,14 @@ expand_expr (exp, target, tmode, modifier)
case GE_EXPR: case GE_EXPR:
case EQ_EXPR: case EQ_EXPR:
case NE_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); preexpand_calls (exp);
temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0); temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
if (temp != 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); do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT 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); do_jump_by_parts_equality (exp, if_false_label, if_true_label);
else else
do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label); 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); do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT 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); do_jump_by_parts_equality (exp, if_true_label, if_false_label);
else else
do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label); 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: case LT_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT 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); do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
else else
do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label); 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: case LE_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT 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); do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
else else
do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label); 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: case GT_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT 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); do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
else else
do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label); 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: case GE_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT 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); do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
else else
do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label); do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
break; 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: default:
normal: normal:
temp = expand_expr (exp, NULL_RTX, VOIDmode, 0); temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
@ -9519,7 +9603,7 @@ do_jump (exp, if_false_label, if_true_label)
emit_jump (target); emit_jump (target);
} }
else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT 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. */ /* Note swapping the labels gives us not-equal. */
do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label); do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
else if (GET_MODE (temp) != VOIDmode) else if (GET_MODE (temp) != VOIDmode)
@ -10059,6 +10143,32 @@ do_store_flag (exp, target, mode, only_cheap)
else else
code = unsignedp ? GEU : GE; code = unsignedp ? GEU : GE;
break; 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: default:
abort (); 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. */ /* 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; return 0;
icode = setcc_gen_code[(int) code]; icode = setcc_gen_code[(int) code];
if (icode == CODE_FOR_nothing if (icode == CODE_FOR_nothing
|| (only_cheap && insn_data[(int) icode].operand[0].mode != mode)) || (only_cheap && insn_data[(int) icode].operand[0].mode != mode))

View File

@ -499,6 +499,7 @@ enum libfunc_index
LTI_gehf2, LTI_gehf2,
LTI_lthf2, LTI_lthf2,
LTI_lehf2, LTI_lehf2,
LTI_unordhf2,
LTI_eqsf2, LTI_eqsf2,
LTI_nesf2, LTI_nesf2,
@ -506,6 +507,7 @@ enum libfunc_index
LTI_gesf2, LTI_gesf2,
LTI_ltsf2, LTI_ltsf2,
LTI_lesf2, LTI_lesf2,
LTI_unordsf2,
LTI_eqdf2, LTI_eqdf2,
LTI_nedf2, LTI_nedf2,
@ -513,6 +515,7 @@ enum libfunc_index
LTI_gedf2, LTI_gedf2,
LTI_ltdf2, LTI_ltdf2,
LTI_ledf2, LTI_ledf2,
LTI_unorddf2,
LTI_eqxf2, LTI_eqxf2,
LTI_nexf2, LTI_nexf2,
@ -520,6 +523,7 @@ enum libfunc_index
LTI_gexf2, LTI_gexf2,
LTI_ltxf2, LTI_ltxf2,
LTI_lexf2, LTI_lexf2,
LTI_unordxf2,
LTI_eqtf2, LTI_eqtf2,
LTI_netf2, LTI_netf2,
@ -527,6 +531,7 @@ enum libfunc_index
LTI_getf2, LTI_getf2,
LTI_lttf2, LTI_lttf2,
LTI_letf2, LTI_letf2,
LTI_unordtf2,
LTI_floatsisf, LTI_floatsisf,
LTI_floatdisf, LTI_floatdisf,
@ -627,6 +632,7 @@ extern rtx libfunc_table[LTI_MAX];
#define gehf2_libfunc (libfunc_table[LTI_gehf2]) #define gehf2_libfunc (libfunc_table[LTI_gehf2])
#define lthf2_libfunc (libfunc_table[LTI_lthf2]) #define lthf2_libfunc (libfunc_table[LTI_lthf2])
#define lehf2_libfunc (libfunc_table[LTI_lehf2]) #define lehf2_libfunc (libfunc_table[LTI_lehf2])
#define unordhf2_libfunc (libfunc_table[LTI_unordhf2])
#define eqsf2_libfunc (libfunc_table[LTI_eqsf2]) #define eqsf2_libfunc (libfunc_table[LTI_eqsf2])
#define nesf2_libfunc (libfunc_table[LTI_nesf2]) #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 gesf2_libfunc (libfunc_table[LTI_gesf2])
#define ltsf2_libfunc (libfunc_table[LTI_ltsf2]) #define ltsf2_libfunc (libfunc_table[LTI_ltsf2])
#define lesf2_libfunc (libfunc_table[LTI_lesf2]) #define lesf2_libfunc (libfunc_table[LTI_lesf2])
#define unordsf2_libfunc (libfunc_table[LTI_unordsf2])
#define eqdf2_libfunc (libfunc_table[LTI_eqdf2]) #define eqdf2_libfunc (libfunc_table[LTI_eqdf2])
#define nedf2_libfunc (libfunc_table[LTI_nedf2]) #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 gedf2_libfunc (libfunc_table[LTI_gedf2])
#define ltdf2_libfunc (libfunc_table[LTI_ltdf2]) #define ltdf2_libfunc (libfunc_table[LTI_ltdf2])
#define ledf2_libfunc (libfunc_table[LTI_ledf2]) #define ledf2_libfunc (libfunc_table[LTI_ledf2])
#define unorddf2_libfunc (libfunc_table[LTI_unorddf2])
#define eqxf2_libfunc (libfunc_table[LTI_eqxf2]) #define eqxf2_libfunc (libfunc_table[LTI_eqxf2])
#define nexf2_libfunc (libfunc_table[LTI_nexf2]) #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 gexf2_libfunc (libfunc_table[LTI_gexf2])
#define ltxf2_libfunc (libfunc_table[LTI_ltxf2]) #define ltxf2_libfunc (libfunc_table[LTI_ltxf2])
#define lexf2_libfunc (libfunc_table[LTI_lexf2]) #define lexf2_libfunc (libfunc_table[LTI_lexf2])
#define unordxf2_libfunc (libfunc_table[LTI_unordxf2])
#define eqtf2_libfunc (libfunc_table[LTI_eqtf2]) #define eqtf2_libfunc (libfunc_table[LTI_eqtf2])
#define netf2_libfunc (libfunc_table[LTI_netf2]) #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 getf2_libfunc (libfunc_table[LTI_getf2])
#define lttf2_libfunc (libfunc_table[LTI_lttf2]) #define lttf2_libfunc (libfunc_table[LTI_lttf2])
#define letf2_libfunc (libfunc_table[LTI_letf2]) #define letf2_libfunc (libfunc_table[LTI_letf2])
#define unordtf2_libfunc (libfunc_table[LTI_unordtf2])
#define floatsisf_libfunc (libfunc_table[LTI_floatsisf]) #define floatsisf_libfunc (libfunc_table[LTI_floatsisf])
#define floatdisf_libfunc (libfunc_table[LTI_floatdisf]) #define floatdisf_libfunc (libfunc_table[LTI_floatdisf])
@ -795,9 +805,11 @@ enum can_compare_purpose
ccp_cmov, ccp_cmov,
ccp_store_flag ccp_store_flag
}; };
/* Nonzero if a compare of mode MODE can be done straightforwardly /* Nonzero if a compare of mode MODE can be done straightforwardly
(without splitting it into pieces). */ (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, extern void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx,
enum machine_mode *, int *, int, 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: */ /* Functions from builtins.c: */
#ifdef TREE_CODE #ifdef TREE_CODE
extern rtx expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int)); 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 void std_expand_builtin_va_start PARAMS ((int, tree, rtx));
extern rtx std_expand_builtin_va_arg PARAMS ((tree, tree)); extern rtx std_expand_builtin_va_arg PARAMS ((tree, tree));
extern rtx 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. /* 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>. 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 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
GNU CC is distributed in the hope that it will be useful, GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330, the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */ Boston, MA 02111-1307, USA. */
/* This is a trivial test program which may be useful to people who are /* 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 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 = 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; sc = f1;
uc = f1; uc = f1;
ss = f1; ss = f1;
@ -143,6 +150,13 @@ main ()
si = d1 >= d2; si = d1 >= d2;
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; sc = d1;
uc = d1; uc = d1;
ss = d1; ss = d1;
@ -182,6 +196,13 @@ main ()
si = D1 >= D2; si = D1 >= D2;
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; sc = D1;
uc = D1; uc = D1;
ss = D1; ss = D1;

View File

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

View File

@ -9163,6 +9163,8 @@ get_condition (jump, earliest)
if (reverse_code) if (reverse_code)
{ {
code = reverse_condition (code); code = reverse_condition (code);
if (code == UNKNOWN)
return 0;
did_reverse_condition ^= 1; did_reverse_condition ^= 1;
reverse_code = 0; reverse_code = 0;
} }
@ -9227,9 +9229,10 @@ get_condition (jump, earliest)
} }
/* If this was floating-point and we reversed anything other than an /* 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 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 && ! flag_fast_math
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) && GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
return 0; 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, /* If this mode is an integer too wide to compare properly,
compare word by word. Rely on CSE to optimize constant cases. */ 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, do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
NULL_RTX, op1); NULL_RTX, op1);
else else
@ -2840,18 +2841,31 @@ emit_0_to_1_insn (x)
} }
/* Nonzero if we can perform a comparison of mode MODE straightforwardly. /* 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 PURPOSE describes how this comparison will be used. CODE is the rtx
comparison, otherwise a store-flags operation. */ 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 int
can_compare_p (mode, purpose) can_compare_p (code, mode, purpose)
enum rtx_code code;
enum machine_mode mode; enum machine_mode mode;
enum can_compare_purpose purpose; enum can_compare_purpose purpose;
{ {
do do
{ {
if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) 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 if (purpose == ccp_jump
&& cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) && cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
return 1; return 1;
@ -3016,7 +3030,7 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align,
*px = x; *px = x;
*py = y; *py = y;
if (can_compare_p (mode, purpose)) if (can_compare_p (*pcomparison, mode, purpose))
return; return;
/* Handle a lib call just for the mode we are using. */ /* 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; libfunc = lehf2_libfunc;
break; break;
case UNORDERED:
libfunc = unordhf2_libfunc;
break;
default: default:
break; break;
} }
@ -3297,6 +3315,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = lesf2_libfunc; libfunc = lesf2_libfunc;
break; break;
case UNORDERED:
libfunc = unordsf2_libfunc;
break;
default: default:
break; break;
} }
@ -3327,6 +3349,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = ledf2_libfunc; libfunc = ledf2_libfunc;
break; break;
case UNORDERED:
libfunc = unorddf2_libfunc;
break;
default: default:
break; break;
} }
@ -3357,6 +3383,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = lexf2_libfunc; libfunc = lexf2_libfunc;
break; break;
case UNORDERED:
libfunc = unordxf2_libfunc;
break;
default: default:
break; break;
} }
@ -3387,6 +3417,10 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
libfunc = letf2_libfunc; libfunc = letf2_libfunc;
break; break;
case UNORDERED:
libfunc = unordtf2_libfunc;
break;
default: default:
break; break;
} }
@ -3415,8 +3449,7 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
if (libfunc == 0) if (libfunc == 0)
abort (); abort ();
emit_library_call (libfunc, 1, emit_library_call (libfunc, 1, word_mode, 2, x, mode, y, mode);
word_mode, 2, x, mode, y, mode);
/* Immediately move the result of the libcall into a pseudo /* Immediately move the result of the libcall into a pseudo
register so reload doesn't clobber the value if it needs 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; *px = result;
*py = const0_rtx; *py = const0_rtx;
*pmode = word_mode; *pmode = word_mode;
if (comparison == UNORDERED)
*pcomparison = NE;
#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL #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; *pcomparison = NE;
#endif #endif
*punsignedp = 0; *punsignedp = 0;
@ -4650,6 +4685,7 @@ init_optabs ()
gehf2_libfunc = init_one_libfunc ("__gehf2"); gehf2_libfunc = init_one_libfunc ("__gehf2");
lthf2_libfunc = init_one_libfunc ("__lthf2"); lthf2_libfunc = init_one_libfunc ("__lthf2");
lehf2_libfunc = init_one_libfunc ("__lehf2"); lehf2_libfunc = init_one_libfunc ("__lehf2");
unordhf2_libfunc = init_one_libfunc ("__unordhf2");
eqsf2_libfunc = init_one_libfunc ("__eqsf2"); eqsf2_libfunc = init_one_libfunc ("__eqsf2");
nesf2_libfunc = init_one_libfunc ("__nesf2"); nesf2_libfunc = init_one_libfunc ("__nesf2");
@ -4657,6 +4693,7 @@ init_optabs ()
gesf2_libfunc = init_one_libfunc ("__gesf2"); gesf2_libfunc = init_one_libfunc ("__gesf2");
ltsf2_libfunc = init_one_libfunc ("__ltsf2"); ltsf2_libfunc = init_one_libfunc ("__ltsf2");
lesf2_libfunc = init_one_libfunc ("__lesf2"); lesf2_libfunc = init_one_libfunc ("__lesf2");
unordsf2_libfunc = init_one_libfunc ("__unordsf2");
eqdf2_libfunc = init_one_libfunc ("__eqdf2"); eqdf2_libfunc = init_one_libfunc ("__eqdf2");
nedf2_libfunc = init_one_libfunc ("__nedf2"); nedf2_libfunc = init_one_libfunc ("__nedf2");
@ -4664,6 +4701,7 @@ init_optabs ()
gedf2_libfunc = init_one_libfunc ("__gedf2"); gedf2_libfunc = init_one_libfunc ("__gedf2");
ltdf2_libfunc = init_one_libfunc ("__ltdf2"); ltdf2_libfunc = init_one_libfunc ("__ltdf2");
ledf2_libfunc = init_one_libfunc ("__ledf2"); ledf2_libfunc = init_one_libfunc ("__ledf2");
unorddf2_libfunc = init_one_libfunc ("__unorddf2");
eqxf2_libfunc = init_one_libfunc ("__eqxf2"); eqxf2_libfunc = init_one_libfunc ("__eqxf2");
nexf2_libfunc = init_one_libfunc ("__nexf2"); nexf2_libfunc = init_one_libfunc ("__nexf2");
@ -4671,6 +4709,7 @@ init_optabs ()
gexf2_libfunc = init_one_libfunc ("__gexf2"); gexf2_libfunc = init_one_libfunc ("__gexf2");
ltxf2_libfunc = init_one_libfunc ("__ltxf2"); ltxf2_libfunc = init_one_libfunc ("__ltxf2");
lexf2_libfunc = init_one_libfunc ("__lexf2"); lexf2_libfunc = init_one_libfunc ("__lexf2");
unordxf2_libfunc = init_one_libfunc ("__unordxf2");
eqtf2_libfunc = init_one_libfunc ("__eqtf2"); eqtf2_libfunc = init_one_libfunc ("__eqtf2");
netf2_libfunc = init_one_libfunc ("__netf2"); netf2_libfunc = init_one_libfunc ("__netf2");
@ -4678,6 +4717,7 @@ init_optabs ()
getf2_libfunc = init_one_libfunc ("__getf2"); getf2_libfunc = init_one_libfunc ("__getf2");
lttf2_libfunc = init_one_libfunc ("__lttf2"); lttf2_libfunc = init_one_libfunc ("__lttf2");
letf2_libfunc = init_one_libfunc ("__letf2"); letf2_libfunc = init_one_libfunc ("__letf2");
unordtf2_libfunc = init_one_libfunc ("__unordtf2");
floatsisf_libfunc = init_one_libfunc ("__floatsisf"); floatsisf_libfunc = init_one_libfunc ("__floatsisf");
floatdisf_libfunc = init_one_libfunc ("__floatdisf"); 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(LEU, "leu", "ee", '<')
DEF_RTL_EXPR(LTU, "ltu", "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. /* Represents the result of sign-extending the sole operand.
The machine modes of the operand and of the SIGN_EXTEND expression The machine modes of the operand and of the SIGN_EXTEND expression
determine how much sign-extension is going on. */ 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) Thu Jan 20 12:34:48 2000 Jeffrey A Law (law@cygnus.com)
* gcc.c-torture/execute/20000120-2.c: New test. * 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 (EQ_EXPR, "eq_expr", '<', 2)
DEFTREECODE (NE_EXPR, "ne_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. */ /* Operations for Pascal sets. Not used now. */
DEFTREECODE (IN_EXPR, "in_expr", '2', 2) DEFTREECODE (IN_EXPR, "in_expr", '2', 2)
DEFTREECODE (SET_LE_EXPR, "set_le_expr", '<', 2) DEFTREECODE (SET_LE_EXPR, "set_le_expr", '<', 2)

View File

@ -116,6 +116,14 @@ enum built_in_function
BUILT_IN_LONGJMP, BUILT_IN_LONGJMP,
BUILT_IN_TRAP, 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. */ /* Various hooks for the DWARF 2 __throw routine. */
BUILT_IN_UNWIND_INIT, BUILT_IN_UNWIND_INIT,
BUILT_IN_DWARF_CFA, BUILT_IN_DWARF_CFA,