Index: lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -2531,16 +2531,19 @@ // Gather all the statepoints which need rewritten. Be careful to only // consider those in reachable code since we need to ask dominance queries - // when rewriting. We'll delete the unreachable ones in a moment. + // when rewriting. If unreachable found then we remove all unreachable + // blocks and recollect the statepoints again. SmallVector ParsePointNeeded; bool HasUnreachableStatepoint = false; for (Instruction &I : instructions(F)) { // TODO: only the ones with the flag set! if (NeedsRewrite(I)) { - if (DT.isReachableFromEntry(I.getParent())) - ParsePointNeeded.push_back(CallSite(&I)); - else + if (!DT.isReachableFromEntry(I.getParent())) { HasUnreachableStatepoint = true; + ParsePointNeeded.clear(); + break; + } + ParsePointNeeded.push_back(CallSite(&I)); } } @@ -2550,8 +2553,19 @@ // statepoints surviving this pass. This makes testing easier and the // resulting IR less confusing to human readers. Rather than be fancy, we // just reuse a utility function which removes the unreachable blocks. - if (HasUnreachableStatepoint) - MadeChange |= removeUnreachableBlocks(F); + if (HasUnreachableStatepoint) { + DeferredDominance DD(DT); + MadeChange |= removeUnreachableBlocks(F, nullptr, &DD); + assert(MadeChange && "changes expected"); + DD.flush(); + for (Instruction &I : instructions(F)) { + if (NeedsRewrite(I)) { + assert(DT.isReachableFromEntry(I.getParent()) && + "no unreachable blocks expected"); + ParsePointNeeded.push_back(CallSite(&I)); + } + } + } // Return early if no work to do. if (ParsePointNeeded.empty()) Index: test/Transforms/RewriteStatepointsForGC/unreachable-regression.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/unreachable-regression.ll +++ test/Transforms/RewriteStatepointsForGC/unreachable-regression.ll @@ -0,0 +1,32 @@ +; RUN: opt -S -rewrite-statepoints-for-gc < %s | FileCheck %s +; RUN: opt -S -passes=rewrite-statepoints-for-gc < %s | FileCheck %s +; +; Regression test: +; If there was found a rewritable callsite in an unreachanble block +; RewriteStatepointsForGC called removeUnreachableBlocks(). +; removeUnreachableBlocks() could remove some reachable blocks with the +; collected rewritable callsites. This made the callsites invalid and +; caused a crash. +declare void @f(i8 addrspace(1)* %obj) + +define void @test(i8 addrspace(1)* %arg) gc "statepoint-example" { +; CHECK-LABEL: test( +; CHECK-NEXT: @f + call void @f(i8 addrspace(1)* %arg) #1 + br i1 true, label %not_zero, label %zero + +not_zero: + ret void + +; This block is reachable but removed by removeUnreachableBlocks() +zero: +; CHECK-NOT: @f + call void @f(i8 addrspace(1)* %arg) #1 + ret void + +unreach: + call void @f(i8 addrspace(1)* %arg) #1 + ret void +} + +attributes #1 = { norecurse noimplicitfloat }