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/IR/Instruction.h"
12 #include "llvm/IR/Instructions.h"
13 #include "gtest/gtest.h"
14 #include <string>
15
16 namespace llvm {
17 namespace {
18
19 #define CHECK_ITERATOR(Range1, ...) \
20 do { \
21 std::vector<VPInstruction *> Tmp = {__VA_ARGS__}; \
22 EXPECT_EQ((size_t)std::distance(Range1.begin(), Range1.end()), \
23 Tmp.size()); \
24 for (auto Pair : zip(Range1, make_range(Tmp.begin(), Tmp.end()))) \
25 EXPECT_EQ(&std::get<0>(Pair), std::get<1>(Pair)); \
26 } while (0)
27
TEST(VPInstructionTest,insertBefore)28 TEST(VPInstructionTest, insertBefore) {
29 VPInstruction *I1 = new VPInstruction(0, {});
30 VPInstruction *I2 = new VPInstruction(1, {});
31 VPInstruction *I3 = new VPInstruction(2, {});
32
33 VPBasicBlock VPBB1;
34 VPBB1.appendRecipe(I1);
35
36 I2->insertBefore(I1);
37 CHECK_ITERATOR(VPBB1, I2, I1);
38
39 I3->insertBefore(I2);
40 CHECK_ITERATOR(VPBB1, I3, I2, I1);
41 }
42
TEST(VPInstructionTest,eraseFromParent)43 TEST(VPInstructionTest, eraseFromParent) {
44 VPInstruction *I1 = new VPInstruction(0, {});
45 VPInstruction *I2 = new VPInstruction(1, {});
46 VPInstruction *I3 = new VPInstruction(2, {});
47
48 VPBasicBlock VPBB1;
49 VPBB1.appendRecipe(I1);
50 VPBB1.appendRecipe(I2);
51 VPBB1.appendRecipe(I3);
52
53 I2->eraseFromParent();
54 CHECK_ITERATOR(VPBB1, I1, I3);
55
56 I1->eraseFromParent();
57 CHECK_ITERATOR(VPBB1, I3);
58
59 I3->eraseFromParent();
60 EXPECT_TRUE(VPBB1.empty());
61 }
62
TEST(VPInstructionTest,moveAfter)63 TEST(VPInstructionTest, moveAfter) {
64 VPInstruction *I1 = new VPInstruction(0, {});
65 VPInstruction *I2 = new VPInstruction(1, {});
66 VPInstruction *I3 = new VPInstruction(2, {});
67
68 VPBasicBlock VPBB1;
69 VPBB1.appendRecipe(I1);
70 VPBB1.appendRecipe(I2);
71 VPBB1.appendRecipe(I3);
72
73 I1->moveAfter(I2);
74
75 CHECK_ITERATOR(VPBB1, I2, I1, I3);
76
77 VPInstruction *I4 = new VPInstruction(4, {});
78 VPInstruction *I5 = new VPInstruction(5, {});
79 VPBasicBlock VPBB2;
80 VPBB2.appendRecipe(I4);
81 VPBB2.appendRecipe(I5);
82
83 I3->moveAfter(I4);
84
85 CHECK_ITERATOR(VPBB1, I2, I1);
86 CHECK_ITERATOR(VPBB2, I4, I3, I5);
87 EXPECT_EQ(I3->getParent(), I4->getParent());
88 }
89
TEST(VPInstructionTest,setOperand)90 TEST(VPInstructionTest, setOperand) {
91 VPValue *VPV1 = new VPValue();
92 VPValue *VPV2 = new VPValue();
93 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
94 EXPECT_EQ(1u, VPV1->getNumUsers());
95 EXPECT_EQ(I1, *VPV1->user_begin());
96 EXPECT_EQ(1u, VPV2->getNumUsers());
97 EXPECT_EQ(I1, *VPV2->user_begin());
98
99 // Replace operand 0 (VPV1) with VPV3.
100 VPValue *VPV3 = new VPValue();
101 I1->setOperand(0, VPV3);
102 EXPECT_EQ(0u, VPV1->getNumUsers());
103 EXPECT_EQ(1u, VPV2->getNumUsers());
104 EXPECT_EQ(I1, *VPV2->user_begin());
105 EXPECT_EQ(1u, VPV3->getNumUsers());
106 EXPECT_EQ(I1, *VPV3->user_begin());
107
108 // Replace operand 1 (VPV2) with VPV3.
109 I1->setOperand(1, VPV3);
110 EXPECT_EQ(0u, VPV1->getNumUsers());
111 EXPECT_EQ(0u, VPV2->getNumUsers());
112 EXPECT_EQ(2u, VPV3->getNumUsers());
113 EXPECT_EQ(I1, *VPV3->user_begin());
114 EXPECT_EQ(I1, *std::next(VPV3->user_begin()));
115
116 // Replace operand 0 (VPV3) with VPV4.
117 VPValue *VPV4 = new VPValue();
118 I1->setOperand(0, VPV4);
119 EXPECT_EQ(1u, VPV3->getNumUsers());
120 EXPECT_EQ(I1, *VPV3->user_begin());
121 EXPECT_EQ(I1, *VPV4->user_begin());
122
123 // Replace operand 1 (VPV3) with VPV4.
124 I1->setOperand(1, VPV4);
125 EXPECT_EQ(0u, VPV3->getNumUsers());
126 EXPECT_EQ(I1, *VPV4->user_begin());
127 EXPECT_EQ(I1, *std::next(VPV4->user_begin()));
128
129 delete I1;
130 delete VPV1;
131 delete VPV2;
132 delete VPV3;
133 delete VPV4;
134 }
135
TEST(VPInstructionTest,replaceAllUsesWith)136 TEST(VPInstructionTest, replaceAllUsesWith) {
137 VPValue *VPV1 = new VPValue();
138 VPValue *VPV2 = new VPValue();
139 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
140
141 // Replace all uses of VPV1 with VPV3.
142 VPValue *VPV3 = new VPValue();
143 VPV1->replaceAllUsesWith(VPV3);
144 EXPECT_EQ(VPV3, I1->getOperand(0));
145 EXPECT_EQ(VPV2, I1->getOperand(1));
146 EXPECT_EQ(0u, VPV1->getNumUsers());
147 EXPECT_EQ(1u, VPV2->getNumUsers());
148 EXPECT_EQ(I1, *VPV2->user_begin());
149 EXPECT_EQ(1u, VPV3->getNumUsers());
150 EXPECT_EQ(I1, *VPV3->user_begin());
151
152 // Replace all uses of VPV2 with VPV3.
153 VPV2->replaceAllUsesWith(VPV3);
154 EXPECT_EQ(VPV3, I1->getOperand(0));
155 EXPECT_EQ(VPV3, I1->getOperand(1));
156 EXPECT_EQ(0u, VPV1->getNumUsers());
157 EXPECT_EQ(0u, VPV2->getNumUsers());
158 EXPECT_EQ(2u, VPV3->getNumUsers());
159 EXPECT_EQ(I1, *VPV3->user_begin());
160
161 // Replace all uses of VPV3 with VPV1.
162 VPV3->replaceAllUsesWith(VPV1);
163 EXPECT_EQ(VPV1, I1->getOperand(0));
164 EXPECT_EQ(VPV1, I1->getOperand(1));
165 EXPECT_EQ(2u, VPV1->getNumUsers());
166 EXPECT_EQ(I1, *VPV1->user_begin());
167 EXPECT_EQ(0u, VPV2->getNumUsers());
168 EXPECT_EQ(0u, VPV3->getNumUsers());
169
170 VPInstruction *I2 = new VPInstruction(0, {VPV1, VPV2});
171 EXPECT_EQ(3u, VPV1->getNumUsers());
172 VPV1->replaceAllUsesWith(VPV3);
173 EXPECT_EQ(3u, VPV3->getNumUsers());
174
175 delete I1;
176 delete I2;
177 delete VPV1;
178 delete VPV2;
179 delete VPV3;
180 }
181
TEST(VPInstructionTest,releaseOperandsAtDeletion)182 TEST(VPInstructionTest, releaseOperandsAtDeletion) {
183 VPValue *VPV1 = new VPValue();
184 VPValue *VPV2 = new VPValue();
185 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
186
187 EXPECT_EQ(1u, VPV1->getNumUsers());
188 EXPECT_EQ(I1, *VPV1->user_begin());
189 EXPECT_EQ(1u, VPV2->getNumUsers());
190 EXPECT_EQ(I1, *VPV2->user_begin());
191
192 delete I1;
193
194 EXPECT_EQ(0u, VPV1->getNumUsers());
195 EXPECT_EQ(0u, VPV2->getNumUsers());
196
197 delete VPV1;
198 delete VPV2;
199 }
TEST(VPBasicBlockTest,getPlan)200 TEST(VPBasicBlockTest, getPlan) {
201 {
202 VPBasicBlock *VPBB1 = new VPBasicBlock();
203 VPBasicBlock *VPBB2 = new VPBasicBlock();
204 VPBasicBlock *VPBB3 = new VPBasicBlock();
205 VPBasicBlock *VPBB4 = new VPBasicBlock();
206
207 // VPBB1
208 // / \
209 // VPBB2 VPBB3
210 // \ /
211 // VPBB4
212 VPBlockUtils::connectBlocks(VPBB1, VPBB2);
213 VPBlockUtils::connectBlocks(VPBB1, VPBB3);
214 VPBlockUtils::connectBlocks(VPBB2, VPBB4);
215 VPBlockUtils::connectBlocks(VPBB3, VPBB4);
216
217 VPlan Plan;
218 Plan.setEntry(VPBB1);
219
220 EXPECT_EQ(&Plan, VPBB1->getPlan());
221 EXPECT_EQ(&Plan, VPBB2->getPlan());
222 EXPECT_EQ(&Plan, VPBB3->getPlan());
223 EXPECT_EQ(&Plan, VPBB4->getPlan());
224 }
225
226 {
227 // Region block is entry into VPlan.
228 VPBasicBlock *R1BB1 = new VPBasicBlock();
229 VPBasicBlock *R1BB2 = new VPBasicBlock();
230 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1");
231 VPBlockUtils::connectBlocks(R1BB1, R1BB2);
232
233 VPlan Plan;
234 Plan.setEntry(R1);
235 EXPECT_EQ(&Plan, R1->getPlan());
236 EXPECT_EQ(&Plan, R1BB1->getPlan());
237 EXPECT_EQ(&Plan, R1BB2->getPlan());
238 }
239
240 {
241 // VPBasicBlock is the entry into the VPlan, followed by a region.
242 VPBasicBlock *R1BB1 = new VPBasicBlock();
243 VPBasicBlock *R1BB2 = new VPBasicBlock();
244 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1");
245 VPBlockUtils::connectBlocks(R1BB1, R1BB2);
246
247 VPBasicBlock *VPBB1 = new VPBasicBlock();
248 VPBlockUtils::connectBlocks(VPBB1, R1);
249
250 VPlan Plan;
251 Plan.setEntry(VPBB1);
252 EXPECT_EQ(&Plan, VPBB1->getPlan());
253 EXPECT_EQ(&Plan, R1->getPlan());
254 EXPECT_EQ(&Plan, R1BB1->getPlan());
255 EXPECT_EQ(&Plan, R1BB2->getPlan());
256 }
257
258 {
259 VPBasicBlock *R1BB1 = new VPBasicBlock();
260 VPBasicBlock *R1BB2 = new VPBasicBlock();
261 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1");
262 VPBlockUtils::connectBlocks(R1BB1, R1BB2);
263
264 VPBasicBlock *R2BB1 = new VPBasicBlock();
265 VPBasicBlock *R2BB2 = new VPBasicBlock();
266 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
267 VPBlockUtils::connectBlocks(R2BB1, R2BB2);
268
269 VPBasicBlock *VPBB1 = new VPBasicBlock();
270 VPBlockUtils::connectBlocks(VPBB1, R1);
271 VPBlockUtils::connectBlocks(VPBB1, R2);
272
273 VPBasicBlock *VPBB2 = new VPBasicBlock();
274 VPBlockUtils::connectBlocks(R1, VPBB2);
275 VPBlockUtils::connectBlocks(R2, VPBB2);
276
277 VPlan Plan;
278 Plan.setEntry(VPBB1);
279 EXPECT_EQ(&Plan, VPBB1->getPlan());
280 EXPECT_EQ(&Plan, R1->getPlan());
281 EXPECT_EQ(&Plan, R1BB1->getPlan());
282 EXPECT_EQ(&Plan, R1BB2->getPlan());
283 EXPECT_EQ(&Plan, R2->getPlan());
284 EXPECT_EQ(&Plan, R2BB1->getPlan());
285 EXPECT_EQ(&Plan, R2BB2->getPlan());
286 EXPECT_EQ(&Plan, VPBB2->getPlan());
287 }
288 }
289
TEST(VPBasicBlockTest,print)290 TEST(VPBasicBlockTest, print) {
291 VPInstruction *I1 = new VPInstruction(Instruction::Add, {});
292 VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1});
293 VPInstruction *I3 = new VPInstruction(Instruction::Br, {I1, I2});
294
295 VPBasicBlock *VPBB1 = new VPBasicBlock();
296 VPBB1->appendRecipe(I1);
297 VPBB1->appendRecipe(I2);
298 VPBB1->appendRecipe(I3);
299
300 VPInstruction *I4 = new VPInstruction(Instruction::Mul, {I2, I1});
301 VPInstruction *I5 = new VPInstruction(Instruction::Ret, {I4});
302 VPBasicBlock *VPBB2 = new VPBasicBlock();
303 VPBB2->appendRecipe(I4);
304 VPBB2->appendRecipe(I5);
305
306 VPBlockUtils::connectBlocks(VPBB1, VPBB2);
307
308 // Check printing an instruction without associated VPlan.
309 {
310 std::string I3Dump;
311 raw_string_ostream OS(I3Dump);
312 I3->print(OS);
313 OS.flush();
314 EXPECT_EQ("br <badref> <badref>", I3Dump);
315 }
316
317 VPlan Plan;
318 Plan.setEntry(VPBB1);
319 std::string FullDump;
320 raw_string_ostream(FullDump) << Plan;
321
322 const char *ExpectedStr = R"(digraph VPlan {
323 graph [labelloc=t, fontsize=30; label="Vectorization Plan"]
324 node [shape=rect, fontname=Courier, fontsize=30]
325 edge [fontname=Courier, fontsize=30]
326 compound=true
327 N0 [label =
328 ":\n" +
329 "EMIT vp<%0> = add\l" +
330 "EMIT vp<%1> = sub vp<%0>\l" +
331 "EMIT br vp<%0> vp<%1>\l"
332 ]
333 N0 -> N1 [ label=""]
334 N1 [label =
335 ":\n" +
336 "EMIT vp<%2> = mul vp<%1> vp<%0>\l" +
337 "EMIT ret vp<%2>\l"
338 ]
339 }
340 )";
341 EXPECT_EQ(ExpectedStr, FullDump);
342
343 {
344 std::string I3Dump;
345 raw_string_ostream OS(I3Dump);
346 I3->print(OS);
347 OS.flush();
348 EXPECT_EQ("br vp<%0> vp<%1>", I3Dump);
349 }
350
351 {
352 std::string I4Dump;
353 raw_string_ostream OS(I4Dump);
354 OS << *I4;
355 OS.flush();
356 EXPECT_EQ("vp<%2> = mul vp<%1> vp<%0>", I4Dump);
357 }
358 }
359
TEST(VPRecipeTest,CastVPInstructionToVPUser)360 TEST(VPRecipeTest, CastVPInstructionToVPUser) {
361 VPValue Op1;
362 VPValue Op2;
363 VPInstruction Recipe(Instruction::Add, {&Op1, &Op2});
364 EXPECT_TRUE(isa<VPUser>(&Recipe));
365 VPRecipeBase *BaseR = &Recipe;
366 EXPECT_TRUE(isa<VPUser>(BaseR));
367 EXPECT_EQ(&Recipe, BaseR->toVPUser());
368 }
369
TEST(VPRecipeTest,CastVPWidenRecipeToVPUser)370 TEST(VPRecipeTest, CastVPWidenRecipeToVPUser) {
371 LLVMContext C;
372
373 IntegerType *Int32 = IntegerType::get(C, 32);
374 auto *AI =
375 BinaryOperator::CreateAdd(UndefValue::get(Int32), UndefValue::get(Int32));
376 VPValue Op1;
377 VPValue Op2;
378 SmallVector<VPValue *, 2> Args;
379 Args.push_back(&Op1);
380 Args.push_back(&Op1);
381 VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end()));
382 EXPECT_TRUE(isa<VPUser>(&WidenR));
383 VPRecipeBase *WidenRBase = &WidenR;
384 EXPECT_TRUE(isa<VPUser>(WidenRBase));
385 EXPECT_EQ(&WidenR, WidenRBase->toVPUser());
386 delete AI;
387 }
388
TEST(VPRecipeTest,CastVPWidenCallRecipeToVPUser)389 TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUser) {
390 LLVMContext C;
391
392 IntegerType *Int32 = IntegerType::get(C, 32);
393 FunctionType *FTy = FunctionType::get(Int32, false);
394 auto *Call = CallInst::Create(FTy, UndefValue::get(FTy));
395 VPValue Op1;
396 VPValue Op2;
397 SmallVector<VPValue *, 2> Args;
398 Args.push_back(&Op1);
399 Args.push_back(&Op2);
400 VPWidenCallRecipe Recipe(*Call, make_range(Args.begin(), Args.end()));
401 EXPECT_TRUE(isa<VPUser>(&Recipe));
402 VPRecipeBase *BaseR = &Recipe;
403 EXPECT_TRUE(isa<VPUser>(BaseR));
404 EXPECT_EQ(&Recipe, BaseR->toVPUser());
405 delete Call;
406 }
407
TEST(VPRecipeTest,CastVPWidenSelectRecipeToVPUser)408 TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUser) {
409 LLVMContext C;
410
411 IntegerType *Int1 = IntegerType::get(C, 1);
412 IntegerType *Int32 = IntegerType::get(C, 32);
413 auto *SelectI = SelectInst::Create(
414 UndefValue::get(Int1), UndefValue::get(Int32), UndefValue::get(Int32));
415 VPValue Op1;
416 VPValue Op2;
417 VPValue Op3;
418 SmallVector<VPValue *, 4> Args;
419 Args.push_back(&Op1);
420 Args.push_back(&Op2);
421 Args.push_back(&Op3);
422 VPWidenSelectRecipe WidenSelectR(*SelectI,
423 make_range(Args.begin(), Args.end()), false);
424 EXPECT_TRUE(isa<VPUser>(&WidenSelectR));
425 VPRecipeBase *BaseR = &WidenSelectR;
426 EXPECT_TRUE(isa<VPUser>(BaseR));
427 EXPECT_EQ(&WidenSelectR, BaseR->toVPUser());
428 delete SelectI;
429 }
430
TEST(VPRecipeTest,CastVPWidenGEPRecipeToVPUser)431 TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUser) {
432 LLVMContext C;
433
434 IntegerType *Int32 = IntegerType::get(C, 32);
435 PointerType *Int32Ptr = PointerType::get(Int32, 0);
436 auto *GEP = GetElementPtrInst::Create(Int32, UndefValue::get(Int32Ptr),
437 UndefValue::get(Int32));
438 VPValue Op1;
439 VPValue Op2;
440 SmallVector<VPValue *, 4> Args;
441 Args.push_back(&Op1);
442 Args.push_back(&Op2);
443 VPWidenGEPRecipe Recipe(GEP, make_range(Args.begin(), Args.end()));
444 EXPECT_TRUE(isa<VPUser>(&Recipe));
445 VPRecipeBase *BaseR = &Recipe;
446 EXPECT_TRUE(isa<VPUser>(BaseR));
447 EXPECT_EQ(&Recipe, BaseR->toVPUser());
448 delete GEP;
449 }
450
TEST(VPRecipeTest,CastVPBlendRecipeToVPUser)451 TEST(VPRecipeTest, CastVPBlendRecipeToVPUser) {
452 LLVMContext C;
453
454 IntegerType *Int32 = IntegerType::get(C, 32);
455 auto *Phi = PHINode::Create(Int32, 1);
456 VPValue Op1;
457 VPValue Op2;
458 SmallVector<VPValue *, 4> Args;
459 Args.push_back(&Op1);
460 Args.push_back(&Op2);
461 VPBlendRecipe Recipe(Phi, Args);
462 EXPECT_TRUE(isa<VPUser>(&Recipe));
463 VPRecipeBase *BaseR = &Recipe;
464 EXPECT_TRUE(isa<VPUser>(BaseR));
465 delete Phi;
466 }
467
TEST(VPRecipeTest,CastVPInterleaveRecipeToVPUser)468 TEST(VPRecipeTest, CastVPInterleaveRecipeToVPUser) {
469 LLVMContext C;
470
471 VPValue Addr;
472 VPValue Mask;
473 VPInterleaveRecipe Recipe(nullptr, &Addr, {}, &Mask);
474 EXPECT_TRUE(isa<VPUser>(&Recipe));
475 VPRecipeBase *BaseR = &Recipe;
476 EXPECT_TRUE(isa<VPUser>(BaseR));
477 EXPECT_EQ(&Recipe, BaseR->toVPUser());
478 }
479
TEST(VPRecipeTest,CastVPReplicateRecipeToVPUser)480 TEST(VPRecipeTest, CastVPReplicateRecipeToVPUser) {
481 LLVMContext C;
482
483 VPValue Op1;
484 VPValue Op2;
485 SmallVector<VPValue *, 4> Args;
486 Args.push_back(&Op1);
487 Args.push_back(&Op2);
488
489 VPReplicateRecipe Recipe(nullptr, make_range(Args.begin(), Args.end()), true,
490 false);
491 EXPECT_TRUE(isa<VPUser>(&Recipe));
492 VPRecipeBase *BaseR = &Recipe;
493 EXPECT_TRUE(isa<VPUser>(BaseR));
494 }
495
TEST(VPRecipeTest,CastVPBranchOnMaskRecipeToVPUser)496 TEST(VPRecipeTest, CastVPBranchOnMaskRecipeToVPUser) {
497 LLVMContext C;
498
499 VPValue Mask;
500 VPBranchOnMaskRecipe Recipe(&Mask);
501 EXPECT_TRUE(isa<VPUser>(&Recipe));
502 VPRecipeBase *BaseR = &Recipe;
503 EXPECT_TRUE(isa<VPUser>(BaseR));
504 EXPECT_EQ(&Recipe, BaseR->toVPUser());
505 }
506
TEST(VPRecipeTest,CastVPWidenMemoryInstructionRecipeToVPUser)507 TEST(VPRecipeTest, CastVPWidenMemoryInstructionRecipeToVPUser) {
508 LLVMContext C;
509
510 IntegerType *Int32 = IntegerType::get(C, 32);
511 PointerType *Int32Ptr = PointerType::get(Int32, 0);
512 auto *Load =
513 new LoadInst(Int32, UndefValue::get(Int32Ptr), "", false, Align(1));
514 VPValue Addr;
515 VPValue Mask;
516 VPWidenMemoryInstructionRecipe Recipe(*Load, &Addr, &Mask);
517 EXPECT_TRUE(isa<VPUser>(&Recipe));
518 VPRecipeBase *BaseR = &Recipe;
519 EXPECT_TRUE(isa<VPUser>(BaseR));
520 EXPECT_EQ(&Recipe, BaseR->toVPUser());
521 delete Load;
522 }
523
TEST(VPRecipeTest,CastVPReductionRecipeToVPUser)524 TEST(VPRecipeTest, CastVPReductionRecipeToVPUser) {
525 LLVMContext C;
526
527 VPValue ChainOp;
528 VPValue VecOp;
529 VPValue CondOp;
530 VPReductionRecipe Recipe(nullptr, nullptr, &ChainOp, &CondOp, &VecOp, false,
531 nullptr);
532 EXPECT_TRUE(isa<VPUser>(&Recipe));
533 VPRecipeBase *BaseR = &Recipe;
534 EXPECT_TRUE(isa<VPUser>(BaseR));
535 }
536
537 struct VPDoubleValueDef : public VPUser, public VPDef {
VPDoubleValueDefllvm::__anonb566d4cc0111::VPDoubleValueDef538 VPDoubleValueDef(ArrayRef<VPValue *> Operands) : VPUser(Operands), VPDef() {
539 new VPValue(nullptr, this);
540 new VPValue(nullptr, this);
541 }
542 };
543
TEST(VPDoubleValueDefTest,traverseUseLists)544 TEST(VPDoubleValueDefTest, traverseUseLists) {
545 // Check that the def-use chains of a multi-def can be traversed in both
546 // directions.
547
548 // Create a new VPDef which defines 2 values and has 2 operands.
549 VPInstruction Op0(20, {});
550 VPInstruction Op1(30, {});
551 VPDoubleValueDef DoubleValueDef({&Op0, &Op1});
552
553 // Create a new users of the defined values.
554 VPInstruction I1(
555 1, {DoubleValueDef.getVPValue(0), DoubleValueDef.getVPValue(1)});
556 VPInstruction I2(2, {DoubleValueDef.getVPValue(0)});
557 VPInstruction I3(3, {DoubleValueDef.getVPValue(1)});
558
559 // Check operands of the VPDef (traversing upwards).
560 SmallVector<VPValue *, 4> DoubleOperands(DoubleValueDef.op_begin(),
561 DoubleValueDef.op_end());
562 EXPECT_EQ(2u, DoubleOperands.size());
563 EXPECT_EQ(&Op0, DoubleOperands[0]);
564 EXPECT_EQ(&Op1, DoubleOperands[1]);
565
566 // Check users of the defined values (traversing downwards).
567 SmallVector<VPUser *, 4> DoubleValueDefV0Users(
568 DoubleValueDef.getVPValue(0)->user_begin(),
569 DoubleValueDef.getVPValue(0)->user_end());
570 EXPECT_EQ(2u, DoubleValueDefV0Users.size());
571 EXPECT_EQ(&I1, DoubleValueDefV0Users[0]);
572 EXPECT_EQ(&I2, DoubleValueDefV0Users[1]);
573
574 SmallVector<VPUser *, 4> DoubleValueDefV1Users(
575 DoubleValueDef.getVPValue(1)->user_begin(),
576 DoubleValueDef.getVPValue(1)->user_end());
577 EXPECT_EQ(2u, DoubleValueDefV1Users.size());
578 EXPECT_EQ(&I1, DoubleValueDefV1Users[0]);
579 EXPECT_EQ(&I3, DoubleValueDefV1Users[1]);
580
581 // Now check that we can get the right VPDef for each defined value.
582 EXPECT_EQ(&DoubleValueDef, I1.getOperand(0)->getDef());
583 EXPECT_EQ(&DoubleValueDef, I1.getOperand(1)->getDef());
584 EXPECT_EQ(&DoubleValueDef, I2.getOperand(0)->getDef());
585 EXPECT_EQ(&DoubleValueDef, I3.getOperand(0)->getDef());
586 }
587
588 } // namespace
589 } // namespace llvm
590