Home | History | Annotate | Download | only in Analysis
      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, getGlobalContext());
     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   std::unique_ptr<Module> M;
    116   Instruction *A, *B;
    117 };
    118 
    119 }
    120 
    121 TEST_F(IsPotentiallyReachableTest, SameBlockNoPath) {
    122   ParseAssembly(
    123       "define void @test() {\n"
    124       "entry:\n"
    125       "  bitcast i8 undef to i8\n"
    126       "  %B = bitcast i8 undef to i8\n"
    127       "  bitcast i8 undef to i8\n"
    128       "  bitcast i8 undef to i8\n"
    129       "  %A = bitcast i8 undef to i8\n"
    130       "  ret void\n"
    131       "}\n");
    132   ExpectPath(false);
    133 }
    134 
    135 TEST_F(IsPotentiallyReachableTest, SameBlockPath) {
    136   ParseAssembly(
    137       "define void @test() {\n"
    138       "entry:\n"
    139       "  %A = bitcast i8 undef to i8\n"
    140       "  bitcast i8 undef to i8\n"
    141       "  bitcast i8 undef to i8\n"
    142       "  %B = bitcast i8 undef to i8\n"
    143       "  ret void\n"
    144       "}\n");
    145   ExpectPath(true);
    146 }
    147 
    148 TEST_F(IsPotentiallyReachableTest, SameBlockNoLoop) {
    149   ParseAssembly(
    150       "define void @test() {\n"
    151       "entry:\n"
    152       "  br label %middle\n"
    153       "middle:\n"
    154       "  %B = bitcast i8 undef to i8\n"
    155       "  bitcast i8 undef to i8\n"
    156       "  bitcast i8 undef to i8\n"
    157       "  %A = bitcast i8 undef to i8\n"
    158       "  br label %nextblock\n"
    159       "nextblock:\n"
    160       "  ret void\n"
    161       "}\n");
    162   ExpectPath(false);
    163 }
    164 
    165 TEST_F(IsPotentiallyReachableTest, StraightNoPath) {
    166   ParseAssembly(
    167       "define void @test() {\n"
    168       "entry:\n"
    169       "  %B = bitcast i8 undef to i8\n"
    170       "  br label %exit\n"
    171       "exit:\n"
    172       "  %A = bitcast i8 undef to i8\n"
    173       "  ret void\n"
    174       "}");
    175   ExpectPath(false);
    176 }
    177 
    178 TEST_F(IsPotentiallyReachableTest, StraightPath) {
    179   ParseAssembly(
    180       "define void @test() {\n"
    181       "entry:\n"
    182       "  %A = bitcast i8 undef to i8\n"
    183       "  br label %exit\n"
    184       "exit:\n"
    185       "  %B = bitcast i8 undef to i8\n"
    186       "  ret void\n"
    187       "}");
    188   ExpectPath(true);
    189 }
    190 
    191 TEST_F(IsPotentiallyReachableTest, DestUnreachable) {
    192   ParseAssembly(
    193       "define void @test() {\n"
    194       "entry:\n"
    195       "  br label %midblock\n"
    196       "midblock:\n"
    197       "  %A = bitcast i8 undef to i8\n"
    198       "  ret void\n"
    199       "unreachable:\n"
    200       "  %B = bitcast i8 undef to i8\n"
    201       "  br label %midblock\n"
    202       "}");
    203   ExpectPath(false);
    204 }
    205 
    206 TEST_F(IsPotentiallyReachableTest, BranchToReturn) {
    207   ParseAssembly(
    208       "define void @test(i1 %x) {\n"
    209       "entry:\n"
    210       "  %A = bitcast i8 undef to i8\n"
    211       "  br i1 %x, label %block1, label %block2\n"
    212       "block1:\n"
    213       "  ret void\n"
    214       "block2:\n"
    215       "  %B = bitcast i8 undef to i8\n"
    216       "  ret void\n"
    217       "}");
    218   ExpectPath(true);
    219 }
    220 
    221 TEST_F(IsPotentiallyReachableTest, SimpleLoop1) {
    222   ParseAssembly(
    223       "declare i1 @switch()\n"
    224       "\n"
    225       "define void @test() {\n"
    226       "entry:\n"
    227       "  br label %loop\n"
    228       "loop:\n"
    229       "  %B = bitcast i8 undef to i8\n"
    230       "  %A = bitcast i8 undef to i8\n"
    231       "  %x = call i1 @switch()\n"
    232       "  br i1 %x, label %loop, label %exit\n"
    233       "exit:\n"
    234       "  ret void\n"
    235       "}");
    236   ExpectPath(true);
    237 }
    238 
    239 TEST_F(IsPotentiallyReachableTest, SimpleLoop2) {
    240   ParseAssembly(
    241       "declare i1 @switch()\n"
    242       "\n"
    243       "define void @test() {\n"
    244       "entry:\n"
    245       "  %B = bitcast i8 undef to i8\n"
    246       "  br label %loop\n"
    247       "loop:\n"
    248       "  %A = bitcast i8 undef to i8\n"
    249       "  %x = call i1 @switch()\n"
    250       "  br i1 %x, label %loop, label %exit\n"
    251       "exit:\n"
    252       "  ret void\n"
    253       "}");
    254   ExpectPath(false);
    255 }
    256 
    257 TEST_F(IsPotentiallyReachableTest, SimpleLoop3) {
    258   ParseAssembly(
    259       "declare i1 @switch()\n"
    260       "\n"
    261       "define void @test() {\n"
    262       "entry:\n"
    263       "  br label %loop\n"
    264       "loop:\n"
    265       "  %B = bitcast i8 undef to i8\n"
    266       "  %x = call i1 @switch()\n"
    267       "  br i1 %x, label %loop, label %exit\n"
    268       "exit:\n"
    269       "  %A = bitcast i8 undef to i8\n"
    270       "  ret void\n"
    271       "}");
    272   ExpectPath(false);
    273 }
    274 
    275 
    276 TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOther1) {
    277   ParseAssembly(
    278       "declare i1 @switch()\n"
    279       "\n"
    280       "define void @test() {\n"
    281       "entry:\n"
    282       "  br label %loop1\n"
    283       "loop1:\n"
    284       "  %A = bitcast i8 undef to i8\n"
    285       "  %x = call i1 @switch()\n"
    286       "  br i1 %x, label %loop1, label %loop1exit\n"
    287       "loop1exit:\n"
    288       "  br label %loop2\n"
    289       "loop2:\n"
    290       "  %B = bitcast i8 undef to i8\n"
    291       "  %y = call i1 @switch()\n"
    292       "  br i1 %x, label %loop2, label %loop2exit\n"
    293       "loop2exit:"
    294       "  ret void\n"
    295       "}");
    296   ExpectPath(true);
    297 }
    298 
    299 TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOther2) {
    300   ParseAssembly(
    301       "declare i1 @switch()\n"
    302       "\n"
    303       "define void @test() {\n"
    304       "entry:\n"
    305       "  br label %loop1\n"
    306       "loop1:\n"
    307       "  %B = bitcast i8 undef to i8\n"
    308       "  %x = call i1 @switch()\n"
    309       "  br i1 %x, label %loop1, label %loop1exit\n"
    310       "loop1exit:\n"
    311       "  br label %loop2\n"
    312       "loop2:\n"
    313       "  %A = bitcast i8 undef to i8\n"
    314       "  %y = call i1 @switch()\n"
    315       "  br i1 %x, label %loop2, label %loop2exit\n"
    316       "loop2exit:"
    317       "  ret void\n"
    318       "}");
    319   ExpectPath(false);
    320 }
    321 
    322 TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOtherInsideAThirdLoop) {
    323   ParseAssembly(
    324       "declare i1 @switch()\n"
    325       "\n"
    326       "define void @test() {\n"
    327       "entry:\n"
    328       "  br label %outerloop3\n"
    329       "outerloop3:\n"
    330       "  br label %innerloop1\n"
    331       "innerloop1:\n"
    332       "  %B = bitcast i8 undef to i8\n"
    333       "  %x = call i1 @switch()\n"
    334       "  br i1 %x, label %innerloop1, label %innerloop1exit\n"
    335       "innerloop1exit:\n"
    336       "  br label %innerloop2\n"
    337       "innerloop2:\n"
    338       "  %A = bitcast i8 undef to i8\n"
    339       "  %y = call i1 @switch()\n"
    340       "  br i1 %x, label %innerloop2, label %innerloop2exit\n"
    341       "innerloop2exit:"
    342       "  ;; In outer loop3 now.\n"
    343       "  %z = call i1 @switch()\n"
    344       "  br i1 %z, label %outerloop3, label %exit\n"
    345       "exit:\n"
    346       "  ret void\n"
    347       "}");
    348   ExpectPath(true);
    349 }
    350 
    351 static const char *BranchInsideLoopIR =
    352     "declare i1 @switch()\n"
    353     "\n"
    354     "define void @test() {\n"
    355     "entry:\n"
    356     "  br label %loop\n"
    357     "loop:\n"
    358     "  %x = call i1 @switch()\n"
    359     "  br i1 %x, label %nextloopblock, label %exit\n"
    360     "nextloopblock:\n"
    361     "  %y = call i1 @switch()\n"
    362     "  br i1 %y, label %left, label %right\n"
    363     "left:\n"
    364     "  %A = bitcast i8 undef to i8\n"
    365     "  br label %loop\n"
    366     "right:\n"
    367     "  %B = bitcast i8 undef to i8\n"
    368     "  br label %loop\n"
    369     "exit:\n"
    370     "  ret void\n"
    371     "}";
    372 
    373 TEST_F(IsPotentiallyReachableTest, BranchInsideLoop) {
    374   ParseAssembly(BranchInsideLoopIR);
    375   ExpectPath(true);
    376 }
    377 
    378 TEST_F(IsPotentiallyReachableTest, ModifyTest) {
    379   ParseAssembly(BranchInsideLoopIR);
    380 
    381   succ_iterator S = succ_begin(++M->getFunction("test")->begin());
    382   BasicBlock *OldBB = S[0];
    383   S[0] = S[1];
    384   ExpectPath(false);
    385   S[0] = OldBB;
    386   ExpectPath(true);
    387 }
    388