From 3e64b2e1a44b0bef896d645e9b293ab84dc16ab8 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 31 Aug 2003 02:47:32 +0000 Subject: Initial checkin of the -prune-eh pass, a very simple exception handling removal pass git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8250 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/PruneEH.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lib/Transforms/IPO/PruneEH.cpp (limited to 'lib/Transforms/IPO/PruneEH.cpp') diff --git a/lib/Transforms/IPO/PruneEH.cpp b/lib/Transforms/IPO/PruneEH.cpp new file mode 100644 index 0000000000..ee2f8c3b9b --- /dev/null +++ b/lib/Transforms/IPO/PruneEH.cpp @@ -0,0 +1,93 @@ +//===- PruneEH.cpp - Pass which deletes unused exception handlers ---------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CallGraphSCCPass.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +#include "llvm/iTerminators.h" +#include "llvm/iOther.h" +#include "llvm/Analysis/CallGraph.h" +#include "Support/Statistic.h" +#include + +namespace { + Statistic<> NumRemoved("prune-eh", "Number of invokes removed"); + + struct PruneEH : public CallGraphSCCPass { + /// DoesNotThrow - This set contains all of the functions which we have + /// determined cannot throw exceptions. + std::set DoesNotThrow; + + // runOnSCC - Analyze the SCC, performing the transformation if possible. + bool runOnSCC(const std::vector &SCC); + }; + RegisterOpt X("prune-eh", "Remove unused exception handling info"); +} + + +bool PruneEH::runOnSCC(const std::vector &SCC) { + CallGraph &CG = getAnalysis(); + + // First, check to see if any callees might throw or if there are any external + // functions in this SCC: if so, we cannot prune any functions in this SCC. + // If this SCC includes the llvm.unwind intrinsic, we KNOW it throws, so + // obviously the SCC might throw. + // + bool SCCMightThrow = false; + for (unsigned i = 0, e = SCC.size(); i != e; ++i) + if (!DoesNotThrow.count(SCC[i]) && // Calls maybe throwing fn + // Make sure this is not one of the fn's in the SCC. + std::find(SCC.begin(), SCC.end(), SCC[i]) == SCC.end()) { + SCCMightThrow = true; break; + } else if (Function *F = SCC[i]->getFunction()) + if (F->isExternal() || // Is external function + F->getIntrinsicID() == LLVMIntrinsic::unwind) {// Is unwind function! + SCCMightThrow = true; break; + } + + bool MadeChange = false; + + for (unsigned i = 0, e = SCC.size(); i != e; ++i) { + // If the SCC can't throw, remember this for callers... + if (!SCCMightThrow) + DoesNotThrow.insert(SCC[i]); + + // Convert any invoke instructions to non-throwing functions in this node + // into call instructions with a branch. This makes the exception blocks + // dead. + if (Function *F = SCC[i]->getFunction()) + for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) + if (InvokeInst *II = dyn_cast(I->getTerminator())) + if (Function *F = II->getCalledFunction()) + if (DoesNotThrow.count(CG[F])) { + // Insert a call instruction before the invoke... + std::string Name = II->getName(); II->setName(""); + Value *Call = new CallInst(II->getCalledValue(), + std::vector(II->op_begin()+3, + II->op_end()), + Name, II); + + // Anything that used the value produced by the invoke instruction + // now uses the value produced by the call instruction. + II->replaceAllUsesWith(Call); + + // Insert a branch to the normal destination right before the + // invoke. + new BranchInst(II->getNormalDest(), II); + + // Finally, delete the invoke instruction! + I->getInstList().pop_back(); + + ++NumRemoved; + MadeChange = true; + } + } + + return MadeChange; +} -- cgit v1.2.3