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