Adding implementation to outline C++ catch handlers for native Windows 64 exception...
[oota-llvm.git] / lib / CodeGen / WinEHPrepare.cpp
1 //===-- WinEHPrepare - Prepare exception handling for code generation ---===//\r
2 //\r
3 //                     The LLVM Compiler Infrastructure\r
4 //\r
5 // This file is distributed under the University of Illinois Open Source\r
6 // License. See LICENSE.TXT for details.\r
7 //\r
8 //===----------------------------------------------------------------------===//\r
9 //\r
10 // This pass lowers LLVM IR exception handling into something closer to what the\r
11 // backend wants. It snifs the personality function to see which kind of\r
12 // preparation is necessary. If the personality function uses the Itanium LSDA,\r
13 // this pass delegates to the DWARF EH preparation pass.\r
14 //\r
15 //===----------------------------------------------------------------------===//\r
16 \r
17 #include "llvm/CodeGen/Passes.h"\r
18 #include "llvm/Analysis/LibCallSemantics.h"\r
19 #include "llvm/IR/Function.h"\r
20 #include "llvm/IR/IRBuilder.h"\r
21 #include "llvm/IR/Instructions.h"\r
22 #include "llvm/IR/IntrinsicInst.h"\r
23 #include "llvm/IR/Module.h"\r
24 #include "llvm/IR/PatternMatch.h"\r
25 #include "llvm/Pass.h"\r
26 #include "llvm/Transforms/Utils/Cloning.h"\r
27 #include "llvm/Transforms/Utils/Local.h"\r
28 #include <memory>\r
29 \r
30 using namespace llvm;\r
31 using namespace llvm::PatternMatch;\r
32 \r
33 #define DEBUG_TYPE "winehprepare"\r
34 \r
35 namespace {\r
36 class WinEHPrepare : public FunctionPass {\r
37   std::unique_ptr<FunctionPass> DwarfPrepare;\r
38 \r
39 public:\r
40   static char ID; // Pass identification, replacement for typeid.\r
41   WinEHPrepare(const TargetMachine *TM = nullptr)\r
42       : FunctionPass(ID), DwarfPrepare(createDwarfEHPass(TM)) {}\r
43 \r
44   bool runOnFunction(Function &Fn) override;\r
45 \r
46   bool doFinalization(Module &M) override;\r
47 \r
48   void getAnalysisUsage(AnalysisUsage &AU) const override;\r
49 \r
50   const char *getPassName() const override {\r
51     return "Windows exception handling preparation";\r
52   }\r
53 \r
54 private:\r
55   bool prepareCPPEHHandlers(Function &F,\r
56                             SmallVectorImpl<LandingPadInst *> &LPads);\r
57   bool outlineCatchHandler(Function *SrcFn, Constant *SelectorType,\r
58                            LandingPadInst *LPad, StructType *EHDataStructTy);\r
59 };\r
60 \r
61 class WinEHCatchDirector : public CloningDirector {\r
62 public:\r
63   WinEHCatchDirector(LandingPadInst *LPI, Function *CatchFn, Value *Selector,\r
64                      Value *EHObj)\r
65       : LPI(LPI), CatchFn(CatchFn),\r
66         CurrentSelector(Selector->stripPointerCasts()), EHObj(EHObj),\r
67         SelectorIDType(Type::getInt32Ty(LPI->getContext())),\r
68         Int8PtrType(Type::getInt8PtrTy(LPI->getContext())) {}\r
69   virtual ~WinEHCatchDirector() {}\r
70 \r
71   CloningAction handleInstruction(ValueToValueMapTy &VMap,\r
72                                   const Instruction *Inst,\r
73                                   BasicBlock *NewBB) override;\r
74 \r
75 private:\r
76   LandingPadInst *LPI;\r
77   Function *CatchFn;\r
78   Value *CurrentSelector;\r
79   Value *EHObj;\r
80   Type *SelectorIDType;\r
81   Type *Int8PtrType;\r
82 \r
83   const Value *ExtractedEHPtr;\r
84   const Value *ExtractedSelector;\r
85   const Value *EHPtrStoreAddr;\r
86   const Value *SelectorStoreAddr;\r
87   const Value *EHObjStoreAddr;\r
88 };\r
89 } // end anonymous namespace\r
90 \r
91 char WinEHPrepare::ID = 0;\r
92 INITIALIZE_TM_PASS(WinEHPrepare, "winehprepare", "Prepare Windows exceptions",\r
93                    false, false)\r
94 \r
95 FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) {\r
96   return new WinEHPrepare(TM);\r
97 }\r
98 \r
99 static bool isMSVCPersonality(EHPersonality Pers) {\r
100   return Pers == EHPersonality::MSVC_Win64SEH ||\r
101          Pers == EHPersonality::MSVC_CXX;\r
102 }\r
103 \r
104 bool WinEHPrepare::runOnFunction(Function &Fn) {\r
105   SmallVector<LandingPadInst *, 4> LPads;\r
106   SmallVector<ResumeInst *, 4> Resumes;\r
107   for (BasicBlock &BB : Fn) {\r
108     if (auto *LP = BB.getLandingPadInst())\r
109       LPads.push_back(LP);\r
110     if (auto *Resume = dyn_cast<ResumeInst>(BB.getTerminator()))\r
111       Resumes.push_back(Resume);\r
112   }\r
113 \r
114   // No need to prepare functions that lack landing pads.\r
115   if (LPads.empty())\r
116     return false;\r
117 \r
118   // Classify the personality to see what kind of preparation we need.\r
119   EHPersonality Pers = classifyEHPersonality(LPads.back()->getPersonalityFn());\r
120 \r
121   // Delegate through to the DWARF pass if this is unrecognized.\r
122   if (!isMSVCPersonality(Pers))\r
123     return DwarfPrepare->runOnFunction(Fn);\r
124 \r
125   // FIXME: This only returns true if the C++ EH handlers were outlined.\r
126   //        When that code is complete, it should always return whatever\r
127   //        prepareCPPEHHandlers returns.\r
128   if (Pers == EHPersonality::MSVC_CXX && prepareCPPEHHandlers(Fn, LPads))\r
129     return true;\r
130 \r
131   // FIXME: SEH Cleanups are unimplemented. Replace them with unreachable.\r
132   if (Resumes.empty())\r
133     return false;\r
134 \r
135   for (ResumeInst *Resume : Resumes) {\r
136     IRBuilder<>(Resume).CreateUnreachable();\r
137     Resume->eraseFromParent();\r
138   }\r
139 \r
140   return true;\r
141 }\r
142 \r
143 bool WinEHPrepare::doFinalization(Module &M) {\r
144   return DwarfPrepare->doFinalization(M);\r
145 }\r
146 \r
147 void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {\r
148   DwarfPrepare->getAnalysisUsage(AU);\r
149 }\r
150 \r
151 bool WinEHPrepare::prepareCPPEHHandlers(\r
152     Function &F, SmallVectorImpl<LandingPadInst *> &LPads) {\r
153   // FIXME: Find all frame variable references in the handlers\r
154   //        to populate the structure elements.\r
155   SmallVector<Type *, 2> AllocStructTys;\r
156   AllocStructTys.push_back(Type::getInt32Ty(F.getContext()));   // EH state\r
157   AllocStructTys.push_back(Type::getInt8PtrTy(F.getContext())); // EH object\r
158   StructType *EHDataStructTy =\r
159       StructType::create(F.getContext(), AllocStructTys, \r
160                          "struct." + F.getName().str() + ".ehdata");\r
161   bool HandlersOutlined = false;\r
162 \r
163   for (LandingPadInst *LPad : LPads) {\r
164     // Look for evidence that this landingpad has already been processed.\r
165     bool LPadHasActionList = false;\r
166     BasicBlock *LPadBB = LPad->getParent();\r
167     for (Instruction &Inst : LPadBB->getInstList()) {\r
168       // FIXME: Make this an intrinsic.\r
169       if (auto *Call = dyn_cast<CallInst>(&Inst))\r
170         if (Call->getCalledFunction()->getName() == "llvm.eh.actions") {\r
171           LPadHasActionList = true;\r
172           break;\r
173         }\r
174     }\r
175 \r
176     // If we've already outlined the handlers for this landingpad,\r
177     // there's nothing more to do here.\r
178     if (LPadHasActionList)\r
179       continue;\r
180 \r
181     for (unsigned Idx = 0, NumClauses = LPad->getNumClauses(); Idx < NumClauses;\r
182          ++Idx) {\r
183       if (LPad->isCatch(Idx))\r
184         HandlersOutlined =\r
185             outlineCatchHandler(&F, LPad->getClause(Idx), LPad, EHDataStructTy);\r
186     } // End for each clause\r
187   }   // End for each landingpad\r
188 \r
189   return HandlersOutlined;\r
190 }\r
191 \r
192 bool WinEHPrepare::outlineCatchHandler(Function *SrcFn, Constant *SelectorType,\r
193                                        LandingPadInst *LPad,\r
194                                        StructType *EHDataStructTy) {\r
195   Module *M = SrcFn->getParent();\r
196   LLVMContext &Context = M->getContext();\r
197 \r
198   // Create a new function to receive the handler contents.\r
199   Type *Int8PtrType = Type::getInt8PtrTy(Context);\r
200   std::vector<Type *> ArgTys;\r
201   ArgTys.push_back(Int8PtrType);\r
202   ArgTys.push_back(Int8PtrType);\r
203   FunctionType *FnType = FunctionType::get(Int8PtrType, ArgTys, false);\r
204   Function *CatchHandler = Function::Create(\r
205       FnType, GlobalVariable::ExternalLinkage, SrcFn->getName() + ".catch", M);\r
206 \r
207   // Generate a standard prolog to setup the frame recovery structure.\r
208   IRBuilder<> Builder(Context);\r
209   BasicBlock *Entry = BasicBlock::Create(Context, "catch.entry");\r
210   CatchHandler->getBasicBlockList().push_front(Entry);\r
211   Builder.SetInsertPoint(Entry);\r
212   Builder.SetCurrentDebugLocation(LPad->getDebugLoc());\r
213 \r
214   // The outlined handler will be called with the parent's frame pointer as\r
215   // its second argument. To enable the handler to access variables from\r
216   // the parent frame, we use that pointer to get locate a special block\r
217   // of memory that was allocated using llvm.eh.allocateframe for this\r
218   // purpose.  During the outlining process we will determine which frame\r
219   // variables are used in handlers and create a structure that maps these\r
220   // variables into the frame allocation block.\r
221   //\r
222   // The frame allocation block also contains an exception state variable\r
223   // used by the runtime and a pointer to the exception object pointer\r
224   // which will be filled in by the runtime for use in the handler.\r
225   Function *RecoverFrameFn =\r
226       Intrinsic::getDeclaration(M, Intrinsic::framerecover);\r
227   Value *RecoverArgs[] = {Builder.CreateBitCast(SrcFn, Int8PtrType, ""),\r
228                           &(CatchHandler->getArgumentList().back())};\r
229   CallInst *EHAlloc =\r
230       Builder.CreateCall(RecoverFrameFn, RecoverArgs, "eh.alloc");\r
231   Value *EHData =\r
232       Builder.CreateBitCast(EHAlloc, EHDataStructTy->getPointerTo(), "ehdata");\r
233   Value *EHObjPtr =\r
234       Builder.CreateConstInBoundsGEP2_32(EHData, 0, 1, "eh.obj.ptr");\r
235 \r
236   // This will give us a raw pointer to the exception object, which\r
237   // corresponds to the formal parameter of the catch statement.  If the\r
238   // handler uses this object, we will generate code during the outlining\r
239   // process to cast the pointer to the appropriate type and deference it\r
240   // as necessary.  The un-outlined landing pad code represents the\r
241   // exception object as the result of the llvm.eh.begincatch call.\r
242   Value *EHObj = Builder.CreateLoad(EHObjPtr, false, "eh.obj");\r
243 \r
244   ValueToValueMapTy VMap;\r
245 \r
246   // FIXME: Map other values referenced in the filter handler.\r
247 \r
248   WinEHCatchDirector Director(LPad, CatchHandler, SelectorType, EHObj);\r
249 \r
250   SmallVector<ReturnInst *, 8> Returns;\r
251   ClonedCodeInfo InlinedFunctionInfo;\r
252 \r
253   BasicBlock::iterator II = LPad;\r
254 \r
255   CloneAndPruneIntoFromInst(CatchHandler, SrcFn, ++II, VMap,\r
256                             /*ModuleLevelChanges=*/false, Returns, "",\r
257                             &InlinedFunctionInfo,\r
258                             SrcFn->getParent()->getDataLayout(), &Director);\r
259 \r
260   // Move all the instructions in the first cloned block into our entry block.\r
261   BasicBlock *FirstClonedBB = std::next(Function::iterator(Entry));\r
262   Entry->getInstList().splice(Entry->end(), FirstClonedBB->getInstList());\r
263   FirstClonedBB->eraseFromParent();\r
264 \r
265   return true;\r
266 }\r
267 \r
268 CloningDirector::CloningAction WinEHCatchDirector::handleInstruction(\r
269     ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {\r
270   // Intercept instructions which extract values from the landing pad aggregate.\r
271   if (auto *Extract = dyn_cast<ExtractValueInst>(Inst)) {\r
272     if (Extract->getAggregateOperand() == LPI) {\r
273       assert(Extract->getNumIndices() == 1 &&\r
274              "Unexpected operation: extracting both landing pad values");\r
275       assert((*(Extract->idx_begin()) == 0 || *(Extract->idx_begin()) == 1) &&\r
276              "Unexpected operation: extracting an unknown landing pad element");\r
277 \r
278       if (*(Extract->idx_begin()) == 0) {\r
279         // Element 0 doesn't directly corresponds to anything in the WinEH scheme.\r
280         // It will be stored to a memory location, then later loaded and finally\r
281         // the loaded value will be used as the argument to an llvm.eh.begincatch\r
282         // call.  We're tracking it here so that we can skip the store and load.\r
283         ExtractedEHPtr = Inst;\r
284       } else {\r
285         // Element 1 corresponds to the filter selector.  We'll map it to 1 for\r
286         // matching purposes, but it will also probably be stored to memory and\r
287         // reloaded, so we need to track the instuction so that we can map the\r
288         // loaded value too.\r
289         VMap[Inst] = ConstantInt::get(SelectorIDType, 1);\r
290         ExtractedSelector = Inst;\r
291       }\r
292 \r
293       // Tell the caller not to clone this instruction.\r
294       return CloningDirector::SkipInstruction;\r
295     }\r
296     // Other extract value instructions just get cloned.\r
297     return CloningDirector::CloneInstruction;\r
298   }\r
299 \r
300   if (auto *Store = dyn_cast<StoreInst>(Inst)) {\r
301     // Look for and suppress stores of the extracted landingpad values.\r
302     const Value *StoredValue = Store->getValueOperand();\r
303     if (StoredValue == ExtractedEHPtr) {\r
304       EHPtrStoreAddr = Store->getPointerOperand();\r
305       return CloningDirector::SkipInstruction;\r
306     }\r
307     if (StoredValue == ExtractedSelector) {\r
308       SelectorStoreAddr = Store->getPointerOperand();\r
309       return CloningDirector::SkipInstruction;\r
310     }\r
311 \r
312     // Any other store just gets cloned.\r
313     return CloningDirector::CloneInstruction;\r
314   }\r
315 \r
316   if (auto *Load = dyn_cast<LoadInst>(Inst)) {\r
317     // Look for loads of (previously suppressed) landingpad values.\r
318     // The EHPtr load can be ignored (it should only be used as\r
319     // an argument to llvm.eh.begincatch), but the selector value\r
320     // needs to be mapped to a constant value of 1 to be used to\r
321     // simplify the branching to always flow to the current handler.\r
322     const Value *LoadAddr = Load->getPointerOperand();\r
323     if (LoadAddr == EHPtrStoreAddr) {\r
324       VMap[Inst] = UndefValue::get(Int8PtrType);\r
325       return CloningDirector::SkipInstruction;\r
326     }\r
327     if (LoadAddr == SelectorStoreAddr) {\r
328       VMap[Inst] = ConstantInt::get(SelectorIDType, 1);\r
329       return CloningDirector::SkipInstruction;\r
330     }\r
331 \r
332     // Any other loads just get cloned.\r
333     return CloningDirector::CloneInstruction;\r
334   }\r
335 \r
336   if (match(Inst, m_Intrinsic<Intrinsic::eh_begincatch>())) {\r
337     // The argument to the call is some form of the first element of the\r
338     // landingpad aggregate value, but that doesn't matter.  It isn't used\r
339     // here.\r
340     // The return value of this instruction, however, is used to access the\r
341     // EH object pointer.  We have generated an instruction to get that value\r
342     // from the EH alloc block, so we can just map to that here.\r
343     VMap[Inst] = EHObj;\r
344     return CloningDirector::SkipInstruction;\r
345   }\r
346   if (match(Inst, m_Intrinsic<Intrinsic::eh_endcatch>())) {\r
347     auto *IntrinCall = dyn_cast<IntrinsicInst>(Inst);\r
348     // It might be interesting to track whether or not we are inside a catch\r
349     // function, but that might make the algorithm more brittle than it needs\r
350     // to be.\r
351 \r
352     // The end catch call can occur in one of two places: either in a\r
353     // landingpad\r
354     // block that is part of the catch handlers exception mechanism, or at the\r
355     // end of the catch block.  If it occurs in a landing pad, we must skip it\r
356     // and continue so that the landing pad gets cloned.\r
357     // FIXME: This case isn't fully supported yet and shouldn't turn up in any\r
358     //        of the test cases until it is.\r
359     if (IntrinCall->getParent()->isLandingPad())\r
360       return CloningDirector::SkipInstruction;\r
361 \r
362     // If an end catch occurs anywhere else the next instruction should be an\r
363     // unconditional branch instruction that we want to replace with a return\r
364     // to the the address of the branch target.\r
365     const BasicBlock *EndCatchBB = IntrinCall->getParent();\r
366     const TerminatorInst *Terminator = EndCatchBB->getTerminator();\r
367     const BranchInst *Branch = dyn_cast<BranchInst>(Terminator);\r
368     assert(Branch && Branch->isUnconditional());\r
369     assert(std::next(BasicBlock::const_iterator(IntrinCall)) ==\r
370             BasicBlock::const_iterator(Branch));\r
371 \r
372     ReturnInst::Create(NewBB->getContext(),\r
373                         BlockAddress::get(Branch->getSuccessor(0)), NewBB);\r
374 \r
375     // We just added a terminator to the cloned block.\r
376     // Tell the caller to stop processing the current basic block so that\r
377     // the branch instruction will be skipped.\r
378     return CloningDirector::StopCloningBB;\r
379   }\r
380   if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>())) {\r
381     auto *IntrinCall = dyn_cast<IntrinsicInst>(Inst);\r
382     Value *Selector = IntrinCall->getArgOperand(0)->stripPointerCasts();\r
383     // This causes a replacement that will collapse the landing pad CFG based\r
384     // on the filter function we intend to match.\r
385     if (Selector == CurrentSelector)\r
386       VMap[Inst] = ConstantInt::get(SelectorIDType, 1);\r
387     else\r
388       VMap[Inst] = ConstantInt::get(SelectorIDType, 0);\r
389     // Tell the caller not to clone this instruction.\r
390     return CloningDirector::SkipInstruction;\r
391   }\r
392 \r
393   // Continue with the default cloning behavior.\r
394   return CloningDirector::CloneInstruction;\r
395 }\r