123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- //===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // 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/CFG.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/IRBuilder.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/Intrinsics.h"
- #include "llvm/IR/IntrinsicsX86.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) { }
- 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, CallBase &Call);
- void rewriteSetJmpCall(IRBuilder<> &Builder, Function &F, CallBase &Call,
- Value *State);
- int getBaseStateForBB(DenseMap<BasicBlock *, ColorVector> &BlockColors,
- WinEHFuncInfo &FuncInfo, BasicBlock *BB);
- int getStateForCall(DenseMap<BasicBlock *, ColorVector> &BlockColors,
- WinEHFuncInfo &FuncInfo, CallBase &Call);
- // 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;
- FunctionCallee SetJmp3 = nullptr;
- FunctionCallee CxxLongjmpUnwind = nullptr;
- // Per-function state
- EHPersonality Personality = EHPersonality::Unknown;
- Function *PersonalityFn = nullptr;
- bool UseStackGuard = false;
- int ParentBaseState = 0;
- FunctionCallee 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;
- };
- } // namespace
- 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));
- 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.getCallee()->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.getInt8PtrTy(
- TheModule->getDataLayout().getAllocaAddrSpace())),
- 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.getCallee()->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(TargetFuncTy, 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(LinkTy->getPointerTo(), 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(LinkTy->getPointerTo(),
- 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::rewriteSetJmpCall(IRBuilder<> &Builder, Function &F,
- CallBase &Call, Value *State) {
- // Don't rewrite calls with a weird number of arguments.
- if (Call.arg_size() != 2)
- return;
- SmallVector<OperandBundleDef, 1> OpBundles;
- Call.getOperandBundlesAsDefs(OpBundles);
- SmallVector<Value *, 3> OptionalArgs;
- if (Personality == EHPersonality::MSVC_CXX) {
- OptionalArgs.push_back(CxxLongjmpUnwind.getCallee());
- OptionalArgs.push_back(State);
- OptionalArgs.push_back(emitEHLSDA(Builder, &F));
- } else if (Personality == EHPersonality::MSVC_X86SEH) {
- OptionalArgs.push_back(SehLongjmpUnwind.getCallee());
- OptionalArgs.push_back(State);
- if (UseStackGuard)
- OptionalArgs.push_back(Cookie);
- } else {
- llvm_unreachable("unhandled personality!");
- }
- SmallVector<Value *, 5> Args;
- Args.push_back(
- Builder.CreateBitCast(Call.getArgOperand(0), Builder.getInt8PtrTy()));
- Args.push_back(Builder.getInt32(OptionalArgs.size()));
- Args.append(OptionalArgs.begin(), OptionalArgs.end());
- CallBase *NewCall;
- if (auto *CI = dyn_cast<CallInst>(&Call)) {
- CallInst *NewCI = Builder.CreateCall(SetJmp3, Args, OpBundles);
- NewCI->setTailCallKind(CI->getTailCallKind());
- NewCall = NewCI;
- } else {
- auto *II = cast<InvokeInst>(&Call);
- NewCall = Builder.CreateInvoke(
- SetJmp3, II->getNormalDest(), II->getUnwindDest(), Args, OpBundles);
- }
- NewCall->setCallingConv(Call.getCallingConv());
- NewCall->setAttributes(Call.getAttributes());
- NewCall->setDebugLoc(Call.getDebugLoc());
- NewCall->takeName(&Call);
- Call.replaceAllUsesWith(NewCall);
- Call.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::getStateForCall(
- DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,
- CallBase &Call) {
- if (auto *II = dyn_cast<InvokeInst>(&Call)) {
- // 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, Call.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,
- CallBase &Call) {
- // If the function touches memory, it needs a state store.
- if (isAsynchronousEHPersonality(Personality))
- return !Call.doesNotAccessMemory();
- // If the function throws, it needs a state store.
- return !Call.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) {
- auto *Call = dyn_cast<CallBase>(&I);
- if (!Call || !isStateStoreNeeded(Personality, *Call))
- continue;
- int State = getStateForCall(BlockColors, FuncInfo, *Call);
- 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) {
- auto *Call = dyn_cast<CallBase>(&I);
- if (!Call || !isStateStoreNeeded(Personality, *Call))
- continue;
- int State = getStateForCall(BlockColors, FuncInfo, *Call);
- 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<CallBase *, 1> SetJmp3Calls;
- for (BasicBlock *BB : RPOT) {
- for (Instruction &I : *BB) {
- auto *Call = dyn_cast<CallBase>(&I);
- if (!Call)
- continue;
- if (Call->getCalledOperand()->stripPointerCasts() !=
- SetJmp3.getCallee()->stripPointerCasts())
- continue;
- SetJmp3Calls.push_back(Call);
- }
- }
- for (CallBase *Call : SetJmp3Calls) {
- auto &BBColors = BlockColors[Call->getParent()];
- BasicBlock *FuncletEntryBB = BBColors.front();
- bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHI());
- IRBuilder<> Builder(Call);
- Value *State;
- if (InCleanup) {
- Value *StateField = Builder.CreateStructGEP(RegNode->getAllocatedType(),
- RegNode, StateFieldIndex);
- State = Builder.CreateLoad(Builder.getInt32Ty(), StateField);
- } else {
- State = Builder.getInt32(getStateForCall(BlockColors, FuncInfo, *Call));
- }
- rewriteSetJmpCall(Builder, F, *Call, State);
- }
- }
- void WinEHStatePass::insertStateNumberStore(Instruction *IP, int State) {
- IRBuilder<> Builder(IP);
- Value *StateField = Builder.CreateStructGEP(RegNode->getAllocatedType(),
- RegNode, StateFieldIndex);
- Builder.CreateStore(Builder.getInt32(State), StateField);
- }
|