diff options
Diffstat (limited to 'gnu/llvm/lib/Target/X86/X86WinEHState.cpp')
| -rw-r--r-- | gnu/llvm/lib/Target/X86/X86WinEHState.cpp | 800 |
1 files changed, 0 insertions, 800 deletions
diff --git a/gnu/llvm/lib/Target/X86/X86WinEHState.cpp b/gnu/llvm/lib/Target/X86/X86WinEHState.cpp deleted file mode 100644 index 185deda97c1..00000000000 --- a/gnu/llvm/lib/Target/X86/X86WinEHState.cpp +++ /dev/null @@ -1,800 +0,0 @@ -//===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// All functions using an MSVC EH personality use an explicitly updated state -// number stored in an exception registration stack object. The registration -// object is linked into a thread-local chain of registrations stored at fs:00. -// This pass adds the registration object and EH state updates. -// -//===----------------------------------------------------------------------===// - -#include "X86.h" -#include "llvm/ADT/PostOrderIterator.h" -#include "llvm/Analysis/CFG.h" -#include "llvm/Analysis/EHPersonalities.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/WinEHFuncInfo.h" -#include "llvm/IR/CallSite.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include <deque> - -using namespace llvm; - -#define DEBUG_TYPE "winehstate" - -namespace { -const int OverdefinedState = INT_MIN; - -class WinEHStatePass : public FunctionPass { -public: - static char ID; // Pass identification, replacement for typeid. - - WinEHStatePass() : FunctionPass(ID) { - initializeWinEHStatePassPass(*PassRegistry::getPassRegistry()); - } - - bool runOnFunction(Function &Fn) override; - - bool doInitialization(Module &M) override; - - bool doFinalization(Module &M) override; - - void getAnalysisUsage(AnalysisUsage &AU) const override; - - StringRef getPassName() const override { - return "Windows 32-bit x86 EH state insertion"; - } - -private: - void emitExceptionRegistrationRecord(Function *F); - - void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler); - void unlinkExceptionRegistration(IRBuilder<> &Builder); - void addStateStores(Function &F, WinEHFuncInfo &FuncInfo); - void insertStateNumberStore(Instruction *IP, int State); - - Value *emitEHLSDA(IRBuilder<> &Builder, Function *F); - - Function *generateLSDAInEAXThunk(Function *ParentFunc); - - bool isStateStoreNeeded(EHPersonality Personality, CallSite CS); - void rewriteSetJmpCallSite(IRBuilder<> &Builder, Function &F, CallSite CS, - Value *State); - int getBaseStateForBB(DenseMap<BasicBlock *, ColorVector> &BlockColors, - WinEHFuncInfo &FuncInfo, BasicBlock *BB); - int getStateForCallSite(DenseMap<BasicBlock *, ColorVector> &BlockColors, - WinEHFuncInfo &FuncInfo, CallSite CS); - - // Module-level type getters. - Type *getEHLinkRegistrationType(); - Type *getSEHRegistrationType(); - Type *getCXXEHRegistrationType(); - - // Per-module data. - Module *TheModule = nullptr; - StructType *EHLinkRegistrationTy = nullptr; - StructType *CXXEHRegistrationTy = nullptr; - StructType *SEHRegistrationTy = nullptr; - Constant *SetJmp3 = nullptr; - Constant *CxxLongjmpUnwind = nullptr; - - // Per-function state - EHPersonality Personality = EHPersonality::Unknown; - Function *PersonalityFn = nullptr; - bool UseStackGuard = false; - int ParentBaseState; - Constant *SehLongjmpUnwind = nullptr; - Constant *Cookie = nullptr; - - /// The stack allocation containing all EH data, including the link in the - /// fs:00 chain and the current state. - AllocaInst *RegNode = nullptr; - - // The allocation containing the EH security guard. - AllocaInst *EHGuardNode = nullptr; - - /// The index of the state field of RegNode. - int StateFieldIndex = ~0U; - - /// The linked list node subobject inside of RegNode. - Value *Link = nullptr; -}; -} - -FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); } - -char WinEHStatePass::ID = 0; - -INITIALIZE_PASS(WinEHStatePass, "x86-winehstate", - "Insert stores for EH state numbers", false, false) - -bool WinEHStatePass::doInitialization(Module &M) { - TheModule = &M; - return false; -} - -bool WinEHStatePass::doFinalization(Module &M) { - assert(TheModule == &M); - TheModule = nullptr; - EHLinkRegistrationTy = nullptr; - CXXEHRegistrationTy = nullptr; - SEHRegistrationTy = nullptr; - SetJmp3 = nullptr; - CxxLongjmpUnwind = nullptr; - SehLongjmpUnwind = nullptr; - Cookie = nullptr; - return false; -} - -void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const { - // This pass should only insert a stack allocation, memory accesses, and - // localrecovers. - AU.setPreservesCFG(); -} - -bool WinEHStatePass::runOnFunction(Function &F) { - // Don't insert state stores or exception handler thunks for - // available_externally functions. The handler needs to reference the LSDA, - // which will not be emitted in this case. - if (F.hasAvailableExternallyLinkage()) - return false; - - // Check the personality. Do nothing if this personality doesn't use funclets. - if (!F.hasPersonalityFn()) - return false; - PersonalityFn = - dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts()); - if (!PersonalityFn) - return false; - Personality = classifyEHPersonality(PersonalityFn); - if (!isFuncletEHPersonality(Personality)) - return false; - - // Skip this function if there are no EH pads and we aren't using IR-level - // outlining. - bool HasPads = false; - for (BasicBlock &BB : F) { - if (BB.isEHPad()) { - HasPads = true; - break; - } - } - if (!HasPads) - return false; - - Type *Int8PtrType = Type::getInt8PtrTy(TheModule->getContext()); - SetJmp3 = TheModule->getOrInsertFunction( - "_setjmp3", FunctionType::get( - Type::getInt32Ty(TheModule->getContext()), - {Int8PtrType, Type::getInt32Ty(TheModule->getContext())}, - /*isVarArg=*/true)); - - // Disable frame pointer elimination in this function. - // FIXME: Do the nested handlers need to keep the parent ebp in ebp, or can we - // use an arbitrary register? - F.addFnAttr("no-frame-pointer-elim", "true"); - - emitExceptionRegistrationRecord(&F); - - // The state numbers calculated here in IR must agree with what we calculate - // later on for the MachineFunction. In particular, if an IR pass deletes an - // unreachable EH pad after this point before machine CFG construction, we - // will be in trouble. If this assumption is ever broken, we should turn the - // numbers into an immutable analysis pass. - WinEHFuncInfo FuncInfo; - addStateStores(F, FuncInfo); - - // Reset per-function state. - PersonalityFn = nullptr; - Personality = EHPersonality::Unknown; - UseStackGuard = false; - RegNode = nullptr; - EHGuardNode = nullptr; - - return true; -} - -/// Get the common EH registration subobject: -/// typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)( -/// _EXCEPTION_RECORD *, void *, _CONTEXT *, void *); -/// struct EHRegistrationNode { -/// EHRegistrationNode *Next; -/// PEXCEPTION_ROUTINE Handler; -/// }; -Type *WinEHStatePass::getEHLinkRegistrationType() { - if (EHLinkRegistrationTy) - return EHLinkRegistrationTy; - LLVMContext &Context = TheModule->getContext(); - EHLinkRegistrationTy = StructType::create(Context, "EHRegistrationNode"); - Type *FieldTys[] = { - EHLinkRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next - Type::getInt8PtrTy(Context) // EXCEPTION_DISPOSITION (*Handler)(...) - }; - EHLinkRegistrationTy->setBody(FieldTys, false); - return EHLinkRegistrationTy; -} - -/// The __CxxFrameHandler3 registration node: -/// struct CXXExceptionRegistration { -/// void *SavedESP; -/// EHRegistrationNode SubRecord; -/// int32_t TryLevel; -/// }; -Type *WinEHStatePass::getCXXEHRegistrationType() { - if (CXXEHRegistrationTy) - return CXXEHRegistrationTy; - LLVMContext &Context = TheModule->getContext(); - Type *FieldTys[] = { - Type::getInt8PtrTy(Context), // void *SavedESP - getEHLinkRegistrationType(), // EHRegistrationNode SubRecord - Type::getInt32Ty(Context) // int32_t TryLevel - }; - CXXEHRegistrationTy = - StructType::create(FieldTys, "CXXExceptionRegistration"); - return CXXEHRegistrationTy; -} - -/// The _except_handler3/4 registration node: -/// struct EH4ExceptionRegistration { -/// void *SavedESP; -/// _EXCEPTION_POINTERS *ExceptionPointers; -/// EHRegistrationNode SubRecord; -/// int32_t EncodedScopeTable; -/// int32_t TryLevel; -/// }; -Type *WinEHStatePass::getSEHRegistrationType() { - if (SEHRegistrationTy) - return SEHRegistrationTy; - LLVMContext &Context = TheModule->getContext(); - Type *FieldTys[] = { - Type::getInt8PtrTy(Context), // void *SavedESP - Type::getInt8PtrTy(Context), // void *ExceptionPointers - getEHLinkRegistrationType(), // EHRegistrationNode SubRecord - Type::getInt32Ty(Context), // int32_t EncodedScopeTable - Type::getInt32Ty(Context) // int32_t TryLevel - }; - SEHRegistrationTy = StructType::create(FieldTys, "SEHExceptionRegistration"); - return SEHRegistrationTy; -} - -// Emit an exception registration record. These are stack allocations with the -// common subobject of two pointers: the previous registration record (the old -// fs:00) and the personality function for the current frame. The data before -// and after that is personality function specific. -void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { - assert(Personality == EHPersonality::MSVC_CXX || - Personality == EHPersonality::MSVC_X86SEH); - - // Struct type of RegNode. Used for GEPing. - Type *RegNodeTy; - - IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin()); - Type *Int8PtrType = Builder.getInt8PtrTy(); - Type *Int32Ty = Builder.getInt32Ty(); - Type *VoidTy = Builder.getVoidTy(); - - if (Personality == EHPersonality::MSVC_CXX) { - RegNodeTy = getCXXEHRegistrationType(); - RegNode = Builder.CreateAlloca(RegNodeTy); - // SavedESP = llvm.stacksave() - Value *SP = Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); - Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - // TryLevel = -1 - StateFieldIndex = 2; - ParentBaseState = -1; - insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState); - // Handler = __ehhandler$F - Function *Trampoline = generateLSDAInEAXThunk(F); - Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1); - linkExceptionRegistration(Builder, Trampoline); - - CxxLongjmpUnwind = TheModule->getOrInsertFunction( - "__CxxLongjmpUnwind", - FunctionType::get(VoidTy, Int8PtrType, /*isVarArg=*/false)); - cast<Function>(CxxLongjmpUnwind->stripPointerCasts()) - ->setCallingConv(CallingConv::X86_StdCall); - } else if (Personality == EHPersonality::MSVC_X86SEH) { - // If _except_handler4 is in use, some additional guard checks and prologue - // stuff is required. - StringRef PersonalityName = PersonalityFn->getName(); - UseStackGuard = (PersonalityName == "_except_handler4"); - - // Allocate local structures. - RegNodeTy = getSEHRegistrationType(); - RegNode = Builder.CreateAlloca(RegNodeTy); - if (UseStackGuard) - EHGuardNode = Builder.CreateAlloca(Int32Ty); - - // SavedESP = llvm.stacksave() - Value *SP = Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); - Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - // TryLevel = -2 / -1 - StateFieldIndex = 4; - ParentBaseState = UseStackGuard ? -2 : -1; - insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState); - // ScopeTable = llvm.x86.seh.lsda(F) - Value *LSDA = emitEHLSDA(Builder, F); - LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty); - // If using _except_handler4, xor the address of the table with - // __security_cookie. - if (UseStackGuard) { - Cookie = TheModule->getOrInsertGlobal("__security_cookie", Int32Ty); - Value *Val = Builder.CreateLoad(Int32Ty, Cookie, "cookie"); - LSDA = Builder.CreateXor(LSDA, Val); - } - Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3)); - - // If using _except_handler4, the EHGuard contains: FramePtr xor Cookie. - if (UseStackGuard) { - Value *Val = Builder.CreateLoad(Int32Ty, Cookie); - Value *FrameAddr = Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress), - Builder.getInt32(0), "frameaddr"); - Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr, Int32Ty); - FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val); - Builder.CreateStore(FrameAddrI32, EHGuardNode); - } - - // Register the exception handler. - Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2); - linkExceptionRegistration(Builder, PersonalityFn); - - SehLongjmpUnwind = TheModule->getOrInsertFunction( - UseStackGuard ? "_seh_longjmp_unwind4" : "_seh_longjmp_unwind", - FunctionType::get(Type::getVoidTy(TheModule->getContext()), Int8PtrType, - /*isVarArg=*/false)); - cast<Function>(SehLongjmpUnwind->stripPointerCasts()) - ->setCallingConv(CallingConv::X86_StdCall); - } else { - llvm_unreachable("unexpected personality function"); - } - - // Insert an unlink before all returns. - for (BasicBlock &BB : *F) { - Instruction *T = BB.getTerminator(); - if (!isa<ReturnInst>(T)) - continue; - Builder.SetInsertPoint(T); - unlinkExceptionRegistration(Builder); - } -} - -Value *WinEHStatePass::emitEHLSDA(IRBuilder<> &Builder, Function *F) { - Value *FI8 = Builder.CreateBitCast(F, Type::getInt8PtrTy(F->getContext())); - return Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8); -} - -/// Generate a thunk that puts the LSDA of ParentFunc in EAX and then calls -/// PersonalityFn, forwarding the parameters passed to PEXCEPTION_ROUTINE: -/// typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)( -/// _EXCEPTION_RECORD *, void *, _CONTEXT *, void *); -/// We essentially want this code: -/// movl $lsda, %eax -/// jmpl ___CxxFrameHandler3 -Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) { - LLVMContext &Context = ParentFunc->getContext(); - Type *Int32Ty = Type::getInt32Ty(Context); - Type *Int8PtrType = Type::getInt8PtrTy(Context); - Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType, - Int8PtrType}; - FunctionType *TrampolineTy = - FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 4), - /*isVarArg=*/false); - FunctionType *TargetFuncTy = - FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 5), - /*isVarArg=*/false); - Function *Trampoline = - Function::Create(TrampolineTy, GlobalValue::InternalLinkage, - Twine("__ehhandler$") + GlobalValue::dropLLVMManglingEscape( - ParentFunc->getName()), - TheModule); - if (auto *C = ParentFunc->getComdat()) - Trampoline->setComdat(C); - BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", Trampoline); - IRBuilder<> Builder(EntryBB); - Value *LSDA = emitEHLSDA(Builder, ParentFunc); - Value *CastPersonality = - Builder.CreateBitCast(PersonalityFn, TargetFuncTy->getPointerTo()); - auto AI = Trampoline->arg_begin(); - Value *Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++}; - CallInst *Call = Builder.CreateCall(CastPersonality, Args); - // Can't use musttail due to prototype mismatch, but we can use tail. - Call->setTailCall(true); - // Set inreg so we pass it in EAX. - Call->addParamAttr(0, Attribute::InReg); - Builder.CreateRet(Call); - return Trampoline; -} - -void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder, - Function *Handler) { - // Emit the .safeseh directive for this function. - Handler->addFnAttr("safeseh"); - - Type *LinkTy = getEHLinkRegistrationType(); - // Handler = Handler - Value *HandlerI8 = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy()); - Builder.CreateStore(HandlerI8, Builder.CreateStructGEP(LinkTy, Link, 1)); - // Next = [fs:00] - Constant *FSZero = - Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257)); - Value *Next = Builder.CreateLoad(FSZero); - Builder.CreateStore(Next, Builder.CreateStructGEP(LinkTy, Link, 0)); - // [fs:00] = Link - Builder.CreateStore(Link, FSZero); -} - -void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) { - // Clone Link into the current BB for better address mode folding. - if (auto *GEP = dyn_cast<GetElementPtrInst>(Link)) { - GEP = cast<GetElementPtrInst>(GEP->clone()); - Builder.Insert(GEP); - Link = GEP; - } - Type *LinkTy = getEHLinkRegistrationType(); - // [fs:00] = Link->Next - Value *Next = - Builder.CreateLoad(Builder.CreateStructGEP(LinkTy, Link, 0)); - Constant *FSZero = - Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257)); - Builder.CreateStore(Next, FSZero); -} - -// Calls to setjmp(p) are lowered to _setjmp3(p, 0) by the frontend. -// The idea behind _setjmp3 is that it takes an optional number of personality -// specific parameters to indicate how to restore the personality-specific frame -// state when longjmp is initiated. Typically, the current TryLevel is saved. -void WinEHStatePass::rewriteSetJmpCallSite(IRBuilder<> &Builder, Function &F, - CallSite CS, Value *State) { - // Don't rewrite calls with a weird number of arguments. - if (CS.getNumArgOperands() != 2) - return; - - Instruction *Inst = CS.getInstruction(); - - SmallVector<OperandBundleDef, 1> OpBundles; - CS.getOperandBundlesAsDefs(OpBundles); - - SmallVector<Value *, 3> OptionalArgs; - if (Personality == EHPersonality::MSVC_CXX) { - OptionalArgs.push_back(CxxLongjmpUnwind); - OptionalArgs.push_back(State); - OptionalArgs.push_back(emitEHLSDA(Builder, &F)); - } else if (Personality == EHPersonality::MSVC_X86SEH) { - OptionalArgs.push_back(SehLongjmpUnwind); - OptionalArgs.push_back(State); - if (UseStackGuard) - OptionalArgs.push_back(Cookie); - } else { - llvm_unreachable("unhandled personality!"); - } - - SmallVector<Value *, 5> Args; - Args.push_back( - Builder.CreateBitCast(CS.getArgOperand(0), Builder.getInt8PtrTy())); - Args.push_back(Builder.getInt32(OptionalArgs.size())); - Args.append(OptionalArgs.begin(), OptionalArgs.end()); - - CallSite NewCS; - if (CS.isCall()) { - auto *CI = cast<CallInst>(Inst); - CallInst *NewCI = Builder.CreateCall(SetJmp3, Args, OpBundles); - NewCI->setTailCallKind(CI->getTailCallKind()); - NewCS = NewCI; - } else { - auto *II = cast<InvokeInst>(Inst); - NewCS = Builder.CreateInvoke( - SetJmp3, II->getNormalDest(), II->getUnwindDest(), Args, OpBundles); - } - NewCS.setCallingConv(CS.getCallingConv()); - NewCS.setAttributes(CS.getAttributes()); - NewCS->setDebugLoc(CS->getDebugLoc()); - - Instruction *NewInst = NewCS.getInstruction(); - NewInst->takeName(Inst); - Inst->replaceAllUsesWith(NewInst); - Inst->eraseFromParent(); -} - -// Figure out what state we should assign calls in this block. -int WinEHStatePass::getBaseStateForBB( - DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo, - BasicBlock *BB) { - int BaseState = ParentBaseState; - auto &BBColors = BlockColors[BB]; - - assert(BBColors.size() == 1 && "multi-color BB not removed by preparation"); - BasicBlock *FuncletEntryBB = BBColors.front(); - if (auto *FuncletPad = - dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI())) { - auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad); - if (BaseStateI != FuncInfo.FuncletBaseStateMap.end()) - BaseState = BaseStateI->second; - } - - return BaseState; -} - -// Calculate the state a call-site is in. -int WinEHStatePass::getStateForCallSite( - DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo, - CallSite CS) { - if (auto *II = dyn_cast<InvokeInst>(CS.getInstruction())) { - // Look up the state number of the EH pad this unwinds to. - assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!"); - return FuncInfo.InvokeStateMap[II]; - } - // Possibly throwing call instructions have no actions to take after - // an unwind. Ensure they are in the -1 state. - return getBaseStateForBB(BlockColors, FuncInfo, CS.getParent()); -} - -// Calculate the intersection of all the FinalStates for a BasicBlock's -// predecessors. -static int getPredState(DenseMap<BasicBlock *, int> &FinalStates, Function &F, - int ParentBaseState, BasicBlock *BB) { - // The entry block has no predecessors but we know that the prologue always - // sets us up with a fixed state. - if (&F.getEntryBlock() == BB) - return ParentBaseState; - - // This is an EH Pad, conservatively report this basic block as overdefined. - if (BB->isEHPad()) - return OverdefinedState; - - int CommonState = OverdefinedState; - for (BasicBlock *PredBB : predecessors(BB)) { - // We didn't manage to get a state for one of these predecessors, - // conservatively report this basic block as overdefined. - auto PredEndState = FinalStates.find(PredBB); - if (PredEndState == FinalStates.end()) - return OverdefinedState; - - // This code is reachable via exceptional control flow, - // conservatively report this basic block as overdefined. - if (isa<CatchReturnInst>(PredBB->getTerminator())) - return OverdefinedState; - - int PredState = PredEndState->second; - assert(PredState != OverdefinedState && - "overdefined BBs shouldn't be in FinalStates"); - if (CommonState == OverdefinedState) - CommonState = PredState; - - // At least two predecessors have different FinalStates, - // conservatively report this basic block as overdefined. - if (CommonState != PredState) - return OverdefinedState; - } - - return CommonState; -} - -// Calculate the intersection of all the InitialStates for a BasicBlock's -// successors. -static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F, - int ParentBaseState, BasicBlock *BB) { - // This block rejoins normal control flow, - // conservatively report this basic block as overdefined. - if (isa<CatchReturnInst>(BB->getTerminator())) - return OverdefinedState; - - int CommonState = OverdefinedState; - for (BasicBlock *SuccBB : successors(BB)) { - // We didn't manage to get a state for one of these predecessors, - // conservatively report this basic block as overdefined. - auto SuccStartState = InitialStates.find(SuccBB); - if (SuccStartState == InitialStates.end()) - return OverdefinedState; - - // This is an EH Pad, conservatively report this basic block as overdefined. - if (SuccBB->isEHPad()) - return OverdefinedState; - - int SuccState = SuccStartState->second; - assert(SuccState != OverdefinedState && - "overdefined BBs shouldn't be in FinalStates"); - if (CommonState == OverdefinedState) - CommonState = SuccState; - - // At least two successors have different InitialStates, - // conservatively report this basic block as overdefined. - if (CommonState != SuccState) - return OverdefinedState; - } - - return CommonState; -} - -bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality, - CallSite CS) { - if (!CS) - return false; - - // If the function touches memory, it needs a state store. - if (isAsynchronousEHPersonality(Personality)) - return !CS.doesNotAccessMemory(); - - // If the function throws, it needs a state store. - return !CS.doesNotThrow(); -} - -void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) { - // Mark the registration node. The backend needs to know which alloca it is so - // that it can recover the original frame pointer. - IRBuilder<> Builder(RegNode->getNextNode()); - Value *RegNodeI8 = Builder.CreateBitCast(RegNode, Builder.getInt8PtrTy()); - Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehregnode), - {RegNodeI8}); - - if (EHGuardNode) { - IRBuilder<> Builder(EHGuardNode->getNextNode()); - Value *EHGuardNodeI8 = - Builder.CreateBitCast(EHGuardNode, Builder.getInt8PtrTy()); - Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehguard), - {EHGuardNodeI8}); - } - - // Calculate state numbers. - if (isAsynchronousEHPersonality(Personality)) - calculateSEHStateNumbers(&F, FuncInfo); - else - calculateWinCXXEHStateNumbers(&F, FuncInfo); - - // Iterate all the instructions and emit state number stores. - DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(F); - ReversePostOrderTraversal<Function *> RPOT(&F); - - // InitialStates yields the state of the first call-site for a BasicBlock. - DenseMap<BasicBlock *, int> InitialStates; - // FinalStates yields the state of the last call-site for a BasicBlock. - DenseMap<BasicBlock *, int> FinalStates; - // Worklist used to revisit BasicBlocks with indeterminate - // Initial/Final-States. - std::deque<BasicBlock *> Worklist; - // Fill in InitialStates and FinalStates for BasicBlocks with call-sites. - for (BasicBlock *BB : RPOT) { - int InitialState = OverdefinedState; - int FinalState; - if (&F.getEntryBlock() == BB) - InitialState = FinalState = ParentBaseState; - for (Instruction &I : *BB) { - CallSite CS(&I); - if (!isStateStoreNeeded(Personality, CS)) - continue; - - int State = getStateForCallSite(BlockColors, FuncInfo, CS); - if (InitialState == OverdefinedState) - InitialState = State; - FinalState = State; - } - // No call-sites in this basic block? That's OK, we will come back to these - // in a later pass. - if (InitialState == OverdefinedState) { - Worklist.push_back(BB); - continue; - } - LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName() - << " InitialState=" << InitialState << '\n'); - LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName() - << " FinalState=" << FinalState << '\n'); - InitialStates.insert({BB, InitialState}); - FinalStates.insert({BB, FinalState}); - } - - // Try to fill-in InitialStates and FinalStates which have no call-sites. - while (!Worklist.empty()) { - BasicBlock *BB = Worklist.front(); - Worklist.pop_front(); - // This BasicBlock has already been figured out, nothing more we can do. - if (InitialStates.count(BB) != 0) - continue; - - int PredState = getPredState(FinalStates, F, ParentBaseState, BB); - if (PredState == OverdefinedState) - continue; - - // We successfully inferred this BasicBlock's state via it's predecessors; - // enqueue it's successors to see if we can infer their states. - InitialStates.insert({BB, PredState}); - FinalStates.insert({BB, PredState}); - for (BasicBlock *SuccBB : successors(BB)) - Worklist.push_back(SuccBB); - } - - // Try to hoist stores from successors. - for (BasicBlock *BB : RPOT) { - int SuccState = getSuccState(InitialStates, F, ParentBaseState, BB); - if (SuccState == OverdefinedState) - continue; - - // Update our FinalState to reflect the common InitialState of our - // successors. - FinalStates.insert({BB, SuccState}); - } - - // Finally, insert state stores before call-sites which transition us to a new - // state. - for (BasicBlock *BB : RPOT) { - auto &BBColors = BlockColors[BB]; - BasicBlock *FuncletEntryBB = BBColors.front(); - if (isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHI())) - continue; - - int PrevState = getPredState(FinalStates, F, ParentBaseState, BB); - LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName() - << " PrevState=" << PrevState << '\n'); - - for (Instruction &I : *BB) { - CallSite CS(&I); - if (!isStateStoreNeeded(Personality, CS)) - continue; - - int State = getStateForCallSite(BlockColors, FuncInfo, CS); - if (State != PrevState) - insertStateNumberStore(&I, State); - PrevState = State; - } - - // We might have hoisted a state store into this block, emit it now. - auto EndState = FinalStates.find(BB); - if (EndState != FinalStates.end()) - if (EndState->second != PrevState) - insertStateNumberStore(BB->getTerminator(), EndState->second); - } - - SmallVector<CallSite, 1> SetJmp3CallSites; - for (BasicBlock *BB : RPOT) { - for (Instruction &I : *BB) { - CallSite CS(&I); - if (!CS) - continue; - if (CS.getCalledValue()->stripPointerCasts() != - SetJmp3->stripPointerCasts()) - continue; - - SetJmp3CallSites.push_back(CS); - } - } - - for (CallSite CS : SetJmp3CallSites) { - auto &BBColors = BlockColors[CS->getParent()]; - BasicBlock *FuncletEntryBB = BBColors.front(); - bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHI()); - - IRBuilder<> Builder(CS.getInstruction()); - Value *State; - if (InCleanup) { - Value *StateField = - Builder.CreateStructGEP(nullptr, RegNode, StateFieldIndex); - State = Builder.CreateLoad(StateField); - } else { - State = Builder.getInt32(getStateForCallSite(BlockColors, FuncInfo, CS)); - } - rewriteSetJmpCallSite(Builder, F, CS, State); - } -} - -void WinEHStatePass::insertStateNumberStore(Instruction *IP, int State) { - IRBuilder<> Builder(IP); - Value *StateField = - Builder.CreateStructGEP(nullptr, RegNode, StateFieldIndex); - Builder.CreateStore(Builder.getInt32(State), StateField); -} |
