28#include "llvm/IR/IntrinsicsX86.h"
36#define DEBUG_TYPE "winehstate"
39const int OverdefinedState = INT_MIN;
49 bool doInitialization(
Module &M)
override;
51 bool doFinalization(
Module &M)
override;
56 return "Windows 32-bit x86 EH state insertion";
60 void emitExceptionRegistrationRecord(
Function *
F);
63 void unlinkExceptionRegistration(
IRBuilder<> &Builder);
65 void insertStateNumberStore(
Instruction *IP,
int State);
82 Type *getEHLinkRegistrationType();
83 Type *getSEHRegistrationType();
84 Type *getCXXEHRegistrationType();
87 Module *TheModule =
nullptr;
97 bool UseStackGuard =
false;
98 int ParentBaseState = 0;
107 Type *RegNodeTy =
nullptr;
113 int StateFieldIndex = ~0U;
116 Value *Link =
nullptr;
122char WinEHStatePass::ID = 0;
125 "Insert stores for EH state numbers",
false,
false)
127bool WinEHStatePass::doInitialization(
Module &M) {
132bool WinEHStatePass::doFinalization(
Module &M) {
135 EHLinkRegistrationTy =
nullptr;
136 CXXEHRegistrationTy =
nullptr;
137 SEHRegistrationTy =
nullptr;
139 CxxLongjmpUnwind =
nullptr;
140 SehLongjmpUnwind =
nullptr;
145void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU)
const {
151bool WinEHStatePass::runOnFunction(Function &
F) {
155 if (
F.hasAvailableExternallyLinkage())
159 if (!
F.hasPersonalityFn())
170 bool HasPads =
false;
171 for (BasicBlock &BB :
F) {
180 Type *Int8PtrType = PointerType::getUnqual(TheModule->
getContext());
182 "_setjmp3", FunctionType::get(
184 {Int8PtrType, Type::getInt32Ty(TheModule->getContext())},
187 emitExceptionRegistrationRecord(&
F);
194 WinEHFuncInfo FuncInfo;
195 addStateStores(
F, FuncInfo);
196 updateEspForInAllocas(
F);
199 PersonalityFn =
nullptr;
200 Personality = EHPersonality::Unknown;
201 UseStackGuard =
false;
204 EHGuardNode =
nullptr;
216Type *WinEHStatePass::getEHLinkRegistrationType() {
217 if (EHLinkRegistrationTy)
218 return EHLinkRegistrationTy;
221 PointerType::getUnqual(
Context),
222 PointerType::getUnqual(
Context)
225 return EHLinkRegistrationTy;
234Type *WinEHStatePass::getCXXEHRegistrationType() {
235 if (CXXEHRegistrationTy)
236 return CXXEHRegistrationTy;
239 PointerType::getUnqual(
Context),
240 getEHLinkRegistrationType(),
243 CXXEHRegistrationTy =
245 return CXXEHRegistrationTy;
256Type *WinEHStatePass::getSEHRegistrationType() {
257 if (SEHRegistrationTy)
258 return SEHRegistrationTy;
261 PointerType::getUnqual(
Context),
262 PointerType::getUnqual(
Context),
263 getEHLinkRegistrationType(),
268 return SEHRegistrationTy;
275void WinEHStatePass::emitExceptionRegistrationRecord(Function *
F) {
276 assert(Personality == EHPersonality::MSVC_CXX ||
277 Personality == EHPersonality::MSVC_X86SEH);
279 IRBuilder<> Builder(&
F->getEntryBlock(),
F->getEntryBlock().begin());
280 Type *Int8PtrType = Builder.getPtrTy();
282 Type *VoidTy = Builder.getVoidTy();
284 if (Personality == EHPersonality::MSVC_CXX) {
285 RegNodeTy = getCXXEHRegistrationType();
286 RegNode = Builder.CreateAlloca(RegNodeTy);
288 Value *
SP = Builder.CreateStackSave();
289 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
292 ParentBaseState = -1;
293 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
295 Function *Trampoline = generateLSDAInEAXThunk(
F);
296 Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
297 linkExceptionRegistration(Builder, Trampoline);
300 "__CxxLongjmpUnwind",
301 FunctionType::get(VoidTy, Int8PtrType,
false));
303 ->setCallingConv(CallingConv::X86_StdCall);
304 }
else if (Personality == EHPersonality::MSVC_X86SEH) {
307 StringRef PersonalityName = PersonalityFn->
getName();
308 UseStackGuard = (PersonalityName ==
"_except_handler4");
311 RegNodeTy = getSEHRegistrationType();
312 RegNode = Builder.CreateAlloca(RegNodeTy);
314 EHGuardNode = Builder.CreateAlloca(
Int32Ty);
317 Value *
SP = Builder.CreateStackSave();
318 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
321 ParentBaseState = UseStackGuard ? -2 : -1;
322 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
324 Value *LSDA = emitEHLSDA(Builder,
F);
325 LSDA = Builder.CreatePtrToInt(LSDA,
Int32Ty);
330 Value *Val = Builder.CreateLoad(
Int32Ty, Cookie,
"cookie");
331 LSDA = Builder.CreateXor(LSDA, Val);
333 Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
338 Value *FrameAddr = Builder.CreateIntrinsic(
339 Intrinsic::frameaddress,
341 Builder.getInt32(0),
nullptr,
"frameaddr");
342 Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr,
Int32Ty);
343 FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val);
344 Builder.CreateStore(FrameAddrI32, EHGuardNode);
348 Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
349 linkExceptionRegistration(Builder, PersonalityFn);
352 UseStackGuard ?
"_seh_longjmp_unwind4" :
"_seh_longjmp_unwind",
353 FunctionType::get(Type::getVoidTy(TheModule->
getContext()), Int8PtrType,
356 ->setCallingConv(CallingConv::X86_StdCall);
362 for (BasicBlock &BB : *
F) {
368 if (CallInst *CI = BB.getTerminatingMustTailCall())
371 Builder.SetInsertPoint(
T);
372 unlinkExceptionRegistration(Builder);
387Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) {
390 Type *Int8PtrType = PointerType::getUnqual(
Context);
391 Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
393 FunctionType *TrampolineTy =
396 FunctionType *TargetFuncTy =
401 Twine(
"__ehhandler$") +
408 Value *LSDA = emitEHLSDA(Builder, ParentFunc);
410 Value *
Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};
411 CallInst *
Call = Builder.
CreateCall(TargetFuncTy, PersonalityFn, Args);
420void WinEHStatePass::linkExceptionRegistration(
IRBuilder<> &Builder,
426 Type *LinkTy = getEHLinkRegistrationType();
437void WinEHStatePass::unlinkExceptionRegistration(
IRBuilder<> &Builder) {
446 Type *LinkTy = getEHLinkRegistrationType();
458void WinEHStatePass::rewriteSetJmpCall(
IRBuilder<> &Builder, Function &
F,
468 if (Personality == EHPersonality::MSVC_CXX) {
471 OptionalArgs.
push_back(emitEHLSDA(Builder, &
F));
472 }
else if (Personality == EHPersonality::MSVC_X86SEH) {
489 CallInst *NewCI = Builder.
CreateCall(SetJmp3, Args, OpBundles);
495 II->getUnwindDest(), Args, OpBundles);
507int WinEHStatePass::getBaseStateForBB(
508 DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,
510 int BaseState = ParentBaseState;
511 auto &BBColors = BlockColors[BB];
513 assert(BBColors.size() == 1 &&
"multi-color BB not removed by preparation");
514 BasicBlock *FuncletEntryBB = BBColors.front();
515 if (
auto *FuncletPad =
519 BaseState = BaseStateI->second;
539int WinEHStatePass::getStateForCall(
540 DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,
544 return getBaseStateForBB(BlockColors, FuncInfo,
II->getNormalDest());
553 return getBaseStateForBB(BlockColors, FuncInfo,
Call.
getParent());
562 if (&
F.getEntryBlock() == BB)
563 return ParentBaseState;
567 return OverdefinedState;
569 int CommonState = OverdefinedState;
573 auto PredEndState = FinalStates.
find(PredBB);
574 if (PredEndState == FinalStates.
end())
575 return OverdefinedState;
580 return OverdefinedState;
582 int PredState = PredEndState->second;
583 assert(PredState != OverdefinedState &&
584 "overdefined BBs shouldn't be in FinalStates");
585 if (CommonState == OverdefinedState)
586 CommonState = PredState;
590 if (CommonState != PredState)
591 return OverdefinedState;
604 return OverdefinedState;
606 int CommonState = OverdefinedState;
610 auto SuccStartState = InitialStates.
find(SuccBB);
611 if (SuccStartState == InitialStates.
end())
612 return OverdefinedState;
615 if (SuccBB->isEHPad())
616 return OverdefinedState;
618 int SuccState = SuccStartState->second;
619 assert(SuccState != OverdefinedState &&
620 "overdefined BBs shouldn't be in FinalStates");
621 if (CommonState == OverdefinedState)
622 CommonState = SuccState;
626 if (CommonState != SuccState)
627 return OverdefinedState;
633bool WinEHStatePass::isStateStoreNeeded(
EHPersonality Personality,
647void WinEHStatePass::addStateStores(Function &
F, WinEHFuncInfo &FuncInfo) {
656 Value *EHGuardNodeI8 =
669 ReversePostOrderTraversal<Function *> RPOT(&
F);
672 DenseMap<BasicBlock *, int> InitialStates;
674 DenseMap<BasicBlock *, int> FinalStates;
677 std::deque<BasicBlock *> Worklist;
679 for (BasicBlock *BB : RPOT) {
680 int InitialState = OverdefinedState;
682 if (&
F.getEntryBlock() == BB)
683 InitialState = FinalState = ParentBaseState;
684 for (Instruction &
I : *BB) {
686 if (!
Call || !isStateStoreNeeded(Personality, *
Call))
689 int State = getStateForCall(BlockColors, FuncInfo, *
Call);
690 if (InitialState == OverdefinedState)
691 InitialState = State;
696 if (InitialState == OverdefinedState) {
697 Worklist.push_back(BB);
701 <<
" InitialState=" << InitialState <<
'\n');
703 <<
" FinalState=" << FinalState <<
'\n');
704 InitialStates.
insert({BB, InitialState});
705 FinalStates.
insert({BB, FinalState});
709 while (!Worklist.empty()) {
711 Worklist.pop_front();
713 if (InitialStates.
count(BB) != 0)
716 int PredState =
getPredState(FinalStates,
F, ParentBaseState, BB);
717 if (PredState == OverdefinedState)
722 InitialStates.
insert({BB, PredState});
723 FinalStates.
insert({BB, PredState});
725 Worklist.push_back(SuccBB);
729 for (BasicBlock *BB : RPOT) {
730 int SuccState =
getSuccState(InitialStates,
F, ParentBaseState, BB);
731 if (SuccState == OverdefinedState)
736 FinalStates.
insert({BB, SuccState});
741 for (BasicBlock *BB : RPOT) {
742 auto &BBColors = BlockColors[BB];
747 int PrevState =
getPredState(FinalStates,
F, ParentBaseState, BB);
749 <<
" PrevState=" << PrevState <<
'\n');
751 for (Instruction &
I : *BB) {
753 if (!
Call || !isStateStoreNeeded(Personality, *
Call))
756 int State = getStateForCall(BlockColors, FuncInfo, *
Call);
757 if (State != PrevState)
758 insertStateNumberStore(&
I, State);
763 auto EndState = FinalStates.
find(BB);
764 if (EndState != FinalStates.
end())
765 if (EndState->second != PrevState)
766 insertStateNumberStore(BB->getTerminator(), EndState->second);
770 for (BasicBlock *BB : RPOT) {
771 for (Instruction &
I : *BB) {
783 for (CallBase *
Call : SetJmp3Calls) {
792 RegNode, StateFieldIndex);
795 State = Builder.
getInt32(getStateForCall(BlockColors, FuncInfo, *
Call));
797 rewriteSetJmpCall(Builder,
F, *
Call, State);
801void WinEHStatePass::insertStateNumberStore(Instruction *IP,
int State) {
804 RegNode, StateFieldIndex);
808void WinEHStatePass::updateEspForInAllocas(Function &
F) {
809 for (BasicBlock &BB :
F) {
810 for (Instruction &
I : BB) {
812 if (Alloca->isStaticAlloca())
821 if (
II->getIntrinsicID() != Intrinsic::stackrestore)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool runOnFunction(Function &F, bool PostInlining)
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static int getPredState(DenseMap< BasicBlock *, int > &FinalStates, Function &F, int ParentBaseState, BasicBlock *BB)
static bool isSehScopeEnd(const CallBase &Call)
static bool isSehScopeBegin(const CallBase &Call)
static bool isIntrinsic(const CallBase &Call, Intrinsic::ID ID)
static int getSuccState(DenseMap< BasicBlock *, int > &InitialStates, Function &F, int ParentBaseState, BasicBlock *BB)
an instruction to allocate memory on the stack
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
LLVM Basic Block Representation.
LLVM_ABI InstListType::const_iterator getFirstNonPHIIt() const
Returns an iterator to the first instruction in this block that is not a PHINode instruction.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction & front() const
bool isEHPad() const
Return true if this basic block is an exception handling block.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
LLVM_ABI void getOperandBundlesAsDefs(SmallVectorImpl< OperandBundleDef > &Defs) const
Return the list of operand bundles attached to this instruction as a vector of OperandBundleDefs.
bool doesNotAccessMemory(unsigned OpNo) const
CallingConv::ID getCallingConv() const
Value * getCalledOperand() const
void setAttributes(AttributeList A)
Set the attributes for this call.
bool doesNotThrow() const
Determine if the call cannot unwind.
Value * getArgOperand(unsigned i) const
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
void setTailCallKind(TailCallKind TCK)
void setTailCall(bool IsTc=true)
This is an important base class in LLVM.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
unsigned getAllocaAddrSpace() const
iterator find(const_arg_type_t< KeyT > Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
FunctionPass class - This class is used to implement most global optimizations.
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
LLVM_ABI void setComdat(Comdat *C)
const Comdat * getComdat() const
static StringRef dropLLVMManglingEscape(StringRef Name)
If the given string begins with the GlobalValue name mangling escape character '\1',...
@ InternalLinkage
Rename collisions when linking (static functions).
CallInst * CreateStackSave(const Twine &Name="")
Create a call to llvm.stacksave.
InvokeInst * CreateInvoke(FunctionType *Ty, Value *Callee, BasicBlock *NormalDest, BasicBlock *UnwindDest, ArrayRef< Value * > Args, ArrayRef< OperandBundleDef > OpBundles, const Twine &Name="")
Create an invoke instruction.
Value * CreateStructGEP(Type *Ty, Value *Ptr, unsigned Idx, const Twine &Name="")
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
ReturnInst * CreateRet(Value *V)
Create a 'ret <val>' instruction.
LLVM_ABI CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
InstTy * Insert(InstTy *I, const Twine &Name="") const
Insert and return the specified instruction.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
LLVMContext & getContext() const
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
A Module instance is used to store all the information related to an LLVM module.
LLVMContext & getContext() const
Get the global data context.
FunctionCallee getOrInsertFunction(StringRef Name, FunctionType *T, AttributeList AttributeList)
Look up the specified function in the module symbol table.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
GlobalVariable * getOrInsertGlobal(StringRef Name, Type *Ty, function_ref< GlobalVariable *()> CreateGlobalCallback)
Look up the specified global in the module symbol table.
void push_back(const T &Elt)
StringRef - Represent a constant reference to a string, i.e.
Class to represent struct types.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
const ParentTy * getParent() const
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createX86WinEHStatePass()
Return an IR pass that inserts EH registration stack objects and explicit EH state updates.
FunctionAddr VTableAddr Value
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
auto successors(const MachineBasicBlock *BB)
LLVM_ABI DenseMap< BasicBlock *, ColorVector > colorEHFunclets(Function &F)
If an EH funclet personality is in use (see isFuncletEHPersonality), this will recompute which blocks...
void calculateWinCXXEHStateNumbers(const Function *ParentFn, WinEHFuncInfo &FuncInfo)
Analyze the IR in ParentFn and it's handlers to build WinEHFuncInfo, which describes the state number...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
bool isFuncletEHPersonality(EHPersonality Pers)
Returns true if this is a personality function that invokes handler funclets (which must return to it...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
void calculateSEHStateNumbers(const Function *ParentFn, WinEHFuncInfo &FuncInfo)
FunctionAddr VTableAddr Next
ArrayRef(const T &OneElt) -> ArrayRef< T >
bool isAsynchronousEHPersonality(EHPersonality Pers)
Returns true if this personality function catches asynchronous exceptions.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto predecessors(const MachineBasicBlock *BB)
DenseMap< const FuncletPadInst *, int > FuncletBaseStateMap
DenseMap< const InvokeInst *, int > InvokeStateMap