From: rth Date: Mon, 24 Jan 2000 20:10:04 +0000 (+0000) Subject: * rtl.def: Add unordered fp comparisions. X-Git-Tag: upstream/4.9.2~103568 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a4110d9a66b1bfab2679b8b4774839bcfb1b3cba;p=platform%2Fupstream%2Flinaro-gcc.git * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@31591 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 87611ce..159d95b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,50 @@ 2000-01-24 Richard Henderson + * 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 + * alpha.c (alpha_emit_xfloating_cvt): Thinko in operand manipulation. * alpha.md (movtf): New expander, insn, and splitter. @@ -139,8 +184,8 @@ Mon Jan 24 16:50:08 MET 2000 Jan Hubicka 2000-01-22 Alan Modra - * 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 2000-01-20 Zack Weinberg * 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 * 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 Use emit_jump_insn for the return insn. Thu Jan 13 14:46:03 2000 Jason Eckhardt - Stan Cox + Stan Cox * 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 2000-01-11 Clinton Popetz - * 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 * 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 @@ -1660,11 +1705,11 @@ Thu Jan 6 13:44:59 CET 2000 Jan Hubicka * 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 1999-12-30 Herman A.J. ten Brugge - * genrecog.c (change_state) Corrected typo. + * genrecog.c (change_state) Corrected typo. 1999-12-30 Kaveh R. Ghazi diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 8d91ab3..5e6b6e5 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 diff --git a/gcc/builtins.c b/gcc/builtins.c index 1ca5b5d..fcb6a7a 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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; +} diff --git a/gcc/c-common.c b/gcc/c-common.c index 0ce1ff1..6d91810 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -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); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index a810a3b..f85931a 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -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); - - TREE_SIDE_EFFECTS (result) = 1; - if (TREE_TYPE (result) == void_type_node) - return result; - return require_complete_type (result); - } + 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); } /* 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; } diff --git a/gcc/combine.c b/gcc/combine.c index 99fe499..8d578eb 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -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)))) diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index c29063e..693fa24 100644 --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -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)); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index ca9e0ec..cbc1688 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -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)); } diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index b146a5a..ad45596 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -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}}, \ diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md index 5f0e221..2325483 100644 --- a/gcc/config/alpha/alpha.md +++ b/gcc/config/alpha/alpha.md @@ -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))] diff --git a/gcc/config/fp-bit.c b/gcc/config/fp-bit.c index d7bc3de..fc496c0 100644 --- a/gcc/config/fp-bit.c +++ b/gcc/config/fp-bit.c @@ -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) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0b2cda1..92dcb79 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2000-01-24 Richard Henderson + + * 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 * cp-tree.h (CPTI_BAD_CAST, CPTI_BAD_TYPEID, CPTI_DCAST): New @@ -111,10 +117,10 @@ 2000-01-19 Gabriel Dos Reis - * 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 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f526abf..991a79d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 2a4a668..29f6086 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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; } diff --git a/gcc/cse.c b/gcc/cse.c index b346199..9aced05 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -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. */ diff --git a/gcc/expmed.c b/gcc/expmed.c index 6344187..92d9a16 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -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 (); diff --git a/gcc/expr.c b/gcc/expr.c index 9e07daf..62f7d56 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -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)) diff --git a/gcc/expr.h b/gcc/expr.h index 9442f0f..95c6942 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -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)); diff --git a/gcc/fp-test.c b/gcc/fp-test.c index 667059c..d071244 100644 --- a/gcc/fp-test.c +++ b/gcc/fp-test.c @@ -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 . -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; diff --git a/gcc/jump.c b/gcc/jump.c index bbd04da..bd22231 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -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); diff --git a/gcc/loop.c b/gcc/loop.c index 936adfb..152f9cf 100644 --- a/gcc/loop.c +++ b/gcc/loop.c @@ -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; diff --git a/gcc/optabs.c b/gcc/optabs.c index 14fd87e..df08316 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -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"); diff --git a/gcc/rtl.def b/gcc/rtl.def index 2c323fc..94b72b8 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fca3656..2081313 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2000-01-24 Richard Henderson + + * 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. diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-4.c b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-4.c new file mode 100644 index 0000000..80342ee --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-4.c @@ -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); +} diff --git a/gcc/tree.def b/gcc/tree.def index 2ba6f2d..b4fb3ca 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -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) diff --git a/gcc/tree.h b/gcc/tree.h index 84a333d..d6e51a0 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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,