[WinEH] Add codegen support for cleanuppad and cleanupret
authorReid Kleckner <rnk@google.com>
Thu, 10 Sep 2015 00:25:23 +0000 (00:25 +0000)
committerReid Kleckner <rnk@google.com>
Thu, 10 Sep 2015 00:25:23 +0000 (00:25 +0000)
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.

llvm-svn: 247219

13 files changed:
llvm/include/llvm/CodeGen/ISDOpcodes.h
llvm/include/llvm/CodeGen/WinEHFuncInfo.h
llvm/lib/CodeGen/AsmPrinter/WinException.cpp
llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/lib/CodeGen/WinEHPrepare.cpp
llvm/lib/Target/X86/X86FrameLowering.cpp
llvm/lib/Target/X86/X86ISelLowering.cpp
llvm/lib/Target/X86/X86ISelLowering.h
llvm/lib/Target/X86/X86InstrCompiler.td
llvm/lib/Target/X86/X86InstrInfo.td
llvm/test/CodeGen/X86/win-catchpad-csrs.ll
llvm/test/CodeGen/X86/win-catchpad.ll

index 5d41e3b..c28802c 100644 (file)
@@ -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
index 369fadd..31021f1 100644 (file)
@@ -116,14 +116,14 @@ void parseEHActions(const IntrinsicInst *II,
 // The following structs respresent the .xdata for functions using C++
 // exceptions on Windows.
 
+typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
+typedef PointerUnion<const Value *, MachineBasicBlock *> ValueOrMBB;
+
 struct WinEHUnwindMapEntry {
   int ToState;
-  const Value *Cleanup;
+  ValueOrMBB Cleanup;
 };
 
-typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
-typedef PointerUnion<const Value *, MachineBasicBlock *> ValueOrMBB;
-
 /// Similar to WinEHUnwindMapEntry, but supports SEH filters.
 struct SEHUnwindMapEntry {
   /// If unwinding continues through this handler, transition to the handler at
index e706d73..0953158 100644 (file)
@@ -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<MachineBasicBlock *>())
     return Handler.get<MachineBasicBlock *>()->getSymbol();
-  else
-    return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
+  return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
 }
 
 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
     }
   }
 
index 15793f6..fe35977 100644 (file)
@@ -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<LandingPadInst>(I)) {
-        llvm_unreachable("unhandled EH pad in MBB graph");
       }
     }
 
@@ -269,7 +267,7 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
   SmallVector<const LandingPadInst *, 4> LPads;
   for (BB = Fn->begin(); BB != EB; ++BB) {
     const Instruction *FNP = BB->getFirstNonPHI();
-    if (BB->isEHPad() && !isa<CatchPadInst>(FNP) && !isa<CatchEndPadInst>(FNP))
+    if (BB->isEHPad() && MBBMap.count(BB))
       MBBMap[BB]->setIsEHPad();
     if (const auto *LPI = dyn_cast<LandingPadInst>(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<BasicBlock>(H.Handler.get<const Value *>()))
+        H.Handler = MBBMap[BB];
+  for (WinEHUnwindMapEntry &UME : EHInfo.UnwindMap)
+    if (UME.Cleanup)
+      if (const auto *BB = dyn_cast<BasicBlock>(UME.Cleanup.get<const Value *>()))
+        UME.Cleanup = MBBMap[BB];
+  for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
+    const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
+    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<BasicBlock>(H.Handler.get<const Value *>()))
-          H.Handler = MBBMap[BB];
-    for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
-      const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
-      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) {
index 6fba18d..2885776 100644 (file)
@@ -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<MachineBasicBlock *> &UnwindDests) {
+  bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
+                   EHPersonality::MSVC_CXX;
+  while (EHPadBB) {
+    const Instruction *Pad = EHPadBB->getFirstNonPHI();
+    if (isa<LandingPadInst>(Pad)) {
+      // Stop on landingpads. They are not funclets.
+      UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
+      break;
+    } else if (isa<CleanupPadInst>(Pad) || isa<LandingPadInst>(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<CatchPadInst>(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<CatchEndPadInst>(Pad)) {
+      EHPadBB = CEPI->getUnwindDest();
+    } else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(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<MachineBasicBlock *, 1> 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<MachineBasicBlock *, 1> UnwindDests;
-  bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
-                   EHPersonality::MSVC_CXX;
-  while (EHPadBB) {
-    const Instruction *Pad = EHPadBB->getFirstNonPHI();
-    if (isa<LandingPadInst>(Pad)) {
-      // Stop on landingpads. They are not funclets.
-      UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
-      break;
-    } else if (isa<CleanupPadInst>(Pad) || isa<LandingPadInst>(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<CatchPadInst>(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<CatchEndPadInst>(Pad)) {
-      EHPadBB = CEPI->getUnwindDest();
-    } else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad)) {
-      EHPadBB = CEPI->getUnwindDest();
-    }
-  }
+  findUnwindDestinations(FuncInfo, EHPadBB, UnwindDests);
 
   // Update successor info.
   // FIXME: The weights for catchpads will be wrong.
index ed3cd5d..ea43cb2 100644 (file)
@@ -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;
index e6c62b8..032e003 100644 (file)
@@ -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;
index 0225b08..bc97ea0 100644 (file)
@@ -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<BasicBlockSDNode>(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<Function *>(MF.getFunction()),
+                        const_cast<BasicBlock *>(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";
index ba9d0ce..fc9b1b6 100644 (file)
@@ -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;
index 4798474..ea8fb20 100644 (file)
@@ -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,
index 73136d9..005c3d5 100644 (file)
@@ -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>]>,
index f765207..6e72268 100644 (file)
@@ -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
index 12a58be..c41087a 100644 (file)
@@ -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