1 //===- llvm/unittests/Transforms/Vectorize/VPlanTest.cpp - VPlan tests ----===//
2 //
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "../lib/Transforms/Vectorize/VPlan.h"
11 #include "llvm/ADT/DepthFirstIterator.h"
12 #include "llvm/ADT/PostOrderIterator.h"
13 #include "llvm/Analysis/VectorUtils.h"
14 #include "llvm/IR/Instruction.h"
15 #include "llvm/IR/Instructions.h"
16 #include "gtest/gtest.h"
17 #include <string>
18
19 namespace llvm {
20 namespace {
21
22 #define CHECK_ITERATOR(Range1, ...) \
23 do { \
24 std::vector<VPInstruction *> Tmp = {__VA_ARGS__}; \
25 EXPECT_EQ((size_t)std::distance(Range1.begin(), Range1.end()), \
26 Tmp.size()); \
27 for (auto Pair : zip(Range1, make_range(Tmp.begin(), Tmp.end()))) \
28 EXPECT_EQ(&std::get<0>(Pair), std::get<1>(Pair)); \
29 } while (0)
30
TEST(VPInstructionTest,insertBefore)31 TEST(VPInstructionTest, insertBefore) {
32 VPInstruction *I1 = new VPInstruction(0, {});
33 VPInstruction *I2 = new VPInstruction(1, {});
34 VPInstruction *I3 = new VPInstruction(2, {});
35
36 VPBasicBlock VPBB1;
37 VPBB1.appendRecipe(I1);
38
39 I2->insertBefore(I1);
40 CHECK_ITERATOR(VPBB1, I2, I1);
41
42 I3->insertBefore(I2);
43 CHECK_ITERATOR(VPBB1, I3, I2, I1);
44 }
45
TEST(VPInstructionTest,eraseFromParent)46 TEST(VPInstructionTest, eraseFromParent) {
47 VPInstruction *I1 = new VPInstruction(0, {});
48 VPInstruction *I2 = new VPInstruction(1, {});
49 VPInstruction *I3 = new VPInstruction(2, {});
50
51 VPBasicBlock VPBB1;
52 VPBB1.appendRecipe(I1);
53 VPBB1.appendRecipe(I2);
54 VPBB1.appendRecipe(I3);
55
56 I2->eraseFromParent();
57 CHECK_ITERATOR(VPBB1, I1, I3);
58
59 I1->eraseFromParent();
60 CHECK_ITERATOR(VPBB1, I3);
61
62 I3->eraseFromParent();
63 EXPECT_TRUE(VPBB1.empty());
64 }
65
TEST(VPInstructionTest,moveAfter)66 TEST(VPInstructionTest, moveAfter) {
67 VPInstruction *I1 = new VPInstruction(0, {});
68 VPInstruction *I2 = new VPInstruction(1, {});
69 VPInstruction *I3 = new VPInstruction(2, {});
70
71 VPBasicBlock VPBB1;
72 VPBB1.appendRecipe(I1);
73 VPBB1.appendRecipe(I2);
74 VPBB1.appendRecipe(I3);
75
76 I1->moveAfter(I2);
77
78 CHECK_ITERATOR(VPBB1, I2, I1, I3);
79
80 VPInstruction *I4 = new VPInstruction(4, {});
81 VPInstruction *I5 = new VPInstruction(5, {});
82 VPBasicBlock VPBB2;
83 VPBB2.appendRecipe(I4);
84 VPBB2.appendRecipe(I5);
85
86 I3->moveAfter(I4);
87
88 CHECK_ITERATOR(VPBB1, I2, I1);
89 CHECK_ITERATOR(VPBB2, I4, I3, I5);
90 EXPECT_EQ(I3->getParent(), I4->getParent());
91 }
92
TEST(VPInstructionTest,moveBefore)93 TEST(VPInstructionTest, moveBefore) {
94 VPInstruction *I1 = new VPInstruction(0, {});
95 VPInstruction *I2 = new VPInstruction(1, {});
96 VPInstruction *I3 = new VPInstruction(2, {});
97
98 VPBasicBlock VPBB1;
99 VPBB1.appendRecipe(I1);
100 VPBB1.appendRecipe(I2);
101 VPBB1.appendRecipe(I3);
102
103 I1->moveBefore(VPBB1, I3->getIterator());
104
105 CHECK_ITERATOR(VPBB1, I2, I1, I3);
106
107 VPInstruction *I4 = new VPInstruction(4, {});
108 VPInstruction *I5 = new VPInstruction(5, {});
109 VPBasicBlock VPBB2;
110 VPBB2.appendRecipe(I4);
111 VPBB2.appendRecipe(I5);
112
113 I3->moveBefore(VPBB2, I4->getIterator());
114
115 CHECK_ITERATOR(VPBB1, I2, I1);
116 CHECK_ITERATOR(VPBB2, I3, I4, I5);
117 EXPECT_EQ(I3->getParent(), I4->getParent());
118
119 VPBasicBlock VPBB3;
120
121 I4->moveBefore(VPBB3, VPBB3.end());
122
123 CHECK_ITERATOR(VPBB1, I2, I1);
124 CHECK_ITERATOR(VPBB2, I3, I5);
125 CHECK_ITERATOR(VPBB3, I4);
126 EXPECT_EQ(&VPBB3, I4->getParent());
127 }
128
TEST(VPInstructionTest,setOperand)129 TEST(VPInstructionTest, setOperand) {
130 VPValue *VPV1 = new VPValue();
131 VPValue *VPV2 = new VPValue();
132 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
133 EXPECT_EQ(1u, VPV1->getNumUsers());
134 EXPECT_EQ(I1, *VPV1->user_begin());
135 EXPECT_EQ(1u, VPV2->getNumUsers());
136 EXPECT_EQ(I1, *VPV2->user_begin());
137
138 // Replace operand 0 (VPV1) with VPV3.
139 VPValue *VPV3 = new VPValue();
140 I1->setOperand(0, VPV3);
141 EXPECT_EQ(0u, VPV1->getNumUsers());
142 EXPECT_EQ(1u, VPV2->getNumUsers());
143 EXPECT_EQ(I1, *VPV2->user_begin());
144 EXPECT_EQ(1u, VPV3->getNumUsers());
145 EXPECT_EQ(I1, *VPV3->user_begin());
146
147 // Replace operand 1 (VPV2) with VPV3.
148 I1->setOperand(1, VPV3);
149 EXPECT_EQ(0u, VPV1->getNumUsers());
150 EXPECT_EQ(0u, VPV2->getNumUsers());
151 EXPECT_EQ(2u, VPV3->getNumUsers());
152 EXPECT_EQ(I1, *VPV3->user_begin());
153 EXPECT_EQ(I1, *std::next(VPV3->user_begin()));
154
155 // Replace operand 0 (VPV3) with VPV4.
156 VPValue *VPV4 = new VPValue();
157 I1->setOperand(0, VPV4);
158 EXPECT_EQ(1u, VPV3->getNumUsers());
159 EXPECT_EQ(I1, *VPV3->user_begin());
160 EXPECT_EQ(I1, *VPV4->user_begin());
161
162 // Replace operand 1 (VPV3) with VPV4.
163 I1->setOperand(1, VPV4);
164 EXPECT_EQ(0u, VPV3->getNumUsers());
165 EXPECT_EQ(I1, *VPV4->user_begin());
166 EXPECT_EQ(I1, *std::next(VPV4->user_begin()));
167
168 delete I1;
169 delete VPV1;
170 delete VPV2;
171 delete VPV3;
172 delete VPV4;
173 }
174
TEST(VPInstructionTest,replaceAllUsesWith)175 TEST(VPInstructionTest, replaceAllUsesWith) {
176 VPValue *VPV1 = new VPValue();
177 VPValue *VPV2 = new VPValue();
178 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
179
180 // Replace all uses of VPV1 with VPV3.
181 VPValue *VPV3 = new VPValue();
182 VPV1->replaceAllUsesWith(VPV3);
183 EXPECT_EQ(VPV3, I1->getOperand(0));
184 EXPECT_EQ(VPV2, I1->getOperand(1));
185 EXPECT_EQ(0u, VPV1->getNumUsers());
186 EXPECT_EQ(1u, VPV2->getNumUsers());
187 EXPECT_EQ(I1, *VPV2->user_begin());
188 EXPECT_EQ(1u, VPV3->getNumUsers());
189 EXPECT_EQ(I1, *VPV3->user_begin());
190
191 // Replace all uses of VPV2 with VPV3.
192 VPV2->replaceAllUsesWith(VPV3);
193 EXPECT_EQ(VPV3, I1->getOperand(0));
194 EXPECT_EQ(VPV3, I1->getOperand(1));
195 EXPECT_EQ(0u, VPV1->getNumUsers());
196 EXPECT_EQ(0u, VPV2->getNumUsers());
197 EXPECT_EQ(2u, VPV3->getNumUsers());
198 EXPECT_EQ(I1, *VPV3->user_begin());
199
200 // Replace all uses of VPV3 with VPV1.
201 VPV3->replaceAllUsesWith(VPV1);
202 EXPECT_EQ(VPV1, I1->getOperand(0));
203 EXPECT_EQ(VPV1, I1->getOperand(1));
204 EXPECT_EQ(2u, VPV1->getNumUsers());
205 EXPECT_EQ(I1, *VPV1->user_begin());
206 EXPECT_EQ(0u, VPV2->getNumUsers());
207 EXPECT_EQ(0u, VPV3->getNumUsers());
208
209 VPInstruction *I2 = new VPInstruction(0, {VPV1, VPV2});
210 EXPECT_EQ(3u, VPV1->getNumUsers());
211 VPV1->replaceAllUsesWith(VPV3);
212 EXPECT_EQ(3u, VPV3->getNumUsers());
213
214 delete I1;
215 delete I2;
216 delete VPV1;
217 delete VPV2;
218 delete VPV3;
219 }
220
TEST(VPInstructionTest,releaseOperandsAtDeletion)221 TEST(VPInstructionTest, releaseOperandsAtDeletion) {
222 VPValue *VPV1 = new VPValue();
223 VPValue *VPV2 = new VPValue();
224 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
225
226 EXPECT_EQ(1u, VPV1->getNumUsers());
227 EXPECT_EQ(I1, *VPV1->user_begin());
228 EXPECT_EQ(1u, VPV2->getNumUsers());
229 EXPECT_EQ(I1, *VPV2->user_begin());
230
231 delete I1;
232
233 EXPECT_EQ(0u, VPV1->getNumUsers());
234 EXPECT_EQ(0u, VPV2->getNumUsers());
235
236 delete VPV1;
237 delete VPV2;
238 }
TEST(VPBasicBlockTest,getPlan)239 TEST(VPBasicBlockTest, getPlan) {
240 {
241 VPBasicBlock *VPBB1 = new VPBasicBlock();
242 VPBasicBlock *VPBB2 = new VPBasicBlock();
243 VPBasicBlock *VPBB3 = new VPBasicBlock();
244 VPBasicBlock *VPBB4 = new VPBasicBlock();
245
246 // VPBB1
247 // / \
248 // VPBB2 VPBB3
249 // \ /
250 // VPBB4
251 VPBlockUtils::connectBlocks(VPBB1, VPBB2);
252 VPBlockUtils::connectBlocks(VPBB1, VPBB3);
253 VPBlockUtils::connectBlocks(VPBB2, VPBB4);
254 VPBlockUtils::connectBlocks(VPBB3, VPBB4);
255
256 VPlan Plan;
257 Plan.setEntry(VPBB1);
258
259 EXPECT_EQ(&Plan, VPBB1->getPlan());
260 EXPECT_EQ(&Plan, VPBB2->getPlan());
261 EXPECT_EQ(&Plan, VPBB3->getPlan());
262 EXPECT_EQ(&Plan, VPBB4->getPlan());
263 }
264
265 {
266 // Region block is entry into VPlan.
267 VPBasicBlock *R1BB1 = new VPBasicBlock();
268 VPBasicBlock *R1BB2 = new VPBasicBlock();
269 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1");
270 VPBlockUtils::connectBlocks(R1BB1, R1BB2);
271
272 VPlan Plan;
273 Plan.setEntry(R1);
274 EXPECT_EQ(&Plan, R1->getPlan());
275 EXPECT_EQ(&Plan, R1BB1->getPlan());
276 EXPECT_EQ(&Plan, R1BB2->getPlan());
277 }
278
279 {
280 // VPBasicBlock is the entry into the VPlan, followed by a region.
281 VPBasicBlock *R1BB1 = new VPBasicBlock();
282 VPBasicBlock *R1BB2 = new VPBasicBlock();
283 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1");
284 VPBlockUtils::connectBlocks(R1BB1, R1BB2);
285
286 VPBasicBlock *VPBB1 = new VPBasicBlock();
287 VPBlockUtils::connectBlocks(VPBB1, R1);
288
289 VPlan Plan;
290 Plan.setEntry(VPBB1);
291 EXPECT_EQ(&Plan, VPBB1->getPlan());
292 EXPECT_EQ(&Plan, R1->getPlan());
293 EXPECT_EQ(&Plan, R1BB1->getPlan());
294 EXPECT_EQ(&Plan, R1BB2->getPlan());
295 }
296
297 {
298 VPBasicBlock *R1BB1 = new VPBasicBlock();
299 VPBasicBlock *R1BB2 = new VPBasicBlock();
300 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1");
301 VPBlockUtils::connectBlocks(R1BB1, R1BB2);
302
303 VPBasicBlock *R2BB1 = new VPBasicBlock();
304 VPBasicBlock *R2BB2 = new VPBasicBlock();
305 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
306 VPBlockUtils::connectBlocks(R2BB1, R2BB2);
307
308 VPBasicBlock *VPBB1 = new VPBasicBlock();
309 VPBlockUtils::connectBlocks(VPBB1, R1);
310 VPBlockUtils::connectBlocks(VPBB1, R2);
311
312 VPBasicBlock *VPBB2 = new VPBasicBlock();
313 VPBlockUtils::connectBlocks(R1, VPBB2);
314 VPBlockUtils::connectBlocks(R2, VPBB2);
315
316 VPlan Plan;
317 Plan.setEntry(VPBB1);
318 EXPECT_EQ(&Plan, VPBB1->getPlan());
319 EXPECT_EQ(&Plan, R1->getPlan());
320 EXPECT_EQ(&Plan, R1BB1->getPlan());
321 EXPECT_EQ(&Plan, R1BB2->getPlan());
322 EXPECT_EQ(&Plan, R2->getPlan());
323 EXPECT_EQ(&Plan, R2BB1->getPlan());
324 EXPECT_EQ(&Plan, R2BB2->getPlan());
325 EXPECT_EQ(&Plan, VPBB2->getPlan());
326 }
327 }
328
TEST(VPBasicBlockTest,TraversingIteratorTest)329 TEST(VPBasicBlockTest, TraversingIteratorTest) {
330 {
331 // VPBasicBlocks only
332 // VPBB1
333 // / \
334 // VPBB2 VPBB3
335 // \ /
336 // VPBB4
337 //
338 VPBasicBlock *VPBB1 = new VPBasicBlock();
339 VPBasicBlock *VPBB2 = new VPBasicBlock();
340 VPBasicBlock *VPBB3 = new VPBasicBlock();
341 VPBasicBlock *VPBB4 = new VPBasicBlock();
342
343 VPBlockUtils::connectBlocks(VPBB1, VPBB2);
344 VPBlockUtils::connectBlocks(VPBB1, VPBB3);
345 VPBlockUtils::connectBlocks(VPBB2, VPBB4);
346 VPBlockUtils::connectBlocks(VPBB3, VPBB4);
347
348 VPBlockRecursiveTraversalWrapper<const VPBlockBase *> Start(VPBB1);
349 SmallVector<const VPBlockBase *> FromIterator(depth_first(Start));
350 EXPECT_EQ(4u, FromIterator.size());
351 EXPECT_EQ(VPBB1, FromIterator[0]);
352 EXPECT_EQ(VPBB2, FromIterator[1]);
353
354 // Use Plan to properly clean up created blocks.
355 VPlan Plan;
356 Plan.setEntry(VPBB1);
357 }
358
359 {
360 // 2 consecutive regions.
361 // R1 {
362 // \
363 // R1BB1
364 // / \ |--|
365 // R1BB2 R1BB3 -|
366 // \ /
367 // R1BB4
368 // }
369 // |
370 // R2 {
371 // \
372 // R2BB1
373 // |
374 // R2BB2
375 //
376 VPBasicBlock *R1BB1 = new VPBasicBlock();
377 VPBasicBlock *R1BB2 = new VPBasicBlock();
378 VPBasicBlock *R1BB3 = new VPBasicBlock();
379 VPBasicBlock *R1BB4 = new VPBasicBlock();
380 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB4, "R1");
381 R1BB2->setParent(R1);
382 R1BB3->setParent(R1);
383 VPBlockUtils::connectBlocks(R1BB1, R1BB2);
384 VPBlockUtils::connectBlocks(R1BB1, R1BB3);
385 VPBlockUtils::connectBlocks(R1BB2, R1BB4);
386 VPBlockUtils::connectBlocks(R1BB3, R1BB4);
387 // Cycle.
388 VPBlockUtils::connectBlocks(R1BB3, R1BB3);
389
390 VPBasicBlock *R2BB1 = new VPBasicBlock();
391 VPBasicBlock *R2BB2 = new VPBasicBlock();
392 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
393 VPBlockUtils::connectBlocks(R2BB1, R2BB2);
394 VPBlockUtils::connectBlocks(R1, R2);
395
396 // Depth-first.
397 VPBlockRecursiveTraversalWrapper<VPBlockBase *> Start(R1);
398 SmallVector<const VPBlockBase *> FromIterator(df_begin(Start),
399 df_end(Start));
400 EXPECT_EQ(8u, FromIterator.size());
401 EXPECT_EQ(R1, FromIterator[0]);
402 EXPECT_EQ(R1BB1, FromIterator[1]);
403 EXPECT_EQ(R1BB2, FromIterator[2]);
404 EXPECT_EQ(R1BB4, FromIterator[3]);
405 EXPECT_EQ(R2, FromIterator[4]);
406 EXPECT_EQ(R2BB1, FromIterator[5]);
407 EXPECT_EQ(R2BB2, FromIterator[6]);
408 EXPECT_EQ(R1BB3, FromIterator[7]);
409
410 // const VPBasicBlocks only.
411 FromIterator.clear();
412 copy(VPBlockUtils::blocksOnly<const VPBasicBlock>(depth_first(Start)),
413 std::back_inserter(FromIterator));
414 EXPECT_EQ(6u, FromIterator.size());
415 EXPECT_EQ(R1BB1, FromIterator[0]);
416 EXPECT_EQ(R1BB2, FromIterator[1]);
417 EXPECT_EQ(R1BB4, FromIterator[2]);
418 EXPECT_EQ(R2BB1, FromIterator[3]);
419 EXPECT_EQ(R2BB2, FromIterator[4]);
420 EXPECT_EQ(R1BB3, FromIterator[5]);
421
422 // VPRegionBlocks only.
423 SmallVector<VPRegionBlock *> FromIteratorVPRegion(
424 VPBlockUtils::blocksOnly<VPRegionBlock>(depth_first(Start)));
425 EXPECT_EQ(2u, FromIteratorVPRegion.size());
426 EXPECT_EQ(R1, FromIteratorVPRegion[0]);
427 EXPECT_EQ(R2, FromIteratorVPRegion[1]);
428
429 // Post-order.
430 FromIterator.clear();
431 copy(post_order(Start), std::back_inserter(FromIterator));
432 EXPECT_EQ(8u, FromIterator.size());
433 EXPECT_EQ(R2BB2, FromIterator[0]);
434 EXPECT_EQ(R2BB1, FromIterator[1]);
435 EXPECT_EQ(R2, FromIterator[2]);
436 EXPECT_EQ(R1BB4, FromIterator[3]);
437 EXPECT_EQ(R1BB2, FromIterator[4]);
438 EXPECT_EQ(R1BB3, FromIterator[5]);
439 EXPECT_EQ(R1BB1, FromIterator[6]);
440 EXPECT_EQ(R1, FromIterator[7]);
441
442 // Use Plan to properly clean up created blocks.
443 VPlan Plan;
444 Plan.setEntry(R1);
445 }
446
447 {
448 // 2 nested regions.
449 // VPBB1
450 // |
451 // R1 {
452 // R1BB1
453 // / \
454 // R2 { |
455 // \ |
456 // R2BB1 |
457 // | \ R1BB2
458 // R2BB2-| |
459 // \ |
460 // R2BB3 |
461 // } /
462 // \ /
463 // R1BB3
464 // }
465 // |
466 // VPBB2
467 //
468 VPBasicBlock *R1BB1 = new VPBasicBlock("R1BB1");
469 VPBasicBlock *R1BB2 = new VPBasicBlock("R1BB2");
470 VPBasicBlock *R1BB3 = new VPBasicBlock("R1BB3");
471 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB3, "R1");
472
473 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
474 VPBasicBlock *R2BB2 = new VPBasicBlock("R2BB2");
475 VPBasicBlock *R2BB3 = new VPBasicBlock("R2BB3");
476 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB3, "R2");
477 R2BB2->setParent(R2);
478 VPBlockUtils::connectBlocks(R2BB1, R2BB2);
479 VPBlockUtils::connectBlocks(R2BB2, R2BB1);
480 VPBlockUtils::connectBlocks(R2BB2, R2BB3);
481
482 R2->setParent(R1);
483 VPBlockUtils::connectBlocks(R1BB1, R2);
484 R1BB2->setParent(R1);
485 VPBlockUtils::connectBlocks(R1BB1, R1BB2);
486 VPBlockUtils::connectBlocks(R1BB2, R1BB3);
487 VPBlockUtils::connectBlocks(R2, R1BB3);
488
489 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
490 VPBlockUtils::connectBlocks(VPBB1, R1);
491 VPBasicBlock *VPBB2 = new VPBasicBlock("VPBB2");
492 VPBlockUtils::connectBlocks(R1, VPBB2);
493
494 // Depth-first.
495 VPBlockRecursiveTraversalWrapper<VPBlockBase *> Start(VPBB1);
496 SmallVector<VPBlockBase *> FromIterator(depth_first(Start));
497 EXPECT_EQ(10u, FromIterator.size());
498 EXPECT_EQ(VPBB1, FromIterator[0]);
499 EXPECT_EQ(R1, FromIterator[1]);
500 EXPECT_EQ(R1BB1, FromIterator[2]);
501 EXPECT_EQ(R2, FromIterator[3]);
502 EXPECT_EQ(R2BB1, FromIterator[4]);
503 EXPECT_EQ(R2BB2, FromIterator[5]);
504 EXPECT_EQ(R2BB3, FromIterator[6]);
505 EXPECT_EQ(R1BB3, FromIterator[7]);
506 EXPECT_EQ(VPBB2, FromIterator[8]);
507 EXPECT_EQ(R1BB2, FromIterator[9]);
508
509 // Post-order.
510 FromIterator.clear();
511 FromIterator.append(po_begin(Start), po_end(Start));
512 EXPECT_EQ(10u, FromIterator.size());
513 EXPECT_EQ(VPBB2, FromIterator[0]);
514 EXPECT_EQ(R1BB3, FromIterator[1]);
515 EXPECT_EQ(R2BB3, FromIterator[2]);
516 EXPECT_EQ(R2BB2, FromIterator[3]);
517 EXPECT_EQ(R2BB1, FromIterator[4]);
518 EXPECT_EQ(R2, FromIterator[5]);
519 EXPECT_EQ(R1BB2, FromIterator[6]);
520 EXPECT_EQ(R1BB1, FromIterator[7]);
521 EXPECT_EQ(R1, FromIterator[8]);
522 EXPECT_EQ(VPBB1, FromIterator[9]);
523
524 // Use Plan to properly clean up created blocks.
525 VPlan Plan;
526 Plan.setEntry(VPBB1);
527 }
528
529 {
530 // VPBB1
531 // |
532 // R1 {
533 // \
534 // R2 {
535 // R2BB1
536 // |
537 // R2BB2
538 // }
539 //
540 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
541 VPBasicBlock *R2BB2 = new VPBasicBlock("R2BB2");
542 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
543 VPBlockUtils::connectBlocks(R2BB1, R2BB2);
544
545 VPRegionBlock *R1 = new VPRegionBlock(R2, R2, "R1");
546 R2->setParent(R1);
547
548 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
549 VPBlockUtils::connectBlocks(VPBB1, R1);
550
551 // Depth-first.
552 VPBlockRecursiveTraversalWrapper<VPBlockBase *> Start(VPBB1);
553 SmallVector<VPBlockBase *> FromIterator(depth_first(Start));
554 EXPECT_EQ(5u, FromIterator.size());
555 EXPECT_EQ(VPBB1, FromIterator[0]);
556 EXPECT_EQ(R1, FromIterator[1]);
557 EXPECT_EQ(R2, FromIterator[2]);
558 EXPECT_EQ(R2BB1, FromIterator[3]);
559 EXPECT_EQ(R2BB2, FromIterator[4]);
560
561 // Post-order.
562 FromIterator.clear();
563 FromIterator.append(po_begin(Start), po_end(Start));
564 EXPECT_EQ(5u, FromIterator.size());
565 EXPECT_EQ(R2BB2, FromIterator[0]);
566 EXPECT_EQ(R2BB1, FromIterator[1]);
567 EXPECT_EQ(R2, FromIterator[2]);
568 EXPECT_EQ(R1, FromIterator[3]);
569 EXPECT_EQ(VPBB1, FromIterator[4]);
570
571 // Use Plan to properly clean up created blocks.
572 VPlan Plan;
573 Plan.setEntry(VPBB1);
574 }
575
576 {
577 // Nested regions with both R3 and R2 being exit nodes without successors.
578 // The successors of R1 should be used.
579 //
580 // VPBB1
581 // |
582 // R1 {
583 // \
584 // R2 {
585 // \
586 // R2BB1
587 // |
588 // R3 {
589 // R3BB1
590 // }
591 // }
592 // |
593 // VPBB2
594 //
595 VPBasicBlock *R3BB1 = new VPBasicBlock("R3BB1");
596 VPRegionBlock *R3 = new VPRegionBlock(R3BB1, R3BB1, "R3");
597
598 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
599 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R3, "R2");
600 R3->setParent(R2);
601 VPBlockUtils::connectBlocks(R2BB1, R3);
602
603 VPRegionBlock *R1 = new VPRegionBlock(R2, R2, "R1");
604 R2->setParent(R1);
605
606 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
607 VPBasicBlock *VPBB2 = new VPBasicBlock("VPBB2");
608 VPBlockUtils::connectBlocks(VPBB1, R1);
609 VPBlockUtils::connectBlocks(R1, VPBB2);
610
611 // Depth-first.
612 VPBlockRecursiveTraversalWrapper<VPBlockBase *> Start(VPBB1);
613 SmallVector<VPBlockBase *> FromIterator(depth_first(Start));
614 EXPECT_EQ(7u, FromIterator.size());
615 EXPECT_EQ(VPBB1, FromIterator[0]);
616 EXPECT_EQ(R1, FromIterator[1]);
617 EXPECT_EQ(R2, FromIterator[2]);
618 EXPECT_EQ(R2BB1, FromIterator[3]);
619 EXPECT_EQ(R3, FromIterator[4]);
620 EXPECT_EQ(R3BB1, FromIterator[5]);
621 EXPECT_EQ(VPBB2, FromIterator[6]);
622
623 SmallVector<VPBlockBase *> FromIteratorVPBB;
624 copy(VPBlockUtils::blocksOnly<VPBasicBlock>(depth_first(Start)),
625 std::back_inserter(FromIteratorVPBB));
626 EXPECT_EQ(VPBB1, FromIteratorVPBB[0]);
627 EXPECT_EQ(R2BB1, FromIteratorVPBB[1]);
628 EXPECT_EQ(R3BB1, FromIteratorVPBB[2]);
629 EXPECT_EQ(VPBB2, FromIteratorVPBB[3]);
630
631 // Post-order.
632 FromIterator.clear();
633 copy(post_order(Start), std::back_inserter(FromIterator));
634 EXPECT_EQ(7u, FromIterator.size());
635 EXPECT_EQ(VPBB2, FromIterator[0]);
636 EXPECT_EQ(R3BB1, FromIterator[1]);
637 EXPECT_EQ(R3, FromIterator[2]);
638 EXPECT_EQ(R2BB1, FromIterator[3]);
639 EXPECT_EQ(R2, FromIterator[4]);
640 EXPECT_EQ(R1, FromIterator[5]);
641 EXPECT_EQ(VPBB1, FromIterator[6]);
642
643 // Post-order, const VPRegionBlocks only.
644 VPBlockRecursiveTraversalWrapper<const VPBlockBase *> StartConst(VPBB1);
645 SmallVector<const VPRegionBlock *> FromIteratorVPRegion(
646 VPBlockUtils::blocksOnly<const VPRegionBlock>(post_order(StartConst)));
647 EXPECT_EQ(3u, FromIteratorVPRegion.size());
648 EXPECT_EQ(R3, FromIteratorVPRegion[0]);
649 EXPECT_EQ(R2, FromIteratorVPRegion[1]);
650 EXPECT_EQ(R1, FromIteratorVPRegion[2]);
651
652 // Post-order, VPBasicBlocks only.
653 FromIterator.clear();
654 copy(VPBlockUtils::blocksOnly<VPBasicBlock>(post_order(Start)),
655 std::back_inserter(FromIterator));
656 EXPECT_EQ(FromIterator.size(), 4u);
657 EXPECT_EQ(VPBB2, FromIterator[0]);
658 EXPECT_EQ(R3BB1, FromIterator[1]);
659 EXPECT_EQ(R2BB1, FromIterator[2]);
660 EXPECT_EQ(VPBB1, FromIterator[3]);
661
662 // Use Plan to properly clean up created blocks.
663 VPlan Plan;
664 Plan.setEntry(VPBB1);
665 }
666 }
667
668 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
TEST(VPBasicBlockTest,print)669 TEST(VPBasicBlockTest, print) {
670 VPInstruction *I1 = new VPInstruction(Instruction::Add, {});
671 VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1});
672 VPInstruction *I3 = new VPInstruction(Instruction::Br, {I1, I2});
673
674 VPBasicBlock *VPBB1 = new VPBasicBlock();
675 VPBB1->appendRecipe(I1);
676 VPBB1->appendRecipe(I2);
677 VPBB1->appendRecipe(I3);
678 VPBB1->setName("bb1");
679
680 VPInstruction *I4 = new VPInstruction(Instruction::Mul, {I2, I1});
681 VPInstruction *I5 = new VPInstruction(Instruction::Ret, {I4});
682 VPBasicBlock *VPBB2 = new VPBasicBlock();
683 VPBB2->appendRecipe(I4);
684 VPBB2->appendRecipe(I5);
685 VPBB2->setName("bb2");
686
687 VPBlockUtils::connectBlocks(VPBB1, VPBB2);
688
689 // Check printing an instruction without associated VPlan.
690 {
691 std::string I3Dump;
692 raw_string_ostream OS(I3Dump);
693 VPSlotTracker SlotTracker;
694 I3->print(OS, "", SlotTracker);
695 OS.flush();
696 EXPECT_EQ("EMIT br <badref> <badref>", I3Dump);
697 }
698
699 VPlan Plan;
700 Plan.setEntry(VPBB1);
701 std::string FullDump;
702 raw_string_ostream OS(FullDump);
703 Plan.printDOT(OS);
704
705 const char *ExpectedStr = R"(digraph VPlan {
706 graph [labelloc=t, fontsize=30; label="Vectorization Plan"]
707 node [shape=rect, fontname=Courier, fontsize=30]
708 edge [fontname=Courier, fontsize=30]
709 compound=true
710 N0 [label =
711 "bb1:\l" +
712 " EMIT vp\<%1\> = add\l" +
713 " EMIT vp\<%2\> = sub vp\<%1\>\l" +
714 " EMIT br vp\<%1\> vp\<%2\>\l" +
715 "Successor(s): bb2\l"
716 ]
717 N0 -> N1 [ label=""]
718 N1 [label =
719 "bb2:\l" +
720 " EMIT vp\<%4\> = mul vp\<%2\> vp\<%1\>\l" +
721 " EMIT ret vp\<%4\>\l" +
722 "No successors\l"
723 ]
724 }
725 )";
726 EXPECT_EQ(ExpectedStr, FullDump);
727
728 const char *ExpectedBlock1Str = R"(bb1:
729 EMIT vp<%1> = add
730 EMIT vp<%2> = sub vp<%1>
731 EMIT br vp<%1> vp<%2>
732 Successor(s): bb2
733 )";
734 std::string Block1Dump;
735 raw_string_ostream OS1(Block1Dump);
736 VPBB1->print(OS1);
737 EXPECT_EQ(ExpectedBlock1Str, Block1Dump);
738
739 // Ensure that numbering is good when dumping the second block in isolation.
740 const char *ExpectedBlock2Str = R"(bb2:
741 EMIT vp<%4> = mul vp<%2> vp<%1>
742 EMIT ret vp<%4>
743 No successors
744 )";
745 std::string Block2Dump;
746 raw_string_ostream OS2(Block2Dump);
747 VPBB2->print(OS2);
748 EXPECT_EQ(ExpectedBlock2Str, Block2Dump);
749
750 {
751 std::string I3Dump;
752 raw_string_ostream OS(I3Dump);
753 VPSlotTracker SlotTracker(&Plan);
754 I3->print(OS, "", SlotTracker);
755 OS.flush();
756 EXPECT_EQ("EMIT br vp<%1> vp<%2>", I3Dump);
757 }
758
759 {
760 std::string I4Dump;
761 raw_string_ostream OS(I4Dump);
762 OS << *I4;
763 OS.flush();
764 EXPECT_EQ("EMIT vp<%4> = mul vp<%2> vp<%1>", I4Dump);
765 }
766 }
767 #endif
768
TEST(VPRecipeTest,CastVPInstructionToVPUser)769 TEST(VPRecipeTest, CastVPInstructionToVPUser) {
770 VPValue Op1;
771 VPValue Op2;
772 VPInstruction Recipe(Instruction::Add, {&Op1, &Op2});
773 EXPECT_TRUE(isa<VPUser>(&Recipe));
774 VPRecipeBase *BaseR = &Recipe;
775 EXPECT_TRUE(isa<VPUser>(BaseR));
776 EXPECT_EQ(&Recipe, BaseR);
777 }
778
TEST(VPRecipeTest,CastVPWidenRecipeToVPUser)779 TEST(VPRecipeTest, CastVPWidenRecipeToVPUser) {
780 LLVMContext C;
781
782 IntegerType *Int32 = IntegerType::get(C, 32);
783 auto *AI =
784 BinaryOperator::CreateAdd(UndefValue::get(Int32), UndefValue::get(Int32));
785 VPValue Op1;
786 VPValue Op2;
787 SmallVector<VPValue *, 2> Args;
788 Args.push_back(&Op1);
789 Args.push_back(&Op1);
790 VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end()));
791 EXPECT_TRUE(isa<VPUser>(&WidenR));
792 VPRecipeBase *WidenRBase = &WidenR;
793 EXPECT_TRUE(isa<VPUser>(WidenRBase));
794 EXPECT_EQ(&WidenR, WidenRBase);
795 delete AI;
796 }
797
TEST(VPRecipeTest,CastVPWidenCallRecipeToVPUserAndVPDef)798 TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) {
799 LLVMContext C;
800
801 IntegerType *Int32 = IntegerType::get(C, 32);
802 FunctionType *FTy = FunctionType::get(Int32, false);
803 auto *Call = CallInst::Create(FTy, UndefValue::get(FTy));
804 VPValue Op1;
805 VPValue Op2;
806 SmallVector<VPValue *, 2> Args;
807 Args.push_back(&Op1);
808 Args.push_back(&Op2);
809 VPWidenCallRecipe Recipe(*Call, make_range(Args.begin(), Args.end()));
810 EXPECT_TRUE(isa<VPUser>(&Recipe));
811 VPRecipeBase *BaseR = &Recipe;
812 EXPECT_TRUE(isa<VPUser>(BaseR));
813 EXPECT_EQ(&Recipe, BaseR);
814
815 VPValue *VPV = &Recipe;
816 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDef()));
817 EXPECT_EQ(&Recipe, dyn_cast<VPRecipeBase>(VPV->getDef()));
818
819 delete Call;
820 }
821
TEST(VPRecipeTest,CastVPWidenSelectRecipeToVPUserAndVPDef)822 TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUserAndVPDef) {
823 LLVMContext C;
824
825 IntegerType *Int1 = IntegerType::get(C, 1);
826 IntegerType *Int32 = IntegerType::get(C, 32);
827 auto *SelectI = SelectInst::Create(
828 UndefValue::get(Int1), UndefValue::get(Int32), UndefValue::get(Int32));
829 VPValue Op1;
830 VPValue Op2;
831 VPValue Op3;
832 SmallVector<VPValue *, 4> Args;
833 Args.push_back(&Op1);
834 Args.push_back(&Op2);
835 Args.push_back(&Op3);
836 VPWidenSelectRecipe WidenSelectR(*SelectI,
837 make_range(Args.begin(), Args.end()), false);
838 EXPECT_TRUE(isa<VPUser>(&WidenSelectR));
839 VPRecipeBase *BaseR = &WidenSelectR;
840 EXPECT_TRUE(isa<VPUser>(BaseR));
841 EXPECT_EQ(&WidenSelectR, BaseR);
842
843 VPValue *VPV = &WidenSelectR;
844 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDef()));
845 EXPECT_EQ(&WidenSelectR, dyn_cast<VPRecipeBase>(VPV->getDef()));
846
847 delete SelectI;
848 }
849
TEST(VPRecipeTest,CastVPWidenGEPRecipeToVPUserAndVPDef)850 TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUserAndVPDef) {
851 LLVMContext C;
852
853 IntegerType *Int32 = IntegerType::get(C, 32);
854 PointerType *Int32Ptr = PointerType::get(Int32, 0);
855 auto *GEP = GetElementPtrInst::Create(Int32, UndefValue::get(Int32Ptr),
856 UndefValue::get(Int32));
857 VPValue Op1;
858 VPValue Op2;
859 SmallVector<VPValue *, 4> Args;
860 Args.push_back(&Op1);
861 Args.push_back(&Op2);
862 VPWidenGEPRecipe Recipe(GEP, make_range(Args.begin(), Args.end()));
863 EXPECT_TRUE(isa<VPUser>(&Recipe));
864 VPRecipeBase *BaseR = &Recipe;
865 EXPECT_TRUE(isa<VPUser>(BaseR));
866 EXPECT_EQ(&Recipe, BaseR);
867
868 VPValue *VPV = &Recipe;
869 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDef()));
870 EXPECT_EQ(&Recipe, dyn_cast<VPRecipeBase>(VPV->getDef()));
871
872 delete GEP;
873 }
874
TEST(VPRecipeTest,CastVPBlendRecipeToVPUser)875 TEST(VPRecipeTest, CastVPBlendRecipeToVPUser) {
876 LLVMContext C;
877
878 IntegerType *Int32 = IntegerType::get(C, 32);
879 auto *Phi = PHINode::Create(Int32, 1);
880 VPValue Op1;
881 VPValue Op2;
882 SmallVector<VPValue *, 4> Args;
883 Args.push_back(&Op1);
884 Args.push_back(&Op2);
885 VPBlendRecipe Recipe(Phi, Args);
886 EXPECT_TRUE(isa<VPUser>(&Recipe));
887 VPRecipeBase *BaseR = &Recipe;
888 EXPECT_TRUE(isa<VPUser>(BaseR));
889 delete Phi;
890 }
891
TEST(VPRecipeTest,CastVPInterleaveRecipeToVPUser)892 TEST(VPRecipeTest, CastVPInterleaveRecipeToVPUser) {
893 LLVMContext C;
894
895 VPValue Addr;
896 VPValue Mask;
897 InterleaveGroup<Instruction> IG(4, false, Align(4));
898 VPInterleaveRecipe Recipe(&IG, &Addr, {}, &Mask);
899 EXPECT_TRUE(isa<VPUser>(&Recipe));
900 VPRecipeBase *BaseR = &Recipe;
901 EXPECT_TRUE(isa<VPUser>(BaseR));
902 EXPECT_EQ(&Recipe, BaseR);
903 }
904
TEST(VPRecipeTest,CastVPReplicateRecipeToVPUser)905 TEST(VPRecipeTest, CastVPReplicateRecipeToVPUser) {
906 LLVMContext C;
907
908 VPValue Op1;
909 VPValue Op2;
910 SmallVector<VPValue *, 4> Args;
911 Args.push_back(&Op1);
912 Args.push_back(&Op2);
913
914 VPReplicateRecipe Recipe(nullptr, make_range(Args.begin(), Args.end()), true,
915 false);
916 EXPECT_TRUE(isa<VPUser>(&Recipe));
917 VPRecipeBase *BaseR = &Recipe;
918 EXPECT_TRUE(isa<VPUser>(BaseR));
919 }
920
TEST(VPRecipeTest,CastVPBranchOnMaskRecipeToVPUser)921 TEST(VPRecipeTest, CastVPBranchOnMaskRecipeToVPUser) {
922 LLVMContext C;
923
924 VPValue Mask;
925 VPBranchOnMaskRecipe Recipe(&Mask);
926 EXPECT_TRUE(isa<VPUser>(&Recipe));
927 VPRecipeBase *BaseR = &Recipe;
928 EXPECT_TRUE(isa<VPUser>(BaseR));
929 EXPECT_EQ(&Recipe, BaseR);
930 }
931
TEST(VPRecipeTest,CastVPWidenMemoryInstructionRecipeToVPUserAndVPDef)932 TEST(VPRecipeTest, CastVPWidenMemoryInstructionRecipeToVPUserAndVPDef) {
933 LLVMContext C;
934
935 IntegerType *Int32 = IntegerType::get(C, 32);
936 PointerType *Int32Ptr = PointerType::get(Int32, 0);
937 auto *Load =
938 new LoadInst(Int32, UndefValue::get(Int32Ptr), "", false, Align(1));
939 VPValue Addr;
940 VPValue Mask;
941 VPWidenMemoryInstructionRecipe Recipe(*Load, &Addr, &Mask, true, false);
942 EXPECT_TRUE(isa<VPUser>(&Recipe));
943 VPRecipeBase *BaseR = &Recipe;
944 EXPECT_TRUE(isa<VPUser>(BaseR));
945 EXPECT_EQ(&Recipe, BaseR);
946
947 VPValue *VPV = Recipe.getVPSingleValue();
948 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDef()));
949 EXPECT_EQ(&Recipe, dyn_cast<VPRecipeBase>(VPV->getDef()));
950
951 delete Load;
952 }
953
TEST(VPRecipeTest,MayHaveSideEffectsAndMayReadWriteMemory)954 TEST(VPRecipeTest, MayHaveSideEffectsAndMayReadWriteMemory) {
955 LLVMContext C;
956 IntegerType *Int1 = IntegerType::get(C, 1);
957 IntegerType *Int32 = IntegerType::get(C, 32);
958 PointerType *Int32Ptr = PointerType::get(Int32, 0);
959
960 {
961 auto *AI = BinaryOperator::CreateAdd(UndefValue::get(Int32),
962 UndefValue::get(Int32));
963 VPValue Op1;
964 VPValue Op2;
965 SmallVector<VPValue *, 2> Args;
966 Args.push_back(&Op1);
967 Args.push_back(&Op1);
968 VPWidenRecipe Recipe(*AI, make_range(Args.begin(), Args.end()));
969 EXPECT_FALSE(Recipe.mayHaveSideEffects());
970 EXPECT_FALSE(Recipe.mayReadFromMemory());
971 EXPECT_FALSE(Recipe.mayWriteToMemory());
972 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
973 delete AI;
974 }
975
976 {
977 auto *SelectI = SelectInst::Create(
978 UndefValue::get(Int1), UndefValue::get(Int32), UndefValue::get(Int32));
979 VPValue Op1;
980 VPValue Op2;
981 VPValue Op3;
982 SmallVector<VPValue *, 4> Args;
983 Args.push_back(&Op1);
984 Args.push_back(&Op2);
985 Args.push_back(&Op3);
986 VPWidenSelectRecipe Recipe(*SelectI, make_range(Args.begin(), Args.end()),
987 false);
988 EXPECT_FALSE(Recipe.mayHaveSideEffects());
989 EXPECT_FALSE(Recipe.mayReadFromMemory());
990 EXPECT_FALSE(Recipe.mayWriteToMemory());
991 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
992 delete SelectI;
993 }
994
995 {
996 auto *GEP = GetElementPtrInst::Create(Int32, UndefValue::get(Int32Ptr),
997 UndefValue::get(Int32));
998 VPValue Op1;
999 VPValue Op2;
1000 SmallVector<VPValue *, 4> Args;
1001 Args.push_back(&Op1);
1002 Args.push_back(&Op2);
1003 VPWidenGEPRecipe Recipe(GEP, make_range(Args.begin(), Args.end()));
1004 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1005 EXPECT_FALSE(Recipe.mayReadFromMemory());
1006 EXPECT_FALSE(Recipe.mayWriteToMemory());
1007 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1008 delete GEP;
1009 }
1010
1011 {
1012 VPValue Mask;
1013 VPBranchOnMaskRecipe Recipe(&Mask);
1014 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1015 EXPECT_FALSE(Recipe.mayReadFromMemory());
1016 EXPECT_FALSE(Recipe.mayWriteToMemory());
1017 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1018 }
1019
1020 {
1021 VPValue ChainOp;
1022 VPValue VecOp;
1023 VPValue CondOp;
1024 VPReductionRecipe Recipe(nullptr, nullptr, &ChainOp, &CondOp, &VecOp,
1025 nullptr);
1026 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1027 EXPECT_FALSE(Recipe.mayReadFromMemory());
1028 EXPECT_FALSE(Recipe.mayWriteToMemory());
1029 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1030 }
1031
1032 {
1033 auto *Load =
1034 new LoadInst(Int32, UndefValue::get(Int32Ptr), "", false, Align(1));
1035 VPValue Addr;
1036 VPValue Mask;
1037 VPWidenMemoryInstructionRecipe Recipe(*Load, &Addr, &Mask, true, false);
1038 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1039 EXPECT_TRUE(Recipe.mayReadFromMemory());
1040 EXPECT_FALSE(Recipe.mayWriteToMemory());
1041 EXPECT_TRUE(Recipe.mayReadOrWriteMemory());
1042 delete Load;
1043 }
1044
1045 {
1046 auto *Store = new StoreInst(UndefValue::get(Int32),
1047 UndefValue::get(Int32Ptr), false, Align(1));
1048 VPValue Addr;
1049 VPValue Mask;
1050 VPValue StoredV;
1051 VPWidenMemoryInstructionRecipe Recipe(*Store, &Addr, &StoredV, &Mask, false,
1052 false);
1053 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1054 EXPECT_FALSE(Recipe.mayReadFromMemory());
1055 EXPECT_TRUE(Recipe.mayWriteToMemory());
1056 EXPECT_TRUE(Recipe.mayReadOrWriteMemory());
1057 delete Store;
1058 }
1059
1060 {
1061 FunctionType *FTy = FunctionType::get(Int32, false);
1062 auto *Call = CallInst::Create(FTy, UndefValue::get(FTy));
1063 VPValue Op1;
1064 VPValue Op2;
1065 SmallVector<VPValue *, 2> Args;
1066 Args.push_back(&Op1);
1067 Args.push_back(&Op2);
1068 VPWidenCallRecipe Recipe(*Call, make_range(Args.begin(), Args.end()));
1069 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1070 EXPECT_TRUE(Recipe.mayReadFromMemory());
1071 EXPECT_TRUE(Recipe.mayWriteToMemory());
1072 EXPECT_TRUE(Recipe.mayReadOrWriteMemory());
1073 delete Call;
1074 }
1075
1076 // The initial implementation is conservative with respect to VPInstructions.
1077 {
1078 VPValue Op1;
1079 VPValue Op2;
1080 VPInstruction VPInst(Instruction::Add, {&Op1, &Op2});
1081 VPRecipeBase &Recipe = VPInst;
1082 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1083 EXPECT_TRUE(Recipe.mayReadFromMemory());
1084 EXPECT_TRUE(Recipe.mayWriteToMemory());
1085 EXPECT_TRUE(Recipe.mayReadOrWriteMemory());
1086 }
1087 }
1088
1089 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
TEST(VPRecipeTest,dump)1090 TEST(VPRecipeTest, dump) {
1091 VPlan Plan;
1092 VPBasicBlock *VPBB1 = new VPBasicBlock();
1093 Plan.setEntry(VPBB1);
1094
1095 LLVMContext C;
1096
1097 IntegerType *Int32 = IntegerType::get(C, 32);
1098 auto *AI =
1099 BinaryOperator::CreateAdd(UndefValue::get(Int32), UndefValue::get(Int32));
1100 AI->setName("a");
1101 SmallVector<VPValue *, 2> Args;
1102 VPValue *ExtVPV1 = Plan.getOrAddExternalDef(ConstantInt::get(Int32, 1));
1103 VPValue *ExtVPV2 = Plan.getOrAddExternalDef(ConstantInt::get(Int32, 2));
1104 Args.push_back(ExtVPV1);
1105 Args.push_back(ExtVPV2);
1106 VPWidenRecipe *WidenR =
1107 new VPWidenRecipe(*AI, make_range(Args.begin(), Args.end()));
1108 VPBB1->appendRecipe(WidenR);
1109
1110 {
1111 // Use EXPECT_EXIT to capture stderr and compare against expected output.
1112 //
1113 // Test VPValue::dump().
1114 VPValue *VPV = WidenR;
1115 EXPECT_EXIT(
1116 {
1117 VPV->dump();
1118 exit(0);
1119 },
1120 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
1121
1122 // Test VPRecipeBase::dump().
1123 VPRecipeBase *R = WidenR;
1124 EXPECT_EXIT(
1125 {
1126 R->dump();
1127 exit(0);
1128 },
1129 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
1130
1131 // Test VPDef::dump().
1132 VPDef *D = WidenR;
1133 EXPECT_EXIT(
1134 {
1135 D->dump();
1136 exit(0);
1137 },
1138 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
1139 }
1140
1141 delete AI;
1142 }
1143 #endif
1144
TEST(VPRecipeTest,CastVPReductionRecipeToVPUser)1145 TEST(VPRecipeTest, CastVPReductionRecipeToVPUser) {
1146 LLVMContext C;
1147
1148 VPValue ChainOp;
1149 VPValue VecOp;
1150 VPValue CondOp;
1151 VPReductionRecipe Recipe(nullptr, nullptr, &ChainOp, &CondOp, &VecOp,
1152 nullptr);
1153 EXPECT_TRUE(isa<VPUser>(&Recipe));
1154 VPRecipeBase *BaseR = &Recipe;
1155 EXPECT_TRUE(isa<VPUser>(BaseR));
1156 }
1157
1158 struct VPDoubleValueDef : public VPRecipeBase {
VPDoubleValueDefllvm::__anonf34d9e050111::VPDoubleValueDef1159 VPDoubleValueDef(ArrayRef<VPValue *> Operands) : VPRecipeBase(99, Operands) {
1160 new VPValue(nullptr, this);
1161 new VPValue(nullptr, this);
1162 }
1163
executellvm::__anonf34d9e050111::VPDoubleValueDef1164 void execute(struct VPTransformState &State) override{};
1165 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
printllvm::__anonf34d9e050111::VPDoubleValueDef1166 void print(raw_ostream &O, const Twine &Indent,
1167 VPSlotTracker &SlotTracker) const override {}
1168 #endif
1169 };
1170
TEST(VPDoubleValueDefTest,traverseUseLists)1171 TEST(VPDoubleValueDefTest, traverseUseLists) {
1172 // Check that the def-use chains of a multi-def can be traversed in both
1173 // directions.
1174
1175 // Create a new VPDef which defines 2 values and has 2 operands.
1176 VPInstruction Op0(20, {});
1177 VPInstruction Op1(30, {});
1178 VPDoubleValueDef DoubleValueDef({&Op0, &Op1});
1179
1180 // Create a new users of the defined values.
1181 VPInstruction I1(
1182 1, {DoubleValueDef.getVPValue(0), DoubleValueDef.getVPValue(1)});
1183 VPInstruction I2(2, {DoubleValueDef.getVPValue(0)});
1184 VPInstruction I3(3, {DoubleValueDef.getVPValue(1)});
1185
1186 // Check operands of the VPDef (traversing upwards).
1187 SmallVector<VPValue *, 4> DoubleOperands(DoubleValueDef.op_begin(),
1188 DoubleValueDef.op_end());
1189 EXPECT_EQ(2u, DoubleOperands.size());
1190 EXPECT_EQ(&Op0, DoubleOperands[0]);
1191 EXPECT_EQ(&Op1, DoubleOperands[1]);
1192
1193 // Check users of the defined values (traversing downwards).
1194 SmallVector<VPUser *, 4> DoubleValueDefV0Users(
1195 DoubleValueDef.getVPValue(0)->user_begin(),
1196 DoubleValueDef.getVPValue(0)->user_end());
1197 EXPECT_EQ(2u, DoubleValueDefV0Users.size());
1198 EXPECT_EQ(&I1, DoubleValueDefV0Users[0]);
1199 EXPECT_EQ(&I2, DoubleValueDefV0Users[1]);
1200
1201 SmallVector<VPUser *, 4> DoubleValueDefV1Users(
1202 DoubleValueDef.getVPValue(1)->user_begin(),
1203 DoubleValueDef.getVPValue(1)->user_end());
1204 EXPECT_EQ(2u, DoubleValueDefV1Users.size());
1205 EXPECT_EQ(&I1, DoubleValueDefV1Users[0]);
1206 EXPECT_EQ(&I3, DoubleValueDefV1Users[1]);
1207
1208 // Now check that we can get the right VPDef for each defined value.
1209 EXPECT_EQ(&DoubleValueDef, I1.getOperand(0)->getDef());
1210 EXPECT_EQ(&DoubleValueDef, I1.getOperand(1)->getDef());
1211 EXPECT_EQ(&DoubleValueDef, I2.getOperand(0)->getDef());
1212 EXPECT_EQ(&DoubleValueDef, I3.getOperand(0)->getDef());
1213 }
1214
1215 } // namespace
1216 } // namespace llvm
1217