[llvm] [TTI][TLI] Support scalable immediates with isLegalAddImmediate (PR #84173)

Graham Hunter via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 6 06:13:26 PST 2024


https://github.com/huntergr-arm created https://github.com/llvm/llvm-project/pull/84173

Adds a second parameter (default to 0) to isLegalAddImmediate, to represent a scalable immediate.

Extends the AArch64 implementation to match immediates based on vscale * base_register_size * immediate in the range [-32,31].

See the vscale-aware LSR RFC for reference: https://discourse.llvm.org/t/rfc-vscale-aware-loopstrengthreduce/77131


>From dd3e5f383d9470cddcb21de32a31734ee5465df8 Mon Sep 17 00:00:00 2001
From: Graham Hunter <graham.hunter at arm.com>
Date: Wed, 6 Mar 2024 11:40:02 +0000
Subject: [PATCH 1/3] [TLI][TTI] Add a scalable immediate parameter to
 isLegalAddImmediate

---
 llvm/include/llvm/Analysis/TargetTransformInfo.h     | 8 ++++----
 llvm/include/llvm/Analysis/TargetTransformInfoImpl.h | 4 +++-
 llvm/include/llvm/CodeGen/BasicTTIImpl.h             | 4 ++--
 llvm/include/llvm/CodeGen/TargetLowering.h           | 4 ++--
 llvm/lib/Analysis/TargetTransformInfo.cpp            | 5 +++--
 llvm/lib/Target/AArch64/AArch64ISelLowering.cpp      | 6 +++++-
 llvm/lib/Target/AArch64/AArch64ISelLowering.h        | 2 +-
 llvm/lib/Target/ARM/ARMISelLowering.cpp              | 3 ++-
 llvm/lib/Target/ARM/ARMISelLowering.h                | 3 ++-
 llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp  | 3 ++-
 llvm/lib/Target/LoongArch/LoongArchISelLowering.h    | 2 +-
 llvm/lib/Target/PowerPC/PPCISelLowering.cpp          | 3 ++-
 llvm/lib/Target/PowerPC/PPCISelLowering.h            | 3 ++-
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp          | 5 +++--
 llvm/lib/Target/RISCV/RISCVISelLowering.h            | 2 +-
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp      | 3 ++-
 llvm/lib/Target/SystemZ/SystemZISelLowering.h        | 2 +-
 llvm/lib/Target/X86/X86ISelLowering.cpp              | 3 ++-
 llvm/lib/Target/X86/X86ISelLowering.h                | 3 ++-
 19 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index 4eab357f1b33b6..f9dd7bbc3dcec8 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -694,7 +694,7 @@ class TargetTransformInfo {
   /// Return true if the specified immediate is legal add immediate, that
   /// is the target has add instructions which can add a register with the
   /// immediate without having to materialize the immediate into a register.
-  bool isLegalAddImmediate(int64_t Imm) const;
+  bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const;
 
   /// Return true if the specified immediate is legal icmp immediate,
   /// that is the target has icmp instructions which can compare a register
@@ -1834,7 +1834,7 @@ class TargetTransformInfo::Concept {
       APInt &UndefElts, APInt &UndefElts2, APInt &UndefElts3,
       std::function<void(Instruction *, unsigned, APInt, APInt &)>
           SimplifyAndSetOp) = 0;
-  virtual bool isLegalAddImmediate(int64_t Imm) = 0;
+  virtual bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm) = 0;
   virtual bool isLegalICmpImmediate(int64_t Imm) = 0;
   virtual bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV,
                                      int64_t BaseOffset, bool HasBaseReg,
@@ -2292,8 +2292,8 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
         IC, II, DemandedElts, UndefElts, UndefElts2, UndefElts3,
         SimplifyAndSetOp);
   }
-  bool isLegalAddImmediate(int64_t Imm) override {
-    return Impl.isLegalAddImmediate(Imm);
+  bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm) override {
+    return Impl.isLegalAddImmediate(Imm, ScalableImm);
   }
   bool isLegalICmpImmediate(int64_t Imm) override {
     return Impl.isLegalICmpImmediate(Imm);
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index 95fb13d1c97154..7fbdfe3fc68437 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -214,7 +214,9 @@ class TargetTransformInfoImplBase {
   void getPeelingPreferences(Loop *, ScalarEvolution &,
                              TTI::PeelingPreferences &) const {}
 
-  bool isLegalAddImmediate(int64_t Imm) const { return false; }
+  bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm) const {
+    return false;
+  }
 
   bool isLegalICmpImmediate(int64_t Imm) const { return false; }
 
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 61f6564e8cd79b..ac8cd28689d35a 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -324,8 +324,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
     return nullptr;
   }
 
-  bool isLegalAddImmediate(int64_t imm) {
-    return getTLI()->isLegalAddImmediate(imm);
+  bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm) {
+    return getTLI()->isLegalAddImmediate(Imm, ScalableImm);
   }
 
   bool isLegalICmpImmediate(int64_t imm) {
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 2f164a460db843..57844dd82d6410 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -2766,8 +2766,8 @@ class TargetLoweringBase {
   /// Return true if the specified immediate is legal add immediate, that is the
   /// target has add instructions which can add a register with the immediate
   /// without having to materialize the immediate into a register.
-  virtual bool isLegalAddImmediate(int64_t) const {
-    return true;
+  virtual bool isLegalAddImmediate(int64_t, int64_t ScalableImm = 0) const {
+    return !ScalableImm;
   }
 
   /// Return true if the specified immediate is legal for the value input of a
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index 15311be4dba277..8791ae4c3744e5 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -391,8 +391,9 @@ void TargetTransformInfo::getPeelingPreferences(Loop *L, ScalarEvolution &SE,
   return TTIImpl->getPeelingPreferences(L, SE, PP);
 }
 
-bool TargetTransformInfo::isLegalAddImmediate(int64_t Imm) const {
-  return TTIImpl->isLegalAddImmediate(Imm);
+bool TargetTransformInfo::isLegalAddImmediate(int64_t Imm,
+                                              int64_t ScalableImm) const {
+  return TTIImpl->isLegalAddImmediate(Imm, ScalableImm);
 }
 
 bool TargetTransformInfo::isLegalICmpImmediate(int64_t Imm) const {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 2290223a06f8ef..4b7464162ac3db 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -16559,7 +16559,11 @@ LLT AArch64TargetLowering::getOptimalMemOpLLT(
 }
 
 // 12-bit optionally shifted immediates are legal for adds.
-bool AArch64TargetLowering::isLegalAddImmediate(int64_t Immed) const {
+bool AArch64TargetLowering::isLegalAddImmediate(int64_t Immed,
+                                                int64_t ScalableImm) const {
+  if (ScalableImm)
+    return false;
+
   if (Immed == std::numeric_limits<int64_t>::min()) {
     LLVM_DEBUG(dbgs() << "Illegal add imm " << Immed
                       << ": avoid UB for INT64_MIN\n");
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 68341c199e0a2a..adec93d7e6aea1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -688,7 +688,7 @@ class AArch64TargetLowering : public TargetLowering {
   bool lowerInterleaveIntrinsicToStore(IntrinsicInst *II,
                                        StoreInst *SI) const override;
 
-  bool isLegalAddImmediate(int64_t) const override;
+  bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const override;
   bool isLegalICmpImmediate(int64_t) const override;
 
   bool isMulAddWithConstProfitable(SDValue AddNode,
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index dc81178311b6d8..65a15f959ff4d9 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -19722,7 +19722,8 @@ bool ARMTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
 /// *or sub* immediate, that is the target has add or sub instructions which can
 /// add a register with the immediate without having to materialize the
 /// immediate into a register.
-bool ARMTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool ARMTargetLowering::isLegalAddImmediate(int64_t Imm,
+                                            int64_t ScalableImm) const {
   // Same encoding for add/sub, just flip the sign.
   int64_t AbsImm = std::abs(Imm);
   if (!Subtarget->isThumb())
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index b13ddf697cb806..70bbb15a1772f8 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -494,7 +494,8 @@ class VectorType;
     /// add immediate, that is the target has add instructions which can
     /// add a register and the immediate without having to materialize
     /// the immediate into a register.
-    bool isLegalAddImmediate(int64_t Imm) const override;
+    bool isLegalAddImmediate(int64_t Imm,
+                             int64_t ScalableImm = 0) const override;
 
     /// getPreIndexedAddressParts - returns true by value, base pointer and
     /// offset pointer and addressing mode by reference if the node's address
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index c8e955a23336d7..f975fc52b2f774 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -4933,7 +4933,8 @@ bool LoongArchTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
   return isInt<12>(Imm);
 }
 
-bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm,
+                                                  int64_t ScalableImm) const {
   return isInt<12>(Imm);
 }
 
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 9e9ac0b8269291..b59a4dfcd9ead3 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -222,7 +222,7 @@ class LoongArchTargetLowering : public TargetLowering {
                              Instruction *I = nullptr) const override;
 
   bool isLegalICmpImmediate(int64_t Imm) const override;
-  bool isLegalAddImmediate(int64_t Imm) const override;
+  bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const override;
   bool isZExtFree(SDValue Val, EVT VT2) const override;
   bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override;
 
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 68c80dd9aa5c76..2aaf7b24d52544 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -17300,7 +17300,8 @@ bool PPCTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
   return isInt<16>(Imm) || isUInt<16>(Imm);
 }
 
-bool PPCTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool PPCTargetLowering::isLegalAddImmediate(int64_t Imm,
+                                            int64_t ScalableImm) const {
   return isInt<16>(Imm) || isUInt<16>(Imm);
 }
 
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index 0bdfdcd15441f4..a1b404bd655b36 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -1023,7 +1023,8 @@ namespace llvm {
     /// add immediate, that is the target has add instructions which can
     /// add a register and the immediate without having to materialize
     /// the immediate into a register.
-    bool isLegalAddImmediate(int64_t Imm) const override;
+    bool isLegalAddImmediate(int64_t Imm,
+                             int64_t ScalableImm = 0) const override;
 
     /// isTruncateFree - Return true if it's free to truncate a value of
     /// type Ty1 to type Ty2. e.g. On PPC it's free to truncate a i64 value in
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 4c3dc63afd878d..c6b02b8b26856b 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -1783,8 +1783,9 @@ bool RISCVTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
   return isInt<12>(Imm);
 }
 
-bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm) const {
-  return isInt<12>(Imm);
+bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm,
+                                              int64_t ScalableImm) const {
+  return !ScalableImm && isInt<12>(Imm);
 }
 
 // On RV32, 64-bit integers are split into their high and low parts and held
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index f90cb4df604761..61fb5809c9b8dd 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -475,7 +475,7 @@ class RISCVTargetLowering : public TargetLowering {
                              unsigned AS,
                              Instruction *I = nullptr) const override;
   bool isLegalICmpImmediate(int64_t Imm) const override;
-  bool isLegalAddImmediate(int64_t Imm) const override;
+  bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const override;
   bool isTruncateFree(Type *SrcTy, Type *DstTy) const override;
   bool isTruncateFree(EVT SrcVT, EVT DstVT) const override;
   bool isZExtFree(SDValue Val, EVT VT2) const override;
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 3b85a6ac0371ed..a2aa33ff059489 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -944,7 +944,8 @@ bool SystemZTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
   return isInt<32>(Imm) || isUInt<32>(Imm);
 }
 
-bool SystemZTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool SystemZTargetLowering::isLegalAddImmediate(int64_t Imm,
+                                                int64_t ScalableImm) const {
   // We can use ALGFI or SLGFI.
   return isUInt<32>(Imm) || isUInt<32>(-Imm);
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index baf4ba41654879..274b23b4d28935 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -477,7 +477,7 @@ class SystemZTargetLowering : public TargetLowering {
   AtomicExpansionKind
   shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const override;
   bool isLegalICmpImmediate(int64_t Imm) const override;
-  bool isLegalAddImmediate(int64_t Imm) const override;
+  bool isLegalAddImmediate(int64_t Imm, int64_t ScalableImm = 0) const override;
   bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty,
                              unsigned AS,
                              Instruction *I = nullptr) const override;
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 6eaaec407dbb08..d5f5ef24e56d5d 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -33882,7 +33882,8 @@ bool X86TargetLowering::isLegalICmpImmediate(int64_t Imm) const {
   return isInt<32>(Imm);
 }
 
-bool X86TargetLowering::isLegalAddImmediate(int64_t Imm) const {
+bool X86TargetLowering::isLegalAddImmediate(int64_t Imm,
+                                            int64_t ScalableImm) const {
   // Can also use sub to handle negated immediates.
   return isInt<32>(Imm);
 }
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index fe1943b5760844..b3cccee0e67bf1 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -1329,7 +1329,8 @@ namespace llvm {
     /// add immediate, that is the target has add instructions which can
     /// add a register and the immediate without having to materialize
     /// the immediate into a register.
-    bool isLegalAddImmediate(int64_t Imm) const override;
+    bool isLegalAddImmediate(int64_t Imm,
+                             int64_t ScalableImm = 0) const override;
 
     bool isLegalStoreImmediate(int64_t Imm) const override;
 

>From f5ee2b52648f88bf206363fa76a5cfdf494d1ec2 Mon Sep 17 00:00:00 2001
From: Graham Hunter <graham.hunter at arm.com>
Date: Wed, 6 Mar 2024 13:24:17 +0000
Subject: [PATCH 2/3] [AArch64] Unit test for scalable isLegalAddImmediate

---
 llvm/unittests/Target/AArch64/CMakeLists.txt |  1 +
 llvm/unittests/Target/AArch64/Immediates.cpp | 75 ++++++++++++++++++++
 2 files changed, 76 insertions(+)
 create mode 100644 llvm/unittests/Target/AArch64/Immediates.cpp

diff --git a/llvm/unittests/Target/AArch64/CMakeLists.txt b/llvm/unittests/Target/AArch64/CMakeLists.txt
index dacd919ba1e33b..64ab991ac479a4 100644
--- a/llvm/unittests/Target/AArch64/CMakeLists.txt
+++ b/llvm/unittests/Target/AArch64/CMakeLists.txt
@@ -29,6 +29,7 @@ add_llvm_target_unittest(AArch64Tests
   MatrixRegisterAliasing.cpp
   SMEAttributesTest.cpp
   AArch64SVESchedPseudoTest.cpp
+  Immediates.cpp
   )
 
 set_property(TARGET AArch64Tests PROPERTY FOLDER "Tests/UnitTests/TargetTests")
diff --git a/llvm/unittests/Target/AArch64/Immediates.cpp b/llvm/unittests/Target/AArch64/Immediates.cpp
new file mode 100644
index 00000000000000..df96b3f5b9ec96
--- /dev/null
+++ b/llvm/unittests/Target/AArch64/Immediates.cpp
@@ -0,0 +1,75 @@
+#include "AArch64Subtarget.h"
+#include "AArch64TargetMachine.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "gtest/gtest.h"
+#include <initializer_list>
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+struct TestCase {
+  int64_t FixedImm;
+  int64_t ScalableImm;
+  bool Result;
+};
+
+const std::initializer_list<TestCase> Tests = {
+    // FixedImm, ScalableImm, Result
+    // No change, easily 'supported'
+    {0, 0, true},
+
+    // Simple fixed immediate cases
+    // +8
+    {8, 0, true},
+    // -16
+    {-16, 0, true},
+
+    // Scalable; addvl increments by whole registers, range [-32,31]
+    // +(16 * vscale), one register's worth
+    {0, 16, false},
+    // +(8 * vscale), half a register's worth
+    {0, 8, false},
+    // -(32 * 16 * vscale)
+    {0, -512, false},
+    // -(33 * 16 * vscale)
+    {0, -528, false},
+    // +(31 * 16 * vscale)
+    {0, 496, false},
+    // +(32 * 16 * vscale)
+    {0, 512, false},
+
+    // Mixed; not supported.
+    // +(16 + (16 * vscale)) -- one register's worth + 16
+    {16, 16, false},
+};
+} // namespace
+
+TEST(Immediates, Immediates) {
+  LLVMInitializeAArch64TargetInfo();
+  LLVMInitializeAArch64Target();
+  LLVMInitializeAArch64TargetMC();
+
+  std::string Error;
+  auto TT = Triple::normalize("aarch64");
+  const Target *T = TargetRegistry::lookupTarget(TT, Error);
+
+  std::unique_ptr<TargetMachine> TM(
+      T->createTargetMachine(TT, "generic", "+sve", TargetOptions(),
+                             std::nullopt, std::nullopt,
+                             CodeGenOptLevel::Default));
+  AArch64Subtarget ST(TM->getTargetTriple(), TM->getTargetCPU(),
+                      TM->getTargetCPU(), TM->getTargetFeatureString(), *TM,
+                      true);
+
+  auto *TLI = ST.getTargetLowering();
+
+  for (const auto &Test : Tests) {
+    ASSERT_EQ(TLI->isLegalAddImmediate(Test.FixedImm, Test.ScalableImm),
+              Test.Result);
+  }
+}

>From 5125e7530fe293acdfd4b5e98cf57622f074a699 Mon Sep 17 00:00:00 2001
From: Graham Hunter <graham.hunter at arm.com>
Date: Wed, 6 Mar 2024 13:38:47 +0000
Subject: [PATCH 3/3] [AArch64] Recognize legal add immediates for addvl

---
 .../lib/Target/AArch64/AArch64ISelLowering.cpp | 18 ++++++++++++++++--
 llvm/unittests/Target/AArch64/Immediates.cpp   |  6 +++---
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 4b7464162ac3db..e53e8ce6a3d227 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -16561,8 +16561,22 @@ LLT AArch64TargetLowering::getOptimalMemOpLLT(
 // 12-bit optionally shifted immediates are legal for adds.
 bool AArch64TargetLowering::isLegalAddImmediate(int64_t Immed,
                                                 int64_t ScalableImm) const {
-  if (ScalableImm)
-    return false;
+  if (ScalableImm) {
+    // Scalable immediates require SVE support; mixed fixed + scalable
+    // immediates are not supported by the current instructions.
+    if (Immed || !Subtarget->hasSVE())
+      return false;
+
+    // addvl's immediates are in terms of the number of bytes in a register.
+    // Since there are 16 in the base supported size (128bits), we need to
+    // divide the immediate by that much to give us a useful immediate to
+    // multiply by vscale. We can't have a remainder as a result of this.
+    if (ScalableImm % 16 != 0)
+      return false;
+    int64_t Imm = ScalableImm / 16;
+
+    return Imm >= -32 && Imm <= 31;
+  }
 
   if (Immed == std::numeric_limits<int64_t>::min()) {
     LLVM_DEBUG(dbgs() << "Illegal add imm " << Immed
diff --git a/llvm/unittests/Target/AArch64/Immediates.cpp b/llvm/unittests/Target/AArch64/Immediates.cpp
index df96b3f5b9ec96..5f5895e44c6110 100644
--- a/llvm/unittests/Target/AArch64/Immediates.cpp
+++ b/llvm/unittests/Target/AArch64/Immediates.cpp
@@ -31,15 +31,15 @@ const std::initializer_list<TestCase> Tests = {
 
     // Scalable; addvl increments by whole registers, range [-32,31]
     // +(16 * vscale), one register's worth
-    {0, 16, false},
+    {0, 16, true},
     // +(8 * vscale), half a register's worth
     {0, 8, false},
     // -(32 * 16 * vscale)
-    {0, -512, false},
+    {0, -512, true},
     // -(33 * 16 * vscale)
     {0, -528, false},
     // +(31 * 16 * vscale)
-    {0, 496, false},
+    {0, 496, true},
     // +(32 * 16 * vscale)
     {0, 512, false},
 



More information about the llvm-commits mailing list