brintos

brintos / llvm-project-archived public Read only

0
0
Text · 58.6 KiB · a6a1f67 Raw
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