xref: /llvm-project/llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp (revision 91be65be656072a68b51a8c4e7bb751ea475d896)
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 &
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 Unsupported: OS << "Unsupported"; break;
31   case NotFound: OS << "NotFound"; break;
32   case UseLegacyRules: OS << "UseLegacyRules"; break;
33   }
34   return OS;
35 }
36 
37 std::ostream &operator<<(std::ostream &OS, const llvm::LegalizeActionStep Ty) {
38   OS << "LegalizeActionStep(" << Ty.Action << ", " << Ty.TypeIdx << ", "
39      << Ty.NewType << ')';
40   return OS;
41 }
42 }
43 
44 namespace {
45 
46 
47 TEST(LegalizerInfoTest, ScalarRISC) {
48   using namespace TargetOpcode;
49   LegalizerInfo L;
50   // Typical RISCy set of operations based on AArch64.
51   for (unsigned Op : {G_ADD, G_SUB}) {
52     for (unsigned Size : {32, 64})
53       L.setAction({Op, 0, LLT::scalar(Size)}, Legal);
54     L.setLegalizeScalarToDifferentSizeStrategy(
55         Op, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest);
56   }
57 
58   L.computeTables();
59 
60   for (unsigned opcode : {G_ADD, G_SUB}) {
61     // Check we infer the correct types and actually do what we're told.
62     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(8)}}),
63               LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
64     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(16)}}),
65               LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
66     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(32)}}),
67               LegalizeActionStep(Legal, 0, LLT{}));
68     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(64)}}),
69               LegalizeActionStep(Legal, 0, LLT{}));
70 
71     // Make sure the default for over-sized types applies.
72     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(128)}}),
73               LegalizeActionStep(NarrowScalar, 0, LLT::scalar(64)));
74     // Make sure we also handle unusual sizes
75     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(1)}}),
76               LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
77     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(31)}}),
78               LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
79     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(33)}}),
80               LegalizeActionStep(WidenScalar, 0, LLT::scalar(64)));
81     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(63)}}),
82               LegalizeActionStep(WidenScalar, 0, LLT::scalar(64)));
83     EXPECT_EQ(L.getAction({opcode, {LLT::scalar(65)}}),
84               LegalizeActionStep(NarrowScalar, 0, LLT::scalar(64)));
85   }
86 }
87 
88 TEST(LegalizerInfoTest, VectorRISC) {
89   using namespace TargetOpcode;
90   LegalizerInfo L;
91   // Typical RISCy set of operations based on ARM.
92   L.setAction({G_ADD, LLT::vector(8, 8)}, Legal);
93   L.setAction({G_ADD, LLT::vector(16, 8)}, Legal);
94   L.setAction({G_ADD, LLT::vector(4, 16)}, Legal);
95   L.setAction({G_ADD, LLT::vector(8, 16)}, Legal);
96   L.setAction({G_ADD, LLT::vector(2, 32)}, Legal);
97   L.setAction({G_ADD, LLT::vector(4, 32)}, Legal);
98 
99   L.setLegalizeVectorElementToDifferentSizeStrategy(
100       G_ADD, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
101 
102   L.setAction({G_ADD, 0, LLT::scalar(32)}, Legal);
103 
104   L.computeTables();
105 
106   // Check we infer the correct types and actually do what we're told for some
107   // simple cases.
108   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 8)}}),
109             LegalizeActionStep(Legal, 0, LLT{}));
110   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 7)}}),
111             LegalizeActionStep(WidenScalar, 0, LLT::vector(8, 8)));
112   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(2, 8)}}),
113             LegalizeActionStep(MoreElements, 0, LLT::vector(8, 8)));
114   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 32)}}),
115             LegalizeActionStep(FewerElements, 0, LLT::vector(4, 32)));
116   // Check a few non-power-of-2 sizes:
117   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(3, 3)}}),
118             LegalizeActionStep(WidenScalar, 0, LLT::vector(3, 8)));
119   EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(3, 8)}}),
120             LegalizeActionStep(MoreElements, 0, LLT::vector(8, 8)));
121 }
122 
123 TEST(LegalizerInfoTest, MultipleTypes) {
124   using namespace TargetOpcode;
125   LegalizerInfo L;
126   LLT p0 = LLT::pointer(0, 64);
127   LLT s64 = LLT::scalar(64);
128 
129   // Typical RISCy set of operations based on AArch64.
130   L.setAction({G_PTRTOINT, 0, s64}, Legal);
131   L.setAction({G_PTRTOINT, 1, p0}, Legal);
132 
133   L.setLegalizeScalarToDifferentSizeStrategy(
134       G_PTRTOINT, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest);
135 
136   L.computeTables();
137 
138   // Check we infer the correct types and actually do what we're told.
139   EXPECT_EQ(L.getAction({G_PTRTOINT, {s64, p0}}),
140             LegalizeActionStep(Legal, 0, LLT{}));
141 
142   // Make sure we also handle unusual sizes
143   EXPECT_EQ(
144       L.getAction({G_PTRTOINT, {LLT::scalar(65), s64}}),
145       LegalizeActionStep(NarrowScalar, 0, s64));
146   EXPECT_EQ(
147       L.getAction({G_PTRTOINT, {s64, LLT::pointer(0, 32)}}),
148       LegalizeActionStep(Unsupported, 1, LLT::pointer(0, 32)));
149 }
150 
151 TEST(LegalizerInfoTest, MultipleSteps) {
152   using namespace TargetOpcode;
153   LegalizerInfo L;
154   LLT s32 = LLT::scalar(32);
155   LLT s64 = LLT::scalar(64);
156 
157   L.setLegalizeScalarToDifferentSizeStrategy(
158       G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
159   L.setAction({G_UREM, 0, s32}, Lower);
160   L.setAction({G_UREM, 0, s64}, Lower);
161 
162   L.computeTables();
163 
164   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(16)}}),
165             LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
166   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(32)}}),
167             LegalizeActionStep(Lower, 0, LLT::scalar(32)));
168 }
169 
170 TEST(LegalizerInfoTest, SizeChangeStrategy) {
171   using namespace TargetOpcode;
172   LegalizerInfo L;
173   for (unsigned Size : {1, 8, 16, 32})
174     L.setAction({G_UREM, 0, LLT::scalar(Size)}, Legal);
175 
176   L.setLegalizeScalarToDifferentSizeStrategy(
177       G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
178   L.computeTables();
179 
180   // Check we infer the correct types and actually do what we're told.
181   for (unsigned Size : {1, 8, 16, 32}) {
182     EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(Size)}}),
183               LegalizeActionStep(Legal, 0, LLT{}));
184   }
185   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(2)}}),
186             LegalizeActionStep(WidenScalar, 0, LLT::scalar(8)));
187   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(7)}}),
188             LegalizeActionStep(WidenScalar, 0, LLT::scalar(8)));
189   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(9)}}),
190             LegalizeActionStep(WidenScalar, 0, LLT::scalar(16)));
191   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(17)}}),
192             LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
193   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(31)}}),
194             LegalizeActionStep(WidenScalar, 0, LLT::scalar(32)));
195   EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(33)}}),
196             LegalizeActionStep(Unsupported, 0, LLT::scalar(33)));
197 }
198 }
199 
200 #define EXPECT_ACTION(Action, Index, Type, Query)                              \
201   do {                                                                         \
202     auto A = LI.getAction(Query);                                              \
203     EXPECT_EQ(LegalizeActionStep(Action, Index, Type), A) << A;                \
204   } while (0)
205 
206 TEST(LegalizerInfoTest, RuleSets) {
207   using namespace TargetOpcode;
208 
209   const LLT s5 = LLT::scalar(5);
210   const LLT s8 = LLT::scalar(8);
211   const LLT s16 = LLT::scalar(16);
212   const LLT s32 = LLT::scalar(32);
213   const LLT s33 = LLT::scalar(33);
214   const LLT s64 = LLT::scalar(64);
215 
216   const LLT v2s5 = LLT::vector(2, 5);
217   const LLT v2s8 = LLT::vector(2, 8);
218   const LLT v2s16 = LLT::vector(2, 16);
219   const LLT v2s32 = LLT::vector(2, 32);
220   const LLT v3s32 = LLT::vector(3, 32);
221   const LLT v4s32 = LLT::vector(4, 32);
222   const LLT v2s33 = LLT::vector(2, 33);
223   const LLT v2s64 = LLT::vector(2, 64);
224 
225   const LLT p0 = LLT::pointer(0, 32);
226   const LLT v3p0 = LLT::vector(3, p0);
227   const LLT v4p0 = LLT::vector(4, p0);
228 
229   {
230     LegalizerInfo LI;
231 
232     LI.getActionDefinitionsBuilder(G_IMPLICIT_DEF)
233       .legalFor({v4s32, v4p0})
234       .moreElementsToNextPow2(0);
235     LI.computeTables();
236 
237     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_IMPLICIT_DEF, {s32}));
238     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_IMPLICIT_DEF, {v2s32}));
239     EXPECT_ACTION(MoreElements, 0, v4p0, LegalityQuery(G_IMPLICIT_DEF, {v3p0}));
240     EXPECT_ACTION(MoreElements, 0, v4s32, LegalityQuery(G_IMPLICIT_DEF, {v3s32}));
241   }
242 
243   // Test minScalarOrElt
244   {
245     LegalizerInfo LI;
246     LI.getActionDefinitionsBuilder(G_OR)
247       .legalFor({s32})
248       .minScalarOrElt(0, s32);
249     LI.computeTables();
250 
251     EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16}));
252     EXPECT_ACTION(WidenScalar, 0, v2s32, LegalityQuery(G_OR, {v2s16}));
253   }
254 
255   // Test maxScalarOrELt
256   {
257     LegalizerInfo LI;
258     LI.getActionDefinitionsBuilder(G_AND)
259       .legalFor({s16})
260       .maxScalarOrElt(0, s16);
261     LI.computeTables();
262 
263     EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32}));
264     EXPECT_ACTION(NarrowScalar, 0, v2s16, LegalityQuery(G_AND, {v2s32}));
265   }
266 
267   // Test clampScalarOrElt
268   {
269     LegalizerInfo LI;
270     LI.getActionDefinitionsBuilder(G_XOR)
271       .legalFor({s16})
272       .clampScalarOrElt(0, s16, s32);
273     LI.computeTables();
274 
275     EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64}));
276     EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8}));
277 
278     // Make sure the number of elements is preserved.
279     EXPECT_ACTION(NarrowScalar, 0, v2s32, LegalityQuery(G_XOR, {v2s64}));
280     EXPECT_ACTION(WidenScalar, 0, v2s16, LegalityQuery(G_XOR, {v2s8}));
281   }
282 
283   // Test minScalar
284   {
285     LegalizerInfo LI;
286     LI.getActionDefinitionsBuilder(G_OR)
287       .legalFor({s32})
288       .minScalar(0, s32);
289     LI.computeTables();
290 
291     // Only handle scalars, ignore vectors.
292     EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16}));
293     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_OR, {v2s16}));
294   }
295 
296   // Test maxScalar
297   {
298     LegalizerInfo LI;
299     LI.getActionDefinitionsBuilder(G_AND)
300       .legalFor({s16})
301       .maxScalar(0, s16);
302     LI.computeTables();
303 
304     // Only handle scalars, ignore vectors.
305     EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32}));
306     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s32}));
307   }
308 
309   // Test clampScalar
310   {
311     LegalizerInfo LI;
312 
313     LI.getActionDefinitionsBuilder(G_XOR)
314       .legalFor({s16})
315       .clampScalar(0, s16, s32);
316     LI.computeTables();
317 
318     EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64}));
319     EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8}));
320 
321     // Only handle scalars, ignore vectors.
322     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_XOR, {v2s64}));
323     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_XOR, {v2s8}));
324   }
325 
326   // Test widenScalarOrEltToNextPow2
327   {
328     LegalizerInfo LI;
329 
330     LI.getActionDefinitionsBuilder(G_AND)
331       .legalFor({s32})
332       .widenScalarOrEltToNextPow2(0, 32);
333     LI.computeTables();
334 
335     // Handle scalars and vectors
336     EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5}));
337     EXPECT_ACTION(WidenScalar, 0, v2s32, LegalityQuery(G_AND, {v2s5}));
338     EXPECT_ACTION(WidenScalar, 0, s64, LegalityQuery(G_AND, {s33}));
339     EXPECT_ACTION(WidenScalar, 0, v2s64, LegalityQuery(G_AND, {v2s33}));
340   }
341 
342   // Test widenScalarToNextPow2
343   {
344     LegalizerInfo LI;
345 
346     LI.getActionDefinitionsBuilder(G_AND)
347       .legalFor({s32})
348       .widenScalarToNextPow2(0, 32);
349     LI.computeTables();
350 
351     EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5}));
352     EXPECT_ACTION(WidenScalar, 0, s64, LegalityQuery(G_AND, {s33}));
353 
354     // Do nothing for vectors.
355     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s5}));
356     EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s33}));
357   }
358 }
359