diff options
Diffstat (limited to 'contrib/llvm/lib/Transforms/IPO/PartialInlining.cpp')
-rw-r--r-- | contrib/llvm/lib/Transforms/IPO/PartialInlining.cpp | 239 |
1 files changed, 137 insertions, 102 deletions
diff --git a/contrib/llvm/lib/Transforms/IPO/PartialInlining.cpp b/contrib/llvm/lib/Transforms/IPO/PartialInlining.cpp index 49c4417..7ef3fc1 100644 --- a/contrib/llvm/lib/Transforms/IPO/PartialInlining.cpp +++ b/contrib/llvm/lib/Transforms/IPO/PartialInlining.cpp @@ -14,6 +14,9 @@ #include "llvm/Transforms/IPO/PartialInlining.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/BranchProbabilityInfo.h" +#include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" @@ -29,161 +32,193 @@ using namespace llvm; STATISTIC(NumPartialInlined, "Number of functions partially inlined"); namespace { +struct PartialInlinerImpl { + PartialInlinerImpl(InlineFunctionInfo IFI) : IFI(IFI) {} + bool run(Module &M); + Function *unswitchFunction(Function *F); + +private: + InlineFunctionInfo IFI; +}; struct PartialInlinerLegacyPass : public ModulePass { static char ID; // Pass identification, replacement for typeid PartialInlinerLegacyPass() : ModulePass(ID) { initializePartialInlinerLegacyPassPass(*PassRegistry::getPassRegistry()); } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired<AssumptionCacheTracker>(); + } bool runOnModule(Module &M) override { if (skipModule(M)) return false; - ModuleAnalysisManager DummyMAM; - auto PA = Impl.run(M, DummyMAM); - return !PA.areAllPreserved(); - } - -private: - PartialInlinerPass Impl; - }; -} - -char PartialInlinerLegacyPass::ID = 0; -INITIALIZE_PASS(PartialInlinerLegacyPass, "partial-inliner", "Partial Inliner", - false, false) -ModulePass *llvm::createPartialInliningPass() { - return new PartialInlinerLegacyPass(); + AssumptionCacheTracker *ACT = &getAnalysis<AssumptionCacheTracker>(); + std::function<AssumptionCache &(Function &)> GetAssumptionCache = + [&ACT](Function &F) -> AssumptionCache & { + return ACT->getAssumptionCache(F); + }; + InlineFunctionInfo IFI(nullptr, &GetAssumptionCache); + return PartialInlinerImpl(IFI).run(M); + } +}; } -Function *PartialInlinerPass::unswitchFunction(Function *F) { +Function *PartialInlinerImpl::unswitchFunction(Function *F) { // First, verify that this function is an unswitching candidate... - BasicBlock *entryBlock = &F->front(); - BranchInst *BR = dyn_cast<BranchInst>(entryBlock->getTerminator()); + BasicBlock *EntryBlock = &F->front(); + BranchInst *BR = dyn_cast<BranchInst>(EntryBlock->getTerminator()); if (!BR || BR->isUnconditional()) return nullptr; - - BasicBlock* returnBlock = nullptr; - BasicBlock* nonReturnBlock = nullptr; - unsigned returnCount = 0; - for (BasicBlock *BB : successors(entryBlock)) { + + BasicBlock *ReturnBlock = nullptr; + BasicBlock *NonReturnBlock = nullptr; + unsigned ReturnCount = 0; + for (BasicBlock *BB : successors(EntryBlock)) { if (isa<ReturnInst>(BB->getTerminator())) { - returnBlock = BB; - returnCount++; + ReturnBlock = BB; + ReturnCount++; } else - nonReturnBlock = BB; + NonReturnBlock = BB; } - - if (returnCount != 1) + + if (ReturnCount != 1) return nullptr; - + // Clone the function, so that we can hack away on it. ValueToValueMapTy VMap; - Function* duplicateFunction = CloneFunction(F, VMap); - duplicateFunction->setLinkage(GlobalValue::InternalLinkage); - BasicBlock* newEntryBlock = cast<BasicBlock>(VMap[entryBlock]); - BasicBlock* newReturnBlock = cast<BasicBlock>(VMap[returnBlock]); - BasicBlock* newNonReturnBlock = cast<BasicBlock>(VMap[nonReturnBlock]); - + Function *DuplicateFunction = CloneFunction(F, VMap); + DuplicateFunction->setLinkage(GlobalValue::InternalLinkage); + BasicBlock *NewEntryBlock = cast<BasicBlock>(VMap[EntryBlock]); + BasicBlock *NewReturnBlock = cast<BasicBlock>(VMap[ReturnBlock]); + BasicBlock *NewNonReturnBlock = cast<BasicBlock>(VMap[NonReturnBlock]); + // Go ahead and update all uses to the duplicate, so that we can just // use the inliner functionality when we're done hacking. - F->replaceAllUsesWith(duplicateFunction); - + F->replaceAllUsesWith(DuplicateFunction); + // Special hackery is needed with PHI nodes that have inputs from more than // one extracted block. For simplicity, just split the PHIs into a two-level // sequence of PHIs, some of which will go in the extracted region, and some // of which will go outside. - BasicBlock* preReturn = newReturnBlock; - newReturnBlock = newReturnBlock->splitBasicBlock( - newReturnBlock->getFirstNonPHI()->getIterator()); - BasicBlock::iterator I = preReturn->begin(); - Instruction *Ins = &newReturnBlock->front(); - while (I != preReturn->end()) { - PHINode* OldPhi = dyn_cast<PHINode>(I); - if (!OldPhi) break; - - PHINode *retPhi = PHINode::Create(OldPhi->getType(), 2, "", Ins); - OldPhi->replaceAllUsesWith(retPhi); - Ins = newReturnBlock->getFirstNonPHI(); - - retPhi->addIncoming(&*I, preReturn); - retPhi->addIncoming(OldPhi->getIncomingValueForBlock(newEntryBlock), - newEntryBlock); - OldPhi->removeIncomingValue(newEntryBlock); - + BasicBlock *PreReturn = NewReturnBlock; + NewReturnBlock = NewReturnBlock->splitBasicBlock( + NewReturnBlock->getFirstNonPHI()->getIterator()); + BasicBlock::iterator I = PreReturn->begin(); + Instruction *Ins = &NewReturnBlock->front(); + while (I != PreReturn->end()) { + PHINode *OldPhi = dyn_cast<PHINode>(I); + if (!OldPhi) + break; + + PHINode *RetPhi = PHINode::Create(OldPhi->getType(), 2, "", Ins); + OldPhi->replaceAllUsesWith(RetPhi); + Ins = NewReturnBlock->getFirstNonPHI(); + + RetPhi->addIncoming(&*I, PreReturn); + RetPhi->addIncoming(OldPhi->getIncomingValueForBlock(NewEntryBlock), + NewEntryBlock); + OldPhi->removeIncomingValue(NewEntryBlock); + ++I; } - newEntryBlock->getTerminator()->replaceUsesOfWith(preReturn, newReturnBlock); - + NewEntryBlock->getTerminator()->replaceUsesOfWith(PreReturn, NewReturnBlock); + // Gather up the blocks that we're going to extract. - std::vector<BasicBlock*> toExtract; - toExtract.push_back(newNonReturnBlock); - for (BasicBlock &BB : *duplicateFunction) - if (&BB != newEntryBlock && &BB != newReturnBlock && - &BB != newNonReturnBlock) - toExtract.push_back(&BB); + std::vector<BasicBlock *> ToExtract; + ToExtract.push_back(NewNonReturnBlock); + for (BasicBlock &BB : *DuplicateFunction) + if (&BB != NewEntryBlock && &BB != NewReturnBlock && + &BB != NewNonReturnBlock) + ToExtract.push_back(&BB); // The CodeExtractor needs a dominator tree. DominatorTree DT; - DT.recalculate(*duplicateFunction); + DT.recalculate(*DuplicateFunction); + + // Manually calculate a BlockFrequencyInfo and BranchProbabilityInfo. + LoopInfo LI(DT); + BranchProbabilityInfo BPI(*DuplicateFunction, LI); + BlockFrequencyInfo BFI(*DuplicateFunction, BPI, LI); // Extract the body of the if. - Function* extractedFunction - = CodeExtractor(toExtract, &DT).extractCodeRegion(); - - InlineFunctionInfo IFI; - + Function *ExtractedFunction = + CodeExtractor(ToExtract, &DT, /*AggregateArgs*/ false, &BFI, &BPI) + .extractCodeRegion(); + // Inline the top-level if test into all callers. - std::vector<User *> Users(duplicateFunction->user_begin(), - duplicateFunction->user_end()); + std::vector<User *> Users(DuplicateFunction->user_begin(), + DuplicateFunction->user_end()); for (User *User : Users) if (CallInst *CI = dyn_cast<CallInst>(User)) InlineFunction(CI, IFI); else if (InvokeInst *II = dyn_cast<InvokeInst>(User)) InlineFunction(II, IFI); - + // Ditch the duplicate, since we're done with it, and rewrite all remaining // users (function pointers, etc.) back to the original function. - duplicateFunction->replaceAllUsesWith(F); - duplicateFunction->eraseFromParent(); - + DuplicateFunction->replaceAllUsesWith(F); + DuplicateFunction->eraseFromParent(); + ++NumPartialInlined; - - return extractedFunction; + + return ExtractedFunction; } -PreservedAnalyses PartialInlinerPass::run(Module &M, ModuleAnalysisManager &) { - std::vector<Function*> worklist; - worklist.reserve(M.size()); +bool PartialInlinerImpl::run(Module &M) { + std::vector<Function *> Worklist; + Worklist.reserve(M.size()); for (Function &F : M) if (!F.use_empty() && !F.isDeclaration()) - worklist.push_back(&F); - - bool changed = false; - while (!worklist.empty()) { - Function* currFunc = worklist.back(); - worklist.pop_back(); - - if (currFunc->use_empty()) continue; - - bool recursive = false; - for (User *U : currFunc->users()) - if (Instruction* I = dyn_cast<Instruction>(U)) - if (I->getParent()->getParent() == currFunc) { - recursive = true; + Worklist.push_back(&F); + + bool Changed = false; + while (!Worklist.empty()) { + Function *CurrFunc = Worklist.back(); + Worklist.pop_back(); + + if (CurrFunc->use_empty()) + continue; + + bool Recursive = false; + for (User *U : CurrFunc->users()) + if (Instruction *I = dyn_cast<Instruction>(U)) + if (I->getParent()->getParent() == CurrFunc) { + Recursive = true; break; } - if (recursive) continue; - - - if (Function* newFunc = unswitchFunction(currFunc)) { - worklist.push_back(newFunc); - changed = true; + if (Recursive) + continue; + + if (Function *NewFunc = unswitchFunction(CurrFunc)) { + Worklist.push_back(NewFunc); + Changed = true; } - } - if (changed) + return Changed; +} + +char PartialInlinerLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(PartialInlinerLegacyPass, "partial-inliner", + "Partial Inliner", false, false) +INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) +INITIALIZE_PASS_END(PartialInlinerLegacyPass, "partial-inliner", + "Partial Inliner", false, false) + +ModulePass *llvm::createPartialInliningPass() { + return new PartialInlinerLegacyPass(); +} + +PreservedAnalyses PartialInlinerPass::run(Module &M, + ModuleAnalysisManager &AM) { + auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); + std::function<AssumptionCache &(Function &)> GetAssumptionCache = + [&FAM](Function &F) -> AssumptionCache & { + return FAM.getResult<AssumptionAnalysis>(F); + }; + InlineFunctionInfo IFI(nullptr, &GetAssumptionCache); + if (PartialInlinerImpl(IFI).run(M)) return PreservedAnalyses::none(); return PreservedAnalyses::all(); } |