1 //===- llvm/unittest/CodeGen/GlobalISel/LegalizerInfoTest.cpp -------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
10 #include "llvm/CodeGen/TargetOpcodes.h"
11 #include "GISelMITest.h"
12 #include "gtest/gtest.h"
15 using namespace LegalizeActions
;
17 // Define a couple of pretty printers to help debugging when things go wrong.
20 operator<<(std::ostream
&OS
, const LegalizeAction 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;
37 std::ostream
&operator<<(std::ostream
&OS
, const llvm::LegalizeActionStep Ty
) {
38 OS
<< "LegalizeActionStep(" << Ty
.Action
<< ", " << Ty
.TypeIdx
<< ", "
47 TEST(LegalizerInfoTest
, ScalarRISC
) {
48 using namespace TargetOpcode
;
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
);
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
;
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
);
106 // Check we infer the correct types and actually do what we're told for some
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
;
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
);
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
144 L
.getAction({G_PTRTOINT
, {LLT::scalar(65), s64
}}),
145 LegalizeActionStep(NarrowScalar
, 0, s64
));
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
;
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
);
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
;
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
);
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) \
202 auto A = LI.getAction(Query); \
203 EXPECT_EQ(LegalizeActionStep(Action, Index, Type), A) << A; \
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
);
232 LI
.getActionDefinitionsBuilder(G_IMPLICIT_DEF
)
233 .legalFor({v4s32
, v4p0
})
234 .moreElementsToNextPow2(0);
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
246 LI
.getActionDefinitionsBuilder(G_OR
)
248 .minScalarOrElt(0, s32
);
251 EXPECT_ACTION(WidenScalar
, 0, s32
, LegalityQuery(G_OR
, {s16
}));
252 EXPECT_ACTION(WidenScalar
, 0, v2s32
, LegalityQuery(G_OR
, {v2s16
}));
255 // Test maxScalarOrELt
258 LI
.getActionDefinitionsBuilder(G_AND
)
260 .maxScalarOrElt(0, s16
);
263 EXPECT_ACTION(NarrowScalar
, 0, s16
, LegalityQuery(G_AND
, {s32
}));
264 EXPECT_ACTION(NarrowScalar
, 0, v2s16
, LegalityQuery(G_AND
, {v2s32
}));
267 // Test clampScalarOrElt
270 LI
.getActionDefinitionsBuilder(G_XOR
)
272 .clampScalarOrElt(0, s16
, s32
);
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
}));
286 LI
.getActionDefinitionsBuilder(G_OR
)
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
}));
299 LI
.getActionDefinitionsBuilder(G_AND
)
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
}));
313 LI
.getActionDefinitionsBuilder(G_XOR
)
315 .clampScalar(0, s16
, s32
);
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
330 LI
.getActionDefinitionsBuilder(G_AND
)
332 .widenScalarOrEltToNextPow2(0, 32);
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
346 LI
.getActionDefinitionsBuilder(G_AND
)
348 .widenScalarToNextPow2(0, 32);
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);
368 LI
.getActionDefinitionsBuilder(G_LOAD
)
369 .legalForTypesWithMemDesc({{s32
, p0
, 32, 32}});
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
;
393 LI
.getActionDefinitionsBuilder(G_LOAD
)
394 .legalForTypesWithMemDesc({{s32
, p0
, 32, MaxAlignInBits
}});
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
}));