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