[llvm] [AArch64] Add patterns for selecing dec from sub (PR #209467)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 06:03:00 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: John Brawn (john-brawn-arm)

<details>
<summary>Changes</summary>

Currently we have patterns to select the SVE dec instruction from an add of a negative vscale, but when vscale is used more than once we get a sub of a positive vscale, so add patterns for that. Also restructure to use a multiclass to reduce the amount of duplication.

---
Full diff: https://github.com/llvm/llvm-project/pull/209467.diff


2 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td (+36-37) 
- (modified) llvm/test/CodeGen/AArch64/sve-vl-arith.ll (+280) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
index 26b0a38f6bae0..a38b551228743 100644
--- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
@@ -2988,6 +2988,14 @@ let Predicates = [HasSVE_or_SME] in {
                 (EXTRACT_SUBREG (DECB_XPiI (INSERT_SUBREG (IMPLICIT_DEF),
                                             GPR32:$op, sub_32), 31, imm),
                                  sub_32)>;
+
+      def : Pat<(sub GPR64:$op, (vscale !mul(imm, 16))),
+                (DECB_XPiI GPR64:$op, 31, imm)>;
+
+      def : Pat<(sub GPR32:$op, (i32 (trunc (vscale !mul(imm, 16))))),
+                (EXTRACT_SUBREG (DECB_XPiI (INSERT_SUBREG (IMPLICIT_DEF),
+                                            GPR32:$op, sub_32), 31, imm),
+                                 sub_32)>;
       }
   }
 
@@ -3000,45 +3008,36 @@ let Predicates = [HasSVE_or_SME] in {
                                         GPR32:$op, sub_32), $imm),
                               sub_32)>;
 
-    def : Pat<(add GPR64:$op, (vscale (sve_cnth_imm i32:$imm))),
-              (INCH_XPiI GPR64:$op, 31, $imm)>;
-    def : Pat<(add GPR64:$op, (vscale (sve_cntw_imm i32:$imm))),
-              (INCW_XPiI GPR64:$op, 31, $imm)>;
-    def : Pat<(add GPR64:$op, (vscale (sve_cntd_imm i32:$imm))),
-              (INCD_XPiI GPR64:$op, 31, $imm)>;
+    multiclass incDecPat<Instruction inc, Instruction dec,
+                         ComplexPattern imm_pat, ComplexPattern imm_pat_neg> {
+      def : Pat<(add GPR64:$op, (vscale (imm_pat i32:$imm))),
+                (inc GPR64:$op, 31, $imm)>;
 
-    def : Pat<(add GPR64:$op, (vscale (sve_cnth_imm_neg i32:$imm))),
-              (DECH_XPiI GPR64:$op, 31, $imm)>;
-    def : Pat<(add GPR64:$op, (vscale (sve_cntw_imm_neg i32:$imm))),
-              (DECW_XPiI GPR64:$op, 31, $imm)>;
-    def : Pat<(add GPR64:$op, (vscale (sve_cntd_imm_neg i32:$imm))),
-              (DECD_XPiI GPR64:$op, 31, $imm)>;
-
-    def : Pat<(add GPR32:$op, (i32 (trunc (vscale (sve_cnth_imm i32:$imm))))),
-              (EXTRACT_SUBREG (INCH_XPiI (INSERT_SUBREG (IMPLICIT_DEF),
-                                          GPR32:$op, sub_32), 31, $imm),
-                               sub_32)>;
-    def : Pat<(add GPR32:$op, (i32 (trunc (vscale (sve_cntw_imm i32:$imm))))),
-              (EXTRACT_SUBREG (INCW_XPiI (INSERT_SUBREG (IMPLICIT_DEF),
-                                          GPR32:$op, sub_32), 31, $imm),
-                               sub_32)>;
-    def : Pat<(add GPR32:$op, (i32 (trunc (vscale (sve_cntd_imm i32:$imm))))),
-              (EXTRACT_SUBREG (INCD_XPiI (INSERT_SUBREG (IMPLICIT_DEF),
-                                          GPR32:$op, sub_32), 31, $imm),
-                               sub_32)>;
+      def : Pat<(add GPR64:$op, (vscale (imm_pat_neg i32:$imm))),
+                (dec GPR64:$op, 31, $imm)>;
 
-    def : Pat<(add GPR32:$op, (i32 (trunc (vscale (sve_cnth_imm_neg i32:$imm))))),
-              (EXTRACT_SUBREG (DECH_XPiI (INSERT_SUBREG (IMPLICIT_DEF),
-                                          GPR32:$op, sub_32), 31, $imm),
-                               sub_32)>;
-    def : Pat<(add GPR32:$op, (i32 (trunc (vscale (sve_cntw_imm_neg i32:$imm))))),
-              (EXTRACT_SUBREG (DECW_XPiI (INSERT_SUBREG (IMPLICIT_DEF),
-                                          GPR32:$op, sub_32), 31, $imm),
-                               sub_32)>;
-    def : Pat<(add GPR32:$op, (i32 (trunc (vscale (sve_cntd_imm_neg i32:$imm))))),
-              (EXTRACT_SUBREG (DECD_XPiI (INSERT_SUBREG (IMPLICIT_DEF),
-                                          GPR32:$op, sub_32), 31, $imm),
-                               sub_32)>;
+      def : Pat<(sub GPR64:$op, (vscale (imm_pat i32:$imm))),
+                (dec GPR64:$op, 31, $imm)>;
+
+      def : Pat<(add GPR32:$op, (i32 (trunc (vscale (imm_pat i32:$imm))))),
+                (EXTRACT_SUBREG (inc (INSERT_SUBREG (IMPLICIT_DEF),
+                                      GPR32:$op, sub_32), 31, $imm),
+                                 sub_32)>;
+
+      def : Pat<(add GPR32:$op, (i32 (trunc (vscale (imm_pat_neg i32:$imm))))),
+                (EXTRACT_SUBREG (dec (INSERT_SUBREG (IMPLICIT_DEF),
+                                      GPR32:$op, sub_32), 31, $imm),
+                                 sub_32)>;
+
+      def : Pat<(sub GPR32:$op, (i32 (trunc (vscale (imm_pat i32:$imm))))),
+                (EXTRACT_SUBREG (dec (INSERT_SUBREG (IMPLICIT_DEF),
+                                      GPR32:$op, sub_32), 31, $imm),
+                                 sub_32)>;
+    }
+
+    defm : incDecPat<INCH_XPiI, DECH_XPiI, sve_cnth_imm, sve_cnth_imm_neg>;
+    defm : incDecPat<INCW_XPiI, DECW_XPiI, sve_cntw_imm, sve_cntw_imm_neg>;
+    defm : incDecPat<INCD_XPiI, DECD_XPiI, sve_cntd_imm, sve_cntd_imm_neg>;
   }
 
   // For big endian, only BITCASTs involving same sized vector types with same
diff --git a/llvm/test/CodeGen/AArch64/sve-vl-arith.ll b/llvm/test/CodeGen/AArch64/sve-vl-arith.ll
index 0a9f4948a5f77..40ac0066ba0e4 100644
--- a/llvm/test/CodeGen/AArch64/sve-vl-arith.ll
+++ b/llvm/test/CodeGen/AArch64/sve-vl-arith.ll
@@ -551,6 +551,286 @@ define i32 @decd_scalar_i32(i32 %a) {
   ret i32 %sub
 }
 
+define void @decb_incb_scalar_i64(i64 %a, ptr %p) {
+; NO_SCALAR_INC-LABEL: decb_incb_scalar_i64:
+; NO_SCALAR_INC:       // %bb.0:
+; NO_SCALAR_INC-NEXT:    rdvl x8, #1
+; NO_SCALAR_INC-NEXT:    add x9, x0, x8
+; NO_SCALAR_INC-NEXT:    sub x8, x1, x8
+; NO_SCALAR_INC-NEXT:    str x9, [x8]
+; NO_SCALAR_INC-NEXT:    ret
+;
+; CHECK-LABEL: decb_incb_scalar_i64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    incb x0
+; CHECK-NEXT:    decb x1
+; CHECK-NEXT:    str x0, [x1]
+; CHECK-NEXT:    ret
+;
+; NO_FAST_INC-LABEL: decb_incb_scalar_i64:
+; NO_FAST_INC:       // %bb.0:
+; NO_FAST_INC-NEXT:    dech x1, all, mul #2
+; NO_FAST_INC-NEXT:    addvl x8, x0, #1
+; NO_FAST_INC-NEXT:    str x8, [x1]
+; NO_FAST_INC-NEXT:    ret
+  %vscale = call i64 @llvm.vscale.i64()
+  %mul = mul i64 %vscale, 16
+  %sub = sub i64 0, %mul
+  %add = add i64 %a, %mul
+  %gep = getelementptr i8, ptr %p, i64 %sub
+  store i64 %add, ptr %gep, align 1
+  ret void
+}
+
+define void @dech_inch_scalar_i64(i64 %a, ptr %p) {
+; NO_SCALAR_INC-LABEL: dech_inch_scalar_i64:
+; NO_SCALAR_INC:       // %bb.0:
+; NO_SCALAR_INC-NEXT:    cnth x8
+; NO_SCALAR_INC-NEXT:    add x9, x0, x8
+; NO_SCALAR_INC-NEXT:    sub x8, x1, x8
+; NO_SCALAR_INC-NEXT:    str x9, [x8]
+; NO_SCALAR_INC-NEXT:    ret
+;
+; CHECK-LABEL: dech_inch_scalar_i64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    inch x0
+; CHECK-NEXT:    dech x1
+; CHECK-NEXT:    str x0, [x1]
+; CHECK-NEXT:    ret
+;
+; NO_FAST_INC-LABEL: dech_inch_scalar_i64:
+; NO_FAST_INC:       // %bb.0:
+; NO_FAST_INC-NEXT:    inch x0
+; NO_FAST_INC-NEXT:    dech x1
+; NO_FAST_INC-NEXT:    str x0, [x1]
+; NO_FAST_INC-NEXT:    ret
+  %vscale = call i64 @llvm.vscale.i64()
+  %mul = mul i64 %vscale, 8
+  %sub = sub i64 0, %mul
+  %add = add i64 %a, %mul
+  %gep = getelementptr i8, ptr %p, i64 %sub
+  store i64 %add, ptr %gep, align 1
+  ret void
+}
+
+define void @decw_incw_scalar_i64(i64 %a, ptr %p) {
+; NO_SCALAR_INC-LABEL: decw_incw_scalar_i64:
+; NO_SCALAR_INC:       // %bb.0:
+; NO_SCALAR_INC-NEXT:    cntw x8
+; NO_SCALAR_INC-NEXT:    add x9, x0, x8
+; NO_SCALAR_INC-NEXT:    sub x8, x1, x8
+; NO_SCALAR_INC-NEXT:    str x9, [x8]
+; NO_SCALAR_INC-NEXT:    ret
+;
+; CHECK-LABEL: decw_incw_scalar_i64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    incw x0
+; CHECK-NEXT:    decw x1
+; CHECK-NEXT:    str x0, [x1]
+; CHECK-NEXT:    ret
+;
+; NO_FAST_INC-LABEL: decw_incw_scalar_i64:
+; NO_FAST_INC:       // %bb.0:
+; NO_FAST_INC-NEXT:    incw x0
+; NO_FAST_INC-NEXT:    decw x1
+; NO_FAST_INC-NEXT:    str x0, [x1]
+; NO_FAST_INC-NEXT:    ret
+  %vscale = call i64 @llvm.vscale.i64()
+  %mul = mul i64 %vscale, 4
+  %sub = sub i64 0, %mul
+  %add = add i64 %a, %mul
+  %gep = getelementptr i8, ptr %p, i64 %sub
+  store i64 %add, ptr %gep, align 1
+  ret void
+}
+
+define void @decd_incd_scalar_i64(i64 %a, ptr %p) {
+; NO_SCALAR_INC-LABEL: decd_incd_scalar_i64:
+; NO_SCALAR_INC:       // %bb.0:
+; NO_SCALAR_INC-NEXT:    cntd x8
+; NO_SCALAR_INC-NEXT:    add x9, x0, x8
+; NO_SCALAR_INC-NEXT:    sub x8, x1, x8
+; NO_SCALAR_INC-NEXT:    str x9, [x8]
+; NO_SCALAR_INC-NEXT:    ret
+;
+; CHECK-LABEL: decd_incd_scalar_i64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    incd x0
+; CHECK-NEXT:    decd x1
+; CHECK-NEXT:    str x0, [x1]
+; CHECK-NEXT:    ret
+;
+; NO_FAST_INC-LABEL: decd_incd_scalar_i64:
+; NO_FAST_INC:       // %bb.0:
+; NO_FAST_INC-NEXT:    incd x0
+; NO_FAST_INC-NEXT:    decd x1
+; NO_FAST_INC-NEXT:    str x0, [x1]
+; NO_FAST_INC-NEXT:    ret
+  %vscale = call i64 @llvm.vscale.i64()
+  %mul = mul i64 %vscale, 2
+  %sub = sub i64 0, %mul
+  %add = add i64 %a, %mul
+  %gep = getelementptr i8, ptr %p, i64 %sub
+  store i64 %add, ptr %gep, align 1
+  ret void
+}
+
+define void @decb_incb_scalar_i32(i32 %a, i32 %b, ptr %p, ptr %q) {
+; NO_SCALAR_INC-LABEL: decb_incb_scalar_i32:
+; NO_SCALAR_INC:       // %bb.0:
+; NO_SCALAR_INC-NEXT:    rdvl x8, #1
+; NO_SCALAR_INC-NEXT:    sub w9, w0, w8
+; NO_SCALAR_INC-NEXT:    add w8, w1, w8
+; NO_SCALAR_INC-NEXT:    str w9, [x2]
+; NO_SCALAR_INC-NEXT:    str w8, [x3]
+; NO_SCALAR_INC-NEXT:    ret
+;
+; CHECK-LABEL: decb_incb_scalar_i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT:    decb x0
+; CHECK-NEXT:    incb x1
+; CHECK-NEXT:    str w0, [x2]
+; CHECK-NEXT:    str w1, [x3]
+; CHECK-NEXT:    ret
+;
+; NO_FAST_INC-LABEL: decb_incb_scalar_i32:
+; NO_FAST_INC:       // %bb.0:
+; NO_FAST_INC-NEXT:    // kill: def $w0 killed $w0 def $x0
+; NO_FAST_INC-NEXT:    // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC-NEXT:    addvl x8, x1, #1
+; NO_FAST_INC-NEXT:    dech x0, all, mul #2
+; NO_FAST_INC-NEXT:    str w0, [x2]
+; NO_FAST_INC-NEXT:    str w8, [x3]
+; NO_FAST_INC-NEXT:    ret
+  %vscale = call i64 @llvm.vscale.i64()
+  %mul = mul i64 %vscale, 16
+  %vl = trunc i64 %mul to i32
+  %sub = sub i32 %a, %vl
+  %add = add i32 %b, %vl
+  store i32 %sub, ptr %p, align 1
+  store i32 %add, ptr %q, align 1
+  ret void
+}
+
+define void @dech_inch_scalar_i32(i32 %a, i32 %b, ptr %p, ptr %q) {
+; NO_SCALAR_INC-LABEL: dech_inch_scalar_i32:
+; NO_SCALAR_INC:       // %bb.0:
+; NO_SCALAR_INC-NEXT:    cnth x8
+; NO_SCALAR_INC-NEXT:    sub w9, w0, w8
+; NO_SCALAR_INC-NEXT:    add w8, w1, w8
+; NO_SCALAR_INC-NEXT:    str w9, [x2]
+; NO_SCALAR_INC-NEXT:    str w8, [x3]
+; NO_SCALAR_INC-NEXT:    ret
+;
+; CHECK-LABEL: dech_inch_scalar_i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT:    dech x0
+; CHECK-NEXT:    inch x1
+; CHECK-NEXT:    str w0, [x2]
+; CHECK-NEXT:    str w1, [x3]
+; CHECK-NEXT:    ret
+;
+; NO_FAST_INC-LABEL: dech_inch_scalar_i32:
+; NO_FAST_INC:       // %bb.0:
+; NO_FAST_INC-NEXT:    // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC-NEXT:    // kill: def $w0 killed $w0 def $x0
+; NO_FAST_INC-NEXT:    dech x0
+; NO_FAST_INC-NEXT:    inch x1
+; NO_FAST_INC-NEXT:    str w0, [x2]
+; NO_FAST_INC-NEXT:    str w1, [x3]
+; NO_FAST_INC-NEXT:    ret
+  %vscale = call i64 @llvm.vscale.i64()
+  %mul = mul i64 %vscale, 8
+  %vl = trunc i64 %mul to i32
+  %sub = sub i32 %a, %vl
+  %add = add i32 %b, %vl
+  store i32 %sub, ptr %p, align 1
+  store i32 %add, ptr %q, align 1
+  ret void
+}
+
+define void @decw_incw_scalar_i32(i32 %a, i32 %b, ptr %p, ptr %q) {
+; NO_SCALAR_INC-LABEL: decw_incw_scalar_i32:
+; NO_SCALAR_INC:       // %bb.0:
+; NO_SCALAR_INC-NEXT:    cntw x8
+; NO_SCALAR_INC-NEXT:    sub w9, w0, w8
+; NO_SCALAR_INC-NEXT:    add w8, w1, w8
+; NO_SCALAR_INC-NEXT:    str w9, [x2]
+; NO_SCALAR_INC-NEXT:    str w8, [x3]
+; NO_SCALAR_INC-NEXT:    ret
+;
+; CHECK-LABEL: decw_incw_scalar_i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT:    decw x0
+; CHECK-NEXT:    incw x1
+; CHECK-NEXT:    str w0, [x2]
+; CHECK-NEXT:    str w1, [x3]
+; CHECK-NEXT:    ret
+;
+; NO_FAST_INC-LABEL: decw_incw_scalar_i32:
+; NO_FAST_INC:       // %bb.0:
+; NO_FAST_INC-NEXT:    // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC-NEXT:    // kill: def $w0 killed $w0 def $x0
+; NO_FAST_INC-NEXT:    decw x0
+; NO_FAST_INC-NEXT:    incw x1
+; NO_FAST_INC-NEXT:    str w0, [x2]
+; NO_FAST_INC-NEXT:    str w1, [x3]
+; NO_FAST_INC-NEXT:    ret
+  %vscale = call i64 @llvm.vscale.i64()
+  %mul = mul i64 %vscale, 4
+  %vl = trunc i64 %mul to i32
+  %sub = sub i32 %a, %vl
+  %add = add i32 %b, %vl
+  store i32 %sub, ptr %p, align 1
+  store i32 %add, ptr %q, align 1
+  ret void
+}
+
+define void @decd_incb_scalar_i32(i32 %a, i32 %b, ptr %p, ptr %q) {
+; NO_SCALAR_INC-LABEL: decd_incb_scalar_i32:
+; NO_SCALAR_INC:       // %bb.0:
+; NO_SCALAR_INC-NEXT:    cntd x8
+; NO_SCALAR_INC-NEXT:    sub w9, w0, w8
+; NO_SCALAR_INC-NEXT:    add w8, w1, w8
+; NO_SCALAR_INC-NEXT:    str w9, [x2]
+; NO_SCALAR_INC-NEXT:    str w8, [x3]
+; NO_SCALAR_INC-NEXT:    ret
+;
+; CHECK-LABEL: decd_incb_scalar_i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT:    // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT:    decd x0
+; CHECK-NEXT:    incd x1
+; CHECK-NEXT:    str w0, [x2]
+; CHECK-NEXT:    str w1, [x3]
+; CHECK-NEXT:    ret
+;
+; NO_FAST_INC-LABEL: decd_incb_scalar_i32:
+; NO_FAST_INC:       // %bb.0:
+; NO_FAST_INC-NEXT:    // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC-NEXT:    // kill: def $w0 killed $w0 def $x0
+; NO_FAST_INC-NEXT:    decd x0
+; NO_FAST_INC-NEXT:    incd x1
+; NO_FAST_INC-NEXT:    str w0, [x2]
+; NO_FAST_INC-NEXT:    str w1, [x3]
+; NO_FAST_INC-NEXT:    ret
+  %vscale = call i64 @llvm.vscale.i64()
+  %mul = mul i64 %vscale, 2
+  %vl = trunc i64 %mul to i32
+  %sub = sub i32 %a, %vl
+  %add = add i32 %b, %vl
+  store i32 %sub, ptr %p, align 1
+  store i32 %add, ptr %q, align 1
+  ret void
+}
+
 declare i16 @llvm.vscale.i16()
 declare i32 @llvm.vscale.i32()
 declare i64 @llvm.vscale.i64()

``````````

</details>


https://github.com/llvm/llvm-project/pull/209467


More information about the llvm-commits mailing list