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/BitVector.h"
17#include "llvm/ADT/Statistic.h"
18#include "llvm/Analysis/CFG.h"
19#include "llvm/Analysis/EHPersonalities.h"
20#include "llvm/Analysis/TargetTransformInfo.h"
21#include "llvm/IR/Dominators.h"
22#include "llvm/IR/Function.h"
23#include "llvm/IR/Instructions.h"
24#include "llvm/IR/Module.h"
25#include "llvm/Pass.h"
26#include "llvm/Target/TargetLowering.h"
27#include "llvm/Target/TargetSubtargetInfo.h"
28#include "llvm/Transforms/Utils/Local.h"
29using namespace llvm;
30
31#define DEBUG_TYPE "dwarfehprepare"
32
33STATISTIC(NumResumesLowered, "Number of resume calls lowered");
34
35namespace {
36  class DwarfEHPrepare : public FunctionPass {
37    const TargetMachine *TM;
38
39    // RewindFunction - _Unwind_Resume or the target equivalent.
40    Constant *RewindFunction;
41
42    DominatorTree *DT;
43    const TargetLowering *TLI;
44
45    bool InsertUnwindResumeCalls(Function &Fn);
46    Value *GetExceptionObject(ResumeInst *RI);
47    size_t
48    pruneUnreachableResumes(Function &Fn,
49                            SmallVectorImpl<ResumeInst *> &Resumes,
50                            SmallVectorImpl<LandingPadInst *> &CleanupLPads);
51
52  public:
53    static char ID; // Pass identification, replacement for typeid.
54
55    // INITIALIZE_TM_PASS requires a default constructor, but it isn't used in
56    // practice.
57    DwarfEHPrepare()
58        : FunctionPass(ID), TM(nullptr), RewindFunction(nullptr), DT(nullptr),
59          TLI(nullptr) {}
60
61    DwarfEHPrepare(const TargetMachine *TM)
62        : FunctionPass(ID), TM(TM), RewindFunction(nullptr), DT(nullptr),
63          TLI(nullptr) {}
64
65    bool runOnFunction(Function &Fn) override;
66
67    bool doFinalization(Module &M) override {
68      RewindFunction = nullptr;
69      return false;
70    }
71
72    void getAnalysisUsage(AnalysisUsage &AU) const override;
73
74    const char *getPassName() const override {
75      return "Exception handling preparation";
76    }
77  };
78} // end anonymous namespace
79
80char DwarfEHPrepare::ID = 0;
81INITIALIZE_TM_PASS_BEGIN(DwarfEHPrepare, "dwarfehprepare",
82                         "Prepare DWARF exceptions", false, false)
83INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
84INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
85INITIALIZE_TM_PASS_END(DwarfEHPrepare, "dwarfehprepare",
86                       "Prepare DWARF exceptions", false, false)
87
88FunctionPass *llvm::createDwarfEHPass(const TargetMachine *TM) {
89  return new DwarfEHPrepare(TM);
90}
91
92void DwarfEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
93  AU.addRequired<TargetTransformInfoWrapperPass>();
94  AU.addRequired<DominatorTreeWrapperPass>();
95}
96
97/// GetExceptionObject - Return the exception object from the value passed into
98/// the 'resume' instruction (typically an aggregate). Clean up any dead
99/// instructions, including the 'resume' instruction.
100Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
101  Value *V = RI->getOperand(0);
102  Value *ExnObj = nullptr;
103  InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
104  LoadInst *SelLoad = nullptr;
105  InsertValueInst *ExcIVI = nullptr;
106  bool EraseIVIs = false;
107
108  if (SelIVI) {
109    if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
110      ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
111      if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
112          ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
113        ExnObj = ExcIVI->getOperand(1);
114        SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
115        EraseIVIs = true;
116      }
117    }
118  }
119
120  if (!ExnObj)
121    ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
122
123  RI->eraseFromParent();
124
125  if (EraseIVIs) {
126    if (SelIVI->use_empty())
127      SelIVI->eraseFromParent();
128    if (ExcIVI->use_empty())
129      ExcIVI->eraseFromParent();
130    if (SelLoad && SelLoad->use_empty())
131      SelLoad->eraseFromParent();
132  }
133
134  return ExnObj;
135}
136
137/// Replace resumes that are not reachable from a cleanup landing pad with
138/// unreachable and then simplify those blocks.
139size_t DwarfEHPrepare::pruneUnreachableResumes(
140    Function &Fn, SmallVectorImpl<ResumeInst *> &Resumes,
141    SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
142  BitVector ResumeReachable(Resumes.size());
143  size_t ResumeIndex = 0;
144  for (auto *RI : Resumes) {
145    for (auto *LP : CleanupLPads) {
146      if (isPotentiallyReachable(LP, RI, DT)) {
147        ResumeReachable.set(ResumeIndex);
148        break;
149      }
150    }
151    ++ResumeIndex;
152  }
153
154  // If everything is reachable, there is no change.
155  if (ResumeReachable.all())
156    return Resumes.size();
157
158  const TargetTransformInfo &TTI =
159      getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn);
160  LLVMContext &Ctx = Fn.getContext();
161
162  // Otherwise, insert unreachable instructions and call simplifycfg.
163  size_t ResumesLeft = 0;
164  for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
165    ResumeInst *RI = Resumes[I];
166    if (ResumeReachable[I]) {
167      Resumes[ResumesLeft++] = RI;
168    } else {
169      BasicBlock *BB = RI->getParent();
170      new UnreachableInst(Ctx, RI);
171      RI->eraseFromParent();
172      SimplifyCFG(BB, TTI, 1);
173    }
174  }
175  Resumes.resize(ResumesLeft);
176  return ResumesLeft;
177}
178
179/// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present
180/// into calls to the appropriate _Unwind_Resume function.
181bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) {
182  SmallVector<ResumeInst*, 16> Resumes;
183  SmallVector<LandingPadInst*, 16> CleanupLPads;
184  for (BasicBlock &BB : Fn) {
185    if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
186      Resumes.push_back(RI);
187    if (auto *LP = BB.getLandingPadInst())
188      if (LP->isCleanup())
189        CleanupLPads.push_back(LP);
190  }
191
192  if (Resumes.empty())
193    return false;
194
195  // Check the personality, don't do anything if it's funclet-based.
196  EHPersonality Pers = classifyEHPersonality(Fn.getPersonalityFn());
197  if (isFuncletEHPersonality(Pers))
198    return false;
199
200  LLVMContext &Ctx = Fn.getContext();
201
202  size_t ResumesLeft = pruneUnreachableResumes(Fn, Resumes, CleanupLPads);
203  if (ResumesLeft == 0)
204    return true; // We pruned them all.
205
206  // Find the rewind function if we didn't already.
207  if (!RewindFunction) {
208    FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx),
209                                          Type::getInt8PtrTy(Ctx), false);
210    const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME);
211    RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy);
212  }
213
214  // Create the basic block where the _Unwind_Resume call will live.
215  if (ResumesLeft == 1) {
216    // Instead of creating a new BB and PHI node, just append the call to
217    // _Unwind_Resume to the end of the single resume block.
218    ResumeInst *RI = Resumes.front();
219    BasicBlock *UnwindBB = RI->getParent();
220    Value *ExnObj = GetExceptionObject(RI);
221
222    // Call the _Unwind_Resume function.
223    CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB);
224    CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
225
226    // We never expect _Unwind_Resume to return.
227    new UnreachableInst(Ctx, UnwindBB);
228    return true;
229  }
230
231  BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn);
232  PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft,
233                                "exn.obj", UnwindBB);
234
235  // Extract the exception object from the ResumeInst and add it to the PHI node
236  // that feeds the _Unwind_Resume call.
237  for (ResumeInst *RI : Resumes) {
238    BasicBlock *Parent = RI->getParent();
239    BranchInst::Create(UnwindBB, Parent);
240
241    Value *ExnObj = GetExceptionObject(RI);
242    PN->addIncoming(ExnObj, Parent);
243
244    ++NumResumesLowered;
245  }
246
247  // Call the function.
248  CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB);
249  CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
250
251  // We never expect _Unwind_Resume to return.
252  new UnreachableInst(Ctx, UnwindBB);
253  return true;
254}
255
256bool DwarfEHPrepare::runOnFunction(Function &Fn) {
257  assert(TM && "DWARF EH preparation requires a target machine");
258  DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
259  TLI = TM->getSubtargetImpl(Fn)->getTargetLowering();
260  bool Changed = InsertUnwindResumeCalls(Fn);
261  DT = nullptr;
262  TLI = nullptr;
263  return Changed;
264}
265