brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.0 KiB · a650f6f Raw
831 lines · cpp
1//===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// All functions using an MSVC EH personality use an explicitly updated state10// number stored in an exception registration stack object. The registration11// object is linked into a thread-local chain of registrations stored at fs:00.12// This pass adds the registration object and EH state updates.13//14//===----------------------------------------------------------------------===//15 16#include "X86.h"17#include "llvm/ADT/PostOrderIterator.h"18#include "llvm/Analysis/CFG.h"19#include "llvm/CodeGen/MachineModuleInfo.h"20#include "llvm/CodeGen/WinEHFuncInfo.h"21#include "llvm/IR/CFG.h"22#include "llvm/IR/EHPersonalities.h"23#include "llvm/IR/Function.h"24#include "llvm/IR/IRBuilder.h"25#include "llvm/IR/Instructions.h"26#include "llvm/IR/IntrinsicInst.h"27#include "llvm/IR/Intrinsics.h"28#include "llvm/IR/IntrinsicsX86.h"29#include "llvm/IR/Module.h"30#include "llvm/Pass.h"31#include "llvm/Support/Debug.h"32#include <deque>33 34using namespace llvm;35 36#define DEBUG_TYPE "winehstate"37 38namespace {39const int OverdefinedState = INT_MIN;40 41class WinEHStatePass : public FunctionPass {42public:43  static char ID; // Pass identification, replacement for typeid.44 45  WinEHStatePass() : FunctionPass(ID) {}46 47  bool runOnFunction(Function &Fn) override;48 49  bool doInitialization(Module &M) override;50 51  bool doFinalization(Module &M) override;52 53  void getAnalysisUsage(AnalysisUsage &AU) const override;54 55  StringRef getPassName() const override {56    return "Windows 32-bit x86 EH state insertion";57  }58 59private:60  void emitExceptionRegistrationRecord(Function *F);61 62  void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler);63  void unlinkExceptionRegistration(IRBuilder<> &Builder);64  void addStateStores(Function &F, WinEHFuncInfo &FuncInfo);65  void insertStateNumberStore(Instruction *IP, int State);66 67  Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);68 69  Function *generateLSDAInEAXThunk(Function *ParentFunc);70 71  bool isStateStoreNeeded(EHPersonality Personality, CallBase &Call);72  void rewriteSetJmpCall(IRBuilder<> &Builder, Function &F, CallBase &Call,73                         Value *State);74  int getBaseStateForBB(DenseMap<BasicBlock *, ColorVector> &BlockColors,75                        WinEHFuncInfo &FuncInfo, BasicBlock *BB);76  int getStateForCall(DenseMap<BasicBlock *, ColorVector> &BlockColors,77                      WinEHFuncInfo &FuncInfo, CallBase &Call);78 79  void updateEspForInAllocas(Function &F);80 81  // Module-level type getters.82  Type *getEHLinkRegistrationType();83  Type *getSEHRegistrationType();84  Type *getCXXEHRegistrationType();85 86  // Per-module data.87  Module *TheModule = nullptr;88  StructType *EHLinkRegistrationTy = nullptr;89  StructType *CXXEHRegistrationTy = nullptr;90  StructType *SEHRegistrationTy = nullptr;91  FunctionCallee SetJmp3 = nullptr;92  FunctionCallee CxxLongjmpUnwind = nullptr;93 94  // Per-function state95  EHPersonality Personality = EHPersonality::Unknown;96  Function *PersonalityFn = nullptr;97  bool UseStackGuard = false;98  int ParentBaseState = 0;99  FunctionCallee SehLongjmpUnwind = nullptr;100  Constant *Cookie = nullptr;101 102  /// The stack allocation containing all EH data, including the link in the103  /// fs:00 chain and the current state.104  AllocaInst *RegNode = nullptr;105 106  // Struct type of RegNode. Used for GEPing.107  Type *RegNodeTy = nullptr;108 109  // The allocation containing the EH security guard.110  AllocaInst *EHGuardNode = nullptr;111 112  /// The index of the state field of RegNode.113  int StateFieldIndex = ~0U;114 115  /// The linked list node subobject inside of RegNode.116  Value *Link = nullptr;117};118} // namespace119 120FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); }121 122char WinEHStatePass::ID = 0;123 124INITIALIZE_PASS(WinEHStatePass, "x86-winehstate",125                "Insert stores for EH state numbers", false, false)126 127bool WinEHStatePass::doInitialization(Module &M) {128  TheModule = &M;129  return false;130}131 132bool WinEHStatePass::doFinalization(Module &M) {133  assert(TheModule == &M);134  TheModule = nullptr;135  EHLinkRegistrationTy = nullptr;136  CXXEHRegistrationTy = nullptr;137  SEHRegistrationTy = nullptr;138  SetJmp3 = nullptr;139  CxxLongjmpUnwind = nullptr;140  SehLongjmpUnwind = nullptr;141  Cookie = nullptr;142  return false;143}144 145void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const {146  // This pass should only insert a stack allocation, memory accesses, and147  // localrecovers.148  AU.setPreservesCFG();149}150 151bool WinEHStatePass::runOnFunction(Function &F) {152  // Don't insert state stores or exception handler thunks for153  // available_externally functions. The handler needs to reference the LSDA,154  // which will not be emitted in this case.155  if (F.hasAvailableExternallyLinkage())156    return false;157 158  // Check the personality. Do nothing if this personality doesn't use funclets.159  if (!F.hasPersonalityFn())160    return false;161  PersonalityFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());162  if (!PersonalityFn)163    return false;164  Personality = classifyEHPersonality(PersonalityFn);165  if (!isFuncletEHPersonality(Personality))166    return false;167 168  // Skip this function if there are no EH pads and we aren't using IR-level169  // outlining.170  bool HasPads = false;171  for (BasicBlock &BB : F) {172    if (BB.isEHPad()) {173      HasPads = true;174      break;175    }176  }177  if (!HasPads)178    return false;179 180  Type *Int8PtrType = PointerType::getUnqual(TheModule->getContext());181  SetJmp3 = TheModule->getOrInsertFunction(182      "_setjmp3", FunctionType::get(183                      Type::getInt32Ty(TheModule->getContext()),184                      {Int8PtrType, Type::getInt32Ty(TheModule->getContext())},185                      /*isVarArg=*/true));186 187  emitExceptionRegistrationRecord(&F);188 189  // The state numbers calculated here in IR must agree with what we calculate190  // later on for the MachineFunction. In particular, if an IR pass deletes an191  // unreachable EH pad after this point before machine CFG construction, we192  // will be in trouble. If this assumption is ever broken, we should turn the193  // numbers into an immutable analysis pass.194  WinEHFuncInfo FuncInfo;195  addStateStores(F, FuncInfo);196  updateEspForInAllocas(F);197 198  // Reset per-function state.199  PersonalityFn = nullptr;200  Personality = EHPersonality::Unknown;201  UseStackGuard = false;202  RegNodeTy = nullptr;203  RegNode = nullptr;204  EHGuardNode = nullptr;205 206  return true;207}208 209/// Get the common EH registration subobject:210///   typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(211///       _EXCEPTION_RECORD *, void *, _CONTEXT *, void *);212///   struct EHRegistrationNode {213///     EHRegistrationNode *Next;214///     PEXCEPTION_ROUTINE Handler;215///   };216Type *WinEHStatePass::getEHLinkRegistrationType() {217  if (EHLinkRegistrationTy)218    return EHLinkRegistrationTy;219  LLVMContext &Context = TheModule->getContext();220  Type *FieldTys[] = {221      PointerType::getUnqual(Context), // EHRegistrationNode *Next222      PointerType::getUnqual(Context)  // EXCEPTION_DISPOSITION (*Handler)(...)223  };224  EHLinkRegistrationTy = StructType::create(FieldTys, "EHRegistrationNode");225  return EHLinkRegistrationTy;226}227 228/// The __CxxFrameHandler3 registration node:229///   struct CXXExceptionRegistration {230///     void *SavedESP;231///     EHRegistrationNode SubRecord;232///     int32_t TryLevel;233///   };234Type *WinEHStatePass::getCXXEHRegistrationType() {235  if (CXXEHRegistrationTy)236    return CXXEHRegistrationTy;237  LLVMContext &Context = TheModule->getContext();238  Type *FieldTys[] = {239      PointerType::getUnqual(Context), // void *SavedESP240      getEHLinkRegistrationType(),     // EHRegistrationNode SubRecord241      Type::getInt32Ty(Context)        // int32_t TryLevel242  };243  CXXEHRegistrationTy =244      StructType::create(FieldTys, "CXXExceptionRegistration");245  return CXXEHRegistrationTy;246}247 248/// The _except_handler3/4 registration node:249///   struct EH4ExceptionRegistration {250///     void *SavedESP;251///     _EXCEPTION_POINTERS *ExceptionPointers;252///     EHRegistrationNode SubRecord;253///     int32_t EncodedScopeTable;254///     int32_t TryLevel;255///   };256Type *WinEHStatePass::getSEHRegistrationType() {257  if (SEHRegistrationTy)258    return SEHRegistrationTy;259  LLVMContext &Context = TheModule->getContext();260  Type *FieldTys[] = {261      PointerType::getUnqual(Context), // void *SavedESP262      PointerType::getUnqual(Context), // void *ExceptionPointers263      getEHLinkRegistrationType(),     // EHRegistrationNode SubRecord264      Type::getInt32Ty(Context),       // int32_t EncodedScopeTable265      Type::getInt32Ty(Context)        // int32_t TryLevel266  };267  SEHRegistrationTy = StructType::create(FieldTys, "SEHExceptionRegistration");268  return SEHRegistrationTy;269}270 271// Emit an exception registration record. These are stack allocations with the272// common subobject of two pointers: the previous registration record (the old273// fs:00) and the personality function for the current frame. The data before274// and after that is personality function specific.275void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {276  assert(Personality == EHPersonality::MSVC_CXX ||277         Personality == EHPersonality::MSVC_X86SEH);278 279  IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());280  Type *Int8PtrType = Builder.getPtrTy();281  Type *Int32Ty = Builder.getInt32Ty();282  Type *VoidTy = Builder.getVoidTy();283 284  if (Personality == EHPersonality::MSVC_CXX) {285    RegNodeTy = getCXXEHRegistrationType();286    RegNode = Builder.CreateAlloca(RegNodeTy);287    // SavedESP = llvm.stacksave()288    Value *SP = Builder.CreateStackSave();289    Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));290    // TryLevel = -1291    StateFieldIndex = 2;292    ParentBaseState = -1;293    insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);294    // Handler = __ehhandler$F295    Function *Trampoline = generateLSDAInEAXThunk(F);296    Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);297    linkExceptionRegistration(Builder, Trampoline);298 299    CxxLongjmpUnwind = TheModule->getOrInsertFunction(300        "__CxxLongjmpUnwind",301        FunctionType::get(VoidTy, Int8PtrType, /*isVarArg=*/false));302    cast<Function>(CxxLongjmpUnwind.getCallee()->stripPointerCasts())303        ->setCallingConv(CallingConv::X86_StdCall);304  } else if (Personality == EHPersonality::MSVC_X86SEH) {305    // If _except_handler4 is in use, some additional guard checks and prologue306    // stuff is required.307    StringRef PersonalityName = PersonalityFn->getName();308    UseStackGuard = (PersonalityName == "_except_handler4");309 310    // Allocate local structures.311    RegNodeTy = getSEHRegistrationType();312    RegNode = Builder.CreateAlloca(RegNodeTy);313    if (UseStackGuard)314      EHGuardNode = Builder.CreateAlloca(Int32Ty);315 316    // SavedESP = llvm.stacksave()317    Value *SP = Builder.CreateStackSave();318    Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));319    // TryLevel = -2 / -1320    StateFieldIndex = 4;321    ParentBaseState = UseStackGuard ? -2 : -1;322    insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);323    // ScopeTable = llvm.x86.seh.lsda(F)324    Value *LSDA = emitEHLSDA(Builder, F);325    LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty);326    // If using _except_handler4, xor the address of the table with327    // __security_cookie.328    if (UseStackGuard) {329      Cookie = TheModule->getOrInsertGlobal("__security_cookie", Int32Ty);330      Value *Val = Builder.CreateLoad(Int32Ty, Cookie, "cookie");331      LSDA = Builder.CreateXor(LSDA, Val);332    }333    Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3));334 335    // If using _except_handler4, the EHGuard contains: FramePtr xor Cookie.336    if (UseStackGuard) {337      Value *Val = Builder.CreateLoad(Int32Ty, Cookie);338      Value *FrameAddr = Builder.CreateIntrinsic(339          Intrinsic::frameaddress,340          Builder.getPtrTy(TheModule->getDataLayout().getAllocaAddrSpace()),341          Builder.getInt32(0), /*FMFSource=*/nullptr, "frameaddr");342      Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr, Int32Ty);343      FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val);344      Builder.CreateStore(FrameAddrI32, EHGuardNode);345    }346 347    // Register the exception handler.348    Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);349    linkExceptionRegistration(Builder, PersonalityFn);350 351    SehLongjmpUnwind = TheModule->getOrInsertFunction(352        UseStackGuard ? "_seh_longjmp_unwind4" : "_seh_longjmp_unwind",353        FunctionType::get(Type::getVoidTy(TheModule->getContext()), Int8PtrType,354                          /*isVarArg=*/false));355    cast<Function>(SehLongjmpUnwind.getCallee()->stripPointerCasts())356        ->setCallingConv(CallingConv::X86_StdCall);357  } else {358    llvm_unreachable("unexpected personality function");359  }360 361  // Insert an unlink before all returns.362  for (BasicBlock &BB : *F) {363    Instruction *T = BB.getTerminator();364    if (!isa<ReturnInst>(T))365      continue;366 367    // If there is a musttail call, that's the de-facto terminator.368    if (CallInst *CI = BB.getTerminatingMustTailCall())369      T = CI;370 371    Builder.SetInsertPoint(T);372    unlinkExceptionRegistration(Builder);373  }374}375 376Value *WinEHStatePass::emitEHLSDA(IRBuilder<> &Builder, Function *F) {377  return Builder.CreateIntrinsic(Intrinsic::x86_seh_lsda, F);378}379 380/// Generate a thunk that puts the LSDA of ParentFunc in EAX and then calls381/// PersonalityFn, forwarding the parameters passed to PEXCEPTION_ROUTINE:382///   typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(383///       _EXCEPTION_RECORD *, void *, _CONTEXT *, void *);384/// We essentially want this code:385///   movl $lsda, %eax386///   jmpl ___CxxFrameHandler3387Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) {388  LLVMContext &Context = ParentFunc->getContext();389  Type *Int32Ty = Type::getInt32Ty(Context);390  Type *Int8PtrType = PointerType::getUnqual(Context);391  Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,392                     Int8PtrType};393  FunctionType *TrampolineTy =394      FunctionType::get(Int32Ty, ArrayRef(&ArgTys[0], 4),395                        /*isVarArg=*/false);396  FunctionType *TargetFuncTy =397      FunctionType::get(Int32Ty, ArrayRef(&ArgTys[0], 5),398                        /*isVarArg=*/false);399  Function *Trampoline = Function::Create(400      TrampolineTy, GlobalValue::InternalLinkage,401      Twine("__ehhandler$") +402          GlobalValue::dropLLVMManglingEscape(ParentFunc->getName()),403      TheModule);404  if (auto *C = ParentFunc->getComdat())405    Trampoline->setComdat(C);406  BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", Trampoline);407  IRBuilder<> Builder(EntryBB);408  Value *LSDA = emitEHLSDA(Builder, ParentFunc);409  auto AI = Trampoline->arg_begin();410  Value *Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};411  CallInst *Call = Builder.CreateCall(TargetFuncTy, PersonalityFn, Args);412  // Can't use musttail due to prototype mismatch, but we can use tail.413  Call->setTailCall(true);414  // Set inreg so we pass it in EAX.415  Call->addParamAttr(0, Attribute::InReg);416  Builder.CreateRet(Call);417  return Trampoline;418}419 420void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder,421                                               Function *Handler) {422  // Emit the .safeseh directive for this function.423  Handler->addFnAttr("safeseh");424 425  LLVMContext &C = Builder.getContext();426  Type *LinkTy = getEHLinkRegistrationType();427  // Handler = Handler428  Builder.CreateStore(Handler, Builder.CreateStructGEP(LinkTy, Link, 1));429  // Next = [fs:00]430  Constant *FSZero = Constant::getNullValue(PointerType::get(C, X86AS::FS));431  Value *Next = Builder.CreateLoad(PointerType::getUnqual(C), FSZero);432  Builder.CreateStore(Next, Builder.CreateStructGEP(LinkTy, Link, 0));433  // [fs:00] = Link434  Builder.CreateStore(Link, FSZero);435}436 437void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) {438  // Clone Link into the current BB for better address mode folding.439  if (auto *GEP = dyn_cast<GetElementPtrInst>(Link)) {440    GEP = cast<GetElementPtrInst>(GEP->clone());441    Builder.Insert(GEP);442    Link = GEP;443  }444 445  LLVMContext &C = Builder.getContext();446  Type *LinkTy = getEHLinkRegistrationType();447  // [fs:00] = Link->Next448  Value *Next = Builder.CreateLoad(PointerType::getUnqual(C),449                                   Builder.CreateStructGEP(LinkTy, Link, 0));450  Constant *FSZero = Constant::getNullValue(PointerType::get(C, X86AS::FS));451  Builder.CreateStore(Next, FSZero);452}453 454// Calls to setjmp(p) are lowered to _setjmp3(p, 0) by the frontend.455// The idea behind _setjmp3 is that it takes an optional number of personality456// specific parameters to indicate how to restore the personality-specific frame457// state when longjmp is initiated.  Typically, the current TryLevel is saved.458void WinEHStatePass::rewriteSetJmpCall(IRBuilder<> &Builder, Function &F,459                                       CallBase &Call, Value *State) {460  // Don't rewrite calls with a weird number of arguments.461  if (Call.arg_size() != 2)462    return;463 464  SmallVector<OperandBundleDef, 1> OpBundles;465  Call.getOperandBundlesAsDefs(OpBundles);466 467  SmallVector<Value *, 3> OptionalArgs;468  if (Personality == EHPersonality::MSVC_CXX) {469    OptionalArgs.push_back(CxxLongjmpUnwind.getCallee());470    OptionalArgs.push_back(State);471    OptionalArgs.push_back(emitEHLSDA(Builder, &F));472  } else if (Personality == EHPersonality::MSVC_X86SEH) {473    OptionalArgs.push_back(SehLongjmpUnwind.getCallee());474    OptionalArgs.push_back(State);475    if (UseStackGuard)476      OptionalArgs.push_back(Cookie);477  } else {478    llvm_unreachable("unhandled personality!");479  }480 481  SmallVector<Value *, 5> Args;482  Args.push_back(483      Builder.CreateBitCast(Call.getArgOperand(0), Builder.getPtrTy()));484  Args.push_back(Builder.getInt32(OptionalArgs.size()));485  Args.append(OptionalArgs.begin(), OptionalArgs.end());486 487  CallBase *NewCall;488  if (auto *CI = dyn_cast<CallInst>(&Call)) {489    CallInst *NewCI = Builder.CreateCall(SetJmp3, Args, OpBundles);490    NewCI->setTailCallKind(CI->getTailCallKind());491    NewCall = NewCI;492  } else {493    auto *II = cast<InvokeInst>(&Call);494    NewCall = Builder.CreateInvoke(SetJmp3, II->getNormalDest(),495                                   II->getUnwindDest(), Args, OpBundles);496  }497  NewCall->setCallingConv(Call.getCallingConv());498  NewCall->setAttributes(Call.getAttributes());499  NewCall->setDebugLoc(Call.getDebugLoc());500 501  NewCall->takeName(&Call);502  Call.replaceAllUsesWith(NewCall);503  Call.eraseFromParent();504}505 506// Figure out what state we should assign calls in this block.507int WinEHStatePass::getBaseStateForBB(508    DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,509    BasicBlock *BB) {510  int BaseState = ParentBaseState;511  auto &BBColors = BlockColors[BB];512 513  assert(BBColors.size() == 1 && "multi-color BB not removed by preparation");514  BasicBlock *FuncletEntryBB = BBColors.front();515  if (auto *FuncletPad =516          dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHIIt())) {517    auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad);518    if (BaseStateI != FuncInfo.FuncletBaseStateMap.end())519      BaseState = BaseStateI->second;520  }521 522  return BaseState;523}524 525static bool isIntrinsic(const CallBase &Call, Intrinsic::ID ID) {526  const Function *CF = Call.getCalledFunction();527  return CF && CF->isIntrinsic() && CF->getIntrinsicID() == ID;528}529 530static bool isSehScopeEnd(const CallBase &Call) {531  return isIntrinsic(Call, Intrinsic::seh_scope_end);532}533 534static bool isSehScopeBegin(const CallBase &Call) {535  return isIntrinsic(Call, Intrinsic::seh_scope_begin);536}537 538// Calculate the state a call-site is in.539int WinEHStatePass::getStateForCall(540    DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,541    CallBase &Call) {542  if (auto *II = dyn_cast<InvokeInst>(&Call)) {543    if (isSehScopeEnd(*II)) {544      return getBaseStateForBB(BlockColors, FuncInfo, II->getNormalDest());545    }546 547    // Look up the state number of the EH pad this unwinds to.548    assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!");549    return FuncInfo.InvokeStateMap[II];550  }551  // Possibly throwing call instructions have no actions to take after552  // an unwind. Ensure they are in the -1 state.553  return getBaseStateForBB(BlockColors, FuncInfo, Call.getParent());554}555 556// Calculate the intersection of all the FinalStates for a BasicBlock's557// predecessors.558static int getPredState(DenseMap<BasicBlock *, int> &FinalStates, Function &F,559                        int ParentBaseState, BasicBlock *BB) {560  // The entry block has no predecessors but we know that the prologue always561  // sets us up with a fixed state.562  if (&F.getEntryBlock() == BB)563    return ParentBaseState;564 565  // This is an EH Pad, conservatively report this basic block as overdefined.566  if (BB->isEHPad())567    return OverdefinedState;568 569  int CommonState = OverdefinedState;570  for (BasicBlock *PredBB : predecessors(BB)) {571    // We didn't manage to get a state for one of these predecessors,572    // conservatively report this basic block as overdefined.573    auto PredEndState = FinalStates.find(PredBB);574    if (PredEndState == FinalStates.end())575      return OverdefinedState;576 577    // This code is reachable via exceptional control flow,578    // conservatively report this basic block as overdefined.579    if (isa<CatchReturnInst>(PredBB->getTerminator()))580      return OverdefinedState;581 582    int PredState = PredEndState->second;583    assert(PredState != OverdefinedState &&584           "overdefined BBs shouldn't be in FinalStates");585    if (CommonState == OverdefinedState)586      CommonState = PredState;587 588    // At least two predecessors have different FinalStates,589    // conservatively report this basic block as overdefined.590    if (CommonState != PredState)591      return OverdefinedState;592  }593 594  return CommonState;595}596 597// Calculate the intersection of all the InitialStates for a BasicBlock's598// successors.599static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F,600                        int ParentBaseState, BasicBlock *BB) {601  // This block rejoins normal control flow,602  // conservatively report this basic block as overdefined.603  if (isa<CatchReturnInst>(BB->getTerminator()))604    return OverdefinedState;605 606  int CommonState = OverdefinedState;607  for (BasicBlock *SuccBB : successors(BB)) {608    // We didn't manage to get a state for one of these predecessors,609    // conservatively report this basic block as overdefined.610    auto SuccStartState = InitialStates.find(SuccBB);611    if (SuccStartState == InitialStates.end())612      return OverdefinedState;613 614    // This is an EH Pad, conservatively report this basic block as overdefined.615    if (SuccBB->isEHPad())616      return OverdefinedState;617 618    int SuccState = SuccStartState->second;619    assert(SuccState != OverdefinedState &&620           "overdefined BBs shouldn't be in FinalStates");621    if (CommonState == OverdefinedState)622      CommonState = SuccState;623 624    // At least two successors have different InitialStates,625    // conservatively report this basic block as overdefined.626    if (CommonState != SuccState)627      return OverdefinedState;628  }629 630  return CommonState;631}632 633bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality,634                                        CallBase &Call) {635  if (isSehScopeBegin(Call) || isSehScopeEnd(Call)) {636    return true;637  }638 639  // If the function touches memory, it needs a state store.640  if (isAsynchronousEHPersonality(Personality))641    return !Call.doesNotAccessMemory();642 643  // If the function throws, it needs a state store.644  return !Call.doesNotThrow();645}646 647void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {648  // Mark the registration node. The backend needs to know which alloca it is so649  // that it can recover the original frame pointer.650  IRBuilder<> Builder(RegNode->getNextNode());651  Value *RegNodeI8 = Builder.CreateBitCast(RegNode, Builder.getPtrTy());652  Builder.CreateIntrinsic(Intrinsic::x86_seh_ehregnode, {RegNodeI8});653 654  if (EHGuardNode) {655    IRBuilder<> Builder(EHGuardNode->getNextNode());656    Value *EHGuardNodeI8 =657        Builder.CreateBitCast(EHGuardNode, Builder.getPtrTy());658    Builder.CreateIntrinsic(Intrinsic::x86_seh_ehguard, {EHGuardNodeI8});659  }660 661  // Calculate state numbers.662  if (isAsynchronousEHPersonality(Personality))663    calculateSEHStateNumbers(&F, FuncInfo);664  else665    calculateWinCXXEHStateNumbers(&F, FuncInfo);666 667  // Iterate all the instructions and emit state number stores.668  DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(F);669  ReversePostOrderTraversal<Function *> RPOT(&F);670 671  // InitialStates yields the state of the first call-site for a BasicBlock.672  DenseMap<BasicBlock *, int> InitialStates;673  // FinalStates yields the state of the last call-site for a BasicBlock.674  DenseMap<BasicBlock *, int> FinalStates;675  // Worklist used to revisit BasicBlocks with indeterminate676  // Initial/Final-States.677  std::deque<BasicBlock *> Worklist;678  // Fill in InitialStates and FinalStates for BasicBlocks with call-sites.679  for (BasicBlock *BB : RPOT) {680    int InitialState = OverdefinedState;681    int FinalState;682    if (&F.getEntryBlock() == BB)683      InitialState = FinalState = ParentBaseState;684    for (Instruction &I : *BB) {685      auto *Call = dyn_cast<CallBase>(&I);686      if (!Call || !isStateStoreNeeded(Personality, *Call))687        continue;688 689      int State = getStateForCall(BlockColors, FuncInfo, *Call);690      if (InitialState == OverdefinedState)691        InitialState = State;692      FinalState = State;693    }694    // No call-sites in this basic block? That's OK, we will come back to these695    // in a later pass.696    if (InitialState == OverdefinedState) {697      Worklist.push_back(BB);698      continue;699    }700    LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName()701                      << " InitialState=" << InitialState << '\n');702    LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName()703                      << " FinalState=" << FinalState << '\n');704    InitialStates.insert({BB, InitialState});705    FinalStates.insert({BB, FinalState});706  }707 708  // Try to fill-in InitialStates and FinalStates which have no call-sites.709  while (!Worklist.empty()) {710    BasicBlock *BB = Worklist.front();711    Worklist.pop_front();712    // This BasicBlock has already been figured out, nothing more we can do.713    if (InitialStates.count(BB) != 0)714      continue;715 716    int PredState = getPredState(FinalStates, F, ParentBaseState, BB);717    if (PredState == OverdefinedState)718      continue;719 720    // We successfully inferred this BasicBlock's state via it's predecessors;721    // enqueue it's successors to see if we can infer their states.722    InitialStates.insert({BB, PredState});723    FinalStates.insert({BB, PredState});724    for (BasicBlock *SuccBB : successors(BB))725       Worklist.push_back(SuccBB);726  }727 728  // Try to hoist stores from successors.729  for (BasicBlock *BB : RPOT) {730    int SuccState = getSuccState(InitialStates, F, ParentBaseState, BB);731    if (SuccState == OverdefinedState)732      continue;733 734    // Update our FinalState to reflect the common InitialState of our735    // successors.736    FinalStates.insert({BB, SuccState});737  }738 739  // Finally, insert state stores before call-sites which transition us to a new740  // state.741  for (BasicBlock *BB : RPOT) {742    auto &BBColors = BlockColors[BB];743    BasicBlock *FuncletEntryBB = BBColors.front();744    if (isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHIIt()))745      continue;746 747    int PrevState = getPredState(FinalStates, F, ParentBaseState, BB);748    LLVM_DEBUG(dbgs() << "X86WinEHState: " << BB->getName()749                      << " PrevState=" << PrevState << '\n');750 751    for (Instruction &I : *BB) {752      auto *Call = dyn_cast<CallBase>(&I);753      if (!Call || !isStateStoreNeeded(Personality, *Call))754        continue;755 756      int State = getStateForCall(BlockColors, FuncInfo, *Call);757      if (State != PrevState)758        insertStateNumberStore(&I, State);759      PrevState = State;760    }761 762    // We might have hoisted a state store into this block, emit it now.763    auto EndState = FinalStates.find(BB);764    if (EndState != FinalStates.end())765      if (EndState->second != PrevState)766        insertStateNumberStore(BB->getTerminator(), EndState->second);767  }768 769  SmallVector<CallBase *, 1> SetJmp3Calls;770  for (BasicBlock *BB : RPOT) {771    for (Instruction &I : *BB) {772      auto *Call = dyn_cast<CallBase>(&I);773      if (!Call)774        continue;775      if (Call->getCalledOperand()->stripPointerCasts() !=776          SetJmp3.getCallee()->stripPointerCasts())777        continue;778 779      SetJmp3Calls.push_back(Call);780    }781  }782 783  for (CallBase *Call : SetJmp3Calls) {784    auto &BBColors = BlockColors[Call->getParent()];785    BasicBlock *FuncletEntryBB = BBColors.front();786    bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHIIt());787 788    IRBuilder<> Builder(Call);789    Value *State;790    if (InCleanup) {791      Value *StateField = Builder.CreateStructGEP(RegNode->getAllocatedType(),792                                                  RegNode, StateFieldIndex);793      State = Builder.CreateLoad(Builder.getInt32Ty(), StateField);794    } else {795      State = Builder.getInt32(getStateForCall(BlockColors, FuncInfo, *Call));796    }797    rewriteSetJmpCall(Builder, F, *Call, State);798  }799}800 801void WinEHStatePass::insertStateNumberStore(Instruction *IP, int State) {802  IRBuilder<> Builder(IP);803  Value *StateField = Builder.CreateStructGEP(RegNode->getAllocatedType(),804                                              RegNode, StateFieldIndex);805  Builder.CreateStore(Builder.getInt32(State), StateField);806}807 808void WinEHStatePass::updateEspForInAllocas(Function &F) {809  for (BasicBlock &BB : F) {810    for (Instruction &I : BB) {811      if (auto *Alloca = dyn_cast<AllocaInst>(&I)) {812        if (Alloca->isStaticAlloca())813          continue;814        IRBuilder<> Builder(Alloca->getNextNode());815        // SavedESP = llvm.stacksave()816        Value *SP = Builder.CreateStackSave();817        Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));818      }819 820      if (auto *II = dyn_cast<IntrinsicInst>(&I)) {821        if (II->getIntrinsicID() != Intrinsic::stackrestore)822          continue;823        IRBuilder<> Builder(II->getNextNode());824        // SavedESP = llvm.stacksave()825        Value *SP = Builder.CreateStackSave();826        Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));827      }828    }829  }830}831