From: David Majnemer Date: Tue, 31 Mar 2015 22:35:44 +0000 (+0000) Subject: [WinEH] Generate .xdata for catch handlers X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=64386621ec978386e0238fc16990861c5d4d98c1;p=oota-llvm.git [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 --- diff --git a/docs/ExceptionHandling.rst b/docs/ExceptionHandling.rst index 0c12b282282..21de19b0752 100644 --- a/docs/ExceptionHandling.rst +++ b/docs/ExceptionHandling.rst @@ -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 --------------- diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h index 807afe6f8ae..8d9c6f24d5f 100644 --- a/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/include/llvm/CodeGen/WinEHFuncInfo.h @@ -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 HandlerArray; + SmallVector HandlerArray; }; struct WinEHFuncInfo { diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index c5ab91ec9b5..da9d8cb61f5 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -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. diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index c1f2fac82f7..63faeceec9d 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -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; diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/lib/CodeGen/AsmPrinter/Win64Exception.cpp index 974e94dcb6a..7a82daa3337 100644 --- a/lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ b/lib/CodeGen/AsmPrinter/Win64Exception.cpp @@ -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 } } } diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index c00b11893bf..e2235fbc044 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -88,6 +88,7 @@ struct WinEHNumbering { int NextState; SmallVector HandlerStack; + SmallPtrSet VisitedHandlers; int currentEHNumber() const { return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState(); @@ -96,7 +97,9 @@ struct WinEHNumbering { void parseEHActions(const IntrinsicInst *II, SmallVectorImpl &Actions); void createUnwindMapEntry(int ToState, ActionHandler *AH); - void proccessCallSite(ArrayRef Actions, ImmutableCallSite CS); + void createTryBlockMapEntry(int TryLow, int TryHigh, + ArrayRef Handlers); + void processCallSite(ArrayRef 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(AH)) + if (auto *CH = dyn_cast_or_null(AH)) UME.Cleanup = cast(CH->getHandlerBlockOrFunc()); else UME.Cleanup = nullptr; FuncInfo.UnwindMap.push_back(UME); } +void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh, + ArrayRef 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(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(GV->getInitializer()); + HT.Adjectives = + cast(CS->getAggregateElement(0U))->getZExtValue(); + HT.TypeDescriptor = cast( + CS->getAggregateElement(1)->stripPointerCasts()); + HT.Handler = cast(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 Actions, - ImmutableCallSite CS) { - // float, int - // float, double, int +void WinEHNumbering::processCallSite(ArrayRef 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 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 UnnumberedHandlers; + SmallVector PoppedCatches; for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) { - if (auto *CH = dyn_cast(HandlerStack.back())) - if (const auto *F = dyn_cast(CH->getHandlerBlockOrFunc())) - UnnumberedHandlers.push_back(F); - // Pop the handlers off of the stack. - delete HandlerStack.back(); + if (auto *CH = dyn_cast(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(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(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 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 ActionList; for (const BasicBlock &BB : F) { @@ -380,21 +455,21 @@ void WinEHNumbering::calculateStateNumbers(const Function &F) { const auto *CI = dyn_cast(&I); if (!CI || CI->doesNotThrow()) continue; - proccessCallSite(None, CI); + processCallSite(None, CI); } const auto *II = dyn_cast(BB.getTerminator()); if (!II) continue; const LandingPadInst *LPI = II->getLandingPadInst(); - if (auto *ActionsCall = dyn_cast(LPI->getNextNode())) { - assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions); - parseEHActions(ActionsCall, ActionList); - proccessCallSite(ActionList, II); - ActionList.clear(); - FuncInfo.LandingPadStateMap[LPI] = currentEHNumber(); - } + auto *ActionsCall = dyn_cast(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 diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index fd9d7e6b69a..fa58614a4b3 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -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(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(I.getArgOperand(0)->stripPointerCasts()); diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index 94e046c424d..5b4ee17d949 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -638,16 +638,6 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn, if (!LPadMap.isInitialized()) LPadMap.mapLandingPad(LPad); if (auto *CatchAction = dyn_cast(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)); diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 15fbea33d89..1cdb99c4366 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -3228,13 +3228,6 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { break; } - case Intrinsic::eh_parentframe: { - auto *AI = dyn_cast(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(CI.getArgOperand(0)->stripPointerCasts()); Assert(AI && AI->isStaticAlloca(), diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 2cb81d06b05..6e7a3bc4db7 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -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; diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 84b71429f33..966aec0df96 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -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 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(); + 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(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()) { diff --git a/test/CodeGen/WinEH/cppeh-catch-unwind.ll b/test/CodeGen/WinEH/cppeh-catch-unwind.ll index 60a5256a133..33d85517efa 100644 --- a/test/CodeGen/WinEH/cppeh-catch-unwind.ll +++ b/test/CodeGen/WinEH/cppeh-catch-unwind.ll @@ -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"() diff --git a/test/CodeGen/WinEH/cppeh-cleanups.ll b/test/CodeGen/WinEH/cppeh-cleanups.ll deleted file mode 100644 index 64d9980be39..00000000000 --- a/test/CodeGen/WinEH/cppeh-cleanups.ll +++ /dev/null @@ -1,226 +0,0 @@ -; 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" - -%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } -%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } -%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } -%eh.ThrowInfo = type { i32, i32, i32, i32 } -%struct.S = type { i8 } - -$"\01??_DS@@QEAA@XZ" = comdat any - -$"\01??_R0H@8" = comdat any - -$"_CT??_R0H@84" = comdat any - -$_CTA1H = comdat any - -$_TI1H = comdat any - -@"\01??_7type_info@@6B@" = external constant i8* -@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -@__ImageBase = external constant i8 -@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat -@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat -@_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: .seh_handlerdata -; CHECK-NEXT: .long ("$cppxdata$?test1@@YAXXZ")@IMGREL -; CHECK-NEXT:"$cppxdata$?test1@@YAXXZ": -; CHECK-NEXT: .long 429065506 -; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long ("$stateUnwindMap$?test1@@YAXXZ")@IMGREL -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long ("$ip2state$?test1@@YAXXZ")@IMGREL -; CHECK-NEXT: .long 64 -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 1 -; CHECK-NEXT:"$stateUnwindMap$?test1@@YAXXZ": -; CHECK-NEXT: .long -1 -; CHECK-NEXT: .long "?test1@@YAXXZ.cleanup"@IMGREL -; CHECK-NEXT:"$ip2state$?test1@@YAXXZ": -; CHECK-NEXT: .long .Ltmp0@IMGREL -; CHECK-NEXT: .long 0 - -define void @"\01?test1@@YAXXZ"() #0 { -entry: - %unwindhelp = alloca i64 - %tmp = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - store i32 0, i32* %tmp - %0 = bitcast i32* %tmp to i8* - call void (...)* @llvm.frameescape() - store volatile i64 -2, i64* %unwindhelp - %1 = bitcast i64* %unwindhelp to i8* - call void @llvm.eh.unwindhelp(i8* %1) - invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #8 - to label %unreachable unwind label %lpad1 - -lpad1: ; preds = %entry - %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) - cleanup - %recover = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test1@@YAXXZ.cleanup") - indirectbr i8* %recover, [] - -unreachable: ; preds = %entry - unreachable -} - -declare void @_CxxThrowException(i8*, %eh.ThrowInfo*) - -declare i32 @__CxxFrameHandler3(...) - -; Function Attrs: nounwind -define linkonce_odr void @"\01??_DS@@QEAA@XZ"(%struct.S* %this) unnamed_addr #1 comdat align 2 { -entry: - %this.addr = alloca %struct.S*, align 8 - store %struct.S* %this, %struct.S** %this.addr, align 8 - %this1 = load %struct.S*, %struct.S** %this.addr - call void @"\01??1S@@QEAA@XZ"(%struct.S* %this1) #4 - ret void -} - -; CHECK-LABEL: "?test2@@YAX_N@Z": -; CHECK: .seh_handlerdata -; CHECK-NEXT: .long ("$cppxdata$?test2@@YAX_N@Z")@IMGREL -; CHECK-NEXT:"$cppxdata$?test2@@YAX_N@Z": -; CHECK-NEXT: .long 429065506 -; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long ("$stateUnwindMap$?test2@@YAX_N@Z")@IMGREL -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 4 -; CHECK-NEXT: .long ("$ip2state$?test2@@YAX_N@Z")@IMGREL -; CHECK-NEXT: .long 64 -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 1 -; CHECK-NEXT:"$stateUnwindMap$?test2@@YAX_N@Z": -; CHECK-NEXT: .long -1 -; CHECK-NEXT: .long "?test2@@YAX_N@Z.cleanup"@IMGREL -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long "?test2@@YAX_N@Z.cleanup1"@IMGREL -; CHECK-NEXT:"$ip2state$?test2@@YAX_N@Z": -; CHECK-NEXT: .long .Lfunc_begin1@IMGREL -; CHECK-NEXT: .long -1 -; CHECK-NEXT: .long .Ltmp7@IMGREL -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long .Ltmp9@IMGREL -; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long .Ltmp12@IMGREL -; CHECK-NEXT: .long 0 - -define void @"\01?test2@@YAX_N@Z"(i1 zeroext %b) #2 { -entry: - %unwindhelp = alloca i64 - %b.addr = alloca i8, align 1 - %s = alloca %struct.S, align 1 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %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* - call void @llvm.eh.unwindhelp(i8* %0) - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont unwind label %lpad1 - -invoke.cont: ; preds = %entry - %1 = load i8, i8* %b.addr, align 1 - %tobool = trunc i8 %1 to i1 - br i1 %tobool, label %if.then, label %if.else - -if.then: ; preds = %invoke.cont - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont3 unwind label %lpad3 - -invoke.cont3: ; preds = %if.then - call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4 - br label %if.end - -lpad1: ; preds = %entry, %if.end - %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) - cleanup - %recover = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup") - indirectbr i8* %recover, [] - -lpad3: ; preds = %if.then - %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) - cleanup - %recover4 = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup1", i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup") - indirectbr i8* %recover4, [] - -if.else: ; preds = %invoke.cont - call void @"\01?dont_throw@@YAXXZ"() #4 - br label %if.end - -if.end: ; preds = %if.else, %invoke.cont3 - invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont4 unwind label %lpad1 - -invoke.cont4: ; preds = %if.end - call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 - ret void -} - -declare void @"\01?may_throw@@YAXXZ"() #3 - -; Function Attrs: nounwind -declare void @"\01?dont_throw@@YAXXZ"() #1 - -; Function Attrs: nounwind -declare void @"\01??1S@@QEAA@XZ"(%struct.S*) #1 - -; Function Attrs: nounwind -declare i8* @llvm.eh.actions(...) #4 - -define internal void @"\01?test1@@YAXXZ.cleanup"(i8*, i8*) #5 { -entry: - %s = alloca %struct.S, align 1 - call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 - ret void -} - -; Function Attrs: nounwind -declare void @llvm.frameescape(...) #4 - -; Function Attrs: nounwind readnone -declare i8* @llvm.framerecover(i8*, i8*, i32) #6 - -; Function Attrs: nounwind -declare void @llvm.eh.unwindhelp(i8*) #4 - -define internal void @"\01?test2@@YAX_N@Z.cleanup"(i8*, i8*) #7 { -entry: - %s.i8 = call i8* @llvm.framerecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 0) - %s = bitcast i8* %s.i8 to %struct.S* - call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 - ret void -} - -define internal void @"\01?test2@@YAX_N@Z.cleanup1"(i8*, i8*) #7 { -entry: - %s1.i8 = call i8* @llvm.framerecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 1) - %s1 = bitcast i8* %s1.i8 to %struct.S* - call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4 - ret void -} - -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"="?test1@@YAXXZ" } -attributes #1 = { nounwind "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 = { "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"="?test2@@YAX_N@Z" } -attributes #3 = { "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 #4 = { nounwind } -attributes #5 = { "wineh-parent"="?test1@@YAXXZ" } -attributes #6 = { nounwind readnone } -attributes #7 = { "wineh-parent"="?test2@@YAX_N@Z" } -attributes #8 = { noreturn } diff --git a/test/CodeGen/WinEH/cppeh-prepared-catch.ll b/test/CodeGen/WinEH/cppeh-prepared-catch.ll new file mode 100644 index 00000000000..a294a075835 --- /dev/null +++ b/test/CodeGen/WinEH/cppeh-prepared-catch.ll @@ -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" } diff --git a/test/CodeGen/WinEH/cppeh-prepared-cleanups.ll b/test/CodeGen/WinEH/cppeh-prepared-cleanups.ll new file mode 100644 index 00000000000..0a76a22208c --- /dev/null +++ b/test/CodeGen/WinEH/cppeh-prepared-cleanups.ll @@ -0,0 +1,226 @@ +; 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" + +%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } +%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } +%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } +%eh.ThrowInfo = type { i32, i32, i32, i32 } +%struct.S = type { i8 } + +$"\01??_DS@@QEAA@XZ" = comdat any + +$"\01??_R0H@8" = comdat any + +$"_CT??_R0H@84" = comdat any + +$_CTA1H = comdat any + +$_TI1H = comdat any + +@"\01??_7type_info@@6B@" = external constant i8* +@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat +@__ImageBase = external constant i8 +@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat +@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat +@_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: .seh_handlerdata +; CHECK-NEXT: .long ("$cppxdata$?test1@@YAXXZ")@IMGREL +; CHECK-NEXT:"$cppxdata$?test1@@YAXXZ": +; CHECK-NEXT: .long 429065506 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long ("$stateUnwindMap$?test1@@YAXXZ")@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long ("$ip2state$?test1@@YAXXZ")@IMGREL +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT:"$stateUnwindMap$?test1@@YAXXZ": +; CHECK-NEXT: .long -1 +; CHECK-NEXT: .long "?test1@@YAXXZ.cleanup"@IMGREL +; CHECK-NEXT:"$ip2state$?test1@@YAXXZ": +; CHECK-NEXT: .long .Ltmp0@IMGREL +; CHECK-NEXT: .long 0 + +define void @"\01?test1@@YAXXZ"() #0 { +entry: + %unwindhelp = alloca i64 + %tmp = alloca i32, align 4 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + store i32 0, i32* %tmp + %0 = bitcast i32* %tmp to i8* + call void (...)* @llvm.frameescape() + store volatile i64 -2, i64* %unwindhelp + %1 = bitcast i64* %unwindhelp to i8* + call void @llvm.eh.unwindhelp(i8* %1) + invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #8 + to label %unreachable unwind label %lpad1 + +lpad1: ; preds = %entry + %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + cleanup + %recover = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test1@@YAXXZ.cleanup") + indirectbr i8* %recover, [] + +unreachable: ; preds = %entry + unreachable +} + +declare void @_CxxThrowException(i8*, %eh.ThrowInfo*) + +declare i32 @__CxxFrameHandler3(...) + +; Function Attrs: nounwind +define linkonce_odr void @"\01??_DS@@QEAA@XZ"(%struct.S* %this) unnamed_addr #1 comdat align 2 { +entry: + %this.addr = alloca %struct.S*, align 8 + store %struct.S* %this, %struct.S** %this.addr, align 8 + %this1 = load %struct.S*, %struct.S** %this.addr + call void @"\01??1S@@QEAA@XZ"(%struct.S* %this1) #4 + ret void +} + +; CHECK-LABEL: "?test2@@YAX_N@Z": +; CHECK: .seh_handlerdata +; CHECK-NEXT: .long ("$cppxdata$?test2@@YAX_N@Z")@IMGREL +; CHECK-NEXT:"$cppxdata$?test2@@YAX_N@Z": +; CHECK-NEXT: .long 429065506 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long ("$stateUnwindMap$?test2@@YAX_N@Z")@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long ("$ip2state$?test2@@YAX_N@Z")@IMGREL +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT:"$stateUnwindMap$?test2@@YAX_N@Z": +; CHECK-NEXT: .long -1 +; CHECK-NEXT: .long "?test2@@YAX_N@Z.cleanup"@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long "?test2@@YAX_N@Z.cleanup1"@IMGREL +; CHECK-NEXT:"$ip2state$?test2@@YAX_N@Z": +; CHECK-NEXT: .long .Lfunc_begin1@IMGREL +; CHECK-NEXT: .long -1 +; CHECK-NEXT: .long .Ltmp7@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp9@IMGREL +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp12@IMGREL +; CHECK-NEXT: .long 0 + +define void @"\01?test2@@YAX_N@Z"(i1 zeroext %b) #2 { +entry: + %unwindhelp = alloca i64 + %b.addr = alloca i8, align 1 + %s = alloca %struct.S, align 1 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + %s1 = alloca %struct.S, align 1 + %frombool = zext i1 %b to i8 + store i8 %frombool, i8* %b.addr, align 1 + %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 + +invoke.cont: ; preds = %entry + %1 = load i8, i8* %b.addr, align 1 + %tobool = trunc i8 %1 to i1 + br i1 %tobool, label %if.then, label %if.else + +if.then: ; preds = %invoke.cont + invoke void @"\01?may_throw@@YAXXZ"() + to label %invoke.cont3 unwind label %lpad3 + +invoke.cont3: ; preds = %if.then + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4 + br label %if.end + +lpad1: ; preds = %entry, %if.end + %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + cleanup + %recover = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup") + indirectbr i8* %recover, [] + +lpad3: ; preds = %if.then + %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + cleanup + %recover4 = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup1", i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup") + indirectbr i8* %recover4, [] + +if.else: ; preds = %invoke.cont + call void @"\01?dont_throw@@YAXXZ"() #4 + br label %if.end + +if.end: ; preds = %if.else, %invoke.cont3 + invoke void @"\01?may_throw@@YAXXZ"() + to label %invoke.cont4 unwind label %lpad1 + +invoke.cont4: ; preds = %if.end + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 + ret void +} + +declare void @"\01?may_throw@@YAXXZ"() #3 + +; Function Attrs: nounwind +declare void @"\01?dont_throw@@YAXXZ"() #1 + +; Function Attrs: nounwind +declare void @"\01??1S@@QEAA@XZ"(%struct.S*) #1 + +; Function Attrs: nounwind +declare i8* @llvm.eh.actions(...) #4 + +define internal void @"\01?test1@@YAXXZ.cleanup"(i8*, i8*) #5 { +entry: + %s = alloca %struct.S, align 1 + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 + ret void +} + +; Function Attrs: nounwind +declare void @llvm.frameescape(...) #4 + +; Function Attrs: nounwind readnone +declare i8* @llvm.framerecover(i8*, i8*, i32) #6 + +; Function Attrs: nounwind +declare void @llvm.eh.unwindhelp(i8*) #4 + +define internal void @"\01?test2@@YAX_N@Z.cleanup"(i8*, i8*) #7 { +entry: + %s.i8 = call i8* @llvm.framerecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 0) + %s = bitcast i8* %s.i8 to %struct.S* + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 + ret void +} + +define internal void @"\01?test2@@YAX_N@Z.cleanup1"(i8*, i8*) #7 { +entry: + %s1.i8 = call i8* @llvm.framerecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 1) + %s1 = bitcast i8* %s1.i8 to %struct.S* + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4 + ret void +} + +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"="?test1@@YAXXZ" } +attributes #1 = { nounwind "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 = { "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"="?test2@@YAX_N@Z" } +attributes #3 = { "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 #4 = { nounwind } +attributes #5 = { "wineh-parent"="?test1@@YAXXZ" } +attributes #6 = { nounwind readnone } +attributes #7 = { "wineh-parent"="?test2@@YAX_N@Z" } +attributes #8 = { noreturn }