The rtl description of signed/unsigned overflow from subtract
was fine, as far as it goes -- we have CC_Cmode and CC_Vmode
that indicate that only those particular bits are valid.

However, it's not clear how to extend that description to
handle signed comparison, where N == V (GE) N != V (LT) are
the only valid bits.

Using an UNSPEC means that we can unify all 3 usages without
fear that combine will try to infer anything from the rtl.
It also means we need far fewer variants when various inputs
have constants propagated in, and the rtl folds.

Accept -1 for the second input by using ADCS.

        * config/aarch64/aarch64.md (UNSPEC_SBCS): New.
        (cmp<GPI>3_carryin): New expander.
        (sub<GPI>3_carryin_cmp): New expander.
        (*cmp<GPI>3_carryin): New pattern.
        (*cmp<GPI>3_carryin_0): New pattern.
        (*sub<GPI>3_carryin_cmp): New pattern.
        (*sub<GPI>3_carryin_cmp_0): New pattern.
        (subvti4, usubvti4, negvti3): Use subdi3_carryin_cmp.
        (negvdi_carryinV): Remove.
        (usub<GPI>3_carryinC): Remove.
        (*usub<GPI>3_carryinC): Remove.
        (*usub<GPI>3_carryinC_z1): Remove.
        (*usub<GPI>3_carryinC_z2): Remove.
        (sub<GPI>3_carryinV): Remove.
        (*sub<GPI>3_carryinV): Remove.
        (*sub<GPI>3_carryinV_z2): Remove.
        * config/aarch64/predicates.md (aarch64_reg_zero_minus1): New.
---
 gcc/config/aarch64/aarch64.md    | 217 +++++++++++++------------------
 gcc/config/aarch64/predicates.md |   7 +
 2 files changed, 94 insertions(+), 130 deletions(-)

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 532c114a42e..564dea390be 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -281,6 +281,7 @@
     UNSPEC_GEN_TAG_RND         ; Generate a random 4-bit MTE tag.
     UNSPEC_TAG_SPACE           ; Translate address to MTE tag address space.
     UNSPEC_LD1RO
+    UNSPEC_SBCS
 ])
 
 (define_c_enum "unspecv" [
@@ -2942,7 +2943,7 @@
   aarch64_expand_addsubti (operands[0], operands[1], operands[2],
                           CODE_FOR_subvdi_insn,
                           CODE_FOR_subdi3_compare1,
-                          CODE_FOR_subdi3_carryinV);
+                          CODE_FOR_subdi3_carryin_cmp);
   aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
   DONE;
 })
@@ -2957,7 +2958,7 @@
   aarch64_expand_addsubti (operands[0], operands[1], operands[2],
                           CODE_FOR_subdi3_compare1,
                           CODE_FOR_subdi3_compare1,
-                          CODE_FOR_usubdi3_carryinC);
+                          CODE_FOR_subdi3_carryin_cmp);
   aarch64_gen_unlikely_cbranch (LTU, CCmode, operands[3]);
   DONE;
 })
@@ -2968,12 +2969,14 @@
    (label_ref (match_operand 2 "" ""))]
   ""
   {
-    emit_insn (gen_negdi_carryout (gen_lowpart (DImode, operands[0]),
-                                  gen_lowpart (DImode, operands[1])));
-    emit_insn (gen_negvdi_carryinV (gen_highpart (DImode, operands[0]),
-                                   gen_highpart (DImode, operands[1])));
-    aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[2]);
+    rtx op0l = gen_lowpart (DImode, operands[0]);
+    rtx op1l = gen_lowpart (DImode, operands[1]);
+    rtx op0h = gen_highpart (DImode, operands[0]);
+    rtx op1h = gen_highpart (DImode, operands[1]);
 
+    emit_insn (gen_negdi_carryout (op0l, op1l));
+    emit_insn (gen_subdi3_carryin_cmp (op0h, const0_rtx, op1h));
+    aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[2]);
     DONE;
   }
 )
@@ -2989,23 +2992,6 @@
   [(set_attr "type" "alus_sreg")]
 )
 
-(define_insn "negvdi_carryinV"
-  [(set (reg:CC_V CC_REGNUM)
-       (compare:CC_V
-        (neg:TI (plus:TI
-                 (ltu:TI (reg:CC CC_REGNUM) (const_int 0))
-                 (sign_extend:TI (match_operand:DI 1 "register_operand" "r"))))
-        (sign_extend:TI
-         (neg:DI (plus:DI (ltu:DI (reg:CC CC_REGNUM) (const_int 0))
-                          (match_dup 1))))))
-   (set (match_operand:DI 0 "register_operand" "=r")
-       (neg:DI (plus:DI (ltu:DI (reg:CC CC_REGNUM) (const_int 0))
-                        (match_dup 1))))]
-  ""
-  "ngcs\\t%0, %1"
-  [(set_attr "type" "alus_sreg")]
-)
-
 (define_insn "*sub<mode>3_compare0"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ (minus:GPI (match_operand:GPI 1 "register_operand" "rk")
@@ -3370,134 +3356,105 @@
   [(set_attr "type" "adc_reg")]
 )
 
-(define_expand "usub<GPI:mode>3_carryinC"
+(define_expand "sub<mode>3_carryin_cmp"
   [(parallel
-     [(set (reg:CC CC_REGNUM)
-          (compare:CC
-            (zero_extend:<DWI>
-              (match_operand:GPI 1 "aarch64_reg_or_zero"))
-            (plus:<DWI>
-              (zero_extend:<DWI>
-                (match_operand:GPI 2 "register_operand"))
-              (ltu:<DWI> (reg:CC CC_REGNUM) (const_int 0)))))
-      (set (match_operand:GPI 0 "register_operand")
-          (minus:GPI
-            (minus:GPI (match_dup 1) (match_dup 2))
-            (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))))])]
+    [(set (match_dup 3)
+         (unspec:CC
+           [(match_operand:GPI 1 "aarch64_reg_or_zero")
+            (match_operand:GPI 2 "aarch64_reg_zero_minus1")
+            (match_dup 4)]
+           UNSPEC_SBCS))
+     (set (match_operand:GPI 0 "register_operand" "=r")
+         (unspec:GPI
+           [(match_dup 1) (match_dup 2) (match_dup 4)]
+           UNSPEC_SBCS))])]
    ""
+  {
+    operands[3] = gen_rtx_REG (CCmode, CC_REGNUM);
+    operands[4] = gen_rtx_LTU (<MODE>mode, operands[3], const0_rtx);
+  }
 )
 
-(define_insn "*usub<GPI:mode>3_carryinC_z1"
+(define_insn "*sub<mode>3_carryin_cmp"
   [(set (reg:CC CC_REGNUM)
-       (compare:CC
-         (const_int 0)
-         (plus:<DWI>
-           (zero_extend:<DWI>
-             (match_operand:GPI 1 "register_operand" "r"))
-           (match_operand:<DWI> 2 "aarch64_borrow_operation" ""))))
-   (set (match_operand:GPI 0 "register_operand" "=r")
-       (minus:GPI
-         (neg:GPI (match_dup 1))
-         (match_operand:GPI 3 "aarch64_borrow_operation" "")))]
+       (unspec:CC
+         [(match_operand:GPI 1 "aarch64_reg_or_zero" "rZ,rZ")
+          (match_operand:GPI 2 "aarch64_reg_zero_minus1" "rZ,UsM")
+          (match_operand:GPI 3 "aarch64_borrow_operation" "")]
+         UNSPEC_SBCS))
+   (set (match_operand:GPI 0 "register_operand" "=r,r")
+       (unspec:GPI
+         [(match_dup 1) (match_dup 2) (match_dup 3)]
+         UNSPEC_SBCS))]
    ""
-   "sbcs\\t%<w>0, <w>zr, %<w>1"
+   "@
+    sbcs\\t%<w>0, %<w>1, %<w>2
+    adcs\\t%<w>0, %<w>1, <w>zr"
   [(set_attr "type" "adc_reg")]
 )
 
-(define_insn "*usub<GPI:mode>3_carryinC_z2"
+(define_expand "cmp<mode>3_carryin"
   [(set (reg:CC CC_REGNUM)
-       (compare:CC
-         (zero_extend:<DWI>
-           (match_operand:GPI 1 "register_operand" "r"))
-         (match_operand:<DWI> 2 "aarch64_borrow_operation" "")))
-   (set (match_operand:GPI 0 "register_operand" "=r")
-       (minus:GPI
-         (match_dup 1)
-         (match_operand:GPI 3 "aarch64_borrow_operation" "")))]
+       (unspec:CC
+         [(match_operand:GPI 0 "aarch64_reg_or_zero")
+          (match_operand:GPI 1 "aarch64_reg_zero_minus1")
+          (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))]
+         UNSPEC_SBCS))]
    ""
-   "sbcs\\t%<w>0, %<w>1, <w>zr"
-  [(set_attr "type" "adc_reg")]
 )
 
-(define_insn "*usub<GPI:mode>3_carryinC"
+(define_insn "*cmp<mode>3_carryin"
   [(set (reg:CC CC_REGNUM)
-       (compare:CC
-         (zero_extend:<DWI>
-           (match_operand:GPI 1 "register_operand" "r"))
-         (plus:<DWI>
-           (zero_extend:<DWI>
-             (match_operand:GPI 2 "register_operand" "r"))
-           (match_operand:<DWI> 3 "aarch64_borrow_operation" ""))))
-   (set (match_operand:GPI 0 "register_operand" "=r")
-       (minus:GPI
-         (minus:GPI (match_dup 1) (match_dup 2))
-         (match_operand:GPI 4 "aarch64_borrow_operation" "")))]
+       (unspec:CC
+         [(match_operand:GPI 0 "aarch64_reg_or_zero" "rZ,rZ")
+          (match_operand:GPI 1 "aarch64_reg_zero_minus1" "rZ,UsM")
+          (match_operand:GPI 2 "aarch64_borrow_operation" "")]
+         UNSPEC_SBCS))]
    ""
-   "sbcs\\t%<w>0, %<w>1, %<w>2"
+   "@
+    sbcs\\t<w>zr, %<w>0, %<w>1
+    adcs\\t<w>zr, %<w>0, <w>zr"
   [(set_attr "type" "adc_reg")]
 )
 
-(define_expand "sub<GPI:mode>3_carryinV"
-  [(parallel
-     [(set (reg:CC_V CC_REGNUM)
-          (compare:CC_V
-           (minus:<DWI>
-            (sign_extend:<DWI>
-              (match_operand:GPI 1 "aarch64_reg_or_zero"))
-            (plus:<DWI>
-              (sign_extend:<DWI>
-                (match_operand:GPI 2 "register_operand"))
-              (ltu:<DWI> (reg:CC CC_REGNUM) (const_int 0))))
-           (sign_extend:<DWI>
-            (minus:GPI (match_dup 1)
-                       (plus:GPI (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))
-                                 (match_dup 2))))))
-      (set (match_operand:GPI 0 "register_operand")
-          (minus:GPI
-            (minus:GPI (match_dup 1) (match_dup 2))
-            (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))))])]
-   ""
+;; If combine can show that the borrow is 0, fold SBCS to SUBS.
+(define_insn_and_split "*sub<mode>3_carryin_cmp_0"
+  [(set (reg:CC CC_REGNUM)
+       (unspec:CC
+         [(match_operand:GPI 1 "aarch64_reg_or_zero" "rk,rkZ")
+          (match_operand:GPI 2 "aarch64_plus_immediate" "rIJ,r")
+          (const_int 0)]
+         UNSPEC_SBCS))
+   (set (match_operand:GPI 0 "register_operand")
+       (unspec:GPI
+         [(match_dup 1) (match_dup 2) (const_int 0)]
+         UNSPEC_SBCS))]
+  ""
+  "#"
+  ""
+  [(scratch)]
+  {
+    emit_insn (gen_sub<mode>3_compare1 (operands[0], operands[1],
+                                       operands[2]));
+    DONE;
+  }
 )
 
-(define_insn "*sub<mode>3_carryinV_z2"
-  [(set (reg:CC_V CC_REGNUM)
-       (compare:CC_V
-        (minus:<DWI>
-         (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))
-         (match_operand:<DWI> 2 "aarch64_borrow_operation" ""))
-        (sign_extend:<DWI>
-         (minus:GPI (match_dup 1)
-                    (match_operand:GPI 3 "aarch64_borrow_operation" "")))))
-   (set (match_operand:GPI 0 "register_operand" "=r")
-       (minus:GPI
-        (match_dup 1) (match_dup 3)))]
+(define_insn_and_split "*cmp<mode>3_carryin_0"
+  [(set (reg:CC CC_REGNUM)
+       (unspec:CC
+         [(match_operand:GPI 0 "aarch64_reg_or_zero" "rk,rZ")
+          (match_operand:GPI 1 "aarch64_plus_operand" "rIJ,r")
+          (const_int 0)]
+         UNSPEC_SBCS))]
    ""
-   "sbcs\\t%<w>0, %<w>1, <w>zr"
-  [(set_attr "type" "adc_reg")]
-)
-
-(define_insn "*sub<mode>3_carryinV"
-  [(set (reg:CC_V CC_REGNUM)
-       (compare:CC_V
-        (minus:<DWI>
-         (sign_extend:<DWI>
-           (match_operand:GPI 1 "register_operand" "r"))
-         (plus:<DWI>
-           (sign_extend:<DWI>
-             (match_operand:GPI 2 "register_operand" "r"))
-           (match_operand:<DWI> 3 "aarch64_borrow_operation" "")))
-        (sign_extend:<DWI>
-         (minus:GPI
-          (match_dup 1)
-          (plus:GPI (match_operand:GPI 4 "aarch64_borrow_operation" "")
-                    (match_dup 2))))))
-   (set (match_operand:GPI 0 "register_operand" "=r")
-       (minus:GPI
-         (minus:GPI (match_dup 1) (match_dup 2))
-         (match_dup 4)))]
+   "#"
    ""
-   "sbcs\\t%<w>0, %<w>1, %<w>2"
-  [(set_attr "type" "adc_reg")]
+  [(scratch)]
+  {
+    emit_insn (gen_cmp<mode> (operands[0], operands[1]));
+    DONE;
+  }
 )
 
 (define_insn "*sub_uxt<mode>_shift2"
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 215fcec5955..5f44ef7d672 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -68,6 +68,13 @@
        (ior (match_operand 0 "register_operand")
            (match_test "op == CONST0_RTX (GET_MODE (op))"))))
 
+(define_predicate "aarch64_reg_zero_minus1"
+  (and (match_code "reg,subreg,const_int")
+       (ior (match_operand 0 "register_operand")
+           (ior (match_test "op == CONST0_RTX (GET_MODE (op))")
+                (match_test "op == CONSTM1_RTX (GET_MODE (op))")))))
+
+
 (define_predicate "aarch64_reg_or_fp_zero"
   (ior (match_operand 0 "register_operand")
        (and (match_code "const_double")
-- 
2.20.1

Reply via email to