1 //===- llvm/unittests/Transforms/Vectorize/VPlanTest.cpp - VPlan tests ----===// 2 // 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "../lib/Transforms/Vectorize/VPlan.h" 11 #include "llvm/IR/Instruction.h" 12 #include "llvm/IR/Instructions.h" 13 #include "gtest/gtest.h" 14 #include <string> 15 16 namespace llvm { 17 namespace { 18 19 #define CHECK_ITERATOR(Range1, ...) \ 20 do { \ 21 std::vector<VPInstruction *> Tmp = {__VA_ARGS__}; \ 22 EXPECT_EQ((size_t)std::distance(Range1.begin(), Range1.end()), \ 23 Tmp.size()); \ 24 for (auto Pair : zip(Range1, make_range(Tmp.begin(), Tmp.end()))) \ 25 EXPECT_EQ(&std::get<0>(Pair), std::get<1>(Pair)); \ 26 } while (0) 27 28 TEST(VPInstructionTest, insertBefore) { 29 VPInstruction *I1 = new VPInstruction(0, {}); 30 VPInstruction *I2 = new VPInstruction(1, {}); 31 VPInstruction *I3 = new VPInstruction(2, {}); 32 33 VPBasicBlock VPBB1; 34 VPBB1.appendRecipe(I1); 35 36 I2->insertBefore(I1); 37 CHECK_ITERATOR(VPBB1, I2, I1); 38 39 I3->insertBefore(I2); 40 CHECK_ITERATOR(VPBB1, I3, I2, I1); 41 } 42 43 TEST(VPInstructionTest, eraseFromParent) { 44 VPInstruction *I1 = new VPInstruction(0, {}); 45 VPInstruction *I2 = new VPInstruction(1, {}); 46 VPInstruction *I3 = new VPInstruction(2, {}); 47 48 VPBasicBlock VPBB1; 49 VPBB1.appendRecipe(I1); 50 VPBB1.appendRecipe(I2); 51 VPBB1.appendRecipe(I3); 52 53 I2->eraseFromParent(); 54 CHECK_ITERATOR(VPBB1, I1, I3); 55 56 I1->eraseFromParent(); 57 CHECK_ITERATOR(VPBB1, I3); 58 59 I3->eraseFromParent(); 60 EXPECT_TRUE(VPBB1.empty()); 61 } 62 63 TEST(VPInstructionTest, moveAfter) { 64 VPInstruction *I1 = new VPInstruction(0, {}); 65 VPInstruction *I2 = new VPInstruction(1, {}); 66 VPInstruction *I3 = new VPInstruction(2, {}); 67 68 VPBasicBlock VPBB1; 69 VPBB1.appendRecipe(I1); 70 VPBB1.appendRecipe(I2); 71 VPBB1.appendRecipe(I3); 72 73 I1->moveAfter(I2); 74 75 CHECK_ITERATOR(VPBB1, I2, I1, I3); 76 77 VPInstruction *I4 = new VPInstruction(4, {}); 78 VPInstruction *I5 = new VPInstruction(5, {}); 79 VPBasicBlock VPBB2; 80 VPBB2.appendRecipe(I4); 81 VPBB2.appendRecipe(I5); 82 83 I3->moveAfter(I4); 84 85 CHECK_ITERATOR(VPBB1, I2, I1); 86 CHECK_ITERATOR(VPBB2, I4, I3, I5); 87 EXPECT_EQ(I3->getParent(), I4->getParent()); 88 } 89 90 TEST(VPBasicBlockTest, getPlan) { 91 { 92 VPBasicBlock *VPBB1 = new VPBasicBlock(); 93 VPBasicBlock *VPBB2 = new VPBasicBlock(); 94 VPBasicBlock *VPBB3 = new VPBasicBlock(); 95 VPBasicBlock *VPBB4 = new VPBasicBlock(); 96 97 // VPBB1 98 // / \ 99 // VPBB2 VPBB3 100 // \ / 101 // VPBB4 102 VPBlockUtils::connectBlocks(VPBB1, VPBB2); 103 VPBlockUtils::connectBlocks(VPBB1, VPBB3); 104 VPBlockUtils::connectBlocks(VPBB2, VPBB4); 105 VPBlockUtils::connectBlocks(VPBB3, VPBB4); 106 107 VPlan Plan; 108 Plan.setEntry(VPBB1); 109 110 EXPECT_EQ(&Plan, VPBB1->getPlan()); 111 EXPECT_EQ(&Plan, VPBB2->getPlan()); 112 EXPECT_EQ(&Plan, VPBB3->getPlan()); 113 EXPECT_EQ(&Plan, VPBB4->getPlan()); 114 } 115 116 { 117 // Region block is entry into VPlan. 118 VPBasicBlock *R1BB1 = new VPBasicBlock(); 119 VPBasicBlock *R1BB2 = new VPBasicBlock(); 120 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1"); 121 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 122 123 VPlan Plan; 124 Plan.setEntry(R1); 125 EXPECT_EQ(&Plan, R1->getPlan()); 126 EXPECT_EQ(&Plan, R1BB1->getPlan()); 127 EXPECT_EQ(&Plan, R1BB2->getPlan()); 128 } 129 130 { 131 // VPBasicBlock is the entry into the VPlan, followed by a region. 132 VPBasicBlock *R1BB1 = new VPBasicBlock(); 133 VPBasicBlock *R1BB2 = new VPBasicBlock(); 134 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1"); 135 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 136 137 VPBasicBlock *VPBB1 = new VPBasicBlock(); 138 VPBlockUtils::connectBlocks(VPBB1, R1); 139 140 VPlan Plan; 141 Plan.setEntry(VPBB1); 142 EXPECT_EQ(&Plan, VPBB1->getPlan()); 143 EXPECT_EQ(&Plan, R1->getPlan()); 144 EXPECT_EQ(&Plan, R1BB1->getPlan()); 145 EXPECT_EQ(&Plan, R1BB2->getPlan()); 146 } 147 148 { 149 VPBasicBlock *R1BB1 = new VPBasicBlock(); 150 VPBasicBlock *R1BB2 = new VPBasicBlock(); 151 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1"); 152 VPBlockUtils::connectBlocks(R1BB1, R1BB2); 153 154 VPBasicBlock *R2BB1 = new VPBasicBlock(); 155 VPBasicBlock *R2BB2 = new VPBasicBlock(); 156 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2"); 157 VPBlockUtils::connectBlocks(R2BB1, R2BB2); 158 159 VPBasicBlock *VPBB1 = new VPBasicBlock(); 160 VPBlockUtils::connectBlocks(VPBB1, R1); 161 VPBlockUtils::connectBlocks(VPBB1, R2); 162 163 VPBasicBlock *VPBB2 = new VPBasicBlock(); 164 VPBlockUtils::connectBlocks(R1, VPBB2); 165 VPBlockUtils::connectBlocks(R2, VPBB2); 166 167 VPlan Plan; 168 Plan.setEntry(VPBB1); 169 EXPECT_EQ(&Plan, VPBB1->getPlan()); 170 EXPECT_EQ(&Plan, R1->getPlan()); 171 EXPECT_EQ(&Plan, R1BB1->getPlan()); 172 EXPECT_EQ(&Plan, R1BB2->getPlan()); 173 EXPECT_EQ(&Plan, R2->getPlan()); 174 EXPECT_EQ(&Plan, R2BB1->getPlan()); 175 EXPECT_EQ(&Plan, R2BB2->getPlan()); 176 EXPECT_EQ(&Plan, VPBB2->getPlan()); 177 } 178 } 179 180 TEST(VPBasicBlockTest, print) { 181 VPInstruction *I1 = new VPInstruction(Instruction::Add, {}); 182 VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1}); 183 VPInstruction *I3 = new VPInstruction(Instruction::Br, {I1, I2}); 184 185 VPBasicBlock *VPBB1 = new VPBasicBlock(); 186 VPBB1->appendRecipe(I1); 187 VPBB1->appendRecipe(I2); 188 VPBB1->appendRecipe(I3); 189 190 VPInstruction *I4 = new VPInstruction(Instruction::Mul, {I2, I1}); 191 VPInstruction *I5 = new VPInstruction(Instruction::Ret, {I4}); 192 VPBasicBlock *VPBB2 = new VPBasicBlock(); 193 VPBB2->appendRecipe(I4); 194 VPBB2->appendRecipe(I5); 195 196 VPBlockUtils::connectBlocks(VPBB1, VPBB2); 197 198 // Check printing an instruction without associated VPlan. 199 { 200 std::string I3Dump; 201 raw_string_ostream OS(I3Dump); 202 I3->print(OS); 203 OS.flush(); 204 EXPECT_EQ("br <badref> <badref>", I3Dump); 205 } 206 207 VPlan Plan; 208 Plan.setEntry(VPBB1); 209 std::string FullDump; 210 raw_string_ostream(FullDump) << Plan; 211 212 const char *ExpectedStr = R"(digraph VPlan { 213 graph [labelloc=t, fontsize=30; label="Vectorization Plan"] 214 node [shape=rect, fontname=Courier, fontsize=30] 215 edge [fontname=Courier, fontsize=30] 216 compound=true 217 N0 [label = 218 ":\n" + 219 "EMIT vp<%0> = add\l" + 220 "EMIT vp<%1> = sub vp<%0>\l" + 221 "EMIT br vp<%0> vp<%1>\l" 222 ] 223 N0 -> N1 [ label=""] 224 N1 [label = 225 ":\n" + 226 "EMIT vp<%2> = mul vp<%1> vp<%0>\l" + 227 "EMIT ret vp<%2>\l" 228 ] 229 } 230 )"; 231 EXPECT_EQ(ExpectedStr, FullDump); 232 233 { 234 std::string I3Dump; 235 raw_string_ostream OS(I3Dump); 236 I3->print(OS); 237 OS.flush(); 238 EXPECT_EQ("br vp<%0> vp<%1>", I3Dump); 239 } 240 241 { 242 std::string I4Dump; 243 raw_string_ostream OS(I4Dump); 244 OS << *I4; 245 OS.flush(); 246 EXPECT_EQ("vp<%2> = mul vp<%1> vp<%0>", I4Dump); 247 } 248 } 249 250 } // namespace 251 } // namespace llvm 252