1 //===- PatternMatchTest.cpp -----------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "LegalizerHelperTest.h"
11 
12 namespace {
13 
14 // Test CTTZ expansion when CTTZ_ZERO_UNDEF is legal or custom,
15 // in which case it becomes CTTZ_ZERO_UNDEF with select.
16 TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ0) {
17   if (!TM)
18     return;
19 
20   // Declare your legalization info
21   DefineLegalizerInfo(
22       A, { getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF).legalFor({s64}); });
23   // Build Instr
24   auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, LLT::scalar(64), Copies[0]);
25   AInfo Info(MF->getSubtarget());
26   LegalizerHelper Helper(*MF, Info);
27   // Perform Legalization
28   ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
29               LegalizerHelper::LegalizeResult::Legalized);
30 
31   auto CheckStr = R"(
32   CHECK: [[CZU:%[0-9]+]]:_(s64) = G_CTTZ_ZERO_UNDEF %0
33   CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
34   CHECK: [[SIXTY4:%[0-9]+]]:_(s64) = G_CONSTANT i64 64
35   CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]]
36   CHECK: [[SEL:%[0-9]+]]:_(s64) = G_SELECT [[CMP]]:_(s1), [[SIXTY4]]:_, [[CZU]]
37   )";
38 
39   // Check
40   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
41 }
42 
43 // CTTZ expansion in terms of CTLZ
44 TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ1) {
45   if (!TM)
46     return;
47 
48   // Declare your legalization info
49   DefineLegalizerInfo(A,
50                       { getActionDefinitionsBuilder(G_CTLZ).legalFor({s64}); });
51   // Build Instr
52   auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, LLT::scalar(64), Copies[0]);
53   AInfo Info(MF->getSubtarget());
54   LegalizerHelper Helper(*MF, Info);
55   // Perform Legalization
56   ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
57               LegalizerHelper::LegalizeResult::Legalized);
58 
59   auto CheckStr = R"(
60   CHECK: [[NEG1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1
61   CHECK: [[NOT:%[0-9]+]]:_(s64) = G_XOR %0:_, [[NEG1]]
62   CHECK: [[SUB1:%[0-9]+]]:_(s64) = G_ADD %0:_, [[NEG1]]
63   CHECK: [[AND1:%[0-9]+]]:_(s64) = G_AND [[NOT]]:_, [[SUB1]]:_
64   CHECK: [[CST64:%[0-9]+]]:_(s64) = G_CONSTANT i64 64
65   CHECK: [[CTLZ:%[0-9]+]]:_(s64) = G_CTLZ [[AND1]]:_
66   CHECK: G_SUB [[CST64]]:_, [[CTLZ]]:_
67   )";
68 
69   // Check
70   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
71 }
72 
73 // CTTZ expansion in terms of CTPOP
74 TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ2) {
75   if (!TM)
76     return;
77 
78   // Declare your legalization info
79   DefineLegalizerInfo(
80       A, { getActionDefinitionsBuilder(G_CTPOP).legalFor({s64}); });
81   // Build
82   auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, LLT::scalar(64), Copies[0]);
83   AInfo Info(MF->getSubtarget());
84   LegalizerHelper Helper(*MF, Info);
85   ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
86               LegalizerHelper::LegalizeResult::Legalized);
87 
88   auto CheckStr = R"(
89   CHECK: [[NEG1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1
90   CHECK: [[NOT:%[0-9]+]]:_(s64) = G_XOR %0:_, [[NEG1]]
91   CHECK: [[SUB1:%[0-9]+]]:_(s64) = G_ADD %0:_, [[NEG1]]
92   CHECK: [[AND1:%[0-9]+]]:_(s64) = G_AND [[NOT]]:_, [[SUB1]]:_
93   CHECK: [[POP:%[0-9]+]]:_(s64) = G_CTPOP [[AND1]]
94   )";
95 
96   // Check
97   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
98 }
99 
100 // CTTZ_ZERO_UNDEF expansion in terms of CTTZ
101 TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ3) {
102   if (!TM)
103     return;
104 
105   // Declare your legalization info
106   DefineLegalizerInfo(A,
107                       { getActionDefinitionsBuilder(G_CTTZ).legalFor({s64}); });
108   // Build
109   auto MIBCTTZ =
110       B.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF, LLT::scalar(64), Copies[0]);
111   AInfo Info(MF->getSubtarget());
112   LegalizerHelper Helper(*MF, Info);
113   ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
114               LegalizerHelper::LegalizeResult::Legalized);
115 
116   auto CheckStr = R"(
117   CHECK: CTTZ
118   )";
119 
120   // Check
121   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
122 }
123 
124 // CTLZ expansion in terms of CTLZ_ZERO_UNDEF
125 TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ0) {
126   if (!TM)
127     return;
128 
129   // Declare your legalization info
130   DefineLegalizerInfo(
131       A, { getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF).legalFor({s64}); });
132   // Build
133   auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, LLT::scalar(64), Copies[0]);
134   AInfo Info(MF->getSubtarget());
135   LegalizerHelper Helper(*MF, Info);
136   ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, LLT::scalar(64)) ==
137               LegalizerHelper::LegalizeResult::Legalized);
138 
139   auto CheckStr = R"(
140   CHECK: [[CZU:%[0-9]+]]:_(s64) = G_CTLZ_ZERO_UNDEF %0
141   CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
142   CHECK: [[SIXTY4:%[0-9]+]]:_(s64) = G_CONSTANT i64 64
143   CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]]
144   CHECK: [[SEL:%[0-9]+]]:_(s64) = G_SELECT [[CMP]]:_(s1), [[SIXTY4]]:_, [[CZU]]
145   )";
146 
147   // Check
148   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
149 }
150 
151 // CTLZ expansion
152 TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ1) {
153   if (!TM)
154     return;
155 
156   // Declare your legalization info
157   DefineLegalizerInfo(A,
158                       { getActionDefinitionsBuilder(G_CTPOP).legalFor({s8}); });
159   // Build
160   // Trunc it to s8.
161   LLT s8{LLT::scalar(8)};
162   auto MIBTrunc = B.buildTrunc(s8, Copies[0]);
163   auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, s8, MIBTrunc);
164   AInfo Info(MF->getSubtarget());
165   LegalizerHelper Helper(*MF, Info);
166   ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, s8) ==
167               LegalizerHelper::LegalizeResult::Legalized);
168 
169   auto CheckStr = R"(
170   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC
171   CHECK: [[Cst1:%[0-9]+]]:_(s8) = G_CONSTANT i8 1
172   CHECK: [[Sh1:%[0-9]+]]:_(s8) = G_LSHR [[Trunc]]:_, [[Cst1]]:_
173   CHECK: [[Or1:%[0-9]+]]:_(s8) = G_OR [[Trunc]]:_, [[Sh1]]:_
174   CHECK: [[Cst2:%[0-9]+]]:_(s8) = G_CONSTANT i8 2
175   CHECK: [[Sh2:%[0-9]+]]:_(s8) = G_LSHR [[Or1]]:_, [[Cst2]]:_
176   CHECK: [[Or2:%[0-9]+]]:_(s8) = G_OR [[Or1]]:_, [[Sh2]]:_
177   CHECK: [[Cst4:%[0-9]+]]:_(s8) = G_CONSTANT i8 4
178   CHECK: [[Sh4:%[0-9]+]]:_(s8) = G_LSHR [[Or2]]:_, [[Cst4]]:_
179   CHECK: [[Or4:%[0-9]+]]:_(s8) = G_OR [[Or2]]:_, [[Sh4]]:_
180   CHECK: [[CTPOP:%[0-9]+]]:_(s8) = G_CTPOP [[Or4]]:_
181   CHECK: [[Len:%[0-9]+]]:_(s8) = G_CONSTANT i8 8
182   CHECK: [[Sub:%[0-9]+]]:_(s8) = G_SUB [[Len]]:_, [[CTPOP]]:_
183   )";
184 
185   // Check
186   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
187 }
188 
189 // CTLZ widening.
190 TEST_F(LegalizerHelperTest, WidenBitCountingCTLZ) {
191   if (!TM)
192     return;
193 
194   // Declare your legalization info
195   DefineLegalizerInfo(A,
196                       { getActionDefinitionsBuilder(G_CTLZ).legalFor({s16}); });
197   // Build
198   // Trunc it to s8.
199   LLT s8{LLT::scalar(8)};
200   LLT s16{LLT::scalar(16)};
201   auto MIBTrunc = B.buildTrunc(s8, Copies[0]);
202   auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, s8, MIBTrunc);
203   AInfo Info(MF->getSubtarget());
204   LegalizerHelper Helper(*MF, Info);
205   ASSERT_TRUE(Helper.widenScalar(*MIBCTLZ, 0, s16) ==
206               LegalizerHelper::LegalizeResult::Legalized);
207 
208   auto CheckStr = R"(
209   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC
210   CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
211   CHECK: [[Ctlz:%[0-9]+]]:_(s16) = G_CTLZ [[Zext]]
212   CHECK: [[Cst8:%[0-9]+]]:_(s16) = G_CONSTANT i16 8
213   CHECK: [[Sub:%[0-9]+]]:_(s16) = G_SUB [[Ctlz]]:_, [[Cst8]]:_
214   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[Sub]]
215   )";
216 
217   // Check
218   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
219 }
220 
221 // CTLZ_ZERO_UNDEF widening.
222 TEST_F(LegalizerHelperTest, WidenBitCountingCTLZZeroUndef) {
223   if (!TM)
224     return;
225 
226   // Declare your legalization info
227   DefineLegalizerInfo(
228       A, { getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF).legalFor({s16}); });
229   // Build
230   // Trunc it to s8.
231   LLT s8{LLT::scalar(8)};
232   LLT s16{LLT::scalar(16)};
233   auto MIBTrunc = B.buildTrunc(s8, Copies[0]);
234   auto MIBCTLZ_ZU = B.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, s8, MIBTrunc);
235   AInfo Info(MF->getSubtarget());
236   LegalizerHelper Helper(*MF, Info);
237   ASSERT_TRUE(Helper.widenScalar(*MIBCTLZ_ZU, 0, s16) ==
238               LegalizerHelper::LegalizeResult::Legalized);
239 
240   auto CheckStr = R"(
241   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC
242   CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
243   CHECK: [[CtlzZu:%[0-9]+]]:_(s16) = G_CTLZ_ZERO_UNDEF [[Zext]]
244   CHECK: [[Cst8:%[0-9]+]]:_(s16) = G_CONSTANT i16 8
245   CHECK: [[Sub:%[0-9]+]]:_(s16) = G_SUB [[CtlzZu]]:_, [[Cst8]]:_
246   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[Sub]]
247   )";
248 
249   // Check
250   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
251 }
252 
253 // CTPOP widening.
254 TEST_F(LegalizerHelperTest, WidenBitCountingCTPOP) {
255   if (!TM)
256     return;
257 
258   // Declare your legalization info
259   DefineLegalizerInfo(
260       A, { getActionDefinitionsBuilder(G_CTPOP).legalFor({s16}); });
261   // Build
262   // Trunc it to s8.
263   LLT s8{LLT::scalar(8)};
264   LLT s16{LLT::scalar(16)};
265   auto MIBTrunc = B.buildTrunc(s8, Copies[0]);
266   auto MIBCTPOP = B.buildInstr(TargetOpcode::G_CTPOP, s8, MIBTrunc);
267   AInfo Info(MF->getSubtarget());
268   LegalizerHelper Helper(*MF, Info);
269   ASSERT_TRUE(Helper.widenScalar(*MIBCTPOP, 0, s16) ==
270               LegalizerHelper::LegalizeResult::Legalized);
271 
272   auto CheckStr = R"(
273   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC
274   CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
275   CHECK: [[Ctpop:%[0-9]+]]:_(s16) = G_CTPOP [[Zext]]
276   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[Ctpop]]
277   )";
278 
279   // Check
280   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
281 }
282 
283 // CTTZ_ZERO_UNDEF widening.
284 TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ_ZERO_UNDEF) {
285   if (!TM)
286     return;
287 
288   // Declare your legalization info
289   DefineLegalizerInfo(
290       A, { getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF).legalFor({s16}); });
291   // Build
292   // Trunc it to s8.
293   LLT s8{LLT::scalar(8)};
294   LLT s16{LLT::scalar(16)};
295   auto MIBTrunc = B.buildTrunc(s8, Copies[0]);
296   auto MIBCTTZ_ZERO_UNDEF =
297       B.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF, s8, MIBTrunc);
298   AInfo Info(MF->getSubtarget());
299   LegalizerHelper Helper(*MF, Info);
300   ASSERT_TRUE(Helper.widenScalar(*MIBCTTZ_ZERO_UNDEF, 0, s16) ==
301               LegalizerHelper::LegalizeResult::Legalized);
302 
303   auto CheckStr = R"(
304   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC
305   CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
306   CHECK: [[CttzZu:%[0-9]+]]:_(s16) = G_CTTZ_ZERO_UNDEF [[Zext]]
307   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[CttzZu]]
308   )";
309 
310   // Check
311   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
312 }
313 
314 // CTTZ widening.
315 TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ) {
316   if (!TM)
317     return;
318 
319   // Declare your legalization info
320   DefineLegalizerInfo(A,
321                       { getActionDefinitionsBuilder(G_CTTZ).legalFor({s16}); });
322   // Build
323   // Trunc it to s8.
324   LLT s8{LLT::scalar(8)};
325   LLT s16{LLT::scalar(16)};
326   auto MIBTrunc = B.buildTrunc(s8, Copies[0]);
327   auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, s8, MIBTrunc);
328   AInfo Info(MF->getSubtarget());
329   LegalizerHelper Helper(*MF, Info);
330   ASSERT_TRUE(Helper.widenScalar(*MIBCTTZ, 0, s16) ==
331               LegalizerHelper::LegalizeResult::Legalized);
332 
333   auto CheckStr = R"(
334   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC
335   CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
336   CHECK: [[Cst:%[0-9]+]]:_(s16) = G_CONSTANT i16 256
337   CHECK: [[Or:%[0-9]+]]:_(s16) = G_OR [[Zext]]:_, [[Cst]]
338   CHECK: [[Cttz:%[0-9]+]]:_(s16) = G_CTTZ [[Or]]
339   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[Cttz]]
340   )";
341 
342   // Check
343   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
344 }
345 // UADDO widening.
346 TEST_F(LegalizerHelperTest, WidenUADDO) {
347   if (!TM)
348     return;
349 
350   // Declare your legalization info
351   DefineLegalizerInfo(A,
352                       { getActionDefinitionsBuilder(G_ADD).legalFor({s16}); });
353   // Build
354   // Trunc it to s8.
355   LLT s8{LLT::scalar(8)};
356   LLT s16{LLT::scalar(16)};
357   auto MIBTrunc = B.buildTrunc(s8, Copies[0]);
358   unsigned CarryReg = MRI->createGenericVirtualRegister(LLT::scalar(1));
359   auto MIBUAddO = B.buildInstr(TargetOpcode::G_UADDO, s8)
360                       .addDef(CarryReg)
361                       .addUse(MIBTrunc->getOperand(0).getReg())
362                       .addUse(MIBTrunc->getOperand(0).getReg());
363   AInfo Info(MF->getSubtarget());
364   LegalizerHelper Helper(*MF, Info);
365   ASSERT_TRUE(Helper.widenScalar(*MIBUAddO, 0, s16) ==
366               LegalizerHelper::LegalizeResult::Legalized);
367 
368   auto CheckStr = R"(
369   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC
370   CHECK: [[LHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
371   CHECK: [[RHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
372   CHECK: [[ADD:%[0-9]+]]:_(s16) = G_ADD [[LHS]]:_, [[RHS]]:_
373   CHECK: [[CST:%[0-9]+]]:_(s16) = G_CONSTANT i16 255
374   CHECK: [[AND:%[0-9]+]]:_(s16) = G_AND [[ADD]]:_, [[CST]]:_
375   CHECK: G_ICMP intpred(ne), [[ADD]]:_(s16), [[AND]]:_
376   CHECK: G_TRUNC [[ADD]]
377   )";
378 
379   // Check
380   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
381 }
382 
383 // USUBO widening.
384 TEST_F(LegalizerHelperTest, WidenUSUBO) {
385   if (!TM)
386     return;
387 
388   // Declare your legalization info
389   DefineLegalizerInfo(A,
390                       { getActionDefinitionsBuilder(G_SUB).legalFor({s16}); });
391   // Build
392   // Trunc it to s8.
393   LLT s8{LLT::scalar(8)};
394   LLT s16{LLT::scalar(16)};
395   auto MIBTrunc = B.buildTrunc(s8, Copies[0]);
396   unsigned CarryReg = MRI->createGenericVirtualRegister(LLT::scalar(1));
397   auto MIBUSUBO = B.buildInstr(TargetOpcode::G_USUBO, s8)
398                       .addDef(CarryReg)
399                       .addUse(MIBTrunc->getOperand(0).getReg())
400                       .addUse(MIBTrunc->getOperand(0).getReg());
401   AInfo Info(MF->getSubtarget());
402   LegalizerHelper Helper(*MF, Info);
403   ASSERT_TRUE(Helper.widenScalar(*MIBUSUBO, 0, s16) ==
404               LegalizerHelper::LegalizeResult::Legalized);
405 
406   auto CheckStr = R"(
407   CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC
408   CHECK: [[LHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
409   CHECK: [[RHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]]
410   CHECK: [[SUB:%[0-9]+]]:_(s16) = G_SUB [[LHS]]:_, [[RHS]]:_
411   CHECK: [[CST:%[0-9]+]]:_(s16) = G_CONSTANT i16 255
412   CHECK: [[AND:%[0-9]+]]:_(s16) = G_AND [[SUB]]:_, [[CST]]:_
413   CHECK: G_ICMP intpred(ne), [[SUB]]:_(s16), [[AND]]:_
414   CHECK: G_TRUNC [[SUB]]
415   )";
416 
417   // Check
418   ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
419 }
420 } // namespace
421