From 75771885f89fd206bd38c1899469df09eef49a22 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 10 Sep 2015 00:25:23 +0000 Subject: [PATCH] [WinEH] Add codegen support for cleanuppad and cleanupret All of the complexity is in cleanupret, and it mostly follows the same codepaths as catchret, except it doesn't take a return value in RAX. This small example now compiles and executes successfully on win32: extern "C" int printf(const char *, ...) noexcept; struct Dtor { ~Dtor() { printf("~Dtor\n"); } }; void has_cleanup() { Dtor o; throw 42; } int main() { try { has_cleanup(); } catch (int) { printf("caught it\n"); } } Don't try to put the cleanup in the same function as the catch, or Bad Things will happen. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247219 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/ISDOpcodes.h | 5 + include/llvm/CodeGen/WinEHFuncInfo.h | 8 +- lib/CodeGen/AsmPrinter/WinException.cpp | 10 +- .../SelectionDAG/FunctionLoweringInfo.cpp | 35 +++---- .../SelectionDAG/SelectionDAGBuilder.cpp | 91 ++++++++++++------- lib/CodeGen/WinEHPrepare.cpp | 2 +- lib/Target/X86/X86FrameLowering.cpp | 2 + lib/Target/X86/X86ISelLowering.cpp | 21 +++-- lib/Target/X86/X86ISelLowering.h | 7 ++ lib/Target/X86/X86InstrCompiler.td | 8 ++ lib/Target/X86/X86InstrInfo.td | 2 + test/CodeGen/X86/win-catchpad-csrs.ll | 4 +- test/CodeGen/X86/win-catchpad.ll | 4 +- 13 files changed, 129 insertions(+), 70 deletions(-) diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index 5d41e3bc0d7..c28802c34b2 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -591,8 +591,13 @@ namespace ISD { /// take a chain as input and return a chain. EH_LABEL, + /// CATCHRET - Represents a return from a catch block funclet. Used for + /// MSVC compatible exception handling. Takes a chain operand and a + /// destination basic block operand. CATCHRET, + /// CLEANUPRET - Represents a return from a cleanup block funclet. Used for + /// MSVC compatible exception handling. Takes only a chain operand. CLEANUPRET, /// STACKSAVE - STACKSAVE has one operand, an input chain. It produces a diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h index 369faddd647..31021f12858 100644 --- a/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/include/llvm/CodeGen/WinEHFuncInfo.h @@ -116,14 +116,14 @@ void parseEHActions(const IntrinsicInst *II, // The following structs respresent the .xdata for functions using C++ // exceptions on Windows. +typedef PointerUnion MBBOrBasicBlock; +typedef PointerUnion ValueOrMBB; + struct WinEHUnwindMapEntry { int ToState; - const Value *Cleanup; + ValueOrMBB Cleanup; }; -typedef PointerUnion MBBOrBasicBlock; -typedef PointerUnion ValueOrMBB; - /// Similar to WinEHUnwindMapEntry, but supports SEH filters. struct SEHUnwindMapEntry { /// If unwinding continues through this handler, transition to the handler at diff --git a/lib/CodeGen/AsmPrinter/WinException.cpp b/lib/CodeGen/AsmPrinter/WinException.cpp index e706d73dee2..095315809cb 100644 --- a/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/lib/CodeGen/AsmPrinter/WinException.cpp @@ -316,10 +316,11 @@ void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { /// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues /// are used in the old WinEH scheme, and they will be removed eventually. static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) { + if (!Handler) + return nullptr; if (Handler.is()) return Handler.get()->getSymbol(); - else - return Asm->getSymbol(cast(Handler.get())); + return Asm->getSymbol(cast(Handler.get())); } void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { @@ -404,8 +405,9 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { if (UnwindMapXData) { OS.EmitLabel(UnwindMapXData); for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { - OS.EmitIntValue(UME.ToState, 4); // ToState - OS.EmitValue(create32bitRef(UME.Cleanup), 4); // Action + MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup); + OS.EmitIntValue(UME.ToState, 4); // ToState + OS.EmitValue(create32bitRef(CleanupSym), 4); // Action } } diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 15793f666ea..fe359777a36 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -223,8 +223,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, assert(&*BB->begin() == I && "WinEHPrepare failed to remove PHIs from imaginary BBs"); continue; - } else if (!isa(I)) { - llvm_unreachable("unhandled EH pad in MBB graph"); } } @@ -269,7 +267,7 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, SmallVector LPads; for (BB = Fn->begin(); BB != EB; ++BB) { const Instruction *FNP = BB->getFirstNonPHI(); - if (BB->isEHPad() && !isa(FNP) && !isa(FNP)) + if (BB->isEHPad() && MBBMap.count(BB)) MBBMap[BB]->setIsEHPad(); if (const auto *LPI = dyn_cast(FNP)) LPads.push_back(LPI); @@ -289,24 +287,27 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, // Calculate state numbers if we haven't already. WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn); - if (Personality == EHPersonality::MSVC_CXX) { - const Function *WinEHParentFn = MMI.getWinEHParent(&fn); + const Function *WinEHParentFn = MMI.getWinEHParent(&fn); + if (Personality == EHPersonality::MSVC_CXX) calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo); - } else { - const Function *WinEHParentFn = MMI.getWinEHParent(&fn); + else calculateSEHStateNumbers(WinEHParentFn, EHInfo); + + // Map all BB references in the WinEH data to MBBs. + for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) + for (WinEHHandlerType &H : TBME.HandlerArray) + if (const auto *BB = + dyn_cast(H.Handler.get())) + H.Handler = MBBMap[BB]; + for (WinEHUnwindMapEntry &UME : EHInfo.UnwindMap) + if (UME.Cleanup) + if (const auto *BB = dyn_cast(UME.Cleanup.get())) + UME.Cleanup = MBBMap[BB]; + for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) { + const BasicBlock *BB = UME.Handler.get(); + UME.Handler = MBBMap[BB]; } - // Map all BB references in the EH data to MBBs. - for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) - for (WinEHHandlerType &H : TBME.HandlerArray) - if (const auto *BB = - dyn_cast(H.Handler.get())) - H.Handler = MBBMap[BB]; - for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) { - const BasicBlock *BB = UME.Handler.get(); - UME.Handler = MBBMap[BB]; - } // If there's an explicit EH registration node on the stack, record its // frame index. if (EHInfo.EHRegNode && EHInfo.EHRegNode->getParent()->getParent() == Fn) { diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 6fba18d60b2..2885776a306 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1165,9 +1165,8 @@ void SelectionDAGBuilder::visitCatchPad(const CatchPadInst &I) { void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) { // Update machine-CFG edge. - MachineBasicBlock *PadMBB = FuncInfo.MBB; MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()]; - PadMBB->addSuccessor(TargetMBB); + FuncInfo.MBB->addSuccessor(TargetMBB); // Create the terminator node. SDValue Ret = DAG.getNode(ISD::CATCHRET, getCurSDLoc(), MVT::Other, @@ -1180,11 +1179,64 @@ void SelectionDAGBuilder::visitCatchEndPad(const CatchEndPadInst &I) { } void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) { - report_fatal_error("visitCleanupPad not yet implemented!"); + // Don't emit any special code for the cleanuppad instruction. It just marks + // the start of a funclet. + FuncInfo.MBB->setIsEHFuncletEntry(); +} + +/// When an invoke or a cleanupret unwinds to the next EH pad, there are +/// many places it could ultimately go. In the IR, we have a single unwind +/// destination, but in the machine CFG, we enumerate all the possible blocks. +/// This function skips over imaginary basic blocks that hold catchpad, +/// terminatepad, or catchendpad instructions, and finds all the "real" machine +/// basic block destinations. +static void +findUnwindDestinations(FunctionLoweringInfo &FuncInfo, + const BasicBlock *EHPadBB, + SmallVectorImpl &UnwindDests) { + bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) == + EHPersonality::MSVC_CXX; + while (EHPadBB) { + const Instruction *Pad = EHPadBB->getFirstNonPHI(); + if (isa(Pad)) { + // Stop on landingpads. They are not funclets. + UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]); + break; + } else if (isa(Pad) || isa(Pad)) { + // Stop on cleanup pads. Cleanups are always funclet entries for all known + // personalities. + UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]); + UnwindDests.back()->setIsEHFuncletEntry(); + break; + } else if (const auto *CPI = dyn_cast(Pad)) { + // Add the catchpad handler to the possible destinations. + UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]); + // In MSVC C++, catchblocks are funclets and need prologues. + if (IsMSVCCXX) + UnwindDests.back()->setIsEHFuncletEntry(); + EHPadBB = CPI->getUnwindDest(); + } else if (const auto *CEPI = dyn_cast(Pad)) { + EHPadBB = CEPI->getUnwindDest(); + } else if (const auto *CEPI = dyn_cast(Pad)) { + EHPadBB = CEPI->getUnwindDest(); + } + } } void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) { - report_fatal_error("visitCleanupRet not yet implemented!"); + // Update successor info. + // FIXME: The weights for catchpads will be wrong. + SmallVector UnwindDests; + findUnwindDestinations(FuncInfo, I.getUnwindDest(), UnwindDests); + for (MachineBasicBlock *UnwindDest : UnwindDests) { + UnwindDest->setIsEHPad(); + addSuccessorWithWeight(FuncInfo.MBB, UnwindDest); + } + + // Create the terminator node. + SDValue Ret = + DAG.getNode(ISD::CLEANUPRET, getCurSDLoc(), MVT::Other, getControlRoot()); + DAG.setRoot(Ret); } void SelectionDAGBuilder::visitCleanupEndPad(const CleanupEndPadInst &I) { @@ -2020,37 +2072,8 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) { CopyToExportRegsIfNeeded(&I); } - // Stop when we hit a pad that generates real code or we unwind to caller. - // Catchpads are conditional branches that add real MBB destinations and - // continue the loop. EH "end" pads are not real BBs and simply continue. SmallVector UnwindDests; - bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) == - EHPersonality::MSVC_CXX; - while (EHPadBB) { - const Instruction *Pad = EHPadBB->getFirstNonPHI(); - if (isa(Pad)) { - // Stop on landingpads. They are not funclets. - UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]); - break; - } else if (isa(Pad) || isa(Pad)) { - // Stop on cleanup pads. Cleanups are always funclet entries for all known - // personalities. - UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]); - UnwindDests.back()->setIsEHFuncletEntry(); - break; - } else if (const auto *CPI = dyn_cast(Pad)) { - // Add the catchpad handler to the possible destinations. - UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]); - // In MSVC C++, catchblocks are funclets and need prologues. - if (IsMSVCCXX) - UnwindDests.back()->setIsEHFuncletEntry(); - EHPadBB = CPI->getUnwindDest(); - } else if (const auto *CEPI = dyn_cast(Pad)) { - EHPadBB = CEPI->getUnwindDest(); - } else if (const auto *CEPI = dyn_cast(Pad)) { - EHPadBB = CEPI->getUnwindDest(); - } - } + findUnwindDestinations(FuncInfo, EHPadBB, UnwindDests); // Update successor info. // FIXME: The weights for catchpads will be wrong. diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index ed3cd5d400b..ea43cb2ffeb 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -3053,7 +3053,7 @@ static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo, } static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState, - const Function *Filter, const BasicBlock *Handler) { + const Function *Filter, const BasicBlock *Handler) { SEHUnwindMapEntry Entry; Entry.ToState = ParentState; Entry.Filter = Filter; diff --git a/lib/Target/X86/X86FrameLowering.cpp b/lib/Target/X86/X86FrameLowering.cpp index e6c62b8dd6b..032e003fe47 100644 --- a/lib/Target/X86/X86FrameLowering.cpp +++ b/lib/Target/X86/X86FrameLowering.cpp @@ -1030,6 +1030,8 @@ static bool isFuncletReturnInstr(MachineInstr *MI) { switch (MI->getOpcode()) { case X86::CATCHRET: case X86::CATCHRET64: + case X86::CLEANUPRET: + case X86::CLEANUPRET64: return true; default: return false; diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 0225b081edf..bc97ea036bf 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -418,6 +418,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM, } setOperationAction(ISD::EH_RETURN , MVT::Other, Custom); setOperationAction(ISD::CATCHRET , MVT::Other, Custom); + setOperationAction(ISD::CLEANUPRET , MVT::Other, Custom); // NOTE: EH_SJLJ_SETJMP/_LONGJMP supported here is NOT intended to support // SjLj exception handling but a light-weight setjmp/longjmp replacement to // support continuation, user-level threading, and etc.. As a result, no @@ -16889,20 +16890,26 @@ SDValue X86TargetLowering::LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const { return DAG.getNode(ISD::BR, DL, MVT::Other, Chain, Dest); } - unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX); // Load the address of the destination block. + // FIXME: Do this without creating a BlockAddress. MachineBasicBlock *DestMBB = cast(Dest)->getBasicBlock(); - SDValue BlockPtr = DAG.getMCSymbol(DestMBB->getSymbol(), PtrVT); - unsigned WrapperKind = - Subtarget->isPICStyleRIPRel() ? X86ISD::WrapperRIP : X86ISD::Wrapper; - SDValue WrappedPtr = DAG.getNode(WrapperKind, DL, PtrVT, BlockPtr); - Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, WrappedPtr); + BlockAddress *BA = + BlockAddress::get(const_cast(MF.getFunction()), + const_cast(DestMBB->getBasicBlock())); + DestMBB->setHasAddressTaken(); + SDValue BlockPtr = DAG.getBlockAddress(BA, PtrVT); + Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, BlockPtr); return DAG.getNode(X86ISD::CATCHRET, DL, MVT::Other, Chain, DAG.getRegister(ReturnReg, PtrVT)); } +SDValue X86TargetLowering::LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const { + return DAG.getNode(X86ISD::CLEANUPRET, SDLoc(Op), MVT::Other, + Op.getOperand(0)); +} + SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -19142,6 +19149,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { return LowerFRAME_TO_ARGS_OFFSET(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG); + case ISD::CLEANUPRET: return LowerCLEANUPRET(Op, DAG); case ISD::CATCHRET: return LowerCATCHRET(Op, DAG); case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG); case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG); @@ -19480,6 +19488,7 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const { case X86ISD::EH_SJLJ_LONGJMP: return "X86ISD::EH_SJLJ_LONGJMP"; case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN"; case X86ISD::CATCHRET: return "X86ISD::CATCHRET"; + case X86ISD::CLEANUPRET: return "X86ISD::CLEANUPRET"; case X86ISD::TC_RETURN: return "X86ISD::TC_RETURN"; case X86ISD::FNSTCW16m: return "X86ISD::FNSTCW16m"; case X86ISD::FNSTSW16r: return "X86ISD::FNSTSW16r"; diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index ba9d0ce69e2..fc9b1b6c0fe 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -268,8 +268,14 @@ namespace llvm { // Exception Handling helpers. EH_RETURN, + // CATCHRET - Represents a return from a catch block funclet. Used for + // MSVC compatible exception handling. Takes a chain operand and RAX. CATCHRET, + // CLEANUPRET - Represents a return from a cleanup block funclet. Used + // for MSVC compatible exception handling. Takes only a chain operand. + CLEANUPRET, + // SjLj exception handling setjmp. EH_SJLJ_SETJMP, @@ -1009,6 +1015,7 @@ namespace llvm { SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const; SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const; SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const; SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const; diff --git a/lib/Target/X86/X86InstrCompiler.td b/lib/Target/X86/X86InstrCompiler.td index 4798474cecb..ea8fb20f1d4 100644 --- a/lib/Target/X86/X86InstrCompiler.td +++ b/lib/Target/X86/X86InstrCompiler.td @@ -159,6 +159,14 @@ def CATCHRET : I<0xC3, RawFrm, (outs), (ins GR32:$addr), def CATCHRET64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr), "ret{q}\t# CATCHRET", [(X86catchret GR64:$addr)], IIC_RET>, Sched<[WriteJumpLd]>; +def CLEANUPRET : I<0xC3, RawFrm, (outs), (ins), + "ret{l}\t# CLEANUPRET", + [(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>, + Requires<[Not64BitMode]>; +def CLEANUPRET64 : I<0xC3, RawFrm, (outs), (ins), + "ret{q}\t# CLEANUPRET", + [(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>, + Requires<[In64BitMode]>; } let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1, diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 73136d9c5d9..005c3d518f7 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -207,6 +207,8 @@ def X86ehret : SDNode<"X86ISD::EH_RETURN", SDT_X86EHRET, def X86catchret : SDNode<"X86ISD::CATCHRET", SDT_X86EHRET, [SDNPHasChain]>; +def X86cleanupret : SDNode<"X86ISD::CLEANUPRET", SDTX86Void, [SDNPHasChain]>; + def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP", SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisPtrTy<1>]>, diff --git a/test/CodeGen/X86/win-catchpad-csrs.ll b/test/CodeGen/X86/win-catchpad-csrs.ll index f765207d19d..6e72268432a 100644 --- a/test/CodeGen/X86/win-catchpad-csrs.ll +++ b/test/CodeGen/X86/win-catchpad-csrs.ll @@ -63,7 +63,7 @@ catchendblock: ; preds = %catch, ; X86: movl $0, -{{[0-9]+}}(%ebp) ; X86: movl $1, (%esp) ; X86: calll _f -; X86: [[contbb:LBB0_[0-9]+]]: +; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken ; X86: movl -{{[0-9]+}}(%ebp), %esp ; X86: addl ${{[0-9]+}}, %esp ; X86: popl %esi @@ -111,7 +111,7 @@ catchendblock: ; preds = %catch, ; X64: callq useints ; X64: movl $1, %ecx ; X64: callq f -; X64: [[contbb:\.LBB0_[0-9]+]]: +; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken ; X64: addq $40, %rsp ; X64: popq %rbp ; X64: retq diff --git a/test/CodeGen/X86/win-catchpad.ll b/test/CodeGen/X86/win-catchpad.ll index 12a58be6dea..c41087a4deb 100644 --- a/test/CodeGen/X86/win-catchpad.ll +++ b/test/CodeGen/X86/win-catchpad.ll @@ -71,7 +71,7 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X86-DAG: movl %[[addr_reg]], 4(%esp) ; X86-DAG: movl $1, (%esp) ; X86: calll _f -; X86: [[contbb:LBB0_[0-9]+]]: +; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken ; X86: movl -{{[0-9]+}}(%ebp), %esp ; X86: retl @@ -120,7 +120,7 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx ; X64-DAG: movl $1, %ecx ; X64: callq f -; X64: [[contbb:\.LBB0_[0-9]+]]: +; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken ; X64: addq $48, %rsp ; X64: popq %rbp ; X64: retq -- 2.34.1