diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -6652,6 +6652,15 @@ /// merged. In some cases, this could result in removal of the PHI entirely. static bool TryToMergeLandingPad(LandingPadInst *LPad, BranchInst *BI, BasicBlock *BB, DomTreeUpdater *DTU) { + + // Invokes with deopt bundles must have unique landingpads + // (See RewriteStatepointsForGC.cpp). Prohibit landingpad merging + // for such invokes. + BasicBlock *Pred = *pred_begin(BB); + if (auto *Invoke = dyn_cast(Pred->getTerminator())) + if (Invoke->getOperandBundle(LLVMContext::OB_deopt)) + return false; + auto Succ = BB->getUniqueSuccessor(); assert(Succ); // If there's a phi in the successor block, we'd likely have to introduce diff --git a/llvm/test/Transforms/SimplifyCFG/duplicate-landingpad.ll b/llvm/test/Transforms/SimplifyCFG/duplicate-landingpad.ll --- a/llvm/test/Transforms/SimplifyCFG/duplicate-landingpad.ll +++ b/llvm/test/Transforms/SimplifyCFG/duplicate-landingpad.ll @@ -147,3 +147,52 @@ call void @fn() ret void } + +; Should not trigger when invokes have deopt bundles +; CHECK-LABEL: @neg3( +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @fn() +; CHECK-NEXT: to label [[INVOKE2:%.*]] unwind label [[LPAD1:%.*]] +; CHECK: invoke2: +; CHECK-NEXT: invoke void @fn() +; CHECK-NEXT: to label [[COMMON_RET:%.*]] unwind label [[LPAD2:%.*]] +; CHECK: common.ret: +; CHECK-NEXT: ret void +; CHECK: lpad1: +; CHECK-NEXT: [[EXN:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: cleanup +; CHECK-NEXT: br label [[SHARED_RESUME:%.*]] +; CHECK: lpad2: +; CHECK-NEXT: [[EXN2:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: cleanup +; CHECK-NEXT: br label [[SHARED_RESUME]] +; CHECK: shared_resume: +; CHECK-NEXT: call void @fn() +; CHECK-NEXT: br label [[COMMON_RET]] +; +define void @neg3() gc "statepoint-example" personality i32 (...)* @__gxx_personality_v0 { +entry: + invoke void @fn() [ "deopt"() ] + to label %invoke2 unwind label %lpad1 + +invoke2: + invoke void @fn() [ "deopt"() ] + to label %invoke.cont unwind label %lpad2 + +invoke.cont: + ret void + +lpad1: + %exn = landingpad {i8*, i32} + cleanup + br label %shared_resume + +lpad2: + %exn2 = landingpad {i8*, i32} + cleanup + br label %shared_resume + +shared_resume: + call void @fn() + ret void +}