[llvm] [DAGCombine][AArch64] Combine add vscale to sub if imm is legal (PR #214284)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 09:52:47 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-selectiondag
Author: John Brawn (john-brawn-arm)
<details>
<summary>Changes</summary>
Currently (sub X, (vscale * C)) is combined to (add X, (vscale * -C)) only if (vscale * C) has a single use. If (vscale * -C) is a legal add immediate then we know the add will become a single instruction, so it's always profitable.
In AArch64TargetLowering::isLegalAddImmediate we also need to check useScalarIncVL to correctly decide if the immediate is legal.
---
Full diff: https://github.com/llvm/llvm-project/pull/214284.diff
3 Files Affected:
- (modified) llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (+7-4)
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+1-1)
- (modified) llvm/test/CodeGen/AArch64/sve-vl-arith.ll (+450-6)
``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 418ef38daac29..216a4ebf24aaa 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -4580,12 +4580,15 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
}
}
- // canonicalize (sub X, (vscale * C)) to (add X, (vscale * -C))
+ // canonicalize (sub X, (vscale * C)) to (add X, (vscale * -C)) if this is the
+ // only use of the vscale value or if (vscale * -C) is a valid add immediate.
// avoid if ISD::MUL handling is poor and ISD::SHL isn't an option.
- if (N1.getOpcode() == ISD::VSCALE && N1.hasOneUse()) {
+ if (N1.getOpcode() == ISD::VSCALE) {
const APInt &IntVal = N1.getConstantOperandAPInt(0);
- if (!IntVal.isPowerOf2() ||
- hasOperation(ISD::MUL, N1.getOperand(0).getValueType()))
+ if ((N1.hasOneUse() ||
+ TLI.isLegalAddScalableImmediate(-IntVal.getSExtValue())) &&
+ (!IntVal.isPowerOf2() ||
+ hasOperation(ISD::MUL, N1.getOperand(0).getValueType())))
return DAG.getNode(ISD::ADD, DL, VT, N0, DAG.getVScale(DL, VT, -IntVal));
}
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 52095b4618aaf..66281054ae606 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -19958,7 +19958,7 @@ bool AArch64TargetLowering::isLegalAddImmediate(int64_t Immed) const {
bool AArch64TargetLowering::isLegalAddScalableImmediate(int64_t Imm) const {
// We will only emit addvl/inc* instructions for SVE2
- if (!Subtarget->hasSVE2())
+ if (!Subtarget->hasSVE2() || !Subtarget->useScalarIncVL())
return false;
// addvl's immediates are in terms of the number of bytes in a register.
diff --git a/llvm/test/CodeGen/AArch64/sve-vl-arith.ll b/llvm/test/CodeGen/AArch64/sve-vl-arith.ll
index 0a9f4948a5f77..2c67a923d89e7 100644
--- a/llvm/test/CodeGen/AArch64/sve-vl-arith.ll
+++ b/llvm/test/CodeGen/AArch64/sve-vl-arith.ll
@@ -1,10 +1,10 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve -verify-machineinstrs < %s | FileCheck %s -check-prefix=NO_SCALAR_INC
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve -sve-use-scalar-inc-vl=true -verify-machineinstrs < %s | FileCheck %s
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve,disable-fast-inc-vl -sve-use-scalar-inc-vl=true -verify-machineinstrs < %s | FileCheck %s -check-prefix=NO_FAST_INC
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2 -verify-machineinstrs < %s | FileCheck %s
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2 -sve-use-scalar-inc-vl=false -verify-machineinstrs < %s | FileCheck %s -check-prefix=NO_SCALAR_INC
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2,disable-fast-inc-vl -verify-machineinstrs < %s | FileCheck %s -check-prefix=NO_FAST_INC
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve -verify-machineinstrs < %s | FileCheck %s -check-prefixes=NO_SCALAR_INC
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve -sve-use-scalar-inc-vl=true -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK_SVE1
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve,disable-fast-inc-vl -sve-use-scalar-inc-vl=true -verify-machineinstrs < %s | FileCheck %s -check-prefixes=NO_FAST_INC,NO_FAST_INC_SVE1
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2 -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK_SVE2
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2 -sve-use-scalar-inc-vl=false -verify-machineinstrs < %s | FileCheck %s -check-prefixes=NO_SCALAR_INC
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2,disable-fast-inc-vl -verify-machineinstrs < %s | FileCheck %s -check-prefixes=NO_FAST_INC,NO_FAST_INC_SVE2
define <vscale x 8 x i16> @inch_vec(<vscale x 8 x i16> %a) {
; NO_SCALAR_INC-LABEL: inch_vec:
@@ -551,6 +551,450 @@ define i32 @decd_scalar_i32(i32 %a) {
ret i32 %sub
}
+define void @decb_incb_scalar_i64(i64 %a, i64 %b, ptr %p, ptr %q) {
+; 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, x1, x8
+; NO_SCALAR_INC-NEXT: sub x8, x0, x8
+; NO_SCALAR_INC-NEXT: str x9, [x2]
+; NO_SCALAR_INC-NEXT: str x8, [x3]
+; NO_SCALAR_INC-NEXT: ret
+;
+; CHECK_SVE1-LABEL: decb_incb_scalar_i64:
+; CHECK_SVE1: // %bb.0:
+; CHECK_SVE1-NEXT: incb x1
+; CHECK_SVE1-NEXT: rdvl x8, #1
+; CHECK_SVE1-NEXT: sub x8, x0, x8
+; CHECK_SVE1-NEXT: str x1, [x2]
+; CHECK_SVE1-NEXT: str x8, [x3]
+; CHECK_SVE1-NEXT: ret
+;
+; NO_FAST_INC_SVE1-LABEL: decb_incb_scalar_i64:
+; NO_FAST_INC_SVE1: // %bb.0:
+; NO_FAST_INC_SVE1-NEXT: rdvl x8, #1
+; NO_FAST_INC_SVE1-NEXT: addvl x9, x1, #1
+; NO_FAST_INC_SVE1-NEXT: sub x8, x0, x8
+; NO_FAST_INC_SVE1-NEXT: str x9, [x2]
+; NO_FAST_INC_SVE1-NEXT: str x8, [x3]
+; NO_FAST_INC_SVE1-NEXT: ret
+;
+; CHECK_SVE2-LABEL: decb_incb_scalar_i64:
+; CHECK_SVE2: // %bb.0:
+; CHECK_SVE2-NEXT: incb x1
+; CHECK_SVE2-NEXT: decb x0
+; CHECK_SVE2-NEXT: str x1, [x2]
+; CHECK_SVE2-NEXT: str x0, [x3]
+; CHECK_SVE2-NEXT: ret
+;
+; NO_FAST_INC_SVE2-LABEL: decb_incb_scalar_i64:
+; NO_FAST_INC_SVE2: // %bb.0:
+; NO_FAST_INC_SVE2-NEXT: addvl x8, x1, #1
+; NO_FAST_INC_SVE2-NEXT: addvl x9, x0, #-1
+; NO_FAST_INC_SVE2-NEXT: str x8, [x2]
+; NO_FAST_INC_SVE2-NEXT: str x9, [x3]
+; NO_FAST_INC_SVE2-NEXT: ret
+ %vscale = call i64 @llvm.vscale.i64()
+ %mul = mul i64 %vscale, 16
+ %sub = sub i64 %a, %mul
+ %add = add i64 %b, %mul
+ store i64 %add, ptr %p, align 1
+ store i64 %sub, ptr %q, align 1
+ ret void
+}
+
+define void @dech_inch_scalar_i64(i64 %a, i64 %b, ptr %p, ptr %q) {
+; 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, x1, x8
+; NO_SCALAR_INC-NEXT: sub x8, x0, x8
+; NO_SCALAR_INC-NEXT: str x9, [x2]
+; NO_SCALAR_INC-NEXT: str x8, [x3]
+; NO_SCALAR_INC-NEXT: ret
+;
+; CHECK_SVE1-LABEL: dech_inch_scalar_i64:
+; CHECK_SVE1: // %bb.0:
+; CHECK_SVE1-NEXT: inch x1
+; CHECK_SVE1-NEXT: cnth x8
+; CHECK_SVE1-NEXT: sub x8, x0, x8
+; CHECK_SVE1-NEXT: str x1, [x2]
+; CHECK_SVE1-NEXT: str x8, [x3]
+; CHECK_SVE1-NEXT: ret
+;
+; NO_FAST_INC_SVE1-LABEL: dech_inch_scalar_i64:
+; NO_FAST_INC_SVE1: // %bb.0:
+; NO_FAST_INC_SVE1-NEXT: inch x1
+; NO_FAST_INC_SVE1-NEXT: cnth x8
+; NO_FAST_INC_SVE1-NEXT: sub x8, x0, x8
+; NO_FAST_INC_SVE1-NEXT: str x1, [x2]
+; NO_FAST_INC_SVE1-NEXT: str x8, [x3]
+; NO_FAST_INC_SVE1-NEXT: ret
+;
+; CHECK_SVE2-LABEL: dech_inch_scalar_i64:
+; CHECK_SVE2: // %bb.0:
+; CHECK_SVE2-NEXT: inch x1
+; CHECK_SVE2-NEXT: dech x0
+; CHECK_SVE2-NEXT: str x1, [x2]
+; CHECK_SVE2-NEXT: str x0, [x3]
+; CHECK_SVE2-NEXT: ret
+;
+; NO_FAST_INC_SVE2-LABEL: dech_inch_scalar_i64:
+; NO_FAST_INC_SVE2: // %bb.0:
+; NO_FAST_INC_SVE2-NEXT: inch x1
+; NO_FAST_INC_SVE2-NEXT: dech x0
+; NO_FAST_INC_SVE2-NEXT: str x1, [x2]
+; NO_FAST_INC_SVE2-NEXT: str x0, [x3]
+; NO_FAST_INC_SVE2-NEXT: ret
+ %vscale = call i64 @llvm.vscale.i64()
+ %mul = mul i64 %vscale, 8
+ %sub = sub i64 %a, %mul
+ %add = add i64 %b, %mul
+ store i64 %add, ptr %p, align 1
+ store i64 %sub, ptr %q, align 1
+ ret void
+}
+
+define void @decw_incw_scalar_i64(i64 %a, i64 %b, ptr %p, ptr %q) {
+; 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, x1, x8
+; NO_SCALAR_INC-NEXT: sub x8, x0, x8
+; NO_SCALAR_INC-NEXT: str x9, [x2]
+; NO_SCALAR_INC-NEXT: str x8, [x3]
+; NO_SCALAR_INC-NEXT: ret
+;
+; CHECK_SVE1-LABEL: decw_incw_scalar_i64:
+; CHECK_SVE1: // %bb.0:
+; CHECK_SVE1-NEXT: incw x1
+; CHECK_SVE1-NEXT: cntw x8
+; CHECK_SVE1-NEXT: sub x8, x0, x8
+; CHECK_SVE1-NEXT: str x1, [x2]
+; CHECK_SVE1-NEXT: str x8, [x3]
+; CHECK_SVE1-NEXT: ret
+;
+; NO_FAST_INC_SVE1-LABEL: decw_incw_scalar_i64:
+; NO_FAST_INC_SVE1: // %bb.0:
+; NO_FAST_INC_SVE1-NEXT: incw x1
+; NO_FAST_INC_SVE1-NEXT: cntw x8
+; NO_FAST_INC_SVE1-NEXT: sub x8, x0, x8
+; NO_FAST_INC_SVE1-NEXT: str x1, [x2]
+; NO_FAST_INC_SVE1-NEXT: str x8, [x3]
+; NO_FAST_INC_SVE1-NEXT: ret
+;
+; CHECK_SVE2-LABEL: decw_incw_scalar_i64:
+; CHECK_SVE2: // %bb.0:
+; CHECK_SVE2-NEXT: incw x1
+; CHECK_SVE2-NEXT: decw x0
+; CHECK_SVE2-NEXT: str x1, [x2]
+; CHECK_SVE2-NEXT: str x0, [x3]
+; CHECK_SVE2-NEXT: ret
+;
+; NO_FAST_INC_SVE2-LABEL: decw_incw_scalar_i64:
+; NO_FAST_INC_SVE2: // %bb.0:
+; NO_FAST_INC_SVE2-NEXT: incw x1
+; NO_FAST_INC_SVE2-NEXT: decw x0
+; NO_FAST_INC_SVE2-NEXT: str x1, [x2]
+; NO_FAST_INC_SVE2-NEXT: str x0, [x3]
+; NO_FAST_INC_SVE2-NEXT: ret
+ %vscale = call i64 @llvm.vscale.i64()
+ %mul = mul i64 %vscale, 4
+ %sub = sub i64 %a, %mul
+ %add = add i64 %b, %mul
+ store i64 %add, ptr %p, align 1
+ store i64 %sub, ptr %q, align 1
+ ret void
+}
+
+define void @decd_incd_scalar_i64(i64 %a, i64 %b, ptr %p, ptr %q) {
+; 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, x1, x8
+; NO_SCALAR_INC-NEXT: sub x8, x0, x8
+; NO_SCALAR_INC-NEXT: str x9, [x2]
+; NO_SCALAR_INC-NEXT: str x8, [x3]
+; NO_SCALAR_INC-NEXT: ret
+;
+; CHECK_SVE1-LABEL: decd_incd_scalar_i64:
+; CHECK_SVE1: // %bb.0:
+; CHECK_SVE1-NEXT: incd x1
+; CHECK_SVE1-NEXT: cntd x8
+; CHECK_SVE1-NEXT: sub x8, x0, x8
+; CHECK_SVE1-NEXT: str x1, [x2]
+; CHECK_SVE1-NEXT: str x8, [x3]
+; CHECK_SVE1-NEXT: ret
+;
+; NO_FAST_INC_SVE1-LABEL: decd_incd_scalar_i64:
+; NO_FAST_INC_SVE1: // %bb.0:
+; NO_FAST_INC_SVE1-NEXT: incd x1
+; NO_FAST_INC_SVE1-NEXT: cntd x8
+; NO_FAST_INC_SVE1-NEXT: sub x8, x0, x8
+; NO_FAST_INC_SVE1-NEXT: str x1, [x2]
+; NO_FAST_INC_SVE1-NEXT: str x8, [x3]
+; NO_FAST_INC_SVE1-NEXT: ret
+;
+; CHECK_SVE2-LABEL: decd_incd_scalar_i64:
+; CHECK_SVE2: // %bb.0:
+; CHECK_SVE2-NEXT: incd x1
+; CHECK_SVE2-NEXT: decd x0
+; CHECK_SVE2-NEXT: str x1, [x2]
+; CHECK_SVE2-NEXT: str x0, [x3]
+; CHECK_SVE2-NEXT: ret
+;
+; NO_FAST_INC_SVE2-LABEL: decd_incd_scalar_i64:
+; NO_FAST_INC_SVE2: // %bb.0:
+; NO_FAST_INC_SVE2-NEXT: incd x1
+; NO_FAST_INC_SVE2-NEXT: decd x0
+; NO_FAST_INC_SVE2-NEXT: str x1, [x2]
+; NO_FAST_INC_SVE2-NEXT: str x0, [x3]
+; NO_FAST_INC_SVE2-NEXT: ret
+ %vscale = call i64 @llvm.vscale.i64()
+ %mul = mul i64 %vscale, 2
+ %sub = sub i64 %a, %mul
+ %add = add i64 %b, %mul
+ store i64 %add, ptr %p, align 1
+ store i64 %sub, ptr %q, 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_SVE1-LABEL: decb_incb_scalar_i32:
+; CHECK_SVE1: // %bb.0:
+; CHECK_SVE1-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK_SVE1-NEXT: rdvl x8, #1
+; CHECK_SVE1-NEXT: incb x1
+; CHECK_SVE1-NEXT: sub w8, w0, w8
+; CHECK_SVE1-NEXT: str w8, [x2]
+; CHECK_SVE1-NEXT: str w1, [x3]
+; CHECK_SVE1-NEXT: ret
+;
+; NO_FAST_INC_SVE1-LABEL: decb_incb_scalar_i32:
+; NO_FAST_INC_SVE1: // %bb.0:
+; NO_FAST_INC_SVE1-NEXT: rdvl x8, #1
+; NO_FAST_INC_SVE1-NEXT: // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC_SVE1-NEXT: addvl x9, x1, #1
+; NO_FAST_INC_SVE1-NEXT: sub w8, w0, w8
+; NO_FAST_INC_SVE1-NEXT: str w8, [x2]
+; NO_FAST_INC_SVE1-NEXT: str w9, [x3]
+; NO_FAST_INC_SVE1-NEXT: ret
+;
+; CHECK_SVE2-LABEL: decb_incb_scalar_i32:
+; CHECK_SVE2: // %bb.0:
+; CHECK_SVE2-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK_SVE2-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK_SVE2-NEXT: decb x0
+; CHECK_SVE2-NEXT: incb x1
+; CHECK_SVE2-NEXT: str w0, [x2]
+; CHECK_SVE2-NEXT: str w1, [x3]
+; CHECK_SVE2-NEXT: ret
+;
+; NO_FAST_INC_SVE2-LABEL: decb_incb_scalar_i32:
+; NO_FAST_INC_SVE2: // %bb.0:
+; NO_FAST_INC_SVE2-NEXT: // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC_SVE2-NEXT: // kill: def $w0 killed $w0 def $x0
+; NO_FAST_INC_SVE2-NEXT: addvl x8, x1, #1
+; NO_FAST_INC_SVE2-NEXT: addvl x9, x0, #-1
+; NO_FAST_INC_SVE2-NEXT: str w9, [x2]
+; NO_FAST_INC_SVE2-NEXT: str w8, [x3]
+; NO_FAST_INC_SVE2-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_SVE1-LABEL: dech_inch_scalar_i32:
+; CHECK_SVE1: // %bb.0:
+; CHECK_SVE1-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK_SVE1-NEXT: cnth x8
+; CHECK_SVE1-NEXT: inch x1
+; CHECK_SVE1-NEXT: sub w8, w0, w8
+; CHECK_SVE1-NEXT: str w8, [x2]
+; CHECK_SVE1-NEXT: str w1, [x3]
+; CHECK_SVE1-NEXT: ret
+;
+; NO_FAST_INC_SVE1-LABEL: dech_inch_scalar_i32:
+; NO_FAST_INC_SVE1: // %bb.0:
+; NO_FAST_INC_SVE1-NEXT: // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC_SVE1-NEXT: cnth x8
+; NO_FAST_INC_SVE1-NEXT: inch x1
+; NO_FAST_INC_SVE1-NEXT: sub w8, w0, w8
+; NO_FAST_INC_SVE1-NEXT: str w8, [x2]
+; NO_FAST_INC_SVE1-NEXT: str w1, [x3]
+; NO_FAST_INC_SVE1-NEXT: ret
+;
+; CHECK_SVE2-LABEL: dech_inch_scalar_i32:
+; CHECK_SVE2: // %bb.0:
+; CHECK_SVE2-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK_SVE2-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK_SVE2-NEXT: dech x0
+; CHECK_SVE2-NEXT: inch x1
+; CHECK_SVE2-NEXT: str w0, [x2]
+; CHECK_SVE2-NEXT: str w1, [x3]
+; CHECK_SVE2-NEXT: ret
+;
+; NO_FAST_INC_SVE2-LABEL: dech_inch_scalar_i32:
+; NO_FAST_INC_SVE2: // %bb.0:
+; NO_FAST_INC_SVE2-NEXT: // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC_SVE2-NEXT: // kill: def $w0 killed $w0 def $x0
+; NO_FAST_INC_SVE2-NEXT: dech x0
+; NO_FAST_INC_SVE2-NEXT: inch x1
+; NO_FAST_INC_SVE2-NEXT: str w0, [x2]
+; NO_FAST_INC_SVE2-NEXT: str w1, [x3]
+; NO_FAST_INC_SVE2-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_SVE1-LABEL: decw_incw_scalar_i32:
+; CHECK_SVE1: // %bb.0:
+; CHECK_SVE1-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK_SVE1-NEXT: cntw x8
+; CHECK_SVE1-NEXT: incw x1
+; CHECK_SVE1-NEXT: sub w8, w0, w8
+; CHECK_SVE1-NEXT: str w8, [x2]
+; CHECK_SVE1-NEXT: str w1, [x3]
+; CHECK_SVE1-NEXT: ret
+;
+; NO_FAST_INC_SVE1-LABEL: decw_incw_scalar_i32:
+; NO_FAST_INC_SVE1: // %bb.0:
+; NO_FAST_INC_SVE1-NEXT: // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC_SVE1-NEXT: cntw x8
+; NO_FAST_INC_SVE1-NEXT: incw x1
+; NO_FAST_INC_SVE1-NEXT: sub w8, w0, w8
+; NO_FAST_INC_SVE1-NEXT: str w8, [x2]
+; NO_FAST_INC_SVE1-NEXT: str w1, [x3]
+; NO_FAST_INC_SVE1-NEXT: ret
+;
+; CHECK_SVE2-LABEL: decw_incw_scalar_i32:
+; CHECK_SVE2: // %bb.0:
+; CHECK_SVE2-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK_SVE2-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK_SVE2-NEXT: decw x0
+; CHECK_SVE2-NEXT: incw x1
+; CHECK_SVE2-NEXT: str w0, [x2]
+; CHECK_SVE2-NEXT: str w1, [x3]
+; CHECK_SVE2-NEXT: ret
+;
+; NO_FAST_INC_SVE2-LABEL: decw_incw_scalar_i32:
+; NO_FAST_INC_SVE2: // %bb.0:
+; NO_FAST_INC_SVE2-NEXT: // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC_SVE2-NEXT: // kill: def $w0 killed $w0 def $x0
+; NO_FAST_INC_SVE2-NEXT: decw x0
+; NO_FAST_INC_SVE2-NEXT: incw x1
+; NO_FAST_INC_SVE2-NEXT: str w0, [x2]
+; NO_FAST_INC_SVE2-NEXT: str w1, [x3]
+; NO_FAST_INC_SVE2-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_SVE1-LABEL: decd_incb_scalar_i32:
+; CHECK_SVE1: // %bb.0:
+; CHECK_SVE1-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK_SVE1-NEXT: cntd x8
+; CHECK_SVE1-NEXT: incd x1
+; CHECK_SVE1-NEXT: sub w8, w0, w8
+; CHECK_SVE1-NEXT: str w8, [x2]
+; CHECK_SVE1-NEXT: str w1, [x3]
+; CHECK_SVE1-NEXT: ret
+;
+; NO_FAST_INC_SVE1-LABEL: decd_incb_scalar_i32:
+; NO_FAST_INC_SVE1: // %bb.0:
+; NO_FAST_INC_SVE1-NEXT: // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC_SVE1-NEXT: cntd x8
+; NO_FAST_INC_SVE1-NEXT: incd x1
+; NO_FAST_INC_SVE1-NEXT: sub w8, w0, w8
+; NO_FAST_INC_SVE1-NEXT: str w8, [x2]
+; NO_FAST_INC_SVE1-NEXT: str w1, [x3]
+; NO_FAST_INC_SVE1-NEXT: ret
+;
+; CHECK_SVE2-LABEL: decd_incb_scalar_i32:
+; CHECK_SVE2: // %bb.0:
+; CHECK_SVE2-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK_SVE2-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK_SVE2-NEXT: decd x0
+; CHECK_SVE2-NEXT: incd x1
+; CHECK_SVE2-NEXT: str w0, [x2]
+; CHECK_SVE2-NEXT: str w1, [x3]
+; CHECK_SVE2-NEXT: ret
+;
+; NO_FAST_INC_SVE2-LABEL: decd_incb_scalar_i32:
+; NO_FAST_INC_SVE2: // %bb.0:
+; NO_FAST_INC_SVE2-NEXT: // kill: def $w1 killed $w1 def $x1
+; NO_FAST_INC_SVE2-NEXT: // kill: def $w0 killed $w0 def $x0
+; NO_FAST_INC_SVE2-NEXT: decd x0
+; NO_FAST_INC_SVE2-NEXT: incd x1
+; NO_FAST_INC_SVE2-NEXT: str w0, [x2]
+; NO_FAST_INC_SVE2-NEXT: str w1, [x3]
+; NO_FAST_INC_SVE2-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/214284
More information about the llvm-commits
mailing list