+2017-10-27 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/82692
+ * config/i386/i386-modes.def (CCFPU): Remove definition.
+ * config/i386/i386.c (put_condition_mode): Remove CCFPU mode handling.
+ (ix86_cc_modes_compatible): Ditto.
+ (ix86_expand_carry_flag_compare): Ditto.
+ (ix86_expand_int_movcc): Ditto.
+ (ix86_expand_int_addcc): Ditto.
+ (ix86_reverse_condition): Ditto.
+ (ix86_unordered_fp_compare): Rename from ix86_fp_compare_mode.
+ Return true/false for unordered/ordered fp comparisons.
+ (ix86_cc_mode): Always return CCFPmode for float mode comparisons.
+ (ix86_prepare_fp_compare_args): Update for rename.
+ (ix86_expand_fp_compare): Update for rename. Generate unordered
+ compare RTXes wrapped with UNSPEC_NOTRAP unspec.
+ (ix86_expand_sse_compare_and_jump): Ditto.
+ * config/i386/predicates.md (fcmov_comparison_operator):
+ Remove CCFPU mode handling.
+ (ix86_comparison_operator): Ditto.
+ (ix86_carry_flag_operator): Ditto.
+ * config/i386/i386.md (UNSPEC_NOTRAP): New unspec.
+ (*cmpu<mode>_i387): Wrap compare RTX with UNSPEC_NOTRAP unspec.
+ (*cmpu<mode>_cc_i387): Ditto.
+ (FPCMP): Remove mode iterator.
+ (unord): Remove mode attribute.
+ (unord_subst): New define_subst transformation
+ (unord): New define_subst attribute.
+ (unordered): Ditto.
+ (*cmpi<unord><MODEF:mode>): Rewrite using unord_subst transformation.
+ (*cmpi<unord>xf_i387): Ditto.
+ * config/i386/sse.md (<sse>_<unord>comi<round_saeonly_name>): Merge
+ from <sse>_comi<round_saeonly_name> and <sse>_ucomi<round_saeonly_name>
+ using unord_subst transformation.
+ * config/i386/subst.md (SUBST_A): Remove CCFP and CCFPU modes.
+ (round_saeonly): Also handle CCFP mode.
+ * reg-stack.c (subst_stack_regs_pat): Handle UNSPEC_NOTRAP unspec.
+ Remove UNSPEC_SAHF unspec handling.
+
2017-10-27 Jan Hubicka <hubicka@ucw.cz>
* x86-tune.def (X86_TUNE_INTER_UNIT_MOVES_TO_VEC): Disable for Zen.
CC_MODE (CCP);
CC_MODE (CCS);
CC_MODE (CCZ);
+
CC_MODE (CCFP);
-CC_MODE (CCFPU);
/* Vector modes. Note that VEC_CONCAT patterns require vector
sizes twice as big as implemented in hardware. */
{
const char *suffix;
- if (mode == CCFPmode || mode == CCFPUmode)
+ if (mode == CCFPmode)
{
code = ix86_fp_compare_code_to_integer (code);
mode = CCmode;
return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
}
-/* Figure out whether to use ordered or unordered fp comparisons.
- Return the appropriate mode to use. */
+/* Figure out whether to use unordered fp comparisons. */
-machine_mode
-ix86_fp_compare_mode (enum rtx_code code)
+static bool
+ix86_unordered_fp_compare (enum rtx_code code)
{
if (!TARGET_IEEE_FP)
- return CCFPmode;
+ return false;
switch (code)
{
case GE:
case LT:
case LE:
- return CCFPmode;
+ return false;
case EQ:
case NE:
case UNGT:
case UNGE:
case UNEQ:
- return CCFPUmode;
+ return true;
default:
gcc_unreachable ();
if (SCALAR_FLOAT_MODE_P (mode))
{
gcc_assert (!DECIMAL_FLOAT_MODE_P (mode));
- return ix86_fp_compare_mode (code);
+ return CCFPmode;
}
switch (code)
}
case E_CCFPmode:
- case E_CCFPUmode:
/* These are only compatible with themselves, which we already
checked above. */
return VOIDmode;
static enum rtx_code
ix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1)
{
- machine_mode fpcmp_mode = ix86_fp_compare_mode (code);
+ bool unordered_compare = ix86_unordered_fp_compare (code);
rtx op0 = *pop0, op1 = *pop1;
machine_mode op_mode = GET_MODE (op0);
bool is_sse = TARGET_SSE_MATH && SSE_FLOAT_MODE_P (op_mode);
floating point. */
if (!is_sse
- && (fpcmp_mode == CCFPUmode
+ && (unordered_compare
|| (op_mode == XFmode
&& ! (standard_80387_constant_p (op0) == 1
|| standard_80387_constant_p (op1) == 1)
static rtx
ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
{
- machine_mode fpcmp_mode, intcmp_mode;
+ bool unordered_compare = ix86_unordered_fp_compare (code);
+ machine_mode intcmp_mode;
rtx tmp, tmp2;
- fpcmp_mode = ix86_fp_compare_mode (code);
code = ix86_prepare_fp_compare_args (code, &op0, &op1);
/* Do fcomi/sahf based test when profitable. */
switch (ix86_fp_comparison_strategy (code))
{
case IX86_FPCMP_COMI:
- intcmp_mode = fpcmp_mode;
- tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
- tmp = gen_rtx_SET (gen_rtx_REG (fpcmp_mode, FLAGS_REG), tmp);
- emit_insn (tmp);
+ intcmp_mode = CCFPmode;
+ tmp = gen_rtx_COMPARE (CCFPmode, op0, op1);
+ if (unordered_compare)
+ tmp = gen_rtx_UNSPEC (CCFPmode, gen_rtvec (1, tmp), UNSPEC_NOTRAP);
+ emit_insn (gen_rtx_SET (gen_rtx_REG (CCFPmode, FLAGS_REG), tmp));
break;
case IX86_FPCMP_SAHF:
- intcmp_mode = fpcmp_mode;
- tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
- tmp = gen_rtx_SET (gen_rtx_REG (fpcmp_mode, FLAGS_REG), tmp);
-
+ intcmp_mode = CCFPmode;
+ tmp = gen_rtx_COMPARE (CCFPmode, op0, op1);
+ if (unordered_compare)
+ tmp = gen_rtx_UNSPEC (CCFPmode, gen_rtvec (1, tmp), UNSPEC_NOTRAP);
+ tmp = gen_rtx_SET (gen_rtx_REG (CCFPmode, FLAGS_REG), tmp);
if (!scratch)
scratch = gen_reg_rtx (HImode);
tmp2 = gen_rtx_CLOBBER (VOIDmode, scratch);
case IX86_FPCMP_ARITH:
/* Sadness wrt reg-stack pops killing fpsr -- gotta get fnstsw first. */
- tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
- tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), UNSPEC_FNSTSW);
+ tmp = gen_rtx_COMPARE (CCFPmode, op0, op1);
+ if (unordered_compare)
+ tmp = gen_rtx_UNSPEC (CCFPmode, gen_rtvec (1, tmp), UNSPEC_NOTRAP);
+ tmp = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), UNSPEC_FNSTSW);
if (!scratch)
scratch = gen_reg_rtx (HImode);
- emit_insn (gen_rtx_SET (scratch, tmp2));
+ emit_insn (gen_rtx_SET (scratch, tmp));
/* In the unordered case, we have to check C2 for NaN's, which
doesn't happen to work out to anything nice combination-wise.
compare_seq = get_insns ();
end_sequence ();
- if (GET_MODE (XEXP (compare_op, 0)) == CCFPmode
- || GET_MODE (XEXP (compare_op, 0)) == CCFPUmode)
+ if (GET_MODE (XEXP (compare_op, 0)) == CCFPmode)
code = ix86_fp_compare_code_to_integer (GET_CODE (compare_op));
else
code = GET_CODE (compare_op);
flags = XEXP (compare_op, 0);
- if (GET_MODE (flags) == CCFPmode
- || GET_MODE (flags) == CCFPUmode)
+ if (GET_MODE (flags) == CCFPmode)
{
fpcmp = true;
compare_code
flags = XEXP (compare_op, 0);
- if (GET_MODE (flags) == CCFPmode
- || GET_MODE (flags) == CCFPUmode)
+ if (GET_MODE (flags) == CCFPmode)
{
fpcmp = true;
code = ix86_fp_compare_code_to_integer (code);
enum rtx_code
ix86_reverse_condition (enum rtx_code code, machine_mode mode)
{
- return (mode != CCFPmode && mode != CCFPUmode
+ return (mode != CCFPmode
? reverse_condition (code)
: reverse_condition_maybe_unordered (code));
}
ix86_expand_sse_compare_and_jump (enum rtx_code code, rtx op0, rtx op1,
bool swap_operands)
{
- machine_mode fpcmp_mode = ix86_fp_compare_mode (code);
+ bool unordered_compare = ix86_unordered_fp_compare (code);
rtx_code_label *label;
- rtx tmp;
+ rtx tmp, reg;
if (swap_operands)
std::swap (op0, op1);
label = gen_label_rtx ();
- tmp = gen_rtx_REG (fpcmp_mode, FLAGS_REG);
- emit_insn (gen_rtx_SET (tmp, gen_rtx_COMPARE (fpcmp_mode, op0, op1)));
- tmp = gen_rtx_fmt_ee (code, VOIDmode, tmp, const0_rtx);
+ tmp = gen_rtx_COMPARE (CCFPmode, op0, op1);
+ if (unordered_compare)
+ tmp = gen_rtx_UNSPEC (CCFPmode, gen_rtvec (1, tmp), UNSPEC_NOTRAP);
+ reg = gen_rtx_REG (CCFPmode, FLAGS_REG);
+ emit_insn (gen_rtx_SET (reg, tmp));
+ tmp = gen_rtx_fmt_ee (code, VOIDmode, reg, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode, label), pc_rtx);
tmp = emit_jump_insn (gen_rtx_SET (pc_rtx, tmp));
UNSPEC_SCAS
UNSPEC_FNSTSW
UNSPEC_SAHF
+ UNSPEC_NOTRAP
UNSPEC_PARITY
UNSPEC_FSTCW
UNSPEC_FLDCW
;; FP compares, step 1:
;; Set the FP condition codes.
-;;
-;; CCFPmode compare with exceptions
-;; CCFPUmode compare with no exceptions
;; We may not use "#" to split and emit these, since the REG_DEAD notes
;; used to manage the reg stack popping would not be preserved.
(define_insn "*cmpu<mode>_i387"
[(set (match_operand:HI 0 "register_operand" "=a")
(unspec:HI
- [(compare:CCFPU
- (match_operand:X87MODEF 1 "register_operand" "f")
- (match_operand:X87MODEF 2 "register_operand" "f"))]
+ [(unspec:CCFP
+ [(compare:CCFP
+ (match_operand:X87MODEF 1 "register_operand" "f")
+ (match_operand:X87MODEF 2 "register_operand" "f"))]
+ UNSPEC_NOTRAP)]
UNSPEC_FNSTSW))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, false, true);"
(set_attr "mode" "<MODE>")])
(define_insn_and_split "*cmpu<mode>_cc_i387"
- [(set (reg:CCFPU FLAGS_REG)
- (compare:CCFPU
- (match_operand:X87MODEF 1 "register_operand" "f")
- (match_operand:X87MODEF 2 "register_operand" "f")))
+ [(set (reg:CCFP FLAGS_REG)
+ (unspec:CCFP
+ [(compare:CCFP
+ (match_operand:X87MODEF 1 "register_operand" "f")
+ (match_operand:X87MODEF 2 "register_operand" "f"))]
+ UNSPEC_NOTRAP))
(clobber (match_operand:HI 0 "register_operand" "=a"))]
"TARGET_80387 && TARGET_SAHF && !TARGET_CMOVE"
"#"
"&& reload_completed"
[(set (match_dup 0)
(unspec:HI
- [(compare:CCFPU (match_dup 1)(match_dup 2))]
- UNSPEC_FNSTSW))
+ [(unspec:CCFP
+ [(compare:CCFP (match_dup 1)(match_dup 2))]
+ UNSPEC_NOTRAP)]
+ UNSPEC_FNSTSW))
(set (reg:CC FLAGS_REG)
(unspec:CC [(match_dup 0)] UNSPEC_SAHF))]
""
;; Pentium Pro can do steps 1 through 3 in one go.
;; (these instructions set flags directly)
-(define_mode_iterator FPCMP [CCFP CCFPU])
-(define_mode_attr unord [(CCFP "") (CCFPU "u")])
+(define_subst_attr "unord" "unord_subst" "" "u")
+(define_subst_attr "unordered" "unord_subst" "false" "true")
+
+(define_subst "unord_subst"
+ [(set (match_operand:CCFP 0)
+ (match_operand:CCFP 1))]
+ ""
+ [(set (match_dup 0)
+ (unspec:CCFP
+ [(match_dup 1)]
+ UNSPEC_NOTRAP))])
-(define_insn "*cmpi<FPCMP:unord><MODEF:mode>"
- [(set (reg:FPCMP FLAGS_REG)
- (compare:FPCMP
+(define_insn "*cmpi<unord><MODEF:mode>"
+ [(set (reg:CCFP FLAGS_REG)
+ (compare:CCFP
(match_operand:MODEF 0 "register_operand" "f,v")
(match_operand:MODEF 1 "register_ssemem_operand" "f,vm")))]
"(SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH)
|| (TARGET_80387 && TARGET_CMOVE)"
"@
- * return output_fp_compare (insn, operands, true, \
- <FPCMP:MODE>mode == CCFPUmode);
- %v<FPCMP:unord>comi<MODEF:ssemodesuffix>\t{%1, %0|%0, %1}"
+ * return output_fp_compare (insn, operands, true, <unordered>);
+ %v<unord>comi<MODEF:ssemodesuffix>\t{%1, %0|%0, %1}"
[(set_attr "type" "fcmp,ssecomi")
(set_attr "prefix" "orig,maybe_vex")
(set_attr "mode" "<MODEF:MODE>")
(symbol_ref "false"))))])
(define_insn "*cmpi<unord>xf_i387"
- [(set (reg:FPCMP FLAGS_REG)
- (compare:FPCMP
+ [(set (reg:CCFP FLAGS_REG)
+ (compare:CCFP
(match_operand:XF 0 "register_operand" "f")
(match_operand:XF 1 "register_operand" "f")))]
"TARGET_80387 && TARGET_CMOVE"
- "* return output_fp_compare (insn, operands, true,
- <MODE>mode == CCFPUmode);"
+ "* return output_fp_compare (insn, operands, true, <unordered>);"
[(set_attr "type" "fcmp")
(set_attr "mode" "XF")
(set_attr "athlon_decode" "vector")
machine_mode inmode = GET_MODE (XEXP (op, 0));
enum rtx_code code = GET_CODE (op);
- if (inmode == CCFPmode || inmode == CCFPUmode)
+ if (inmode == CCFPmode)
{
if (!ix86_trivial_fp_comparison_operator (op, mode))
return false;
switch (code)
{
case LTU: case GTU: case LEU: case GEU:
- if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode
+ if (inmode == CCmode || inmode == CCFPmode
|| inmode == CCCmode)
return true;
return false;
machine_mode inmode = GET_MODE (XEXP (op, 0));
enum rtx_code code = GET_CODE (op);
- if (inmode == CCFPmode || inmode == CCFPUmode)
+ if (inmode == CCFPmode)
return ix86_trivial_fp_comparison_operator (op, mode);
switch (code)
machine_mode inmode = GET_MODE (XEXP (op, 0));
enum rtx_code code = GET_CODE (op);
- if (inmode == CCFPmode || inmode == CCFPUmode)
+ if (inmode == CCFPmode)
{
if (!ix86_trivial_fp_comparison_operator (op, mode))
return false;
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
-(define_insn "<sse>_comi<round_saeonly_name>"
+(define_insn "<sse>_<unord>comi<round_saeonly_name>"
[(set (reg:CCFP FLAGS_REG)
(compare:CCFP
(vec_select:MODEF
(match_operand:<ssevecmode> 1 "<round_saeonly_nimm_scalar_predicate>" "<round_saeonly_constraint>")
(parallel [(const_int 0)]))))]
"SSE_FLOAT_MODE_P (<MODE>mode)"
- "%vcomi<ssemodesuffix>\t{<round_saeonly_op2>%1, %0|%0, %<iptr>1<round_saeonly_op2>}"
- [(set_attr "type" "ssecomi")
- (set_attr "prefix" "maybe_vex")
- (set_attr "prefix_rep" "0")
- (set (attr "prefix_data16")
- (if_then_else (eq_attr "mode" "DF")
- (const_string "1")
- (const_string "0")))
- (set_attr "mode" "<MODE>")])
-
-(define_insn "<sse>_ucomi<round_saeonly_name>"
- [(set (reg:CCFPU FLAGS_REG)
- (compare:CCFPU
- (vec_select:MODEF
- (match_operand:<ssevecmode> 0 "register_operand" "v")
- (parallel [(const_int 0)]))
- (vec_select:MODEF
- (match_operand:<ssevecmode> 1 "<round_saeonly_nimm_scalar_predicate>" "<round_saeonly_constraint>")
- (parallel [(const_int 0)]))))]
- "SSE_FLOAT_MODE_P (<MODE>mode)"
- "%vucomi<ssemodesuffix>\t{<round_saeonly_op2>%1, %0|%0, %<iptr>1<round_saeonly_op2>}"
+ "%v<unord>comi<ssemodesuffix>\t{<round_saeonly_op2>%1, %0|%0, %<iptr>1<round_saeonly_op2>}"
[(set_attr "type" "ssecomi")
(set_attr "prefix" "maybe_vex")
(set_attr "prefix_rep" "0")
V8DI V4DI V2DI
V16SF V8SF V4SF
V8DF V4DF V2DF
- QI HI SI DI SF DF
- CCFP CCFPU])
+ QI HI SI DI SF DF])
(define_subst_attr "mask_name" "mask" "" "_mask")
(define_subst_attr "mask_applied" "mask" "false" "true")
UNSPEC_EMBEDDED_ROUNDING))
])
+(define_subst "round_saeonly"
+ [(set (match_operand:CCFP 0)
+ (match_operand:CCFP 1))]
+ "TARGET_AVX512F"
+ [(set (match_dup 0)
+ (unspec:CCFP [(match_dup 1)
+ (match_operand:SI 2 "const48_operand")]
+ UNSPEC_EMBEDDED_ROUNDING))
+])
+
(define_subst_attr "round_expand_name" "round_expand" "" "_round")
(define_subst_attr "round_expand_nimm_predicate" "round_expand" "nonimmediate_operand" "register_operand")
(define_subst_attr "round_expand_operand" "round_expand" "" ", operands[5]")
switch (GET_CODE (pat_src))
{
- case COMPARE:
- /* `fcomi' insn can't pop two regs. */
- compare_for_stack_reg (insn, regstack, pat_src,
- REGNO (*dest) != FLAGS_REG);
- break;
-
case CALL:
{
int count;
replace_reg (src2, FIRST_STACK_REG + 1);
break;
- case UNSPEC_SAHF:
- /* (unspec [(unspec [(compare)] UNSPEC_FNSTSW)] UNSPEC_SAHF)
- The combination matches the PPRO fcomi instruction. */
-
- pat_src = XVECEXP (pat_src, 0, 0);
- gcc_assert (GET_CODE (pat_src) == UNSPEC);
- gcc_assert (XINT (pat_src, 1) == UNSPEC_FNSTSW);
- /* Fall through. */
-
case UNSPEC_FNSTSW:
/* Combined fcomp+fnstsw generated for doing well with
CSE. When optimizing this would have been broken
up before now. */
pat_src = XVECEXP (pat_src, 0, 0);
- gcc_assert (GET_CODE (pat_src) == COMPARE);
+ if (GET_CODE (pat_src) == COMPARE)
+ goto do_compare;
- compare_for_stack_reg (insn, regstack, pat_src, true);
- break;
+ /* Fall through. */
+
+ case UNSPEC_NOTRAP:
+
+ pat_src = XVECEXP (pat_src, 0, 0);
+ gcc_assert (GET_CODE (pat_src) == COMPARE);
+ goto do_compare;
default:
gcc_unreachable ();
}
break;
+ case COMPARE:
+ do_compare:
+ /* `fcomi' insn can't pop two regs. */
+ compare_for_stack_reg (insn, regstack, pat_src,
+ REGNO (*dest) != FLAGS_REG);
+ break;
+
case IF_THEN_ELSE:
/* This insn requires the top of stack to be the destination. */
+2017-10-27 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/82692
+ * gcc.dg/torture/pr82692.c: New test.
+
2017-10-27 Will Schmidt <will_schmidt@vnet.ibm.com>
* gcc.target/powerpc/fold-vec-neg-char.c: New.
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target fenv_exceptions } */
+
+#include <fenv.h>
+
+extern void abort (void);
+extern void exit (int);
+
+double __attribute__ ((noinline, noclone))
+foo (double x)
+{
+ if (__builtin_islessequal (x, 0.0) || __builtin_isgreater (x, 1.0))
+ return x + x;
+ return x * x;
+}
+
+int
+main (void)
+{
+ volatile double x = foo (__builtin_nan (""));
+ if (fetestexcept (FE_INVALID))
+ abort ();
+ exit (0);
+}