diff options
author | Uros Bizjak <ubizjak@gmail.com> | 2024-12-05 17:02:46 +0100 |
---|---|---|
committer | Uros Bizjak <ubizjak@gmail.com> | 2024-12-05 17:13:55 +0100 |
commit | b3cb0c3302a7c16e661a08c15c897c8f7bbb5d23 (patch) | |
tree | 64d702d9e830d4f297c7938fe07daced3441e81a /gcc | |
parent | a92b2be97f369ae4c6e1cdcbb7a45525994afaad (diff) | |
download | gcc-b3cb0c3302a7c16e661a08c15c897c8f7bbb5d23.zip gcc-b3cb0c3302a7c16e661a08c15c897c8f7bbb5d23.tar.gz gcc-b3cb0c3302a7c16e661a08c15c897c8f7bbb5d23.tar.bz2 |
i386: Fix addcarry/subborrow issues [PR117860]
Fix several things to enable combine to handle addcarry/subborrow patterns:
- Fix wrong canonical form of addcarry<mode> insn and friends. For
commutative operand (PLUS RTX) binary operand (LTU) takes precedence before
unary operand (ZERO_EXTEND).
- Swap operands of GTU comparison to canonicalize addcarry/subborrow
comparison. Again, the canonical form of the compare is PLUS RTX before
ZERO_EXTEND RTX. GTU comparison is not a carry flag comparison, so we have
to swap operands in x86_canonicalize_comparison to a non-canonical form
to use LTU comparison.
- Return correct compare mode (CCCmode) for addcarry/subborrow pattern
from ix86_cc_mode, so combine is able to emit required compare mode for
combined insn.
- Add *subborrow<mode>_1 pattern having const_scalar_int_operand predicate.
Here, canonicalization of SUB (op1, const) RTX to PLUS (op1, -const) requires
negation of constant operand when ckecking operands.
With the above changes, combine is able to create *addcarry_1/*subborrow_1
pattern with immediate operand for the testcase in the PR:
SomeAddFunc:
addq %rcx, %rsi # 10 [c=4 l=3] adddi3_cc_overflow_1/0
movq %rdi, %rax # 33 [c=4 l=3] *movdi_internal/3
adcq $5, %rdx # 19 [c=4 l=4] *addcarrydi_1/0
movq %rsi, (%rdi) # 23 [c=4 l=3] *movdi_internal/5
movq %rdx, 8(%rdi) # 24 [c=4 l=4] *movdi_internal/5
setc %dl # 39 [c=4 l=3] *setcc_qi
movzbl %dl, %edx # 40 [c=4 l=3] zero_extendqidi2/0
movq %rdx, 16(%rdi) # 26 [c=4 l=4] *movdi_internal/5
ret # 43 [c=0 l=1] simple_return_internal
SomeSubFunc:
subq %rcx, %rsi # 10 [c=4 l=3] *subdi_3/0
movq %rdi, %rax # 42 [c=4 l=3] *movdi_internal/3
sbbq $17, %rdx # 19 [c=4 l=4] *subborrowdi_1/0
movq %rsi, (%rdi) # 33 [c=4 l=3] *movdi_internal/5
sbbq %rcx, %rcx # 29 [c=8 l=3] *x86_movdicc_0_m1_neg
movq %rdx, 8(%rdi) # 34 [c=4 l=4] *movdi_internal/5
movq %rcx, 16(%rdi) # 35 [c=4 l=4] *movdi_internal/5
ret # 51 [c=0 l=1] simple_return_internal
PR target/117860
gcc/ChangeLog:
* config/i386/i386.cc (ix86_canonicalize_comparison): Swap
operands of GTU comparison to canonicalize addcarry/subborrow
comparison.
(ix86_cc_mode): Return CCCmode for the comparison of
addcarry/subborrow pattern.
* config/i386/i386.md (addcarry<mode>): Swap operands of
PLUS RTX to make it canonical.
(*addcarry<mode>_1): Ditto.
(addcarry peephole2s): Update RTXes for addcarry<mode>_1 change.
(*add<dwi>3_doubleword_cc_overflow_1): Ditto.
(*subborrow<mode>_1): New insn pattern.
gcc/testsuite/ChangeLog:
* gcc.target/i386/pr117860.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/i386/i386.cc | 23 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 85 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr117860.c | 52 |
3 files changed, 140 insertions, 20 deletions
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 0beeb51..23ff16b 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -578,11 +578,25 @@ ix86_canonicalize_comparison (int *code, rtx *op0, rtx *op1, { std::swap (*op0, *op1); *code = (int) scode; + return; } } + + /* Swap operands of GTU comparison to canonicalize + addcarry/subborrow comparison. */ + if (!op0_preserve_value + && *code == GTU + && GET_CODE (*op0) == PLUS + && ix86_carry_flag_operator (XEXP (*op0, 0), VOIDmode) + && GET_CODE (XEXP (*op0, 1)) == ZERO_EXTEND + && GET_CODE (*op1) == ZERO_EXTEND) + { + std::swap (*op0, *op1); + *code = (int) swap_condition ((enum rtx_code) *code); + return; + } } - /* Hook to determine if one function can safely inline another. */ static bool @@ -16479,6 +16493,13 @@ ix86_cc_mode (enum rtx_code code, rtx op0, rtx op1) && GET_CODE (op1) == GEU && GET_MODE (XEXP (op1, 0)) == CCCmode) return CCCmode; + /* Similarly for the comparison of addcarry/subborrow pattern. */ + else if (code == LTU + && GET_CODE (op0) == ZERO_EXTEND + && GET_CODE (op1) == PLUS + && ix86_carry_flag_operator (XEXP (op1, 0), VOIDmode) + && GET_CODE (XEXP (op1, 1)) == ZERO_EXTEND) + return CCCmode; else return CCmode; case GTU: /* CF=0 & ZF=0 */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index ffbb107..ec816be 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -9036,12 +9036,12 @@ (match_operand:SWI48 1 "nonimmediate_operand" "%0,0,rm,r")) (match_operand:SWI48 2 "nonimmediate_operand" "r,rm,r,m"))) (plus:<DWI> - (zero_extend:<DWI> (match_dup 2)) (match_operator:<DWI> 4 "ix86_carry_flag_operator" - [(match_dup 3) (const_int 0)])))) + [(match_dup 3) (const_int 0)]) + (zero_extend:<DWI> (match_dup 2))))) (set (match_operand:SWI48 0 "nonimmediate_operand" "=rm,r,r,r") (plus:SWI48 (plus:SWI48 (match_op_dup 5 - [(match_dup 3) (const_int 0)]) + [(match_dup 3) (const_int 0)]) (match_dup 1)) (match_dup 2)))] "ix86_binary_operator_ok (PLUS, <MODE>mode, operands, TARGET_APX_NDD)" @@ -9068,9 +9068,9 @@ (match_operand:SWI48 0 "general_reg_operand")) (match_operand:SWI48 1 "memory_operand"))) (plus:<DWI> - (zero_extend:<DWI> (match_dup 1)) (match_operator:<DWI> 3 "ix86_carry_flag_operator" - [(match_dup 2) (const_int 0)])))) + [(match_dup 2) (const_int 0)]) + (zero_extend:<DWI> (match_dup 1))))) (set (match_dup 0) (plus:SWI48 (plus:SWI48 (match_op_dup 4 [(match_dup 2) (const_int 0)]) @@ -9090,9 +9090,9 @@ (match_dup 1)) (match_dup 0))) (plus:<DWI> - (zero_extend:<DWI> (match_dup 0)) (match_op_dup 3 - [(match_dup 2) (const_int 0)])))) + [(match_dup 2) (const_int 0)]) + (zero_extend:<DWI> (match_dup 0))))) (set (match_dup 1) (plus:SWI48 (plus:SWI48 (match_op_dup 4 [(match_dup 2) (const_int 0)]) @@ -9113,9 +9113,9 @@ (match_dup 0)) (match_operand:SWI48 2 "memory_operand"))) (plus:<DWI> - (zero_extend:<DWI> (match_dup 2)) (match_operator:<DWI> 4 "ix86_carry_flag_operator" - [(match_dup 3) (const_int 0)])))) + [(match_dup 3) (const_int 0)]) + (zero_extend:<DWI> (match_dup 2))))) (set (match_dup 0) (plus:SWI48 (plus:SWI48 (match_op_dup 5 [(match_dup 3) (const_int 0)]) @@ -9137,9 +9137,9 @@ (match_dup 1)) (match_dup 0))) (plus:<DWI> - (zero_extend:<DWI> (match_dup 0)) (match_op_dup 4 - [(match_dup 3) (const_int 0)])))) + [(match_dup 3) (const_int 0)]) + (zero_extend:<DWI> (match_dup 0))))) (set (match_dup 1) (plus:SWI48 (plus:SWI48 (match_op_dup 5 [(match_dup 3) (const_int 0)]) @@ -9158,9 +9158,9 @@ (match_operand:SWI48 0 "general_reg_operand")) (match_operand:SWI48 1 "memory_operand"))) (plus:<DWI> - (zero_extend:<DWI> (match_dup 1)) (match_operator:<DWI> 3 "ix86_carry_flag_operator" - [(match_dup 2) (const_int 0)])))) + [(match_dup 2) (const_int 0)]) + (zero_extend:<DWI> (match_dup 1))))) (set (match_dup 0) (plus:SWI48 (plus:SWI48 (match_op_dup 4 [(match_dup 2) (const_int 0)]) @@ -9188,9 +9188,9 @@ (match_dup 1)) (match_dup 0))) (plus:<DWI> - (zero_extend:<DWI> (match_dup 0)) (match_op_dup 3 - [(match_dup 2) (const_int 0)])))) + [(match_dup 2) (const_int 0)]) + (zero_extend:<DWI> (match_dup 0))))) (set (match_dup 1) (plus:SWI48 (plus:SWI48 (match_op_dup 4 [(match_dup 2) (const_int 0)]) @@ -9222,9 +9222,9 @@ (match_operand:SWI48 1 "nonimmediate_operand" "%0,rm")) (match_operand:SWI48 2 "x86_64_immediate_operand" "e,e"))) (plus:<DWI> - (match_operand:<DWI> 6 "const_scalar_int_operand") (match_operator:<DWI> 4 "ix86_carry_flag_operator" - [(match_dup 3) (const_int 0)])))) + [(match_dup 3) (const_int 0)]) + (match_operand:<DWI> 6 "const_scalar_int_operand")))) (set (match_operand:SWI48 0 "nonimmediate_operand" "=rm,r") (plus:SWI48 (plus:SWI48 (match_op_dup 5 [(match_dup 3) (const_int 0)]) @@ -9748,6 +9748,53 @@ (minus:SWI48 (match_dup 1) (match_dup 2)))])] "ix86_binary_operator_ok (MINUS, <MODE>mode, operands, TARGET_APX_NDD)") +(define_insn "*subborrow<mode>_1" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend:<DWI> + (match_operand:SWI48 1 "nonimmediate_operand" "0,rm")) + (plus:<DWI> + (match_operator:<DWI> 4 "ix86_carry_flag_operator" + [(match_operand 3 "flags_reg_operand") (const_int 0)]) + (match_operand:<DWI> 6 "const_scalar_int_operand")))) + (set (match_operand:SWI48 0 "nonimmediate_operand" "=rm,r") + (plus:SWI48 (minus:SWI48 + (match_dup 1) + (match_operator:SWI48 5 "ix86_carry_flag_operator" + [(match_dup 3) (const_int 0)])) + (match_operand:SWI48 2 "x86_64_immediate_operand" "e,e")))] + "ix86_binary_operator_ok (MINUS, <MODE>mode, operands, TARGET_APX_NDD) + && CONST_INT_P (operands[2]) + /* Check that operands[6] is -operands[2] zero extended from + <MODE>mode to <DWI>mode. */ + && ((<MODE>mode == SImode || -INTVAL (operands[2]) >= 0) + ? (CONST_INT_P (operands[6]) + && (UINTVAL (operands[6]) + == ((unsigned HOST_WIDE_INT) -INTVAL (operands[2]) + & GET_MODE_MASK (<MODE>mode)))) + : (CONST_WIDE_INT_P (operands[6]) + && CONST_WIDE_INT_NUNITS (operands[6]) == 2 + && ((unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (operands[6], 0) + == (unsigned HOST_WIDE_INT) -INTVAL (operands[2])) + && CONST_WIDE_INT_ELT (operands[6], 1) == 0))" +{ + bool use_ndd = get_attr_isa (insn) == ISA_APX_NDD; + + operands[2] = GEN_INT (-INTVAL (operands[2])); + + return use_ndd ? "sbb{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}" + : "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"; +} + [(set_attr "isa" "*,apx_ndd") + (set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "<MODE>") + (set (attr "length_immediate") + (if_then_else (match_test "IN_RANGE (-INTVAL (operands[2]), -128, 127)") + (const_string "1") + (const_string "4")))]) + (define_expand "uaddc<mode>5" [(match_operand:SWI48 0 "register_operand") (match_operand:SWI48 1 "register_operand") @@ -10040,8 +10087,8 @@ (match_dup 4)) (match_dup 5))) (plus:<DWI> - (match_dup 6) - (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))))) + (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0)) + (match_dup 6)))) (set (match_dup 3) (plus:DWIH (plus:DWIH (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)) diff --git a/gcc/testsuite/gcc.target/i386/pr117860.c b/gcc/testsuite/gcc.target/i386/pr117860.c new file mode 100644 index 0000000..22ed0af --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr117860.c @@ -0,0 +1,52 @@ +/* PR target/117116 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -masm=att" } */ + +#include <stdint.h> + +#if (defined(__GNUC__) || defined(__clang__)) +#include <immintrin.h> +#elif defined(_MSC_VER) +#include <intrin.h> +#endif + +typedef struct { + uint64_t lo64; + uint64_t mid64; + uint64_t hi64; +} UInt192; + +UInt192 SomeAddFunc(uint64_t a_lo, uint64_t a_hi, uint64_t b) { + UInt192 result; + unsigned char cf; + unsigned long long sum; + + cf = _addcarry_u64(0, a_lo, b, &sum); + result.lo64 = sum; + + cf = _addcarry_u64(cf, a_hi, 5, &sum); + result.mid64 = sum; + result.hi64 = cf; + + return result; +} + +/* { dg-final { scan-assembler "adcq\[ \\t\]+\\\$5," } } */ + +UInt192 SomeSubFunc(uint64_t a_lo, uint64_t a_hi, uint64_t b) { + UInt192 result; + unsigned char cf; + unsigned long long diff; + + cf = _subborrow_u64(0, a_lo, b, &diff); + result.lo64 = diff; + + cf = _subborrow_u64(cf, a_hi, 17, &diff); + result.mid64 = diff; + (void)_subborrow_u64(cf, 0, 0, &diff); + result.hi64 = diff; + + return result; +} + +/* { dg-final { scan-assembler "sbbq\[ \\t\]+\\\$17," } } */ |