summaryrefslogtreecommitdiff
path: root/lib/Target/X86/X86WinEHState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/X86/X86WinEHState.cpp')
-rw-r--r--lib/Target/X86/X86WinEHState.cpp464
1 files changed, 402 insertions, 62 deletions
diff --git a/lib/Target/X86/X86WinEHState.cpp b/lib/Target/X86/X86WinEHState.cpp
index dce94a9e9ef78..99387edef99a9 100644
--- a/lib/Target/X86/X86WinEHState.cpp
+++ b/lib/Target/X86/X86WinEHState.cpp
@@ -15,33 +15,32 @@
//===----------------------------------------------------------------------===//
#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/Passes.h"
#include "llvm/CodeGen/WinEHFuncInfo.h"
-#include "llvm/IR/Dominators.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/IRBuilder.h"
#include "llvm/IR/Module.h"
-#include "llvm/IR/PatternMatch.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/Utils/BasicBlockUtils.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include "llvm/Transforms/Utils/Local.h"
+#include <deque>
using namespace llvm;
-using namespace llvm::PatternMatch;
#define DEBUG_TYPE "winehstate"
-namespace llvm { void initializeWinEHStatePassPass(PassRegistry &); }
+namespace llvm {
+void initializeWinEHStatePassPass(PassRegistry &);
+}
namespace {
+const int OverdefinedState = INT_MIN;
+
class WinEHStatePass : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid.
@@ -68,12 +67,20 @@ private:
void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler);
void unlinkExceptionRegistration(IRBuilder<> &Builder);
void addStateStores(Function &F, WinEHFuncInfo &FuncInfo);
- void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State);
+ 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();
@@ -84,20 +91,23 @@ private:
StructType *EHLinkRegistrationTy = nullptr;
StructType *CXXEHRegistrationTy = nullptr;
StructType *SEHRegistrationTy = nullptr;
- Function *FrameRecover = nullptr;
- Function *FrameAddress = nullptr;
- Function *FrameEscape = 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;
- /// Struct type of RegNode. Used for GEPing.
- Type *RegNodeTy = nullptr;
+ // The allocation containing the EH security guard.
+ AllocaInst *EHGuardNode = nullptr;
/// The index of the state field of RegNode.
int StateFieldIndex = ~0U;
@@ -116,9 +126,6 @@ INITIALIZE_PASS(WinEHStatePass, "x86-winehstate",
bool WinEHStatePass::doInitialization(Module &M) {
TheModule = &M;
- FrameEscape = Intrinsic::getDeclaration(TheModule, Intrinsic::localescape);
- FrameRecover = Intrinsic::getDeclaration(TheModule, Intrinsic::localrecover);
- FrameAddress = Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress);
return false;
}
@@ -128,9 +135,10 @@ bool WinEHStatePass::doFinalization(Module &M) {
EHLinkRegistrationTy = nullptr;
CXXEHRegistrationTy = nullptr;
SEHRegistrationTy = nullptr;
- FrameEscape = nullptr;
- FrameRecover = nullptr;
- FrameAddress = nullptr;
+ SetJmp3 = nullptr;
+ CxxLongjmpUnwind = nullptr;
+ SehLongjmpUnwind = nullptr;
+ Cookie = nullptr;
return false;
}
@@ -164,6 +172,13 @@ bool WinEHStatePass::runOnFunction(Function &F) {
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?
@@ -182,6 +197,10 @@ bool WinEHStatePass::runOnFunction(Function &F) {
// Reset per-function state.
PersonalityFn = nullptr;
Personality = EHPersonality::Unknown;
+ UseStackGuard = false;
+ RegNode = nullptr;
+ EHGuardNode = nullptr;
+
return true;
}
@@ -256,9 +275,14 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
assert(Personality == EHPersonality::MSVC_CXX ||
Personality == EHPersonality::MSVC_X86SEH);
- StringRef PersonalityName = PersonalityFn->getName();
+ // 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);
@@ -268,42 +292,71 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
// TryLevel = -1
StateFieldIndex = 2;
- insertStateNumberStore(RegNode, &*Builder.GetInsertPoint(), -1);
+ 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.
- bool UseStackGuard = (PersonalityName == "_except_handler4");
+ 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;
- insertStateNumberStore(RegNode, &*Builder.GetInsertPoint(),
- UseStackGuard ? -2 : -1);
+ ParentBaseState = UseStackGuard ? -2 : -1;
+ insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
// ScopeTable = llvm.x86.seh.lsda(F)
- Value *FI8 = Builder.CreateBitCast(F, Int8PtrType);
- Value *LSDA = Builder.CreateCall(
- Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8);
- Type *Int32Ty = Type::getInt32Ty(TheModule->getContext());
+ 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) {
- Value *Cookie =
- TheModule->getOrInsertGlobal("__security_cookie", Int32Ty);
- Value *Val = Builder.CreateLoad(Int32Ty, Cookie);
+ 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");
}
@@ -398,15 +451,203 @@ void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) {
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->getParent(), std::next(RegNode->getIterator()));
+ 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);
@@ -415,42 +656,141 @@ void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
// Iterate all the instructions and emit state number stores.
DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(F);
- for (BasicBlock &BB : F) {
- // Figure out what state we should assign calls in this block.
- int BaseState = -1;
- auto &BBColors = BlockColors[&BB];
+ 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;
+ }
+ DEBUG(dbgs() << "X86WinEHState: " << BB->getName()
+ << " InitialState=" << InitialState << '\n');
+ DEBUG(dbgs() << "X86WinEHState: " << BB->getName()
+ << " FinalState=" << FinalState << '\n');
+ InitialStates.insert({BB, InitialState});
+ FinalStates.insert({BB, FinalState});
+ }
- assert(BBColors.size() == 1 &&
- "multi-color BB not removed by preparation");
+ // 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 (auto *FuncletPad =
- dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI())) {
- auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad);
- if (BaseStateI != FuncInfo.FuncletBaseStateMap.end())
- BaseState = BaseStateI->second;
+ if (isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHI()))
+ continue;
+
+ int PrevState = getPredState(FinalStates, F, ParentBaseState, BB);
+ 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;
}
- for (Instruction &I : BB) {
- if (auto *CI = dyn_cast<CallInst>(&I)) {
- // Possibly throwing call instructions have no actions to take after
- // an unwind. Ensure they are in the -1 state.
- if (CI->doesNotThrow())
- continue;
- insertStateNumberStore(RegNode, CI, BaseState);
- } else if (auto *II = dyn_cast<InvokeInst>(&I)) {
- // Look up the state number of the landingpad this unwinds to.
- assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!");
- int State = FuncInfo.InvokeStateMap[II];
- insertStateNumberStore(RegNode, II, 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(Value *ParentRegNode,
- Instruction *IP, int State) {
+void WinEHStatePass::insertStateNumberStore(Instruction *IP, int State) {
IRBuilder<> Builder(IP);
Value *StateField =
- Builder.CreateStructGEP(RegNodeTy, ParentRegNode, StateFieldIndex);
+ Builder.CreateStructGEP(nullptr, RegNode, StateFieldIndex);
Builder.CreateStore(Builder.getInt32(State), StateField);
}