mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-27 17:31:33 +00:00
[WinEH] Generate .xdata for catch handlers
This lets us catch exceptions in simple cases. N.B. Things that do not work include (but are not limited to): - Throwing from within a catch handler. - Catching an object with a named catch parameter. - 'CatchHigh' is fictitious, we aren't sure of its purpose. - We aren't entirely efficient with regards to the number of EH states that we generate. - IP-to-State tables are sensitive to the order of emission. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233767 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
58bc60892e
commit
64386621ec
@ -551,17 +551,6 @@ This object is used by Windows native exception handling on non-x86 platforms
|
||||
where xdata unwind information is used. It is typically an 8 byte chunk of
|
||||
memory treated as two 32-bit integers.
|
||||
|
||||
``llvm.eh.parentframe``
|
||||
-----------------------
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
void @llvm.eh.parentframe(i8*)
|
||||
|
||||
This intrinsic designates the provided static alloca as the object which holds
|
||||
the address of the parent frame.
|
||||
This object is used by Windows native exception handling on non-x86 platforms
|
||||
where xdata unwind information is used.
|
||||
|
||||
SJLJ Intrinsics
|
||||
---------------
|
||||
|
@ -103,7 +103,9 @@ struct WinEHUnwindMapEntry {
|
||||
|
||||
struct WinEHHandlerType {
|
||||
int Adjectives;
|
||||
GlobalValue *TypeDescriptor;
|
||||
GlobalVariable *TypeDescriptor;
|
||||
int CatchObjIdx;
|
||||
int CatchObjOffset;
|
||||
Function *Handler;
|
||||
};
|
||||
|
||||
@ -111,7 +113,7 @@ struct WinEHTryBlockMapEntry {
|
||||
int TryLow;
|
||||
int TryHigh;
|
||||
int CatchHigh;
|
||||
SmallVector<WinEHHandlerType, 4> HandlerArray;
|
||||
SmallVector<WinEHHandlerType, 1> HandlerArray;
|
||||
};
|
||||
|
||||
struct WinEHFuncInfo {
|
||||
|
@ -425,10 +425,6 @@ def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
|
||||
// for WinEH.
|
||||
def int_eh_unwindhelp : Intrinsic<[], [llvm_ptr_ty], []>;
|
||||
|
||||
// Designates the provided static alloca as the object which holds the address
|
||||
// of the parent frame. Required for WinEH.
|
||||
def int_eh_parentframe : Intrinsic<[], [llvm_ptrptr_ty], []>;
|
||||
|
||||
// __builtin_unwind_init is an undocumented GCC intrinsic that causes all
|
||||
// callee-saved registers to be saved and restored (regardless of whether they
|
||||
// are used) in the calling function. It is used by libgcc_eh.
|
||||
|
@ -259,6 +259,7 @@ namespace llvm {
|
||||
MCSymbol *getOrCreateSectionSymbol(const MCSectionELF &Section);
|
||||
|
||||
MCSymbol *getOrCreateFrameAllocSymbol(StringRef FuncName, unsigned Idx);
|
||||
MCSymbol *getOrCreateParentFrameOffsetSymbol(StringRef FuncName);
|
||||
|
||||
/// Get the symbol for \p Name, or null.
|
||||
MCSymbol *LookupSymbol(const Twine &Name) const;
|
||||
|
@ -68,6 +68,27 @@ void Win64Exception::beginFunction(const MachineFunction *MF) {
|
||||
shouldEmitLSDA = shouldEmitPersonality &&
|
||||
LSDAEncoding != dwarf::DW_EH_PE_omit;
|
||||
|
||||
|
||||
// If this was an outlined handler, we need to define the label corresponding
|
||||
// to the offset of the parent frame relative to the stack pointer after the
|
||||
// prologue.
|
||||
const Function *F = MF->getFunction();
|
||||
const Function *ParentF = MMI->getWinEHParent(F);
|
||||
if (F != ParentF) {
|
||||
WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
|
||||
auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F);
|
||||
if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) {
|
||||
MCSymbol *HandlerTypeParentFrameOffset =
|
||||
Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
|
||||
GlobalValue::getRealLinkageName(F->getName()));
|
||||
|
||||
// Emit a symbol assignment.
|
||||
Asm->OutStreamer.EmitAssignment(
|
||||
HandlerTypeParentFrameOffset,
|
||||
MCConstantExpr::Create(I->second, Asm->OutContext));
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldEmitPersonality && !shouldEmitMoves)
|
||||
return;
|
||||
|
||||
@ -253,6 +274,7 @@ void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||
const Function *F = MF->getFunction();
|
||||
const Function *ParentF = MMI->getWinEHParent(F);
|
||||
auto &OS = Asm->OutStreamer;
|
||||
WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
|
||||
|
||||
StringRef ParentLinkageName =
|
||||
GlobalValue::getRealLinkageName(ParentF->getName());
|
||||
@ -279,8 +301,6 @@ void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||
// an ordinary call) between the end of the previous try-range and now.
|
||||
bool SawPotentiallyThrowing = false;
|
||||
|
||||
WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
|
||||
|
||||
int LastEHState = -2;
|
||||
|
||||
// The parent function and the catch handlers contribute to the 'ip2state'
|
||||
@ -424,11 +444,17 @@ void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||
// };
|
||||
OS.EmitLabel(HandlerMapXData);
|
||||
for (const WinEHHandlerType &HT : TBME.HandlerArray) {
|
||||
MCSymbol *ParentFrameOffset =
|
||||
Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
|
||||
GlobalValue::getRealLinkageName(HT.Handler->getName()));
|
||||
const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::Create(
|
||||
ParentFrameOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
|
||||
|
||||
OS.EmitIntValue(HT.Adjectives, 4); // Adjectives
|
||||
OS.EmitValue(createImageRel32(HT.TypeDescriptor), 4); // Type
|
||||
OS.EmitIntValue(0, 4); // CatchObjOffset
|
||||
OS.EmitIntValue(HT.CatchObjOffset, 4); // CatchObjOffset
|
||||
OS.EmitValue(createImageRel32(HT.Handler), 4); // Handler
|
||||
OS.EmitIntValue(0, 4); // ParentFrameOffset
|
||||
OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,7 @@ struct WinEHNumbering {
|
||||
int NextState;
|
||||
|
||||
SmallVector<ActionHandler *, 4> HandlerStack;
|
||||
SmallPtrSet<const Function *, 4> VisitedHandlers;
|
||||
|
||||
int currentEHNumber() const {
|
||||
return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState();
|
||||
@ -96,7 +97,9 @@ struct WinEHNumbering {
|
||||
void parseEHActions(const IntrinsicInst *II,
|
||||
SmallVectorImpl<ActionHandler *> &Actions);
|
||||
void createUnwindMapEntry(int ToState, ActionHandler *AH);
|
||||
void proccessCallSite(ArrayRef<ActionHandler *> Actions, ImmutableCallSite CS);
|
||||
void createTryBlockMapEntry(int TryLow, int TryHigh,
|
||||
ArrayRef<CatchHandler *> Handlers);
|
||||
void processCallSite(ArrayRef<ActionHandler *> Actions, ImmutableCallSite CS);
|
||||
void calculateStateNumbers(const Function &F);
|
||||
};
|
||||
}
|
||||
@ -276,8 +279,12 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
||||
MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
|
||||
|
||||
// Calculate EH numbers for WinEH.
|
||||
if (fn.getFnAttribute("wineh-parent").getValueAsString() == fn.getName())
|
||||
WinEHNumbering(MMI.getWinEHFuncInfo(&fn)).calculateStateNumbers(fn);
|
||||
if (fn.getFnAttribute("wineh-parent").getValueAsString() == fn.getName()) {
|
||||
WinEHNumbering Num(MMI.getWinEHFuncInfo(&fn));
|
||||
Num.calculateStateNumbers(fn);
|
||||
// Pop everything on the handler stack.
|
||||
Num.processCallSite(None, ImmutableCallSite());
|
||||
}
|
||||
}
|
||||
|
||||
void WinEHNumbering::parseEHActions(const IntrinsicInst *II,
|
||||
@ -309,13 +316,42 @@ void WinEHNumbering::parseEHActions(const IntrinsicInst *II,
|
||||
void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) {
|
||||
WinEHUnwindMapEntry UME;
|
||||
UME.ToState = ToState;
|
||||
if (auto *CH = dyn_cast<CleanupHandler>(AH))
|
||||
if (auto *CH = dyn_cast_or_null<CleanupHandler>(AH))
|
||||
UME.Cleanup = cast<Function>(CH->getHandlerBlockOrFunc());
|
||||
else
|
||||
UME.Cleanup = nullptr;
|
||||
FuncInfo.UnwindMap.push_back(UME);
|
||||
}
|
||||
|
||||
void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh,
|
||||
ArrayRef<CatchHandler *> Handlers) {
|
||||
WinEHTryBlockMapEntry TBME;
|
||||
TBME.TryLow = TryLow;
|
||||
TBME.TryHigh = TryHigh;
|
||||
// FIXME: This should be revisited when we want to throw inside a catch
|
||||
// handler.
|
||||
TBME.CatchHigh = INT_MAX;
|
||||
assert(TBME.TryLow <= TBME.TryHigh);
|
||||
assert(TBME.CatchHigh > TBME.TryHigh);
|
||||
for (CatchHandler *CH : Handlers) {
|
||||
WinEHHandlerType HT;
|
||||
auto *GV = cast<GlobalVariable>(CH->getSelector()->stripPointerCasts());
|
||||
// Selectors are always pointers to GlobalVariables with 'struct' type.
|
||||
// The struct has two fields, adjectives and a type descriptor.
|
||||
auto *CS = cast<ConstantStruct>(GV->getInitializer());
|
||||
HT.Adjectives =
|
||||
cast<ConstantInt>(CS->getAggregateElement(0U))->getZExtValue();
|
||||
HT.TypeDescriptor = cast<GlobalVariable>(
|
||||
CS->getAggregateElement(1)->stripPointerCasts());
|
||||
HT.Handler = cast<Function>(CH->getHandlerBlockOrFunc());
|
||||
// FIXME: We don't support catching objects yet!
|
||||
HT.CatchObjIdx = INT_MAX;
|
||||
HT.CatchObjOffset = 0;
|
||||
TBME.HandlerArray.push_back(HT);
|
||||
}
|
||||
FuncInfo.TryBlockMap.push_back(TBME);
|
||||
}
|
||||
|
||||
static void print_name(const Value *V) {
|
||||
#ifndef NDEBUG
|
||||
if (!V) {
|
||||
@ -330,10 +366,8 @@ static void print_name(const Value *V) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> Actions,
|
||||
ImmutableCallSite CS) {
|
||||
// float, int
|
||||
// float, double, int
|
||||
void WinEHNumbering::processCallSite(ArrayRef<ActionHandler *> Actions,
|
||||
ImmutableCallSite CS) {
|
||||
int FirstMismatch = 0;
|
||||
for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E;
|
||||
++FirstMismatch) {
|
||||
@ -343,28 +377,65 @@ void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> Actions,
|
||||
delete Actions[FirstMismatch];
|
||||
}
|
||||
|
||||
bool EnteringScope = (int)Actions.size() > FirstMismatch;
|
||||
bool ExitingScope = (int)HandlerStack.size() > FirstMismatch;
|
||||
|
||||
// Don't recurse while we are looping over the handler stack. Instead, defer
|
||||
// the numbering of the catch handlers until we are done popping.
|
||||
SmallVector<const Function *, 4> UnnumberedHandlers;
|
||||
SmallVector<CatchHandler *, 4> PoppedCatches;
|
||||
for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) {
|
||||
if (auto *CH = dyn_cast<CatchHandler>(HandlerStack.back()))
|
||||
if (const auto *F = dyn_cast<Function>(CH->getHandlerBlockOrFunc()))
|
||||
UnnumberedHandlers.push_back(F);
|
||||
// Pop the handlers off of the stack.
|
||||
delete HandlerStack.back();
|
||||
if (auto *CH = dyn_cast<CatchHandler>(HandlerStack.back())) {
|
||||
PoppedCatches.push_back(CH);
|
||||
} else {
|
||||
// Delete cleanup handlers
|
||||
delete HandlerStack.back();
|
||||
}
|
||||
HandlerStack.pop_back();
|
||||
}
|
||||
|
||||
for (const Function *F : UnnumberedHandlers)
|
||||
calculateStateNumbers(*F);
|
||||
// We need to create a new state number if we are exiting a try scope and we
|
||||
// will not push any more actions.
|
||||
int TryHigh = NextState - 1;
|
||||
if (ExitingScope && !EnteringScope && !PoppedCatches.empty()) {
|
||||
createUnwindMapEntry(currentEHNumber(), nullptr);
|
||||
++NextState;
|
||||
}
|
||||
|
||||
int LastTryLowIdx = 0;
|
||||
for (int I = 0, E = PoppedCatches.size(); I != E; ++I) {
|
||||
CatchHandler *CH = PoppedCatches[I];
|
||||
if (I + 1 == E || CH->getEHState() != PoppedCatches[I + 1]->getEHState()) {
|
||||
int TryLow = CH->getEHState();
|
||||
auto Handlers =
|
||||
makeArrayRef(&PoppedCatches[LastTryLowIdx], I - LastTryLowIdx + 1);
|
||||
createTryBlockMapEntry(TryLow, TryHigh, Handlers);
|
||||
LastTryLowIdx = I + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (CatchHandler *CH : PoppedCatches) {
|
||||
if (auto *F = dyn_cast<Function>(CH->getHandlerBlockOrFunc()))
|
||||
calculateStateNumbers(*F);
|
||||
delete CH;
|
||||
}
|
||||
|
||||
bool LastActionWasCatch = false;
|
||||
for (size_t I = FirstMismatch; I != Actions.size(); ++I) {
|
||||
createUnwindMapEntry(currentEHNumber(), Actions[I]);
|
||||
Actions[I]->setEHState(NextState++);
|
||||
DEBUG(dbgs() << "Creating unwind map entry for: (");
|
||||
print_name(Actions[I]->getHandlerBlockOrFunc());
|
||||
DEBUG(dbgs() << ", " << currentEHNumber() << ")\n");
|
||||
// We can reuse eh states when pushing two catches for the same invoke.
|
||||
bool CurrActionIsCatch = isa<CatchHandler>(Actions[I]);
|
||||
// FIXME: Reenable this optimization!
|
||||
if (CurrActionIsCatch && LastActionWasCatch && false) {
|
||||
Actions[I]->setEHState(currentEHNumber());
|
||||
} else {
|
||||
createUnwindMapEntry(currentEHNumber(), Actions[I]);
|
||||
Actions[I]->setEHState(NextState);
|
||||
NextState++;
|
||||
DEBUG(dbgs() << "Creating unwind map entry for: (");
|
||||
print_name(Actions[I]->getHandlerBlockOrFunc());
|
||||
DEBUG(dbgs() << ", " << currentEHNumber() << ")\n");
|
||||
}
|
||||
HandlerStack.push_back(Actions[I]);
|
||||
LastActionWasCatch = CurrActionIsCatch;
|
||||
}
|
||||
|
||||
DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: ");
|
||||
@ -373,6 +444,10 @@ void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> Actions,
|
||||
}
|
||||
|
||||
void WinEHNumbering::calculateStateNumbers(const Function &F) {
|
||||
auto I = VisitedHandlers.insert(&F);
|
||||
if (!I.second)
|
||||
return; // We've already visited this handler, don't renumber it.
|
||||
|
||||
DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n');
|
||||
SmallVector<ActionHandler *, 4> ActionList;
|
||||
for (const BasicBlock &BB : F) {
|
||||
@ -380,21 +455,21 @@ void WinEHNumbering::calculateStateNumbers(const Function &F) {
|
||||
const auto *CI = dyn_cast<CallInst>(&I);
|
||||
if (!CI || CI->doesNotThrow())
|
||||
continue;
|
||||
proccessCallSite(None, CI);
|
||||
processCallSite(None, CI);
|
||||
}
|
||||
const auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
|
||||
if (!II)
|
||||
continue;
|
||||
const LandingPadInst *LPI = II->getLandingPadInst();
|
||||
if (auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode())) {
|
||||
assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
|
||||
parseEHActions(ActionsCall, ActionList);
|
||||
proccessCallSite(ActionList, II);
|
||||
ActionList.clear();
|
||||
FuncInfo.LandingPadStateMap[LPI] = currentEHNumber();
|
||||
}
|
||||
auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode());
|
||||
if (!ActionsCall)
|
||||
continue;
|
||||
assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
|
||||
parseEHActions(ActionsCall, ActionList);
|
||||
processCallSite(ActionList, II);
|
||||
ActionList.clear();
|
||||
FuncInfo.LandingPadStateMap[LPI] = currentEHNumber();
|
||||
}
|
||||
proccessCallSite(None, ImmutableCallSite());
|
||||
}
|
||||
|
||||
/// clear - Clear out all the function-specific state. This returns this
|
||||
|
@ -5450,18 +5450,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
||||
case Intrinsic::eh_begincatch:
|
||||
case Intrinsic::eh_endcatch:
|
||||
llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
|
||||
case Intrinsic::eh_parentframe: {
|
||||
AllocaInst *Slot =
|
||||
cast<AllocaInst>(I.getArgOperand(0)->stripPointerCasts());
|
||||
assert(FuncInfo.StaticAllocaMap.count(Slot) &&
|
||||
"can only use static allocas with llvm.eh.parentframe");
|
||||
int FI = FuncInfo.StaticAllocaMap[Slot];
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
const Function *F = MF.getFunction();
|
||||
MachineModuleInfo &MMI = MF.getMMI();
|
||||
MMI.getWinEHFuncInfo(F).CatchHandlerParentFrameObjIdx[F] = FI;
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::eh_unwindhelp: {
|
||||
AllocaInst *Slot =
|
||||
cast<AllocaInst>(I.getArgOperand(0)->stripPointerCasts());
|
||||
|
@ -638,16 +638,6 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn,
|
||||
if (!LPadMap.isInitialized())
|
||||
LPadMap.mapLandingPad(LPad);
|
||||
if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
|
||||
// Insert an alloca for the object which holds the address of the parent's
|
||||
// frame pointer. The stack offset of this object needs to be encoded in
|
||||
// xdata.
|
||||
AllocaInst *ParentFrame = new AllocaInst(Int8PtrType, "parentframe", Entry);
|
||||
Builder.CreateStore(&Handler->getArgumentList().back(), ParentFrame,
|
||||
/*isStore=*/true);
|
||||
Function *ParentFrameFn =
|
||||
Intrinsic::getDeclaration(M, Intrinsic::eh_parentframe);
|
||||
Builder.CreateCall(ParentFrameFn, ParentFrame);
|
||||
|
||||
Constant *Sel = CatchAction->getSelector();
|
||||
Director.reset(new WinEHCatchDirector(Handler, Sel, VarInfo, LPadMap));
|
||||
LPadMap.remapSelector(VMap, ConstantInt::get(Type::getInt32Ty(Context), 1));
|
||||
|
@ -3228,13 +3228,6 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Intrinsic::eh_parentframe: {
|
||||
auto *AI = dyn_cast<AllocaInst>(CI.getArgOperand(0)->stripPointerCasts());
|
||||
Assert(AI && AI->isStaticAlloca(),
|
||||
"llvm.eh.parentframe requires a static alloca", &CI);
|
||||
break;
|
||||
}
|
||||
|
||||
case Intrinsic::eh_unwindhelp: {
|
||||
auto *AI = dyn_cast<AllocaInst>(CI.getArgOperand(0)->stripPointerCasts());
|
||||
Assert(AI && AI->isStaticAlloca(),
|
||||
|
@ -139,6 +139,11 @@ MCSymbol *MCContext::getOrCreateFrameAllocSymbol(StringRef FuncName,
|
||||
"$frame_escape_" + Twine(Idx));
|
||||
}
|
||||
|
||||
MCSymbol *MCContext::getOrCreateParentFrameOffsetSymbol(StringRef FuncName) {
|
||||
return GetOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + FuncName +
|
||||
"$parent_frame_offset");
|
||||
}
|
||||
|
||||
MCSymbol *MCContext::CreateSymbol(StringRef Name, bool AlwaysAddSuffix) {
|
||||
// Determine whether this is an assembler temporary or normal label, if used.
|
||||
bool IsTemporary = false;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/WinEHFuncInfo.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
@ -2266,6 +2267,12 @@ static ArrayRef<MCPhysReg> get64BitArgumentXMMs(MachineFunction &MF,
|
||||
return makeArrayRef(std::begin(XMMArgRegs64Bit), std::end(XMMArgRegs64Bit));
|
||||
}
|
||||
|
||||
static bool isOutlinedHandler(const MachineFunction &MF) {
|
||||
const MachineModuleInfo &MMI = MF.getMMI();
|
||||
const Function *F = MF.getFunction();
|
||||
return MMI.getWinEHParent(F) != F;
|
||||
}
|
||||
|
||||
SDValue
|
||||
X86TargetLowering::LowerFormalArguments(SDValue Chain,
|
||||
CallingConv::ID CallConv,
|
||||
@ -2277,6 +2284,7 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
|
||||
const {
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
X86MachineFunctionInfo *FuncInfo = MF.getInfo<X86MachineFunctionInfo>();
|
||||
const TargetFrameLowering &TFI = *Subtarget->getFrameLowering();
|
||||
|
||||
const Function* Fn = MF.getFunction();
|
||||
if (Fn->hasExternalLinkage() &&
|
||||
@ -2452,7 +2460,6 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
|
||||
}
|
||||
|
||||
if (IsWin64) {
|
||||
const TargetFrameLowering &TFI = *Subtarget->getFrameLowering();
|
||||
// Get to the caller-allocated home save location. Add 8 to account
|
||||
// for the return address.
|
||||
int HomeOffset = TFI.getOffsetOfLocalArea() + 8;
|
||||
@ -2505,6 +2512,28 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
|
||||
|
||||
if (!MemOps.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);
|
||||
} else if (IsWin64 && isOutlinedHandler(MF)) {
|
||||
// Get to the caller-allocated home save location. Add 8 to account
|
||||
// for the return address.
|
||||
int HomeOffset = TFI.getOffsetOfLocalArea() + 8;
|
||||
FuncInfo->setRegSaveFrameIndex(MFI->CreateFixedObject(
|
||||
/*Size=*/1, /*SPOffset=*/HomeOffset + 8, /*Immutable=*/false));
|
||||
|
||||
MachineModuleInfo &MMI = MF.getMMI();
|
||||
MMI.getWinEHFuncInfo(Fn)
|
||||
.CatchHandlerParentFrameObjIdx[const_cast<Function *>(Fn)] =
|
||||
FuncInfo->getRegSaveFrameIndex();
|
||||
|
||||
// Store the second integer parameter (rdx) into rsp+16 relative to the
|
||||
// stack pointer at the entry of the function.
|
||||
SDValue RSFIN =
|
||||
DAG.getFrameIndex(FuncInfo->getRegSaveFrameIndex(), getPointerTy());
|
||||
unsigned GPR = MF.addLiveIn(X86::RDX, &X86::GR64RegClass);
|
||||
SDValue Val = DAG.getCopyFromReg(Chain, dl, GPR, MVT::i64);
|
||||
Chain = DAG.getStore(
|
||||
Val.getValue(1), dl, Val, RSFIN,
|
||||
MachinePointerInfo::getFixedStack(FuncInfo->getRegSaveFrameIndex()),
|
||||
/*isVolatile=*/true, /*isNonTemporal=*/false, /*Alignment=*/0);
|
||||
}
|
||||
|
||||
if (isVarArg && MFI->hasMustTailInVarArgFunc()) {
|
||||
|
@ -180,9 +180,6 @@ eh.resume: ; preds = %catch.dispatch7
|
||||
|
||||
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
|
||||
; CHECK: entry:
|
||||
; CHECK: [[PARENTFRAME:\%.+]] = alloca i8*
|
||||
; CHECK: store volatile i8* %1, i8** [[PARENTFRAME]]
|
||||
; CHECK: call void @llvm.eh.parentframe(i8** [[PARENTFRAME]])
|
||||
; CHECK: [[RECOVER_TMP1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
|
||||
; CHECK: [[TMP1_PTR:\%.+]] = bitcast i8* [[RECOVER_TMP1]] to i32*
|
||||
; CHECK: call void @"\01?handle_exception@@YAXXZ"()
|
||||
@ -199,9 +196,6 @@ eh.resume: ; preds = %catch.dispatch7
|
||||
|
||||
; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*)
|
||||
; CHECK: entry:
|
||||
; CHECK: [[PARENTFRAME:\%.+]] = alloca i8*
|
||||
; CHECK: store volatile i8* %1, i8** [[PARENTFRAME]]
|
||||
; CHECK: call void @llvm.eh.parentframe(i8** [[PARENTFRAME]])
|
||||
; CHECK: [[RECOVER_TMP0:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
|
||||
; CHECK: [[TMP0_PTR:\%.+]] = bitcast i8* [[RECOVER_TMP0]] to i32*
|
||||
; CHECK: invoke void @"\01?handle_exception@@YAXXZ"()
|
||||
|
206
test/CodeGen/WinEH/cppeh-prepared-catch.ll
Normal file
206
test/CodeGen/WinEH/cppeh-prepared-catch.ll
Normal file
@ -0,0 +1,206 @@
|
||||
; RUN: llc < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
||||
; This test case is equivalent to:
|
||||
; void f() {
|
||||
; try {
|
||||
; try {
|
||||
; may_throw();
|
||||
; } catch (int &) {
|
||||
; may_throw();
|
||||
; }
|
||||
; may_throw();
|
||||
; } catch (double) {
|
||||
; }
|
||||
; }
|
||||
|
||||
|
||||
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
|
||||
%eh.CatchHandlerType = type { i32, i8* }
|
||||
|
||||
$"\01??_R0N@8" = comdat any
|
||||
|
||||
$"\01??_R0H@8" = comdat any
|
||||
|
||||
@"\01??_7type_info@@6B@" = external constant i8*
|
||||
@"\01??_R0N@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".N\00" }, comdat
|
||||
@llvm.eh.handlertype.N.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0N@8" to i8*) }, section "llvm.metadata"
|
||||
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
|
||||
@llvm.eh.handlertype.H.8 = private unnamed_addr constant %eh.CatchHandlerType { i32 8, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
|
||||
|
||||
define internal i8* @"\01?f@@YAXXZ.catch"(i8*, i8*) #4 {
|
||||
entry:
|
||||
%.i8 = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?f@@YAXXZ" to i8*), i8* %1, i32 0)
|
||||
%2 = bitcast i8* %.i8 to i32**
|
||||
%3 = bitcast i32** %2 to i8*
|
||||
invoke void @"\01?may_throw@@YAXXZ"()
|
||||
to label %invoke.cont2 unwind label %lpad1
|
||||
|
||||
invoke.cont2: ; preds = %entry
|
||||
ret i8* blockaddress(@"\01?f@@YAXXZ", %try.cont)
|
||||
|
||||
lpad1: ; preds = %entry
|
||||
%4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
|
||||
cleanup
|
||||
catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
|
||||
%recover = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), double* null, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
|
||||
indirectbr i8* %recover, [label %invoke.cont2]
|
||||
}
|
||||
|
||||
; CHECK-LABEL: "?f@@YAXXZ.catch":
|
||||
; CHECK: ".L?f@@YAXXZ.catch$parent_frame_offset" = 56
|
||||
; CHECK: movq %rdx, 56(%rsp)
|
||||
; CHECK: .seh_handlerdata
|
||||
; CHECK: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
|
||||
|
||||
|
||||
define internal i8* @"\01?f@@YAXXZ.catch1"(i8*, i8*) #4 {
|
||||
entry:
|
||||
%.i8 = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?f@@YAXXZ" to i8*), i8* %1, i32 1)
|
||||
%2 = bitcast i8* %.i8 to double*
|
||||
%3 = bitcast double* %2 to i8*
|
||||
invoke void (...)* @llvm.donothing()
|
||||
to label %done unwind label %lpad
|
||||
|
||||
done:
|
||||
ret i8* blockaddress(@"\01?f@@YAXXZ", %try.cont8)
|
||||
|
||||
lpad: ; preds = %entry
|
||||
%4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
|
||||
cleanup
|
||||
unreachable
|
||||
}
|
||||
|
||||
; CHECK-LABEL: "?f@@YAXXZ.catch1":
|
||||
; CHECK: ".L?f@@YAXXZ.catch1$parent_frame_offset" = 16
|
||||
; CHECK: movq %rdx, 16(%rsp)
|
||||
; CHECK: .seh_handlerdata
|
||||
; CHECK: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
|
||||
|
||||
define void @"\01?f@@YAXXZ"() #0 {
|
||||
entry:
|
||||
%unwindhelp = alloca i64
|
||||
%exn.slot = alloca i8*
|
||||
%ehselector.slot = alloca i32
|
||||
%0 = alloca i32*, align 8
|
||||
%1 = alloca double, align 8
|
||||
call void (...)* @llvm.frameescape(i32** %0, double* %1)
|
||||
store volatile i64 -2, i64* %unwindhelp
|
||||
%2 = bitcast i64* %unwindhelp to i8*
|
||||
call void @llvm.eh.unwindhelp(i8* %2)
|
||||
invoke void @"\01?may_throw@@YAXXZ"()
|
||||
to label %invoke.cont unwind label %lpad2
|
||||
|
||||
invoke.cont: ; preds = %entry
|
||||
br label %try.cont
|
||||
|
||||
lpad2: ; preds = %entry
|
||||
%3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
|
||||
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.8
|
||||
catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
|
||||
%recover = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.8 to i8*), i32** %0, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch", i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), double* %1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
|
||||
indirectbr i8* %recover, [label %try.cont, label %try.cont8]
|
||||
|
||||
try.cont: ; preds = %lpad2, %invoke.cont
|
||||
invoke void @"\01?may_throw@@YAXXZ"()
|
||||
to label %try.cont8 unwind label %lpad1
|
||||
|
||||
lpad1:
|
||||
%4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
|
||||
catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
|
||||
%recover2 = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), double* null, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
|
||||
indirectbr i8* %recover2, [label %try.cont8]
|
||||
|
||||
try.cont8: ; preds = %lpad2, %try.cont
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: "?f@@YAXXZ":
|
||||
; CHECK: .seh_handlerdata
|
||||
; CHECK-NEXT: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
|
||||
; CHECK-NEXT:"$cppxdata$?f@@YAXXZ":
|
||||
; CHECK-NEXT: .long 429065506
|
||||
; CHECK-NEXT: .long 4
|
||||
; CHECK-NEXT: .long ("$stateUnwindMap$?f@@YAXXZ")@IMGREL
|
||||
; CHECK-NEXT: .long 2
|
||||
; CHECK-NEXT: .long ("$tryMap$?f@@YAXXZ")@IMGREL
|
||||
; CHECK-NEXT: .long 3
|
||||
; CHECK-NEXT: .long ("$ip2state$?f@@YAXXZ")@IMGREL
|
||||
; CHECK-NEXT: .long 64
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long 1
|
||||
; CHECK-NEXT:"$stateUnwindMap$?f@@YAXXZ":
|
||||
; CHECK-NEXT: .long -1
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long -1
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT:"$tryMap$?f@@YAXXZ":
|
||||
; CHECK-NEXT: .long 1
|
||||
; CHECK-NEXT: .long 1
|
||||
; CHECK-NEXT: .long 2147483647
|
||||
; CHECK-NEXT: .long 1
|
||||
; CHECK-NEXT: .long ("$handlerMap$0$?f@@YAXXZ")@IMGREL
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long 2
|
||||
; CHECK-NEXT: .long 2147483647
|
||||
; CHECK-NEXT: .long 1
|
||||
; CHECK-NEXT: .long ("$handlerMap$1$?f@@YAXXZ")@IMGREL
|
||||
; CHECK-NEXT:"$handlerMap$0$?f@@YAXXZ":
|
||||
; CHECK-NEXT: .long 8
|
||||
; CHECK-NEXT: .long "??_R0H@8"@IMGREL
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long "?f@@YAXXZ.catch"@IMGREL
|
||||
; CHECK-NEXT: .long ".L?f@@YAXXZ.catch$parent_frame_offset"
|
||||
; CHECK-NEXT:"$handlerMap$1$?f@@YAXXZ":
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long "??_R0N@8"@IMGREL
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long "?f@@YAXXZ.catch1"@IMGREL
|
||||
; CHECK-NEXT: .long ".L?f@@YAXXZ.catch1$parent_frame_offset"
|
||||
; CHECK-NEXT:"$ip2state$?f@@YAXXZ":
|
||||
; CHECK-NEXT: .long .Ltmp0@IMGREL
|
||||
; CHECK-NEXT: .long 0
|
||||
; CHECK-NEXT: .long .Ltmp13@IMGREL
|
||||
; CHECK-NEXT: .long 1
|
||||
; CHECK-NEXT: .long .Ltmp16@IMGREL
|
||||
; CHECK-NEXT: .long 0
|
||||
|
||||
|
||||
declare void @"\01?may_throw@@YAXXZ"() #1
|
||||
|
||||
declare i32 @__CxxFrameHandler3(...)
|
||||
|
||||
; Function Attrs: nounwind readnone
|
||||
declare i32 @llvm.eh.typeid.for(i8*) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.eh.endcatch() #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare i8* @llvm.eh.actions(...) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.frameescape(...) #3
|
||||
|
||||
; Function Attrs: nounwind readnone
|
||||
declare i8* @llvm.framerecover(i8*, i8*, i32) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.eh.unwindhelp(i8*) #3
|
||||
|
||||
declare void @llvm.donothing(...)
|
||||
|
||||
attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="?f@@YAXXZ" }
|
||||
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #2 = { nounwind readnone }
|
||||
attributes #3 = { nounwind }
|
||||
attributes #4 = { "wineh-parent"="?f@@YAXXZ" }
|
@ -27,7 +27,7 @@ $_TI1H = comdat any
|
||||
@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
|
||||
|
||||
|
||||
; CHECK-LABEL: ?test1@@YAXXZ":
|
||||
; CHECK-LABEL: "?test1@@YAXXZ":
|
||||
; CHECK: .seh_handlerdata
|
||||
; CHECK-NEXT: .long ("$cppxdata$?test1@@YAXXZ")@IMGREL
|
||||
; CHECK-NEXT:"$cppxdata$?test1@@YAXXZ":
|
||||
@ -126,11 +126,11 @@ entry:
|
||||
%s1 = alloca %struct.S, align 1
|
||||
%frombool = zext i1 %b to i8
|
||||
store i8 %frombool, i8* %b.addr, align 1
|
||||
call void @"\01?may_throw@@YAXXZ"()
|
||||
call void (...)* @llvm.frameescape(%struct.S* %s, %struct.S* %s1)
|
||||
store volatile i64 -2, i64* %unwindhelp
|
||||
%0 = bitcast i64* %unwindhelp to i8*
|
||||
store volatile i64 -2, i64* %unwindhelp
|
||||
call void (...)* @llvm.frameescape(%struct.S* %s, %struct.S* %s1)
|
||||
call void @llvm.eh.unwindhelp(i8* %0)
|
||||
call void @"\01?may_throw@@YAXXZ"()
|
||||
invoke void @"\01?may_throw@@YAXXZ"()
|
||||
to label %invoke.cont unwind label %lpad1
|
||||
|
Loading…
x
Reference in New Issue
Block a user