//===- LowerInvoke.cpp - Eliminate Invoke & Unwind instructions -----------===////// 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 transformation is designed for use by code generators which do not yet// support stack unwinding. This pass supports two models of exception handling// lowering, the 'cheap' support and the 'expensive' support.//// 'Cheap' exception handling support gives the program the ability to execute// any program which does not "throw an exception", by turning 'invoke'// instructions into calls and by turning 'unwind' instructions into calls to// abort(). If the program does dynamically use the unwind instruction, the// program will print a message then abort.//// 'Expensive' exception handling support gives the full exception handling// support to the program at the cost of making the 'invoke' instruction// really expensive. It basically inserts setjmp/longjmp calls to emulate the// exception handling as necessary.//// Because the 'expensive' support slows down programs a lot, and EH is only// used for a subset of the programs, it must be specifically enabled by an// option.//// Note that after this pass runs the CFG is not entirely accurate (exceptional// control flow edges are not correct anymore) so only very simple things should// be done after the lowerinvoke pass has run (like generation of native code).// This should not be used as a general purpose "my LLVM-to-LLVM pass doesn't// support the invoke instruction yet" lowering pass.////===----------------------------------------------------------------------===//#define DEBUG_TYPE "lowerinvoke"#include"llvm/Transforms/Scalar.h"#include"llvm/Constants.h"#include"llvm/DerivedTypes.h"#include"llvm/Instructions.h"#include"llvm/Module.h"#include"llvm/Pass.h"#include"llvm/Transforms/Utils/BasicBlockUtils.h"#include"llvm/Transforms/Utils/Local.h"#include"llvm/ADT/Statistic.h"#include"llvm/Support/CommandLine.h"#include"llvm/Support/Compiler.h"#include"llvm/Target/TargetLowering.h"#include<csetjmp>#include<set>usingnamespacellvm;STATISTIC(NumInvokes,"Number of invokes replaced");STATISTIC(NumUnwinds,"Number of unwinds replaced");STATISTIC(NumSpilled,"Number of registers live across unwind edges");staticcl::opt<bool>ExpensiveEHSupport("enable-correct-eh-support",cl::desc("Make the -lowerinvoke pass insert expensive, but correct, EH code"));namespace{classVISIBILITY_HIDDENLowerInvoke:publicFunctionPass{// Used for both models.Constant*WriteFn;Constant*AbortFn;Value*AbortMessage;unsignedAbortMessageLength;// Used for expensive EH support.constType*JBLinkTy;GlobalVariable*JBListHead;Constant*SetJmpFn,*LongJmpFn;// We peek in TLI to grab the target's jmp_buf size and alignmentconstTargetLowering*TLI;public:staticcharID;// Pass identification, replacement for typeidexplicitLowerInvoke(constTargetLowering*tli=NULL):FunctionPass((intptr_t)&ID),TLI(tli){}booldoInitialization(Module&M);boolrunOnFunction(Function&F);virtualvoidgetAnalysisUsage(AnalysisUsage&AU)const{// This is a cluster of orthogonal TransformsAU.addPreservedID(PromoteMemoryToRegisterID);AU.addPreservedID(LowerSelectID);AU.addPreservedID(LowerSwitchID);AU.addPreservedID(LowerAllocationsID);}private:voidcreateAbortMessage(Module*M);voidwriteAbortMessage(Instruction*IB);boolinsertCheapEHSupport(Function&F);voidsplitLiveRangesLiveAcrossInvokes(std::vector<InvokeInst*>&Invokes);voidrewriteExpensiveInvoke(InvokeInst*II,unsignedInvokeNo,AllocaInst*InvokeNum,SwitchInst*CatchSwitch);boolinsertExpensiveEHSupport(Function&F);};charLowerInvoke::ID=0;RegisterPass<LowerInvoke>X("lowerinvoke","Lower invoke and unwind, for unwindless code generators");}constPassInfo*llvm::LowerInvokePassID=X.getPassInfo();// Public Interface To the LowerInvoke pass.FunctionPass*llvm::createLowerInvokePass(constTargetLowering*TLI){returnnewLowerInvoke(TLI);}// doInitialization - Make sure that there is a prototype for abort in the// current module.boolLowerInvoke::doInitialization(Module&M){constType*VoidPtrTy=PointerType::getUnqual(Type::Int8Ty);AbortMessage=0;if(ExpensiveEHSupport){// Insert a type for the linked list of jump buffers.unsignedJBSize=TLI?TLI->getJumpBufSize():0;JBSize=JBSize?JBSize:200;constType*JmpBufTy=ArrayType::get(VoidPtrTy,JBSize);{// The type is recursive, so use a type holder.std::vector<constType*>Elements;Elements.push_back(JmpBufTy);OpaqueType*OT=OpaqueType::get();Elements.push_back(PointerType::getUnqual(OT));PATypeHolderJBLType(StructType::get(Elements));OT->refineAbstractTypeTo(JBLType.get());// Complete the cycle.JBLinkTy=JBLType.get();M.addTypeName("llvm.sjljeh.jmpbufty",JBLinkTy);}constType*PtrJBList=PointerType::getUnqual(JBLinkTy);// Now that we've done that, insert the jmpbuf list head global, unless it// already exists.if(!(JBListHead=M.getGlobalVariable("llvm.sjljeh.jblist",PtrJBList))){JBListHead=newGlobalVariable(PtrJBList,false,GlobalValue::LinkOnceLinkage,Constant::getNullValue(PtrJBList),"llvm.sjljeh.jblist",&M);}SetJmpFn=M.getOrInsertFunction("llvm.setjmp",Type::Int32Ty,PointerType::getUnqual(JmpBufTy),(Type*)0);LongJmpFn=M.getOrInsertFunction("llvm.longjmp",Type::VoidTy,PointerType::getUnqual(JmpBufTy),Type::Int32Ty,(Type*)0);}// We need the 'write' and 'abort' functions for both models.AbortFn=M.getOrInsertFunction("abort",Type::VoidTy,(Type*)0);#if 0 // "write" is Unix-specific.. code is going away soon anyway. WriteFn = M.getOrInsertFunction("write", Type::VoidTy, Type::Int32Ty, VoidPtrTy, Type::Int32Ty, (Type *)0);#elseWriteFn=0;#endifreturntrue;}voidLowerInvoke::createAbortMessage(Module*M){if(ExpensiveEHSupport){// The abort message for expensive EH support tells the user that the// program 'unwound' without an 'invoke' instruction.Constant*Msg=ConstantArray::get("ERROR: Exception thrown, but not caught!\n");AbortMessageLength=Msg->getNumOperands()-1;// don't include \0GlobalVariable*MsgGV=newGlobalVariable(Msg->getType(),true,GlobalValue::InternalLinkage,Msg,"abortmsg",M);std::vector<Constant*>GEPIdx(2,Constant::getNullValue(Type::Int32Ty));AbortMessage=ConstantExpr::getGetElementPtr(MsgGV,&GEPIdx[0],2);}else{// The abort message for cheap EH support tells the user that EH is not// enabled.Constant*Msg=ConstantArray::get("Exception handler needed, but not enabled. Recompile"" program with -enable-correct-eh-support.\n");AbortMessageLength=Msg->getNumOperands()-1;// don't include \0GlobalVariable*MsgGV=newGlobalVariable(Msg->getType(),true,GlobalValue::InternalLinkage,Msg,"abortmsg",M);std::vector<Constant*>GEPIdx(2,Constant::getNullValue(Type::Int32Ty));AbortMessage=ConstantExpr::getGetElementPtr(MsgGV,&GEPIdx[0],2);}}voidLowerInvoke::writeAbortMessage(Instruction*IB){#if 0 if (AbortMessage == 0) createAbortMessage(IB->getParent()->getParent()->getParent()); // These are the arguments we WANT... Value* Args[3]; Args[0] = ConstantInt::get(Type::Int32Ty, 2); Args[1] = AbortMessage; Args[2] = ConstantInt::get(Type::Int32Ty, AbortMessageLength); (new CallInst(WriteFn, Args, 3, "", IB))->setTailCall();#endif}boolLowerInvoke::insertCheapEHSupport(Function&F){boolChanged=false;for(Function::iteratorBB=F.begin(),E=F.end();BB!=E;++BB)if(InvokeInst*II=dyn_cast<InvokeInst>(BB->getTerminator())){std::vector<Value*>CallArgs(II->op_begin()+3,II->op_end());// Insert a normal call instruction...CallInst*NewCall=newCallInst(II->getCalledValue(),CallArgs.begin(),CallArgs.end(),"",II);NewCall->takeName(II);NewCall->setCallingConv(II->getCallingConv());NewCall->setParamAttrs(II->getParamAttrs());II->replaceAllUsesWith(NewCall);// Insert an unconditional branch to the normal destination.newBranchInst(II->getNormalDest(),II);// Remove any PHI node entries from the exception destination.II->getUnwindDest()->removePredecessor(BB);// Remove the invoke instruction now.BB->getInstList().erase(II);++NumInvokes;Changed=true;}elseif(UnwindInst*UI=dyn_cast<UnwindInst>(BB->getTerminator())){// Insert a new call to write(2, AbortMessage, AbortMessageLength);writeAbortMessage(UI);// Insert a call to abort()(newCallInst(AbortFn,"",UI))->setTailCall();// Insert a return instruction. This really should be a "barrier", as it// is unreachable.newReturnInst(F.getReturnType()==Type::VoidTy?0:Constant::getNullValue(F.getReturnType()),UI);// Remove the unwind instruction now.BB->getInstList().erase(UI);++NumUnwinds;Changed=true;}returnChanged;}/// rewriteExpensiveInvoke - Insert code and hack the function to replace the/// specified invoke instruction with a call.voidLowerInvoke::rewriteExpensiveInvoke(InvokeInst*II,unsignedInvokeNo,AllocaInst*InvokeNum,SwitchInst*CatchSwitch){ConstantInt*InvokeNoC=ConstantInt::get(Type::Int32Ty,InvokeNo);// Insert a store of the invoke num before the invoke and store zero into the// location afterward.newStoreInst(InvokeNoC,InvokeNum,true,II);// volatileBasicBlock::iteratorNI=II->getNormalDest()->begin();while(isa<PHINode>(NI))++NI;// nonvolatile.newStoreInst(Constant::getNullValue(Type::Int32Ty),InvokeNum,false,NI);// Add a switch case to our unwind block.CatchSwitch->addCase(InvokeNoC,II->getUnwindDest());// Insert a normal call instruction.std::vector<Value*>CallArgs(II->op_begin()+3,II->op_end());CallInst*NewCall=newCallInst(II->getCalledValue(),CallArgs.begin(),CallArgs.end(),"",II);NewCall->takeName(II);NewCall->setCallingConv(II->getCallingConv());NewCall->setParamAttrs(II->getParamAttrs());II->replaceAllUsesWith(NewCall);// Replace the invoke with an uncond branch.newBranchInst(II->getNormalDest(),NewCall->getParent());II->eraseFromParent();}/// MarkBlocksLiveIn - Insert BB and all of its predescessors into LiveBBs until/// we reach blocks we've already seen.staticvoidMarkBlocksLiveIn(BasicBlock*BB,std::set<BasicBlock*>&LiveBBs){if(!LiveBBs.insert(BB).second)return;// already been here.for(pred_iteratorPI=pred_begin(BB),E=pred_end(BB);PI!=E;++PI)MarkBlocksLiveIn(*PI,LiveBBs);}// First thing we need to do is scan the whole function for values that are// live across unwind edges. Each value that is live across an unwind edge// we spill into a stack location, guaranteeing that there is nothing live// across the unwind edge. This process also splits all critical edges// coming out of invoke's.voidLowerInvoke::splitLiveRangesLiveAcrossInvokes(std::vector<InvokeInst*>&Invokes){// First step, split all critical edges from invoke instructions.for(unsignedi=0,e=Invokes.size();i!=e;++i){InvokeInst*II=Invokes[i];SplitCriticalEdge(II,0,this);SplitCriticalEdge(II,1,this);assert(!isa<PHINode>(II->getNormalDest())&&!isa<PHINode>(II->getUnwindDest())&&"critical edge splitting left single entry phi nodes?");}Function*F=Invokes.back()->getParent()->getParent();// To avoid having to handle incoming arguments specially, we lower each arg// to a copy instruction in the entry block. This ensures that the argument// value itself cannot be live across the entry block.BasicBlock::iteratorAfterAllocaInsertPt=F->begin()->begin();while(isa<AllocaInst>(AfterAllocaInsertPt)&&isa<ConstantInt>(cast<AllocaInst>(AfterAllocaInsertPt)->getArraySize()))++AfterAllocaInsertPt;for(Function::arg_iteratorAI=F->arg_begin(),E=F->arg_end();AI!=E;++AI){// This is always a no-op cast because we're casting AI to AI->getType() so// src and destination types are identical. BitCast is the only possibility.CastInst*NC=newBitCastInst(AI,AI->getType(),AI->getName()+".tmp",AfterAllocaInsertPt);AI->replaceAllUsesWith(NC);// Normally its is forbidden to replace a CastInst's operand because it// could cause the opcode to reflect an illegal conversion. However, we're// replacing it here with the same value it was constructed with to simply// make NC its user.NC->setOperand(0,AI);}// Finally, scan the code looking for instructions with bad live ranges.for(Function::iteratorBB=F->begin(),E=F->end();BB!=E;++BB)for(BasicBlock::iteratorII=BB->begin(),E=BB->end();II!=E;++II){// Ignore obvious cases we don't have to handle. In particular, most// instructions either have no uses or only have a single use inside the// current block. Ignore them quickly.Instruction*Inst=II;if(Inst->use_empty())continue;if(Inst->hasOneUse()&&cast<Instruction>(Inst->use_back())->getParent()==BB&&!isa<PHINode>(Inst->use_back()))continue;// If this is an alloca in the entry block, it's not a real register// value.if(AllocaInst*AI=dyn_cast<AllocaInst>(Inst))if(isa<ConstantInt>(AI->getArraySize())&&BB==F->begin())continue;// Avoid iterator invalidation by copying users to a temporary vector.std::vector<Instruction*>Users;for(Value::use_iteratorUI=Inst->use_begin(),E=Inst->use_end();UI!=E;++UI){Instruction*User=cast<Instruction>(*UI);if(User->getParent()!=BB||isa<PHINode>(User))Users.push_back(User);}// Scan all of the uses and see if the live range is live across an unwind// edge. If we find a use live across an invoke edge, create an alloca// and spill the value.std::set<InvokeInst*>InvokesWithStoreInserted;// Find all of the blocks that this value is live in.std::set<BasicBlock*>LiveBBs;LiveBBs.insert(Inst->getParent());while(!Users.empty()){Instruction*U=Users.back();Users.pop_back();if(!isa<PHINode>(U)){MarkBlocksLiveIn(U->getParent(),LiveBBs);}else{// Uses for a PHI node occur in their predecessor block.PHINode*PN=cast<PHINode>(U);for(unsignedi=0,e=PN->getNumIncomingValues();i!=e;++i)if(PN->getIncomingValue(i)==Inst)MarkBlocksLiveIn(PN->getIncomingBlock(i),LiveBBs);}}// Now that we know all of the blocks that this thing is live in, see if// it includes any of the unwind locations.boolNeedsSpill=false;for(unsignedi=0,e=Invokes.size();i!=e;++i){BasicBlock*UnwindBlock=Invokes[i]->getUnwindDest();if(UnwindBlock!=BB&&LiveBBs.count(UnwindBlock)){NeedsSpill=true;}}// If we decided we need a spill, do it.if(NeedsSpill){++NumSpilled;DemoteRegToStack(*Inst,true);}}}boolLowerInvoke::insertExpensiveEHSupport(Function&F){std::vector<ReturnInst*>Returns;std::vector<UnwindInst*>Unwinds;std::vector<InvokeInst*>Invokes;for(Function::iteratorBB=F.begin(),E=F.end();BB!=E;++BB)if(ReturnInst*RI=dyn_cast<ReturnInst>(BB->getTerminator())){// Remember all return instructions in case we insert an invoke into this// function.Returns.push_back(RI);}elseif(InvokeInst*II=dyn_cast<InvokeInst>(BB->getTerminator())){Invokes.push_back(II);}elseif(UnwindInst*UI=dyn_cast<UnwindInst>(BB->getTerminator())){Unwinds.push_back(UI);}if(Unwinds.empty()&&Invokes.empty())returnfalse;NumInvokes+=Invokes.size();NumUnwinds+=Unwinds.size();// TODO: This is not an optimal way to do this. In particular, this always// inserts setjmp calls into the entries of functions with invoke instructions// even though there are possibly paths through the function that do not// execute any invokes. In particular, for functions with early exits, e.g.// the 'addMove' method in hexxagon, it would be nice to not have to do the// setjmp stuff on the early exit path. This requires a bit of dataflow, but// would not be too hard to do.// If we have an invoke instruction, insert a setjmp that dominates all// invokes. After the setjmp, use a cond branch that goes to the original// code path on zero, and to a designated 'catch' block of nonzero.Value*OldJmpBufPtr=0;if(!Invokes.empty()){// First thing we need to do is scan the whole function for values that are// live across unwind edges. Each value that is live across an unwind edge// we spill into a stack location, guaranteeing that there is nothing live// across the unwind edge. This process also splits all critical edges// coming out of invoke's.splitLiveRangesLiveAcrossInvokes(Invokes);BasicBlock*EntryBB=F.begin();// Create an alloca for the incoming jump buffer ptr and the new jump buffer// that needs to be restored on all exits from the function. This is an// alloca because the value needs to be live across invokes.unsignedAlign=TLI?TLI->getJumpBufAlignment():0;AllocaInst*JmpBuf=newAllocaInst(JBLinkTy,0,Align,"jblink",F.begin()->begin());std::vector<Value*>Idx;Idx.push_back(Constant::getNullValue(Type::Int32Ty));Idx.push_back(ConstantInt::get(Type::Int32Ty,1));OldJmpBufPtr=newGetElementPtrInst(JmpBuf,Idx.begin(),Idx.end(),"OldBuf",EntryBB->getTerminator());// Copy the JBListHead to the alloca.Value*OldBuf=newLoadInst(JBListHead,"oldjmpbufptr",true,EntryBB->getTerminator());newStoreInst(OldBuf,OldJmpBufPtr,true,EntryBB->getTerminator());// Add the new jumpbuf to the list.newStoreInst(JmpBuf,JBListHead,true,EntryBB->getTerminator());// Create the catch block. The catch block is basically a big switch// statement that goes to all of the invoke catch blocks.BasicBlock*CatchBB=newBasicBlock("setjmp.catch",&F);// Create an alloca which keeps track of which invoke is currently// executing. For normal calls it contains zero.AllocaInst*InvokeNum=newAllocaInst(Type::Int32Ty,0,"invokenum",EntryBB->begin());newStoreInst(ConstantInt::get(Type::Int32Ty,0),InvokeNum,true,EntryBB->getTerminator());// Insert a load in the Catch block, and a switch on its value. By default,// we go to a block that just does an unwind (which is the correct action// for a standard call).BasicBlock*UnwindBB=newBasicBlock("unwindbb",&F);Unwinds.push_back(newUnwindInst(UnwindBB));Value*CatchLoad=newLoadInst(InvokeNum,"invoke.num",true,CatchBB);SwitchInst*CatchSwitch=newSwitchInst(CatchLoad,UnwindBB,Invokes.size(),CatchBB);// Now that things are set up, insert the setjmp call itself.// Split the entry block to insert the conditional branch for the setjmp.BasicBlock*ContBlock=EntryBB->splitBasicBlock(EntryBB->getTerminator(),"setjmp.cont");Idx[1]=ConstantInt::get(Type::Int32Ty,0);Value*JmpBufPtr=newGetElementPtrInst(JmpBuf,Idx.begin(),Idx.end(),"TheJmpBuf",EntryBB->getTerminator());Value*SJRet=newCallInst(SetJmpFn,JmpBufPtr,"sjret",EntryBB->getTerminator());// Compare the return value to zero.Value*IsNormal=newICmpInst(ICmpInst::ICMP_EQ,SJRet,Constant::getNullValue(SJRet->getType()),"notunwind",EntryBB->getTerminator());// Nuke the uncond branch.EntryBB->getTerminator()->eraseFromParent();// Put in a new condbranch in its place.newBranchInst(ContBlock,CatchBB,IsNormal,EntryBB);// At this point, we are all set up, rewrite each invoke instruction.for(unsignedi=0,e=Invokes.size();i!=e;++i)rewriteExpensiveInvoke(Invokes[i],i+1,InvokeNum,CatchSwitch);}// We know that there is at least one unwind.// Create three new blocks, the block to load the jmpbuf ptr and compare// against null, the block to do the longjmp, and the error block for if it// is null. Add them at the end of the function because they are not hot.BasicBlock*UnwindHandler=newBasicBlock("dounwind",&F);BasicBlock*UnwindBlock=newBasicBlock("unwind",&F);BasicBlock*TermBlock=newBasicBlock("unwinderror",&F);// If this function contains an invoke, restore the old jumpbuf ptr.Value*BufPtr;if(OldJmpBufPtr){// Before the return, insert a copy from the saved value to the new value.BufPtr=newLoadInst(OldJmpBufPtr,"oldjmpbufptr",UnwindHandler);newStoreInst(BufPtr,JBListHead,UnwindHandler);}else{BufPtr=newLoadInst(JBListHead,"ehlist",UnwindHandler);}// Load the JBList, if it's null, then there was no catch!Value*NotNull=newICmpInst(ICmpInst::ICMP_NE,BufPtr,Constant::getNullValue(BufPtr->getType()),"notnull",UnwindHandler);newBranchInst(UnwindBlock,TermBlock,NotNull,UnwindHandler);// Create the block to do the longjmp.// Get a pointer to the jmpbuf and longjmp.std::vector<Value*>Idx;Idx.push_back(Constant::getNullValue(Type::Int32Ty));Idx.push_back(ConstantInt::get(Type::Int32Ty,0));Idx[0]=newGetElementPtrInst(BufPtr,Idx.begin(),Idx.end(),"JmpBuf",UnwindBlock);Idx[1]=ConstantInt::get(Type::Int32Ty,1);newCallInst(LongJmpFn,Idx.begin(),Idx.end(),"",UnwindBlock);newUnreachableInst(UnwindBlock);// Set up the term block ("throw without a catch").newUnreachableInst(TermBlock);// Insert a new call to write(2, AbortMessage, AbortMessageLength);writeAbortMessage(TermBlock->getTerminator());// Insert a call to abort()(newCallInst(AbortFn,"",TermBlock->getTerminator()))->setTailCall();// Replace all unwinds with a branch to the unwind handler.for(unsignedi=0,e=Unwinds.size();i!=e;++i){newBranchInst(UnwindHandler,Unwinds[i]);Unwinds[i]->eraseFromParent();}// Finally, for any returns from this function, if this function contains an// invoke, restore the old jmpbuf pointer to its input value.if(OldJmpBufPtr){for(unsignedi=0,e=Returns.size();i!=e;++i){ReturnInst*R=Returns[i];// Before the return, insert a copy from the saved value to the new value.Value*OldBuf=newLoadInst(OldJmpBufPtr,"oldjmpbufptr",true,R);newStoreInst(OldBuf,JBListHead,true,R);}}returntrue;}boolLowerInvoke::runOnFunction(Function&F){if(ExpensiveEHSupport)returninsertExpensiveEHSupport(F);elsereturninsertCheapEHSupport(F);}