123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- //===-- DwarfEHPrepare - Prepare exception handling for code generation ---===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- //
- // This pass mulches exception handling code into a form adapted to code
- // generation. Required if using dwarf exception handling.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/CodeGen/Passes.h"
- #include "llvm/ADT/BitVector.h"
- #include "llvm/ADT/Statistic.h"
- #include "llvm/Analysis/CFG.h"
- #include "llvm/Analysis/LibCallSemantics.h"
- #include "llvm/Analysis/TargetTransformInfo.h"
- #include "llvm/IR/Dominators.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/Module.h"
- #include "llvm/Pass.h"
- #include "llvm/Target/TargetLowering.h"
- #include "llvm/Target/TargetSubtargetInfo.h"
- #include "llvm/Transforms/Utils/Local.h"
- using namespace llvm;
- #define DEBUG_TYPE "dwarfehprepare"
- STATISTIC(NumResumesLowered, "Number of resume calls lowered");
- namespace {
- class DwarfEHPrepare : public FunctionPass {
- const TargetMachine *TM;
- // RewindFunction - _Unwind_Resume or the target equivalent.
- Constant *RewindFunction;
- DominatorTree *DT;
- const TargetLowering *TLI;
- bool InsertUnwindResumeCalls(Function &Fn);
- Value *GetExceptionObject(ResumeInst *RI);
- size_t
- pruneUnreachableResumes(Function &Fn,
- SmallVectorImpl<ResumeInst *> &Resumes,
- SmallVectorImpl<LandingPadInst *> &CleanupLPads);
- public:
- static char ID; // Pass identification, replacement for typeid.
- // INITIALIZE_TM_PASS requires a default constructor, but it isn't used in
- // practice.
- DwarfEHPrepare()
- : FunctionPass(ID), TM(nullptr), RewindFunction(nullptr), DT(nullptr),
- TLI(nullptr) {}
- DwarfEHPrepare(const TargetMachine *TM)
- : FunctionPass(ID), TM(TM), RewindFunction(nullptr), DT(nullptr),
- TLI(nullptr) {}
- bool runOnFunction(Function &Fn) override;
- bool doFinalization(Module &M) override {
- RewindFunction = nullptr;
- return false;
- }
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- const char *getPassName() const override {
- return "Exception handling preparation";
- }
- };
- } // end anonymous namespace
- char DwarfEHPrepare::ID = 0;
- INITIALIZE_TM_PASS_BEGIN(DwarfEHPrepare, "dwarfehprepare",
- "Prepare DWARF exceptions", false, false)
- INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
- INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
- INITIALIZE_TM_PASS_END(DwarfEHPrepare, "dwarfehprepare",
- "Prepare DWARF exceptions", false, false)
- FunctionPass *llvm::createDwarfEHPass(const TargetMachine *TM) {
- return new DwarfEHPrepare(TM);
- }
- void DwarfEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<TargetTransformInfoWrapperPass>();
- AU.addRequired<DominatorTreeWrapperPass>();
- }
- /// GetExceptionObject - Return the exception object from the value passed into
- /// the 'resume' instruction (typically an aggregate). Clean up any dead
- /// instructions, including the 'resume' instruction.
- Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
- Value *V = RI->getOperand(0);
- Value *ExnObj = nullptr;
- InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
- LoadInst *SelLoad = nullptr;
- InsertValueInst *ExcIVI = nullptr;
- bool EraseIVIs = false;
- if (SelIVI) {
- if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
- ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
- if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
- ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
- ExnObj = ExcIVI->getOperand(1);
- SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
- EraseIVIs = true;
- }
- }
- }
- if (!ExnObj)
- ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
- RI->eraseFromParent();
- if (EraseIVIs) {
- if (SelIVI->use_empty())
- SelIVI->eraseFromParent();
- if (ExcIVI->use_empty())
- ExcIVI->eraseFromParent();
- if (SelLoad && SelLoad->use_empty())
- SelLoad->eraseFromParent();
- }
- return ExnObj;
- }
- /// Replace resumes that are not reachable from a cleanup landing pad with
- /// unreachable and then simplify those blocks.
- size_t DwarfEHPrepare::pruneUnreachableResumes(
- Function &Fn, SmallVectorImpl<ResumeInst *> &Resumes,
- SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
- BitVector ResumeReachable(Resumes.size());
- size_t ResumeIndex = 0;
- for (auto *RI : Resumes) {
- for (auto *LP : CleanupLPads) {
- if (isPotentiallyReachable(LP, RI, DT)) {
- ResumeReachable.set(ResumeIndex);
- break;
- }
- }
- ++ResumeIndex;
- }
- // If everything is reachable, there is no change.
- if (ResumeReachable.all())
- return Resumes.size();
- const TargetTransformInfo &TTI =
- getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn);
- LLVMContext &Ctx = Fn.getContext();
- // Otherwise, insert unreachable instructions and call simplifycfg.
- size_t ResumesLeft = 0;
- for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
- ResumeInst *RI = Resumes[I];
- if (ResumeReachable[I]) {
- Resumes[ResumesLeft++] = RI;
- } else {
- BasicBlock *BB = RI->getParent();
- new UnreachableInst(Ctx, RI);
- RI->eraseFromParent();
- SimplifyCFG(BB, TTI, 1);
- }
- }
- Resumes.resize(ResumesLeft);
- return ResumesLeft;
- }
- /// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present
- /// into calls to the appropriate _Unwind_Resume function.
- bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) {
- SmallVector<ResumeInst*, 16> Resumes;
- SmallVector<LandingPadInst*, 16> CleanupLPads;
- for (BasicBlock &BB : Fn) {
- if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
- Resumes.push_back(RI);
- if (auto *LP = BB.getLandingPadInst())
- if (LP->isCleanup())
- CleanupLPads.push_back(LP);
- }
- if (Resumes.empty())
- return false;
- // Check the personality, don't do anything if it's for MSVC.
- EHPersonality Pers = classifyEHPersonality(Fn.getPersonalityFn());
- if (isMSVCEHPersonality(Pers))
- return false;
- LLVMContext &Ctx = Fn.getContext();
- size_t ResumesLeft = pruneUnreachableResumes(Fn, Resumes, CleanupLPads);
- if (ResumesLeft == 0)
- return true; // We pruned them all.
- // Find the rewind function if we didn't already.
- if (!RewindFunction) {
- FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx),
- Type::getInt8PtrTy(Ctx), false);
- const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME);
- RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy);
- }
- // Create the basic block where the _Unwind_Resume call will live.
- if (ResumesLeft == 1) {
- // Instead of creating a new BB and PHI node, just append the call to
- // _Unwind_Resume to the end of the single resume block.
- ResumeInst *RI = Resumes.front();
- BasicBlock *UnwindBB = RI->getParent();
- Value *ExnObj = GetExceptionObject(RI);
- // Call the _Unwind_Resume function.
- CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB);
- CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
- // We never expect _Unwind_Resume to return.
- new UnreachableInst(Ctx, UnwindBB);
- return true;
- }
- BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn);
- PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft,
- "exn.obj", UnwindBB);
- // Extract the exception object from the ResumeInst and add it to the PHI node
- // that feeds the _Unwind_Resume call.
- for (ResumeInst *RI : Resumes) {
- BasicBlock *Parent = RI->getParent();
- BranchInst::Create(UnwindBB, Parent);
- Value *ExnObj = GetExceptionObject(RI);
- PN->addIncoming(ExnObj, Parent);
- ++NumResumesLowered;
- }
- // Call the function.
- CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB);
- CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
- // We never expect _Unwind_Resume to return.
- new UnreachableInst(Ctx, UnwindBB);
- return true;
- }
- bool DwarfEHPrepare::runOnFunction(Function &Fn) {
- assert(TM && "DWARF EH preparation requires a target machine");
- DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- TLI = TM->getSubtargetImpl(Fn)->getTargetLowering();
- bool Changed = InsertUnwindResumeCalls(Fn);
- DT = nullptr;
- TLI = nullptr;
- return Changed;
- }
|