[llvm] r236563 - [StatepointLowering] Don't create temporary instructions. NFCI.

Sanjoy Das sanjoy at playingwithpointers.com
Tue May 5 19:36:20 PDT 2015


Author: sanjoy
Date: Tue May  5 21:36:20 2015
New Revision: 236563

URL: http://llvm.org/viewvc/llvm-project?rev=236563&view=rev
Log:
[StatepointLowering] Don't create temporary instructions.  NFCI.

Summary:
Instead of creating a temporary call instruction and lowering that, use
SelectionDAGBuilder::lowerCallOperands.

Reviewers: reames

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D9480

Added:
    llvm/trunk/test/CodeGen/X86/statepoint-indirect-return.ll
Modified:
    llvm/trunk/include/llvm/IR/Statepoint.h
    llvm/trunk/lib/CodeGen/SelectionDAG/StatepointLowering.cpp

Modified: llvm/trunk/include/llvm/IR/Statepoint.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Statepoint.h?rev=236563&r1=236562&r2=236563&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Statepoint.h (original)
+++ llvm/trunk/include/llvm/IR/Statepoint.h Tue May  5 21:36:20 2015
@@ -72,6 +72,13 @@ class StatepointBase {
   ValueTy *actualCallee() {
     return StatepointCS.getArgument(0);
   }
+  /// Return the type of the value returned by the call underlying the
+  /// statepoint.
+  Type *actualReturnType() {
+    auto *FTy = cast<FunctionType>(
+        cast<PointerType>(actualCallee()->getType())->getElementType());
+    return FTy->getReturnType();
+  }
   /// Number of arguments to be passed to the actual callee.
   int numCallArgs() {
     return cast<ConstantInt>(StatepointCS.getArgument(1))->getZExtValue();
@@ -82,14 +89,16 @@ class StatepointBase {
     return cast<ConstantInt>(StatepointCS.getArgument(3 + numCallArgs()))->getZExtValue();
   }
 
+  int callArgsBeginOffset() { return 3; }
+
   typename CallSiteTy::arg_iterator call_args_begin() {
     // 3 = callTarget, #callArgs, flag
-    int Offset = 3;
+    int Offset = callArgsBeginOffset();
     assert(Offset <= (int)StatepointCS.arg_size());
     return StatepointCS.arg_begin() + Offset;
   }
   typename CallSiteTy::arg_iterator call_args_end() {
-    int Offset = 3 + numCallArgs();
+    int Offset = callArgsBeginOffset() + numCallArgs();
     assert(Offset <= (int)StatepointCS.arg_size());
     return StatepointCS.arg_begin() + Offset;
   }

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/StatepointLowering.cpp?rev=236563&r1=236562&r2=236563&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/StatepointLowering.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/StatepointLowering.cpp Tue May  5 21:36:20 2015
@@ -222,33 +222,61 @@ static void removeDuplicatesGCPtrs(Small
 /// Extract call from statepoint, lower it and return pointer to the
 /// call node. Also update NodeMap so that getValue(statepoint) will
 /// reference lowered call result
-static SDNode *lowerCallFromStatepoint(ImmutableStatepoint StatepointSite,
-                                       MachineBasicBlock *LandingPad,
-                                       SelectionDAGBuilder &Builder) {
-
-  ImmutableCallSite CS(StatepointSite.getCallSite());
-
-  // Lower the actual call itself - This is a bit of a hack, but we want to
-  // avoid modifying the actual lowering code.  This is similiar in intent to
-  // the LowerCallOperands mechanism used by PATCHPOINT, but is structured
-  // differently.  Hopefully, this is slightly more robust w.r.t. calling
-  // convention, return values, and other function attributes.
-  Value *ActualCallee = const_cast<Value *>(StatepointSite.actualCallee());
-
-  std::vector<Value *> Args;
-  CallInst::const_op_iterator arg_begin = StatepointSite.call_args_begin();
-  CallInst::const_op_iterator arg_end = StatepointSite.call_args_end();
-  Args.insert(Args.end(), arg_begin, arg_end);
-  // TODO: remove the creation of a new instruction!  We should not be
-  // modifying the IR (even temporarily) at this point.
-  CallInst *Tmp = CallInst::Create(ActualCallee, Args);
-  Tmp->setTailCall(CS.isTailCall());
-  Tmp->setCallingConv(CS.getCallingConv());
-  Tmp->setAttributes(CS.getAttributes());
-  Builder.LowerCallTo(Tmp, Builder.getValue(ActualCallee), false, LandingPad);
+static SDNode *
+lowerCallFromStatepoint(ImmutableStatepoint ISP, MachineBasicBlock *LandingPad,
+                        SelectionDAGBuilder &Builder,
+                        SmallVectorImpl<SDValue> &PendingExports) {
+
+  ImmutableCallSite CS(ISP.getCallSite());
+
+  SDValue ActualCallee = Builder.getValue(ISP.actualCallee());
+
+  // Handle immediate and symbolic callees.
+  if (auto *ConstCallee = dyn_cast<ConstantSDNode>(ActualCallee.getNode()))
+    ActualCallee = Builder.DAG.getIntPtrConstant(ConstCallee->getZExtValue(),
+                                                 Builder.getCurSDLoc(),
+                                                 /*isTarget=*/true);
+  else if (auto *SymbolicCallee =
+               dyn_cast<GlobalAddressSDNode>(ActualCallee.getNode()))
+    ActualCallee = Builder.DAG.getTargetGlobalAddress(
+        SymbolicCallee->getGlobal(), SDLoc(SymbolicCallee),
+        SymbolicCallee->getValueType(0));
+
+  assert(CS.getCallingConv() != CallingConv::AnyReg &&
+         "anyregcc is not supported on statepoints!");
+
+  Type *DefTy = ISP.actualReturnType();
+  bool HasDef = !DefTy->isVoidTy();
+
+  SDValue ReturnValue, CallEndVal;
+  std::tie(ReturnValue, CallEndVal) = Builder.lowerCallOperands(
+      ISP.getCallSite(), ISP.callArgsBeginOffset(), ISP.numCallArgs(),
+      ActualCallee, DefTy, LandingPad, false /* IsPatchPoint */);
+
+  SDNode *CallEnd = CallEndVal.getNode();
+
+  // Get a call instruction from the call sequence chain.  Tail calls are not
+  // allowed.  The following code is essentially reverse engineering X86's
+  // LowerCallTo.
+  //
+  // We are expecting DAG to have the following form:
+  //
+  // ch = eh_label (only in case of invoke statepoint)
+  //   ch, glue = callseq_start ch
+  //   ch, glue = X86::Call ch, glue
+  //   ch, glue = callseq_end ch, glue
+  //   get_return_value ch, glue
+  //
+  // get_return_value can either be a CopyFromReg to grab the return value from
+  // %RAX, or it can be a LOAD to load a value returned by reference via a stack
+  // slot.
+
+  if (HasDef && (CallEnd->getOpcode() == ISD::CopyFromReg ||
+                 CallEnd->getOpcode() == ISD::LOAD))
+    CallEnd = CallEnd->getOperand(0).getNode();
+
+  assert(CallEnd->getOpcode() == ISD::CALLSEQ_END && "expected!");
 
-  // Handle the return value of the call iff any.
-  const bool HasDef = !Tmp->getType()->isVoidTy();
   if (HasDef) {
     if (CS.isInvoke()) {
       // Result value will be used in different basic block for invokes
@@ -258,62 +286,29 @@ static SDNode *lowerCallFromStatepoint(I
       // register with correct type and save value into it manually.
       // TODO: To eliminate this problem we can remove gc.result intrinsics
       //       completelly and make statepoint call to return a tuple.
-      unsigned reg = Builder.FuncInfo.CreateRegs(Tmp->getType());
-      Builder.CopyValueToVirtualRegister(Tmp, reg);
-      Builder.FuncInfo.ValueMap[CS.getInstruction()] = reg;
+      unsigned Reg = Builder.FuncInfo.CreateRegs(ISP.actualReturnType());
+      RegsForValue RFV(*Builder.DAG.getContext(),
+                       Builder.DAG.getTargetLoweringInfo(), Reg,
+                       ISP.actualReturnType());
+      SDValue Chain = Builder.DAG.getEntryNode();
+
+      RFV.getCopyToRegs(ReturnValue, Builder.DAG, Builder.getCurSDLoc(), Chain,
+                        nullptr);
+      PendingExports.push_back(Chain);
+      Builder.FuncInfo.ValueMap[CS.getInstruction()] = Reg;
     } else {
       // The value of the statepoint itself will be the value of call itself.
       // We'll replace the actually call node shortly.  gc_result will grab
       // this value.
-      Builder.setValue(CS.getInstruction(), Builder.getValue(Tmp));
+      Builder.setValue(CS.getInstruction(), ReturnValue);
     }
   } else {
     // The token value is never used from here on, just generate a poison value
     Builder.setValue(CS.getInstruction(),
                      Builder.DAG.getIntPtrConstant(-1, Builder.getCurSDLoc()));
   }
-  // Remove the fake entry we created so we don't have a hanging reference
-  // after we delete this node.
-  Builder.removeValue(Tmp);
-  delete Tmp;
-  Tmp = nullptr;
-
-  // Search for the call node
-  // The following code is essentially reverse engineering X86's
-  // LowerCallTo.
-  // We are expecting DAG to have the following form:
-  // ch = eh_label (only in case of invoke statepoint)
-  //   ch, glue = callseq_start ch
-  //   ch, glue = X86::Call ch, glue
-  //   ch, glue = callseq_end ch, glue
-  // ch = eh_label ch (only in case of invoke statepoint)
-  //
-  // DAG root will be either last eh_label or callseq_end.
-
-  SDNode *CallNode = nullptr;
-
-  // We just emitted a call, so it should be last thing generated
-  SDValue Chain = Builder.DAG.getRoot();
 
-  // Find closest CALLSEQ_END walking back through lowered nodes if needed
-  SDNode *CallEnd = Chain.getNode();
-  int Sanity = 0;
-  while (CallEnd->getOpcode() != ISD::CALLSEQ_END) {
-    assert(CallEnd->getNumOperands() >= 1 &&
-           CallEnd->getOperand(0).getValueType() == MVT::Other);
-
-    CallEnd = CallEnd->getOperand(0).getNode();
-
-    assert(Sanity < 20 && "should have found call end already");
-    Sanity++;
-  }
-  assert(CallEnd->getOpcode() == ISD::CALLSEQ_END &&
-         "Expected a callseq node.");
-  assert(CallEnd->getGluedNode());
-
-  // Step back inside the CALLSEQ
-  CallNode = CallEnd->getGluedNode();
-  return CallNode;
+  return CallEnd->getOperand(0).getNode();
 }
 
 /// Callect all gc pointers coming into statepoint intrinsic, clean them up,
@@ -586,7 +581,8 @@ void SelectionDAGBuilder::LowerStatepoin
   lowerStatepointMetaArgs(LoweredMetaArgs, ISP, *this);
 
   // Get call node, we will replace it later with statepoint
-  SDNode *CallNode = lowerCallFromStatepoint(ISP, LandingPad, *this);
+  SDNode *CallNode =
+      lowerCallFromStatepoint(ISP, LandingPad, *this, PendingExports);
 
   // Construct the actual STATEPOINT node with all the appropriate arguments
   // and return values.

Added: llvm/trunk/test/CodeGen/X86/statepoint-indirect-return.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/statepoint-indirect-return.ll?rev=236563&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/X86/statepoint-indirect-return.ll (added)
+++ llvm/trunk/test/CodeGen/X86/statepoint-indirect-return.ll Tue May  5 21:36:20 2015
@@ -0,0 +1,29 @@
+; RUN: llc < %s | FileCheck %s
+
+declare i1024 @g()
+
+define i1024 @f() gc "statepoint-example" {
+; CHECK-LABEL: _f
+; CHECK: callq _g
+  %1 = invoke i32 (i1024 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1024f(i1024 ()* @g, i32 0, i32 0, i32 0)
+          to label %normal unwind label %except
+
+normal:                                           ; preds = %0
+  %x1 = call i1024 @llvm.experimental.gc.result.i1024(i32 %1)
+  ret i1024 %x1
+
+except:                                           ; preds = %0
+  %landing_pad = landingpad { i8*, i32 } personality i32 ()* @personality_function
+          cleanup
+  ret i1024 0
+}
+
+declare i32 @personality_function()
+
+; Function Attrs: nounwind
+declare i32 @llvm.experimental.gc.statepoint.p0f_i1024f(i1024 ()*, i32, i32, ...) #0
+
+; Function Attrs: nounwind
+declare i1024 @llvm.experimental.gc.result.i1024(i32) #0
+
+attributes #0 = { nounwind }





More information about the llvm-commits mailing list