Coverage Report

Created: 2019-07-24 05:18

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