28#include "llvm/IR/IntrinsicsX86.h"
36#define DEBUG_TYPE "winehstate"
39const int OverdefinedState = INT_MIN;
41constexpr StringRef X86WinEHStatePassName =
42 "Windows 32-bit x86 EH state insertion";
44class WinEHStateFnPassImpl {
46 WinEHStateFnPassImpl() =
default;
55 void emitExceptionRegistrationRecord(
Function *
F);
58 void unlinkExceptionRegistration(
IRBuilder<> &Builder);
60 void insertStateNumberStore(
Instruction *IP,
int State);
77 Type *getEHLinkRegistrationType();
78 Type *getSEHRegistrationType();
79 Type *getCXXEHRegistrationType();
82 Module *TheModule =
nullptr;
92 bool UseStackGuard =
false;
93 int ParentBaseState = 0;
102 Type *RegNodeTy =
nullptr;
108 int StateFieldIndex = ~0U;
111 Value *Link =
nullptr;
122 bool doInitialization(
Module &M)
override {
return Impl.initialize(M); }
124 bool doFinalization(
Module &M)
override {
return Impl.finalize(M); }
128 StringRef getPassName()
const override {
return X86WinEHStatePassName; }
131 WinEHStateFnPassImpl Impl;
138 WinEHStateFnPassImpl Impl;
143 bool ModifiedForFn = Impl.runOnFunction(
F);
156 return new WinEHStateLegacy();
159char WinEHStateLegacy::ID = 0;
162 "Insert stores for EH state numbers",
false,
false)
169bool WinEHStateFnPassImpl::finalize(
Module &M) {
172 EHLinkRegistrationTy =
nullptr;
173 CXXEHRegistrationTy =
nullptr;
174 SEHRegistrationTy =
nullptr;
176 CxxLongjmpUnwind =
nullptr;
177 SehLongjmpUnwind =
nullptr;
182void WinEHStateLegacy::getAnalysisUsage(
AnalysisUsage &AU)
const {
188bool WinEHStateFnPassImpl::runOnFunction(
Function &
F) {
192 if (
F.hasAvailableExternallyLinkage())
196 if (!
F.hasPersonalityFn())
207 bool HasPads =
false;
218 SetJmp3 = TheModule->getOrInsertFunction(
221 {Int8PtrType, Type::getInt32Ty(TheModule->getContext())},
224 emitExceptionRegistrationRecord(&
F);
232 addStateStores(
F, FuncInfo);
233 updateEspForInAllocas(
F);
236 PersonalityFn =
nullptr;
238 UseStackGuard =
false;
241 EHGuardNode =
nullptr;
253Type *WinEHStateFnPassImpl::getEHLinkRegistrationType() {
254 if (EHLinkRegistrationTy)
255 return EHLinkRegistrationTy;
262 return EHLinkRegistrationTy;
271Type *WinEHStateFnPassImpl::getCXXEHRegistrationType() {
272 if (CXXEHRegistrationTy)
273 return CXXEHRegistrationTy;
277 getEHLinkRegistrationType(),
280 CXXEHRegistrationTy =
282 return CXXEHRegistrationTy;
293Type *WinEHStateFnPassImpl::getSEHRegistrationType() {
294 if (SEHRegistrationTy)
295 return SEHRegistrationTy;
300 getEHLinkRegistrationType(),
305 return SEHRegistrationTy;
312void WinEHStateFnPassImpl::emitExceptionRegistrationRecord(
Function *
F) {
316 IRBuilder<> Builder(&
F->getEntryBlock(),
F->getEntryBlock().begin());
317 Type *Int8PtrType = Builder.getPtrTy();
322 RegNodeTy = getCXXEHRegistrationType();
323 RegNode = Builder.CreateAlloca(RegNodeTy);
325 Value *
SP = Builder.CreateStackSave();
326 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
329 ParentBaseState = -1;
330 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
332 Function *Trampoline = generateLSDAInEAXThunk(
F);
333 Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
334 linkExceptionRegistration(Builder, Trampoline);
336 CxxLongjmpUnwind = TheModule->getOrInsertFunction(
337 "__CxxLongjmpUnwind",
344 StringRef PersonalityName = PersonalityFn->getName();
345 UseStackGuard = (PersonalityName ==
"_except_handler4");
348 RegNodeTy = getSEHRegistrationType();
349 RegNode = Builder.CreateAlloca(RegNodeTy);
351 EHGuardNode = Builder.CreateAlloca(
Int32Ty);
354 Value *
SP = Builder.CreateStackSave();
355 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
358 ParentBaseState = UseStackGuard ? -2 : -1;
359 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
361 Value *LSDA = emitEHLSDA(Builder,
F);
362 LSDA = Builder.CreatePtrToInt(LSDA,
Int32Ty);
366 Cookie = TheModule->getOrInsertGlobal(
"__security_cookie",
Int32Ty);
367 Value *Val = Builder.CreateLoad(
Int32Ty, Cookie,
"cookie");
368 LSDA = Builder.CreateXor(LSDA, Val);
370 Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
375 Value *FrameAddr = Builder.CreateIntrinsic(
376 Intrinsic::frameaddress,
377 Builder.getPtrTy(TheModule->getDataLayout().getAllocaAddrSpace()),
378 Builder.getInt32(0),
nullptr,
"frameaddr");
379 Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr,
Int32Ty);
380 FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val);
381 Builder.CreateStore(FrameAddrI32, EHGuardNode);
385 Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
386 linkExceptionRegistration(Builder, PersonalityFn);
388 SehLongjmpUnwind = TheModule->getOrInsertFunction(
389 UseStackGuard ?
"_seh_longjmp_unwind4" :
"_seh_longjmp_unwind",
405 if (
CallInst *CI = BB.getTerminatingMustTailCall())
408 Builder.SetInsertPoint(
T);
409 unlinkExceptionRegistration(Builder);
424Function *WinEHStateFnPassImpl::generateLSDAInEAXThunk(
Function *ParentFunc) {
428 Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
438 Twine(
"__ehhandler$") +
445 Value *LSDA = emitEHLSDA(Builder, ParentFunc);
447 Value *
Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};
457void WinEHStateFnPassImpl::linkExceptionRegistration(
IRBuilder<> &Builder,
463 Type *LinkTy = getEHLinkRegistrationType();
474void WinEHStateFnPassImpl::unlinkExceptionRegistration(
IRBuilder<> &Builder) {
483 Type *LinkTy = getEHLinkRegistrationType();
506 OptionalArgs.
push_back(CxxLongjmpUnwind.getCallee());
508 OptionalArgs.
push_back(emitEHLSDA(Builder, &
F));
510 OptionalArgs.
push_back(SehLongjmpUnwind.getCallee());
532 II->getUnwindDest(), Args, OpBundles);
544int WinEHStateFnPassImpl::getBaseStateForBB(
547 int BaseState = ParentBaseState;
548 auto &BBColors = BlockColors[BB];
550 assert(BBColors.size() == 1 &&
"multi-color BB not removed by preparation");
552 if (
auto *FuncletPad =
556 BaseState = BaseStateI->second;
576int WinEHStateFnPassImpl::getStateForCall(
581 return getBaseStateForBB(BlockColors, FuncInfo,
II->getNormalDest());
590 return getBaseStateForBB(BlockColors, FuncInfo,
Call.
getParent());
599 if (&
F.getEntryBlock() == BB)
600 return ParentBaseState;
604 return OverdefinedState;
606 int CommonState = OverdefinedState;
610 auto PredEndState = FinalStates.
find(PredBB);
611 if (PredEndState == FinalStates.
end())
612 return OverdefinedState;
617 return OverdefinedState;
619 int PredState = PredEndState->second;
620 assert(PredState != OverdefinedState &&
621 "overdefined BBs shouldn't be in FinalStates");
622 if (CommonState == OverdefinedState)
623 CommonState = PredState;
627 if (CommonState != PredState)
628 return OverdefinedState;
641 return OverdefinedState;
643 int CommonState = OverdefinedState;
647 auto SuccStartState = InitialStates.
find(SuccBB);
648 if (SuccStartState == InitialStates.
end())
649 return OverdefinedState;
652 if (SuccBB->isEHPad())
653 return OverdefinedState;
655 int SuccState = SuccStartState->second;
656 assert(SuccState != OverdefinedState &&
657 "overdefined BBs shouldn't be in FinalStates");
658 if (CommonState == OverdefinedState)
659 CommonState = SuccState;
663 if (CommonState != SuccState)
664 return OverdefinedState;
670bool WinEHStateFnPassImpl::isStateStoreNeeded(
EHPersonality Personality,
684void WinEHStateFnPassImpl::addStateStores(
Function &
F,
694 Value *EHGuardNodeI8 =
715 std::deque<BasicBlock *> Worklist;
718 int InitialState = OverdefinedState;
720 if (&
F.getEntryBlock() == BB)
721 InitialState = FinalState = ParentBaseState;
724 if (!
Call || !isStateStoreNeeded(Personality, *
Call))
727 int State = getStateForCall(BlockColors, FuncInfo, *
Call);
728 if (InitialState == OverdefinedState)
729 InitialState = State;
734 if (InitialState == OverdefinedState) {
735 Worklist.push_back(BB);
739 <<
" InitialState=" << InitialState <<
'\n');
741 <<
" FinalState=" << FinalState <<
'\n');
742 InitialStates.
insert({BB, InitialState});
743 FinalStates.
insert({BB, FinalState});
747 while (!Worklist.empty()) {
749 Worklist.pop_front();
751 if (InitialStates.
count(BB) != 0)
754 int PredState =
getPredState(FinalStates,
F, ParentBaseState, BB);
755 if (PredState == OverdefinedState)
760 InitialStates.
insert({BB, PredState});
761 FinalStates.
insert({BB, PredState});
763 Worklist.push_back(SuccBB);
768 int SuccState =
getSuccState(InitialStates,
F, ParentBaseState, BB);
769 if (SuccState == OverdefinedState)
774 FinalStates.
insert({BB, SuccState});
780 auto &BBColors = BlockColors[BB];
785 int PrevState =
getPredState(FinalStates,
F, ParentBaseState, BB);
787 <<
" PrevState=" << PrevState <<
'\n');
791 if (!
Call || !isStateStoreNeeded(Personality, *
Call))
794 int State = getStateForCall(BlockColors, FuncInfo, *
Call);
795 if (State != PrevState)
796 insertStateNumberStore(&
I, State);
801 auto EndState = FinalStates.
find(BB);
802 if (EndState != FinalStates.
end())
803 if (EndState->second != PrevState)
804 insertStateNumberStore(BB->getTerminator(), EndState->second);
833 State = Builder.
getInt32(getStateForCall(BlockColors, FuncInfo, *
Call));
835 rewriteSetJmpCall(Builder,
F, *
Call, State);
839void WinEHStateFnPassImpl::insertStateNumberStore(
Instruction *IP,
int State) {
846void WinEHStateFnPassImpl::updateEspForInAllocas(
Function &
F) {
850 if (Alloca->isStaticAlloca())
859 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
ModuleAnalysisManager MAM
#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 void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
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
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...
Represents analyses that only rely on functions' control flow.
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.
This class represents a function call, abstracting a target machine's calling convention.
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.
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.
Class to represent function types.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
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.
This is an important class for using LLVM in a threaded context.
A Module instance is used to store all the information related to an LLVM module.
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
static LLVM_ABI PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
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.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
const ParentTy * getParent() const
#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.
@ X86_StdCall
stdcall is mostly used by the Win32 API.
@ C
The default llvm calling convention, compatible with C.
This is an optimization pass for GlobalISel generic memory operations.
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.
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...
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)
FunctionPass * createX86WinEHStateLegacyPass()
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
DenseMap< const FuncletPadInst *, int > FuncletBaseStateMap
DenseMap< const InvokeInst *, int > InvokeStateMap