brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.7 KiB · 00ceeba Raw
662 lines · cpp
1//===- llvm/unittest/IR/LegacyPassManager.cpp - Legacy PassManager tests --===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This unit test exercises the legacy pass manager infrastructure. We use the10// old names as well to ensure that the source-level compatibility is preserved11// where possible.12//13//===----------------------------------------------------------------------===//14 15#include "llvm/IR/LegacyPassManager.h"16#include "llvm/Analysis/CallGraph.h"17#include "llvm/Analysis/CallGraphSCCPass.h"18#include "llvm/Analysis/LoopInfo.h"19#include "llvm/Analysis/LoopPass.h"20#include "llvm/AsmParser/Parser.h"21#include "llvm/IR/AbstractCallSite.h"22#include "llvm/IR/BasicBlock.h"23#include "llvm/IR/CallingConv.h"24#include "llvm/IR/DataLayout.h"25#include "llvm/IR/DerivedTypes.h"26#include "llvm/IR/Function.h"27#include "llvm/IR/GlobalVariable.h"28#include "llvm/IR/Instructions.h"29#include "llvm/IR/LLVMContext.h"30#include "llvm/IR/Module.h"31#include "llvm/IR/OptBisect.h"32#include "llvm/InitializePasses.h"33#include "llvm/Support/MathExtras.h"34#include "llvm/Support/SourceMgr.h"35#include "llvm/Support/raw_ostream.h"36#include "llvm/Transforms/Utils/CallGraphUpdater.h"37#include "gtest/gtest.h"38 39using namespace llvm;40 41namespace llvm {42  void initializeModuleNDMPass(PassRegistry&);43  void initializeFPassPass(PassRegistry&);44  void initializeCGPassPass(PassRegistry&);45  void initializeLPassPass(PassRegistry&);46 47  namespace {48    // ND = no deps49    // NM = no modifications50    struct ModuleNDNM: public ModulePass {51    public:52      static char run;53      static char ID;54      ModuleNDNM() : ModulePass(ID) { }55      bool runOnModule(Module &M) override {56        run++;57        return false;58      }59      void getAnalysisUsage(AnalysisUsage &AU) const override {60        AU.setPreservesAll();61      }62    };63    char ModuleNDNM::ID=0;64    char ModuleNDNM::run=0;65 66    struct ModuleNDM : public ModulePass {67    public:68      static char run;69      static char ID;70      ModuleNDM() : ModulePass(ID) {}71      bool runOnModule(Module &M) override {72        run++;73        return true;74      }75    };76    char ModuleNDM::ID=0;77    char ModuleNDM::run=0;78 79    struct ModuleNDM2 : public ModulePass {80    public:81      static char run;82      static char ID;83      ModuleNDM2() : ModulePass(ID) {}84      bool runOnModule(Module &M) override {85        run++;86        return true;87      }88    };89    char ModuleNDM2::ID=0;90    char ModuleNDM2::run=0;91 92    struct ModuleDNM : public ModulePass {93    public:94      static char run;95      static char ID;96      ModuleDNM() : ModulePass(ID) {97        initializeModuleNDMPass(*PassRegistry::getPassRegistry());98      }99      bool runOnModule(Module &M) override {100        run++;101        return false;102      }103      void getAnalysisUsage(AnalysisUsage &AU) const override {104        AU.addRequired<ModuleNDM>();105        AU.setPreservesAll();106      }107    };108    char ModuleDNM::ID=0;109    char ModuleDNM::run=0;110 111    template<typename P>112    struct PassTestBase : public P {113    protected:114      static int runc;115      static bool initialized;116      static bool finalized;117      int allocated;118      void run() {119        EXPECT_TRUE(initialized);120        EXPECT_FALSE(finalized);121        EXPECT_EQ(0, allocated);122        allocated++;123        runc++;124      }125    public:126      static char ID;127      static void finishedOK(int run) {128        EXPECT_GT(runc, 0);129        EXPECT_TRUE(initialized);130        EXPECT_TRUE(finalized);131        EXPECT_EQ(run, runc);132      }133      PassTestBase() : P(ID), allocated(0) {134        initialized = false;135        finalized = false;136        runc = 0;137      }138 139      void releaseMemory() override {140        EXPECT_GT(runc, 0);141        EXPECT_GT(allocated, 0);142        allocated--;143      }144    };145    template<typename P> char PassTestBase<P>::ID;146    template<typename P> int PassTestBase<P>::runc;147    template<typename P> bool PassTestBase<P>::initialized;148    template<typename P> bool PassTestBase<P>::finalized;149 150    template<typename T, typename P>151    struct PassTest : public PassTestBase<P> {152    public:153#ifndef _MSC_VER // MSVC complains that Pass is not base class.154      using llvm::Pass::doInitialization;155      using llvm::Pass::doFinalization;156#endif157      bool doInitialization(T &t) override {158        EXPECT_FALSE(PassTestBase<P>::initialized);159        PassTestBase<P>::initialized = true;160        return false;161      }162      bool doFinalization(T &t) override {163        EXPECT_FALSE(PassTestBase<P>::finalized);164        PassTestBase<P>::finalized = true;165        EXPECT_EQ(0, PassTestBase<P>::allocated);166        return false;167      }168    };169 170    struct CGPass : public PassTest<CallGraph, CallGraphSCCPass> {171    public:172      CGPass() {173        initializeCGPassPass(*PassRegistry::getPassRegistry());174      }175      bool runOnSCC(CallGraphSCC &SCMM) override {176        run();177        return false;178      }179    };180 181    struct FPass : public PassTest<Module, FunctionPass> {182    public:183      bool runOnFunction(Function &F) override {184        // FIXME: PR4112185        // EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>());186        run();187        return false;188      }189    };190 191    struct LPass : public PassTestBase<LoopPass> {192    private:193      static int initcount;194      static int fincount;195    public:196      LPass() {197        initializeLPassPass(*PassRegistry::getPassRegistry());198        initcount = 0; fincount=0;199        EXPECT_FALSE(initialized);200      }201      static void finishedOK(int run, int finalized) {202        PassTestBase<LoopPass>::finishedOK(run);203        EXPECT_EQ(run, initcount);204        EXPECT_EQ(finalized, fincount);205      }206      using llvm::Pass::doInitialization;207      using llvm::Pass::doFinalization;208      bool doInitialization(Loop* L, LPPassManager &LPM) override {209        initialized = true;210        initcount++;211        return false;212      }213      bool runOnLoop(Loop *L, LPPassManager &LPM) override {214        run();215        return false;216      }217      bool doFinalization() override {218        fincount++;219        finalized = true;220        return false;221      }222    };223    int LPass::initcount=0;224    int LPass::fincount=0;225 226    struct OnTheFlyTest: public ModulePass {227    public:228      static char ID;229      OnTheFlyTest() : ModulePass(ID) {230        initializeFPassPass(*PassRegistry::getPassRegistry());231      }232      bool runOnModule(Module &M) override {233        for (Module::iterator I=M.begin(),E=M.end(); I != E; ++I) {234          Function &F = *I;235          {236            SCOPED_TRACE("Running on the fly function pass");237            getAnalysis<FPass>(F);238          }239        }240        return false;241      }242      void getAnalysisUsage(AnalysisUsage &AU) const override {243        AU.addRequired<FPass>();244      }245    };246    char OnTheFlyTest::ID=0;247 248    TEST(PassManager, RunOnce) {249      LLVMContext Context;250      Module M("test-once", Context);251      struct ModuleNDNM *mNDNM = new ModuleNDNM();252      struct ModuleDNM *mDNM = new ModuleDNM();253      struct ModuleNDM *mNDM = new ModuleNDM();254      struct ModuleNDM2 *mNDM2 = new ModuleNDM2();255 256      mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0;257 258      legacy::PassManager Passes;259      Passes.add(mNDM2);260      Passes.add(mNDM);261      Passes.add(mNDNM);262      Passes.add(mDNM);263 264      Passes.run(M);265      // each pass must be run exactly once, since nothing invalidates them266      EXPECT_EQ(1, mNDM->run);267      EXPECT_EQ(1, mNDNM->run);268      EXPECT_EQ(1, mDNM->run);269      EXPECT_EQ(1, mNDM2->run);270    }271 272    TEST(PassManager, ReRun) {273      LLVMContext Context;274      Module M("test-rerun", Context);275      struct ModuleNDNM *mNDNM = new ModuleNDNM();276      struct ModuleDNM *mDNM = new ModuleDNM();277      struct ModuleNDM *mNDM = new ModuleNDM();278      struct ModuleNDM2 *mNDM2 = new ModuleNDM2();279 280      mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0;281 282      legacy::PassManager Passes;283      Passes.add(mNDM);284      Passes.add(mNDNM);285      Passes.add(mNDM2);// invalidates mNDM needed by mDNM286      Passes.add(mDNM);287 288      Passes.run(M);289      // Some passes must be rerun because a pass that modified the290      // module/function was run in between291      EXPECT_EQ(2, mNDM->run);292      EXPECT_EQ(1, mNDNM->run);293      EXPECT_EQ(1, mNDM2->run);294      EXPECT_EQ(1, mDNM->run);295    }296 297    Module *makeLLVMModule(LLVMContext &Context);298 299    template<typename T>300    void MemoryTestHelper(int run) {301      LLVMContext Context;302      std::unique_ptr<Module> M(makeLLVMModule(Context));303      T *P = new T();304      legacy::PassManager Passes;305      Passes.add(P);306      Passes.run(*M);307      T::finishedOK(run);308    }309 310    template<typename T>311    void MemoryTestHelper(int run, int N) {312      LLVMContext Context;313      Module *M = makeLLVMModule(Context);314      T *P = new T();315      legacy::PassManager Passes;316      Passes.add(P);317      Passes.run(*M);318      T::finishedOK(run, N);319      delete M;320    }321 322    TEST(PassManager, Memory) {323      // SCC#1: test1->test2->test3->test1324      // SCC#2: test4325      // SCC#3: indirect call node326      {327        SCOPED_TRACE("Callgraph pass");328        MemoryTestHelper<CGPass>(3);329      }330 331      {332        SCOPED_TRACE("Function pass");333        MemoryTestHelper<FPass>(4);// 4 functions334      }335 336      {337        SCOPED_TRACE("Loop pass");338        MemoryTestHelper<LPass>(2, 1); //2 loops, 1 function339      }340 341    }342 343    TEST(PassManager, MemoryOnTheFly) {344      LLVMContext Context;345      Module *M = makeLLVMModule(Context);346      {347        SCOPED_TRACE("Running OnTheFlyTest");348        struct OnTheFlyTest *O = new OnTheFlyTest();349        legacy::PassManager Passes;350        Passes.add(O);351        Passes.run(*M);352 353        FPass::finishedOK(4);354      }355      delete M;356    }357 358    // Skips or runs optional passes.359    struct CustomOptPassGate : public OptPassGate {360      bool Skip;361      CustomOptPassGate(bool Skip) : Skip(Skip) { }362      bool shouldRunPass(StringRef PassName,363                         StringRef IRDescription) const override {364        return !Skip;365      }366      bool isEnabled() const override { return true; }367    };368 369    // Optional module pass.370    struct ModuleOpt: public ModulePass {371      char run = 0;372      static char ID;373      ModuleOpt() : ModulePass(ID) { }374      bool runOnModule(Module &M) override {375        if (!skipModule(M))376          run++;377        return false;378      }379    };380    char ModuleOpt::ID=0;381 382    TEST(PassManager, CustomOptPassGate) {383      LLVMContext Context0;384      LLVMContext Context1;385      LLVMContext Context2;386      CustomOptPassGate SkipOptionalPasses(true);387      CustomOptPassGate RunOptionalPasses(false);388 389      Module M0("custom-opt-bisect", Context0);390      Module M1("custom-opt-bisect", Context1);391      Module M2("custom-opt-bisect2", Context2);392      struct ModuleOpt *mOpt0 = new ModuleOpt();393      struct ModuleOpt *mOpt1 = new ModuleOpt();394      struct ModuleOpt *mOpt2 = new ModuleOpt();395 396      mOpt0->run = mOpt1->run = mOpt2->run = 0;397 398      legacy::PassManager Passes0;399      legacy::PassManager Passes1;400      legacy::PassManager Passes2;401 402      Passes0.add(mOpt0);403      Passes1.add(mOpt1);404      Passes2.add(mOpt2);405 406      Context1.setOptPassGate(SkipOptionalPasses);407      Context2.setOptPassGate(RunOptionalPasses);408 409      Passes0.run(M0);410      Passes1.run(M1);411      Passes2.run(M2);412 413      // By default optional passes are run.414      EXPECT_EQ(1, mOpt0->run);415 416      // The first context skips optional passes.417      EXPECT_EQ(0, mOpt1->run);418 419      // The second context runs optional passes.420      EXPECT_EQ(1, mOpt2->run);421    }422 423    Module *makeLLVMModule(LLVMContext &Context) {424      // Module Construction425      Module *mod = new Module("test-mem", Context);426      mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"427                         "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"428                         "a:0:64-s:64:64-f80:128:128");429      mod->setTargetTriple(Triple("x86_64-unknown-linux-gnu"));430 431      // Type Definitions432      std::vector<Type*>FuncTy_0_args;433      FunctionType *FuncTy_0 = FunctionType::get(434          /*Result=*/IntegerType::get(Context, 32),435          /*Params=*/FuncTy_0_args,436          /*isVarArg=*/false);437 438      std::vector<Type*>FuncTy_2_args;439      FuncTy_2_args.push_back(IntegerType::get(Context, 1));440      FunctionType *FuncTy_2 = FunctionType::get(441          /*Result=*/Type::getVoidTy(Context),442          /*Params=*/FuncTy_2_args,443          /*isVarArg=*/false);444 445      // Function Declarations446 447      Function* func_test1 = Function::Create(448        /*Type=*/FuncTy_0,449        /*Linkage=*/GlobalValue::ExternalLinkage,450        /*Name=*/"test1", mod);451      func_test1->setCallingConv(CallingConv::C);452      AttributeList func_test1_PAL;453      func_test1->setAttributes(func_test1_PAL);454 455      Function* func_test2 = Function::Create(456        /*Type=*/FuncTy_0,457        /*Linkage=*/GlobalValue::ExternalLinkage,458        /*Name=*/"test2", mod);459      func_test2->setCallingConv(CallingConv::C);460      AttributeList func_test2_PAL;461      func_test2->setAttributes(func_test2_PAL);462 463      Function* func_test3 = Function::Create(464        /*Type=*/FuncTy_0,465        /*Linkage=*/GlobalValue::InternalLinkage,466        /*Name=*/"test3", mod);467      func_test3->setCallingConv(CallingConv::C);468      AttributeList func_test3_PAL;469      func_test3->setAttributes(func_test3_PAL);470 471      Function* func_test4 = Function::Create(472        /*Type=*/FuncTy_2,473        /*Linkage=*/GlobalValue::ExternalLinkage,474        /*Name=*/"test4", mod);475      func_test4->setCallingConv(CallingConv::C);476      AttributeList func_test4_PAL;477      func_test4->setAttributes(func_test4_PAL);478 479      // Global Variable Declarations480 481 482      // Constant Definitions483 484      // Global Variable Definitions485 486      // Function Definitions487 488      // Function: test1 (func_test1)489      {490 491        BasicBlock *label_entry =492            BasicBlock::Create(Context, "entry", func_test1, nullptr);493 494        // Block entry (label_entry)495        CallInst* int32_3 = CallInst::Create(func_test2, "", label_entry);496        int32_3->setCallingConv(CallingConv::C);497        int32_3->setTailCall(false);498        AttributeList int32_3_PAL;499        int32_3->setAttributes(int32_3_PAL);500 501        ReturnInst::Create(Context, int32_3, label_entry);502      }503 504      // Function: test2 (func_test2)505      {506 507        BasicBlock *label_entry_5 =508            BasicBlock::Create(Context, "entry", func_test2, nullptr);509 510        // Block entry (label_entry_5)511        CallInst* int32_6 = CallInst::Create(func_test3, "", label_entry_5);512        int32_6->setCallingConv(CallingConv::C);513        int32_6->setTailCall(false);514        AttributeList int32_6_PAL;515        int32_6->setAttributes(int32_6_PAL);516 517        ReturnInst::Create(Context, int32_6, label_entry_5);518      }519 520      // Function: test3 (func_test3)521      {522 523        BasicBlock *label_entry_8 =524            BasicBlock::Create(Context, "entry", func_test3, nullptr);525 526        // Block entry (label_entry_8)527        CallInst* int32_9 = CallInst::Create(func_test1, "", label_entry_8);528        int32_9->setCallingConv(CallingConv::C);529        int32_9->setTailCall(false);530        AttributeList int32_9_PAL;531        int32_9->setAttributes(int32_9_PAL);532 533        ReturnInst::Create(Context, int32_9, label_entry_8);534      }535 536      // Function: test4 (func_test4)537      {538        Function::arg_iterator args = func_test4->arg_begin();539        Value *int1_f = &*args++;540        int1_f->setName("f");541 542        BasicBlock *label_entry_11 =543            BasicBlock::Create(Context, "entry", func_test4, nullptr);544        BasicBlock *label_bb =545            BasicBlock::Create(Context, "bb", func_test4, nullptr);546        BasicBlock *label_bb1 =547            BasicBlock::Create(Context, "bb1", func_test4, nullptr);548        BasicBlock *label_return =549            BasicBlock::Create(Context, "return", func_test4, nullptr);550 551        // Block entry (label_entry_11)552        auto *AI = new AllocaInst(func_test3->getType(), 0, "func3ptr",553                                  label_entry_11);554        new StoreInst(func_test3, AI, label_entry_11);555        BranchInst::Create(label_bb, label_entry_11);556 557        // Block bb (label_bb)558        BranchInst::Create(label_bb, label_bb1, int1_f, label_bb);559 560        // Block bb1 (label_bb1)561        BranchInst::Create(label_bb1, label_return, int1_f, label_bb1);562 563        // Block return (label_return)564        ReturnInst::Create(Context, label_return);565      }566      return mod;567    }568 569    // Test for call graph SCC pass that replaces all callback call instructions570    // with clones and updates CallGraph by calling CallGraph::replaceCallEdge()571    // method. Test is expected to complete successfully after running pass on572    // all SCCs in the test module.573    struct CallbackCallsModifierPass : public CGPass {574      bool runOnSCC(CallGraphSCC &SCC) override {575        CGPass::run();576 577        CallGraph &CG = const_cast<CallGraph &>(SCC.getCallGraph());578 579        bool Changed = false;580        for (CallGraphNode *CGN : SCC) {581          Function *F = CGN->getFunction();582          if (!F || F->isDeclaration())583            continue;584 585          SmallVector<CallBase *, 4u> Calls;586          for (Use &U : F->uses()) {587            AbstractCallSite ACS(&U);588            if (!ACS || !ACS.isCallbackCall() || !ACS.isCallee(&U))589              continue;590            Calls.push_back(cast<CallBase>(ACS.getInstruction()));591          }592          if (Calls.empty())593            continue;594 595          for (CallBase *OldCB : Calls) {596            CallGraphNode *CallerCGN = CG[OldCB->getParent()->getParent()];597            assert(any_of(*CallerCGN,598                          [CGN](const CallGraphNode::CallRecord &CallRecord) {599                            return CallRecord.second == CGN;600                          }) &&601                   "function is not a callee");602 603            CallBase *NewCB = cast<CallBase>(OldCB->clone());604 605            NewCB->insertBefore(OldCB->getIterator());606            NewCB->takeName(OldCB);607 608            CallerCGN->replaceCallEdge(*OldCB, *NewCB, CG[F]);609 610            OldCB->replaceAllUsesWith(NewCB);611            OldCB->eraseFromParent();612          }613          Changed = true;614        }615        return Changed;616      }617    };618 619    TEST(PassManager, CallbackCallsModifier0) {620      LLVMContext Context;621 622      const char *IR = "define void @foo() {\n"623                       "  call void @broker(void (i8*)* @callback0, i8* null)\n"624                       "  call void @broker(void (i8*)* @callback1, i8* null)\n"625                       "  ret void\n"626                       "}\n"627                       "\n"628                       "declare !callback !0 void @broker(void (i8*)*, i8*)\n"629                       "\n"630                       "define internal void @callback0(i8* %arg) {\n"631                       "  ret void\n"632                       "}\n"633                       "\n"634                       "define internal void @callback1(i8* %arg) {\n"635                       "  ret void\n"636                       "}\n"637                       "\n"638                       "!0 = !{!1}\n"639                       "!1 = !{i64 0, i64 1, i1 false}";640 641      SMDiagnostic Err;642      std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Context);643      if (!M)644        Err.print("LegacyPassManagerTest", errs());645 646      CallbackCallsModifierPass *P = new CallbackCallsModifierPass();647      legacy::PassManager Passes;648      Passes.add(P);649      Passes.run(*M);650    }651  }652}653 654INITIALIZE_PASS(ModuleNDM, "mndm", "mndm", false, false)655INITIALIZE_PASS_BEGIN(CGPass, "cgp","cgp", false, false)656INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)657INITIALIZE_PASS_END(CGPass, "cgp","cgp", false, false)658INITIALIZE_PASS(FPass, "fp","fp", false, false)659INITIALIZE_PASS_BEGIN(LPass, "lp","lp", false, false)660INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)661INITIALIZE_PASS_END(LPass, "lp","lp", false, false)662