[llvm] [DAGCombine][AArch64] Combine add vscale to sub if imm is legal (PR #214284)

John Brawn via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 09:52:02 PDT 2026


https://github.com/john-brawn-arm created https://github.com/llvm/llvm-project/pull/214284

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.

>From 59ab478c212da7af3f5a40d614cc0d0dc585b12e Mon Sep 17 00:00:00 2001
From: John Brawn <john.brawn at arm.com>
Date: Mon, 13 Jul 2026 16:02:27 +0100
Subject: [PATCH] [DAGCombine][AArch64] Combine add vscale to sub if imm is
 legal

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.
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  11 +-
 .../Target/AArch64/AArch64ISelLowering.cpp    |   2 +-
 llvm/test/CodeGen/AArch64/sve-vl-arith.ll     | 456 +++++++++++++++++-
 3 files changed, 458 insertions(+), 11 deletions(-)

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()



More information about the llvm-commits mailing list