DwarfEHPrepare.cpp revision dce4a407a24b04eebc6a376f8e62b41aaa7b071f
1//===-- DwarfEHPrepare - Prepare exception handling for code generation ---===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This pass mulches exception handling code into a form adapted to code 11// generation. Required if using dwarf exception handling. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/CodeGen/Passes.h" 16#include "llvm/ADT/Statistic.h" 17#include "llvm/IR/CallSite.h" 18#include "llvm/IR/Dominators.h" 19#include "llvm/IR/Function.h" 20#include "llvm/IR/Instructions.h" 21#include "llvm/IR/IntrinsicInst.h" 22#include "llvm/IR/Module.h" 23#include "llvm/MC/MCAsmInfo.h" 24#include "llvm/Pass.h" 25#include "llvm/Target/TargetLowering.h" 26#include "llvm/Transforms/Utils/BasicBlockUtils.h" 27#include "llvm/Transforms/Utils/SSAUpdater.h" 28using namespace llvm; 29 30#define DEBUG_TYPE "dwarfehprepare" 31 32STATISTIC(NumResumesLowered, "Number of resume calls lowered"); 33 34namespace { 35 class DwarfEHPrepare : public FunctionPass { 36 const TargetMachine *TM; 37 38 // RewindFunction - _Unwind_Resume or the target equivalent. 39 Constant *RewindFunction; 40 41 bool InsertUnwindResumeCalls(Function &Fn); 42 Value *GetExceptionObject(ResumeInst *RI); 43 44 public: 45 static char ID; // Pass identification, replacement for typeid. 46 DwarfEHPrepare(const TargetMachine *TM) 47 : FunctionPass(ID), TM(TM), RewindFunction(nullptr) { 48 initializeDominatorTreeWrapperPassPass(*PassRegistry::getPassRegistry()); 49 } 50 51 bool runOnFunction(Function &Fn) override; 52 53 void getAnalysisUsage(AnalysisUsage &AU) const override { } 54 55 const char *getPassName() const override { 56 return "Exception handling preparation"; 57 } 58 }; 59} // end anonymous namespace 60 61char DwarfEHPrepare::ID = 0; 62 63FunctionPass *llvm::createDwarfEHPass(const TargetMachine *TM) { 64 return new DwarfEHPrepare(TM); 65} 66 67/// GetExceptionObject - Return the exception object from the value passed into 68/// the 'resume' instruction (typically an aggregate). Clean up any dead 69/// instructions, including the 'resume' instruction. 70Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) { 71 Value *V = RI->getOperand(0); 72 Value *ExnObj = nullptr; 73 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V); 74 LoadInst *SelLoad = nullptr; 75 InsertValueInst *ExcIVI = nullptr; 76 bool EraseIVIs = false; 77 78 if (SelIVI) { 79 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) { 80 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0)); 81 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) && 82 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) { 83 ExnObj = ExcIVI->getOperand(1); 84 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1)); 85 EraseIVIs = true; 86 } 87 } 88 } 89 90 if (!ExnObj) 91 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI); 92 93 RI->eraseFromParent(); 94 95 if (EraseIVIs) { 96 if (SelIVI->getNumUses() == 0) 97 SelIVI->eraseFromParent(); 98 if (ExcIVI->getNumUses() == 0) 99 ExcIVI->eraseFromParent(); 100 if (SelLoad && SelLoad->getNumUses() == 0) 101 SelLoad->eraseFromParent(); 102 } 103 104 return ExnObj; 105} 106 107/// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present 108/// into calls to the appropriate _Unwind_Resume function. 109bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) { 110 SmallVector<ResumeInst*, 16> Resumes; 111 for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) { 112 TerminatorInst *TI = I->getTerminator(); 113 if (ResumeInst *RI = dyn_cast<ResumeInst>(TI)) 114 Resumes.push_back(RI); 115 } 116 117 if (Resumes.empty()) 118 return false; 119 120 // Find the rewind function if we didn't already. 121 const TargetLowering *TLI = TM->getTargetLowering(); 122 if (!RewindFunction) { 123 LLVMContext &Ctx = Resumes[0]->getContext(); 124 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), 125 Type::getInt8PtrTy(Ctx), false); 126 const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME); 127 RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy); 128 } 129 130 // Create the basic block where the _Unwind_Resume call will live. 131 LLVMContext &Ctx = Fn.getContext(); 132 unsigned ResumesSize = Resumes.size(); 133 134 if (ResumesSize == 1) { 135 // Instead of creating a new BB and PHI node, just append the call to 136 // _Unwind_Resume to the end of the single resume block. 137 ResumeInst *RI = Resumes.front(); 138 BasicBlock *UnwindBB = RI->getParent(); 139 Value *ExnObj = GetExceptionObject(RI); 140 141 // Call the _Unwind_Resume function. 142 CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB); 143 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 144 145 // We never expect _Unwind_Resume to return. 146 new UnreachableInst(Ctx, UnwindBB); 147 return true; 148 } 149 150 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn); 151 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesSize, 152 "exn.obj", UnwindBB); 153 154 // Extract the exception object from the ResumeInst and add it to the PHI node 155 // that feeds the _Unwind_Resume call. 156 for (SmallVectorImpl<ResumeInst*>::iterator 157 I = Resumes.begin(), E = Resumes.end(); I != E; ++I) { 158 ResumeInst *RI = *I; 159 BasicBlock *Parent = RI->getParent(); 160 BranchInst::Create(UnwindBB, Parent); 161 162 Value *ExnObj = GetExceptionObject(RI); 163 PN->addIncoming(ExnObj, Parent); 164 165 ++NumResumesLowered; 166 } 167 168 // Call the function. 169 CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB); 170 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 171 172 // We never expect _Unwind_Resume to return. 173 new UnreachableInst(Ctx, UnwindBB); 174 return true; 175} 176 177bool DwarfEHPrepare::runOnFunction(Function &Fn) { 178 bool Changed = InsertUnwindResumeCalls(Fn); 179 return Changed; 180} 181