Author: baldrick Date: Mon Dec 10 13:09:40 2007 New Revision: 44802 URL: http://llvm.org/viewvc/llvm-project?rev=44802&view=rev Log: Make PruneEH update the nounwind/noreturn attributes on functions as it calculates them.
Added: llvm/trunk/test/Transforms/PruneEH/simpletest.ll Removed: llvm/trunk/test/Transforms/PruneEH/simpletest.llx Modified: llvm/trunk/include/llvm/Function.h llvm/trunk/include/llvm/Instructions.h llvm/trunk/lib/Transforms/IPO/PruneEH.cpp llvm/trunk/lib/Transforms/Scalar/SimplifyCFG.cpp llvm/trunk/test/Transforms/PruneEH/simplenoreturntest.ll Modified: llvm/trunk/include/llvm/Function.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Function.h?rev=44802&r1=44801&r2=44802&view=diff ============================================================================== --- llvm/trunk/include/llvm/Function.h (original) +++ llvm/trunk/include/llvm/Function.h Mon Dec 10 13:09:40 2007 @@ -165,6 +165,16 @@ return ParamAttrs && ParamAttrs->paramHasAttr(i, attr); } + /// @brief Determine if the function cannot return. + bool isNoReturn() const { + return paramHasAttr(0, ParamAttr::NoReturn); + } + + /// @brief Determine if the function cannot unwind. + bool isNoUnwind() const { + return paramHasAttr(0, ParamAttr::NoUnwind); + } + /// @brief Determine if the function does not access memory. bool doesNotAccessMemory() const { return paramHasAttr(0, ParamAttr::ReadNone); Modified: llvm/trunk/include/llvm/Instructions.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Instructions.h?rev=44802&r1=44801&r2=44802&view=diff ============================================================================== --- llvm/trunk/include/llvm/Instructions.h (original) +++ llvm/trunk/include/llvm/Instructions.h Mon Dec 10 13:09:40 2007 @@ -937,6 +937,11 @@ return doesNotAccessMemory() || paramHasAttr(0, ParamAttr::ReadOnly); } + /// @brief Determine if the call cannot return. + bool isNoReturn() const { + return paramHasAttr(0, ParamAttr::NoReturn); + } + /// @brief Determine if the call cannot unwind. bool isNoUnwind() const { return paramHasAttr(0, ParamAttr::NoUnwind); @@ -1736,6 +1741,11 @@ return doesNotAccessMemory() || paramHasAttr(0, ParamAttr::ReadOnly); } + /// @brief Determine if the call cannot return. + bool isNoReturn() const { + return paramHasAttr(0, ParamAttr::NoReturn); + } + /// @brief Determine if the call cannot unwind. bool isNoUnwind() const { return paramHasAttr(0, ParamAttr::NoUnwind); Modified: llvm/trunk/lib/Transforms/IPO/PruneEH.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PruneEH.cpp?rev=44802&r1=44801&r2=44802&view=diff ============================================================================== --- llvm/trunk/lib/Transforms/IPO/PruneEH.cpp (original) +++ llvm/trunk/lib/Transforms/IPO/PruneEH.cpp Mon Dec 10 13:09:40 2007 @@ -9,8 +9,8 @@ // // 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. // //===----------------------------------------------------------------------===// @@ -19,7 +19,6 @@ #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" @@ -38,14 +37,6 @@ static char ID; // Pass identification, replacement for typeid PruneEH() : CallGraphSCCPass((intptr_t)&ID) {} - /// DoesNotUnwind - This set contains all of the functions which we have - /// determined cannot unwind. - std::set<CallGraphNode*> DoesNotUnwind; - - /// DoesNotReturn - This set contains all of the functions which we have - /// determined cannot return normally (but might unwind). - std::set<CallGraphNode*> DoesNotReturn; - // runOnSCC - Analyze the SCC, performing the transformation if possible. bool runOnSCC(const std::vector<CallGraphNode *> &SCC); @@ -79,33 +70,41 @@ for (unsigned i = 0, e = SCC.size(); (!SCCMightUnwind || !SCCMightReturn) && i != e; ++i) { Function *F = SCC[i]->getFunction(); - if (F == 0 || (F->isDeclaration() && !F->getIntrinsicID())) { + if (F == 0) { SCCMightUnwind = true; SCCMightReturn = true; + } else if (F->isDeclaration()) { + SCCMightUnwind |= !F->isNoUnwind(); + SCCMightReturn |= !F->isNoReturn(); } else { - if (F->isDeclaration()) - SCCMightReturn = true; + bool CheckUnwind = !SCCMightUnwind && !F->isNoUnwind(); + bool CheckReturn = !SCCMightReturn && !F->isNoReturn(); + + 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<UnwindInst>(BB->getTerminator())) { // Uses unwind! + if (CheckUnwind && isa<UnwindInst>(BB->getTerminator())) { + // Uses unwind! SCCMightUnwind = true; - } else if (isa<ReturnInst>(BB->getTerminator())) { + } else if (CheckReturn && isa<ReturnInst>(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<CallInst>(I)) { - if (Function *Callee = CI->getCalledFunction()) { + if (CI->isNoUnwind()) { + // 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; } @@ -121,12 +120,21 @@ } // 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) { + const ParamAttrsList *PAL = SCC[i]->getFunction()->getParamAttrs(); + uint16_t RAttributes = PAL ? PAL->getParamAttrs(0) : 0; + + if (!SCCMightUnwind) + RAttributes |= ParamAttr::NoUnwind; + if (!SCCMightReturn) + RAttributes |= ParamAttr::NoReturn; + + ParamAttrsVector modVec; + modVec.push_back(ParamAttrsWithIndex::get(0, RAttributes)); + PAL = ParamAttrsList::getModified(PAL, modVec); + SCC[i]->getFunction()->setParamAttrs(PAL); + } for (unsigned i = 0, e = SCC.size(); i != e; ++i) { // Convert any invoke instructions to non-throwing functions in this node @@ -144,61 +152,58 @@ // 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<CallGraph>(); bool MadeChange = false; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator())) - if (Function *F = II->getCalledFunction()) - if (DoesNotUnwind.count(CG[F])) { - SmallVector<Value*, 8> Args(II->op_begin()+3, II->op_end()); - // Insert a call instruction before the invoke. - CallInst *Call = new CallInst(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. - new BranchInst(II->getNormalDest(), II); + if (II->isNoUnwind()) { + SmallVector<Value*, 8> Args(II->op_begin()+3, II->op_end()); + // Insert a call instruction before the invoke. + CallInst *Call = new CallInst(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. + 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. - // Finally, delete the invoke instruction! - BB->getInstList().pop_back(); + ++NumRemoved; + MadeChange = true; + } - // If the unwind block is now dead, nuke it. - if (pred_begin(UnwindBlock) == pred_end(UnwindBlock)) - DeleteBasicBlock(UnwindBlock); // Delete the new BB. + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) + if (CallInst *CI = dyn_cast<CallInst>(I++)) + if (CI->isNoReturn() && !isa<UnreachableInst>(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); - ++NumRemoved; + DeleteBasicBlock(New); // Delete the new BB. MadeChange = true; + ++NumUnreach; + break; } - for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) - if (CallInst *CI = dyn_cast<CallInst>(I++)) - if (Function *Callee = CI->getCalledFunction()) - if (DoesNotReturn.count(CG[Callee]) && !isa<UnreachableInst>(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; } Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyCFG.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SimplifyCFG.cpp?rev=44802&r1=44801&r2=44802&view=diff ============================================================================== --- llvm/trunk/lib/Transforms/Scalar/SimplifyCFG.cpp (original) +++ llvm/trunk/lib/Transforms/Scalar/SimplifyCFG.cpp Mon Dec 10 13:09:40 2007 @@ -111,7 +111,7 @@ // canonicalizes unreachable insts into stores to null or undef. for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E;++BBI){ if (CallInst *CI = dyn_cast<CallInst>(BBI)) { - if (CI->paramHasAttr(0, ParamAttr::NoReturn)) { + if (CI->isNoReturn()) { // If we found a call to a no-return function, insert an unreachable // instruction after it. Make sure there isn't *already* one there // though. Modified: llvm/trunk/test/Transforms/PruneEH/simplenoreturntest.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/PruneEH/simplenoreturntest.ll?rev=44802&r1=44801&r2=44802&view=diff ============================================================================== --- llvm/trunk/test/Transforms/PruneEH/simplenoreturntest.ll (original) +++ llvm/trunk/test/Transforms/PruneEH/simplenoreturntest.ll Mon Dec 10 13:09:40 2007 @@ -1,17 +1,13 @@ -; RUN: llvm-upgrade < %s | llvm-as | opt -prune-eh | llvm-dis | \ -; RUN: not grep {ret i32} +; RUN: llvm-as < %s | opt -prune-eh | llvm-dis | not grep {ret i32} -void %noreturn() { - unwind -} +declare void @noreturn() noreturn; -int %caller() { - ; noreturn never returns, so the ret is unreachable. - call void %noreturn() - ret int 17 +define i32 @caller() { + call void @noreturn( ) + ret i32 17 } -int %caller2() { - %T = call int %caller() - ret int %T ;; this is also unreachable! +define i32 @caller2() { + %T = call i32 @caller( ) ; <i32> [#uses=1] + ret i32 %T } Added: llvm/trunk/test/Transforms/PruneEH/simpletest.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/PruneEH/simpletest.ll?rev=44802&view=auto ============================================================================== --- llvm/trunk/test/Transforms/PruneEH/simpletest.ll (added) +++ llvm/trunk/test/Transforms/PruneEH/simpletest.ll Mon Dec 10 13:09:40 2007 @@ -0,0 +1,19 @@ +; RUN: llvm-as < %s | opt -prune-eh | llvm-dis | not grep invoke + +declare void @nounwind() nounwind + +define internal void @foo() { + call void @nounwind() + ret void +} + +define i32 @caller() { + invoke void @foo( ) + to label %Normal unwind label %Except + +Normal: ; preds = %0 + ret i32 0 + +Except: ; preds = %0 + ret i32 1 +} Removed: llvm/trunk/test/Transforms/PruneEH/simpletest.llx URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/PruneEH/simpletest.llx?rev=44801&view=auto ============================================================================== --- llvm/trunk/test/Transforms/PruneEH/simpletest.llx (original) +++ llvm/trunk/test/Transforms/PruneEH/simpletest.llx (removed) @@ -1,15 +0,0 @@ -; RUN: llvm-upgrade < %s | llvm-as | opt -prune-eh | llvm-dis | not grep invoke - -implementation - -internal void %foo() { - ret void ; does not throw -} - -int %caller() { - invoke void %foo() to label %Normal except label %Except -Normal: - ret int 0 -Except: - ret int 1 -} _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits