+2020-01-17 Richard Sandiford <richard.sandiford@arm.com>
+
+ * config/aarch64/aarch64.h (REVERSIBLE_CC_MODE): Return false
+ for FP modes.
+ (REVERSE_CONDITION): Delete.
+ * config/aarch64/iterators.md (CC_ONLY): New mode iterator.
+ (CCFP_CCFPE): Likewise.
+ (e): New mode attribute.
+ * config/aarch64/aarch64.md (ccmp<GPI:mode>): Rename to...
+ (@ccmp<CC_ONLY:mode><GPI:mode>): ...this, using CC_ONLY instead of CC.
+ (fccmp<GPF:mode>, fccmpe<GPF:mode>): Merge into...
+ (@ccmp<CCFP_CCFPE:mode><GPF:mode>): ...this combined pattern.
+ (@ccmp<CC_ONLY:mode><GPI:mode>_rev): New pattern.
+ (@ccmp<CCFP_CCFPE:mode><GPF:mode>_rev): Likewise.
+ * config/aarch64/aarch64.c (aarch64_gen_compare_reg): Update
+ name of generator from gen_ccmpdi to gen_ccmpccdi.
+ (aarch64_gen_ccmp_next): Use code_for_ccmp. If we want to reverse
+ the previous comparison but aren't able to, use the new ccmp_rev
+ patterns instead.
+
2020-01-17 Richard Sandiford <richard.sandiford@arm.com>
* gimplify.c (gimplify_return_expr): Use poly_int_tree_p rather
rtx x_hi = operand_subword (x, 1, 0, TImode);
rtx y_hi = operand_subword (y, 1, 0, TImode);
- emit_insn (gen_ccmpdi (cc_reg, cc_reg, x_hi, y_hi,
- gen_rtx_EQ (cc_mode, cc_reg, const0_rtx),
- GEN_INT (AARCH64_EQ)));
+ emit_insn (gen_ccmpccdi (cc_reg, cc_reg, x_hi, y_hi,
+ gen_rtx_EQ (cc_mode, cc_reg, const0_rtx),
+ GEN_INT (AARCH64_EQ)));
}
else
{
case E_HImode:
case E_SImode:
cmp_mode = SImode;
- icode = CODE_FOR_ccmpsi;
break;
case E_DImode:
cmp_mode = DImode;
- icode = CODE_FOR_ccmpdi;
break;
case E_SFmode:
cmp_mode = SFmode;
cc_mode = aarch64_select_cc_mode ((rtx_code) cmp_code, op0, op1);
- icode = cc_mode == CCFPEmode ? CODE_FOR_fccmpesf : CODE_FOR_fccmpsf;
break;
case E_DFmode:
cmp_mode = DFmode;
cc_mode = aarch64_select_cc_mode ((rtx_code) cmp_code, op0, op1);
- icode = cc_mode == CCFPEmode ? CODE_FOR_fccmpedf : CODE_FOR_fccmpdf;
break;
default:
return NULL_RTX;
}
+ icode = code_for_ccmp (cc_mode, cmp_mode);
+
op0 = prepare_operand (icode, op0, 2, op_mode, cmp_mode, unsignedp);
op1 = prepare_operand (icode, op1, 3, op_mode, cmp_mode, unsignedp);
if (!op0 || !op1)
if (bit_code != AND)
{
- prev = gen_rtx_fmt_ee (REVERSE_CONDITION (GET_CODE (prev),
- GET_MODE (XEXP (prev, 0))),
- VOIDmode, XEXP (prev, 0), const0_rtx);
+ /* Treat the ccmp patterns as canonical and use them where possible,
+ but fall back to ccmp_rev patterns if there's no other option. */
+ rtx_code prev_code = GET_CODE (prev);
+ machine_mode prev_mode = GET_MODE (XEXP (prev, 0));
+ if ((prev_mode == CCFPmode || prev_mode == CCFPEmode)
+ && !(prev_code == EQ
+ || prev_code == NE
+ || prev_code == ORDERED
+ || prev_code == UNORDERED))
+ icode = code_for_ccmp_rev (cc_mode, cmp_mode);
+ else
+ {
+ rtx_code code = reverse_condition (prev_code);
+ prev = gen_rtx_fmt_ee (code, VOIDmode, XEXP (prev, 0), const0_rtx);
+ }
aarch64_cond = AARCH64_INVERSE_CONDITION_CODE (aarch64_cond);
}
#define SELECT_CC_MODE(OP, X, Y) aarch64_select_cc_mode (OP, X, Y)
-#define REVERSIBLE_CC_MODE(MODE) 1
-
-#define REVERSE_CONDITION(CODE, MODE) \
- (((MODE) == CCFPmode || (MODE) == CCFPEmode) \
- ? reverse_condition_maybe_unordered (CODE) \
- : reverse_condition (CODE))
+/* Having an integer comparison mode guarantees that we can use
+ reverse_condition, but the usual restrictions apply to floating-point
+ comparisons. */
+#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPmode && (MODE) != CCFPEmode)
#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
((VALUE) = GET_MODE_UNIT_BITSIZE (MODE), 2)
""
"")
-(define_insn "ccmp<mode>"
- [(set (match_operand:CC 1 "cc_register" "")
- (if_then_else:CC
+(define_insn "@ccmp<CC_ONLY:mode><GPI:mode>"
+ [(set (match_operand:CC_ONLY 1 "cc_register" "")
+ (if_then_else:CC_ONLY
(match_operator 4 "aarch64_comparison_operator"
[(match_operand 0 "cc_register" "")
(const_int 0)])
- (compare:CC
+ (compare:CC_ONLY
(match_operand:GPI 2 "register_operand" "r,r,r")
(match_operand:GPI 3 "aarch64_ccmp_operand" "r,Uss,Usn"))
- (unspec:CC [(match_operand 5 "immediate_operand")] UNSPEC_NZCV)))]
+ (unspec:CC_ONLY
+ [(match_operand 5 "immediate_operand")]
+ UNSPEC_NZCV)))]
""
"@
ccmp\\t%<w>2, %<w>3, %k5, %m4
[(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
)
-(define_insn "fccmp<mode>"
- [(set (match_operand:CCFP 1 "cc_register" "")
- (if_then_else:CCFP
+(define_insn "@ccmp<CCFP_CCFPE:mode><GPF:mode>"
+ [(set (match_operand:CCFP_CCFPE 1 "cc_register" "")
+ (if_then_else:CCFP_CCFPE
(match_operator 4 "aarch64_comparison_operator"
[(match_operand 0 "cc_register" "")
(const_int 0)])
- (compare:CCFP
+ (compare:CCFP_CCFPE
(match_operand:GPF 2 "register_operand" "w")
(match_operand:GPF 3 "register_operand" "w"))
- (unspec:CCFP [(match_operand 5 "immediate_operand")] UNSPEC_NZCV)))]
+ (unspec:CCFP_CCFPE
+ [(match_operand 5 "immediate_operand")]
+ UNSPEC_NZCV)))]
"TARGET_FLOAT"
- "fccmp\\t%<s>2, %<s>3, %k5, %m4"
+ "fccmp<e>\\t%<s>2, %<s>3, %k5, %m4"
[(set_attr "type" "fccmp<s>")]
)
-(define_insn "fccmpe<mode>"
- [(set (match_operand:CCFPE 1 "cc_register" "")
- (if_then_else:CCFPE
+(define_insn "@ccmp<CC_ONLY:mode><GPI:mode>_rev"
+ [(set (match_operand:CC_ONLY 1 "cc_register" "")
+ (if_then_else:CC_ONLY
(match_operator 4 "aarch64_comparison_operator"
[(match_operand 0 "cc_register" "")
- (const_int 0)])
- (compare:CCFPE
+ (const_int 0)])
+ (unspec:CC_ONLY
+ [(match_operand 5 "immediate_operand")]
+ UNSPEC_NZCV)
+ (compare:CC_ONLY
+ (match_operand:GPI 2 "register_operand" "r,r,r")
+ (match_operand:GPI 3 "aarch64_ccmp_operand" "r,Uss,Usn"))))]
+ ""
+ "@
+ ccmp\\t%<w>2, %<w>3, %k5, %M4
+ ccmp\\t%<w>2, %3, %k5, %M4
+ ccmn\\t%<w>2, #%n3, %k5, %M4"
+ [(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
+)
+
+(define_insn "@ccmp<CCFP_CCFPE:mode><GPF:mode>_rev"
+ [(set (match_operand:CCFP_CCFPE 1 "cc_register" "")
+ (if_then_else:CCFP_CCFPE
+ (match_operator 4 "aarch64_comparison_operator"
+ [(match_operand 0 "cc_register" "")
+ (const_int 0)])
+ (unspec:CCFP_CCFPE
+ [(match_operand 5 "immediate_operand")]
+ UNSPEC_NZCV)
+ (compare:CCFP_CCFPE
(match_operand:GPF 2 "register_operand" "w")
- (match_operand:GPF 3 "register_operand" "w"))
- (unspec:CCFPE [(match_operand 5 "immediate_operand")] UNSPEC_NZCV)))]
+ (match_operand:GPF 3 "register_operand" "w"))))]
"TARGET_FLOAT"
- "fccmpe\\t%<s>2, %<s>3, %k5, %m4"
+ "fccmp<e>\\t%<s>2, %<s>3, %k5, %M4"
[(set_attr "type" "fccmp<s>")]
)
;; Mode Iterators
;; -------------------------------------------------------------------
+;; Condition-code iterators.
+(define_mode_iterator CC_ONLY [CC])
+(define_mode_iterator CCFP_CCFPE [CCFP CCFPE])
;; Iterator for General Purpose Integer registers (32- and 64-bit modes)
(define_mode_iterator GPI [SI DI])
;; Mode attributes
;; -------------------------------------------------------------------
+;; "e" for signaling operations, "" for quiet operations.
+(define_mode_attr e [(CCFP "") (CCFPE "e")])
+
;; In GPI templates, a string like "%<w>0" will expand to "%w0" in the
;; 32-bit version and "%x0" in the 64-bit version.
(define_mode_attr w [(QI "w") (HI "w") (SI "w") (DI "x") (SF "s") (DF "d")])
--- /dev/null
+/* { dg-do run } */
+/* { dg-add-options ieee } */
+/* { dg-require-effective-target fenv_exceptions } */
+/* { dg-skip-if "fenv" { powerpc-ibm-aix* } } */
+
+#include <fenv.h>
+
+int
+__attribute__ ((noinline, noclone))
+f1 (float a, float b)
+{
+ return -__builtin_isgreater (a, b);
+}
+
+int
+__attribute__ ((noinline, noclone))
+f2 (float a, float b)
+{
+ return -(a > b);
+}
+
+int
+main (void)
+{
+ volatile int r;
+
+ float nanf = __builtin_nanf ("");
+ float argf = 1.0f;
+
+ feclearexcept (FE_INVALID);
+
+ r = f1 (nanf, argf);
+ if (r != 0 || fetestexcept (FE_INVALID))
+ __builtin_abort ();
+
+ r = f2 (nanf, argf);
+ if (r != 0 || !fetestexcept (FE_INVALID))
+ __builtin_abort ();
+
+ return 0;
+}