2000-01-24 Richard Henderson <rth@cygnus.com>
+ * rtl.def: Add unordered fp comparisions.
+ * tree.def: Likewise.
+ * tree.h: Add ISO C 9x unordered fp comparision builtins.
+
+ * builtins.c (expand_tree_builtin): New function.
+ * c-typeck.c (build_function_call): Use it.
+ (build_binary_op): Support unordered compares.
+ * c-common.c (c_common_nodes_and_builtins): Add unordered compares.
+
+ * combine.c (known_cond): Handle reverse_condition returning UNKNOWN.
+ (reversible_comparison_p): Allow UNORDERED/ORDERED to be reversed.
+ * cse.c (fold_rtx): Check FLOAT_MODE_P before reversing.
+ (record_jump_equiv): Handle reverse_condition returning UNKNOWN.
+ * jump.c (reverse_condition): Don't abort for UNLE etc, but
+ return UNKNOWN.
+ (swap_condition): Handle unordered compares.
+ (thread_jumps): Check can_reverse before reversing.
+ * loop.c (get_condition): Likewise. Allow UNORERED/ORDERED to be
+ reversed for FP.
+
+ * optabs.c (can_compare_p): New argument CODE. Verify branch or
+ setcc is present before acking for cmp_optab. Update all callers.
+ (prepare_float_lib_cmp, init_optabs): Handle UNORDERED.
+ * expmed.c (do_cmp_and_jump): Update for can_compare_p.
+ * expr.c (expand_expr): Likewise. Support unordered compares.
+ (do_jump, do_store_flag): Likewise.
+ * expr.h (enum libfunc_index): Add unordered compares.
+
+ * Makefile.in (FPBIT_FUNCS): Add _unord_sf.
+ (DPBIT_FUNCS): Add _unord_df.
+ * config/fp-bit.c (_unord_f2): New.
+ * fp-test.c (main): Try unordered compare builtins.
+
+ * alpha-protos.h (alpha_fp_comparison_operator): Declare.
+ * alpha.c (alpha_comparison_operator): Check mode properly.
+ (alpha_swapped_comparison_operator): Likewise.
+ (signed_comparison_operator): Likewise.
+ (alpha_fp_comparison_operator): New.
+ (alpha_emit_conditional_branch): Handle unordered compares.
+ * alpha.h (PREDICATE_CODES): Update.
+ * alpha.md (fp compares): Use alpha_fp_comparison_operator.
+ (bunordered, bordered): New.
+
+2000-01-24 Richard Henderson <rth@cygnus.com>
+
* alpha.c (alpha_emit_xfloating_cvt): Thinko in operand manipulation.
* alpha.md (movtf): New expander, insn, and splitter.
2000-01-22 Alan Modra <alan@SPRI.Levels.UniSA.Edu.Au>
- * config/elfos.h (UNIQUE_SECTION): Restore uninitialised data
- section naming to that prior to 2000-01-07 patch.
+ * config/elfos.h (UNIQUE_SECTION): Restore uninitialised data
+ section naming to that prior to 2000-01-07 patch.
* config/mips/elf.h (UNIQUE_SECTION): Ditto.
* config/mips/elf64.h (UNIQUE_SECTION): Ditto.
* config/mips/iris6gld.h (UNIQUE_SECTION): Ditto.
2000-01-20 Zack Weinberg <zack@wolery.cumb.org>
* Makefile.in (fixinc.sh): Depend on specs.
- * fixinc/Makefile.in: Add rule to create machname.h.
- (fixlib.o): Depend on machname.h.
- * fixinc/fixtests.c (machine_name): New test.
- * fixinc/fixfixes.c (machine_name): New fix.
- * fixinc/fixlib.c (mn_get_regexps): New helper function for
- the machine_name test and fix.
- * fixinc/fixlib.h: Prototype it.
- * fixinc/inclhack.def (machine_name): Use the C test and fix.
+ * fixinc/Makefile.in: Add rule to create machname.h.
+ (fixlib.o): Depend on machname.h.
+ * fixinc/fixtests.c (machine_name): New test.
+ * fixinc/fixfixes.c (machine_name): New fix.
+ * fixinc/fixlib.c (mn_get_regexps): New helper function for
+ the machine_name test and fix.
+ * fixinc/fixlib.h: Prototype it.
+ * fixinc/inclhack.def (machine_name): Use the C test and fix.
* fixinc/fixincl.x, fixinc/inclhack.sh: Rebuild.
- * gcc.c (do_spec_1) [case P]: Take care not to create
- identifiers with three leading or trailing underscores.
+ * gcc.c (do_spec_1) [case P]: Take care not to create
+ identifiers with three leading or trailing underscores.
* fixinc/Makefile.in (FIXINC_DEFS): Add -DIN_GCC.
(fixincl): Don't specify libraries twice on link line.
2000-01-14 Clinton Popetz <cpopetz@cygnus.com>
* config/mips/mips.h (REGISTER_MOVE_COST): Remove redundant
- case for moving from HI/LO/HI_LO_REG. This makes the behavior
- match the comment for MIPS16.
+ case for moving from HI/LO/HI_LO_REG. This makes the behavior
+ match the comment for MIPS16.
Fri Jan 14 00:28:06 2000 Jeffrey A Law (law@cygnus.com)
Use emit_jump_insn for the return insn.
Thu Jan 13 14:46:03 2000 Jason Eckhardt <jle@cygnus.com>
- Stan Cox <scox@cygnus.com>
+ Stan Cox <scox@cygnus.com>
* predict.c: New file. Preliminary infrastructure work for static
branch prediction and basic block reordering.
2000-01-11 Clinton Popetz <cpopetz@cygnus.com>
- * config/mips/mips.c (mips_va_arg): For EABI, emit the queued
- integer vararg POSTINCREMENT before the destination of the jump
- for the hard fp case.
- (function_arg_pass_by_reference): Pass a copy of CUM to
+ * config/mips/mips.c (mips_va_arg): For EABI, emit the queued
+ integer vararg POSTINCREMENT before the destination of the jump
+ for the hard fp case.
+ (function_arg_pass_by_reference): Pass a copy of CUM to
FUNCTION_ARG.
-
- * config/mips/mips.h (GO_IF_LEGITIMATE_ADDRESS): Move check
- for CONSTANT_ADDRESS_P above while loop for subreg.
+
+ * config/mips/mips.h (GO_IF_LEGITIMATE_ADDRESS): Move check
+ for CONSTANT_ADDRESS_P above while loop for subreg.
2000-01-11 Clinton Popetz <cpopetz@cygnus.com>
* flow.c (propagate_block): When a prologue/epilogue insn
- is marked dead, unconditionally clear libcall_is_dead and
- insn_is_dead, and only dump rtl if warnings aren't being
- suppressed.
+ is marked dead, unconditionally clear libcall_is_dead and
+ insn_is_dead, and only dump rtl if warnings aren't being
+ suppressed.
Tue Jan 11 16:26:47 MET 2000 Jan Hubicka <jh@suse.cz>
* 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.
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>
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
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;
+}
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);
{
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);
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);
}
\f
/* Convert the argument expressions in the list VALUES
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;
}
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)
{
{
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))))
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));
{
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
{
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);
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. */
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:
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));
}
{"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}}, \
"")
\f
;; 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"
[(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"
(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")]))]
(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")]))]
(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"))]))]
(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"))]))]
(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
(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
""
"{ 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))]
/* 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
#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
# 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
# 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
}
#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)
+2000-01-24 Richard Henderson <rth@cygnus.com>
+
+ * call.c (build_over_call): Use expand_tree_builtin.
+ * typeck.c (build_function_call_real): Likewise.
+ (build_binary_op_nodefault): Handle unordered compares.
+
2000-01-24 Nathan Sidwell <sidwell@codesourcery.com>
* cp-tree.h (CPTI_BAD_CAST, CPTI_BAD_TYPEID, CPTI_DCAST): New
2000-01-19 Gabriel Dos Reis <gdr@codesourcery.coom>
- * typeck.c (build_unary_op): Use cp_pedwarn, not pedwarn.
+ * typeck.c (build_unary_op): Use cp_pedwarn, not pedwarn.
- * typeck2.c (incomplete_type_error): Restore previous
- cp_error and cp_error_at call sequence.
+ * typeck2.c (incomplete_type_error): Restore previous
+ cp_error and cp_error_at call sequence.
2000-01-20 Brad Lucier <lucier@math.purdue.edu>
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)
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;
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
}
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;
}
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,
{
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. */
/* 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 ();
/* 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),
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)
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);
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);
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);
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);
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);
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);
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)
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 ();
}
}
/* 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))
LTI_gehf2,
LTI_lthf2,
LTI_lehf2,
+ LTI_unordhf2,
LTI_eqsf2,
LTI_nesf2,
LTI_gesf2,
LTI_ltsf2,
LTI_lesf2,
+ LTI_unordsf2,
LTI_eqdf2,
LTI_nedf2,
LTI_gedf2,
LTI_ltdf2,
LTI_ledf2,
+ LTI_unorddf2,
LTI_eqxf2,
LTI_nexf2,
LTI_gexf2,
LTI_ltxf2,
LTI_lexf2,
+ LTI_unordxf2,
LTI_eqtf2,
LTI_netf2,
LTI_getf2,
LTI_lttf2,
LTI_letf2,
+ LTI_unordtf2,
LTI_floatsisf,
LTI_floatdisf,
#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])
#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])
#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])
#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])
#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])
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,
/* 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));
/* fp-test.c - Check that all floating-point operations are available.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2000 Free Software Foundation, Inc.
Contributed by Ronald F. Guilmette <rfg@monkeys.com>.
-This file is part of GNU CC.
+ This file is part of GNU CC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+ GNU CC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ GNU CC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
/* This is a trivial test program which may be useful to people who are
porting the GCC or G++ compilers to a new system. The intent here is
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;
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;
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;
&& 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
{
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;
}
}
{
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;
}
}
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);
if (reverse_code)
{
code = reverse_condition (code);
+ if (code == UNKNOWN)
+ return 0;
did_reverse_condition ^= 1;
reverse_code = 0;
}
}
/* 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;
/* 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
}
/* 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;
*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. */
libfunc = lehf2_libfunc;
break;
+ case UNORDERED:
+ libfunc = unordhf2_libfunc;
+ break;
+
default:
break;
}
libfunc = lesf2_libfunc;
break;
+ case UNORDERED:
+ libfunc = unordsf2_libfunc;
+ break;
+
default:
break;
}
libfunc = ledf2_libfunc;
break;
+ case UNORDERED:
+ libfunc = unorddf2_libfunc;
+ break;
+
default:
break;
}
libfunc = lexf2_libfunc;
break;
+ case UNORDERED:
+ libfunc = unordxf2_libfunc;
+ break;
+
default:
break;
}
libfunc = letf2_libfunc;
break;
+ case UNORDERED:
+ libfunc = unordtf2_libfunc;
+ break;
+
default:
break;
}
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
*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;
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");
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");
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");
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");
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");
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. */
+2000-01-24 Richard Henderson <rth@cygnus.com>
+
+ * gcc.c-torture/execute/ieee/fp-cmp-4.c: New.
+
Thu Jan 20 12:34:48 2000 Jeffrey A Law (law@cygnus.com)
* gcc.c-torture/execute/20000120-2.c: New test.
--- /dev/null
+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);
+}
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)
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,