diff --git a/gcc/config/i386/i386-features.c b/gcc/config/i386/i386-features.c index 620f7f157f453a9f0d02e761e0e57d206d02b215..ff6676f54f74d34f2f71ea42e33f29338161c79a 100644 --- a/gcc/config/i386/i386-features.c +++ b/gcc/config/i386/i386-features.c @@ -581,7 +581,8 @@ general_scalar_chain::compute_convert_gain () else if (GET_CODE (src) == NEG || GET_CODE (src) == NOT) igain += m * ix86_cost->add - ix86_cost->sse_op - COSTS_N_INSNS (1); - else if (GET_CODE (src) == SMAX + else if (GET_CODE (src) == ABS + || GET_CODE (src) == SMAX || GET_CODE (src) == SMIN || GET_CODE (src) == UMAX || GET_CODE (src) == UMIN) @@ -986,13 +987,6 @@ general_scalar_chain::convert_insn (rtx_insn *insn) switch (GET_CODE (src)) { - case ASHIFT: - case ASHIFTRT: - case LSHIFTRT: - convert_op (&XEXP (src, 0), insn); - PUT_MODE (src, vmode); - break; - case PLUS: case MINUS: case IOR: @@ -1002,8 +996,14 @@ general_scalar_chain::convert_insn (rtx_insn *insn) case SMIN: case UMAX: case UMIN: - convert_op (&XEXP (src, 0), insn); convert_op (&XEXP (src, 1), insn); + /* FALLTHRU */ + + case ABS: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + convert_op (&XEXP (src, 0), insn); PUT_MODE (src, vmode); break; @@ -1414,6 +1414,12 @@ general_scalar_to_vector_candidate_p (rtx_insn *insn, enum machine_mode mode) return false; break; + case ABS: + if ((mode == DImode && !TARGET_AVX512VL) + || (mode == SImode && !TARGET_SSSE3)) + return false; + break; + case NEG: case NOT: break; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 299350147729fb9beaf6aa72a8b16b5153bc3efd..2b2ba2f3a2070cd002b30e1bbf17df41228a6d4f 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -10062,8 +10062,8 @@ "#" "reload_completed" [(parallel - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (neg:DWIH (match_dup 1)) (const_int 0))) + [(set (reg:CCC FLAGS_REG) + (ne:CCC (match_dup 1) (const_int 0))) (set (match_dup 0) (neg:DWIH (match_dup 1)))]) (parallel [(set (match_dup 2) @@ -10077,7 +10077,7 @@ (clobber (reg:CC FLAGS_REG))])] "split_double_mode (<DWI>mode, &operands[0], 2, &operands[0], &operands[2]);") -(define_insn "*neg<mode>2_1" +(define_insn "*neg<mode>_1" [(set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m") (neg:SWI (match_operand:SWI 1 "nonimmediate_operand" "0"))) (clobber (reg:CC FLAGS_REG))] @@ -10086,7 +10086,7 @@ [(set_attr "type" "negnot") (set_attr "mode" "<MODE>")]) -(define_insn "*negsi2_1_zext" +(define_insn "*negsi_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (neg:SI (match_operand:SI 1 "register_operand" "0")))) @@ -10096,36 +10096,46 @@ [(set_attr "type" "negnot") (set_attr "mode" "SI")]) -;; The problem with neg is that it does not perform (compare x 0), -;; it really performs (compare 0 x), which leaves us with the zero -;; flag being the only useful item. - -(define_insn "*neg<mode>2_cmpz" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ +(define_insn "*neg<mode>_2" + [(set (reg FLAGS_REG) + (compare (neg:SWI (match_operand:SWI 1 "nonimmediate_operand" "0")) - (const_int 0))) + (const_int 0))) (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m") (neg:SWI (match_dup 1)))] - "ix86_unary_operator_ok (NEG, <MODE>mode, operands)" + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_unary_operator_ok (NEG, <MODE>mode, operands)" "neg{<imodesuffix>}\t%0" [(set_attr "type" "negnot") (set_attr "mode" "<MODE>")]) -(define_insn "*negsi2_cmpz_zext" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ +(define_insn "*negsi_2_zext" + [(set (reg FLAGS_REG) + (compare (neg:SI (match_operand:SI 1 "register_operand" "0")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (neg:SI (match_dup 1))))] - "TARGET_64BIT && ix86_unary_operator_ok (NEG, SImode, operands)" + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_unary_operator_ok (NEG, SImode, operands)" "neg{l}\t%k0" [(set_attr "type" "negnot") (set_attr "mode" "SI")]) -(define_insn "*neg<mode>_ccc" +(define_insn "*neg<mode>_ccc_1" + [(set (reg:CCC FLAGS_REG) + (ne:CCC + (match_operand:SWI 1 "nonimmediate_operand" "0") + (const_int 0))) + (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m") + (neg:SWI (match_dup 1)))] + "" + "neg{<imodesuffix>}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "<MODE>")]) + +(define_insn "*neg<mode>_ccc_2" [(set (reg:CCC FLAGS_REG) (ne:CCC (match_operand:SWI 1 "nonimmediate_operand" "0") @@ -10169,27 +10179,102 @@ ;; Special expand pattern to handle integer mode abs (define_expand "abs<mode>2" - [(set (match_operand:SWI48x 0 "register_operand") - (abs:SWI48x - (match_operand:SWI48x 1 "register_operand")))] - "TARGET_EXPAND_ABS" - { - machine_mode mode = <MODE>mode; - - /* Generate rtx abs using abs (x) = (((signed) x >> (W-1)) ^ x) - - ((signed) x >> (W-1)) */ - rtx shift_amount = gen_int_mode (GET_MODE_PRECISION (mode) - 1, QImode); - rtx shift_dst = expand_simple_binop (mode, ASHIFTRT, operands[1], - shift_amount, NULL_RTX, - 0, OPTAB_DIRECT); - rtx xor_dst = expand_simple_binop (mode, XOR, shift_dst, operands[1], - operands[0], 0, OPTAB_DIRECT); - rtx minus_dst = expand_simple_binop (mode, MINUS, xor_dst, shift_dst, - operands[0], 0, OPTAB_DIRECT); - if (!rtx_equal_p (minus_dst, operands[0])) - emit_move_insn (operands[0], minus_dst); - DONE; - }) + [(parallel + [(set (match_operand:SWI48x 0 "register_operand") + (abs:SWI48x + (match_operand:SWI48x 1 "general_operand"))) + (clobber (reg:CC FLAGS_REG))])] + "TARGET_CMOVE" +{ + if (TARGET_EXPAND_ABS) + { + machine_mode mode = <MODE>mode; + operands[1] = force_reg (mode, operands[1]); + + /* Generate rtx abs using: + abs (x) = (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)) */ + + rtx shift_amount = gen_int_mode (GET_MODE_PRECISION (mode) - 1, QImode); + rtx shift_dst = expand_simple_binop (mode, ASHIFTRT, operands[1], + shift_amount, NULL_RTX, + 0, OPTAB_DIRECT); + rtx xor_dst = expand_simple_binop (mode, XOR, shift_dst, operands[1], + operands[0], 0, OPTAB_DIRECT); + rtx minus_dst = expand_simple_binop (mode, MINUS, xor_dst, shift_dst, + operands[0], 0, OPTAB_DIRECT); + if (!rtx_equal_p (minus_dst, operands[0])) + emit_move_insn (operands[0], minus_dst); + DONE; + } +}) + +(define_insn_and_split "*abs<mode>2_1" + [(set (match_operand:SWI48 0 "register_operand") + (abs:SWI48 + (match_operand:SWI48 1 "general_operand"))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_CMOVE && ix86_pre_reload_split ()" + "#" + "&& 1" + [(parallel + [(set (reg:CCGOC FLAGS_REG) + (compare:CCGOC + (neg:SWI48 (match_dup 1)) + (const_int 0))) + (set (match_dup 2) + (neg:SWI48 (match_dup 1)))]) + (set (match_dup 0) + (if_then_else:SWI48 + (ge (reg:CCGOC FLAGS_REG) (const_int 0)) + (match_dup 2) + (match_dup 1)))] +{ + operands[1] = force_reg (<MODE>mode, operands[1]); + operands[2] = gen_reg_rtx (<MODE>mode); +}) + +(define_insn_and_split "*absdi2_doubleword" + [(set (match_operand:DI 0 "register_operand") + (abs:DI + (match_operand:DI 1 "general_operand"))) + (clobber (reg:CC FLAGS_REG))] + "!TARGET_64BIT && TARGET_CMOVE + && ix86_pre_reload_split ()" + "#" + "&& 1" + [(parallel + [(set (reg:CCC FLAGS_REG) + (ne:CCC (match_dup 1) (const_int 0))) + (set (match_dup 2) (neg:DWIH (match_dup 1)))]) + (parallel + [(set (match_dup 5) + (plus:DWIH (plus:DWIH (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)) + (match_dup 4)) + (const_int 0))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (reg:CCGOC FLAGS_REG) + (compare:CCGOC + (neg:SI (match_dup 5)) + (const_int 0))) + (set (match_dup 5) + (neg:SI (match_dup 5)))]) + (set (match_dup 0) + (if_then_else:SI + (ge (reg:CCGOC FLAGS_REG) (const_int 0)) + (match_dup 2) + (match_dup 1))) + (set (match_dup 3) + (if_then_else:SI + (ge (reg:CCGOC FLAGS_REG) (const_int 0)) + (match_dup 5) + (match_dup 4)))] +{ + operands[1] = force_reg (DImode, operands[1]); + operands[2] = gen_reg_rtx (DImode); + + split_double_mode (DImode, &operands[0], 3, &operands[0], &operands[3]); +}) (define_expand "<code>tf2" [(set (match_operand:TF 0 "register_operand") @@ -18881,33 +18966,32 @@ (define_expand "<code><mode>3" [(parallel - [(set (match_operand:SWI248 0 "register_operand") - (maxmin:SWI248 - (match_operand:SWI248 1 "register_operand") - (match_operand:SWI248 2 "general_operand"))) + [(set (match_operand:SWI48x 0 "register_operand") + (maxmin:SWI48x + (match_operand:SWI48x 1 "register_operand") + (match_operand:SWI48x 2 "general_operand"))) (clobber (reg:CC FLAGS_REG))])] "TARGET_CMOVE") (define_insn_and_split "*<code><mode>3_1" - [(set (match_operand:SWI248 0 "register_operand") - (maxmin:SWI248 - (match_operand:SWI248 1 "register_operand") - (match_operand:SWI248 2 "general_operand"))) + [(set (match_operand:SWI48 0 "register_operand") + (maxmin:SWI48 + (match_operand:SWI48 1 "register_operand") + (match_operand:SWI48 2 "general_operand"))) (clobber (reg:CC FLAGS_REG))] "TARGET_CMOVE && ix86_pre_reload_split ()" "#" "&& 1" [(set (match_dup 0) - (if_then_else:SWI248 (match_dup 3) + (if_then_else:SWI48 (match_dup 3) (match_dup 1) (match_dup 2)))] { machine_mode mode = <MODE>mode; rtx cmp_op = operands[2]; - if (!register_operand (cmp_op, mode)) - operands[2] = force_reg (mode, cmp_op); + operands[2] = force_reg (mode, cmp_op); enum rtx_code code = <maxmin_rel>; @@ -18961,8 +19045,7 @@ (match_dup 4) (match_dup 5)))] { - if (!register_operand (operands[2], DImode)) - operands[2] = force_reg (DImode, operands[2]); + operands[2] = force_reg (DImode, operands[2]); split_double_mode (DImode, &operands[0], 3, &operands[0], &operands[3]); diff --git a/gcc/testsuite/gcc.target/i386/pr97873-1.c b/gcc/testsuite/gcc.target/i386/pr97873-1.c new file mode 100644 index 0000000000000000000000000000000000000000..48c1d278020703e0b1d624a0e316ec76225631ad --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr97873-1.c @@ -0,0 +1,12 @@ +/* PR target/97873 */ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -mavx512vl -mstv -mno-stackrealign" } */ +/* { dg-final { scan-assembler "pabsq" } } */ + +extern long long z; + +void +foo (long long x) +{ + z = (x < 0) ? -x : x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr97873.c b/gcc/testsuite/gcc.target/i386/pr97873.c new file mode 100644 index 0000000000000000000000000000000000000000..ec598f9fda0d982285a064a13c32a43efd63a26b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr97873.c @@ -0,0 +1,9 @@ +/* PR target/97873 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse2 -mno-sse3 -mtune=generic" } */ +/* { dg-final { scan-assembler-not "test|cmp" } } */ + +int foo (int x) +{ + return (x < 0) ? -x : x; +}