Skip to content

Commit 36a3f8f

Browse files
authored
[TTI][TLI][AArch64] Support scalable immediates with isLegalAddImmediate (#84173)
Adds a second parameter (default to 0) to isLegalAddImmediate, to represent a scalable immediate. Extends the AArch64 implementation to match immediates based on what addvl and inc[h|w|d] support.
1 parent 7227ec9 commit 36a3f8f

File tree

9 files changed

+166
-0
lines changed

9 files changed

+166
-0
lines changed

llvm/include/llvm/Analysis/TargetTransformInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,12 @@ class TargetTransformInfo {
696696
/// immediate without having to materialize the immediate into a register.
697697
bool isLegalAddImmediate(int64_t Imm) const;
698698

699+
/// Return true if adding the specified scalable immediate is legal, that is
700+
/// the target has add instructions which can add a register with the
701+
/// immediate (multiplied by vscale) without having to materialize the
702+
/// immediate into a register.
703+
bool isLegalAddScalableImmediate(int64_t Imm) const;
704+
699705
/// Return true if the specified immediate is legal icmp immediate,
700706
/// that is the target has icmp instructions which can compare a register
701707
/// against the immediate without having to materialize the immediate into a
@@ -1842,6 +1848,7 @@ class TargetTransformInfo::Concept {
18421848
std::function<void(Instruction *, unsigned, APInt, APInt &)>
18431849
SimplifyAndSetOp) = 0;
18441850
virtual bool isLegalAddImmediate(int64_t Imm) = 0;
1851+
virtual bool isLegalAddScalableImmediate(int64_t Imm) = 0;
18451852
virtual bool isLegalICmpImmediate(int64_t Imm) = 0;
18461853
virtual bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV,
18471854
int64_t BaseOffset, bool HasBaseReg,
@@ -2303,6 +2310,9 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
23032310
bool isLegalAddImmediate(int64_t Imm) override {
23042311
return Impl.isLegalAddImmediate(Imm);
23052312
}
2313+
bool isLegalAddScalableImmediate(int64_t Imm) override {
2314+
return Impl.isLegalAddScalableImmediate(Imm);
2315+
}
23062316
bool isLegalICmpImmediate(int64_t Imm) override {
23072317
return Impl.isLegalICmpImmediate(Imm);
23082318
}

llvm/include/llvm/Analysis/TargetTransformInfoImpl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ class TargetTransformInfoImplBase {
216216

217217
bool isLegalAddImmediate(int64_t Imm) const { return false; }
218218

219+
bool isLegalAddScalableImmediate(int64_t Imm) const { return false; }
220+
219221
bool isLegalICmpImmediate(int64_t Imm) const { return false; }
220222

221223
bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,

llvm/include/llvm/CodeGen/BasicTTIImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
328328
return getTLI()->isLegalAddImmediate(imm);
329329
}
330330

331+
bool isLegalAddScalableImmediate(int64_t Imm) {
332+
return getTLI()->isLegalAddScalableImmediate(Imm);
333+
}
334+
331335
bool isLegalICmpImmediate(int64_t imm) {
332336
return getTLI()->isLegalICmpImmediate(imm);
333337
}

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,6 +2772,12 @@ class TargetLoweringBase {
27722772
return true;
27732773
}
27742774

2775+
/// Return true if adding the specified scalable immediate is legal, that is
2776+
/// the target has add instructions which can add a register with the
2777+
/// immediate (multiplied by vscale) without having to materialize the
2778+
/// immediate into a register.
2779+
virtual bool isLegalAddScalableImmediate(int64_t) const { return false; }
2780+
27752781
/// Return true if the specified immediate is legal for the value input of a
27762782
/// store instruction.
27772783
virtual bool isLegalStoreImmediate(int64_t Value) const {

llvm/lib/Analysis/TargetTransformInfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,10 @@ bool TargetTransformInfo::isLegalAddImmediate(int64_t Imm) const {
396396
return TTIImpl->isLegalAddImmediate(Imm);
397397
}
398398

399+
bool TargetTransformInfo::isLegalAddScalableImmediate(int64_t Imm) const {
400+
return TTIImpl->isLegalAddScalableImmediate(Imm);
401+
}
402+
399403
bool TargetTransformInfo::isLegalICmpImmediate(int64_t Imm) const {
400404
return TTIImpl->isLegalICmpImmediate(Imm);
401405
}

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16616,6 +16616,38 @@ bool AArch64TargetLowering::isLegalAddImmediate(int64_t Immed) const {
1661616616
return IsLegal;
1661716617
}
1661816618

16619+
bool AArch64TargetLowering::isLegalAddScalableImmediate(int64_t Imm) const {
16620+
// We will only emit addvl/inc* instructions for SVE2
16621+
if (!Subtarget->hasSVE2())
16622+
return false;
16623+
16624+
// addvl's immediates are in terms of the number of bytes in a register.
16625+
// Since there are 16 in the base supported size (128bits), we need to
16626+
// divide the immediate by that much to give us a useful immediate to
16627+
// multiply by vscale. We can't have a remainder as a result of this.
16628+
if (Imm % 16 == 0)
16629+
return isInt<6>(Imm / 16);
16630+
16631+
// Inc[b|h|w|d] instructions take a pattern and a positive immediate
16632+
// multiplier. For now, assume a pattern of 'all'. Incb would be a subset
16633+
// of addvl as a result, so only take h|w|d into account.
16634+
// Dec[h|w|d] will cover subtractions.
16635+
// Immediates are in the range [1,16], so we can't do a 2's complement check.
16636+
// FIXME: Can we make use of other patterns to cover other immediates?
16637+
16638+
// inch|dech
16639+
if (Imm % 8 == 0)
16640+
return std::labs(Imm / 8) <= 16;
16641+
// incw|decw
16642+
if (Imm % 4 == 0)
16643+
return std::labs(Imm / 4) <= 16;
16644+
// incd|decd
16645+
if (Imm % 2 == 0)
16646+
return std::labs(Imm / 2) <= 16;
16647+
16648+
return false;
16649+
}
16650+
1661916651
// Return false to prevent folding
1662016652
// (mul (add x, c1), c2) -> (add (mul x, c2), c2*c1) in DAGCombine,
1662116653
// if the folding leads to worse code.

llvm/lib/Target/AArch64/AArch64ISelLowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@ class AArch64TargetLowering : public TargetLowering {
689689
StoreInst *SI) const override;
690690

691691
bool isLegalAddImmediate(int64_t) const override;
692+
bool isLegalAddScalableImmediate(int64_t) const override;
692693
bool isLegalICmpImmediate(int64_t) const override;
693694

694695
bool isMulAddWithConstProfitable(SDValue AddNode,

llvm/unittests/Target/AArch64/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_llvm_target_unittest(AArch64Tests
2929
MatrixRegisterAliasing.cpp
3030
SMEAttributesTest.cpp
3131
AArch64SVESchedPseudoTest.cpp
32+
Immediates.cpp
3233
)
3334

3435
set_property(TARGET AArch64Tests PROPERTY FOLDER "Tests/UnitTests/TargetTests")
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#include "AArch64Subtarget.h"
2+
#include "AArch64TargetMachine.h"
3+
#include "llvm/IR/DataLayout.h"
4+
#include "llvm/MC/TargetRegistry.h"
5+
#include "llvm/Support/TargetSelect.h"
6+
7+
#include "gtest/gtest.h"
8+
#include <initializer_list>
9+
#include <memory>
10+
11+
using namespace llvm;
12+
13+
namespace {
14+
15+
struct TestCase {
16+
int64_t Imm;
17+
bool Result;
18+
};
19+
20+
const std::initializer_list<TestCase> Tests = {
21+
// ScalableImm, Result
22+
// No change, easily 'supported'
23+
{0, true},
24+
25+
// addvl increments by whole registers, range [-32,31]
26+
// +(16 * vscale), one register's worth
27+
{16, true},
28+
// -(32 * 16 * vscale)
29+
{-512, true},
30+
// -(33 * 16 * vscale)
31+
{-528, false},
32+
// +(31 * 16 * vscale)
33+
{496, true},
34+
// +(32 * 16 * vscale)
35+
{512, false},
36+
37+
// inc[h|w|d] increments by the number of 16/32/64bit elements in a
38+
// register. mult_imm is in the range [1,16]
39+
// +(mult_imm * num_elts * vscale)
40+
// +(1 * 8 * vscale), 16 bit
41+
{8, true},
42+
// +(15 * 8 * vscale), 16 bit
43+
{120, true},
44+
// +(1 * 4 * vscale), 32 bit
45+
{4, true},
46+
// +(7 * 4 * vscale), 32 bit
47+
{28, true},
48+
// +(1 * 2 * vscale), 64 bit
49+
{2, true},
50+
// +(13 * 2 * vscale), 64 bit
51+
{26, true},
52+
// +(17 * 8 * vscale), 16 bit, out of range.
53+
{136, false},
54+
// +(19 * 2 * vscale), 64 bit, out of range.
55+
{38, false},
56+
// +(21 * 4 * vscale), 32 bit, out of range.
57+
{84, false},
58+
59+
// dec[h|w|d] -- Same as above, but negative.
60+
// -(mult_imm * num_elts * vscale)
61+
// -(1 * 8 * vscale), 16 bit
62+
{-8, true},
63+
// -(15 * 8 * vscale), 16 bit
64+
{-120, true},
65+
// -(1 * 4 * vscale), 32 bit
66+
{-4, true},
67+
// -(7 * 4 * vscale), 32 bit
68+
{-28, true},
69+
// -(1 * 2 * vscale), 64 bit
70+
{-2, true},
71+
// -(13 * 2 * vscale), 64 bit
72+
{-26, true},
73+
// -(17 * 8 * vscale), 16 bit, out of range.
74+
{-136, false},
75+
// -(19 * 2 * vscale), 64 bit, out of range.
76+
{-38, false},
77+
// -(21 * 4 * vscale), 32 bit, out of range.
78+
{-84, false},
79+
80+
// Invalid; not divisible by the above powers of 2.
81+
{5, false},
82+
};
83+
} // namespace
84+
85+
TEST(Immediates, Immediates) {
86+
LLVMInitializeAArch64TargetInfo();
87+
LLVMInitializeAArch64Target();
88+
LLVMInitializeAArch64TargetMC();
89+
90+
std::string Error;
91+
auto TT = Triple::normalize("aarch64");
92+
const Target *T = TargetRegistry::lookupTarget(TT, Error);
93+
94+
std::unique_ptr<TargetMachine> TM(T->createTargetMachine(
95+
TT, "generic", "+sve2", TargetOptions(), std::nullopt, std::nullopt,
96+
CodeGenOptLevel::Default));
97+
AArch64Subtarget ST(TM->getTargetTriple(), TM->getTargetCPU(),
98+
TM->getTargetCPU(), TM->getTargetFeatureString(), *TM,
99+
true);
100+
101+
auto *TLI = ST.getTargetLowering();
102+
103+
for (const auto &Test : Tests) {
104+
ASSERT_EQ(TLI->isLegalAddScalableImmediate(Test.Imm), Test.Result);
105+
}
106+
}

0 commit comments

Comments
 (0)