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);
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;
176 SetJmp3 = TheModule->getOrInsertFunction(
177 "_setjmp3", FunctionType::get(
179 {Int8PtrType, Type::getInt32Ty(TheModule->getContext())},
182 emitExceptionRegistrationRecord(&
F);
193 PersonalityFn =
nullptr;
194 Personality = EHPersonality::Unknown;
195 UseStackGuard =
false;
197 EHGuardNode =
nullptr;
209Type *WinEHStatePass::getEHLinkRegistrationType() {
210 if (EHLinkRegistrationTy)
211 return EHLinkRegistrationTy;
218 EHLinkRegistrationTy->setBody(FieldTys,
false);
219 return EHLinkRegistrationTy;
228Type *WinEHStatePass::getCXXEHRegistrationType() {
229 if (CXXEHRegistrationTy)
230 return CXXEHRegistrationTy;
234 getEHLinkRegistrationType(),
237 CXXEHRegistrationTy =
239 return CXXEHRegistrationTy;
250Type *WinEHStatePass::getSEHRegistrationType() {
251 if (SEHRegistrationTy)
252 return SEHRegistrationTy;
257 getEHLinkRegistrationType(),
262 return SEHRegistrationTy;
269void WinEHStatePass::emitExceptionRegistrationRecord(
Function *
F) {
270 assert(Personality == EHPersonality::MSVC_CXX ||
271 Personality == EHPersonality::MSVC_X86SEH);
281 if (Personality == EHPersonality::MSVC_CXX) {
282 RegNodeTy = getCXXEHRegistrationType();
283 RegNode =
Builder.CreateAlloca(RegNodeTy);
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);
317 Builder.CreateStore(SP,
Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
320 ParentBaseState = UseStackGuard ? -2 : -1;
321 insertStateNumberStore(&*
Builder.GetInsertPoint(), ParentBaseState);
323 Value *LSDA = emitEHLSDA(Builder,
F);
328 Cookie = TheModule->getOrInsertGlobal(
"__security_cookie",
Int32Ty);
330 LSDA =
Builder.CreateXor(LSDA, Val);
332 Builder.CreateStore(LSDA,
Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
339 TheModule, Intrinsic::frameaddress,
341 TheModule->getDataLayout().getAllocaAddrSpace())),
342 Builder.getInt32(0),
"frameaddr");
344 FrameAddrI32 =
Builder.CreateXor(FrameAddrI32, Val);
345 Builder.CreateStore(FrameAddrI32, EHGuardNode);
349 Link =
Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
350 linkExceptionRegistration(Builder, PersonalityFn);
352 SehLongjmpUnwind = TheModule->getOrInsertFunction(
353 UseStackGuard ?
"_seh_longjmp_unwind4" :
"_seh_longjmp_unwind",
354 FunctionType::get(
Type::getVoidTy(TheModule->getContext()), Int8PtrType,
356 cast<Function>(SehLongjmpUnwind.getCallee()->stripPointerCasts())
365 if (!isa<ReturnInst>(
T))
368 unlinkExceptionRegistration(Builder);
389 Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
406 Value *LSDA = emitEHLSDA(Builder, ParentFunc);
407 Value *CastPersonality =
408 Builder.CreateBitCast(PersonalityFn, TargetFuncTy->getPointerTo());
410 Value *
Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};
413 Call->setTailCall(
true);
415 Call->addParamAttr(0, Attribute::InReg);
420void WinEHStatePass::linkExceptionRegistration(
IRBuilder<> &Builder,
425 Type *LinkTy = getEHLinkRegistrationType();
428 Builder.CreateStore(HandlerI8,
Builder.CreateStructGEP(LinkTy, Link, 1));
433 Builder.CreateStore(Next,
Builder.CreateStructGEP(LinkTy, Link, 0));
435 Builder.CreateStore(Link, FSZero);
438void WinEHStatePass::unlinkExceptionRegistration(
IRBuilder<> &Builder) {
440 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(Link)) {
441 GEP = cast<GetElementPtrInst>(
GEP->clone());
445 Type *LinkTy = getEHLinkRegistrationType();
448 Builder.CreateStructGEP(LinkTy, Link, 0));
451 Builder.CreateStore(Next, FSZero);
461 if (
Call.arg_size() != 2)
465 Call.getOperandBundlesAsDefs(OpBundles);
468 if (Personality == EHPersonality::MSVC_CXX) {
469 OptionalArgs.
push_back(CxxLongjmpUnwind.getCallee());
471 OptionalArgs.
push_back(emitEHLSDA(Builder, &
F));
472 }
else if (Personality == EHPersonality::MSVC_X86SEH) {
473 OptionalArgs.
push_back(SehLongjmpUnwind.getCallee());
488 if (
auto *CI = dyn_cast<CallInst>(&Call)) {
493 auto *II = cast<InvokeInst>(&Call);
494 NewCall =
Builder.CreateInvoke(
495 SetJmp3, II->getNormalDest(), II->getUnwindDest(), Args, OpBundles);
502 Call.replaceAllUsesWith(NewCall);
503 Call.eraseFromParent();
507int WinEHStatePass::getBaseStateForBB(
510 int BaseState = ParentBaseState;
511 auto &BBColors = BlockColors[BB];
513 assert(BBColors.size() == 1 &&
"multi-color BB not removed by preparation");
515 if (
auto *FuncletPad =
517 auto BaseStateI =
FuncInfo.FuncletBaseStateMap.find(FuncletPad);
518 if (BaseStateI !=
FuncInfo.FuncletBaseStateMap.end())
519 BaseState = BaseStateI->second;
526int WinEHStatePass::getStateForCall(
529 if (
auto *II = dyn_cast<InvokeInst>(&Call)) {
531 assert(
FuncInfo.InvokeStateMap.count(II) &&
"invoke has no state!");
536 return getBaseStateForBB(BlockColors,
FuncInfo,
Call.getParent());
545 if (&
F.getEntryBlock() == BB)
546 return ParentBaseState;
550 return OverdefinedState;
552 int CommonState = OverdefinedState;
556 auto PredEndState = FinalStates.
find(PredBB);
557 if (PredEndState == FinalStates.
end())
558 return OverdefinedState;
562 if (isa<CatchReturnInst>(PredBB->getTerminator()))
563 return OverdefinedState;
565 int PredState = PredEndState->second;
566 assert(PredState != OverdefinedState &&
567 "overdefined BBs shouldn't be in FinalStates");
568 if (CommonState == OverdefinedState)
569 CommonState = PredState;
573 if (CommonState != PredState)
574 return OverdefinedState;
587 return OverdefinedState;
589 int CommonState = OverdefinedState;
593 auto SuccStartState = InitialStates.
find(SuccBB);
594 if (SuccStartState == InitialStates.
end())
595 return OverdefinedState;
598 if (SuccBB->isEHPad())
599 return OverdefinedState;
601 int SuccState = SuccStartState->second;
602 assert(SuccState != OverdefinedState &&
603 "overdefined BBs shouldn't be in FinalStates");
604 if (CommonState == OverdefinedState)
605 CommonState = SuccState;
609 if (CommonState != SuccState)
610 return OverdefinedState;
616bool WinEHStatePass::isStateStoreNeeded(
EHPersonality Personality,
620 return !
Call.doesNotAccessMemory();
623 return !
Call.doesNotThrow();
637 Value *EHGuardNodeI8 =
660 std::deque<BasicBlock *> Worklist;
663 int InitialState = OverdefinedState;
665 if (&
F.getEntryBlock() == BB)
666 InitialState = FinalState = ParentBaseState;
668 auto *
Call = dyn_cast<CallBase>(&
I);
669 if (!Call || !isStateStoreNeeded(Personality, *Call))
672 int State = getStateForCall(BlockColors,
FuncInfo, *Call);
673 if (InitialState == OverdefinedState)
674 InitialState = State;
679 if (InitialState == OverdefinedState) {
680 Worklist.push_back(BB);
684 <<
" InitialState=" << InitialState <<
'\n');
686 <<
" FinalState=" << FinalState <<
'\n');
687 InitialStates.
insert({BB, InitialState});
688 FinalStates.
insert({BB, FinalState});
692 while (!Worklist.empty()) {
694 Worklist.pop_front();
696 if (InitialStates.
count(BB) != 0)
699 int PredState =
getPredState(FinalStates,
F, ParentBaseState, BB);
700 if (PredState == OverdefinedState)
705 InitialStates.
insert({BB, PredState});
706 FinalStates.
insert({BB, PredState});
708 Worklist.push_back(SuccBB);
713 int SuccState =
getSuccState(InitialStates,
F, ParentBaseState, BB);
714 if (SuccState == OverdefinedState)
719 FinalStates.
insert({BB, SuccState});
725 auto &BBColors = BlockColors[BB];
730 int PrevState =
getPredState(FinalStates,
F, ParentBaseState, BB);
732 <<
" PrevState=" << PrevState <<
'\n');
735 auto *
Call = dyn_cast<CallBase>(&
I);
736 if (!Call || !isStateStoreNeeded(Personality, *Call))
739 int State = getStateForCall(BlockColors,
FuncInfo, *Call);
740 if (State != PrevState)
741 insertStateNumberStore(&
I, State);
746 auto EndState = FinalStates.
find(BB);
747 if (EndState != FinalStates.
end())
748 if (EndState->second != PrevState)
749 insertStateNumberStore(BB->getTerminator(), EndState->second);
755 auto *
Call = dyn_cast<CallBase>(&
I);
758 if (
Call->getCalledOperand()->stripPointerCasts() !=
759 SetJmp3.getCallee()->stripPointerCasts())
766 for (
CallBase *Call : SetJmp3Calls) {
767 auto &BBColors = BlockColors[
Call->getParent()];
769 bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->
getFirstNonPHI());
774 Value *StateField =
Builder.CreateStructGEP(RegNode->getAllocatedType(),
775 RegNode, StateFieldIndex);
778 State =
Builder.getInt32(getStateForCall(BlockColors,
FuncInfo, *Call));
780 rewriteSetJmpCall(Builder,
F, *Call, State);
784void WinEHStatePass::insertStateNumberStore(
Instruction *IP,
int State) {
786 Value *StateField =
Builder.CreateStructGEP(RegNode->getAllocatedType(),
787 RegNode, StateFieldIndex);
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
typename CallsiteContextGraph< DerivedCCG, FuncTy, CallTy >::FuncInfo FuncInfo
Module.h This file contains the declarations for the Module class.
#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).
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.
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
static Type * getVoidTy(LLVMContext &C)
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
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)