[llvm] r265485 - [RS4GC] Better codegen for deoptimize calls

Sanjoy Das via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 5 16:18:36 PDT 2016


Author: sanjoy
Date: Tue Apr  5 18:18:35 2016
New Revision: 265485

URL: http://llvm.org/viewvc/llvm-project?rev=265485&view=rev
Log:
[RS4GC] Better codegen for deoptimize calls

Don't emit a gc.result for a statepoint lowered from
@llvm.experimental.deoptimize since the call into __llvm_deoptimize is
effectively noreturn.  Instead follow the corresponding gc.statepoint
with an "unreachable".

Modified:
    llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
    llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll

Modified: llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp?rev=265485&r1=265484&r2=265485&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp Tue Apr  5 18:18:35 2016
@@ -1278,6 +1278,9 @@ namespace {
 class DeferredReplacement {
   AssertingVH<Instruction> Old;
   AssertingVH<Instruction> New;
+  bool IsDeoptimize = false;
+
+  DeferredReplacement() {}
 
 public:
   explicit DeferredReplacement(Instruction *Old, Instruction *New) :
@@ -1285,18 +1288,40 @@ public:
     assert(Old != New && "Not allowed!");
   }
 
+  static DeferredReplacement createDeoptimizeReplacement(Instruction *Old) {
+#ifndef NDEBUG
+    auto *F = cast<CallInst>(Old)->getCalledFunction();
+    assert(F && F->getIntrinsicID() == Intrinsic::experimental_deoptimize &&
+           "Only way to construct a deoptimize deferred replacement");
+#endif
+    DeferredReplacement D;
+    D.Old = Old;
+    D.IsDeoptimize = true;
+    return D;
+  }
+
   /// Does the task represented by this instance.
   void doReplacement() {
     Instruction *OldI = Old;
     Instruction *NewI = New;
 
     assert(OldI != NewI && "Disallowed at construction?!");
+    assert(!IsDeoptimize || !New && "Deoptimize instrinsics are not replaced!");
 
     Old = nullptr;
     New = nullptr;
 
     if (NewI)
       OldI->replaceAllUsesWith(NewI);
+
+    if (IsDeoptimize) {
+      // Note: we've inserted instructions, so the call to llvm.deoptimize may
+      // not necessarilly be followed by the matching return.
+      auto *RI = cast<ReturnInst>(OldI->getParent()->getTerminator());
+      new UnreachableInst(RI->getContext(), RI);
+      RI->eraseFromParent();
+    }
+
     OldI->eraseFromParent();
   }
 };
@@ -1330,6 +1355,7 @@ makeStatepointExplicitImpl(const CallSit
     Flags |= uint32_t(StatepointFlags::GCTransition);
     TransitionArgs = TransitionBundle->Inputs;
   }
+  bool IsDeoptimize = false;
 
   StatepointDirectives SD =
       parseStatepointDirectivesFromAttrs(CS.getAttributes());
@@ -1348,7 +1374,7 @@ makeStatepointExplicitImpl(const CallSit
       SmallVector<Type *, 8> DomainTy;
       for (Value *Arg : CallArgs)
         DomainTy.push_back(Arg->getType());
-      auto *FTy = FunctionType::get(F->getReturnType(), DomainTy,
+      auto *FTy = FunctionType::get(Type::getVoidTy(F->getContext()), DomainTy,
                                     /* isVarArg = */ false);
 
       // Note: CallTarget can be a bitcast instruction of a symbol if there are
@@ -1357,6 +1383,8 @@ makeStatepointExplicitImpl(const CallSit
       // was doing when generating this kind of IR.
       CallTarget =
           F->getParent()->getOrInsertFunction("__llvm_deoptimize", FTy);
+
+      IsDeoptimize = true;
     }
   }
 
@@ -1440,22 +1468,30 @@ makeStatepointExplicitImpl(const CallSit
   }
   assert(Token && "Should be set in one of the above branches!");
 
-  Token->setName("statepoint_token");
-  if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) {
-    StringRef Name =
-      CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : "";
-    CallInst *GCResult = Builder.CreateGCResult(Token, CS.getType(), Name);
-    GCResult->setAttributes(CS.getAttributes().getRetAttributes());
-
-    // We cannot RAUW or delete CS.getInstruction() because it could be in the
-    // live set of some other safepoint, in which case that safepoint's
-    // PartiallyConstructedSafepointRecord will hold a raw pointer to this
-    // llvm::Instruction.  Instead, we defer the replacement and deletion to
-    // after the live sets have been made explicit in the IR, and we no longer
-    // have raw pointers to worry about.
-    Replacements.emplace_back(CS.getInstruction(), GCResult);
+  if (IsDeoptimize) {
+    // If we're wrapping an @llvm.experimental.deoptimize in a statepoint, we
+    // transform the tail-call like structure to a call to a void function
+    // followed by unreachable to get better codegen.
+    Replacements.push_back(
+        DeferredReplacement::createDeoptimizeReplacement(CS.getInstruction()));
   } else {
-    Replacements.emplace_back(CS.getInstruction(), nullptr);
+    Token->setName("statepoint_token");
+    if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) {
+      StringRef Name =
+          CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : "";
+      CallInst *GCResult = Builder.CreateGCResult(Token, CS.getType(), Name);
+      GCResult->setAttributes(CS.getAttributes().getRetAttributes());
+
+      // We cannot RAUW or delete CS.getInstruction() because it could be in the
+      // live set of some other safepoint, in which case that safepoint's
+      // PartiallyConstructedSafepointRecord will hold a raw pointer to this
+      // llvm::Instruction.  Instead, we defer the replacement and deletion to
+      // after the live sets have been made explicit in the IR, and we no longer
+      // have raw pointers to worry about.
+      Replacements.emplace_back(CS.getInstruction(), GCResult);
+    } else {
+      Replacements.emplace_back(CS.getInstruction(), nullptr);
+    }
   }
 
   Result.StatepointToken = Token;

Modified: llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll?rev=265485&r1=265484&r2=265485&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll (original)
+++ llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll Tue Apr  5 18:18:35 2016
@@ -4,10 +4,12 @@ target datalayout = "e-m:o-i64:64-f80:12
 target triple = "x86_64-apple-macosx10.11.0"
 
 declare i32 @llvm.experimental.deoptimize.i32(...)
+declare void @llvm.experimental.deoptimize.isVoid(...)
 
 define i32 @caller_0(i32 addrspace(1)* %ptr) gc "statepoint-example" {
 ; CHECK-LABEL: @caller_0(
-; CHECK: @llvm.experimental.gc.statepoint.p0f_i32f(i64 2882400000, i32 0, i32 ()* @__llvm_deoptimize, i32 0
+; CHECK: @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @__llvm_deoptimize, i32 0
+; CHECK: unreachable
 entry:
   %v = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 0, i32 addrspace(1)* %ptr) ]
   ret i32 %v
@@ -16,8 +18,18 @@ entry:
 
 define i32 @caller_1(i32 addrspace(1)* %ptr) gc "statepoint-example" {
 ; CHECK-LABEL: @caller_1
-; CHECK: @llvm.experimental.gc.statepoint.p0f_i32i32p1i32f(i64 2882400000, i32 0, i32 (i32, i32 addrspace(1)*)* bitcast (i32 ()* @__llvm_deoptimize to i32 (i32, i32 addrspace(1)*)*), i32 2, i32 0, i32 50, i32 addrspace(1)* %ptr
+; CHECK: @llvm.experimental.gc.statepoint.p0f_isVoidi32p1i32f(i64 2882400000, i32 0, void (i32, i32 addrspace(1)*)* bitcast (void ()* @__llvm_deoptimize to void (i32, i32 addrspace(1)*)*), i32 2, i32 0, i32 50, i32 addrspace(1)* %ptr
+; CHECK: unreachable
 entry:
   %v = call i32(...) @llvm.experimental.deoptimize.i32(i32 50, i32 addrspace(1)* %ptr) [ "deopt"(i32 0) ]
   ret i32 %v
 }
+
+define void @caller_2(i32 addrspace(1)* %ptr) gc "statepoint-example" {
+; CHECK-LABEL: @caller_2(
+; CHECK: @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @__llvm_deoptimize, i32 0
+; CHECK: unreachable
+entry:
+  call void(...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 0, i32 addrspace(1)* %ptr) ]
+  ret void
+}




More information about the llvm-commits mailing list