1 //===- llvm/unittest/CodeGen/GlobalISel/LegalizerInfoTest.cpp -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
10 #include "llvm/CodeGen/TargetOpcodes.h"
11 #include "GISelMITest.h"
12 #include "gtest/gtest.h"
13 
14 using namespace llvm;
15 using namespace LegalizeActions;
16 
17 // Define a couple of pretty printers to help debugging when things go wrong.
18 namespace llvm {
19 std::ostream &
operator <<(std::ostream & OS,const LegalizeAction Act)20 operator<<(std::ostream &OS, const LegalizeAction Act) {
21   switch (Act) {
22   case Lower: OS << "Lower"; break;
23   case Legal: OS << "Legal"; break;
24   case NarrowScalar: OS << "NarrowScalar"; break;
25   case WidenScalar:  OS << "WidenScalar"; break;
26   case FewerElements:  OS << "FewerElements"; break;
27   case MoreElements:  OS << "MoreElements"; break;
28   case Libcall: OS << "Libcall"; break;
29   case Custom: OS << "Custom"; break;
30   case Bitcast: OS << "Bitcast"; break;
31   case Unsupported: OS << "Unsupported"; break;
32   case NotFound: OS << "NotFound"; break;
33   case UseLegacyRules: OS << "UseLegacyRules"; break;
34   }
35   return OS;
36 }
37 
operator <<(std::ostream & OS,const llvm::LegalizeActionStep Ty)38 std::ostream &operator<<(std::ostream &OS, const llvm::LegalizeActionStep Ty) {
39   OS << "LegalizeActionStep(" << Ty.Action << ", " << Ty.TypeIdx << ", "
40      << Ty.NewType << ')';
41   return OS;
42 }
43 }
44 
45 namespace {
46 
47 
TEST(LegalizerInfoTest,ScalarRISC)48 TEST(LegalizerInfoTest, ScalarRISC) {
49   using namespace TargetOpcode;
50   LegalizerInfo L;
51   // Typical RISCy set of operations based on AArch64.
52   for (unsigned Op : {G_ADD, G_SUB}) {
53     for (unsigned Size : {32, 64})
54       L.setAction({Op, 0, LLT::scalar(Size)}, Legal);
55     L.setLegalizeScalarToDifferentSizeStrategy(
56         Op, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest);
57   }
58 
59   L.computeTables();
60 
61   for (unsigned opcode : {G_ADD, G_SUB}) {
62     // Check we infer the correct types and actually do what we're told.
63     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(8)}}),
64               LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
65     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(16)}}),
66               LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
67     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(32)}}),
68               LegalizeActionStep(Legal, 0, LLT{}));
69     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(64)}}),
70               LegalizeActionStep(Legal, 0, LLT{}));
71 
72     // Make sure the default for over-sized types applies.
73     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(128)}}),
74               LegalizeActionStep(NarrowScalar, 0, LLT::scalar(64)));
75     // Make sure we also handle unusual sizes
76     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(1)}}),
77               LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
78     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(31)}}),
79               LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
80     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(33)}}),
81               LegalizeActionStep(WidenScalar, 0, LLT::scalar(64)));
82     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(63)}}),
83               LegalizeActionStep(WidenScalar, 0, LLT::scalar(64)));
84     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(65)}}),
85               LegalizeActionStep(NarrowScalar, 0, LLT::scalar(64)));
86   }
87 }
88 
TEST(LegalizerInfoTest,VectorRISC)89 TEST(LegalizerInfoTest, VectorRISC) {
90   using namespace TargetOpcode;
91   LegalizerInfo L;
92   // Typical RISCy set of operations based on ARM.
93   L.setAction({G_ADD, LLT::vector(8, 8)}, Legal);
94   L.setAction({G_ADD, LLT::vector(16, 8)}, Legal);
95   L.setAction({G_ADD, LLT::vector(4, 16)}, Legal);
96   L.setAction({G_ADD, LLT::vector(8, 16)}, Legal);
97   L.setAction({G_ADD, LLT::vector(2, 32)}, Legal);
98   L.setAction({G_ADD, LLT::vector(4, 32)}, Legal);
99 
100   L.setLegalizeVectorElementToDifferentSizeStrategy(
101       G_ADD, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
102 
103   L.setAction({G_ADD, 0, LLT::scalar(32)}, Legal);
104 
105   L.computeTables();
106 
107   // Check we infer the correct types and actually do what we're told for some
108   // simple cases.
109   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 8)}}),
110             LegalizeActionStep(Legal, 0, LLT{}));
111   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 7)}}),
112             LegalizeActionStep(WidenScalar, 0, LLT::vector(8, 8)));
113   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(2, 8)}}),
114             LegalizeActionStep(MoreElements, 0, LLT::vector(8, 8)));
115   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 32)}}),
116             LegalizeActionStep(FewerElements, 0, LLT::vector(4, 32)));
117   // Check a few non-power-of-2 sizes:
118   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(3, 3)}}),
119             LegalizeActionStep(WidenScalar, 0, LLT::vector(3, 8)));
120   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(3, 8)}}),
121             LegalizeActionStep(MoreElements, 0, LLT::vector(8, 8)));
122 }
123 
TEST(LegalizerInfoTest,MultipleTypes)124 TEST(LegalizerInfoTest, MultipleTypes) {
125   using namespace TargetOpcode;
126   LegalizerInfo L;
127   LLT p0 = LLT::pointer(0, 64);
128   LLT s64 = LLT::scalar(64);
129 
130   // Typical RISCy set of operations based on AArch64.
131   L.setAction({G_PTRTOINT, 0, s64}, Legal);
132   L.setAction({G_PTRTOINT, 1, p0}, Legal);
133 
134   L.setLegalizeScalarToDifferentSizeStrategy(
135       G_PTRTOINT, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest);
136 
137   L.computeTables();
138 
139   // Check we infer the correct types and actually do what we're told.
140   EXPECT_EQ(L.getAction({G_PTRTOINT, {s64, p0}}),
141             LegalizeActionStep(Legal, 0, LLT{}));
142 
143   // Make sure we also handle unusual sizes
144   EXPECT_EQ(
145       L.getAction({G_PTRTOINT, {LLT::scalar(65), s64}}),
146       LegalizeActionStep(NarrowScalar, 0, s64));
147   EXPECT_EQ(
148       L.getAction({G_PTRTOINT, {s64, LLT::pointer(0, 32)}}),
149       LegalizeActionStep(Unsupported, 1, LLT::pointer(0, 32)));
150 }
151 
TEST(LegalizerInfoTest,MultipleSteps)152 TEST(LegalizerInfoTest, MultipleSteps) {
153   using namespace TargetOpcode;
154   LegalizerInfo L;
155   LLT s32 = LLT::scalar(32);
156   LLT s64 = LLT::scalar(64);
157 
158   L.setLegalizeScalarToDifferentSizeStrategy(
159       G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
160   L.setAction({G_UREM, 0, s32}, Lower);
161   L.setAction({G_UREM, 0, s64}, Lower);
162 
163   L.computeTables();
164 
165   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(16)}}),
166             LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
167   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(32)}}),
168             LegalizeActionStep(Lower, 0, LLT::scalar(32)));
169 }
170 
TEST(LegalizerInfoTest,SizeChangeStrategy)171 TEST(LegalizerInfoTest, SizeChangeStrategy) {
172   using namespace TargetOpcode;
173   LegalizerInfo L;
174   for (unsigned Size : {1, 8, 16, 32})
175     L.setAction({G_UREM, 0, LLT::scalar(Size)}, Legal);
176 
177   L.setLegalizeScalarToDifferentSizeStrategy(
178       G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
179   L.computeTables();
180 
181   // Check we infer the correct types and actually do what we're told.
182   for (unsigned Size : {1, 8, 16, 32}) {
183     EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(Size)}}),
184               LegalizeActionStep(Legal, 0, LLT{}));
185   }
186   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(2)}}),
187             LegalizeActionStep(WidenScalar, 0, LLT::scalar(8)));
188   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(7)}}),
189             LegalizeActionStep(WidenScalar, 0, LLT::scalar(8)));
190   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(9)}}),
191             LegalizeActionStep(WidenScalar, 0, LLT::scalar(16)));
192   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(17)}}),
193             LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
194   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(31)}}),
195             LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
196   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(33)}}),
197             LegalizeActionStep(Unsupported, 0, LLT::scalar(33)));
198 }
199 }
200 
201 #define EXPECT_ACTION(Action, Index, Type, Query)                              \
202   do {                                                                         \
203     auto A = LI.getAction(Query);                                              \
204     EXPECT_EQ(LegalizeActionStep(Action, Index, Type), A) << A;                \
205   } while (0)
206 
TEST(LegalizerInfoTest,RuleSets)207 TEST(LegalizerInfoTest, RuleSets) {
208   using namespace TargetOpcode;
209 
210   const LLT s5 = LLT::scalar(5);
211   const LLT s8 = LLT::scalar(8);
212   const LLT s16 = LLT::scalar(16);
213   const LLT s32 = LLT::scalar(32);
214   const LLT s33 = LLT::scalar(33);
215   const LLT s64 = LLT::scalar(64);
216 
217   const LLT v2s5 = LLT::vector(2, 5);
218   const LLT v2s8 = LLT::vector(2, 8);
219   const LLT v2s16 = LLT::vector(2, 16);
220   const LLT v2s32 = LLT::vector(2, 32);
221   const LLT v3s32 = LLT::vector(3, 32);
222   const LLT v4s32 = LLT::vector(4, 32);
223   const LLT v2s33 = LLT::vector(2, 33);
224   const LLT v2s64 = LLT::vector(2, 64);
225 
226   const LLT p0 = LLT::pointer(0, 32);
227   const LLT v3p0 = LLT::vector(3, p0);
228   const LLT v4p0 = LLT::vector(4, p0);
229 
230   {
231     LegalizerInfo LI;
232 
233     LI.getActionDefinitionsBuilder(G_IMPLICIT_DEF)
234       .legalFor({v4s32, v4p0})
235       .moreElementsToNextPow2(0);
236     LI.computeTables();
237 
238     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_IMPLICIT_DEF, {s32}));
239     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_IMPLICIT_DEF, {v2s32}));
240     EXPECT_ACTION(MoreElements, 0, v4p0, LegalityQuery(G_IMPLICIT_DEF, {v3p0}));
241     EXPECT_ACTION(MoreElements, 0, v4s32, LegalityQuery(G_IMPLICIT_DEF, {v3s32}));
242   }
243 
244   // Test minScalarOrElt
245   {
246     LegalizerInfo LI;
247     LI.getActionDefinitionsBuilder(G_OR)
248       .legalFor({s32})
249       .minScalarOrElt(0, s32);
250     LI.computeTables();
251 
252     EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16}));
253     EXPECT_ACTION(WidenScalar, 0, v2s32, LegalityQuery(G_OR, {v2s16}));
254   }
255 
256   // Test maxScalarOrELt
257   {
258     LegalizerInfo LI;
259     LI.getActionDefinitionsBuilder(G_AND)
260       .legalFor({s16})
261       .maxScalarOrElt(0, s16);
262     LI.computeTables();
263 
264     EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32}));
265     EXPECT_ACTION(NarrowScalar, 0, v2s16, LegalityQuery(G_AND, {v2s32}));
266   }
267 
268   // Test clampScalarOrElt
269   {
270     LegalizerInfo LI;
271     LI.getActionDefinitionsBuilder(G_XOR)
272       .legalFor({s16})
273       .clampScalarOrElt(0, s16, s32);
274     LI.computeTables();
275 
276     EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64}));
277     EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8}));
278 
279     // Make sure the number of elements is preserved.
280     EXPECT_ACTION(NarrowScalar, 0, v2s32, LegalityQuery(G_XOR, {v2s64}));
281     EXPECT_ACTION(WidenScalar, 0, v2s16, LegalityQuery(G_XOR, {v2s8}));
282   }
283 
284   // Test minScalar
285   {
286     LegalizerInfo LI;
287     LI.getActionDefinitionsBuilder(G_OR)
288       .legalFor({s32})
289       .minScalar(0, s32);
290     LI.computeTables();
291 
292     // Only handle scalars, ignore vectors.
293     EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16}));
294     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_OR, {v2s16}));
295   }
296 
297   // Test maxScalar
298   {
299     LegalizerInfo LI;
300     LI.getActionDefinitionsBuilder(G_AND)
301       .legalFor({s16})
302       .maxScalar(0, s16);
303     LI.computeTables();
304 
305     // Only handle scalars, ignore vectors.
306     EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32}));
307     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s32}));
308   }
309 
310   // Test clampScalar
311   {
312     LegalizerInfo LI;
313 
314     LI.getActionDefinitionsBuilder(G_XOR)
315       .legalFor({s16})
316       .clampScalar(0, s16, s32);
317     LI.computeTables();
318 
319     EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64}));
320     EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8}));
321 
322     // Only handle scalars, ignore vectors.
323     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_XOR, {v2s64}));
324     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_XOR, {v2s8}));
325   }
326 
327   // Test widenScalarOrEltToNextPow2
328   {
329     LegalizerInfo LI;
330 
331     LI.getActionDefinitionsBuilder(G_AND)
332       .legalFor({s32})
333       .widenScalarOrEltToNextPow2(0, 32);
334     LI.computeTables();
335 
336     // Handle scalars and vectors
337     EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5}));
338     EXPECT_ACTION(WidenScalar, 0, v2s32, LegalityQuery(G_AND, {v2s5}));
339     EXPECT_ACTION(WidenScalar, 0, s64, LegalityQuery(G_AND, {s33}));
340     EXPECT_ACTION(WidenScalar, 0, v2s64, LegalityQuery(G_AND, {v2s33}));
341   }
342 
343   // Test widenScalarToNextPow2
344   {
345     LegalizerInfo LI;
346 
347     LI.getActionDefinitionsBuilder(G_AND)
348       .legalFor({s32})
349       .widenScalarToNextPow2(0, 32);
350     LI.computeTables();
351 
352     EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5}));
353     EXPECT_ACTION(WidenScalar, 0, s64, LegalityQuery(G_AND, {s33}));
354 
355     // Do nothing for vectors.
356     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s5}));
357     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s33}));
358   }
359 }
360 
TEST(LegalizerInfoTest,MMOAlignment)361 TEST(LegalizerInfoTest, MMOAlignment) {
362   using namespace TargetOpcode;
363 
364   const LLT s32 = LLT::scalar(32);
365   const LLT p0 = LLT::pointer(0, 64);
366 
367   {
368     LegalizerInfo LI;
369     LI.getActionDefinitionsBuilder(G_LOAD)
370       .legalForTypesWithMemDesc({{s32, p0, 32, 32}});
371 
372     LI.computeTables();
373 
374     EXPECT_ACTION(Legal, 0, LLT(),
375                   LegalityQuery(G_LOAD, {s32, p0},
376                                 LegalityQuery::MemDesc{
377                                   32, 32, AtomicOrdering::NotAtomic}));
378     EXPECT_ACTION(Unsupported, 0, LLT(),
379                   LegalityQuery(G_LOAD, {s32, p0},
380                                 LegalityQuery::MemDesc{
381                                   32, 16, AtomicOrdering::NotAtomic }));
382     EXPECT_ACTION(Unsupported, 0, LLT(),
383                   LegalityQuery(G_LOAD, {s32, p0},
384                                 LegalityQuery::MemDesc{
385                                   32, 8, AtomicOrdering::NotAtomic}));
386   }
387 
388   // Test that the maximum supported alignment value isn't truncated
389   {
390     // Maximum IR defined alignment in bytes.
391     const uint64_t MaxAlignment = UINT64_C(1) << 29;
392     const uint64_t MaxAlignInBits = 8 * MaxAlignment;
393     LegalizerInfo LI;
394     LI.getActionDefinitionsBuilder(G_LOAD)
395       .legalForTypesWithMemDesc({{s32, p0, 32, MaxAlignInBits}});
396 
397     LI.computeTables();
398 
399     EXPECT_ACTION(Legal, 0, LLT(),
400                   LegalityQuery(G_LOAD, {s32, p0},
401                                 LegalityQuery::MemDesc{32,
402                                     MaxAlignInBits, AtomicOrdering::NotAtomic}));
403     EXPECT_ACTION(Unsupported, 0, LLT(),
404                   LegalityQuery(G_LOAD, {s32, p0},
405                                 LegalityQuery::MemDesc{
406                                   32, 8, AtomicOrdering::NotAtomic }));
407   }
408 }
409