[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