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 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 | }; |
25 | struct TestCase { |
26 | AddrMode AM; |
27 | unsigned TypeBits; |
28 | bool Result; |
29 | }; |
30 | |
31 | const 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 | |
159 | struct SVETestCase { |
160 | AddrMode AM; |
161 | unsigned TypeBits; |
162 | unsigned NumElts; |
163 | bool Result; |
164 | }; |
165 | |
166 | const 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 | |
199 | TEST(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 | |