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