27#include "llvm/IR/IntrinsicsX86.h"
35#define DEBUG_TYPE "winehstate"
38const int OverdefinedState = INT_MIN;
55 return "Windows 32-bit x86 EH state insertion";
59 void emitExceptionRegistrationRecord(
Function *
F);
62 void unlinkExceptionRegistration(
IRBuilder<> &Builder);
64 void insertStateNumberStore(
Instruction *IP,
int State);
79 Type *getEHLinkRegistrationType();
80 Type *getSEHRegistrationType();
81 Type *getCXXEHRegistrationType();
84 Module *TheModule =
nullptr;
94 bool UseStackGuard =
false;
95 int ParentBaseState = 0;
107 int StateFieldIndex = ~0U;
110 Value *Link =
nullptr;
116char WinEHStatePass::ID = 0;
119 "Insert stores for EH state numbers",
false,
false)
121bool WinEHStatePass::doInitialization(
Module &M) {
126bool WinEHStatePass::doFinalization(
Module &M) {
129 EHLinkRegistrationTy =
nullptr;
130 CXXEHRegistrationTy =
nullptr;
131 SEHRegistrationTy =
nullptr;
133 CxxLongjmpUnwind =
nullptr;
134 SehLongjmpUnwind =
nullptr;
139void WinEHStatePass::getAnalysisUsage(
AnalysisUsage &AU)
const {
145bool WinEHStatePass::runOnFunction(
Function &
F) {
149 if (
F.hasAvailableExternallyLinkage())
153 if (!
F.hasPersonalityFn())
156 dyn_cast<Function>(
F.getPersonalityFn()->stripPointerCasts());
165 bool HasPads =
false;
175 Type *Int8PtrType = PointerType::getUnqual(TheModule->getContext());
176 SetJmp3 = TheModule->getOrInsertFunction(
177 "_setjmp3", FunctionType::get(
179 {Int8PtrType, Type::getInt32Ty(TheModule->getContext())},
182 emitExceptionRegistrationRecord(&
F);
190 addStateStores(
F, FuncInfo);
193 PersonalityFn =
nullptr;
194 Personality = EHPersonality::Unknown;
195 UseStackGuard =
false;
197 EHGuardNode =
nullptr;
209Type *WinEHStatePass::getEHLinkRegistrationType() {
210 if (EHLinkRegistrationTy)
211 return EHLinkRegistrationTy;
215 PointerType::getUnqual(
216 EHLinkRegistrationTy->getContext()),
217 PointerType::getUnqual(Context)
219 EHLinkRegistrationTy->setBody(FieldTys,
false);
220 return EHLinkRegistrationTy;
229Type *WinEHStatePass::getCXXEHRegistrationType() {
230 if (CXXEHRegistrationTy)
231 return CXXEHRegistrationTy;
234 PointerType::getUnqual(Context),
235 getEHLinkRegistrationType(),
238 CXXEHRegistrationTy =
240 return CXXEHRegistrationTy;
251Type *WinEHStatePass::getSEHRegistrationType() {
252 if (SEHRegistrationTy)
253 return SEHRegistrationTy;
256 PointerType::getUnqual(Context),
257 PointerType::getUnqual(Context),
258 getEHLinkRegistrationType(),
263 return SEHRegistrationTy;
270void WinEHStatePass::emitExceptionRegistrationRecord(
Function *
F) {
271 assert(Personality == EHPersonality::MSVC_CXX ||
272 Personality == EHPersonality::MSVC_X86SEH);
277 IRBuilder<> Builder(&
F->getEntryBlock(),
F->getEntryBlock().begin());
278 Type *Int8PtrType = Builder.getPtrTy();
282 if (Personality == EHPersonality::MSVC_CXX) {
283 RegNodeTy = getCXXEHRegistrationType();
284 RegNode = Builder.CreateAlloca(RegNodeTy);
286 Value *SP = Builder.CreateStackSave();
287 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
290 ParentBaseState = -1;
291 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
293 Function *Trampoline = generateLSDAInEAXThunk(
F);
294 Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
295 linkExceptionRegistration(Builder, Trampoline);
297 CxxLongjmpUnwind = TheModule->getOrInsertFunction(
298 "__CxxLongjmpUnwind",
299 FunctionType::get(VoidTy, Int8PtrType,
false));
300 cast<Function>(CxxLongjmpUnwind.getCallee()->stripPointerCasts())
302 }
else if (Personality == EHPersonality::MSVC_X86SEH) {
305 StringRef PersonalityName = PersonalityFn->getName();
306 UseStackGuard = (PersonalityName ==
"_except_handler4");
309 RegNodeTy = getSEHRegistrationType();
310 RegNode = Builder.CreateAlloca(RegNodeTy);
312 EHGuardNode = Builder.CreateAlloca(Int32Ty);
315 Value *SP = Builder.CreateStackSave();
316 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
319 ParentBaseState = UseStackGuard ? -2 : -1;
320 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
322 Value *LSDA = emitEHLSDA(Builder,
F);
323 LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty);
327 Cookie = TheModule->getOrInsertGlobal(
"__security_cookie", Int32Ty);
328 Value *Val = Builder.CreateLoad(Int32Ty, Cookie,
"cookie");
329 LSDA = Builder.CreateXor(LSDA, Val);
331 Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
335 Value *Val = Builder.CreateLoad(Int32Ty, Cookie);
336 Value *FrameAddr = Builder.CreateCall(
338 TheModule, Intrinsic::frameaddress,
340 TheModule->getDataLayout().getAllocaAddrSpace())),
341 Builder.getInt32(0),
"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);
351 SehLongjmpUnwind = TheModule->getOrInsertFunction(
352 UseStackGuard ?
"_seh_longjmp_unwind4" :
"_seh_longjmp_unwind",
353 FunctionType::get(
Type::getVoidTy(TheModule->getContext()), Int8PtrType,
355 cast<Function>(SehLongjmpUnwind.getCallee()->stripPointerCasts())
364 if (!isa<ReturnInst>(
T))
366 Builder.SetInsertPoint(
T);
367 unlinkExceptionRegistration(Builder);
386 Type *Int8PtrType = PointerType::getUnqual(Context);
387 Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
390 FunctionType::get(Int32Ty,
ArrayRef(&ArgTys[0], 4),
393 FunctionType::get(Int32Ty,
ArrayRef(&ArgTys[0], 5),
404 Value *LSDA = emitEHLSDA(Builder, ParentFunc);
406 Value *
Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};
409 Call->setTailCall(
true);
411 Call->addParamAttr(0, Attribute::InReg);
416void WinEHStatePass::linkExceptionRegistration(
IRBuilder<> &Builder,
422 Type *LinkTy = getEHLinkRegistrationType();
433void WinEHStatePass::unlinkExceptionRegistration(
IRBuilder<> &Builder) {
435 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(Link)) {
436 GEP = cast<GetElementPtrInst>(
GEP->clone());
442 Type *LinkTy = getEHLinkRegistrationType();
457 if (
Call.arg_size() != 2)
461 Call.getOperandBundlesAsDefs(OpBundles);
464 if (Personality == EHPersonality::MSVC_CXX) {
465 OptionalArgs.
push_back(CxxLongjmpUnwind.getCallee());
467 OptionalArgs.
push_back(emitEHLSDA(Builder, &
F));
468 }
else if (Personality == EHPersonality::MSVC_X86SEH) {
469 OptionalArgs.
push_back(SehLongjmpUnwind.getCallee());
484 if (
auto *CI = dyn_cast<CallInst>(&Call)) {
489 auto *
II = cast<InvokeInst>(&Call);
491 SetJmp3,
II->getNormalDest(),
II->getUnwindDest(), Args, OpBundles);
498 Call.replaceAllUsesWith(NewCall);
499 Call.eraseFromParent();
503int WinEHStatePass::getBaseStateForBB(
506 int BaseState = ParentBaseState;
507 auto &BBColors = BlockColors[BB];
509 assert(BBColors.size() == 1 &&
"multi-color BB not removed by preparation");
511 if (
auto *FuncletPad =
515 BaseState = BaseStateI->second;
522int WinEHStatePass::getStateForCall(
525 if (
auto *
II = dyn_cast<InvokeInst>(&Call)) {
532 return getBaseStateForBB(BlockColors, FuncInfo,
Call.getParent());
541 if (&
F.getEntryBlock() == BB)
542 return ParentBaseState;
546 return OverdefinedState;
548 int CommonState = OverdefinedState;
552 auto PredEndState = FinalStates.
find(PredBB);
553 if (PredEndState == FinalStates.
end())
554 return OverdefinedState;
558 if (isa<CatchReturnInst>(PredBB->getTerminator()))
559 return OverdefinedState;
561 int PredState = PredEndState->second;
562 assert(PredState != OverdefinedState &&
563 "overdefined BBs shouldn't be in FinalStates");
564 if (CommonState == OverdefinedState)
565 CommonState = PredState;
569 if (CommonState != PredState)
570 return OverdefinedState;
583 return OverdefinedState;
585 int CommonState = OverdefinedState;
589 auto SuccStartState = InitialStates.
find(SuccBB);
590 if (SuccStartState == InitialStates.
end())
591 return OverdefinedState;
594 if (SuccBB->isEHPad())
595 return OverdefinedState;
597 int SuccState = SuccStartState->second;
598 assert(SuccState != OverdefinedState &&
599 "overdefined BBs shouldn't be in FinalStates");
600 if (CommonState == OverdefinedState)
601 CommonState = SuccState;
605 if (CommonState != SuccState)
606 return OverdefinedState;
612bool WinEHStatePass::isStateStoreNeeded(
EHPersonality Personality,
616 return !
Call.doesNotAccessMemory();
619 return !
Call.doesNotThrow();
633 Value *EHGuardNodeI8 =
656 std::deque<BasicBlock *> Worklist;
659 int InitialState = OverdefinedState;
661 if (&
F.getEntryBlock() == BB)
662 InitialState = FinalState = ParentBaseState;
664 auto *
Call = dyn_cast<CallBase>(&
I);
665 if (!Call || !isStateStoreNeeded(Personality, *Call))
668 int State = getStateForCall(BlockColors, FuncInfo, *Call);
669 if (InitialState == OverdefinedState)
670 InitialState = State;
675 if (InitialState == OverdefinedState) {
676 Worklist.push_back(BB);
680 <<
" InitialState=" << InitialState <<
'\n');
682 <<
" FinalState=" << FinalState <<
'\n');
683 InitialStates.
insert({BB, InitialState});
684 FinalStates.
insert({BB, FinalState});
688 while (!Worklist.empty()) {
690 Worklist.pop_front();
692 if (InitialStates.
count(BB) != 0)
695 int PredState =
getPredState(FinalStates,
F, ParentBaseState, BB);
696 if (PredState == OverdefinedState)
701 InitialStates.
insert({BB, PredState});
702 FinalStates.
insert({BB, PredState});
704 Worklist.push_back(SuccBB);
709 int SuccState =
getSuccState(InitialStates,
F, ParentBaseState, BB);
710 if (SuccState == OverdefinedState)
715 FinalStates.
insert({BB, SuccState});
721 auto &BBColors = BlockColors[BB];
726 int PrevState =
getPredState(FinalStates,
F, ParentBaseState, BB);
728 <<
" PrevState=" << PrevState <<
'\n');
731 auto *
Call = dyn_cast<CallBase>(&
I);
732 if (!Call || !isStateStoreNeeded(Personality, *Call))
735 int State = getStateForCall(BlockColors, FuncInfo, *Call);
736 if (State != PrevState)
737 insertStateNumberStore(&
I, State);
742 auto EndState = FinalStates.
find(BB);
743 if (EndState != FinalStates.
end())
744 if (EndState->second != PrevState)
745 insertStateNumberStore(BB->getTerminator(), EndState->second);
751 auto *
Call = dyn_cast<CallBase>(&
I);
754 if (
Call->getCalledOperand()->stripPointerCasts() !=
755 SetJmp3.getCallee()->stripPointerCasts())
762 for (
CallBase *Call : SetJmp3Calls) {
763 auto &BBColors = BlockColors[
Call->getParent()];
765 bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->
getFirstNonPHI());
771 RegNode, StateFieldIndex);
774 State = Builder.
getInt32(getStateForCall(BlockColors, FuncInfo, *Call));
776 rewriteSetJmpCall(Builder,
F, *Call, State);
780void WinEHStatePass::insertStateNumberStore(
Instruction *IP,
int State) {
783 RegNode, StateFieldIndex);
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.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static int getPredState(DenseMap< BasicBlock *, int > &FinalStates, Function &F, int ParentBaseState, BasicBlock *BB)
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.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const Instruction & front() const
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
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)
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
void setTailCallKind(TailCallKind TCK)
This is an important base class in LLVM.
static 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.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
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)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
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).
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.
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)
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args=std::nullopt, const Twine &Name="", MDNode *FPMathTag=nullptr)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
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.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
virtual bool doFinalization(Module &)
doFinalization - Virtual method overriden by subclasses to do any necessary clean up after all passes...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
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 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 Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
void takeName(Value *V)
Transfer the name from V to this value.
#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.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
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.
auto successors(const MachineBasicBlock *BB)
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...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
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)
bool isAsynchronousEHPersonality(EHPersonality Pers)
Returns true if this personality function catches asynchronous exceptions.
auto predecessors(const MachineBasicBlock *BB)
DenseMap< const FuncletPadInst *, int > FuncletBaseStateMap
DenseMap< const InvokeInst *, int > InvokeStateMap