[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / unittests / CodeGen / GlobalISel / LegalizerInfoTest.cpp
blobb342143e13942f7adc5461ed49bfa59f50eab322
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 //===----------------------------------------------------------------------===//
9 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
10 #include "llvm/CodeGen/TargetOpcodes.h"
11 #include "GISelMITest.h"
12 #include "gtest/gtest.h"
14 using namespace llvm;
15 using namespace LegalizeActions;
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;
34 return OS;
37 std::ostream &operator<<(std::ostream &OS, const llvm::LegalizeActionStep Ty) {
38 OS << "LegalizeActionStep(" << Ty.Action << ", " << Ty.TypeIdx << ", "
39 << Ty.NewType << ')';
40 return OS;
44 namespace {
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);
58 L.computeTables();
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{}));
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)));
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);
99 L.setLegalizeVectorElementToDifferentSizeStrategy(
100 G_ADD, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
102 L.setAction({G_ADD, 0, LLT::scalar(32)}, Legal);
104 L.computeTables();
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)));
123 TEST(LegalizerInfoTest, MultipleTypes) {
124 using namespace TargetOpcode;
125 LegalizerInfo L;
126 LLT p0 = LLT::pointer(0, 64);
127 LLT s64 = LLT::scalar(64);
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);
133 L.setLegalizeScalarToDifferentSizeStrategy(
134 G_PTRTOINT, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest);
136 L.computeTables();
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{}));
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)));
151 TEST(LegalizerInfoTest, MultipleSteps) {
152 using namespace TargetOpcode;
153 LegalizerInfo L;
154 LLT s32 = LLT::scalar(32);
155 LLT s64 = LLT::scalar(64);
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);
162 L.computeTables();
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)));
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);
176 L.setLegalizeScalarToDifferentSizeStrategy(
177 G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
178 L.computeTables();
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{}));
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)));
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)
206 TEST(LegalizerInfoTest, RuleSets) {
207 using namespace TargetOpcode;
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);
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);
225 const LLT p0 = LLT::pointer(0, 32);
226 const LLT v3p0 = LLT::vector(3, p0);
227 const LLT v4p0 = LLT::vector(4, p0);
230 LegalizerInfo LI;
232 LI.getActionDefinitionsBuilder(G_IMPLICIT_DEF)
233 .legalFor({v4s32, v4p0})
234 .moreElementsToNextPow2(0);
235 LI.computeTables();
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}));
243 // Test minScalarOrElt
245 LegalizerInfo LI;
246 LI.getActionDefinitionsBuilder(G_OR)
247 .legalFor({s32})
248 .minScalarOrElt(0, s32);
249 LI.computeTables();
251 EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16}));
252 EXPECT_ACTION(WidenScalar, 0, v2s32, LegalityQuery(G_OR, {v2s16}));
255 // Test maxScalarOrELt
257 LegalizerInfo LI;
258 LI.getActionDefinitionsBuilder(G_AND)
259 .legalFor({s16})
260 .maxScalarOrElt(0, s16);
261 LI.computeTables();
263 EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32}));
264 EXPECT_ACTION(NarrowScalar, 0, v2s16, LegalityQuery(G_AND, {v2s32}));
267 // Test clampScalarOrElt
269 LegalizerInfo LI;
270 LI.getActionDefinitionsBuilder(G_XOR)
271 .legalFor({s16})
272 .clampScalarOrElt(0, s16, s32);
273 LI.computeTables();
275 EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64}));
276 EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8}));
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}));
283 // Test minScalar
285 LegalizerInfo LI;
286 LI.getActionDefinitionsBuilder(G_OR)
287 .legalFor({s32})
288 .minScalar(0, s32);
289 LI.computeTables();
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}));
296 // Test maxScalar
298 LegalizerInfo LI;
299 LI.getActionDefinitionsBuilder(G_AND)
300 .legalFor({s16})
301 .maxScalar(0, s16);
302 LI.computeTables();
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}));
309 // Test clampScalar
311 LegalizerInfo LI;
313 LI.getActionDefinitionsBuilder(G_XOR)
314 .legalFor({s16})
315 .clampScalar(0, s16, s32);
316 LI.computeTables();
318 EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64}));
319 EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8}));
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}));
326 // Test widenScalarOrEltToNextPow2
328 LegalizerInfo LI;
330 LI.getActionDefinitionsBuilder(G_AND)
331 .legalFor({s32})
332 .widenScalarOrEltToNextPow2(0, 32);
333 LI.computeTables();
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}));
342 // Test widenScalarToNextPow2
344 LegalizerInfo LI;
346 LI.getActionDefinitionsBuilder(G_AND)
347 .legalFor({s32})
348 .widenScalarToNextPow2(0, 32);
349 LI.computeTables();
351 EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5}));
352 EXPECT_ACTION(WidenScalar, 0, s64, LegalityQuery(G_AND, {s33}));
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}));
360 TEST(LegalizerInfoTest, MMOAlignment) {
361 using namespace TargetOpcode;
363 const LLT s32 = LLT::scalar(32);
364 const LLT p0 = LLT::pointer(0, 64);
367 LegalizerInfo LI;
368 LI.getActionDefinitionsBuilder(G_LOAD)
369 .legalForTypesWithMemDesc({{s32, p0, 32, 32}});
371 LI.computeTables();
373 EXPECT_ACTION(Legal, 0, LLT(),
374 LegalityQuery(G_LOAD, {s32, p0},
375 LegalityQuery::MemDesc{
376 32, 32, AtomicOrdering::NotAtomic}));
377 EXPECT_ACTION(Unsupported, 0, LLT(),
378 LegalityQuery(G_LOAD, {s32, p0},
379 LegalityQuery::MemDesc{
380 32, 16, AtomicOrdering::NotAtomic }));
381 EXPECT_ACTION(Unsupported, 0, LLT(),
382 LegalityQuery(G_LOAD, {s32, p0},
383 LegalityQuery::MemDesc{
384 32, 8, AtomicOrdering::NotAtomic}));
387 // Test that the maximum supported alignment value isn't truncated
389 // Maximum IR defined alignment in bytes.
390 const uint64_t MaxAlignment = UINT64_C(1) << 29;
391 const uint64_t MaxAlignInBits = 8 * MaxAlignment;
392 LegalizerInfo LI;
393 LI.getActionDefinitionsBuilder(G_LOAD)
394 .legalForTypesWithMemDesc({{s32, p0, 32, MaxAlignInBits}});
396 LI.computeTables();
398 EXPECT_ACTION(Legal, 0, LLT(),
399 LegalityQuery(G_LOAD, {s32, p0},
400 LegalityQuery::MemDesc{32,
401 MaxAlignInBits, AtomicOrdering::NotAtomic}));
402 EXPECT_ACTION(Unsupported, 0, LLT(),
403 LegalityQuery(G_LOAD, {s32, p0},
404 LegalityQuery::MemDesc{
405 32, 8, AtomicOrdering::NotAtomic }));