1
0
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:
David Majnemer 2015-03-31 22:35:44 +00:00
parent 58bc60892e
commit 64386621ec
14 changed files with 385 additions and 91 deletions

@ -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"()

@ -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