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