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 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 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 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 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 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 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 } 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 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 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 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 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 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 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 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 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 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 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 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 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 { 538 VPDoubleValueDef(ArrayRef<VPValue *> Operands) : VPUser(Operands), VPDef() { 539 new VPValue(nullptr, this); 540 new VPValue(nullptr, this); 541 } 542 }; 543 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