X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTransforms%2FIPO%2FPruneEH.cpp;h=01816052569036882a41c9a21faa3c347aa7f42e;hb=280a6e607d8eb7401749a92db624a82de47da777;hp=1dec7d70470d5ae68e7658698faeb9def69715eb;hpb=ac0b6ae358944ae8b2b5a11dc08f52c3ed89f2da;p=oota-llvm.git diff --git a/lib/Transforms/IPO/PruneEH.cpp b/lib/Transforms/IPO/PruneEH.cpp index 1dec7d70470..01816052569 100644 --- a/lib/Transforms/IPO/PruneEH.cpp +++ b/lib/Transforms/IPO/PruneEH.cpp @@ -2,43 +2,40 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements a simple interprocedural pass which walks the // call-graph, turning invoke instructions into calls, iff the callee cannot -// throw an exception. It implements this as a bottom-up traversal of the -// call-graph. +// throw an exception, and marking functions 'nounwind' if they cannot throw. +// It implements this as a bottom-up traversal of the call-graph. // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "prune-eh" #include "llvm/Transforms/IPO.h" #include "llvm/CallGraphSCCPass.h" #include "llvm/Constants.h" #include "llvm/Function.h" -#include "llvm/Intrinsics.h" #include "llvm/Instructions.h" #include "llvm/Analysis/CallGraph.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CFG.h" +#include "llvm/Support/Compiler.h" #include #include using namespace llvm; -namespace { - Statistic NumRemoved("prune-eh", "Number of invokes removed"); - Statistic NumUnreach("prune-eh", "Number of noreturn calls optimized"); - - struct PruneEH : public CallGraphSCCPass { - /// DoesNotUnwind - This set contains all of the functions which we have - /// determined cannot unwind. - std::set DoesNotUnwind; +STATISTIC(NumRemoved, "Number of invokes removed"); +STATISTIC(NumUnreach, "Number of noreturn calls optimized"); - /// DoesNotReturn - This set contains all of the functions which we have - /// determined cannot return normally (but might unwind). - std::set DoesNotReturn; +namespace { + struct VISIBILITY_HIDDEN PruneEH : public CallGraphSCCPass { + static char ID; // Pass identification, replacement for typeid + PruneEH() : CallGraphSCCPass((intptr_t)&ID) {} // runOnSCC - Analyze the SCC, performing the transformation if possible. bool runOnSCC(const std::vector &SCC); @@ -46,10 +43,12 @@ namespace { bool SimplifyFunction(Function *F); void DeleteBasicBlock(BasicBlock *BB); }; + + char PruneEH::ID = 0; RegisterPass X("prune-eh", "Remove unused exception handling info"); } -ModulePass *llvm::createPruneEHPass() { return new PruneEH(); } +Pass *llvm::createPruneEHPass() { return new PruneEH(); } bool PruneEH::runOnSCC(const std::vector &SCC) { @@ -71,33 +70,41 @@ bool PruneEH::runOnSCC(const std::vector &SCC) { for (unsigned i = 0, e = SCC.size(); (!SCCMightUnwind || !SCCMightReturn) && i != e; ++i) { Function *F = SCC[i]->getFunction(); - if (F == 0 || (F->isExternal() && !F->getIntrinsicID())) { + if (F == 0) { SCCMightUnwind = true; SCCMightReturn = true; + } else if (F->isDeclaration()) { + SCCMightUnwind |= !F->doesNotThrow(); + SCCMightReturn |= !F->doesNotReturn(); } else { - if (F->isExternal()) - SCCMightReturn = true; + bool CheckUnwind = !SCCMightUnwind && !F->doesNotThrow(); + bool CheckReturn = !SCCMightReturn && !F->doesNotReturn(); + + if (!CheckUnwind && !CheckReturn) + continue; // Check to see if this function performs an unwind or calls an // unwinding function. for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { - if (isa(BB->getTerminator())) { // Uses unwind! + if (CheckUnwind && isa(BB->getTerminator())) { + // Uses unwind! SCCMightUnwind = true; - } else if (isa(BB->getTerminator())) { + } else if (CheckReturn && isa(BB->getTerminator())) { SCCMightReturn = true; } // Invoke instructions don't allow unwinding to continue, so we are // only interested in call instructions. - if (!SCCMightUnwind) + if (CheckUnwind && !SCCMightUnwind) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) if (CallInst *CI = dyn_cast(I)) { - if (Function *Callee = CI->getCalledFunction()) { + if (CI->doesNotThrow()) { + // This call cannot throw. + } else if (Function *Callee = CI->getCalledFunction()) { CallGraphNode *CalleeNode = CG[Callee]; - // If the callee is outside our current SCC, or if it is not - // known to throw, then we might throw also. - if (std::find(SCC.begin(), SCC.end(), CalleeNode) == SCC.end()&& - !DoesNotUnwind.count(CalleeNode)) { + // If the callee is outside our current SCC then we may + // throw because it might. + if (std::find(SCC.begin(), SCC.end(), CalleeNode) == SCC.end()){ SCCMightUnwind = true; break; } @@ -113,12 +120,18 @@ bool PruneEH::runOnSCC(const std::vector &SCC) { } // If the SCC doesn't unwind or doesn't throw, note this fact. - if (!SCCMightUnwind) - for (unsigned i = 0, e = SCC.size(); i != e; ++i) - DoesNotUnwind.insert(SCC[i]); - if (!SCCMightReturn) - for (unsigned i = 0, e = SCC.size(); i != e; ++i) - DoesNotReturn.insert(SCC[i]); + if (!SCCMightUnwind || !SCCMightReturn) + for (unsigned i = 0, e = SCC.size(); i != e; ++i) { + ParameterAttributes NewAttributes = ParamAttr::None; + + if (!SCCMightUnwind) + NewAttributes |= ParamAttr::NoUnwind; + if (!SCCMightReturn) + NewAttributes |= ParamAttr::NoReturn; + + const PAListPtr &PAL = SCC[i]->getFunction()->getParamAttrs(); + SCC[i]->getFunction()->setParamAttrs(PAL.addAttr(0, NewAttributes)); + } for (unsigned i = 0, e = SCC.size(); i != e; ++i) { // Convert any invoke instructions to non-throwing functions in this node @@ -136,62 +149,59 @@ bool PruneEH::runOnSCC(const std::vector &SCC) { // function if we have invokes to non-unwinding functions or code after calls to // no-return functions. bool PruneEH::SimplifyFunction(Function *F) { - CallGraph &CG = getAnalysis(); bool MadeChange = false; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { if (InvokeInst *II = dyn_cast(BB->getTerminator())) - if (Function *F = II->getCalledFunction()) - if (DoesNotUnwind.count(CG[F])) { - // Insert a call instruction before the invoke... - std::string Name = II->getName(); II->setName(""); - CallInst *Call = new CallInst(II->getCalledValue(), - std::vector(II->op_begin()+3, - II->op_end()), - Name, II); - Call->setCallingConv(II->getCallingConv()); - - // Anything that used the value produced by the invoke instruction - // now uses the value produced by the call instruction. - II->replaceAllUsesWith(Call); - BasicBlock *UnwindBlock = II->getUnwindDest(); - UnwindBlock->removePredecessor(II->getParent()); - - // Insert a branch to the normal destination right before the - // invoke. - new BranchInst(II->getNormalDest(), II); - - // Finally, delete the invoke instruction! - BB->getInstList().pop_back(); - - // If the unwind block is now dead, nuke it. - if (pred_begin(UnwindBlock) == pred_end(UnwindBlock)) - DeleteBasicBlock(UnwindBlock); // Delete the new BB. - - ++NumRemoved; - MadeChange = true; - } + if (II->doesNotThrow()) { + SmallVector Args(II->op_begin()+3, II->op_end()); + // Insert a call instruction before the invoke. + CallInst *Call = CallInst::Create(II->getCalledValue(), + Args.begin(), Args.end(), "", II); + Call->takeName(II); + Call->setCallingConv(II->getCallingConv()); + Call->setParamAttrs(II->getParamAttrs()); + + // Anything that used the value produced by the invoke instruction + // now uses the value produced by the call instruction. + II->replaceAllUsesWith(Call); + BasicBlock *UnwindBlock = II->getUnwindDest(); + UnwindBlock->removePredecessor(II->getParent()); + + // Insert a branch to the normal destination right before the + // invoke. + BranchInst::Create(II->getNormalDest(), II); + + // Finally, delete the invoke instruction! + BB->getInstList().pop_back(); + + // If the unwind block is now dead, nuke it. + if (pred_begin(UnwindBlock) == pred_end(UnwindBlock)) + DeleteBasicBlock(UnwindBlock); // Delete the new BB. + + ++NumRemoved; + MadeChange = true; + } for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) if (CallInst *CI = dyn_cast(I++)) - if (Function *Callee = CI->getCalledFunction()) - if (DoesNotReturn.count(CG[Callee]) && !isa(I)) { - // This call calls a function that cannot return. Insert an - // unreachable instruction after it and simplify the code. Do this - // by splitting the BB, adding the unreachable, then deleting the - // new BB. - BasicBlock *New = BB->splitBasicBlock(I); - - // Remove the uncond branch and add an unreachable. - BB->getInstList().pop_back(); - new UnreachableInst(BB); - - DeleteBasicBlock(New); // Delete the new BB. - MadeChange = true; - ++NumUnreach; - break; - } + if (CI->doesNotReturn() && !isa(I)) { + // This call calls a function that cannot return. Insert an + // unreachable instruction after it and simplify the code. Do this + // by splitting the BB, adding the unreachable, then deleting the + // new BB. + BasicBlock *New = BB->splitBasicBlock(I); + + // Remove the uncond branch and add an unreachable. + BB->getInstList().pop_back(); + new UnreachableInst(BB); + DeleteBasicBlock(New); // Delete the new BB. + MadeChange = true; + ++NumUnreach; + break; + } } + return MadeChange; }