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 checking 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.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

Uros.
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 0beeb514cf9..23ff16b4081 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 ffbb10730c0..ec816be6182 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -9036,12 +9036,12 @@ (define_insn "addcarry<mode>"
                (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 @@ (define_peephole2
                           (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 @@ (define_peephole2
                           (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 @@ (define_peephole2
                           (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 @@ (define_peephole2
                           (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 @@ (define_peephole2
                           (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 @@ (define_peephole2
                           (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 @@ (define_insn "*addcarry<mode>_1"
                (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 @@ (define_expand "subborrow<mode>_0"
           (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 @@ (define_insn_and_split 
"*add<dwi>3_doubleword_cc_overflow_1"
                           (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 00000000000..22ed0af0680
--- /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," } } */

Reply via email to