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
11using namespace llvm;
12
13namespace {
14
15struct AddrMode : public TargetLowering::AddrMode {
16 constexpr AddrMode(GlobalValue *GV, int64_t Offs, bool HasBase, int64_t S,
17 int64_t SOffs = 0) {
18 BaseGV = GV;
19 BaseOffs = Offs;
20 HasBaseReg = HasBase;
21 Scale = S;
22 ScalableOffset = SOffs;
23 }
24};
25struct TestCase {
26 AddrMode AM;
27 unsigned TypeBits;
28 bool Result;
29};
30
31const std::initializer_list<TestCase> Tests = {
32 // {BaseGV, BaseOffs, HasBaseReg, Scale}, Bits, Result
33 {.AM: {reinterpret_cast<GlobalValue *>(-1), 0, false, 0}, .TypeBits: 64, .Result: false},
34 {.AM: {nullptr, 8, true, 1}, .TypeBits: 64, .Result: false},
35 {.AM: {nullptr, 0, false, 2}, .TypeBits: 64, .Result: true},
36 {.AM: {nullptr, 0, false, 1}, .TypeBits: 64, .Result: true},
37 {.AM: {nullptr, 4, false, 0}, .TypeBits: 64, .Result: false},
38
39 {.AM: {nullptr, 0, true, 1}, .TypeBits: 64, .Result: true},
40 {.AM: {nullptr, 0, true, 1}, .TypeBits: 32, .Result: true},
41 {.AM: {nullptr, 0, true, 1}, .TypeBits: 16, .Result: true},
42 {.AM: {nullptr, 0, true, 1}, .TypeBits: 8, .Result: true},
43
44 {.AM: {nullptr, 0, true, 2}, .TypeBits: 64, .Result: false},
45 {.AM: {nullptr, 0, true, 2}, .TypeBits: 32, .Result: false},
46 {.AM: {nullptr, 0, true, 2}, .TypeBits: 16, .Result: true},
47 {.AM: {nullptr, 0, true, 2}, .TypeBits: 8, .Result: false},
48 {.AM: {nullptr, 0, true, 4}, .TypeBits: 64, .Result: false},
49 {.AM: {nullptr, 0, true, 4}, .TypeBits: 32, .Result: true},
50 {.AM: {nullptr, 0, true, 4}, .TypeBits: 16, .Result: false},
51 {.AM: {nullptr, 0, true, 4}, .TypeBits: 8, .Result: false},
52
53 {.AM: {nullptr, 0, true, 8}, .TypeBits: 64, .Result: true},
54 {.AM: {nullptr, 0, true, 8}, .TypeBits: 32, .Result: false},
55 {.AM: {nullptr, 0, true, 8}, .TypeBits: 16, .Result: false},
56 {.AM: {nullptr, 0, true, 8}, .TypeBits: 8, .Result: false},
57
58 {.AM: {nullptr, 0, true, 16}, .TypeBits: 64, .Result: false},
59 {.AM: {nullptr, 0, true, 16}, .TypeBits: 32, .Result: false},
60 {.AM: {nullptr, 0, true, 16}, .TypeBits: 16, .Result: false},
61 {.AM: {nullptr, 0, true, 16}, .TypeBits: 8, .Result: false},
62
63 {.AM: {nullptr, -257, true, 0}, .TypeBits: 64, .Result: false},
64 {.AM: {nullptr, -256, true, 0}, .TypeBits: 64, .Result: true},
65 {.AM: {nullptr, -255, true, 0}, .TypeBits: 64, .Result: true},
66 {.AM: {nullptr, -1, true, 0}, .TypeBits: 64, .Result: true},
67 {.AM: {nullptr, 0, true, 0}, .TypeBits: 64, .Result: true},
68 {.AM: {nullptr, 1, true, 0}, .TypeBits: 64, .Result: true},
69 {.AM: {nullptr, 254, true, 0}, .TypeBits: 64, .Result: true},
70 {.AM: {nullptr, 255, true, 0}, .TypeBits: 64, .Result: true},
71 {.AM: {nullptr, 256, true, 0}, .TypeBits: 64, .Result: true},
72 {.AM: {nullptr, 257, true, 0}, .TypeBits: 64, .Result: false},
73 {.AM: {nullptr, 258, true, 0}, .TypeBits: 64, .Result: false},
74 {.AM: {nullptr, 259, true, 0}, .TypeBits: 64, .Result: false},
75 {.AM: {nullptr, 260, true, 0}, .TypeBits: 64, .Result: false},
76 {.AM: {nullptr, 261, true, 0}, .TypeBits: 64, .Result: false},
77 {.AM: {nullptr, 262, true, 0}, .TypeBits: 64, .Result: false},
78 {.AM: {nullptr, 263, true, 0}, .TypeBits: 64, .Result: false},
79 {.AM: {nullptr, 264, true, 0}, .TypeBits: 64, .Result: true},
80
81 {.AM: {nullptr, 4096 * 8 - 8, true, 0}, .TypeBits: 64, .Result: true},
82 {.AM: {nullptr, 4096 * 8 - 7, true, 0}, .TypeBits: 64, .Result: false},
83 {.AM: {nullptr, 4096 * 8 - 6, true, 0}, .TypeBits: 64, .Result: false},
84 {.AM: {nullptr, 4096 * 8 - 5, true, 0}, .TypeBits: 64, .Result: false},
85 {.AM: {nullptr, 4096 * 8 - 4, true, 0}, .TypeBits: 64, .Result: false},
86 {.AM: {nullptr, 4096 * 8 - 3, true, 0}, .TypeBits: 64, .Result: false},
87 {.AM: {nullptr, 4096 * 8 - 2, true, 0}, .TypeBits: 64, .Result: false},
88 {.AM: {nullptr, 4096 * 8 - 1, true, 0}, .TypeBits: 64, .Result: false},
89 {.AM: {nullptr, 4096 * 8, true, 0}, .TypeBits: 64, .Result: false},
90 {.AM: {nullptr, 4096 * 8 + 1, true, 0}, .TypeBits: 64, .Result: false},
91 {.AM: {nullptr, 4096 * 8 + 2, true, 0}, .TypeBits: 64, .Result: false},
92 {.AM: {nullptr, 4096 * 8 + 3, true, 0}, .TypeBits: 64, .Result: false},
93 {.AM: {nullptr, 4096 * 8 + 4, true, 0}, .TypeBits: 64, .Result: false},
94 {.AM: {nullptr, 4096 * 8 + 5, true, 0}, .TypeBits: 64, .Result: false},
95 {.AM: {nullptr, 4096 * 8 + 6, true, 0}, .TypeBits: 64, .Result: false},
96 {.AM: {nullptr, 4096 * 8 + 7, true, 0}, .TypeBits: 64, .Result: false},
97 {.AM: {nullptr, 4096 * 8 + 8, true, 0}, .TypeBits: 64, .Result: false},
98
99 {.AM: {nullptr, -257, true, 0}, .TypeBits: 32, .Result: false},
100 {.AM: {nullptr, -256, true, 0}, .TypeBits: 32, .Result: true},
101 {.AM: {nullptr, -255, true, 0}, .TypeBits: 32, .Result: true},
102 {.AM: {nullptr, -1, true, 0}, .TypeBits: 32, .Result: true},
103 {.AM: {nullptr, 0, true, 0}, .TypeBits: 32, .Result: true},
104 {.AM: {nullptr, 1, true, 0}, .TypeBits: 32, .Result: true},
105 {.AM: {nullptr, 254, true, 0}, .TypeBits: 32, .Result: true},
106 {.AM: {nullptr, 255, true, 0}, .TypeBits: 32, .Result: true},
107 {.AM: {nullptr, 256, true, 0}, .TypeBits: 32, .Result: true},
108 {.AM: {nullptr, 257, true, 0}, .TypeBits: 32, .Result: false},
109 {.AM: {nullptr, 258, true, 0}, .TypeBits: 32, .Result: false},
110 {.AM: {nullptr, 259, true, 0}, .TypeBits: 32, .Result: false},
111 {.AM: {nullptr, 260, true, 0}, .TypeBits: 32, .Result: true},
112
113 {.AM: {nullptr, 4096 * 4 - 4, true, 0}, .TypeBits: 32, .Result: true},
114 {.AM: {nullptr, 4096 * 4 - 3, true, 0}, .TypeBits: 32, .Result: false},
115 {.AM: {nullptr, 4096 * 4 - 2, true, 0}, .TypeBits: 32, .Result: false},
116 {.AM: {nullptr, 4096 * 4 - 1, true, 0}, .TypeBits: 32, .Result: false},
117 {.AM: {nullptr, 4096 * 4, true, 0}, .TypeBits: 32, .Result: false},
118 {.AM: {nullptr, 4096 * 4 + 1, true, 0}, .TypeBits: 32, .Result: false},
119 {.AM: {nullptr, 4096 * 4 + 2, true, 0}, .TypeBits: 32, .Result: false},
120 {.AM: {nullptr, 4096 * 4 + 3, true, 0}, .TypeBits: 32, .Result: false},
121 {.AM: {nullptr, 4096 * 4 + 4, true, 0}, .TypeBits: 32, .Result: false},
122
123 {.AM: {nullptr, -257, true, 0}, .TypeBits: 16, .Result: false},
124 {.AM: {nullptr, -256, true, 0}, .TypeBits: 16, .Result: true},
125 {.AM: {nullptr, -255, true, 0}, .TypeBits: 16, .Result: true},
126 {.AM: {nullptr, -1, true, 0}, .TypeBits: 16, .Result: true},
127 {.AM: {nullptr, 0, true, 0}, .TypeBits: 16, .Result: true},
128 {.AM: {nullptr, 1, true, 0}, .TypeBits: 16, .Result: true},
129 {.AM: {nullptr, 254, true, 0}, .TypeBits: 16, .Result: true},
130 {.AM: {nullptr, 255, true, 0}, .TypeBits: 16, .Result: true},
131 {.AM: {nullptr, 256, true, 0}, .TypeBits: 16, .Result: true},
132 {.AM: {nullptr, 257, true, 0}, .TypeBits: 16, .Result: false},
133 {.AM: {nullptr, 258, true, 0}, .TypeBits: 16, .Result: true},
134
135 {.AM: {nullptr, 4096 * 2 - 2, true, 0}, .TypeBits: 16, .Result: true},
136 {.AM: {nullptr, 4096 * 2 - 1, true, 0}, .TypeBits: 16, .Result: false},
137 {.AM: {nullptr, 4096 * 2, true, 0}, .TypeBits: 16, .Result: false},
138 {.AM: {nullptr, 4096 * 2 + 1, true, 0}, .TypeBits: 16, .Result: false},
139 {.AM: {nullptr, 4096 * 2 + 2, true, 0}, .TypeBits: 16, .Result: false},
140
141 {.AM: {nullptr, -257, true, 0}, .TypeBits: 8, .Result: false},
142 {.AM: {nullptr, -256, true, 0}, .TypeBits: 8, .Result: true},
143 {.AM: {nullptr, -255, true, 0}, .TypeBits: 8, .Result: true},
144 {.AM: {nullptr, -1, true, 0}, .TypeBits: 8, .Result: true},
145 {.AM: {nullptr, 0, true, 0}, .TypeBits: 8, .Result: true},
146 {.AM: {nullptr, 1, true, 0}, .TypeBits: 8, .Result: true},
147 {.AM: {nullptr, 254, true, 0}, .TypeBits: 8, .Result: true},
148 {.AM: {nullptr, 255, true, 0}, .TypeBits: 8, .Result: true},
149 {.AM: {nullptr, 256, true, 0}, .TypeBits: 8, .Result: true},
150 {.AM: {nullptr, 257, true, 0}, .TypeBits: 8, .Result: true},
151
152 {.AM: {nullptr, 4096 - 2, true, 0}, .TypeBits: 8, .Result: true},
153 {.AM: {nullptr, 4096 - 1, true, 0}, .TypeBits: 8, .Result: true},
154 {.AM: {nullptr, 4096, true, 0}, .TypeBits: 8, .Result: false},
155 {.AM: {nullptr, 4096 + 1, true, 0}, .TypeBits: 8, .Result: false},
156
157};
158
159struct SVETestCase {
160 AddrMode AM;
161 unsigned TypeBits;
162 unsigned NumElts;
163 bool Result;
164};
165
166const std::initializer_list<SVETestCase> SVETests = {
167 // {BaseGV, BaseOffs, HasBaseReg, Scale, SOffs}, EltBits, Count, Result
168 // Test immediate range -- [-8,7] vector's worth.
169 // <vscale x 16 x i8>, increment by one vector
170 {.AM: {nullptr, 0, true, 0, 16}, .TypeBits: 8, .NumElts: 16, .Result: true},
171 // <vscale x 4 x i32>, increment by eight vectors
172 {.AM: {nullptr, 0, true, 0, 128}, .TypeBits: 32, .NumElts: 4, .Result: false},
173 // <vscale x 8 x i16>, increment by seven vectors
174 {.AM: {nullptr, 0, true, 0, 112}, .TypeBits: 16, .NumElts: 8, .Result: true},
175 // <vscale x 2 x i64>, decrement by eight vectors
176 {.AM: {nullptr, 0, true, 0, -128}, .TypeBits: 64, .NumElts: 2, .Result: true},
177 // <vscale x 16 x i8>, decrement by nine vectors
178 {.AM: {nullptr, 0, true, 0, -144}, .TypeBits: 8, .NumElts: 16, .Result: false},
179
180 // Half the size of a vector register, but allowable with extending
181 // loads and truncating stores
182 // <vscale x 8 x i8>, increment by three vectors
183 {.AM: {nullptr, 0, true, 0, 24}, .TypeBits: 8, .NumElts: 8, .Result: true},
184
185 // Test invalid types or offsets
186 // <vscale x 5 x i32>, increment by one vector (base size > 16B)
187 {.AM: {nullptr, 0, true, 0, 20}, .TypeBits: 32, .NumElts: 5, .Result: false},
188 // <vscale x 8 x i16>, increment by half a vector
189 {.AM: {nullptr, 0, true, 0, 8}, .TypeBits: 16, .NumElts: 8, .Result: false},
190 // <vscale x 3 x i8>, increment by 3 vectors (non-power-of-two)
191 {.AM: {nullptr, 0, true, 0, 9}, .TypeBits: 8, .NumElts: 3, .Result: false},
192
193 // Scalable and fixed offsets
194 // <vscale x 16 x i8>, increment by 32 then decrement by vscale x 16
195 {.AM: {nullptr, 32, true, 0, -16}, .TypeBits: 8, .NumElts: 16, .Result: false},
196};
197} // namespace
198
199TEST(AddressingModes, AddressingModes) {
200 LLVMInitializeAArch64TargetInfo();
201 LLVMInitializeAArch64Target();
202 LLVMInitializeAArch64TargetMC();
203
204 std::string Error;
205 auto TT = Triple::normalize(Str: "aarch64");
206 const Target *T = TargetRegistry::lookupTarget(Triple: TT, Error);
207
208 std::unique_ptr<TargetMachine> TM(
209 T->createTargetMachine(TT, CPU: "generic", Features: "", Options: TargetOptions(), RM: std::nullopt,
210 CM: std::nullopt, OL: CodeGenOptLevel::Default));
211 AArch64Subtarget ST(TM->getTargetTriple(), TM->getTargetCPU(),
212 TM->getTargetCPU(), TM->getTargetFeatureString(), *TM,
213 true);
214
215 auto *TLI = ST.getTargetLowering();
216 DataLayout DL("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
217 LLVMContext Ctx;
218
219 for (const auto &Test : Tests) {
220 Type *Typ = Type::getIntNTy(C&: Ctx, N: Test.TypeBits);
221 ASSERT_EQ(TLI->isLegalAddressingMode(DL, Test.AM, Typ, 0), Test.Result);
222 }
223
224 for (const auto &SVETest : SVETests) {
225 Type *Ty = VectorType::get(ElementType: Type::getIntNTy(C&: Ctx, N: SVETest.TypeBits),
226 EC: ElementCount::getScalable(MinVal: SVETest.NumElts));
227 ASSERT_EQ(TLI->isLegalAddressingMode(DL, SVETest.AM, Ty, 0),
228 SVETest.Result);
229 }
230}
231

source code of llvm/unittests/Target/AArch64/AddressingModes.cpp