xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/X86WinEHState.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // All functions using an MSVC EH personality use an explicitly updated state
100b57cec5SDimitry Andric // number stored in an exception registration stack object. The registration
110b57cec5SDimitry Andric // object is linked into a thread-local chain of registrations stored at fs:00.
120b57cec5SDimitry Andric // This pass adds the registration object and EH state updates.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "X86.h"
170b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
180b57cec5SDimitry Andric #include "llvm/Analysis/CFG.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/WinEHFuncInfo.h"
215ffd83dbSDimitry Andric #include "llvm/IR/CFG.h"
2206c3fb27SDimitry Andric #include "llvm/IR/EHPersonalities.h"
230b57cec5SDimitry Andric #include "llvm/IR/Function.h"
240b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
250b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
26480093f4SDimitry Andric #include "llvm/IR/Intrinsics.h"
27480093f4SDimitry Andric #include "llvm/IR/IntrinsicsX86.h"
280b57cec5SDimitry Andric #include "llvm/IR/Module.h"
290b57cec5SDimitry Andric #include "llvm/Pass.h"
300b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
310b57cec5SDimitry Andric #include <deque>
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric using namespace llvm;
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric #define DEBUG_TYPE "winehstate"
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric namespace {
380b57cec5SDimitry Andric const int OverdefinedState = INT_MIN;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric class WinEHStatePass : public FunctionPass {
410b57cec5SDimitry Andric public:
420b57cec5SDimitry Andric   static char ID; // Pass identification, replacement for typeid.
430b57cec5SDimitry Andric 
WinEHStatePass()440b57cec5SDimitry Andric   WinEHStatePass() : FunctionPass(ID) { }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   bool runOnFunction(Function &Fn) override;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   bool doInitialization(Module &M) override;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   bool doFinalization(Module &M) override;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
530b57cec5SDimitry Andric 
getPassName() const540b57cec5SDimitry Andric   StringRef getPassName() const override {
550b57cec5SDimitry Andric     return "Windows 32-bit x86 EH state insertion";
560b57cec5SDimitry Andric   }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric private:
590b57cec5SDimitry Andric   void emitExceptionRegistrationRecord(Function *F);
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler);
620b57cec5SDimitry Andric   void unlinkExceptionRegistration(IRBuilder<> &Builder);
630b57cec5SDimitry Andric   void addStateStores(Function &F, WinEHFuncInfo &FuncInfo);
640b57cec5SDimitry Andric   void insertStateNumberStore(Instruction *IP, int State);
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   Function *generateLSDAInEAXThunk(Function *ParentFunc);
690b57cec5SDimitry Andric 
705ffd83dbSDimitry Andric   bool isStateStoreNeeded(EHPersonality Personality, CallBase &Call);
715ffd83dbSDimitry Andric   void rewriteSetJmpCall(IRBuilder<> &Builder, Function &F, CallBase &Call,
720b57cec5SDimitry Andric                          Value *State);
730b57cec5SDimitry Andric   int getBaseStateForBB(DenseMap<BasicBlock *, ColorVector> &BlockColors,
740b57cec5SDimitry Andric                         WinEHFuncInfo &FuncInfo, BasicBlock *BB);
755ffd83dbSDimitry Andric   int getStateForCall(DenseMap<BasicBlock *, ColorVector> &BlockColors,
765ffd83dbSDimitry Andric                       WinEHFuncInfo &FuncInfo, CallBase &Call);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   // Module-level type getters.
790b57cec5SDimitry Andric   Type *getEHLinkRegistrationType();
800b57cec5SDimitry Andric   Type *getSEHRegistrationType();
810b57cec5SDimitry Andric   Type *getCXXEHRegistrationType();
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   // Per-module data.
840b57cec5SDimitry Andric   Module *TheModule = nullptr;
850b57cec5SDimitry Andric   StructType *EHLinkRegistrationTy = nullptr;
860b57cec5SDimitry Andric   StructType *CXXEHRegistrationTy = nullptr;
870b57cec5SDimitry Andric   StructType *SEHRegistrationTy = nullptr;
880b57cec5SDimitry Andric   FunctionCallee SetJmp3 = nullptr;
890b57cec5SDimitry Andric   FunctionCallee CxxLongjmpUnwind = nullptr;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   // Per-function state
920b57cec5SDimitry Andric   EHPersonality Personality = EHPersonality::Unknown;
930b57cec5SDimitry Andric   Function *PersonalityFn = nullptr;
940b57cec5SDimitry Andric   bool UseStackGuard = false;
95480093f4SDimitry Andric   int ParentBaseState = 0;
960b57cec5SDimitry Andric   FunctionCallee SehLongjmpUnwind = nullptr;
970b57cec5SDimitry Andric   Constant *Cookie = nullptr;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   /// The stack allocation containing all EH data, including the link in the
1000b57cec5SDimitry Andric   /// fs:00 chain and the current state.
1010b57cec5SDimitry Andric   AllocaInst *RegNode = nullptr;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   // The allocation containing the EH security guard.
1040b57cec5SDimitry Andric   AllocaInst *EHGuardNode = nullptr;
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   /// The index of the state field of RegNode.
1070b57cec5SDimitry Andric   int StateFieldIndex = ~0U;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   /// The linked list node subobject inside of RegNode.
1100b57cec5SDimitry Andric   Value *Link = nullptr;
1110b57cec5SDimitry Andric };
112e8d8bef9SDimitry Andric } // namespace
1130b57cec5SDimitry Andric 
createX86WinEHStatePass()1140b57cec5SDimitry Andric FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric char WinEHStatePass::ID = 0;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric INITIALIZE_PASS(WinEHStatePass, "x86-winehstate",
1190b57cec5SDimitry Andric                 "Insert stores for EH state numbers", false, false)
1200b57cec5SDimitry Andric 
doInitialization(Module & M)1210b57cec5SDimitry Andric bool WinEHStatePass::doInitialization(Module &M) {
1220b57cec5SDimitry Andric   TheModule = &M;
1230b57cec5SDimitry Andric   return false;
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
doFinalization(Module & M)1260b57cec5SDimitry Andric bool WinEHStatePass::doFinalization(Module &M) {
1270b57cec5SDimitry Andric   assert(TheModule == &M);
1280b57cec5SDimitry Andric   TheModule = nullptr;
1290b57cec5SDimitry Andric   EHLinkRegistrationTy = nullptr;
1300b57cec5SDimitry Andric   CXXEHRegistrationTy = nullptr;
1310b57cec5SDimitry Andric   SEHRegistrationTy = nullptr;
1320b57cec5SDimitry Andric   SetJmp3 = nullptr;
1330b57cec5SDimitry Andric   CxxLongjmpUnwind = nullptr;
1340b57cec5SDimitry Andric   SehLongjmpUnwind = nullptr;
1350b57cec5SDimitry Andric   Cookie = nullptr;
1360b57cec5SDimitry Andric   return false;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const1390b57cec5SDimitry Andric void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const {
1400b57cec5SDimitry Andric   // This pass should only insert a stack allocation, memory accesses, and
1410b57cec5SDimitry Andric   // localrecovers.
1420b57cec5SDimitry Andric   AU.setPreservesCFG();
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
runOnFunction(Function & F)1450b57cec5SDimitry Andric bool WinEHStatePass::runOnFunction(Function &F) {
1460b57cec5SDimitry Andric   // Don't insert state stores or exception handler thunks for
1470b57cec5SDimitry Andric   // available_externally functions. The handler needs to reference the LSDA,
1480b57cec5SDimitry Andric   // which will not be emitted in this case.
1490b57cec5SDimitry Andric   if (F.hasAvailableExternallyLinkage())
1500b57cec5SDimitry Andric     return false;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   // Check the personality. Do nothing if this personality doesn't use funclets.
1530b57cec5SDimitry Andric   if (!F.hasPersonalityFn())
1540b57cec5SDimitry Andric     return false;
1550b57cec5SDimitry Andric   PersonalityFn =
1560b57cec5SDimitry Andric       dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());
1570b57cec5SDimitry Andric   if (!PersonalityFn)
1580b57cec5SDimitry Andric     return false;
1590b57cec5SDimitry Andric   Personality = classifyEHPersonality(PersonalityFn);
1600b57cec5SDimitry Andric   if (!isFuncletEHPersonality(Personality))
1610b57cec5SDimitry Andric     return false;
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   // Skip this function if there are no EH pads and we aren't using IR-level
1640b57cec5SDimitry Andric   // outlining.
1650b57cec5SDimitry Andric   bool HasPads = false;
1660b57cec5SDimitry Andric   for (BasicBlock &BB : F) {
1670b57cec5SDimitry Andric     if (BB.isEHPad()) {
1680b57cec5SDimitry Andric       HasPads = true;
1690b57cec5SDimitry Andric       break;
1700b57cec5SDimitry Andric     }
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric   if (!HasPads)
1730b57cec5SDimitry Andric     return false;
1740b57cec5SDimitry Andric 
175*5f757f3fSDimitry Andric   Type *Int8PtrType = PointerType::getUnqual(TheModule->getContext());
1760b57cec5SDimitry Andric   SetJmp3 = TheModule->getOrInsertFunction(
1770b57cec5SDimitry Andric       "_setjmp3", FunctionType::get(
1780b57cec5SDimitry Andric                       Type::getInt32Ty(TheModule->getContext()),
1790b57cec5SDimitry Andric                       {Int8PtrType, Type::getInt32Ty(TheModule->getContext())},
1800b57cec5SDimitry Andric                       /*isVarArg=*/true));
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric   emitExceptionRegistrationRecord(&F);
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   // The state numbers calculated here in IR must agree with what we calculate
1850b57cec5SDimitry Andric   // later on for the MachineFunction. In particular, if an IR pass deletes an
1860b57cec5SDimitry Andric   // unreachable EH pad after this point before machine CFG construction, we
1870b57cec5SDimitry Andric   // will be in trouble. If this assumption is ever broken, we should turn the
1880b57cec5SDimitry Andric   // numbers into an immutable analysis pass.
1890b57cec5SDimitry Andric   WinEHFuncInfo FuncInfo;
1900b57cec5SDimitry Andric   addStateStores(F, FuncInfo);
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   // Reset per-function state.
1930b57cec5SDimitry Andric   PersonalityFn = nullptr;
1940b57cec5SDimitry Andric   Personality = EHPersonality::Unknown;
1950b57cec5SDimitry Andric   UseStackGuard = false;
1960b57cec5SDimitry Andric   RegNode = nullptr;
1970b57cec5SDimitry Andric   EHGuardNode = nullptr;
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   return true;
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric /// Get the common EH registration subobject:
2030b57cec5SDimitry Andric ///   typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(
2040b57cec5SDimitry Andric ///       _EXCEPTION_RECORD *, void *, _CONTEXT *, void *);
2050b57cec5SDimitry Andric ///   struct EHRegistrationNode {
2060b57cec5SDimitry Andric ///     EHRegistrationNode *Next;
2070b57cec5SDimitry Andric ///     PEXCEPTION_ROUTINE Handler;
2080b57cec5SDimitry Andric ///   };
getEHLinkRegistrationType()2090b57cec5SDimitry Andric Type *WinEHStatePass::getEHLinkRegistrationType() {
2100b57cec5SDimitry Andric   if (EHLinkRegistrationTy)
2110b57cec5SDimitry Andric     return EHLinkRegistrationTy;
2120b57cec5SDimitry Andric   LLVMContext &Context = TheModule->getContext();
2130b57cec5SDimitry Andric   EHLinkRegistrationTy = StructType::create(Context, "EHRegistrationNode");
2140b57cec5SDimitry Andric   Type *FieldTys[] = {
21506c3fb27SDimitry Andric       PointerType::getUnqual(
21606c3fb27SDimitry Andric           EHLinkRegistrationTy->getContext()), // EHRegistrationNode *Next
217*5f757f3fSDimitry Andric       PointerType::getUnqual(Context) // EXCEPTION_DISPOSITION (*Handler)(...)
2180b57cec5SDimitry Andric   };
2190b57cec5SDimitry Andric   EHLinkRegistrationTy->setBody(FieldTys, false);
2200b57cec5SDimitry Andric   return EHLinkRegistrationTy;
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric /// The __CxxFrameHandler3 registration node:
2240b57cec5SDimitry Andric ///   struct CXXExceptionRegistration {
2250b57cec5SDimitry Andric ///     void *SavedESP;
2260b57cec5SDimitry Andric ///     EHRegistrationNode SubRecord;
2270b57cec5SDimitry Andric ///     int32_t TryLevel;
2280b57cec5SDimitry Andric ///   };
getCXXEHRegistrationType()2290b57cec5SDimitry Andric Type *WinEHStatePass::getCXXEHRegistrationType() {
2300b57cec5SDimitry Andric   if (CXXEHRegistrationTy)
2310b57cec5SDimitry Andric     return CXXEHRegistrationTy;
2320b57cec5SDimitry Andric   LLVMContext &Context = TheModule->getContext();
2330b57cec5SDimitry Andric   Type *FieldTys[] = {
234*5f757f3fSDimitry Andric       PointerType::getUnqual(Context), // void *SavedESP
2350b57cec5SDimitry Andric       getEHLinkRegistrationType(),     // EHRegistrationNode SubRecord
2360b57cec5SDimitry Andric       Type::getInt32Ty(Context)        // int32_t TryLevel
2370b57cec5SDimitry Andric   };
2380b57cec5SDimitry Andric   CXXEHRegistrationTy =
2390b57cec5SDimitry Andric       StructType::create(FieldTys, "CXXExceptionRegistration");
2400b57cec5SDimitry Andric   return CXXEHRegistrationTy;
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric /// The _except_handler3/4 registration node:
2440b57cec5SDimitry Andric ///   struct EH4ExceptionRegistration {
2450b57cec5SDimitry Andric ///     void *SavedESP;
2460b57cec5SDimitry Andric ///     _EXCEPTION_POINTERS *ExceptionPointers;
2470b57cec5SDimitry Andric ///     EHRegistrationNode SubRecord;
2480b57cec5SDimitry Andric ///     int32_t EncodedScopeTable;
2490b57cec5SDimitry Andric ///     int32_t TryLevel;
2500b57cec5SDimitry Andric ///   };
getSEHRegistrationType()2510b57cec5SDimitry Andric Type *WinEHStatePass::getSEHRegistrationType() {
2520b57cec5SDimitry Andric   if (SEHRegistrationTy)
2530b57cec5SDimitry Andric     return SEHRegistrationTy;
2540b57cec5SDimitry Andric   LLVMContext &Context = TheModule->getContext();
2550b57cec5SDimitry Andric   Type *FieldTys[] = {
256*5f757f3fSDimitry Andric       PointerType::getUnqual(Context), // void *SavedESP
257*5f757f3fSDimitry Andric       PointerType::getUnqual(Context), // void *ExceptionPointers
2580b57cec5SDimitry Andric       getEHLinkRegistrationType(),     // EHRegistrationNode SubRecord
2590b57cec5SDimitry Andric       Type::getInt32Ty(Context),       // int32_t EncodedScopeTable
2600b57cec5SDimitry Andric       Type::getInt32Ty(Context)        // int32_t TryLevel
2610b57cec5SDimitry Andric   };
2620b57cec5SDimitry Andric   SEHRegistrationTy = StructType::create(FieldTys, "SEHExceptionRegistration");
2630b57cec5SDimitry Andric   return SEHRegistrationTy;
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric // Emit an exception registration record. These are stack allocations with the
2670b57cec5SDimitry Andric // common subobject of two pointers: the previous registration record (the old
2680b57cec5SDimitry Andric // fs:00) and the personality function for the current frame. The data before
2690b57cec5SDimitry Andric // and after that is personality function specific.
emitExceptionRegistrationRecord(Function * F)2700b57cec5SDimitry Andric void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
2710b57cec5SDimitry Andric   assert(Personality == EHPersonality::MSVC_CXX ||
2720b57cec5SDimitry Andric          Personality == EHPersonality::MSVC_X86SEH);
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   // Struct type of RegNode. Used for GEPing.
2750b57cec5SDimitry Andric   Type *RegNodeTy;
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
278*5f757f3fSDimitry Andric   Type *Int8PtrType = Builder.getPtrTy();
2790b57cec5SDimitry Andric   Type *Int32Ty = Builder.getInt32Ty();
2800b57cec5SDimitry Andric   Type *VoidTy = Builder.getVoidTy();
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   if (Personality == EHPersonality::MSVC_CXX) {
2830b57cec5SDimitry Andric     RegNodeTy = getCXXEHRegistrationType();
2840b57cec5SDimitry Andric     RegNode = Builder.CreateAlloca(RegNodeTy);
2850b57cec5SDimitry Andric     // SavedESP = llvm.stacksave()
286*5f757f3fSDimitry Andric     Value *SP = Builder.CreateStackSave();
2870b57cec5SDimitry Andric     Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
2880b57cec5SDimitry Andric     // TryLevel = -1
2890b57cec5SDimitry Andric     StateFieldIndex = 2;
2900b57cec5SDimitry Andric     ParentBaseState = -1;
2910b57cec5SDimitry Andric     insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
2920b57cec5SDimitry Andric     // Handler = __ehhandler$F
2930b57cec5SDimitry Andric     Function *Trampoline = generateLSDAInEAXThunk(F);
2940b57cec5SDimitry Andric     Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
2950b57cec5SDimitry Andric     linkExceptionRegistration(Builder, Trampoline);
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric     CxxLongjmpUnwind = TheModule->getOrInsertFunction(
2980b57cec5SDimitry Andric         "__CxxLongjmpUnwind",
2990b57cec5SDimitry Andric         FunctionType::get(VoidTy, Int8PtrType, /*isVarArg=*/false));
3000b57cec5SDimitry Andric     cast<Function>(CxxLongjmpUnwind.getCallee()->stripPointerCasts())
3010b57cec5SDimitry Andric         ->setCallingConv(CallingConv::X86_StdCall);
3020b57cec5SDimitry Andric   } else if (Personality == EHPersonality::MSVC_X86SEH) {
3030b57cec5SDimitry Andric     // If _except_handler4 is in use, some additional guard checks and prologue
3040b57cec5SDimitry Andric     // stuff is required.
3050b57cec5SDimitry Andric     StringRef PersonalityName = PersonalityFn->getName();
3060b57cec5SDimitry Andric     UseStackGuard = (PersonalityName == "_except_handler4");
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric     // Allocate local structures.
3090b57cec5SDimitry Andric     RegNodeTy = getSEHRegistrationType();
3100b57cec5SDimitry Andric     RegNode = Builder.CreateAlloca(RegNodeTy);
3110b57cec5SDimitry Andric     if (UseStackGuard)
3120b57cec5SDimitry Andric       EHGuardNode = Builder.CreateAlloca(Int32Ty);
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric     // SavedESP = llvm.stacksave()
315*5f757f3fSDimitry Andric     Value *SP = Builder.CreateStackSave();
3160b57cec5SDimitry Andric     Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
3170b57cec5SDimitry Andric     // TryLevel = -2 / -1
3180b57cec5SDimitry Andric     StateFieldIndex = 4;
3190b57cec5SDimitry Andric     ParentBaseState = UseStackGuard ? -2 : -1;
3200b57cec5SDimitry Andric     insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
3210b57cec5SDimitry Andric     // ScopeTable = llvm.x86.seh.lsda(F)
3220b57cec5SDimitry Andric     Value *LSDA = emitEHLSDA(Builder, F);
3230b57cec5SDimitry Andric     LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty);
3240b57cec5SDimitry Andric     // If using _except_handler4, xor the address of the table with
3250b57cec5SDimitry Andric     // __security_cookie.
3260b57cec5SDimitry Andric     if (UseStackGuard) {
3270b57cec5SDimitry Andric       Cookie = TheModule->getOrInsertGlobal("__security_cookie", Int32Ty);
3280b57cec5SDimitry Andric       Value *Val = Builder.CreateLoad(Int32Ty, Cookie, "cookie");
3290b57cec5SDimitry Andric       LSDA = Builder.CreateXor(LSDA, Val);
3300b57cec5SDimitry Andric     }
3310b57cec5SDimitry Andric     Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric     // If using _except_handler4, the EHGuard contains: FramePtr xor Cookie.
3340b57cec5SDimitry Andric     if (UseStackGuard) {
3350b57cec5SDimitry Andric       Value *Val = Builder.CreateLoad(Int32Ty, Cookie);
3360b57cec5SDimitry Andric       Value *FrameAddr = Builder.CreateCall(
3378bcb0991SDimitry Andric           Intrinsic::getDeclaration(
3388bcb0991SDimitry Andric               TheModule, Intrinsic::frameaddress,
339*5f757f3fSDimitry Andric               Builder.getPtrTy(
3408bcb0991SDimitry Andric                   TheModule->getDataLayout().getAllocaAddrSpace())),
3410b57cec5SDimitry Andric           Builder.getInt32(0), "frameaddr");
3420b57cec5SDimitry Andric       Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr, Int32Ty);
3430b57cec5SDimitry Andric       FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val);
3440b57cec5SDimitry Andric       Builder.CreateStore(FrameAddrI32, EHGuardNode);
3450b57cec5SDimitry Andric     }
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric     // Register the exception handler.
3480b57cec5SDimitry Andric     Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
3490b57cec5SDimitry Andric     linkExceptionRegistration(Builder, PersonalityFn);
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric     SehLongjmpUnwind = TheModule->getOrInsertFunction(
3520b57cec5SDimitry Andric         UseStackGuard ? "_seh_longjmp_unwind4" : "_seh_longjmp_unwind",
3530b57cec5SDimitry Andric         FunctionType::get(Type::getVoidTy(TheModule->getContext()), Int8PtrType,
3540b57cec5SDimitry Andric                           /*isVarArg=*/false));
3550b57cec5SDimitry Andric     cast<Function>(SehLongjmpUnwind.getCallee()->stripPointerCasts())
3560b57cec5SDimitry Andric         ->setCallingConv(CallingConv::X86_StdCall);
3570b57cec5SDimitry Andric   } else {
3580b57cec5SDimitry Andric     llvm_unreachable("unexpected personality function");
3590b57cec5SDimitry Andric   }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   // Insert an unlink before all returns.
3620b57cec5SDimitry Andric   for (BasicBlock &BB : *F) {
3630b57cec5SDimitry Andric     Instruction *T = BB.getTerminator();
3640b57cec5SDimitry Andric     if (!isa<ReturnInst>(T))
3650b57cec5SDimitry Andric       continue;
3660b57cec5SDimitry Andric     Builder.SetInsertPoint(T);
3670b57cec5SDimitry Andric     unlinkExceptionRegistration(Builder);
3680b57cec5SDimitry Andric   }
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric 
emitEHLSDA(IRBuilder<> & Builder,Function * F)3710b57cec5SDimitry Andric Value *WinEHStatePass::emitEHLSDA(IRBuilder<> &Builder, Function *F) {
3720b57cec5SDimitry Andric   return Builder.CreateCall(
373*5f757f3fSDimitry Andric       Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), F);
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric /// Generate a thunk that puts the LSDA of ParentFunc in EAX and then calls
3770b57cec5SDimitry Andric /// PersonalityFn, forwarding the parameters passed to PEXCEPTION_ROUTINE:
3780b57cec5SDimitry Andric ///   typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(
3790b57cec5SDimitry Andric ///       _EXCEPTION_RECORD *, void *, _CONTEXT *, void *);
3800b57cec5SDimitry Andric /// We essentially want this code:
3810b57cec5SDimitry Andric ///   movl $lsda, %eax
3820b57cec5SDimitry Andric ///   jmpl ___CxxFrameHandler3
generateLSDAInEAXThunk(Function * ParentFunc)3830b57cec5SDimitry Andric Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) {
3840b57cec5SDimitry Andric   LLVMContext &Context = ParentFunc->getContext();
3850b57cec5SDimitry Andric   Type *Int32Ty = Type::getInt32Ty(Context);
386*5f757f3fSDimitry Andric   Type *Int8PtrType = PointerType::getUnqual(Context);
3870b57cec5SDimitry Andric   Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
3880b57cec5SDimitry Andric                      Int8PtrType};
3890b57cec5SDimitry Andric   FunctionType *TrampolineTy =
390bdd1243dSDimitry Andric       FunctionType::get(Int32Ty, ArrayRef(&ArgTys[0], 4),
3910b57cec5SDimitry Andric                         /*isVarArg=*/false);
3920b57cec5SDimitry Andric   FunctionType *TargetFuncTy =
393bdd1243dSDimitry Andric       FunctionType::get(Int32Ty, ArrayRef(&ArgTys[0], 5),
3940b57cec5SDimitry Andric                         /*isVarArg=*/false);
3950b57cec5SDimitry Andric   Function *Trampoline =
3960b57cec5SDimitry Andric       Function::Create(TrampolineTy, GlobalValue::InternalLinkage,
3970b57cec5SDimitry Andric                        Twine("__ehhandler$") + GlobalValue::dropLLVMManglingEscape(
3980b57cec5SDimitry Andric                                                    ParentFunc->getName()),
3990b57cec5SDimitry Andric                        TheModule);
4000b57cec5SDimitry Andric   if (auto *C = ParentFunc->getComdat())
4010b57cec5SDimitry Andric     Trampoline->setComdat(C);
4020b57cec5SDimitry Andric   BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", Trampoline);
4030b57cec5SDimitry Andric   IRBuilder<> Builder(EntryBB);
4040b57cec5SDimitry Andric   Value *LSDA = emitEHLSDA(Builder, ParentFunc);
4050b57cec5SDimitry Andric   auto AI = Trampoline->arg_begin();
4060b57cec5SDimitry Andric   Value *Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};
40706c3fb27SDimitry Andric   CallInst *Call = Builder.CreateCall(TargetFuncTy, PersonalityFn, Args);
4080b57cec5SDimitry Andric   // Can't use musttail due to prototype mismatch, but we can use tail.
4090b57cec5SDimitry Andric   Call->setTailCall(true);
4100b57cec5SDimitry Andric   // Set inreg so we pass it in EAX.
4110b57cec5SDimitry Andric   Call->addParamAttr(0, Attribute::InReg);
4120b57cec5SDimitry Andric   Builder.CreateRet(Call);
4130b57cec5SDimitry Andric   return Trampoline;
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric 
linkExceptionRegistration(IRBuilder<> & Builder,Function * Handler)4160b57cec5SDimitry Andric void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder,
4170b57cec5SDimitry Andric                                                Function *Handler) {
4180b57cec5SDimitry Andric   // Emit the .safeseh directive for this function.
4190b57cec5SDimitry Andric   Handler->addFnAttr("safeseh");
4200b57cec5SDimitry Andric 
421*5f757f3fSDimitry Andric   LLVMContext &C = Builder.getContext();
4220b57cec5SDimitry Andric   Type *LinkTy = getEHLinkRegistrationType();
4230b57cec5SDimitry Andric   // Handler = Handler
424*5f757f3fSDimitry Andric   Builder.CreateStore(Handler, Builder.CreateStructGEP(LinkTy, Link, 1));
4250b57cec5SDimitry Andric   // Next = [fs:00]
426*5f757f3fSDimitry Andric   Constant *FSZero = Constant::getNullValue(PointerType::get(C, 257));
427*5f757f3fSDimitry Andric   Value *Next = Builder.CreateLoad(PointerType::getUnqual(C), FSZero);
4280b57cec5SDimitry Andric   Builder.CreateStore(Next, Builder.CreateStructGEP(LinkTy, Link, 0));
4290b57cec5SDimitry Andric   // [fs:00] = Link
4300b57cec5SDimitry Andric   Builder.CreateStore(Link, FSZero);
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric 
unlinkExceptionRegistration(IRBuilder<> & Builder)4330b57cec5SDimitry Andric void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) {
4340b57cec5SDimitry Andric   // Clone Link into the current BB for better address mode folding.
4350b57cec5SDimitry Andric   if (auto *GEP = dyn_cast<GetElementPtrInst>(Link)) {
4360b57cec5SDimitry Andric     GEP = cast<GetElementPtrInst>(GEP->clone());
4370b57cec5SDimitry Andric     Builder.Insert(GEP);
4380b57cec5SDimitry Andric     Link = GEP;
4390b57cec5SDimitry Andric   }
440*5f757f3fSDimitry Andric 
441*5f757f3fSDimitry Andric   LLVMContext &C = Builder.getContext();
4420b57cec5SDimitry Andric   Type *LinkTy = getEHLinkRegistrationType();
4430b57cec5SDimitry Andric   // [fs:00] = Link->Next
444*5f757f3fSDimitry Andric   Value *Next = Builder.CreateLoad(PointerType::getUnqual(C),
4450b57cec5SDimitry Andric                                    Builder.CreateStructGEP(LinkTy, Link, 0));
446*5f757f3fSDimitry Andric   Constant *FSZero = Constant::getNullValue(PointerType::get(C, 257));
4470b57cec5SDimitry Andric   Builder.CreateStore(Next, FSZero);
4480b57cec5SDimitry Andric }
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric // Calls to setjmp(p) are lowered to _setjmp3(p, 0) by the frontend.
4510b57cec5SDimitry Andric // The idea behind _setjmp3 is that it takes an optional number of personality
4520b57cec5SDimitry Andric // specific parameters to indicate how to restore the personality-specific frame
4530b57cec5SDimitry Andric // state when longjmp is initiated.  Typically, the current TryLevel is saved.
rewriteSetJmpCall(IRBuilder<> & Builder,Function & F,CallBase & Call,Value * State)4545ffd83dbSDimitry Andric void WinEHStatePass::rewriteSetJmpCall(IRBuilder<> &Builder, Function &F,
4555ffd83dbSDimitry Andric                                        CallBase &Call, Value *State) {
4560b57cec5SDimitry Andric   // Don't rewrite calls with a weird number of arguments.
457349cc55cSDimitry Andric   if (Call.arg_size() != 2)
4580b57cec5SDimitry Andric     return;
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   SmallVector<OperandBundleDef, 1> OpBundles;
4615ffd83dbSDimitry Andric   Call.getOperandBundlesAsDefs(OpBundles);
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric   SmallVector<Value *, 3> OptionalArgs;
4640b57cec5SDimitry Andric   if (Personality == EHPersonality::MSVC_CXX) {
4650b57cec5SDimitry Andric     OptionalArgs.push_back(CxxLongjmpUnwind.getCallee());
4660b57cec5SDimitry Andric     OptionalArgs.push_back(State);
4670b57cec5SDimitry Andric     OptionalArgs.push_back(emitEHLSDA(Builder, &F));
4680b57cec5SDimitry Andric   } else if (Personality == EHPersonality::MSVC_X86SEH) {
4690b57cec5SDimitry Andric     OptionalArgs.push_back(SehLongjmpUnwind.getCallee());
4700b57cec5SDimitry Andric     OptionalArgs.push_back(State);
4710b57cec5SDimitry Andric     if (UseStackGuard)
4720b57cec5SDimitry Andric       OptionalArgs.push_back(Cookie);
4730b57cec5SDimitry Andric   } else {
4740b57cec5SDimitry Andric     llvm_unreachable("unhandled personality!");
4750b57cec5SDimitry Andric   }
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   SmallVector<Value *, 5> Args;
4780b57cec5SDimitry Andric   Args.push_back(
479*5f757f3fSDimitry Andric       Builder.CreateBitCast(Call.getArgOperand(0), Builder.getPtrTy()));
4800b57cec5SDimitry Andric   Args.push_back(Builder.getInt32(OptionalArgs.size()));
4810b57cec5SDimitry Andric   Args.append(OptionalArgs.begin(), OptionalArgs.end());
4820b57cec5SDimitry Andric 
4835ffd83dbSDimitry Andric   CallBase *NewCall;
4845ffd83dbSDimitry Andric   if (auto *CI = dyn_cast<CallInst>(&Call)) {
4850b57cec5SDimitry Andric     CallInst *NewCI = Builder.CreateCall(SetJmp3, Args, OpBundles);
4860b57cec5SDimitry Andric     NewCI->setTailCallKind(CI->getTailCallKind());
4875ffd83dbSDimitry Andric     NewCall = NewCI;
4880b57cec5SDimitry Andric   } else {
4895ffd83dbSDimitry Andric     auto *II = cast<InvokeInst>(&Call);
4905ffd83dbSDimitry Andric     NewCall = Builder.CreateInvoke(
4910b57cec5SDimitry Andric         SetJmp3, II->getNormalDest(), II->getUnwindDest(), Args, OpBundles);
4920b57cec5SDimitry Andric   }
4935ffd83dbSDimitry Andric   NewCall->setCallingConv(Call.getCallingConv());
4945ffd83dbSDimitry Andric   NewCall->setAttributes(Call.getAttributes());
4955ffd83dbSDimitry Andric   NewCall->setDebugLoc(Call.getDebugLoc());
4960b57cec5SDimitry Andric 
4975ffd83dbSDimitry Andric   NewCall->takeName(&Call);
4985ffd83dbSDimitry Andric   Call.replaceAllUsesWith(NewCall);
4995ffd83dbSDimitry Andric   Call.eraseFromParent();
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric // Figure out what state we should assign calls in this block.
getBaseStateForBB(DenseMap<BasicBlock *,ColorVector> & BlockColors,WinEHFuncInfo & FuncInfo,BasicBlock * BB)5030b57cec5SDimitry Andric int WinEHStatePass::getBaseStateForBB(
5040b57cec5SDimitry Andric     DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,
5050b57cec5SDimitry Andric     BasicBlock *BB) {
5060b57cec5SDimitry Andric   int BaseState = ParentBaseState;
5070b57cec5SDimitry Andric   auto &BBColors = BlockColors[BB];
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric   assert(BBColors.size() == 1 && "multi-color BB not removed by preparation");
5100b57cec5SDimitry Andric   BasicBlock *FuncletEntryBB = BBColors.front();
5110b57cec5SDimitry Andric   if (auto *FuncletPad =
5120b57cec5SDimitry Andric           dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI())) {
5130b57cec5SDimitry Andric     auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad);
5140b57cec5SDimitry Andric     if (BaseStateI != FuncInfo.FuncletBaseStateMap.end())
5150b57cec5SDimitry Andric       BaseState = BaseStateI->second;
5160b57cec5SDimitry Andric   }
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric   return BaseState;
5190b57cec5SDimitry Andric }
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric // Calculate the state a call-site is in.
getStateForCall(DenseMap<BasicBlock *,ColorVector> & BlockColors,WinEHFuncInfo & FuncInfo,CallBase & Call)5225ffd83dbSDimitry Andric int WinEHStatePass::getStateForCall(
5230b57cec5SDimitry Andric     DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,
5245ffd83dbSDimitry Andric     CallBase &Call) {
5255ffd83dbSDimitry Andric   if (auto *II = dyn_cast<InvokeInst>(&Call)) {
5260b57cec5SDimitry Andric     // Look up the state number of the EH pad this unwinds to.
5270b57cec5SDimitry Andric     assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!");
5280b57cec5SDimitry Andric     return FuncInfo.InvokeStateMap[II];
5290b57cec5SDimitry Andric   }
5300b57cec5SDimitry Andric   // Possibly throwing call instructions have no actions to take after
5310b57cec5SDimitry Andric   // an unwind. Ensure they are in the -1 state.
5325ffd83dbSDimitry Andric   return getBaseStateForBB(BlockColors, FuncInfo, Call.getParent());
5330b57cec5SDimitry Andric }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric // Calculate the intersection of all the FinalStates for a BasicBlock's
5360b57cec5SDimitry Andric // predecessors.
getPredState(DenseMap<BasicBlock *,int> & FinalStates,Function & F,int ParentBaseState,BasicBlock * BB)5370b57cec5SDimitry Andric static int getPredState(DenseMap<BasicBlock *, int> &FinalStates, Function &F,
5380b57cec5SDimitry Andric                         int ParentBaseState, BasicBlock *BB) {
5390b57cec5SDimitry Andric   // The entry block has no predecessors but we know that the prologue always
5400b57cec5SDimitry Andric   // sets us up with a fixed state.
5410b57cec5SDimitry Andric   if (&F.getEntryBlock() == BB)
5420b57cec5SDimitry Andric     return ParentBaseState;
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric   // This is an EH Pad, conservatively report this basic block as overdefined.
5450b57cec5SDimitry Andric   if (BB->isEHPad())
5460b57cec5SDimitry Andric     return OverdefinedState;
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric   int CommonState = OverdefinedState;
5490b57cec5SDimitry Andric   for (BasicBlock *PredBB : predecessors(BB)) {
5500b57cec5SDimitry Andric     // We didn't manage to get a state for one of these predecessors,
5510b57cec5SDimitry Andric     // conservatively report this basic block as overdefined.
5520b57cec5SDimitry Andric     auto PredEndState = FinalStates.find(PredBB);
5530b57cec5SDimitry Andric     if (PredEndState == FinalStates.end())
5540b57cec5SDimitry Andric       return OverdefinedState;
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric     // This code is reachable via exceptional control flow,
5570b57cec5SDimitry Andric     // conservatively report this basic block as overdefined.
5580b57cec5SDimitry Andric     if (isa<CatchReturnInst>(PredBB->getTerminator()))
5590b57cec5SDimitry Andric       return OverdefinedState;
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric     int PredState = PredEndState->second;
5620b57cec5SDimitry Andric     assert(PredState != OverdefinedState &&
5630b57cec5SDimitry Andric            "overdefined BBs shouldn't be in FinalStates");
5640b57cec5SDimitry Andric     if (CommonState == OverdefinedState)
5650b57cec5SDimitry Andric       CommonState = PredState;
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric     // At least two predecessors have different FinalStates,
5680b57cec5SDimitry Andric     // conservatively report this basic block as overdefined.
5690b57cec5SDimitry Andric     if (CommonState != PredState)
5700b57cec5SDimitry Andric       return OverdefinedState;
5710b57cec5SDimitry Andric   }
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   return CommonState;
5740b57cec5SDimitry Andric }
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric // Calculate the intersection of all the InitialStates for a BasicBlock's
5770b57cec5SDimitry Andric // successors.
getSuccState(DenseMap<BasicBlock *,int> & InitialStates,Function & F,int ParentBaseState,BasicBlock * BB)5780b57cec5SDimitry Andric static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F,
5790b57cec5SDimitry Andric                         int ParentBaseState, BasicBlock *BB) {
5800b57cec5SDimitry Andric   // This block rejoins normal control flow,
5810b57cec5SDimitry Andric   // conservatively report this basic block as overdefined.
5820b57cec5SDimitry Andric   if (isa<CatchReturnInst>(BB->getTerminator()))
5830b57cec5SDimitry Andric     return OverdefinedState;
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric   int CommonState = OverdefinedState;
5860b57cec5SDimitry Andric   for (BasicBlock *SuccBB : successors(BB)) {
5870b57cec5SDimitry Andric     // We didn't manage to get a state for one of these predecessors,
5880b57cec5SDimitry Andric     // conservatively report this basic block as overdefined.
5890b57cec5SDimitry Andric     auto SuccStartState = InitialStates.find(SuccBB);
5900b57cec5SDimitry Andric     if (SuccStartState == InitialStates.end())
5910b57cec5SDimitry Andric       return OverdefinedState;
5920b57cec5SDimitry Andric 
5930b57cec5SDimitry Andric     // This is an EH Pad, conservatively report this basic block as overdefined.
5940b57cec5SDimitry Andric     if (SuccBB->isEHPad())
5950b57cec5SDimitry Andric       return OverdefinedState;
5960b57cec5SDimitry Andric 
5970b57cec5SDimitry Andric     int SuccState = SuccStartState->second;
5980b57cec5SDimitry Andric     assert(SuccState != OverdefinedState &&
5990b57cec5SDimitry Andric            "overdefined BBs shouldn't be in FinalStates");
6000b57cec5SDimitry Andric     if (CommonState == OverdefinedState)
6010b57cec5SDimitry Andric       CommonState = SuccState;
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric     // At least two successors have different InitialStates,
6040b57cec5SDimitry Andric     // conservatively report this basic block as overdefined.
6050b57cec5SDimitry Andric     if (CommonState != SuccState)
6060b57cec5SDimitry Andric       return OverdefinedState;
6070b57cec5SDimitry Andric   }
6080b57cec5SDimitry Andric 
6090b57cec5SDimitry Andric   return CommonState;
6100b57cec5SDimitry Andric }
6110b57cec5SDimitry Andric 
isStateStoreNeeded(EHPersonality Personality,CallBase & Call)6120b57cec5SDimitry Andric bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality,
6135ffd83dbSDimitry Andric                                         CallBase &Call) {
6140b57cec5SDimitry Andric   // If the function touches memory, it needs a state store.
6150b57cec5SDimitry Andric   if (isAsynchronousEHPersonality(Personality))
6165ffd83dbSDimitry Andric     return !Call.doesNotAccessMemory();
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric   // If the function throws, it needs a state store.
6195ffd83dbSDimitry Andric   return !Call.doesNotThrow();
6200b57cec5SDimitry Andric }
6210b57cec5SDimitry Andric 
addStateStores(Function & F,WinEHFuncInfo & FuncInfo)6220b57cec5SDimitry Andric void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
6230b57cec5SDimitry Andric   // Mark the registration node. The backend needs to know which alloca it is so
6240b57cec5SDimitry Andric   // that it can recover the original frame pointer.
6250b57cec5SDimitry Andric   IRBuilder<> Builder(RegNode->getNextNode());
626*5f757f3fSDimitry Andric   Value *RegNodeI8 = Builder.CreateBitCast(RegNode, Builder.getPtrTy());
6270b57cec5SDimitry Andric   Builder.CreateCall(
6280b57cec5SDimitry Andric       Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehregnode),
6290b57cec5SDimitry Andric       {RegNodeI8});
6300b57cec5SDimitry Andric 
6310b57cec5SDimitry Andric   if (EHGuardNode) {
6320b57cec5SDimitry Andric     IRBuilder<> Builder(EHGuardNode->getNextNode());
6330b57cec5SDimitry Andric     Value *EHGuardNodeI8 =
634*5f757f3fSDimitry Andric         Builder.CreateBitCast(EHGuardNode, Builder.getPtrTy());
6350b57cec5SDimitry Andric     Builder.CreateCall(
6360b57cec5SDimitry Andric         Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehguard),
6370b57cec5SDimitry Andric         {EHGuardNodeI8});
6380b57cec5SDimitry Andric   }
6390b57cec5SDimitry Andric 
6400b57cec5SDimitry Andric   // Calculate state numbers.
6410b57cec5SDimitry Andric   if (isAsynchronousEHPersonality(Personality))
6420b57cec5SDimitry Andric     calculateSEHStateNumbers(&F, FuncInfo);
6430b57cec5SDimitry Andric   else
6440b57cec5SDimitry Andric     calculateWinCXXEHStateNumbers(&F, FuncInfo);
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric   // Iterate all the instructions and emit state number stores.
6470b57cec5SDimitry Andric   DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(F);
6480b57cec5SDimitry Andric   ReversePostOrderTraversal<Function *> RPOT(&F);
6490b57cec5SDimitry Andric 
6500b57cec5SDimitry Andric   // InitialStates yields the state of the first call-site for a BasicBlock.
6510b57cec5SDimitry Andric   DenseMap<BasicBlock *, int> InitialStates;
6520b57cec5SDimitry Andric   // FinalStates yields the state of the last call-site for a BasicBlock.
6530b57cec5SDimitry Andric   DenseMap<BasicBlock *, int> FinalStates;
6540b57cec5SDimitry Andric   // Worklist used to revisit BasicBlocks with indeterminate
6550b57cec5SDimitry Andric   // Initial/Final-States.
6560b57cec5SDimitry Andric   std::deque<BasicBlock *> Worklist;
6570b57cec5SDimitry Andric   // Fill in InitialStates and FinalStates for BasicBlocks with call-sites.
6580b57cec5SDimitry Andric   for (BasicBlock *BB : RPOT) {
6590b57cec5SDimitry Andric     int InitialState = OverdefinedState;
6600b57cec5SDimitry Andric     int FinalState;
6610b57cec5SDimitry Andric     if (&F.getEntryBlock() == BB)
6620b57cec5SDimitry Andric       InitialState = FinalState = ParentBaseState;
6630b57cec5SDimitry Andric     for (Instruction &I : *BB) {
6645ffd83dbSDimitry Andric       auto *Call = dyn_cast<CallBase>(&I);
6655ffd83dbSDimitry Andric       if (!Call || !isStateStoreNeeded(Personality, *Call))
6660b57cec5SDimitry Andric         continue;
6670b57cec5SDimitry Andric 
6685ffd83dbSDimitry Andric       int State = getStateForCall(BlockColors, FuncInfo, *Call);
6690b57cec5SDimitry Andric       if (InitialState == OverdefinedState)
6700b57cec5SDimitry Andric         InitialState = State;
6710b57cec5SDimitry Andric       FinalState = State;
6720b57cec5SDimitry Andric     }
6730b57cec5SDimitry Andric     // No call-sites in this basic block? That's OK, we will come back to these
6740b57cec5SDimitry Andric     // in a later pass.
6750b57cec5SDimitry Andric     if (InitialState == OverdefinedState) {
6760b57cec5SDimitry Andric       Worklist.push_back(BB);
6770b57cec5SDimitry Andric       continue;
6780b57cec5SDimitry Andric     }
6790b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName()
6800b57cec5SDimitry Andric                       << " InitialState=" << InitialState << '\n');
6810b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName()
6820b57cec5SDimitry Andric                       << " FinalState=" << FinalState << '\n');
6830b57cec5SDimitry Andric     InitialStates.insert({BB, InitialState});
6840b57cec5SDimitry Andric     FinalStates.insert({BB, FinalState});
6850b57cec5SDimitry Andric   }
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric   // Try to fill-in InitialStates and FinalStates which have no call-sites.
6880b57cec5SDimitry Andric   while (!Worklist.empty()) {
6890b57cec5SDimitry Andric     BasicBlock *BB = Worklist.front();
6900b57cec5SDimitry Andric     Worklist.pop_front();
6910b57cec5SDimitry Andric     // This BasicBlock has already been figured out, nothing more we can do.
6920b57cec5SDimitry Andric     if (InitialStates.count(BB) != 0)
6930b57cec5SDimitry Andric       continue;
6940b57cec5SDimitry Andric 
6950b57cec5SDimitry Andric     int PredState = getPredState(FinalStates, F, ParentBaseState, BB);
6960b57cec5SDimitry Andric     if (PredState == OverdefinedState)
6970b57cec5SDimitry Andric       continue;
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric     // We successfully inferred this BasicBlock's state via it's predecessors;
7000b57cec5SDimitry Andric     // enqueue it's successors to see if we can infer their states.
7010b57cec5SDimitry Andric     InitialStates.insert({BB, PredState});
7020b57cec5SDimitry Andric     FinalStates.insert({BB, PredState});
7030b57cec5SDimitry Andric     for (BasicBlock *SuccBB : successors(BB))
7040b57cec5SDimitry Andric       Worklist.push_back(SuccBB);
7050b57cec5SDimitry Andric   }
7060b57cec5SDimitry Andric 
7070b57cec5SDimitry Andric   // Try to hoist stores from successors.
7080b57cec5SDimitry Andric   for (BasicBlock *BB : RPOT) {
7090b57cec5SDimitry Andric     int SuccState = getSuccState(InitialStates, F, ParentBaseState, BB);
7100b57cec5SDimitry Andric     if (SuccState == OverdefinedState)
7110b57cec5SDimitry Andric       continue;
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric     // Update our FinalState to reflect the common InitialState of our
7140b57cec5SDimitry Andric     // successors.
7150b57cec5SDimitry Andric     FinalStates.insert({BB, SuccState});
7160b57cec5SDimitry Andric   }
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric   // Finally, insert state stores before call-sites which transition us to a new
7190b57cec5SDimitry Andric   // state.
7200b57cec5SDimitry Andric   for (BasicBlock *BB : RPOT) {
7210b57cec5SDimitry Andric     auto &BBColors = BlockColors[BB];
7220b57cec5SDimitry Andric     BasicBlock *FuncletEntryBB = BBColors.front();
7230b57cec5SDimitry Andric     if (isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHI()))
7240b57cec5SDimitry Andric       continue;
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric     int PrevState = getPredState(FinalStates, F, ParentBaseState, BB);
7270b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName()
7280b57cec5SDimitry Andric                       << " PrevState=" << PrevState << '\n');
7290b57cec5SDimitry Andric 
7300b57cec5SDimitry Andric     for (Instruction &I : *BB) {
7315ffd83dbSDimitry Andric       auto *Call = dyn_cast<CallBase>(&I);
7325ffd83dbSDimitry Andric       if (!Call || !isStateStoreNeeded(Personality, *Call))
7330b57cec5SDimitry Andric         continue;
7340b57cec5SDimitry Andric 
7355ffd83dbSDimitry Andric       int State = getStateForCall(BlockColors, FuncInfo, *Call);
7360b57cec5SDimitry Andric       if (State != PrevState)
7370b57cec5SDimitry Andric         insertStateNumberStore(&I, State);
7380b57cec5SDimitry Andric       PrevState = State;
7390b57cec5SDimitry Andric     }
7400b57cec5SDimitry Andric 
7410b57cec5SDimitry Andric     // We might have hoisted a state store into this block, emit it now.
7420b57cec5SDimitry Andric     auto EndState = FinalStates.find(BB);
7430b57cec5SDimitry Andric     if (EndState != FinalStates.end())
7440b57cec5SDimitry Andric       if (EndState->second != PrevState)
7450b57cec5SDimitry Andric         insertStateNumberStore(BB->getTerminator(), EndState->second);
7460b57cec5SDimitry Andric   }
7470b57cec5SDimitry Andric 
7485ffd83dbSDimitry Andric   SmallVector<CallBase *, 1> SetJmp3Calls;
7490b57cec5SDimitry Andric   for (BasicBlock *BB : RPOT) {
7500b57cec5SDimitry Andric     for (Instruction &I : *BB) {
7515ffd83dbSDimitry Andric       auto *Call = dyn_cast<CallBase>(&I);
7525ffd83dbSDimitry Andric       if (!Call)
7530b57cec5SDimitry Andric         continue;
7545ffd83dbSDimitry Andric       if (Call->getCalledOperand()->stripPointerCasts() !=
7550b57cec5SDimitry Andric           SetJmp3.getCallee()->stripPointerCasts())
7560b57cec5SDimitry Andric         continue;
7570b57cec5SDimitry Andric 
7585ffd83dbSDimitry Andric       SetJmp3Calls.push_back(Call);
7590b57cec5SDimitry Andric     }
7600b57cec5SDimitry Andric   }
7610b57cec5SDimitry Andric 
7625ffd83dbSDimitry Andric   for (CallBase *Call : SetJmp3Calls) {
7635ffd83dbSDimitry Andric     auto &BBColors = BlockColors[Call->getParent()];
7640b57cec5SDimitry Andric     BasicBlock *FuncletEntryBB = BBColors.front();
7650b57cec5SDimitry Andric     bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHI());
7660b57cec5SDimitry Andric 
7675ffd83dbSDimitry Andric     IRBuilder<> Builder(Call);
7680b57cec5SDimitry Andric     Value *State;
7690b57cec5SDimitry Andric     if (InCleanup) {
7700b57cec5SDimitry Andric       Value *StateField = Builder.CreateStructGEP(RegNode->getAllocatedType(),
7710b57cec5SDimitry Andric                                                   RegNode, StateFieldIndex);
7720b57cec5SDimitry Andric       State = Builder.CreateLoad(Builder.getInt32Ty(), StateField);
7730b57cec5SDimitry Andric     } else {
7745ffd83dbSDimitry Andric       State = Builder.getInt32(getStateForCall(BlockColors, FuncInfo, *Call));
7750b57cec5SDimitry Andric     }
7765ffd83dbSDimitry Andric     rewriteSetJmpCall(Builder, F, *Call, State);
7770b57cec5SDimitry Andric   }
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric 
insertStateNumberStore(Instruction * IP,int State)7800b57cec5SDimitry Andric void WinEHStatePass::insertStateNumberStore(Instruction *IP, int State) {
7810b57cec5SDimitry Andric   IRBuilder<> Builder(IP);
7820b57cec5SDimitry Andric   Value *StateField = Builder.CreateStructGEP(RegNode->getAllocatedType(),
7830b57cec5SDimitry Andric                                               RegNode, StateFieldIndex);
7840b57cec5SDimitry Andric   Builder.CreateStore(Builder.getInt32(State), StateField);
7850b57cec5SDimitry Andric }
786