Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -597,6 +597,11 @@ for (auto &Funclets : FuncletBlocks) { BasicBlock *FuncletPadBB = Funclets.first; std::vector &BlocksInFunclet = Funclets.second; + Value *FuncletToken; + if (FuncletPadBB == &F.getEntryBlock()) + FuncletToken = ConstantTokenNone::get(F.getContext()); + else + FuncletToken = FuncletPadBB->getFirstNonPHI(); std::vector> Orig2Clone; ValueToValueMapTy VMap; @@ -668,14 +673,43 @@ RemapInstruction(&I, VMap, RF_IgnoreMissingEntries | RF_NoModuleLevelChanges); + // Catchrets targeting cloned blocks need to be updated separately from + // the loop above because they are not in the current funclet. + SmallVector FixupCatchrets; + for (auto &BBMapping : Orig2Clone) { + BasicBlock *OldBlock = BBMapping.first; + BasicBlock *NewBlock = BBMapping.second; + + FixupCatchrets.clear(); + for (BasicBlock *Pred : predecessors(OldBlock)) + if (auto *CatchRet = dyn_cast(Pred->getTerminator())) + if (CatchRet->getParentPad() == FuncletToken) + FixupCatchrets.push_back(CatchRet); + + for (CatchReturnInst *CatchRet : FixupCatchrets) + CatchRet->setSuccessor(NewBlock); + } + auto UpdatePHIOnClonedBlock = [&](PHINode *PN, bool IsForOldBlock) { unsigned NumPreds = PN->getNumIncomingValues(); for (unsigned PredIdx = 0, PredEnd = NumPreds; PredIdx != PredEnd; ++PredIdx) { BasicBlock *IncomingBlock = PN->getIncomingBlock(PredIdx); - ColorVector &IncomingColors = BlockColors[IncomingBlock]; - bool BlockInFunclet = IncomingColors.size() == 1 && - IncomingColors.front() == FuncletPadBB; + bool BlockInFunclet; + if (auto *CRI = + dyn_cast(IncomingBlock->getTerminator())) { + BlockInFunclet = (CRI->getParentPad() == FuncletToken); + } else { + ColorVector &IncomingColors = BlockColors[IncomingBlock]; + assert(IncomingColors.size() && "Block not colored!"); + assert((IncomingColors.size() == 1 || + llvm::all_of(IncomingColors, + [&](BasicBlock *Color) { + return Color != FuncletPadBB; + })) && + "Cloning should leave this funclet's blocks monochromatic"); + BlockInFunclet = (IncomingColors.front() == FuncletPadBB); + } if (IsForOldBlock != BlockInFunclet) continue; PN->removeIncomingValue(IncomingBlock, /*DeletePHIIfEmpty=*/false); Index: test/CodeGen/WinEH/wineh-cloning.ll =================================================================== --- test/CodeGen/WinEH/wineh-cloning.ll +++ test/CodeGen/WinEH/wineh-cloning.ll @@ -2,6 +2,7 @@ declare i32 @__CxxFrameHandler3(...) declare i32 @__C_specific_handler(...) +declare void @ProcessCLRException(...) declare void @f() @@ -369,6 +370,50 @@ unreachable } +define void @test14() personality void (...)* @ProcessCLRException { +entry: + invoke void @f() + to label %cont unwind label %cleanup +cont: + invoke void @f() + to label %exit unwind label %switch.outer +cleanup: + %cleanpad = cleanuppad within none [] + invoke void @f() [ "funclet" (token %cleanpad) ] + to label %cleanret unwind label %switch.inner +switch.inner: + %cs.inner = catchswitch within %cleanpad [label %pad.inner] unwind to caller +pad.inner: + %cp.inner = catchpad within %cs.inner [i32 1] + catchret from %cp.inner to label %join +cleanret: + cleanupret from %cleanpad unwind to caller +switch.outer: + %cs.outer = catchswitch within none [label %pad.outer] unwind to caller +pad.outer: + %cp.outer = catchpad within %cs.outer [i32 2] + catchret from %cp.outer to label %join +join: + %phi = phi i32 [ 1, %pad.inner ], [ 2, %pad.outer ] + call void @llvm.foo(i32 %phi) + unreachable +exit: + ret void +} +; Both catchrets target %join, but the catchret from %cp.inner +; returns to %cleanpad and the catchret from %cp.outer returns to the +; main function, so %join needs to get cloned and one of the cleanuprets +; needs to be updated to target the clone +; CHECK-LABEL: define void @test14() +; CHECK: catchret from %cp.inner to label %[[Clone1:.+]] +; CHECK: catchret from %cp.outer to label %[[Clone2:.+]] +; CHECK: [[Clone1]]: +; CHECK-NEXT: call void @llvm.foo(i32 1) +; CHECK-NEXT: unreachable +; CHECK: [[Clone2]]: +; CHECK-NEXT: call void @llvm.foo(i32 2) +; CHECK-NEXT: unreachable + ;; Debug info (from test12) ; Make sure the DISubprogram doesn't get cloned