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 "../lib/Transforms/Vectorize/VPlanCFG.h" 12 #include "llvm/ADT/DepthFirstIterator.h" 13 #include "llvm/ADT/PostOrderIterator.h" 14 #include "llvm/Analysis/VectorUtils.h" 15 #include "llvm/IR/Instruction.h" 16 #include "llvm/IR/Instructions.h" 17 #include "gtest/gtest.h" 18 #include <string> 19 20 namespace llvm { 21 namespace { 22 23 #define CHECK_ITERATOR(Range1, ...) \ 24 do { \ 25 std::vector<VPInstruction *> Tmp = {__VA_ARGS__}; \ 26 EXPECT_EQ((size_t)std::distance(Range1.begin(), Range1.end()), \ 27 Tmp.size()); \ 28 for (auto Pair : zip(Range1, make_range(Tmp.begin(), Tmp.end()))) \ 29 EXPECT_EQ(&std::get<0>(Pair), std::get<1>(Pair)); \ 30 } while (0) 31 32 TEST(VPInstructionTest, insertBefore) { 33 VPInstruction *I1 = new VPInstruction(0, {}); 34 VPInstruction *I2 = new VPInstruction(1, {}); 35 VPInstruction *I3 = new VPInstruction(2, {}); 36 37 VPBasicBlock VPBB1; 38 VPBB1.appendRecipe(I1); 39 40 I2->insertBefore(I1); 41 CHECK_ITERATOR(VPBB1, I2, I1); 42 43 I3->insertBefore(I2); 44 CHECK_ITERATOR(VPBB1, I3, I2, I1); 45 } 46 47 TEST(VPInstructionTest, eraseFromParent) { 48 VPInstruction *I1 = new VPInstruction(0, {}); 49 VPInstruction *I2 = new VPInstruction(1, {}); 50 VPInstruction *I3 = new VPInstruction(2, {}); 51 52 VPBasicBlock VPBB1; 53 VPBB1.appendRecipe(I1); 54 VPBB1.appendRecipe(I2); 55 VPBB1.appendRecipe(I3); 56 57 I2->eraseFromParent(); 58 CHECK_ITERATOR(VPBB1, I1, I3); 59 60 I1->eraseFromParent(); 61 CHECK_ITERATOR(VPBB1, I3); 62 63 I3->eraseFromParent(); 64 EXPECT_TRUE(VPBB1.empty()); 65 } 66 67 TEST(VPInstructionTest, moveAfter) { 68 VPInstruction *I1 = new VPInstruction(0, {}); 69 VPInstruction *I2 = new VPInstruction(1, {}); 70 VPInstruction *I3 = new VPInstruction(2, {}); 71 72 VPBasicBlock VPBB1; 73 VPBB1.appendRecipe(I1); 74 VPBB1.appendRecipe(I2); 75 VPBB1.appendRecipe(I3); 76 77 I1->moveAfter(I2); 78 79 CHECK_ITERATOR(VPBB1, I2, I1, I3); 80 81 VPInstruction *I4 = new VPInstruction(4, {}); 82 VPInstruction *I5 = new VPInstruction(5, {}); 83 VPBasicBlock VPBB2; 84 VPBB2.appendRecipe(I4); 85 VPBB2.appendRecipe(I5); 86 87 I3->moveAfter(I4); 88 89 CHECK_ITERATOR(VPBB1, I2, I1); 90 CHECK_ITERATOR(VPBB2, I4, I3, I5); 91 EXPECT_EQ(I3->getParent(), I4->getParent()); 92 } 93 94 TEST(VPInstructionTest, moveBefore) { 95 VPInstruction *I1 = new VPInstruction(0, {}); 96 VPInstruction *I2 = new VPInstruction(1, {}); 97 VPInstruction *I3 = new VPInstruction(2, {}); 98 99 VPBasicBlock VPBB1; 100 VPBB1.appendRecipe(I1); 101 VPBB1.appendRecipe(I2); 102 VPBB1.appendRecipe(I3); 103 104 I1->moveBefore(VPBB1, I3->getIterator()); 105 106 CHECK_ITERATOR(VPBB1, I2, I1, I3); 107 108 VPInstruction *I4 = new VPInstruction(4, {}); 109 VPInstruction *I5 = new VPInstruction(5, {}); 110 VPBasicBlock VPBB2; 111 VPBB2.appendRecipe(I4); 112 VPBB2.appendRecipe(I5); 113 114 I3->moveBefore(VPBB2, I4->getIterator()); 115 116 CHECK_ITERATOR(VPBB1, I2, I1); 117 CHECK_ITERATOR(VPBB2, I3, I4, I5); 118 EXPECT_EQ(I3->getParent(), I4->getParent()); 119 120 VPBasicBlock VPBB3; 121 122 I4->moveBefore(VPBB3, VPBB3.end()); 123 124 CHECK_ITERATOR(VPBB1, I2, I1); 125 CHECK_ITERATOR(VPBB2, I3, I5); 126 CHECK_ITERATOR(VPBB3, I4); 127 EXPECT_EQ(&VPBB3, I4->getParent()); 128 } 129 130 TEST(VPInstructionTest, setOperand) { 131 VPValue *VPV1 = new VPValue(); 132 VPValue *VPV2 = new VPValue(); 133 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2}); 134 EXPECT_EQ(1u, VPV1->getNumUsers()); 135 EXPECT_EQ(I1, *VPV1->user_begin()); 136 EXPECT_EQ(1u, VPV2->getNumUsers()); 137 EXPECT_EQ(I1, *VPV2->user_begin()); 138 139 // Replace operand 0 (VPV1) with VPV3. 140 VPValue *VPV3 = new VPValue(); 141 I1->setOperand(0, VPV3); 142 EXPECT_EQ(0u, VPV1->getNumUsers()); 143 EXPECT_EQ(1u, VPV2->getNumUsers()); 144 EXPECT_EQ(I1, *VPV2->user_begin()); 145 EXPECT_EQ(1u, VPV3->getNumUsers()); 146 EXPECT_EQ(I1, *VPV3->user_begin()); 147 148 // Replace operand 1 (VPV2) with VPV3. 149 I1->setOperand(1, VPV3); 150 EXPECT_EQ(0u, VPV1->getNumUsers()); 151 EXPECT_EQ(0u, VPV2->getNumUsers()); 152 EXPECT_EQ(2u, VPV3->getNumUsers()); 153 EXPECT_EQ(I1, *VPV3->user_begin()); 154 EXPECT_EQ(I1, *std::next(VPV3->user_begin())); 155 156 // Replace operand 0 (VPV3) with VPV4. 157 VPValue *VPV4 = new VPValue(); 158 I1->setOperand(0, VPV4); 159 EXPECT_EQ(1u, VPV3->getNumUsers()); 160 EXPECT_EQ(I1, *VPV3->user_begin()); 161 EXPECT_EQ(I1, *VPV4->user_begin()); 162 163 // Replace operand 1 (VPV3) with VPV4. 164 I1->setOperand(1, VPV4); 165 EXPECT_EQ(0u, VPV3->getNumUsers()); 166 EXPECT_EQ(I1, *VPV4->user_begin()); 167 EXPECT_EQ(I1, *std::next(VPV4->user_begin())); 168 169 delete I1; 170 delete VPV1; 171 delete VPV2; 172 delete VPV3; 173 delete VPV4; 174 } 175 176 TEST(VPInstructionTest, replaceAllUsesWith) { 177 VPValue *VPV1 = new VPValue(); 178 VPValue *VPV2 = new VPValue(); 179 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2}); 180 181 // Replace all uses of VPV1 with VPV3. 182 VPValue *VPV3 = new VPValue(); 183 VPV1->replaceAllUsesWith(VPV3); 184 EXPECT_EQ(VPV3, I1->getOperand(0)); 185 EXPECT_EQ(VPV2, I1->getOperand(1)); 186 EXPECT_EQ(0u, VPV1->getNumUsers()); 187 EXPECT_EQ(1u, VPV2->getNumUsers()); 188 EXPECT_EQ(I1, *VPV2->user_begin()); 189 EXPECT_EQ(1u, VPV3->getNumUsers()); 190 EXPECT_EQ(I1, *VPV3->user_begin()); 191 192 // Replace all uses of VPV2 with VPV3. 193 VPV2->replaceAllUsesWith(VPV3); 194 EXPECT_EQ(VPV3, I1->getOperand(0)); 195 EXPECT_EQ(VPV3, I1->getOperand(1)); 196 EXPECT_EQ(0u, VPV1->getNumUsers()); 197 EXPECT_EQ(0u, VPV2->getNumUsers()); 198 EXPECT_EQ(2u, VPV3->getNumUsers()); 199 EXPECT_EQ(I1, *VPV3->user_begin()); 200 201 // Replace all uses of VPV3 with VPV1. 202 VPV3->replaceAllUsesWith(VPV1); 203 EXPECT_EQ(VPV1, I1->getOperand(0)); 204 EXPECT_EQ(VPV1, I1->getOperand(1)); 205 EXPECT_EQ(2u, VPV1->getNumUsers()); 206 EXPECT_EQ(I1, *VPV1->user_begin()); 207 EXPECT_EQ(0u, VPV2->getNumUsers()); 208 EXPECT_EQ(0u, VPV3->getNumUsers()); 209 210 VPInstruction *I2 = new VPInstruction(0, {VPV1, VPV2}); 211 EXPECT_EQ(3u, VPV1->getNumUsers()); 212 VPV1->replaceAllUsesWith(VPV3); 213 EXPECT_EQ(3u, VPV3->getNumUsers()); 214 215 delete I1; 216 delete I2; 217 delete VPV1; 218 delete VPV2; 219 delete VPV3; 220 } 221 222 TEST(VPInstructionTest, releaseOperandsAtDeletion) { 223 VPValue *VPV1 = new VPValue(); 224 VPValue *VPV2 = new VPValue(); 225 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2}); 226 227 EXPECT_EQ(1u, VPV1->getNumUsers()); 228 EXPECT_EQ(I1, *VPV1->user_begin()); 229 EXPECT_EQ(1u, VPV2->getNumUsers()); 230 EXPECT_EQ(I1, *VPV2->user_begin()); 231 232 delete I1; 233 234 EXPECT_EQ(0u, VPV1->getNumUsers()); 235 EXPECT_EQ(0u, VPV2->getNumUsers()); 236 237 delete VPV1; 238 delete VPV2; 239 } 240 TEST(VPBasicBlockTest, getPlan) { 241 LLVMContext C; 242 auto *ScalarHeader = BasicBlock::Create(C, ""); 243 { 244 VPBasicBlock *VPPH = new VPBasicBlock("ph"); 245 VPBasicBlock *VPBB1 = new VPBasicBlock(); 246 VPBasicBlock *VPBB2 = new VPBasicBlock(); 247 VPBasicBlock *VPBB3 = new VPBasicBlock(); 248 VPBasicBlock *VPBB4 = new VPBasicBlock(); 249 250 // VPBB1 251 // / \ 252 // VPBB2 VPBB3 253 // \ / 254 // VPBB4 255 VPBlockUtils::connectBlocks(VPBB1, VPBB2); 256 VPBlockUtils::connectBlocks(VPBB1, VPBB3); 257 VPBlockUtils::connectBlocks(VPBB2, VPBB4); 258 VPBlockUtils::connectBlocks(VPBB3, VPBB4); 259 260 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 261 VPBlockUtils::connectBlocks(VPBB4, ScalarHeaderVPBB); 262 VPBlockUtils::connectBlocks(VPPH, VPBB1); 263 VPlan Plan(VPPH, ScalarHeaderVPBB); 264 265 EXPECT_EQ(&Plan, VPBB1->getPlan()); 266 EXPECT_EQ(&Plan, VPBB2->getPlan()); 267 EXPECT_EQ(&Plan, VPBB3->getPlan()); 268 EXPECT_EQ(&Plan, VPBB4->getPlan()); 269 } 270 271 { 272 VPBasicBlock *VPPH = new VPBasicBlock("ph"); 273 // VPBasicBlock is the entry into the VPlan, followed by a region. 274 VPBasicBlock *R1BB1 = new VPBasicBlock(); 275 VPBasicBlock *R1BB2 = new VPBasicBlock(); 276 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1"); 277 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 278 279 VPBasicBlock *VPBB1 = new VPBasicBlock(); 280 VPBlockUtils::connectBlocks(VPBB1, R1); 281 282 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 283 VPBlockUtils::connectBlocks(R1, ScalarHeaderVPBB); 284 VPBlockUtils::connectBlocks(VPPH, VPBB1); 285 VPlan Plan(VPPH, ScalarHeaderVPBB); 286 287 EXPECT_EQ(&Plan, VPBB1->getPlan()); 288 EXPECT_EQ(&Plan, R1->getPlan()); 289 EXPECT_EQ(&Plan, R1BB1->getPlan()); 290 EXPECT_EQ(&Plan, R1BB2->getPlan()); 291 } 292 293 { 294 VPBasicBlock *VPPH = new VPBasicBlock("ph"); 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 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 315 VPBlockUtils::connectBlocks(R2, ScalarHeaderVPBB); 316 VPBlockUtils::connectBlocks(VPPH, VPBB1); 317 VPlan Plan(VPPH, ScalarHeaderVPBB); 318 319 EXPECT_EQ(&Plan, VPBB1->getPlan()); 320 EXPECT_EQ(&Plan, R1->getPlan()); 321 EXPECT_EQ(&Plan, R1BB1->getPlan()); 322 EXPECT_EQ(&Plan, R1BB2->getPlan()); 323 EXPECT_EQ(&Plan, R2->getPlan()); 324 EXPECT_EQ(&Plan, R2BB1->getPlan()); 325 EXPECT_EQ(&Plan, R2BB2->getPlan()); 326 EXPECT_EQ(&Plan, VPBB2->getPlan()); 327 } 328 delete ScalarHeader; 329 } 330 331 TEST(VPBasicBlockTest, TraversingIteratorTest) { 332 LLVMContext C; 333 auto *ScalarHeader = BasicBlock::Create(C, ""); 334 { 335 // VPBasicBlocks only 336 // VPBB1 337 // / \ 338 // VPBB2 VPBB3 339 // \ / 340 // VPBB4 341 // 342 VPBasicBlock *VPPH = new VPBasicBlock("ph"); 343 VPBasicBlock *VPBB1 = new VPBasicBlock(); 344 VPBasicBlock *VPBB2 = new VPBasicBlock(); 345 VPBasicBlock *VPBB3 = new VPBasicBlock(); 346 VPBasicBlock *VPBB4 = new VPBasicBlock(); 347 348 VPBlockUtils::connectBlocks(VPBB1, VPBB2); 349 VPBlockUtils::connectBlocks(VPBB1, VPBB3); 350 VPBlockUtils::connectBlocks(VPBB2, VPBB4); 351 VPBlockUtils::connectBlocks(VPBB3, VPBB4); 352 353 VPBlockDeepTraversalWrapper<const VPBlockBase *> Start(VPBB1); 354 SmallVector<const VPBlockBase *> FromIterator(depth_first(Start)); 355 EXPECT_EQ(4u, FromIterator.size()); 356 EXPECT_EQ(VPBB1, FromIterator[0]); 357 EXPECT_EQ(VPBB2, FromIterator[1]); 358 359 // Use Plan to properly clean up created blocks. 360 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 361 VPBlockUtils::connectBlocks(VPBB4, ScalarHeaderVPBB); 362 VPBlockUtils::connectBlocks(VPPH, VPBB1); 363 VPlan Plan(VPPH, ScalarHeaderVPBB); 364 } 365 366 { 367 // 2 consecutive regions. 368 // VPBB0 369 // | 370 // R1 { 371 // \ 372 // R1BB1 373 // / \ |--| 374 // R1BB2 R1BB3 -| 375 // \ / 376 // R1BB4 377 // } 378 // | 379 // R2 { 380 // \ 381 // R2BB1 382 // | 383 // R2BB2 384 // 385 VPBasicBlock *VPPH = new VPBasicBlock("ph"); 386 VPBasicBlock *VPBB0 = new VPBasicBlock("VPBB0"); 387 VPBasicBlock *R1BB1 = new VPBasicBlock(); 388 VPBasicBlock *R1BB2 = new VPBasicBlock(); 389 VPBasicBlock *R1BB3 = new VPBasicBlock(); 390 VPBasicBlock *R1BB4 = new VPBasicBlock(); 391 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB4, "R1"); 392 R1BB2->setParent(R1); 393 R1BB3->setParent(R1); 394 VPBlockUtils::connectBlocks(VPBB0, R1); 395 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 396 VPBlockUtils::connectBlocks(R1BB1, R1BB3); 397 VPBlockUtils::connectBlocks(R1BB2, R1BB4); 398 VPBlockUtils::connectBlocks(R1BB3, R1BB4); 399 // Cycle. 400 VPBlockUtils::connectBlocks(R1BB3, R1BB3); 401 402 VPBasicBlock *R2BB1 = new VPBasicBlock(); 403 VPBasicBlock *R2BB2 = new VPBasicBlock(); 404 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2"); 405 VPBlockUtils::connectBlocks(R2BB1, R2BB2); 406 VPBlockUtils::connectBlocks(R1, R2); 407 408 // Successors of R1. 409 SmallVector<const VPBlockBase *> FromIterator( 410 VPAllSuccessorsIterator<VPBlockBase *>(R1), 411 VPAllSuccessorsIterator<VPBlockBase *>::end(R1)); 412 EXPECT_EQ(1u, FromIterator.size()); 413 EXPECT_EQ(R1BB1, FromIterator[0]); 414 415 // Depth-first. 416 VPBlockDeepTraversalWrapper<VPBlockBase *> Start(R1); 417 FromIterator.clear(); 418 copy(df_begin(Start), df_end(Start), std::back_inserter(FromIterator)); 419 EXPECT_EQ(8u, FromIterator.size()); 420 EXPECT_EQ(R1, FromIterator[0]); 421 EXPECT_EQ(R1BB1, FromIterator[1]); 422 EXPECT_EQ(R1BB2, FromIterator[2]); 423 EXPECT_EQ(R1BB4, FromIterator[3]); 424 EXPECT_EQ(R2, FromIterator[4]); 425 EXPECT_EQ(R2BB1, FromIterator[5]); 426 EXPECT_EQ(R2BB2, FromIterator[6]); 427 EXPECT_EQ(R1BB3, FromIterator[7]); 428 429 // const VPBasicBlocks only. 430 FromIterator.clear(); 431 copy(VPBlockUtils::blocksOnly<const VPBasicBlock>(depth_first(Start)), 432 std::back_inserter(FromIterator)); 433 EXPECT_EQ(6u, FromIterator.size()); 434 EXPECT_EQ(R1BB1, FromIterator[0]); 435 EXPECT_EQ(R1BB2, FromIterator[1]); 436 EXPECT_EQ(R1BB4, FromIterator[2]); 437 EXPECT_EQ(R2BB1, FromIterator[3]); 438 EXPECT_EQ(R2BB2, FromIterator[4]); 439 EXPECT_EQ(R1BB3, FromIterator[5]); 440 441 // VPRegionBlocks only. 442 SmallVector<VPRegionBlock *> FromIteratorVPRegion( 443 VPBlockUtils::blocksOnly<VPRegionBlock>(depth_first(Start))); 444 EXPECT_EQ(2u, FromIteratorVPRegion.size()); 445 EXPECT_EQ(R1, FromIteratorVPRegion[0]); 446 EXPECT_EQ(R2, FromIteratorVPRegion[1]); 447 448 // Post-order. 449 FromIterator.clear(); 450 copy(post_order(Start), std::back_inserter(FromIterator)); 451 EXPECT_EQ(8u, FromIterator.size()); 452 EXPECT_EQ(R2BB2, FromIterator[0]); 453 EXPECT_EQ(R2BB1, FromIterator[1]); 454 EXPECT_EQ(R2, FromIterator[2]); 455 EXPECT_EQ(R1BB4, FromIterator[3]); 456 EXPECT_EQ(R1BB2, FromIterator[4]); 457 EXPECT_EQ(R1BB3, FromIterator[5]); 458 EXPECT_EQ(R1BB1, FromIterator[6]); 459 EXPECT_EQ(R1, FromIterator[7]); 460 461 // Use Plan to properly clean up created blocks. 462 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 463 VPBlockUtils::connectBlocks(R2, ScalarHeaderVPBB); 464 VPBlockUtils::connectBlocks(VPPH, VPBB0); 465 VPlan Plan(VPPH, ScalarHeaderVPBB); 466 } 467 468 { 469 // 2 nested regions. 470 // VPBB1 471 // | 472 // R1 { 473 // R1BB1 474 // / \ 475 // R2 { | 476 // \ | 477 // R2BB1 | 478 // | \ R1BB2 479 // R2BB2-| | 480 // \ | 481 // R2BB3 | 482 // } / 483 // \ / 484 // R1BB3 485 // } 486 // | 487 // VPBB2 488 // 489 VPBasicBlock *VPPH = new VPBasicBlock("ph"); 490 VPBasicBlock *R1BB1 = new VPBasicBlock("R1BB1"); 491 VPBasicBlock *R1BB2 = new VPBasicBlock("R1BB2"); 492 VPBasicBlock *R1BB3 = new VPBasicBlock("R1BB3"); 493 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB3, "R1"); 494 495 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1"); 496 VPBasicBlock *R2BB2 = new VPBasicBlock("R2BB2"); 497 VPBasicBlock *R2BB3 = new VPBasicBlock("R2BB3"); 498 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB3, "R2"); 499 R2BB2->setParent(R2); 500 VPBlockUtils::connectBlocks(R2BB1, R2BB2); 501 VPBlockUtils::connectBlocks(R2BB2, R2BB1); 502 VPBlockUtils::connectBlocks(R2BB2, R2BB3); 503 504 R2->setParent(R1); 505 VPBlockUtils::connectBlocks(R1BB1, R2); 506 R1BB2->setParent(R1); 507 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 508 VPBlockUtils::connectBlocks(R1BB2, R1BB3); 509 VPBlockUtils::connectBlocks(R2, R1BB3); 510 511 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1"); 512 VPBlockUtils::connectBlocks(VPBB1, R1); 513 VPBasicBlock *VPBB2 = new VPBasicBlock("VPBB2"); 514 VPBlockUtils::connectBlocks(R1, VPBB2); 515 516 // Depth-first. 517 VPBlockDeepTraversalWrapper<VPBlockBase *> Start(VPBB1); 518 SmallVector<VPBlockBase *> FromIterator(depth_first(Start)); 519 EXPECT_EQ(10u, FromIterator.size()); 520 EXPECT_EQ(VPBB1, FromIterator[0]); 521 EXPECT_EQ(R1, FromIterator[1]); 522 EXPECT_EQ(R1BB1, FromIterator[2]); 523 EXPECT_EQ(R2, FromIterator[3]); 524 EXPECT_EQ(R2BB1, FromIterator[4]); 525 EXPECT_EQ(R2BB2, FromIterator[5]); 526 EXPECT_EQ(R2BB3, FromIterator[6]); 527 EXPECT_EQ(R1BB3, FromIterator[7]); 528 EXPECT_EQ(VPBB2, FromIterator[8]); 529 EXPECT_EQ(R1BB2, FromIterator[9]); 530 531 // Post-order. 532 FromIterator.clear(); 533 FromIterator.append(po_begin(Start), po_end(Start)); 534 EXPECT_EQ(10u, FromIterator.size()); 535 EXPECT_EQ(VPBB2, FromIterator[0]); 536 EXPECT_EQ(R1BB3, FromIterator[1]); 537 EXPECT_EQ(R2BB3, FromIterator[2]); 538 EXPECT_EQ(R2BB2, FromIterator[3]); 539 EXPECT_EQ(R2BB1, FromIterator[4]); 540 EXPECT_EQ(R2, FromIterator[5]); 541 EXPECT_EQ(R1BB2, FromIterator[6]); 542 EXPECT_EQ(R1BB1, FromIterator[7]); 543 EXPECT_EQ(R1, FromIterator[8]); 544 EXPECT_EQ(VPBB1, FromIterator[9]); 545 546 // Use Plan to properly clean up created blocks. 547 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 548 VPBlockUtils::connectBlocks(VPBB2, ScalarHeaderVPBB); 549 VPBlockUtils::connectBlocks(VPPH, VPBB1); 550 VPlan Plan(VPPH, ScalarHeaderVPBB); 551 } 552 553 { 554 // VPBB1 555 // | 556 // R1 { 557 // \ 558 // R2 { 559 // R2BB1 560 // | 561 // R2BB2 562 // } 563 // 564 VPBasicBlock *VPPH = new VPBasicBlock("ph"); 565 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1"); 566 VPBasicBlock *R2BB2 = new VPBasicBlock("R2BB2"); 567 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2"); 568 VPBlockUtils::connectBlocks(R2BB1, R2BB2); 569 570 VPRegionBlock *R1 = new VPRegionBlock(R2, R2, "R1"); 571 R2->setParent(R1); 572 573 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1"); 574 VPBlockUtils::connectBlocks(VPBB1, R1); 575 576 // Depth-first. 577 VPBlockDeepTraversalWrapper<VPBlockBase *> Start(VPBB1); 578 SmallVector<VPBlockBase *> FromIterator(depth_first(Start)); 579 EXPECT_EQ(5u, FromIterator.size()); 580 EXPECT_EQ(VPBB1, FromIterator[0]); 581 EXPECT_EQ(R1, FromIterator[1]); 582 EXPECT_EQ(R2, FromIterator[2]); 583 EXPECT_EQ(R2BB1, FromIterator[3]); 584 EXPECT_EQ(R2BB2, FromIterator[4]); 585 586 // Post-order. 587 FromIterator.clear(); 588 FromIterator.append(po_begin(Start), po_end(Start)); 589 EXPECT_EQ(5u, FromIterator.size()); 590 EXPECT_EQ(R2BB2, FromIterator[0]); 591 EXPECT_EQ(R2BB1, FromIterator[1]); 592 EXPECT_EQ(R2, FromIterator[2]); 593 EXPECT_EQ(R1, FromIterator[3]); 594 EXPECT_EQ(VPBB1, FromIterator[4]); 595 596 // Use Plan to properly clean up created blocks. 597 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 598 VPBlockUtils::connectBlocks(R1, ScalarHeaderVPBB); 599 VPBlockUtils::connectBlocks(VPPH, VPBB1); 600 VPlan Plan(VPPH, ScalarHeaderVPBB); 601 } 602 603 { 604 // Nested regions with both R3 and R2 being exit nodes without successors. 605 // The successors of R1 should be used. 606 // 607 // VPBB1 608 // | 609 // R1 { 610 // \ 611 // R2 { 612 // \ 613 // R2BB1 614 // | 615 // R3 { 616 // R3BB1 617 // } 618 // } 619 // | 620 // VPBB2 621 // 622 VPBasicBlock *VPPH = new VPBasicBlock("ph"); 623 VPBasicBlock *R3BB1 = new VPBasicBlock("R3BB1"); 624 VPRegionBlock *R3 = new VPRegionBlock(R3BB1, R3BB1, "R3"); 625 626 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1"); 627 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R3, "R2"); 628 R3->setParent(R2); 629 VPBlockUtils::connectBlocks(R2BB1, R3); 630 631 VPRegionBlock *R1 = new VPRegionBlock(R2, R2, "R1"); 632 R2->setParent(R1); 633 634 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1"); 635 VPBasicBlock *VPBB2 = new VPBasicBlock("VPBB2"); 636 VPBlockUtils::connectBlocks(VPBB1, R1); 637 VPBlockUtils::connectBlocks(R1, VPBB2); 638 639 // Depth-first. 640 VPBlockDeepTraversalWrapper<VPBlockBase *> Start(VPBB1); 641 SmallVector<VPBlockBase *> FromIterator(depth_first(Start)); 642 EXPECT_EQ(7u, FromIterator.size()); 643 EXPECT_EQ(VPBB1, FromIterator[0]); 644 EXPECT_EQ(R1, FromIterator[1]); 645 EXPECT_EQ(R2, FromIterator[2]); 646 EXPECT_EQ(R2BB1, FromIterator[3]); 647 EXPECT_EQ(R3, FromIterator[4]); 648 EXPECT_EQ(R3BB1, FromIterator[5]); 649 EXPECT_EQ(VPBB2, FromIterator[6]); 650 651 SmallVector<VPBlockBase *> FromIteratorVPBB; 652 copy(VPBlockUtils::blocksOnly<VPBasicBlock>(depth_first(Start)), 653 std::back_inserter(FromIteratorVPBB)); 654 EXPECT_EQ(VPBB1, FromIteratorVPBB[0]); 655 EXPECT_EQ(R2BB1, FromIteratorVPBB[1]); 656 EXPECT_EQ(R3BB1, FromIteratorVPBB[2]); 657 EXPECT_EQ(VPBB2, FromIteratorVPBB[3]); 658 659 // Post-order. 660 FromIterator.clear(); 661 copy(post_order(Start), std::back_inserter(FromIterator)); 662 EXPECT_EQ(7u, FromIterator.size()); 663 EXPECT_EQ(VPBB2, FromIterator[0]); 664 EXPECT_EQ(R3BB1, FromIterator[1]); 665 EXPECT_EQ(R3, FromIterator[2]); 666 EXPECT_EQ(R2BB1, FromIterator[3]); 667 EXPECT_EQ(R2, FromIterator[4]); 668 EXPECT_EQ(R1, FromIterator[5]); 669 EXPECT_EQ(VPBB1, FromIterator[6]); 670 671 // Post-order, const VPRegionBlocks only. 672 VPBlockDeepTraversalWrapper<const VPBlockBase *> StartConst(VPBB1); 673 SmallVector<const VPRegionBlock *> FromIteratorVPRegion( 674 VPBlockUtils::blocksOnly<const VPRegionBlock>(post_order(StartConst))); 675 EXPECT_EQ(3u, FromIteratorVPRegion.size()); 676 EXPECT_EQ(R3, FromIteratorVPRegion[0]); 677 EXPECT_EQ(R2, FromIteratorVPRegion[1]); 678 EXPECT_EQ(R1, FromIteratorVPRegion[2]); 679 680 // Post-order, VPBasicBlocks only. 681 FromIterator.clear(); 682 copy(VPBlockUtils::blocksOnly<VPBasicBlock>(post_order(Start)), 683 std::back_inserter(FromIterator)); 684 EXPECT_EQ(FromIterator.size(), 4u); 685 EXPECT_EQ(VPBB2, FromIterator[0]); 686 EXPECT_EQ(R3BB1, FromIterator[1]); 687 EXPECT_EQ(R2BB1, FromIterator[2]); 688 EXPECT_EQ(VPBB1, FromIterator[3]); 689 690 // Use Plan to properly clean up created blocks. 691 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 692 VPBlockUtils::connectBlocks(VPBB2, ScalarHeaderVPBB); 693 VPBlockUtils::connectBlocks(VPPH, VPBB1); 694 VPlan Plan(VPPH, ScalarHeaderVPBB); 695 } 696 delete ScalarHeader; 697 } 698 699 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 700 TEST(VPBasicBlockTest, print) { 701 VPInstruction *TC = new VPInstruction(Instruction::Add, {}); 702 VPBasicBlock *VPBB0 = new VPBasicBlock("preheader"); 703 VPBB0->appendRecipe(TC); 704 705 VPInstruction *I1 = new VPInstruction(Instruction::Add, {}); 706 VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1}); 707 VPInstruction *I3 = new VPInstruction(Instruction::Br, {I1, I2}); 708 709 VPBasicBlock *VPBB1 = new VPBasicBlock(); 710 VPBB1->appendRecipe(I1); 711 VPBB1->appendRecipe(I2); 712 VPBB1->appendRecipe(I3); 713 VPBB1->setName("bb1"); 714 715 VPInstruction *I4 = new VPInstruction(Instruction::Mul, {I2, I1}); 716 VPInstruction *I5 = new VPInstruction(Instruction::Ret, {I4}); 717 VPBasicBlock *VPBB2 = new VPBasicBlock(); 718 VPBB2->appendRecipe(I4); 719 VPBB2->appendRecipe(I5); 720 VPBB2->setName("bb2"); 721 722 VPBlockUtils::connectBlocks(VPBB1, VPBB2); 723 724 // Check printing an instruction without associated VPlan. 725 { 726 std::string I3Dump; 727 raw_string_ostream OS(I3Dump); 728 VPSlotTracker SlotTracker; 729 I3->print(OS, "", SlotTracker); 730 EXPECT_EQ("EMIT br <badref>, <badref>", I3Dump); 731 } 732 733 LLVMContext C; 734 auto *ScalarHeader = BasicBlock::Create(C, "scalar.header"); 735 auto * ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 736 VPBlockUtils::connectBlocks(VPBB2, ScalarHeaderVPBB); 737 VPBlockUtils::connectBlocks(VPBB0, VPBB1); 738 VPlan Plan(VPBB0, TC, ScalarHeaderVPBB); 739 std::string FullDump; 740 raw_string_ostream OS(FullDump); 741 Plan.printDOT(OS); 742 743 const char *ExpectedStr = R"(digraph VPlan { 744 graph [labelloc=t, fontsize=30; label="Vectorization Plan\n for UF\>=1\nvp\<%1\> = original trip-count\n"] 745 node [shape=rect, fontname=Courier, fontsize=30] 746 edge [fontname=Courier, fontsize=30] 747 compound=true 748 N0 [label = 749 "preheader:\l" + 750 " EMIT vp\<%1\> = add\l" + 751 "Successor(s): bb1\l" 752 ] 753 N0 -> N1 [ label=""] 754 N1 [label = 755 "bb1:\l" + 756 " EMIT vp\<%2\> = add\l" + 757 " EMIT vp\<%3\> = sub vp\<%2\>\l" + 758 " EMIT br vp\<%2\>, vp\<%3\>\l" + 759 "Successor(s): bb2\l" 760 ] 761 N1 -> N2 [ label=""] 762 N2 [label = 763 "bb2:\l" + 764 " EMIT vp\<%5\> = mul vp\<%3\>, vp\<%2\>\l" + 765 " EMIT ret vp\<%5\>\l" + 766 "Successor(s): ir-bb\<scalar.header\>\l" 767 ] 768 N2 -> N3 [ label=""] 769 N3 [label = 770 "ir-bb\<scalar.header\>:\l" + 771 "No successors\l" 772 ] 773 } 774 )"; 775 EXPECT_EQ(ExpectedStr, FullDump); 776 777 const char *ExpectedBlock1Str = R"(bb1: 778 EMIT vp<%2> = add 779 EMIT vp<%3> = sub vp<%2> 780 EMIT br vp<%2>, vp<%3> 781 Successor(s): bb2 782 )"; 783 std::string Block1Dump; 784 raw_string_ostream OS1(Block1Dump); 785 VPBB1->print(OS1); 786 EXPECT_EQ(ExpectedBlock1Str, Block1Dump); 787 788 // Ensure that numbering is good when dumping the second block in isolation. 789 const char *ExpectedBlock2Str = R"(bb2: 790 EMIT vp<%5> = mul vp<%3>, vp<%2> 791 EMIT ret vp<%5> 792 Successor(s): ir-bb<scalar.header> 793 )"; 794 std::string Block2Dump; 795 raw_string_ostream OS2(Block2Dump); 796 VPBB2->print(OS2); 797 EXPECT_EQ(ExpectedBlock2Str, Block2Dump); 798 799 { 800 std::string I3Dump; 801 raw_string_ostream OS(I3Dump); 802 VPSlotTracker SlotTracker(&Plan); 803 I3->print(OS, "", SlotTracker); 804 EXPECT_EQ("EMIT br vp<%2>, vp<%3>", I3Dump); 805 } 806 807 { 808 std::string I4Dump; 809 raw_string_ostream OS(I4Dump); 810 OS << *I4; 811 EXPECT_EQ("EMIT vp<%5> = mul vp<%3>, vp<%2>", I4Dump); 812 } 813 delete ScalarHeader; 814 } 815 816 TEST(VPBasicBlockTest, printPlanWithVFsAndUFs) { 817 818 VPInstruction *TC = new VPInstruction(Instruction::Sub, {}); 819 VPBasicBlock *VPBB0 = new VPBasicBlock("preheader"); 820 VPBB0->appendRecipe(TC); 821 822 VPInstruction *I1 = new VPInstruction(Instruction::Add, {}); 823 VPBasicBlock *VPBB1 = new VPBasicBlock(); 824 VPBB1->appendRecipe(I1); 825 VPBB1->setName("bb1"); 826 827 LLVMContext C; 828 auto *ScalarHeader = BasicBlock::Create(C, ""); 829 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 830 VPBlockUtils::connectBlocks(VPBB1, ScalarHeaderVPBB); 831 VPBlockUtils::connectBlocks(VPBB0, VPBB1); 832 VPlan Plan(VPBB0, TC, ScalarHeaderVPBB); 833 Plan.setName("TestPlan"); 834 Plan.addVF(ElementCount::getFixed(4)); 835 836 { 837 std::string FullDump; 838 raw_string_ostream OS(FullDump); 839 Plan.print(OS); 840 841 const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4},UF>=1' { 842 vp<%1> = original trip-count 843 844 preheader: 845 EMIT vp<%1> = sub 846 Successor(s): bb1 847 848 bb1: 849 EMIT vp<%2> = add 850 Successor(s): ir-bb<> 851 852 ir-bb<>: 853 No successors 854 } 855 )"; 856 EXPECT_EQ(ExpectedStr, FullDump); 857 } 858 859 { 860 Plan.addVF(ElementCount::getScalable(8)); 861 std::string FullDump; 862 raw_string_ostream OS(FullDump); 863 Plan.print(OS); 864 865 const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4,vscale x 8},UF>=1' { 866 vp<%1> = original trip-count 867 868 preheader: 869 EMIT vp<%1> = sub 870 Successor(s): bb1 871 872 bb1: 873 EMIT vp<%2> = add 874 Successor(s): ir-bb<> 875 876 ir-bb<>: 877 No successors 878 } 879 )"; 880 EXPECT_EQ(ExpectedStr, FullDump); 881 } 882 883 { 884 Plan.setUF(4); 885 std::string FullDump; 886 raw_string_ostream OS(FullDump); 887 Plan.print(OS); 888 889 const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4,vscale x 8},UF={4}' { 890 vp<%1> = original trip-count 891 892 preheader: 893 EMIT vp<%1> = sub 894 Successor(s): bb1 895 896 bb1: 897 EMIT vp<%2> = add 898 Successor(s): ir-bb<> 899 900 ir-bb<>: 901 No successors 902 } 903 )"; 904 EXPECT_EQ(ExpectedStr, FullDump); 905 } 906 delete ScalarHeader; 907 } 908 #endif 909 910 TEST(VPRecipeTest, CastVPInstructionToVPUser) { 911 VPValue Op1; 912 VPValue Op2; 913 VPInstruction Recipe(Instruction::Add, {&Op1, &Op2}); 914 EXPECT_TRUE(isa<VPUser>(&Recipe)); 915 VPRecipeBase *BaseR = &Recipe; 916 EXPECT_TRUE(isa<VPUser>(BaseR)); 917 EXPECT_EQ(&Recipe, BaseR); 918 } 919 920 TEST(VPRecipeTest, CastVPWidenRecipeToVPUser) { 921 LLVMContext C; 922 923 IntegerType *Int32 = IntegerType::get(C, 32); 924 auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32), 925 PoisonValue::get(Int32)); 926 VPValue Op1; 927 VPValue Op2; 928 SmallVector<VPValue *, 2> Args; 929 Args.push_back(&Op1); 930 Args.push_back(&Op1); 931 VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end())); 932 EXPECT_TRUE(isa<VPUser>(&WidenR)); 933 VPRecipeBase *WidenRBase = &WidenR; 934 EXPECT_TRUE(isa<VPUser>(WidenRBase)); 935 EXPECT_EQ(&WidenR, WidenRBase); 936 delete AI; 937 } 938 939 TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) { 940 LLVMContext C; 941 942 IntegerType *Int32 = IntegerType::get(C, 32); 943 FunctionType *FTy = FunctionType::get(Int32, false); 944 Function *Fn = Function::Create(FTy, GlobalValue::ExternalLinkage, 0); 945 auto *Call = CallInst::Create(FTy, Fn); 946 VPValue Op1; 947 VPValue Op2; 948 VPValue CalledFn(Call->getCalledFunction()); 949 SmallVector<VPValue *, 2> Args; 950 Args.push_back(&Op1); 951 Args.push_back(&Op2); 952 Args.push_back(&CalledFn); 953 VPWidenCallRecipe Recipe(Call, Fn, Args); 954 EXPECT_TRUE(isa<VPUser>(&Recipe)); 955 VPRecipeBase *BaseR = &Recipe; 956 EXPECT_TRUE(isa<VPUser>(BaseR)); 957 EXPECT_EQ(&Recipe, BaseR); 958 959 VPValue *VPV = &Recipe; 960 EXPECT_TRUE(VPV->getDefiningRecipe()); 961 EXPECT_EQ(&Recipe, VPV->getDefiningRecipe()); 962 963 delete Call; 964 delete Fn; 965 } 966 967 TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUserAndVPDef) { 968 LLVMContext C; 969 970 IntegerType *Int1 = IntegerType::get(C, 1); 971 IntegerType *Int32 = IntegerType::get(C, 32); 972 auto *SelectI = SelectInst::Create( 973 PoisonValue::get(Int1), PoisonValue::get(Int32), PoisonValue::get(Int32)); 974 VPValue Op1; 975 VPValue Op2; 976 VPValue Op3; 977 SmallVector<VPValue *, 4> Args; 978 Args.push_back(&Op1); 979 Args.push_back(&Op2); 980 Args.push_back(&Op3); 981 VPWidenSelectRecipe WidenSelectR(*SelectI, 982 make_range(Args.begin(), Args.end())); 983 EXPECT_TRUE(isa<VPUser>(&WidenSelectR)); 984 VPRecipeBase *BaseR = &WidenSelectR; 985 EXPECT_TRUE(isa<VPUser>(BaseR)); 986 EXPECT_EQ(&WidenSelectR, BaseR); 987 988 VPValue *VPV = &WidenSelectR; 989 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe())); 990 EXPECT_EQ(&WidenSelectR, VPV->getDefiningRecipe()); 991 992 delete SelectI; 993 } 994 995 TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUserAndVPDef) { 996 LLVMContext C; 997 998 IntegerType *Int32 = IntegerType::get(C, 32); 999 PointerType *Int32Ptr = PointerType::get(Int32, 0); 1000 auto *GEP = GetElementPtrInst::Create(Int32, PoisonValue::get(Int32Ptr), 1001 PoisonValue::get(Int32)); 1002 VPValue Op1; 1003 VPValue Op2; 1004 SmallVector<VPValue *, 4> Args; 1005 Args.push_back(&Op1); 1006 Args.push_back(&Op2); 1007 VPWidenGEPRecipe Recipe(GEP, make_range(Args.begin(), Args.end())); 1008 EXPECT_TRUE(isa<VPUser>(&Recipe)); 1009 VPRecipeBase *BaseR = &Recipe; 1010 EXPECT_TRUE(isa<VPUser>(BaseR)); 1011 EXPECT_EQ(&Recipe, BaseR); 1012 1013 VPValue *VPV = &Recipe; 1014 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe())); 1015 EXPECT_EQ(&Recipe, VPV->getDefiningRecipe()); 1016 1017 delete GEP; 1018 } 1019 1020 TEST(VPRecipeTest, CastVPBlendRecipeToVPUser) { 1021 LLVMContext C; 1022 1023 IntegerType *Int32 = IntegerType::get(C, 32); 1024 auto *Phi = PHINode::Create(Int32, 1); 1025 VPValue I1; 1026 VPValue I2; 1027 VPValue M2; 1028 SmallVector<VPValue *, 4> Args; 1029 Args.push_back(&I1); 1030 Args.push_back(&I2); 1031 Args.push_back(&M2); 1032 VPBlendRecipe Recipe(Phi, Args); 1033 EXPECT_TRUE(isa<VPUser>(&Recipe)); 1034 VPRecipeBase *BaseR = &Recipe; 1035 EXPECT_TRUE(isa<VPUser>(BaseR)); 1036 delete Phi; 1037 } 1038 1039 TEST(VPRecipeTest, CastVPInterleaveRecipeToVPUser) { 1040 LLVMContext C; 1041 1042 VPValue Addr; 1043 VPValue Mask; 1044 InterleaveGroup<Instruction> IG(4, false, Align(4)); 1045 VPInterleaveRecipe Recipe(&IG, &Addr, {}, &Mask, false); 1046 EXPECT_TRUE(isa<VPUser>(&Recipe)); 1047 VPRecipeBase *BaseR = &Recipe; 1048 EXPECT_TRUE(isa<VPUser>(BaseR)); 1049 EXPECT_EQ(&Recipe, BaseR); 1050 } 1051 1052 TEST(VPRecipeTest, CastVPReplicateRecipeToVPUser) { 1053 LLVMContext C; 1054 1055 VPValue Op1; 1056 VPValue Op2; 1057 SmallVector<VPValue *, 4> Args; 1058 Args.push_back(&Op1); 1059 Args.push_back(&Op2); 1060 1061 IntegerType *Int32 = IntegerType::get(C, 32); 1062 FunctionType *FTy = FunctionType::get(Int32, false); 1063 auto *Call = CallInst::Create(FTy, PoisonValue::get(FTy)); 1064 VPReplicateRecipe Recipe(Call, make_range(Args.begin(), Args.end()), true); 1065 EXPECT_TRUE(isa<VPUser>(&Recipe)); 1066 VPRecipeBase *BaseR = &Recipe; 1067 EXPECT_TRUE(isa<VPUser>(BaseR)); 1068 delete Call; 1069 } 1070 1071 TEST(VPRecipeTest, CastVPBranchOnMaskRecipeToVPUser) { 1072 LLVMContext C; 1073 1074 VPValue Mask; 1075 VPBranchOnMaskRecipe Recipe(&Mask); 1076 EXPECT_TRUE(isa<VPUser>(&Recipe)); 1077 VPRecipeBase *BaseR = &Recipe; 1078 EXPECT_TRUE(isa<VPUser>(BaseR)); 1079 EXPECT_EQ(&Recipe, BaseR); 1080 } 1081 1082 TEST(VPRecipeTest, CastVPWidenMemoryRecipeToVPUserAndVPDef) { 1083 LLVMContext C; 1084 1085 IntegerType *Int32 = IntegerType::get(C, 32); 1086 PointerType *Int32Ptr = PointerType::get(Int32, 0); 1087 auto *Load = 1088 new LoadInst(Int32, PoisonValue::get(Int32Ptr), "", false, Align(1)); 1089 VPValue Addr; 1090 VPValue Mask; 1091 VPWidenLoadRecipe Recipe(*Load, &Addr, &Mask, true, false, {}); 1092 EXPECT_TRUE(isa<VPUser>(&Recipe)); 1093 VPRecipeBase *BaseR = &Recipe; 1094 EXPECT_TRUE(isa<VPUser>(BaseR)); 1095 EXPECT_EQ(&Recipe, BaseR); 1096 1097 VPValue *VPV = Recipe.getVPSingleValue(); 1098 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe())); 1099 EXPECT_EQ(&Recipe, VPV->getDefiningRecipe()); 1100 1101 delete Load; 1102 } 1103 1104 TEST(VPRecipeTest, MayHaveSideEffectsAndMayReadWriteMemory) { 1105 LLVMContext C; 1106 IntegerType *Int1 = IntegerType::get(C, 1); 1107 IntegerType *Int32 = IntegerType::get(C, 32); 1108 PointerType *Int32Ptr = PointerType::get(Int32, 0); 1109 1110 { 1111 auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32), 1112 PoisonValue::get(Int32)); 1113 VPValue Op1; 1114 VPValue Op2; 1115 SmallVector<VPValue *, 2> Args; 1116 Args.push_back(&Op1); 1117 Args.push_back(&Op1); 1118 VPWidenRecipe Recipe(*AI, make_range(Args.begin(), Args.end())); 1119 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1120 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1121 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1122 EXPECT_FALSE(Recipe.mayReadOrWriteMemory()); 1123 delete AI; 1124 } 1125 1126 { 1127 auto *SelectI = 1128 SelectInst::Create(PoisonValue::get(Int1), PoisonValue::get(Int32), 1129 PoisonValue::get(Int32)); 1130 VPValue Op1; 1131 VPValue Op2; 1132 VPValue Op3; 1133 SmallVector<VPValue *, 4> Args; 1134 Args.push_back(&Op1); 1135 Args.push_back(&Op2); 1136 Args.push_back(&Op3); 1137 VPWidenSelectRecipe Recipe(*SelectI, make_range(Args.begin(), Args.end())); 1138 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1139 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1140 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1141 EXPECT_FALSE(Recipe.mayReadOrWriteMemory()); 1142 delete SelectI; 1143 } 1144 1145 { 1146 auto *GEP = GetElementPtrInst::Create(Int32, PoisonValue::get(Int32Ptr), 1147 PoisonValue::get(Int32)); 1148 VPValue Op1; 1149 VPValue Op2; 1150 SmallVector<VPValue *, 4> Args; 1151 Args.push_back(&Op1); 1152 Args.push_back(&Op2); 1153 VPWidenGEPRecipe Recipe(GEP, make_range(Args.begin(), Args.end())); 1154 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1155 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1156 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1157 EXPECT_FALSE(Recipe.mayReadOrWriteMemory()); 1158 delete GEP; 1159 } 1160 1161 { 1162 VPValue Mask; 1163 VPBranchOnMaskRecipe Recipe(&Mask); 1164 EXPECT_TRUE(Recipe.mayHaveSideEffects()); 1165 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1166 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1167 EXPECT_FALSE(Recipe.mayReadOrWriteMemory()); 1168 } 1169 1170 { 1171 VPValue ChainOp; 1172 VPValue VecOp; 1173 VPValue CondOp; 1174 VPReductionRecipe Recipe(RecurrenceDescriptor(), nullptr, &ChainOp, &CondOp, 1175 &VecOp, false); 1176 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1177 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1178 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1179 EXPECT_FALSE(Recipe.mayReadOrWriteMemory()); 1180 } 1181 1182 { 1183 VPValue ChainOp; 1184 VPValue VecOp; 1185 VPValue CondOp; 1186 VPReductionRecipe Recipe(RecurrenceDescriptor(), nullptr, &ChainOp, &CondOp, 1187 &VecOp, false); 1188 VPValue EVL; 1189 VPReductionEVLRecipe EVLRecipe(Recipe, EVL, &CondOp); 1190 EXPECT_FALSE(EVLRecipe.mayHaveSideEffects()); 1191 EXPECT_FALSE(EVLRecipe.mayReadFromMemory()); 1192 EXPECT_FALSE(EVLRecipe.mayWriteToMemory()); 1193 EXPECT_FALSE(EVLRecipe.mayReadOrWriteMemory()); 1194 } 1195 1196 { 1197 auto *Load = 1198 new LoadInst(Int32, PoisonValue::get(Int32Ptr), "", false, Align(1)); 1199 VPValue Addr; 1200 VPValue Mask; 1201 VPWidenLoadRecipe Recipe(*Load, &Addr, &Mask, true, false, {}); 1202 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1203 EXPECT_TRUE(Recipe.mayReadFromMemory()); 1204 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1205 EXPECT_TRUE(Recipe.mayReadOrWriteMemory()); 1206 delete Load; 1207 } 1208 1209 { 1210 auto *Store = new StoreInst(PoisonValue::get(Int32), 1211 PoisonValue::get(Int32Ptr), false, Align(1)); 1212 VPValue Addr; 1213 VPValue Mask; 1214 VPValue StoredV; 1215 VPWidenStoreRecipe Recipe(*Store, &Addr, &StoredV, &Mask, false, false, {}); 1216 EXPECT_TRUE(Recipe.mayHaveSideEffects()); 1217 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1218 EXPECT_TRUE(Recipe.mayWriteToMemory()); 1219 EXPECT_TRUE(Recipe.mayReadOrWriteMemory()); 1220 delete Store; 1221 } 1222 1223 { 1224 FunctionType *FTy = FunctionType::get(Int32, false); 1225 Function *Fn = Function::Create(FTy, GlobalValue::ExternalLinkage, 0); 1226 auto *Call = CallInst::Create(FTy, Fn); 1227 VPValue Op1; 1228 VPValue Op2; 1229 VPValue CalledFn(Call->getCalledFunction()); 1230 SmallVector<VPValue *, 3> Args; 1231 Args.push_back(&Op1); 1232 Args.push_back(&Op2); 1233 Args.push_back(&CalledFn); 1234 VPWidenCallRecipe Recipe(Call, Fn, Args); 1235 EXPECT_TRUE(Recipe.mayHaveSideEffects()); 1236 EXPECT_TRUE(Recipe.mayReadFromMemory()); 1237 EXPECT_TRUE(Recipe.mayWriteToMemory()); 1238 EXPECT_TRUE(Recipe.mayReadOrWriteMemory()); 1239 delete Call; 1240 delete Fn; 1241 } 1242 1243 { 1244 // Test for a call to a function without side-effects. 1245 LLVMContext C; 1246 Module M("", C); 1247 Function *TheFn = 1248 Intrinsic::getOrInsertDeclaration(&M, Intrinsic::thread_pointer); 1249 1250 auto *Call = CallInst::Create(TheFn->getFunctionType(), TheFn); 1251 VPValue Op1; 1252 VPValue Op2; 1253 VPValue CalledFn(TheFn); 1254 SmallVector<VPValue *, 3> Args; 1255 Args.push_back(&Op1); 1256 Args.push_back(&Op2); 1257 Args.push_back(&CalledFn); 1258 VPWidenCallRecipe Recipe(Call, TheFn, Args); 1259 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1260 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1261 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1262 EXPECT_FALSE(Recipe.mayReadOrWriteMemory()); 1263 delete Call; 1264 } 1265 1266 { 1267 VPValue Op1; 1268 VPValue Op2; 1269 InductionDescriptor IndDesc; 1270 VPScalarIVStepsRecipe Recipe(IndDesc, &Op1, &Op2); 1271 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1272 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1273 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1274 EXPECT_FALSE(Recipe.mayReadOrWriteMemory()); 1275 } 1276 1277 // The initial implementation is conservative with respect to VPInstructions. 1278 { 1279 VPValue Op1; 1280 VPValue Op2; 1281 VPInstruction VPInst(Instruction::Add, {&Op1, &Op2}); 1282 VPRecipeBase &Recipe = VPInst; 1283 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1284 EXPECT_TRUE(Recipe.mayReadFromMemory()); 1285 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1286 EXPECT_TRUE(Recipe.mayReadOrWriteMemory()); 1287 } 1288 { 1289 VPValue Op1; 1290 VPPredInstPHIRecipe Recipe(&Op1, {}); 1291 EXPECT_FALSE(Recipe.mayHaveSideEffects()); 1292 EXPECT_FALSE(Recipe.mayReadFromMemory()); 1293 EXPECT_FALSE(Recipe.mayWriteToMemory()); 1294 EXPECT_FALSE(Recipe.mayReadOrWriteMemory()); 1295 } 1296 } 1297 1298 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1299 TEST(VPRecipeTest, dumpRecipeInPlan) { 1300 VPBasicBlock *VPBB0 = new VPBasicBlock("preheader"); 1301 VPBasicBlock *VPBB1 = new VPBasicBlock(); 1302 LLVMContext C; 1303 auto *ScalarHeader = BasicBlock::Create(C, ""); 1304 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 1305 VPBlockUtils::connectBlocks(VPBB1, ScalarHeaderVPBB); 1306 VPBlockUtils::connectBlocks(VPBB0, VPBB1); 1307 VPlan Plan(VPBB0, ScalarHeaderVPBB); 1308 1309 IntegerType *Int32 = IntegerType::get(C, 32); 1310 auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32), 1311 PoisonValue::get(Int32)); 1312 AI->setName("a"); 1313 SmallVector<VPValue *, 2> Args; 1314 VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1)); 1315 VPValue *ExtVPV2 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2)); 1316 Args.push_back(ExtVPV1); 1317 Args.push_back(ExtVPV2); 1318 VPWidenRecipe *WidenR = 1319 new VPWidenRecipe(*AI, make_range(Args.begin(), Args.end())); 1320 VPBB1->appendRecipe(WidenR); 1321 1322 { 1323 // Use EXPECT_EXIT to capture stderr and compare against expected output. 1324 // 1325 // Test VPValue::dump(). 1326 VPValue *VPV = WidenR; 1327 EXPECT_EXIT( 1328 { 1329 VPV->dump(); 1330 exit(0); 1331 }, 1332 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>"); 1333 1334 VPDef *Def = WidenR; 1335 EXPECT_EXIT( 1336 { 1337 Def->dump(); 1338 exit(0); 1339 }, 1340 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>"); 1341 1342 EXPECT_EXIT( 1343 { 1344 WidenR->dump(); 1345 exit(0); 1346 }, 1347 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>"); 1348 1349 // Test VPRecipeBase::dump(). 1350 VPRecipeBase *R = WidenR; 1351 EXPECT_EXIT( 1352 { 1353 R->dump(); 1354 exit(0); 1355 }, 1356 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>"); 1357 1358 // Test VPDef::dump(). 1359 VPDef *D = WidenR; 1360 EXPECT_EXIT( 1361 { 1362 D->dump(); 1363 exit(0); 1364 }, 1365 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>"); 1366 } 1367 1368 delete AI; 1369 delete ScalarHeader; 1370 } 1371 1372 TEST(VPRecipeTest, dumpRecipeUnnamedVPValuesInPlan) { 1373 VPBasicBlock *VPBB0 = new VPBasicBlock("preheader"); 1374 VPBasicBlock *VPBB1 = new VPBasicBlock(); 1375 LLVMContext C; 1376 auto *ScalarHeader = BasicBlock::Create(C, ""); 1377 VPIRBasicBlock *ScalarHeaderVPBB = new VPIRBasicBlock(ScalarHeader); 1378 VPBlockUtils::connectBlocks(VPBB1, ScalarHeaderVPBB); 1379 VPBlockUtils::connectBlocks(VPBB0, VPBB1); 1380 VPlan Plan(VPBB0, ScalarHeaderVPBB); 1381 1382 IntegerType *Int32 = IntegerType::get(C, 32); 1383 auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32), 1384 PoisonValue::get(Int32)); 1385 AI->setName("a"); 1386 SmallVector<VPValue *, 2> Args; 1387 VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1)); 1388 VPValue *ExtVPV2 = Plan.getOrAddLiveIn(AI); 1389 Args.push_back(ExtVPV1); 1390 Args.push_back(ExtVPV2); 1391 VPInstruction *I1 = new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2}); 1392 VPInstruction *I2 = new VPInstruction(Instruction::Mul, {I1, I1}); 1393 VPBB1->appendRecipe(I1); 1394 VPBB1->appendRecipe(I2); 1395 1396 // Check printing I1. 1397 { 1398 // Use EXPECT_EXIT to capture stderr and compare against expected output. 1399 // 1400 // Test VPValue::dump(). 1401 VPValue *VPV = I1; 1402 EXPECT_EXIT( 1403 { 1404 VPV->dump(); 1405 exit(0); 1406 }, 1407 testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>"); 1408 1409 // Test VPRecipeBase::dump(). 1410 VPRecipeBase *R = I1; 1411 EXPECT_EXIT( 1412 { 1413 R->dump(); 1414 exit(0); 1415 }, 1416 testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>"); 1417 1418 // Test VPDef::dump(). 1419 VPDef *D = I1; 1420 EXPECT_EXIT( 1421 { 1422 D->dump(); 1423 exit(0); 1424 }, 1425 testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>"); 1426 } 1427 // Check printing I2. 1428 { 1429 // Use EXPECT_EXIT to capture stderr and compare against expected output. 1430 // 1431 // Test VPValue::dump(). 1432 VPValue *VPV = I2; 1433 EXPECT_EXIT( 1434 { 1435 VPV->dump(); 1436 exit(0); 1437 }, 1438 testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>"); 1439 1440 // Test VPRecipeBase::dump(). 1441 VPRecipeBase *R = I2; 1442 EXPECT_EXIT( 1443 { 1444 R->dump(); 1445 exit(0); 1446 }, 1447 testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>"); 1448 1449 // Test VPDef::dump(). 1450 VPDef *D = I2; 1451 EXPECT_EXIT( 1452 { 1453 D->dump(); 1454 exit(0); 1455 }, 1456 testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>"); 1457 } 1458 delete AI; 1459 delete ScalarHeader; 1460 } 1461 1462 TEST(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) { 1463 LLVMContext C; 1464 IntegerType *Int32 = IntegerType::get(C, 32); 1465 auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32), 1466 PoisonValue::get(Int32)); 1467 AI->setName("a"); 1468 VPValue *ExtVPV1 = new VPValue(ConstantInt::get(Int32, 1)); 1469 VPValue *ExtVPV2 = new VPValue(AI); 1470 1471 VPInstruction *I1 = new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2}); 1472 VPInstruction *I2 = new VPInstruction(Instruction::Mul, {I1, I1}); 1473 1474 // Check printing I1. 1475 { 1476 // Use EXPECT_EXIT to capture stderr and compare against expected output. 1477 // 1478 // Test VPValue::dump(). 1479 VPValue *VPV = I1; 1480 EXPECT_EXIT( 1481 { 1482 VPV->dump(); 1483 exit(0); 1484 }, 1485 testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>"); 1486 1487 // Test VPRecipeBase::dump(). 1488 VPRecipeBase *R = I1; 1489 EXPECT_EXIT( 1490 { 1491 R->dump(); 1492 exit(0); 1493 }, 1494 testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>"); 1495 1496 // Test VPDef::dump(). 1497 VPDef *D = I1; 1498 EXPECT_EXIT( 1499 { 1500 D->dump(); 1501 exit(0); 1502 }, 1503 testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>"); 1504 } 1505 // Check printing I2. 1506 { 1507 // Use EXPECT_EXIT to capture stderr and compare against expected output. 1508 // 1509 // Test VPValue::dump(). 1510 VPValue *VPV = I2; 1511 EXPECT_EXIT( 1512 { 1513 VPV->dump(); 1514 exit(0); 1515 }, 1516 testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>"); 1517 1518 // Test VPRecipeBase::dump(). 1519 VPRecipeBase *R = I2; 1520 EXPECT_EXIT( 1521 { 1522 R->dump(); 1523 exit(0); 1524 }, 1525 testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>"); 1526 1527 // Test VPDef::dump(). 1528 VPDef *D = I2; 1529 EXPECT_EXIT( 1530 { 1531 D->dump(); 1532 exit(0); 1533 }, 1534 testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>"); 1535 } 1536 1537 delete I2; 1538 delete I1; 1539 delete ExtVPV2; 1540 delete ExtVPV1; 1541 delete AI; 1542 } 1543 1544 #endif 1545 1546 TEST(VPRecipeTest, CastVPReductionRecipeToVPUser) { 1547 LLVMContext C; 1548 1549 VPValue ChainOp; 1550 VPValue VecOp; 1551 VPValue CondOp; 1552 VPReductionRecipe Recipe(RecurrenceDescriptor(), nullptr, &ChainOp, &CondOp, 1553 &VecOp, false); 1554 EXPECT_TRUE(isa<VPUser>(&Recipe)); 1555 VPRecipeBase *BaseR = &Recipe; 1556 EXPECT_TRUE(isa<VPUser>(BaseR)); 1557 } 1558 1559 TEST(VPRecipeTest, CastVPReductionEVLRecipeToVPUser) { 1560 LLVMContext C; 1561 1562 VPValue ChainOp; 1563 VPValue VecOp; 1564 VPValue CondOp; 1565 VPReductionRecipe Recipe(RecurrenceDescriptor(), nullptr, &ChainOp, &CondOp, 1566 &VecOp, false); 1567 VPValue EVL; 1568 VPReductionEVLRecipe EVLRecipe(Recipe, EVL, &CondOp); 1569 EXPECT_TRUE(isa<VPUser>(&EVLRecipe)); 1570 VPRecipeBase *BaseR = &EVLRecipe; 1571 EXPECT_TRUE(isa<VPUser>(BaseR)); 1572 } 1573 1574 struct VPDoubleValueDef : public VPRecipeBase { 1575 VPDoubleValueDef(ArrayRef<VPValue *> Operands) : VPRecipeBase(99, Operands) { 1576 new VPValue(nullptr, this); 1577 new VPValue(nullptr, this); 1578 } 1579 1580 VPRecipeBase *clone() override { return nullptr; } 1581 1582 void execute(struct VPTransformState &State) override {} 1583 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1584 void print(raw_ostream &O, const Twine &Indent, 1585 VPSlotTracker &SlotTracker) const override {} 1586 #endif 1587 }; 1588 1589 TEST(VPDoubleValueDefTest, traverseUseLists) { 1590 // Check that the def-use chains of a multi-def can be traversed in both 1591 // directions. 1592 1593 // Create a new VPDef which defines 2 values and has 2 operands. 1594 VPInstruction Op0(20, {}); 1595 VPInstruction Op1(30, {}); 1596 VPDoubleValueDef DoubleValueDef({&Op0, &Op1}); 1597 1598 // Create a new users of the defined values. 1599 VPInstruction I1( 1600 1, {DoubleValueDef.getVPValue(0), DoubleValueDef.getVPValue(1)}); 1601 VPInstruction I2(2, {DoubleValueDef.getVPValue(0)}); 1602 VPInstruction I3(3, {DoubleValueDef.getVPValue(1)}); 1603 1604 // Check operands of the VPDef (traversing upwards). 1605 SmallVector<VPValue *, 4> DoubleOperands(DoubleValueDef.op_begin(), 1606 DoubleValueDef.op_end()); 1607 EXPECT_EQ(2u, DoubleOperands.size()); 1608 EXPECT_EQ(&Op0, DoubleOperands[0]); 1609 EXPECT_EQ(&Op1, DoubleOperands[1]); 1610 1611 // Check users of the defined values (traversing downwards). 1612 SmallVector<VPUser *, 4> DoubleValueDefV0Users( 1613 DoubleValueDef.getVPValue(0)->user_begin(), 1614 DoubleValueDef.getVPValue(0)->user_end()); 1615 EXPECT_EQ(2u, DoubleValueDefV0Users.size()); 1616 EXPECT_EQ(&I1, DoubleValueDefV0Users[0]); 1617 EXPECT_EQ(&I2, DoubleValueDefV0Users[1]); 1618 1619 SmallVector<VPUser *, 4> DoubleValueDefV1Users( 1620 DoubleValueDef.getVPValue(1)->user_begin(), 1621 DoubleValueDef.getVPValue(1)->user_end()); 1622 EXPECT_EQ(2u, DoubleValueDefV1Users.size()); 1623 EXPECT_EQ(&I1, DoubleValueDefV1Users[0]); 1624 EXPECT_EQ(&I3, DoubleValueDefV1Users[1]); 1625 1626 // Now check that we can get the right VPDef for each defined value. 1627 EXPECT_EQ(&DoubleValueDef, I1.getOperand(0)->getDefiningRecipe()); 1628 EXPECT_EQ(&DoubleValueDef, I1.getOperand(1)->getDefiningRecipe()); 1629 EXPECT_EQ(&DoubleValueDef, I2.getOperand(0)->getDefiningRecipe()); 1630 EXPECT_EQ(&DoubleValueDef, I3.getOperand(0)->getDefiningRecipe()); 1631 } 1632 1633 TEST(VPRecipeTest, CastToVPSingleDefRecipe) { 1634 VPValue Start; 1635 VPEVLBasedIVPHIRecipe R(&Start, {}); 1636 VPRecipeBase *B = &R; 1637 EXPECT_TRUE(isa<VPSingleDefRecipe>(B)); 1638 // TODO: check other VPSingleDefRecipes. 1639 } 1640 1641 } // namespace 1642 } // namespace llvm 1643