Index: lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1003,6 +1003,19 @@ result.PointerToBase = PointerToBase; } +// noreturn call can never return normally so it does not need +// a GC safepoint. Therefore, don't waste time on doing liveness +// analysis for it. +static bool isNoReturnCall(const CallSite &CS) { + // Be conservative on invokes + if (CS.isInvoke()) { return false; } + // Explicitly marked as noreturn + if (CS.hasFnAttr(Attribute::NoReturn)) { return true; } + // Effectively noreturn if the next instruction is unreachable + return CS.getInstruction()->getNextNode() && + isa(CS.getInstruction()->getNextNode()); +} + /// Given an updated version of the dataflow liveness results, update the /// liveset and base pointer maps for the call site CS. static void recomputeLiveInValues(GCPtrLivenessData &RevisedLivenessData, @@ -1019,7 +1032,9 @@ for (size_t i = 0; i < records.size(); i++) { struct PartiallyConstructedSafepointRecord &info = records[i]; const CallSite &CS = toUpdate[i]; - recomputeLiveInValues(RevisedLivenessData, CS, info); + if (!isNoReturnCall(CS)) { + recomputeLiveInValues(RevisedLivenessData, CS, info); + } } } @@ -1681,7 +1696,9 @@ for (size_t i = 0; i < records.size(); i++) { struct PartiallyConstructedSafepointRecord &info = records[i]; const CallSite &CS = toUpdate[i]; - analyzeParsePointLiveness(DT, OriginalLivenessData, CS, info); + if (!isNoReturnCall(CS)) { + analyzeParsePointLiveness(DT, OriginalLivenessData, CS, info); + } } } Index: test/Transforms/RewriteStatepointsForGC/noreturn-calls.ll =================================================================== --- /dev/null +++ test/Transforms/RewriteStatepointsForGC/noreturn-calls.ll @@ -0,0 +1,31 @@ +; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-liveset -S 2>&1 | FileCheck %s + +; We're testing to make sure noreturn call does not need liveness analysis and thus +; there's no live varibales for them + +; CHECK-NOT: Live Variables: + + +%jObject = type { [8 x i8] } + +declare void @some_call(%jObject addrspace(1)*) + +; Function Attrs: noreturn nounwind +define void @"test"(%jObject addrspace(1)* %arg, i1 %cond) #0 gc "statepoint-example" { +bci_0: + br i1 %cond, label %branch1, label %branch2 + +branch1: +; effectively noreturn call because it's unreachable after call + %safepoint_token0 = tail call i32 (i64, i32, void (%jObject addrspace(1)*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidp1jObjectf(i64 0, i32 0, void (%jObject addrspace(1)*)* @some_call, i32 1, i32 0, %jObject addrspace(1)* %arg, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0, i32 0) + unreachable + +branch2: +; explicitly marked as noreturn + %safepoint_token1 = tail call i32 (i64, i32, void (%jObject addrspace(1)*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidp1jObjectf(i64 0, i32 0, void (%jObject addrspace(1)*)* @some_call, i32 1, i32 0, %jObject addrspace(1)* %arg, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0, i32 0) noreturn + ret void +} + +declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidp1jObjectf(i64, i32, void (%jObject addrspace(1)*)*, i32, i32, ...) + +attributes #0 = { noreturn nounwind "gc-add-backedge-safepoints"="true" "gc-add-call-safepoints"="true" "gc-add-entry-safepoints"="true" }