[llvm] 0480927 - [Statepoint Lowering] Handle the case with several gc.result

Serguei Katkov via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 11 03:53:03 PST 2021


Author: Serguei Katkov
Date: 2021-03-11T18:44:44+07:00
New Revision: 0480927712e41a5ba3b1a98d4bd150f1a4d6ab75

URL: https://github.com/llvm/llvm-project/commit/0480927712e41a5ba3b1a98d4bd150f1a4d6ab75
DIFF: https://github.com/llvm/llvm-project/commit/0480927712e41a5ba3b1a98d4bd150f1a4d6ab75.diff

LOG: [Statepoint Lowering] Handle the case with several gc.result

Recently gc.result has been marked with readnone instead of readonly and
this opens a door for different optimization to duplicate gc.result.
Statepoint lowering is not ready to see several gc.results.
The problem appears when there are gc.results with one located in the same
basic block and another located in other basic block.
In this case we need both export VR and fill local setValue.

Note that this case is not sufficient optimization done before CodeGen.
It is evident that local gc.result dominates all other gc.results and it is handled
by GVN and EarlyCSE.

But anyway, even if IR is not optimal Backend should not crash on a valid IR.

Reviewers: reames, dantrushin
Reviewed By: dantrushin
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D98393

Added: 
    llvm/test/CodeGen/X86/statepoint-two-results.ll

Modified: 
    llvm/include/llvm/IR/Statepoint.h
    llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/Statepoint.h b/llvm/include/llvm/IR/Statepoint.h
index 6ce15839df46..7b287fd1d7ea 100644
--- a/llvm/include/llvm/IR/Statepoint.h
+++ b/llvm/include/llvm/IR/Statepoint.h
@@ -203,14 +203,10 @@ class GCStatepointInst : public CallBase {
   /// path of invoke.
   inline std::vector<const GCRelocateInst *> 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<GCResultInst>(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<bool, bool> getGCResultLocality() const;
 };
 
 /// Common base class for representing values projected from a statepoint.
@@ -329,6 +325,18 @@ std::vector<const GCRelocateInst *> GCStatepointInst::getGCRelocates() const {
   return Result;
 }
 
+std::pair<bool, bool> GCStatepointInst::getGCResultLocality() const {
+  std::pair<bool, bool> Res(false, false);
+  for (auto *U : users())
+    if (auto *GRI = dyn_cast<GCResultInst>(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
index aed2ff420fd4..5f796e06fcb2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
@@ -1076,23 +1076,25 @@ SelectionDAGBuilder::LowerStatepoint(const GCStatepointInst &I,
   SDValue ReturnValue = LowerAsSTATEPOINT(SI);
 
   // Export the result value if needed
-  const GCResultInst *GCResult = I.getGCResult();
+  const std::pair<bool, bool> 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 
diff erent basic block so we need to export
   // it now.  Default exporting mechanism will not work here because statepoint
   // call has a 
diff erent 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
index 000000000000..f3aceee9046b
--- /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 at 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 }


        


More information about the llvm-commits mailing list