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/Analysis/VectorUtils.h" 12 #include "llvm/IR/Instruction.h" 13 #include "llvm/IR/Instructions.h" 14 #include "gtest/gtest.h" 15 #include <string> 16 17 namespace llvm { 18 namespace { 19 20 #define CHECK_ITERATOR(Range1, ...) \ 21 do { \ 22 std::vector<VPInstruction *> Tmp = {__VA_ARGS__}; \ 23 EXPECT_EQ((size_t)std::distance(Range1.begin(), Range1.end()), \ 24 Tmp.size()); \ 25 for (auto Pair : zip(Range1, make_range(Tmp.begin(), Tmp.end()))) \ 26 EXPECT_EQ(&std::get<0>(Pair), std::get<1>(Pair)); \ 27 } while (0) 28 29 TEST(VPInstructionTest, insertBefore) { 30 VPInstruction *I1 = new VPInstruction(0, {}); 31 VPInstruction *I2 = new VPInstruction(1, {}); 32 VPInstruction *I3 = new VPInstruction(2, {}); 33 34 VPBasicBlock VPBB1; 35 VPBB1.appendRecipe(I1); 36 37 I2->insertBefore(I1); 38 CHECK_ITERATOR(VPBB1, I2, I1); 39 40 I3->insertBefore(I2); 41 CHECK_ITERATOR(VPBB1, I3, I2, I1); 42 } 43 44 TEST(VPInstructionTest, eraseFromParent) { 45 VPInstruction *I1 = new VPInstruction(0, {}); 46 VPInstruction *I2 = new VPInstruction(1, {}); 47 VPInstruction *I3 = new VPInstruction(2, {}); 48 49 VPBasicBlock VPBB1; 50 VPBB1.appendRecipe(I1); 51 VPBB1.appendRecipe(I2); 52 VPBB1.appendRecipe(I3); 53 54 I2->eraseFromParent(); 55 CHECK_ITERATOR(VPBB1, I1, I3); 56 57 I1->eraseFromParent(); 58 CHECK_ITERATOR(VPBB1, I3); 59 60 I3->eraseFromParent(); 61 EXPECT_TRUE(VPBB1.empty()); 62 } 63 64 TEST(VPInstructionTest, moveAfter) { 65 VPInstruction *I1 = new VPInstruction(0, {}); 66 VPInstruction *I2 = new VPInstruction(1, {}); 67 VPInstruction *I3 = new VPInstruction(2, {}); 68 69 VPBasicBlock VPBB1; 70 VPBB1.appendRecipe(I1); 71 VPBB1.appendRecipe(I2); 72 VPBB1.appendRecipe(I3); 73 74 I1->moveAfter(I2); 75 76 CHECK_ITERATOR(VPBB1, I2, I1, I3); 77 78 VPInstruction *I4 = new VPInstruction(4, {}); 79 VPInstruction *I5 = new VPInstruction(5, {}); 80 VPBasicBlock VPBB2; 81 VPBB2.appendRecipe(I4); 82 VPBB2.appendRecipe(I5); 83 84 I3->moveAfter(I4); 85 86 CHECK_ITERATOR(VPBB1, I2, I1); 87 CHECK_ITERATOR(VPBB2, I4, I3, I5); 88 EXPECT_EQ(I3->getParent(), I4->getParent()); 89 } 90 91 TEST(VPInstructionTest, moveBefore) { 92 VPInstruction *I1 = new VPInstruction(0, {}); 93 VPInstruction *I2 = new VPInstruction(1, {}); 94 VPInstruction *I3 = new VPInstruction(2, {}); 95 96 VPBasicBlock VPBB1; 97 VPBB1.appendRecipe(I1); 98 VPBB1.appendRecipe(I2); 99 VPBB1.appendRecipe(I3); 100 101 I1->moveBefore(VPBB1, I3->getIterator()); 102 103 CHECK_ITERATOR(VPBB1, I2, I1, I3); 104 105 VPInstruction *I4 = new VPInstruction(4, {}); 106 VPInstruction *I5 = new VPInstruction(5, {}); 107 VPBasicBlock VPBB2; 108 VPBB2.appendRecipe(I4); 109 VPBB2.appendRecipe(I5); 110 111 I3->moveBefore(VPBB2, I4->getIterator()); 112 113 CHECK_ITERATOR(VPBB1, I2, I1); 114 CHECK_ITERATOR(VPBB2, I3, I4, I5); 115 EXPECT_EQ(I3->getParent(), I4->getParent()); 116 117 VPBasicBlock VPBB3; 118 119 I4->moveBefore(VPBB3, VPBB3.end()); 120 121 CHECK_ITERATOR(VPBB1, I2, I1); 122 CHECK_ITERATOR(VPBB2, I3, I5); 123 CHECK_ITERATOR(VPBB3, I4); 124 EXPECT_EQ(&VPBB3, I4->getParent()); 125 } 126 127 TEST(VPInstructionTest, setOperand) { 128 VPValue *VPV1 = new VPValue(); 129 VPValue *VPV2 = new VPValue(); 130 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2}); 131 EXPECT_EQ(1u, VPV1->getNumUsers()); 132 EXPECT_EQ(I1, *VPV1->user_begin()); 133 EXPECT_EQ(1u, VPV2->getNumUsers()); 134 EXPECT_EQ(I1, *VPV2->user_begin()); 135 136 // Replace operand 0 (VPV1) with VPV3. 137 VPValue *VPV3 = new VPValue(); 138 I1->setOperand(0, VPV3); 139 EXPECT_EQ(0u, VPV1->getNumUsers()); 140 EXPECT_EQ(1u, VPV2->getNumUsers()); 141 EXPECT_EQ(I1, *VPV2->user_begin()); 142 EXPECT_EQ(1u, VPV3->getNumUsers()); 143 EXPECT_EQ(I1, *VPV3->user_begin()); 144 145 // Replace operand 1 (VPV2) with VPV3. 146 I1->setOperand(1, VPV3); 147 EXPECT_EQ(0u, VPV1->getNumUsers()); 148 EXPECT_EQ(0u, VPV2->getNumUsers()); 149 EXPECT_EQ(2u, VPV3->getNumUsers()); 150 EXPECT_EQ(I1, *VPV3->user_begin()); 151 EXPECT_EQ(I1, *std::next(VPV3->user_begin())); 152 153 // Replace operand 0 (VPV3) with VPV4. 154 VPValue *VPV4 = new VPValue(); 155 I1->setOperand(0, VPV4); 156 EXPECT_EQ(1u, VPV3->getNumUsers()); 157 EXPECT_EQ(I1, *VPV3->user_begin()); 158 EXPECT_EQ(I1, *VPV4->user_begin()); 159 160 // Replace operand 1 (VPV3) with VPV4. 161 I1->setOperand(1, VPV4); 162 EXPECT_EQ(0u, VPV3->getNumUsers()); 163 EXPECT_EQ(I1, *VPV4->user_begin()); 164 EXPECT_EQ(I1, *std::next(VPV4->user_begin())); 165 166 delete I1; 167 delete VPV1; 168 delete VPV2; 169 delete VPV3; 170 delete VPV4; 171 } 172 173 TEST(VPInstructionTest, replaceAllUsesWith) { 174 VPValue *VPV1 = new VPValue(); 175 VPValue *VPV2 = new VPValue(); 176 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2}); 177 178 // Replace all uses of VPV1 with VPV3. 179 VPValue *VPV3 = new VPValue(); 180 VPV1->replaceAllUsesWith(VPV3); 181 EXPECT_EQ(VPV3, I1->getOperand(0)); 182 EXPECT_EQ(VPV2, I1->getOperand(1)); 183 EXPECT_EQ(0u, VPV1->getNumUsers()); 184 EXPECT_EQ(1u, VPV2->getNumUsers()); 185 EXPECT_EQ(I1, *VPV2->user_begin()); 186 EXPECT_EQ(1u, VPV3->getNumUsers()); 187 EXPECT_EQ(I1, *VPV3->user_begin()); 188 189 // Replace all uses of VPV2 with VPV3. 190 VPV2->replaceAllUsesWith(VPV3); 191 EXPECT_EQ(VPV3, I1->getOperand(0)); 192 EXPECT_EQ(VPV3, I1->getOperand(1)); 193 EXPECT_EQ(0u, VPV1->getNumUsers()); 194 EXPECT_EQ(0u, VPV2->getNumUsers()); 195 EXPECT_EQ(2u, VPV3->getNumUsers()); 196 EXPECT_EQ(I1, *VPV3->user_begin()); 197 198 // Replace all uses of VPV3 with VPV1. 199 VPV3->replaceAllUsesWith(VPV1); 200 EXPECT_EQ(VPV1, I1->getOperand(0)); 201 EXPECT_EQ(VPV1, I1->getOperand(1)); 202 EXPECT_EQ(2u, VPV1->getNumUsers()); 203 EXPECT_EQ(I1, *VPV1->user_begin()); 204 EXPECT_EQ(0u, VPV2->getNumUsers()); 205 EXPECT_EQ(0u, VPV3->getNumUsers()); 206 207 VPInstruction *I2 = new VPInstruction(0, {VPV1, VPV2}); 208 EXPECT_EQ(3u, VPV1->getNumUsers()); 209 VPV1->replaceAllUsesWith(VPV3); 210 EXPECT_EQ(3u, VPV3->getNumUsers()); 211 212 delete I1; 213 delete I2; 214 delete VPV1; 215 delete VPV2; 216 delete VPV3; 217 } 218 219 TEST(VPInstructionTest, releaseOperandsAtDeletion) { 220 VPValue *VPV1 = new VPValue(); 221 VPValue *VPV2 = new VPValue(); 222 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2}); 223 224 EXPECT_EQ(1u, VPV1->getNumUsers()); 225 EXPECT_EQ(I1, *VPV1->user_begin()); 226 EXPECT_EQ(1u, VPV2->getNumUsers()); 227 EXPECT_EQ(I1, *VPV2->user_begin()); 228 229 delete I1; 230 231 EXPECT_EQ(0u, VPV1->getNumUsers()); 232 EXPECT_EQ(0u, VPV2->getNumUsers()); 233 234 delete VPV1; 235 delete VPV2; 236 } 237 TEST(VPBasicBlockTest, getPlan) { 238 { 239 VPBasicBlock *VPBB1 = new VPBasicBlock(); 240 VPBasicBlock *VPBB2 = new VPBasicBlock(); 241 VPBasicBlock *VPBB3 = new VPBasicBlock(); 242 VPBasicBlock *VPBB4 = new VPBasicBlock(); 243 244 // VPBB1 245 // / \ 246 // VPBB2 VPBB3 247 // \ / 248 // VPBB4 249 VPBlockUtils::connectBlocks(VPBB1, VPBB2); 250 VPBlockUtils::connectBlocks(VPBB1, VPBB3); 251 VPBlockUtils::connectBlocks(VPBB2, VPBB4); 252 VPBlockUtils::connectBlocks(VPBB3, VPBB4); 253 254 VPlan Plan; 255 Plan.setEntry(VPBB1); 256 257 EXPECT_EQ(&Plan, VPBB1->getPlan()); 258 EXPECT_EQ(&Plan, VPBB2->getPlan()); 259 EXPECT_EQ(&Plan, VPBB3->getPlan()); 260 EXPECT_EQ(&Plan, VPBB4->getPlan()); 261 } 262 263 { 264 // Region block is entry into VPlan. 265 VPBasicBlock *R1BB1 = new VPBasicBlock(); 266 VPBasicBlock *R1BB2 = new VPBasicBlock(); 267 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1"); 268 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 269 270 VPlan Plan; 271 Plan.setEntry(R1); 272 EXPECT_EQ(&Plan, R1->getPlan()); 273 EXPECT_EQ(&Plan, R1BB1->getPlan()); 274 EXPECT_EQ(&Plan, R1BB2->getPlan()); 275 } 276 277 { 278 // VPBasicBlock is the entry into the VPlan, followed by a region. 279 VPBasicBlock *R1BB1 = new VPBasicBlock(); 280 VPBasicBlock *R1BB2 = new VPBasicBlock(); 281 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1"); 282 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 283 284 VPBasicBlock *VPBB1 = new VPBasicBlock(); 285 VPBlockUtils::connectBlocks(VPBB1, R1); 286 287 VPlan Plan; 288 Plan.setEntry(VPBB1); 289 EXPECT_EQ(&Plan, VPBB1->getPlan()); 290 EXPECT_EQ(&Plan, R1->getPlan()); 291 EXPECT_EQ(&Plan, R1BB1->getPlan()); 292 EXPECT_EQ(&Plan, R1BB2->getPlan()); 293 } 294 295 { 296 VPBasicBlock *R1BB1 = new VPBasicBlock(); 297 VPBasicBlock *R1BB2 = new VPBasicBlock(); 298 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1"); 299 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 300 301 VPBasicBlock *R2BB1 = new VPBasicBlock(); 302 VPBasicBlock *R2BB2 = new VPBasicBlock(); 303 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2"); 304 VPBlockUtils::connectBlocks(R2BB1, R2BB2); 305 306 VPBasicBlock *VPBB1 = new VPBasicBlock(); 307 VPBlockUtils::connectBlocks(VPBB1, R1); 308 VPBlockUtils::connectBlocks(VPBB1, R2); 309 310 VPBasicBlock *VPBB2 = new VPBasicBlock(); 311 VPBlockUtils::connectBlocks(R1, VPBB2); 312 VPBlockUtils::connectBlocks(R2, VPBB2); 313 314 VPlan Plan; 315 Plan.setEntry(VPBB1); 316 EXPECT_EQ(&Plan, VPBB1->getPlan()); 317 EXPECT_EQ(&Plan, R1->getPlan()); 318 EXPECT_EQ(&Plan, R1BB1->getPlan()); 319 EXPECT_EQ(&Plan, R1BB2->getPlan()); 320 EXPECT_EQ(&Plan, R2->getPlan()); 321 EXPECT_EQ(&Plan, R2BB1->getPlan()); 322 EXPECT_EQ(&Plan, R2BB2->getPlan()); 323 EXPECT_EQ(&Plan, VPBB2->getPlan()); 324 } 325 } 326 327 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 328 TEST(VPBasicBlockTest, print) { 329 VPInstruction *I1 = new VPInstruction(Instruction::Add, {}); 330 VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1}); 331 VPInstruction *I3 = new VPInstruction(Instruction::Br, {I1, I2}); 332 333 VPBasicBlock *VPBB1 = new VPBasicBlock(); 334 VPBB1->appendRecipe(I1); 335 VPBB1->appendRecipe(I2); 336 VPBB1->appendRecipe(I3); 337 VPBB1->setName("bb1"); 338 339 VPInstruction *I4 = new VPInstruction(Instruction::Mul, {I2, I1}); 340 VPInstruction *I5 = new VPInstruction(Instruction::Ret, {I4}); 341 VPBasicBlock *VPBB2 = new VPBasicBlock(); 342 VPBB2->appendRecipe(I4); 343 VPBB2->appendRecipe(I5); 344 VPBB2->setName("bb2"); 345 346 VPBlockUtils::connectBlocks(VPBB1, VPBB2); 347 348 // Check printing an instruction without associated VPlan. 349 { 350 std::string I3Dump; 351 raw_string_ostream OS(I3Dump); 352 VPSlotTracker SlotTracker; 353 I3->print(OS, "", SlotTracker); 354 OS.flush(); 355 EXPECT_EQ("EMIT br <badref> <badref>", I3Dump); 356 } 357 358 VPlan Plan; 359 Plan.setEntry(VPBB1); 360 std::string FullDump; 361 raw_string_ostream OS(FullDump); 362 Plan.printDOT(OS); 363 364 const char *ExpectedStr = R"(digraph VPlan { 365 graph [labelloc=t, fontsize=30; label="Vectorization Plan"] 366 node [shape=rect, fontname=Courier, fontsize=30] 367 edge [fontname=Courier, fontsize=30] 368 compound=true 369 N0 [label = 370 "bb1:\l" + 371 " EMIT vp\<%0\> = add\l" + 372 " EMIT vp\<%1\> = sub vp\<%0\>\l" + 373 " EMIT br vp\<%0\> vp\<%1\>\l" + 374 "Successor(s): bb2\l" 375 ] 376 N0 -> N1 [ label=""] 377 N1 [label = 378 "bb2:\l" + 379 " EMIT vp\<%3\> = mul vp\<%1\> vp\<%0\>\l" + 380 " EMIT ret vp\<%3\>\l" + 381 "No successors\l" 382 ] 383 } 384 )"; 385 EXPECT_EQ(ExpectedStr, FullDump); 386 387 const char *ExpectedBlock1Str = R"(bb1: 388 EMIT vp<%0> = add 389 EMIT vp<%1> = sub vp<%0> 390 EMIT br vp<%0> vp<%1> 391 Successor(s): bb2 392 )"; 393 std::string Block1Dump; 394 raw_string_ostream OS1(Block1Dump); 395 VPBB1->print(OS1); 396 EXPECT_EQ(ExpectedBlock1Str, Block1Dump); 397 398 // Ensure that numbering is good when dumping the second block in isolation. 399 const char *ExpectedBlock2Str = R"(bb2: 400 EMIT vp<%3> = mul vp<%1> vp<%0> 401 EMIT ret vp<%3> 402 No successors 403 )"; 404 std::string Block2Dump; 405 raw_string_ostream OS2(Block2Dump); 406 VPBB2->print(OS2); 407 EXPECT_EQ(ExpectedBlock2Str, Block2Dump); 408 409 { 410 std::string I3Dump; 411 raw_string_ostream OS(I3Dump); 412 VPSlotTracker SlotTracker(&Plan); 413 I3->print(OS, "", SlotTracker); 414 OS.flush(); 415 EXPECT_EQ("EMIT br vp<%0> vp<%1>", I3Dump); 416 } 417 418 { 419 std::string I4Dump; 420 raw_string_ostream OS(I4Dump); 421 OS << *I4; 422 OS.flush(); 423 EXPECT_EQ("EMIT vp<%3> = mul vp<%1> vp<%0>", I4Dump); 424 } 425 } 426 #endif 427 428 TEST(VPRecipeTest, CastVPInstructionToVPUser) { 429 VPValue Op1; 430 VPValue Op2; 431 VPInstruction Recipe(Instruction::Add, {&Op1, &Op2}); 432 EXPECT_TRUE(isa<VPUser>(&Recipe)); 433 VPRecipeBase *BaseR = &Recipe; 434 EXPECT_TRUE(isa<VPUser>(BaseR)); 435 EXPECT_EQ(&Recipe, BaseR); 436 } 437 438 TEST(VPRecipeTest, CastVPWidenRecipeToVPUser) { 439 LLVMContext C; 440 441 IntegerType *Int32 = IntegerType::get(C, 32); 442 auto *AI = 443 BinaryOperator::CreateAdd(UndefValue::get(Int32), UndefValue::get(Int32)); 444 VPValue Op1; 445 VPValue Op2; 446 SmallVector<VPValue *, 2> Args; 447 Args.push_back(&Op1); 448 Args.push_back(&Op1); 449 VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end())); 450 EXPECT_TRUE(isa<VPUser>(&WidenR)); 451 VPRecipeBase *WidenRBase = &WidenR; 452 EXPECT_TRUE(isa<VPUser>(WidenRBase)); 453 EXPECT_EQ(&WidenR, WidenRBase); 454 delete AI; 455 } 456 457 TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) { 458 LLVMContext C; 459 460 IntegerType *Int32 = IntegerType::get(C, 32); 461 FunctionType *FTy = FunctionType::get(Int32, false); 462 auto *Call = CallInst::Create(FTy, UndefValue::get(FTy)); 463 VPValue Op1; 464 VPValue Op2; 465 SmallVector<VPValue *, 2> Args; 466 Args.push_back(&Op1); 467 Args.push_back(&Op2); 468 VPWidenCallRecipe Recipe(*Call, make_range(Args.begin(), Args.end())); 469 EXPECT_TRUE(isa<VPUser>(&Recipe)); 470 VPRecipeBase *BaseR = &Recipe; 471 EXPECT_TRUE(isa<VPUser>(BaseR)); 472 EXPECT_EQ(&Recipe, BaseR); 473 474 VPValue *VPV = &Recipe; 475 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDef())); 476 EXPECT_EQ(&Recipe, dyn_cast<VPRecipeBase>(VPV->getDef())); 477 478 delete Call; 479 } 480 481 TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUserAndVPDef) { 482 LLVMContext C; 483 484 IntegerType *Int1 = IntegerType::get(C, 1); 485 IntegerType *Int32 = IntegerType::get(C, 32); 486 auto *SelectI = SelectInst::Create( 487 UndefValue::get(Int1), UndefValue::get(Int32), UndefValue::get(Int32)); 488 VPValue Op1; 489 VPValue Op2; 490 VPValue Op3; 491 SmallVector<VPValue *, 4> Args; 492 Args.push_back(&Op1); 493 Args.push_back(&Op2); 494 Args.push_back(&Op3); 495 VPWidenSelectRecipe WidenSelectR(*SelectI, 496 make_range(Args.begin(), Args.end()), false); 497 EXPECT_TRUE(isa<VPUser>(&WidenSelectR)); 498 VPRecipeBase *BaseR = &WidenSelectR; 499 EXPECT_TRUE(isa<VPUser>(BaseR)); 500 EXPECT_EQ(&WidenSelectR, BaseR); 501 502 VPValue *VPV = &WidenSelectR; 503 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDef())); 504 EXPECT_EQ(&WidenSelectR, dyn_cast<VPRecipeBase>(VPV->getDef())); 505 506 delete SelectI; 507 } 508 509 TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUserAndVPDef) { 510 LLVMContext C; 511 512 IntegerType *Int32 = IntegerType::get(C, 32); 513 PointerType *Int32Ptr = PointerType::get(Int32, 0); 514 auto *GEP = GetElementPtrInst::Create(Int32, UndefValue::get(Int32Ptr), 515 UndefValue::get(Int32)); 516 VPValue Op1; 517 VPValue Op2; 518 SmallVector<VPValue *, 4> Args; 519 Args.push_back(&Op1); 520 Args.push_back(&Op2); 521 VPWidenGEPRecipe Recipe(GEP, make_range(Args.begin(), Args.end())); 522 EXPECT_TRUE(isa<VPUser>(&Recipe)); 523 VPRecipeBase *BaseR = &Recipe; 524 EXPECT_TRUE(isa<VPUser>(BaseR)); 525 EXPECT_EQ(&Recipe, BaseR); 526 527 VPValue *VPV = &Recipe; 528 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDef())); 529 EXPECT_EQ(&Recipe, dyn_cast<VPRecipeBase>(VPV->getDef())); 530 531 delete GEP; 532 } 533 534 TEST(VPRecipeTest, CastVPBlendRecipeToVPUser) { 535 LLVMContext C; 536 537 IntegerType *Int32 = IntegerType::get(C, 32); 538 auto *Phi = PHINode::Create(Int32, 1); 539 VPValue Op1; 540 VPValue Op2; 541 SmallVector<VPValue *, 4> Args; 542 Args.push_back(&Op1); 543 Args.push_back(&Op2); 544 VPBlendRecipe Recipe(Phi, Args); 545 EXPECT_TRUE(isa<VPUser>(&Recipe)); 546 VPRecipeBase *BaseR = &Recipe; 547 EXPECT_TRUE(isa<VPUser>(BaseR)); 548 delete Phi; 549 } 550 551 TEST(VPRecipeTest, CastVPInterleaveRecipeToVPUser) { 552 LLVMContext C; 553 554 VPValue Addr; 555 VPValue Mask; 556 InterleaveGroup<Instruction> IG(4, false, Align(4)); 557 VPInterleaveRecipe Recipe(&IG, &Addr, {}, &Mask); 558 EXPECT_TRUE(isa<VPUser>(&Recipe)); 559 VPRecipeBase *BaseR = &Recipe; 560 EXPECT_TRUE(isa<VPUser>(BaseR)); 561 EXPECT_EQ(&Recipe, BaseR); 562 } 563 564 TEST(VPRecipeTest, CastVPReplicateRecipeToVPUser) { 565 LLVMContext C; 566 567 VPValue Op1; 568 VPValue Op2; 569 SmallVector<VPValue *, 4> Args; 570 Args.push_back(&Op1); 571 Args.push_back(&Op2); 572 573 VPReplicateRecipe Recipe(nullptr, make_range(Args.begin(), Args.end()), true, 574 false); 575 EXPECT_TRUE(isa<VPUser>(&Recipe)); 576 VPRecipeBase *BaseR = &Recipe; 577 EXPECT_TRUE(isa<VPUser>(BaseR)); 578 } 579 580 TEST(VPRecipeTest, CastVPBranchOnMaskRecipeToVPUser) { 581 LLVMContext C; 582 583 VPValue Mask; 584 VPBranchOnMaskRecipe Recipe(&Mask); 585 EXPECT_TRUE(isa<VPUser>(&Recipe)); 586 VPRecipeBase *BaseR = &Recipe; 587 EXPECT_TRUE(isa<VPUser>(BaseR)); 588 EXPECT_EQ(&Recipe, BaseR); 589 } 590 591 TEST(VPRecipeTest, CastVPWidenMemoryInstructionRecipeToVPUserAndVPDef) { 592 LLVMContext C; 593 594 IntegerType *Int32 = IntegerType::get(C, 32); 595 PointerType *Int32Ptr = PointerType::get(Int32, 0); 596 auto *Load = 597 new LoadInst(Int32, UndefValue::get(Int32Ptr), "", false, Align(1)); 598 VPValue Addr; 599 VPValue Mask; 600 VPWidenMemoryInstructionRecipe Recipe(*Load, &Addr, &Mask); 601 EXPECT_TRUE(isa<VPUser>(&Recipe)); 602 VPRecipeBase *BaseR = &Recipe; 603 EXPECT_TRUE(isa<VPUser>(BaseR)); 604 EXPECT_EQ(&Recipe, BaseR); 605 606 VPValue *VPV = Recipe.getVPValue(); 607 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDef())); 608 EXPECT_EQ(&Recipe, dyn_cast<VPRecipeBase>(VPV->getDef())); 609 610 delete Load; 611 } 612 613 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 614 TEST(VPRecipeTest, dump) { 615 VPlan Plan; 616 VPBasicBlock *VPBB1 = new VPBasicBlock(); 617 Plan.setEntry(VPBB1); 618 619 LLVMContext C; 620 621 IntegerType *Int32 = IntegerType::get(C, 32); 622 auto *AI = 623 BinaryOperator::CreateAdd(UndefValue::get(Int32), UndefValue::get(Int32)); 624 AI->setName("a"); 625 SmallVector<VPValue *, 2> Args; 626 VPValue *ExtVPV1 = new VPValue(); 627 VPValue *ExtVPV2 = new VPValue(); 628 Plan.addExternalDef(ExtVPV1); 629 Plan.addExternalDef(ExtVPV2); 630 Args.push_back(ExtVPV1); 631 Args.push_back(ExtVPV2); 632 VPWidenRecipe *WidenR = 633 new VPWidenRecipe(*AI, make_range(Args.begin(), Args.end())); 634 VPBB1->appendRecipe(WidenR); 635 636 { 637 // Use EXPECT_EXIT to capture stderr and compare against expected output. 638 // 639 // Test VPValue::dump(). 640 VPValue *VPV = WidenR; 641 EXPECT_EXIT( 642 { 643 VPV->dump(); 644 exit(0); 645 }, 646 testing::ExitedWithCode(0), "WIDEN ir<%a> = add vp<%0>, vp<%1>"); 647 648 // Test VPRecipeBase::dump(). 649 VPRecipeBase *R = WidenR; 650 EXPECT_EXIT( 651 { 652 R->dump(); 653 exit(0); 654 }, 655 testing::ExitedWithCode(0), "WIDEN ir<%a> = add vp<%0>, vp<%1>"); 656 657 // Test VPDef::dump(). 658 VPDef *D = WidenR; 659 EXPECT_EXIT( 660 { 661 D->dump(); 662 exit(0); 663 }, 664 testing::ExitedWithCode(0), "WIDEN ir<%a> = add vp<%0>, vp<%1>"); 665 } 666 667 delete AI; 668 } 669 #endif 670 671 TEST(VPRecipeTest, CastVPReductionRecipeToVPUser) { 672 LLVMContext C; 673 674 VPValue ChainOp; 675 VPValue VecOp; 676 VPValue CondOp; 677 VPReductionRecipe Recipe(nullptr, nullptr, &ChainOp, &CondOp, &VecOp, 678 nullptr); 679 EXPECT_TRUE(isa<VPUser>(&Recipe)); 680 VPRecipeBase *BaseR = &Recipe; 681 EXPECT_TRUE(isa<VPUser>(BaseR)); 682 } 683 684 struct VPDoubleValueDef : public VPRecipeBase { 685 VPDoubleValueDef(ArrayRef<VPValue *> Operands) : VPRecipeBase(99, Operands) { 686 new VPValue(nullptr, this); 687 new VPValue(nullptr, this); 688 } 689 690 void execute(struct VPTransformState &State) override{}; 691 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 692 void print(raw_ostream &O, const Twine &Indent, 693 VPSlotTracker &SlotTracker) const override {} 694 #endif 695 }; 696 697 TEST(VPDoubleValueDefTest, traverseUseLists) { 698 // Check that the def-use chains of a multi-def can be traversed in both 699 // directions. 700 701 // Create a new VPDef which defines 2 values and has 2 operands. 702 VPInstruction Op0(20, {}); 703 VPInstruction Op1(30, {}); 704 VPDoubleValueDef DoubleValueDef({&Op0, &Op1}); 705 706 // Create a new users of the defined values. 707 VPInstruction I1( 708 1, {DoubleValueDef.getVPValue(0), DoubleValueDef.getVPValue(1)}); 709 VPInstruction I2(2, {DoubleValueDef.getVPValue(0)}); 710 VPInstruction I3(3, {DoubleValueDef.getVPValue(1)}); 711 712 // Check operands of the VPDef (traversing upwards). 713 SmallVector<VPValue *, 4> DoubleOperands(DoubleValueDef.op_begin(), 714 DoubleValueDef.op_end()); 715 EXPECT_EQ(2u, DoubleOperands.size()); 716 EXPECT_EQ(&Op0, DoubleOperands[0]); 717 EXPECT_EQ(&Op1, DoubleOperands[1]); 718 719 // Check users of the defined values (traversing downwards). 720 SmallVector<VPUser *, 4> DoubleValueDefV0Users( 721 DoubleValueDef.getVPValue(0)->user_begin(), 722 DoubleValueDef.getVPValue(0)->user_end()); 723 EXPECT_EQ(2u, DoubleValueDefV0Users.size()); 724 EXPECT_EQ(&I1, DoubleValueDefV0Users[0]); 725 EXPECT_EQ(&I2, DoubleValueDefV0Users[1]); 726 727 SmallVector<VPUser *, 4> DoubleValueDefV1Users( 728 DoubleValueDef.getVPValue(1)->user_begin(), 729 DoubleValueDef.getVPValue(1)->user_end()); 730 EXPECT_EQ(2u, DoubleValueDefV1Users.size()); 731 EXPECT_EQ(&I1, DoubleValueDefV1Users[0]); 732 EXPECT_EQ(&I3, DoubleValueDefV1Users[1]); 733 734 // Now check that we can get the right VPDef for each defined value. 735 EXPECT_EQ(&DoubleValueDef, I1.getOperand(0)->getDef()); 736 EXPECT_EQ(&DoubleValueDef, I1.getOperand(1)->getDef()); 737 EXPECT_EQ(&DoubleValueDef, I2.getOperand(0)->getDef()); 738 EXPECT_EQ(&DoubleValueDef, I3.getOperand(0)->getDef()); 739 } 740 741 } // namespace 742 } // namespace llvm 743