diff --git a/llvm/include/llvm/IR/Statepoint.h b/llvm/include/llvm/IR/Statepoint.h --- a/llvm/include/llvm/IR/Statepoint.h +++ b/llvm/include/llvm/IR/Statepoint.h @@ -203,14 +203,10 @@ /// path of invoke. inline std::vector getGCRelocates() const; - /// Get the experimental_gc_result call tied to this statepoint if there is - /// one, otherwise return nullptr. - const GCResultInst *getGCResult() const { - for (auto *U : users()) - if (auto *GRI = dyn_cast(U)) - return GRI; - return nullptr; - } + /// Returns pair of boolean flags. The first one is true is there is + /// a gc.result intrinsic in the same block as statepoint. The second flag + /// is true if there is an intrinsic outside of the block with statepoint. + inline std::pair getGCResultLocality() const; }; /// Common base class for representing values projected from a statepoint. @@ -329,6 +325,18 @@ return Result; } +std::pair GCStatepointInst::getGCResultLocality() const { + std::pair Res(false, false); + for (auto *U : users()) + if (auto *GRI = dyn_cast(U)) { + if (GRI->getParent() == this->getParent()) + Res.first = true; + else + Res.second = true; + } + return Res; +} + /// Call sites that get wrapped by a gc.statepoint (currently only in /// RewriteStatepointsForGC and potentially in other passes in the future) can /// have attributes that describe properties of gc.statepoint call they will be diff --git a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp --- a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp @@ -1076,23 +1076,25 @@ SDValue ReturnValue = LowerAsSTATEPOINT(SI); // Export the result value if needed - const GCResultInst *GCResult = I.getGCResult(); + const std::pair GCResultLocality = I.getGCResultLocality(); Type *RetTy = I.getActualReturnType(); - if (RetTy->isVoidTy() || !GCResult) { + if (RetTy->isVoidTy() || + (!GCResultLocality.first && !GCResultLocality.second)) { // The return value is not needed, just generate a poison value. setValue(&I, DAG.getIntPtrConstant(-1, getCurSDLoc())); return; } - if (GCResult->getParent() == I.getParent()) { + if (GCResultLocality.first) { // Result value will be used in a same basic block. Don't export it or // perform any explicit register copies. The gc_result will simply grab // this value. setValue(&I, ReturnValue); - return; } + if (!GCResultLocality.second) + return; // Result value will be used in a different basic block so we need to export // it now. Default exporting mechanism will not work here because statepoint // call has a different type than the actual call. It means that by default diff --git a/llvm/test/CodeGen/X86/statepoint-two-results.ll b/llvm/test/CodeGen/X86/statepoint-two-results.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/statepoint-two-results.ll @@ -0,0 +1,32 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs < %s | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" + +define void @quux() gc "statepoint-example" { +; CHECK-LABEL: quux: +; CHECK: # %bb.0: # %bb1 +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $4, %esi +; CHECK-NEXT: callq wombat@PLT +; CHECK-NEXT: .Ltmp0: +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +bb1: + %tmp = call token (i64, i32, i8 addrspace(1)* (i8 addrspace(1)*, i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_p1i8p1i8i32f(i64 2882400000, i32 0, i8 addrspace(1)* (i8 addrspace(1)*, i32)* nonnull @wombat, i32 2, i32 0, i8 addrspace(1)* undef, i32 4, i32 0, i32 0) [ "gc-live"() ] + %tmp2 = tail call i8 addrspace(1)* @llvm.experimental.gc.result.p1i8(token %tmp) + br label %bb2 + +bb2: + %tmp5 = tail call i8 addrspace(1)* @llvm.experimental.gc.result.p1i8(token %tmp) + ret void +} + +declare i8 addrspace(1)* @wombat(i8 addrspace(1)*, i32) + +; Function Attrs: nounwind readnone +declare i8 addrspace(1)* @llvm.experimental.gc.result.p1i8(token) #0 +declare token @llvm.experimental.gc.statepoint.p0f_p1i8p1i8i32f(i64, i32, i8 addrspace(1)* (i8 addrspace(1)*, i32)*, i32, i32, ...) +attributes #0 = { nounwind readnone }