1 //===- CFGTest.cpp - CFG tests --------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Analysis/CFG.h" 11 #include "llvm/Analysis/LoopInfo.h" 12 #include "llvm/AsmParser/Parser.h" 13 #include "llvm/IR/Dominators.h" 14 #include "llvm/IR/Function.h" 15 #include "llvm/IR/InstIterator.h" 16 #include "llvm/IR/LLVMContext.h" 17 #include "llvm/IR/Module.h" 18 #include "llvm/Pass.h" 19 #include "llvm/IR/LegacyPassManager.h" 20 #include "llvm/Support/ErrorHandling.h" 21 #include "llvm/Support/SourceMgr.h" 22 #include "gtest/gtest.h" 23 24 using namespace llvm; 25 26 namespace { 27 28 // This fixture assists in running the isPotentiallyReachable utility four ways 29 // and ensuring it produces the correct answer each time. 30 class IsPotentiallyReachableTest : public testing::Test { 31 protected: 32 void ParseAssembly(const char *Assembly) { 33 SMDiagnostic Error; 34 M = parseAssemblyString(Assembly, Error, Context); 35 36 std::string errMsg; 37 raw_string_ostream os(errMsg); 38 Error.print("", os); 39 40 // A failure here means that the test itself is buggy. 41 if (!M) 42 report_fatal_error(os.str().c_str()); 43 44 Function *F = M->getFunction("test"); 45 if (F == nullptr) 46 report_fatal_error("Test must have a function named @test"); 47 48 A = B = nullptr; 49 for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 50 if (I->hasName()) { 51 if (I->getName() == "A") 52 A = &*I; 53 else if (I->getName() == "B") 54 B = &*I; 55 } 56 } 57 if (A == nullptr) 58 report_fatal_error("@test must have an instruction %A"); 59 if (B == nullptr) 60 report_fatal_error("@test must have an instruction %B"); 61 } 62 63 void ExpectPath(bool ExpectedResult) { 64 static char ID; 65 class IsPotentiallyReachableTestPass : public FunctionPass { 66 public: 67 IsPotentiallyReachableTestPass(bool ExpectedResult, 68 Instruction *A, Instruction *B) 69 : FunctionPass(ID), ExpectedResult(ExpectedResult), A(A), B(B) {} 70 71 static int initialize() { 72 PassInfo *PI = new PassInfo("isPotentiallyReachable testing pass", 73 "", &ID, nullptr, true, true); 74 PassRegistry::getPassRegistry()->registerPass(*PI, false); 75 initializeLoopInfoWrapperPassPass(*PassRegistry::getPassRegistry()); 76 initializeDominatorTreeWrapperPassPass( 77 *PassRegistry::getPassRegistry()); 78 return 0; 79 } 80 81 void getAnalysisUsage(AnalysisUsage &AU) const override { 82 AU.setPreservesAll(); 83 AU.addRequired<LoopInfoWrapperPass>(); 84 AU.addRequired<DominatorTreeWrapperPass>(); 85 } 86 87 bool runOnFunction(Function &F) override { 88 if (!F.hasName() || F.getName() != "test") 89 return false; 90 91 LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 92 DominatorTree *DT = 93 &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 94 EXPECT_EQ(isPotentiallyReachable(A, B, nullptr, nullptr), 95 ExpectedResult); 96 EXPECT_EQ(isPotentiallyReachable(A, B, DT, nullptr), ExpectedResult); 97 EXPECT_EQ(isPotentiallyReachable(A, B, nullptr, LI), ExpectedResult); 98 EXPECT_EQ(isPotentiallyReachable(A, B, DT, LI), ExpectedResult); 99 return false; 100 } 101 bool ExpectedResult; 102 Instruction *A, *B; 103 }; 104 105 static int initialize = IsPotentiallyReachableTestPass::initialize(); 106 (void)initialize; 107 108 IsPotentiallyReachableTestPass *P = 109 new IsPotentiallyReachableTestPass(ExpectedResult, A, B); 110 legacy::PassManager PM; 111 PM.add(P); 112 PM.run(*M); 113 } 114 115 LLVMContext Context; 116 std::unique_ptr<Module> M; 117 Instruction *A, *B; 118 }; 119 120 } 121 122 TEST_F(IsPotentiallyReachableTest, SameBlockNoPath) { 123 ParseAssembly( 124 "define void @test() {\n" 125 "entry:\n" 126 " bitcast i8 undef to i8\n" 127 " %B = bitcast i8 undef to i8\n" 128 " bitcast i8 undef to i8\n" 129 " bitcast i8 undef to i8\n" 130 " %A = bitcast i8 undef to i8\n" 131 " ret void\n" 132 "}\n"); 133 ExpectPath(false); 134 } 135 136 TEST_F(IsPotentiallyReachableTest, SameBlockPath) { 137 ParseAssembly( 138 "define void @test() {\n" 139 "entry:\n" 140 " %A = bitcast i8 undef to i8\n" 141 " bitcast i8 undef to i8\n" 142 " bitcast i8 undef to i8\n" 143 " %B = bitcast i8 undef to i8\n" 144 " ret void\n" 145 "}\n"); 146 ExpectPath(true); 147 } 148 149 TEST_F(IsPotentiallyReachableTest, SameBlockNoLoop) { 150 ParseAssembly( 151 "define void @test() {\n" 152 "entry:\n" 153 " br label %middle\n" 154 "middle:\n" 155 " %B = bitcast i8 undef to i8\n" 156 " bitcast i8 undef to i8\n" 157 " bitcast i8 undef to i8\n" 158 " %A = bitcast i8 undef to i8\n" 159 " br label %nextblock\n" 160 "nextblock:\n" 161 " ret void\n" 162 "}\n"); 163 ExpectPath(false); 164 } 165 166 TEST_F(IsPotentiallyReachableTest, StraightNoPath) { 167 ParseAssembly( 168 "define void @test() {\n" 169 "entry:\n" 170 " %B = bitcast i8 undef to i8\n" 171 " br label %exit\n" 172 "exit:\n" 173 " %A = bitcast i8 undef to i8\n" 174 " ret void\n" 175 "}"); 176 ExpectPath(false); 177 } 178 179 TEST_F(IsPotentiallyReachableTest, StraightPath) { 180 ParseAssembly( 181 "define void @test() {\n" 182 "entry:\n" 183 " %A = bitcast i8 undef to i8\n" 184 " br label %exit\n" 185 "exit:\n" 186 " %B = bitcast i8 undef to i8\n" 187 " ret void\n" 188 "}"); 189 ExpectPath(true); 190 } 191 192 TEST_F(IsPotentiallyReachableTest, DestUnreachable) { 193 ParseAssembly( 194 "define void @test() {\n" 195 "entry:\n" 196 " br label %midblock\n" 197 "midblock:\n" 198 " %A = bitcast i8 undef to i8\n" 199 " ret void\n" 200 "unreachable:\n" 201 " %B = bitcast i8 undef to i8\n" 202 " br label %midblock\n" 203 "}"); 204 ExpectPath(false); 205 } 206 207 TEST_F(IsPotentiallyReachableTest, BranchToReturn) { 208 ParseAssembly( 209 "define void @test(i1 %x) {\n" 210 "entry:\n" 211 " %A = bitcast i8 undef to i8\n" 212 " br i1 %x, label %block1, label %block2\n" 213 "block1:\n" 214 " ret void\n" 215 "block2:\n" 216 " %B = bitcast i8 undef to i8\n" 217 " ret void\n" 218 "}"); 219 ExpectPath(true); 220 } 221 222 TEST_F(IsPotentiallyReachableTest, SimpleLoop1) { 223 ParseAssembly( 224 "declare i1 @switch()\n" 225 "\n" 226 "define void @test() {\n" 227 "entry:\n" 228 " br label %loop\n" 229 "loop:\n" 230 " %B = bitcast i8 undef to i8\n" 231 " %A = bitcast i8 undef to i8\n" 232 " %x = call i1 @switch()\n" 233 " br i1 %x, label %loop, label %exit\n" 234 "exit:\n" 235 " ret void\n" 236 "}"); 237 ExpectPath(true); 238 } 239 240 TEST_F(IsPotentiallyReachableTest, SimpleLoop2) { 241 ParseAssembly( 242 "declare i1 @switch()\n" 243 "\n" 244 "define void @test() {\n" 245 "entry:\n" 246 " %B = bitcast i8 undef to i8\n" 247 " br label %loop\n" 248 "loop:\n" 249 " %A = bitcast i8 undef to i8\n" 250 " %x = call i1 @switch()\n" 251 " br i1 %x, label %loop, label %exit\n" 252 "exit:\n" 253 " ret void\n" 254 "}"); 255 ExpectPath(false); 256 } 257 258 TEST_F(IsPotentiallyReachableTest, SimpleLoop3) { 259 ParseAssembly( 260 "declare i1 @switch()\n" 261 "\n" 262 "define void @test() {\n" 263 "entry:\n" 264 " br label %loop\n" 265 "loop:\n" 266 " %B = bitcast i8 undef to i8\n" 267 " %x = call i1 @switch()\n" 268 " br i1 %x, label %loop, label %exit\n" 269 "exit:\n" 270 " %A = bitcast i8 undef to i8\n" 271 " ret void\n" 272 "}"); 273 ExpectPath(false); 274 } 275 276 277 TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOther1) { 278 ParseAssembly( 279 "declare i1 @switch()\n" 280 "\n" 281 "define void @test() {\n" 282 "entry:\n" 283 " br label %loop1\n" 284 "loop1:\n" 285 " %A = bitcast i8 undef to i8\n" 286 " %x = call i1 @switch()\n" 287 " br i1 %x, label %loop1, label %loop1exit\n" 288 "loop1exit:\n" 289 " br label %loop2\n" 290 "loop2:\n" 291 " %B = bitcast i8 undef to i8\n" 292 " %y = call i1 @switch()\n" 293 " br i1 %x, label %loop2, label %loop2exit\n" 294 "loop2exit:" 295 " ret void\n" 296 "}"); 297 ExpectPath(true); 298 } 299 300 TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOther2) { 301 ParseAssembly( 302 "declare i1 @switch()\n" 303 "\n" 304 "define void @test() {\n" 305 "entry:\n" 306 " br label %loop1\n" 307 "loop1:\n" 308 " %B = bitcast i8 undef to i8\n" 309 " %x = call i1 @switch()\n" 310 " br i1 %x, label %loop1, label %loop1exit\n" 311 "loop1exit:\n" 312 " br label %loop2\n" 313 "loop2:\n" 314 " %A = bitcast i8 undef to i8\n" 315 " %y = call i1 @switch()\n" 316 " br i1 %x, label %loop2, label %loop2exit\n" 317 "loop2exit:" 318 " ret void\n" 319 "}"); 320 ExpectPath(false); 321 } 322 323 TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOtherInsideAThirdLoop) { 324 ParseAssembly( 325 "declare i1 @switch()\n" 326 "\n" 327 "define void @test() {\n" 328 "entry:\n" 329 " br label %outerloop3\n" 330 "outerloop3:\n" 331 " br label %innerloop1\n" 332 "innerloop1:\n" 333 " %B = bitcast i8 undef to i8\n" 334 " %x = call i1 @switch()\n" 335 " br i1 %x, label %innerloop1, label %innerloop1exit\n" 336 "innerloop1exit:\n" 337 " br label %innerloop2\n" 338 "innerloop2:\n" 339 " %A = bitcast i8 undef to i8\n" 340 " %y = call i1 @switch()\n" 341 " br i1 %x, label %innerloop2, label %innerloop2exit\n" 342 "innerloop2exit:" 343 " ;; In outer loop3 now.\n" 344 " %z = call i1 @switch()\n" 345 " br i1 %z, label %outerloop3, label %exit\n" 346 "exit:\n" 347 " ret void\n" 348 "}"); 349 ExpectPath(true); 350 } 351 352 static const char *BranchInsideLoopIR = 353 "declare i1 @switch()\n" 354 "\n" 355 "define void @test() {\n" 356 "entry:\n" 357 " br label %loop\n" 358 "loop:\n" 359 " %x = call i1 @switch()\n" 360 " br i1 %x, label %nextloopblock, label %exit\n" 361 "nextloopblock:\n" 362 " %y = call i1 @switch()\n" 363 " br i1 %y, label %left, label %right\n" 364 "left:\n" 365 " %A = bitcast i8 undef to i8\n" 366 " br label %loop\n" 367 "right:\n" 368 " %B = bitcast i8 undef to i8\n" 369 " br label %loop\n" 370 "exit:\n" 371 " ret void\n" 372 "}"; 373 374 TEST_F(IsPotentiallyReachableTest, BranchInsideLoop) { 375 ParseAssembly(BranchInsideLoopIR); 376 ExpectPath(true); 377 } 378 379 TEST_F(IsPotentiallyReachableTest, ModifyTest) { 380 ParseAssembly(BranchInsideLoopIR); 381 382 succ_iterator S = succ_begin(&*++M->getFunction("test")->begin()); 383 BasicBlock *OldBB = S[0]; 384 S[0] = S[1]; 385 ExpectPath(false); 386 S[0] = OldBB; 387 ExpectPath(true); 388 } 389