Index: include/llvm/IR/InstrTypes.h =================================================================== --- include/llvm/IR/InstrTypes.h +++ include/llvm/IR/InstrTypes.h @@ -1217,6 +1217,11 @@ return getTagID() == LLVMContext::OB_deopt; } + /// \brief Return true if this is a "funclet" operand bundle. + bool isFuncletOperandBundle() const { + return getTagID() == LLVMContext::OB_funclet; + } + private: /// \brief Pointer to an entry in LLVMContextImpl::getOrInsertBundleTag. StringMapEntry *Tag; @@ -1428,11 +1433,12 @@ /// may write to the heap. bool hasClobberingOperandBundles() const { for (auto &BOI : bundle_op_infos()) { - if (BOI.Tag->second == LLVMContext::OB_deopt) + if (BOI.Tag->second == LLVMContext::OB_deopt || + BOI.Tag->second == LLVMContext::OB_funclet) continue; - // This instruction has an operand bundle that is not a "deopt" operand - // bundle. Assume the worst. + // This instruction has an operand bundle that is not known to us. + // Assume the worst. return true; } Index: include/llvm/IR/LLVMContext.h =================================================================== --- include/llvm/IR/LLVMContext.h +++ include/llvm/IR/LLVMContext.h @@ -72,7 +72,8 @@ /// Additionally, this scheme allows LLVM to efficiently check for specific /// operand bundle tags without comparing strings. enum { - OB_deopt = 0, // "deopt" + OB_deopt = 0, // "deopt" + OB_funclet = 1, // "funclet" }; /// getMDKindID - Return a unique non-zero ID for the specified metadata kind. Index: include/llvm/Transforms/Utils/Local.h =================================================================== --- include/llvm/Transforms/Utils/Local.h +++ include/llvm/Transforms/Utils/Local.h @@ -288,6 +288,10 @@ bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, bool Deref, int Offset = 0); +/// \brief Insert an unreachable instruction before the specified +/// instruction, making it and the rest of the code in the block dead. +void changeToUnreachable(Instruction *I, bool UseLLVMTrap); + /// Replace 'BB's terminator with one that does not have an unwind successor /// block. Rewrites `invoke` to `call`, etc. Updates any PHIs in unwind /// successor. Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -770,14 +770,15 @@ for (auto &Funclet : FuncletBlocks) { BasicBlock *FuncletPadBB = Funclet.first; std::vector &BlocksInFunclet = Funclet.second; - Instruction *FuncletPadInst = FuncletPadBB->getFirstNonPHI(); - auto *CatchPad = dyn_cast(FuncletPadInst); - auto *CleanupPad = dyn_cast(FuncletPadInst); + Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); + auto *FuncletPad = dyn_cast(FirstNonPHI); + auto *CatchPad = dyn_cast_or_null(FuncletPad); + auto *CleanupPad = dyn_cast_or_null(FuncletPad); for (BasicBlock *BB : BlocksInFunclet) { TerminatorInst *TI = BB->getTerminator(); // CatchPadInst and CleanupPadInst can't transfer control to a ReturnInst. - bool IsUnreachableRet = isa(TI) && (CatchPad || CleanupPad); + bool IsUnreachableRet = isa(TI) && FuncletPad; // The token consumed by a CatchReturnInst must match the funclet token. bool IsUnreachableCatchret = false; if (auto *CRI = dyn_cast(TI)) @@ -788,19 +789,30 @@ IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad; if (IsUnreachableRet || IsUnreachableCatchret || IsUnreachableCleanupret) { - // Loop through all of our successors and make sure they know that one - // of their predecessors is going away. - for (BasicBlock *SuccBB : TI->successors()) - SuccBB->removePredecessor(BB); - - new UnreachableInst(BB->getContext(), TI); - TI->eraseFromParent(); - } else if (isa(TI)) { - // Invokes within a cleanuppad for the MSVC++ personality never - // transfer control to their unwind edge: the personality will - // terminate the program. - if (Personality == EHPersonality::MSVC_CXX && CleanupPad) + changeToUnreachable(TI, /*UseLLVMTrap=*/false); + } else if (auto *II = dyn_cast(TI)) { + Value *FuncletBundleOperand = nullptr; + if (Optional BU = + II->getOperandBundle(LLVMContext::OB_funclet)) + FuncletBundleOperand = BU->Inputs.front(); + + // If this invoke was not part of this funclet, remove it. + if (FuncletBundleOperand != FuncletPad) { + // First, remove the unwind edge. removeUnwindEdge(BB); + + // Get a pointer to the new call. + TI = BB->getTerminator(); + BasicBlock::iterator CallI = std::prev(TI->getIterator()); + auto *CI = cast(&*CallI); + + changeToUnreachable(CI, /*UseLLVMTrap=*/false); + } else if (Personality == EHPersonality::MSVC_CXX && CleanupPad) { + // Invokes within a cleanuppad for the MSVC++ personality never + // transfer control to their unwind edge: the personality will + // terminate the program. + removeUnwindEdge(BB); + } } } } Index: lib/IR/LLVMContext.cpp =================================================================== --- lib/IR/LLVMContext.cpp +++ lib/IR/LLVMContext.cpp @@ -132,6 +132,11 @@ assert(DeoptEntry->second == LLVMContext::OB_deopt && "deopt operand bundle id drifted!"); (void)DeoptEntry; + + auto *FuncletEntry = pImpl->getOrInsertBundleTag("funclet"); + assert(FuncletEntry->second == LLVMContext::OB_funclet && + "funclet operand bundle id drifted!"); + (void)FuncletEntry; } LLVMContext::~LLVMContext() { delete pImpl; } Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -2381,13 +2381,22 @@ if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) visitIntrinsicCallSite(ID, CS); - // Verify that a callsite has at most one "deopt" operand bundle. - bool FoundDeoptBundle = false; + // Verify that a callsite has at most one "deopt" and one "funclet" operand + // bundle. + bool FoundDeoptBundle = false, FoundFuncletBundle = false; for (unsigned i = 0, e = CS.getNumOperandBundles(); i < e; ++i) { - if (CS.getOperandBundleAt(i).getTagID() == LLVMContext::OB_deopt) { + OperandBundleUse BU = CS.getOperandBundleAt(i); + uint32_t Tag = BU.getTagID(); + if (Tag == LLVMContext::OB_deopt) { Assert(!FoundDeoptBundle, "Multiple deopt operand bundles", I); FoundDeoptBundle = true; } + if (Tag == LLVMContext::OB_funclet) { + Assert(!FoundFuncletBundle, "Multiple funclet operand bundles", I); + FoundFuncletBundle = true; + Assert(BU.Inputs.size() == 1, + "Expected exactly one funclet operand bundle input", I); + } } visitInstruction(*I); @@ -3002,6 +3011,8 @@ UnwindDest = CRI->getUnwindDest(); } else if (isa(U) || isa(U)) { continue; + } else if (CallSite(U)) { + continue; } else { Assert(false, "bogus cleanuppad use", &CPI); } Index: lib/Transforms/Utils/InlineFunction.cpp =================================================================== --- lib/Transforms/Utils/InlineFunction.cpp +++ lib/Transforms/Utils/InlineFunction.cpp @@ -1035,12 +1035,17 @@ // The inliner does not know how to inline through calls with operand bundles // in general ... if (CS.hasOperandBundles()) { - // ... but it knows how to inline through "deopt" operand bundles. - bool CanInline = - CS.getNumOperandBundles() == 1 && - CS.getOperandBundleAt(0).getTagID() == LLVMContext::OB_deopt; - if (!CanInline) + for (int i = 0, e = CS.getNumOperandBundles(); i != e; ++i) { + uint32_t Tag = CS.getOperandBundleAt(i).getTagID(); + // ... but it knows how to inline through "deopt" operand bundles ... + if (Tag == LLVMContext::OB_deopt) + continue; + // ... and "funclet" operand bundles. + if (Tag == LLVMContext::OB_funclet) + continue; + return false; + } } // If the call to the callee cannot throw, set the 'nounwind' flag on any @@ -1088,23 +1093,13 @@ // We need to figure out which funclet the callsite was in so that we may // properly nest the callee. Instruction *CallSiteEHPad = nullptr; - if (CalledPersonality && CallerPersonality) { - EHPersonality Personality = classifyEHPersonality(CalledPersonality); + if (CallerPersonality) { + EHPersonality Personality = classifyEHPersonality(CallerPersonality); if (isFuncletEHPersonality(Personality)) { - DenseMap CallerBlockColors = - colorEHFunclets(*Caller); - ColorVector &CallSiteColors = CallerBlockColors[OrigBB]; - size_t NumColors = CallSiteColors.size(); - // There is no single parent, inlining will not succeed. - if (NumColors > 1) - return false; - if (NumColors == 1) { - BasicBlock *CallSiteFuncletBB = CallSiteColors.front(); - if (CallSiteFuncletBB != Caller->begin()) { - CallSiteEHPad = CallSiteFuncletBB->getFirstNonPHI(); - assert(CallSiteEHPad->isEHPad() && "Expected an EHPad!"); - } - } + Optional ParentFunclet = + CS.getOperandBundle(LLVMContext::OB_funclet); + if (ParentFunclet) + CallSiteEHPad = cast(ParentFunclet->Inputs.front()); // OK, the inlining site is legal. What about the target function? @@ -1116,7 +1111,7 @@ // Ok, the call site is within a cleanuppad. Let's check the callee // for catchpads. for (const BasicBlock &CalledBB : *CalledFunc) { - if (isa(CalledBB.getFirstNonPHI())) + if (isa(CalledBB.getFirstNonPHI())) return false; } } @@ -1195,11 +1190,9 @@ HandleByValArgumentInit(Init.first, Init.second, Caller->getParent(), &*FirstNewBlock, IFI); - if (CS.hasOperandBundles()) { - auto ParentDeopt = CS.getOperandBundleAt(0); - assert(ParentDeopt.getTagID() == LLVMContext::OB_deopt && - "Checked on entry!"); - + Optional ParentDeopt = + CS.getOperandBundle(LLVMContext::OB_deopt); + if (ParentDeopt) { SmallVector OpDefs; for (auto &VH : InlinedFunctionInfo.OperandBundleCallSites) { @@ -1225,12 +1218,12 @@ // Prepend the parent's deoptimization continuation to the newly // inlined call's deoptimization continuation. std::vector MergedDeoptArgs; - MergedDeoptArgs.reserve(ParentDeopt.Inputs.size() + + MergedDeoptArgs.reserve(ParentDeopt->Inputs.size() + ChildOB.Inputs.size()); MergedDeoptArgs.insert(MergedDeoptArgs.end(), - ParentDeopt.Inputs.begin(), - ParentDeopt.Inputs.end()); + ParentDeopt->Inputs.begin(), + ParentDeopt->Inputs.end()); MergedDeoptArgs.insert(MergedDeoptArgs.end(), ChildOB.Inputs.begin(), ChildOB.Inputs.end()); @@ -1425,10 +1418,46 @@ // Update the lexical scopes of the new funclets. Anything that had 'none' as // its parent is now nested inside the callsite's EHPad. + if (CallSiteEHPad) { for (Function::iterator BB = FirstNewBlock->getIterator(), E = Caller->end(); BB != E; ++BB) { + // Add bundle operands to any top-level call sites. + SmallVector OpBundles; + for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E;) { + Instruction *I = &*BBI++; + CallSite CS(I); + if (!CS) + continue; + + // Skip call sites which are nounwind intrinsics. + auto *CalledFn = + dyn_cast(CS.getCalledValue()->stripPointerCasts()); + if (CalledFn && CalledFn->isIntrinsic() && CS.doesNotThrow()) + continue; + + // Skip call sites which already have a "funclet" bundle. + if (CS.getOperandBundle(LLVMContext::OB_funclet)) + continue; + + CS.getOperandBundlesAsDefs(OpBundles); + ArrayRef Inputs = CallSiteEHPad; + OpBundles.emplace_back("funclet", Inputs); + + Instruction *NewInst; + if (CS.isCall()) { + NewInst = CallInst::Create(cast(I), OpBundles, I); + } else { + NewInst = InvokeInst::Create(cast(I), OpBundles, I); + } + NewInst->takeName(I); + I->replaceAllUsesWith(NewInst); + I->eraseFromParent(); + + OpBundles.clear(); + } + Instruction *I = BB->getFirstNonPHI(); if (!I->isEHPad()) continue; Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1180,9 +1180,7 @@ Deref, Offset); } -/// changeToUnreachable - Insert an unreachable instruction before the specified -/// instruction, making it and the rest of the code in the block dead. -static void changeToUnreachable(Instruction *I, bool UseLLVMTrap) { +void llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap) { BasicBlock *BB = I->getParent(); // Loop over all of the successors, removing BB's entry from any PHI // nodes. Index: test/CodeGen/WinEH/wineh-cloning.ll =================================================================== --- test/CodeGen/WinEH/wineh-cloning.ll +++ test/CodeGen/WinEH/wineh-cloning.ll @@ -200,7 +200,7 @@ outer: %o = cleanuppad within none [] %x = call i32 @g() - invoke void @f() + invoke void @f() [ "funclet"(token %o) ] to label %outer.ret unwind label %catch.switch catch.switch: %cs = catchswitch within %o [label %inner] unwind to caller @@ -231,53 +231,6 @@ ; CHECK-NEXT: br label %outer.ret -define void @test6() personality i32 (...)* @__C_specific_handler { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - cleanuppad within none [] - br label %shared -right: - %cs = catchswitch within none [label %right.catch] unwind to caller -right.catch: - catchpad within %cs [] - br label %shared -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - %i = cleanuppad within none [] - call void @h(i32 %x) - cleanupret from %i unwind to caller -exit: - ret void -} -; CHECK-LABEL: define void @test6( -; CHECK: left: -; CHECK: %x.for.left = call i32 @g() -; CHECK: invoke void @f() -; CHECK: to label %shared.cont.for.left unwind label %inner -; CHECK: right.catch: -; CHECK: catchpad -; CHECK: %x = call i32 @g() -; CHECK: to label %shared.cont unwind label %inner -; CHECK: shared.cont: -; CHECK: unreachable -; CHECK: shared.cont.for.left: -; CHECK: unreachable -; CHECK: inner: -; CHECK: %i = cleanuppad within none [] -; CHECK: call void @h(i32 %x1.wineh.reload) -; CHECK: cleanupret from %i unwind to caller - - define void @test9() personality i32 (...)* @__C_specific_handler { entry: invoke void @f() @@ -286,14 +239,14 @@ invoke void @f() to label %unreachable unwind label %right left: - cleanuppad within none [] + %cp.left = cleanuppad within none [] call void @h(i32 1) - invoke void @f() + invoke void @f() [ "funclet"(token %cp.left) ] to label %unreachable unwind label %right right: - cleanuppad within none [] + %cp.right = cleanuppad within none [] call void @h(i32 2) - invoke void @f() + invoke void @f() [ "funclet"(token %cp.right) ] to label %unreachable unwind label %left unreachable: unreachable @@ -361,7 +314,7 @@ to label %exit unwind label %cleanup.outer cleanup.outer: %outer = cleanuppad within none [] - invoke void @f() + invoke void @f() [ "funclet"(token %outer) ] to label %outer.cont unwind label %cleanup.inner outer.cont: br label %merge Index: test/CodeGen/WinEH/wineh-demotion.ll =================================================================== --- test/CodeGen/WinEH/wineh-demotion.ll +++ test/CodeGen/WinEH/wineh-demotion.ll @@ -84,7 +84,7 @@ %z = call i32 @g() ; CHECK: store i32 %z ; CHECK-NEXT: invoke void @f - invoke void @f() + invoke void @f() [ "funclet"(token %cpinner) ] to label %catchret.inner unwind label %merge.outer catchret.inner: Index: test/CodeGen/WinEH/wineh-no-demotion.ll =================================================================== --- test/CodeGen/WinEH/wineh-no-demotion.ll +++ test/CodeGen/WinEH/wineh-no-demotion.ll @@ -1,4 +1,4 @@ -; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare -disable-demotion < %s | FileCheck %s +; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare -disable-demotion -disable-cleanups < %s | FileCheck %s declare i32 @__CxxFrameHandler3(...) @@ -11,22 +11,21 @@ declare void @h(i32) ; CHECK-LABEL: @test1( -define void @test1() personality i32 (...)* @__C_specific_handler { +define void @test1(i1 %bool) personality i32 (...)* @__C_specific_handler { entry: invoke void @f() - to label %invoke.cont1 unwind label %left - -invoke.cont1: - invoke void @f() - to label %invoke.cont2 unwind label %right + to label %invoke.cont unwind label %left -invoke.cont2: +invoke.cont: invoke void @f() to label %exit unwind label %inner left: %0 = cleanuppad within none [] - br label %shared + br i1 %bool, label %shared, label %cleanupret + +cleanupret: + cleanupret from %0 unwind label %right right: %1 = cleanuppad within none [] @@ -34,19 +33,19 @@ shared: %x = call i32 @g() - invoke void @f() + invoke void @f() [ "funclet"(token %0) ] to label %shared.cont unwind label %inner shared.cont: unreachable inner: - %phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont2 ] + %phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont ] %i = cleanuppad within none [] call void @h(i32 %phi) unreachable -; CHECK: %phi = phi i32 [ %x, %right ], [ 0, %invoke.cont2 ], [ %x.for.left, %left ] +; CHECK: %phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont ], [ %x.for.left, %shared.for.left ] ; CHECK: %i = cleanuppad within none [] ; CHECK: call void @h(i32 %phi) @@ -55,26 +54,25 @@ } ; CHECK-LABEL: @test2( -define void @test2() personality i32 (...)* @__C_specific_handler { +define void @test2(i1 %bool) personality i32 (...)* @__C_specific_handler { entry: invoke void @f() - to label %invoke.cont unwind label %left - -invoke.cont: - invoke void @f() - to label %exit unwind label %right + to label %shared.cont unwind label %left left: - cleanuppad within none [] - br label %shared + %0 = cleanuppad within none [] + br i1 %bool, label %shared, label %cleanupret + +cleanupret: + cleanupret from %0 unwind label %right right: - cleanuppad within none [] + %1 = cleanuppad within none [] br label %shared shared: %x = call i32 @g() - invoke void @f() + invoke void @f() [ "funclet"(token %0) ] to label %shared.cont unwind label %inner shared.cont: @@ -85,9 +83,9 @@ call void @h(i32 %x) unreachable -; CHECK: %x1 = phi i32 [ %x.for.left, %left ], [ %x, %right ] -; CHECK: %i = cleanuppad within none [] -; CHECK: call void @h(i32 %x1) +; CHECK: %x1 = phi i32 [ %x.for.left, %shared.for.left ], [ %x, %shared ] +; CHECK: %i = cleanuppad within none [] +; CHECK: call void @h(i32 %x1) exit: unreachable @@ -119,13 +117,12 @@ call void @h(i32 %phi) unreachable -; CHECK: %0 = cleanuppad within none [] -; CHECK: call void @h(i32 1) - -; CHECK: %1 = cleanuppad within none [] ; CHECK: %phi = phi i32 [ 0, %right ], [ -1, %right.other ] ; CHECK: call void @h(i32 %phi) +; CHECK: %phi.for.left = phi i32 [ 1, %left ] +; CHECK: call void @h(i32 %phi.for.left) + exit: unreachable } Index: test/CodeGen/X86/funclet-layout.ll =================================================================== --- test/CodeGen/X86/funclet-layout.ll +++ test/CodeGen/X86/funclet-layout.ll @@ -59,7 +59,7 @@ catch: ; preds = %catch.dispatch %0 = catchpad within %cs1 [i8* null, i32 64, i8* null] - invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1 + invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1 ["funclet"(token %0)] to label %unreachable unwind label %catch.dispatch.1 catch.dispatch.1: ; preds = %catch Index: test/CodeGen/X86/seh-catchpad.ll =================================================================== --- test/CodeGen/X86/seh-catchpad.ll +++ test/CodeGen/X86/seh-catchpad.ll @@ -69,7 +69,7 @@ ehcleanup: ; preds = %__except.2 %cp2 = cleanuppad within none [] - invoke fastcc void @"\01?fin$0@0@main@@"() #4 + invoke fastcc void @"\01?fin$0@0@main@@"() #4 [ "funclet"(token %cp2) ] to label %invoke.cont.6 unwind label %catch.dispatch.7 invoke.cont.6: ; preds = %ehcleanup Index: test/CodeGen/X86/seh-except-finally.ll =================================================================== --- test/CodeGen/X86/seh-except-finally.ll +++ test/CodeGen/X86/seh-except-finally.ll @@ -51,7 +51,7 @@ __finally: ; preds = %entry %cleanuppad = cleanuppad within none [] %locals = call i8* @llvm.localaddress() - invoke void @"\01?fin$0@0@use_both@@"(i1 zeroext true, i8* %locals) #5 + invoke void @"\01?fin$0@0@use_both@@"(i1 zeroext true, i8* %locals) #5 [ "funclet"(token %cleanuppad) ] to label %invoke.cont3 unwind label %catch.dispatch invoke.cont3: ; preds = %__finally Index: test/CodeGen/X86/win-catchpad-nested-cxx.ll =================================================================== --- test/CodeGen/X86/win-catchpad-nested-cxx.ll +++ test/CodeGen/X86/win-catchpad-nested-cxx.ll @@ -31,7 +31,7 @@ %cs1 = catchswitch within none [label %handler1] unwind to caller handler1: %h1 = catchpad within %cs1 [i8* null, i32 64, i8* null] - invoke void @f(i32 2) + invoke void @f(i32 2) [ "funclet"(token %h1) ] to label %catchret1 unwind label %catch.dispatch.2 catchret1: catchret from %h1 to label %try.cont Index: test/CodeGen/X86/win-catchpad-nested.ll =================================================================== --- test/CodeGen/X86/win-catchpad-nested.ll +++ test/CodeGen/X86/win-catchpad-nested.ll @@ -16,7 +16,7 @@ outer.catch: %cp1 = catchpad within %cs1 [i32 1] - invoke void @f() + invoke void @f() [ "funclet"(token %cp1) ] to label %outer.ret unwind label %catch.dispatch.2 outer.ret: catchret from %cp1 to label %exit Index: test/CodeGen/X86/win32-eh-states.ll =================================================================== --- test/CodeGen/X86/win32-eh-states.ll +++ test/CodeGen/X86/win32-eh-states.ll @@ -48,7 +48,7 @@ catch: ; preds = %lpad.1 %p1 = catchpad within %cs1 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null] - invoke void @may_throw(i32 3) + invoke void @may_throw(i32 3) [ "funclet"(token %p1) ] to label %invoke.cont.3 unwind label %lpad.1 invoke.cont.3: ; preds = %catch @@ -131,19 +131,19 @@ catch: ; preds = %catch.dispatch %1 = catchpad within %0 [i8* null, i32 64, i8* null] - invoke void @may_throw(i32 0) + invoke void @may_throw(i32 0) [ "funclet"(token %1) ] to label %invoke.cont unwind label %ehcleanup5 invoke.cont: ; preds = %catch - invoke void @may_throw(i32 1) + invoke void @may_throw(i32 1) [ "funclet"(token %1) ] to label %invoke.cont2 unwind label %ehcleanup invoke.cont2: ; preds = %invoke.cont - invoke void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %y) + invoke void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %y) [ "funclet"(token %1) ] to label %invoke.cont3 unwind label %ehcleanup5 invoke.cont3: ; preds = %invoke.cont2 - invoke void @may_throw(i32 2) + invoke void @may_throw(i32 2) [ "funclet"(token %1) ] to label %invoke.cont4 unwind label %ehcleanup5 invoke.cont4: ; preds = %invoke.cont3 @@ -155,12 +155,12 @@ ehcleanup: ; preds = %invoke.cont %2 = cleanuppad within %1 [] - call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %y) + call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %y) [ "funclet"(token %2) ] cleanupret from %2 unwind label %ehcleanup5 ehcleanup5: ; preds = %invoke.cont2, %invoke.cont3, %ehcleanup, %catch, %catch.dispatch %3 = cleanuppad within none [] - call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %x) + call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %x) [ "funclet"(token %3) ] cleanupret from %3 unwind to caller unreachable: ; preds = %entry Index: test/CodeGen/X86/win32-seh-nested-finally.ll =================================================================== --- test/CodeGen/X86/win32-seh-nested-finally.ll +++ test/CodeGen/X86/win32-seh-nested-finally.ll @@ -18,7 +18,7 @@ ehcleanup: ; preds = %entry %0 = cleanuppad within none [] - invoke void @f(i32 2) #3 + invoke void @f(i32 2) #3 [ "funclet"(token %0) ] to label %invoke.cont.2 unwind label %ehcleanup.3 invoke.cont.2: ; preds = %ehcleanup Index: test/CodeGen/X86/wineh-coreclr.ll =================================================================== --- test/CodeGen/X86/wineh-coreclr.ll +++ test/CodeGen/X86/wineh-coreclr.ll @@ -70,7 +70,7 @@ ; CHECK-NEXT: movl $3, %ecx ; CHECK-NEXT: callq f ; CHECK-NEXT: [[L_after_f3:.+]]: - invoke void @f(i32 3) + invoke void @f(i32 3) [ "funclet"(token %catch1) ] to label %catch1.ret unwind label %finally.pad catch1.ret: catchret from %catch1 to label %finally.clone @@ -93,7 +93,7 @@ ; CHECK-NEXT: movl $4, %ecx ; CHECK-NEXT: callq f ; CHECK-NEXT: [[L_after_f4:.+]]: - invoke void @f(i32 4) + invoke void @f(i32 4) [ "funclet"(token %catch2) ] to label %try_in_catch unwind label %finally.pad try_in_catch: ; CHECK: # %try_in_catch @@ -101,7 +101,7 @@ ; CHECK-NEXT: movl $5, %ecx ; CHECK-NEXT: callq f ; CHECK-NEXT: [[L_after_f5:.+]]: - invoke void @f(i32 5) + invoke void @f(i32 5) [ "funclet"(token %catch2) ] to label %catch2.ret unwind label %fault.pad fault.pad: ; CHECK: .seh_proc [[L_fault:[^ ]+]] @@ -117,7 +117,7 @@ ; CHECK-NEXT: movl $6, %ecx ; CHECK-NEXT: callq f ; CHECK-NEXT: [[L_after_f6:.+]]: - invoke void @f(i32 6) + invoke void @f(i32 6) [ "funclet"(token %fault) ] to label %fault.ret unwind label %finally.pad fault.ret: cleanupret from %fault unwind label %finally.pad