Define CallSDNode, an SDNode subclass for use with ISD::CALL.
Currently it just holds the calling convention and flags
for isVarArgs and isTailCall.

And it has several utility methods, which eliminate magic
5+2*i and similar index computations in several places.

CallSDNodes are not CSE'd. Teach UpdateNodeOperands to handle
nodes that are not CSE'd gracefully.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@56183 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/SelectionDAG/CallingConvLower.cpp b/lib/CodeGen/SelectionDAG/CallingConvLower.cpp
index 5987e0c..a6f52dd 100644
--- a/lib/CodeGen/SelectionDAG/CallingConvLower.cpp
+++ b/lib/CodeGen/SelectionDAG/CallingConvLower.cpp
@@ -91,12 +91,11 @@
 
 /// AnalyzeCallOperands - Analyze an ISD::CALL node, incorporating info
 /// about the passed values into this state.
-void CCState::AnalyzeCallOperands(SDNode *TheCall, CCAssignFn Fn) {
-  unsigned NumOps = (TheCall->getNumOperands() - 5) / 2;
+void CCState::AnalyzeCallOperands(CallSDNode *TheCall, CCAssignFn Fn) {
+  unsigned NumOps = TheCall->getNumArgs();
   for (unsigned i = 0; i != NumOps; ++i) {
-    MVT ArgVT = TheCall->getOperand(5+2*i).getValueType();
-    ISD::ArgFlagsTy ArgFlags =
-      cast<ARG_FLAGSSDNode>(TheCall->getOperand(5+2*i+1))->getArgFlags();
+    MVT ArgVT = TheCall->getArg(i).getValueType();
+    ISD::ArgFlagsTy ArgFlags = TheCall->getArgFlags(i);
     if (Fn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, *this)) {
       cerr << "Call operand #" << i << " has unhandled type "
            << ArgVT.getMVTString() << "\n";
@@ -124,9 +123,9 @@
 
 /// AnalyzeCallResult - Analyze the return values of an ISD::CALL node,
 /// incorporating info about the passed values into this state.
-void CCState::AnalyzeCallResult(SDNode *TheCall, CCAssignFn Fn) {
-  for (unsigned i = 0, e = TheCall->getNumValues() - 1; i != e; ++i) {
-    MVT VT = TheCall->getValueType(i);
+void CCState::AnalyzeCallResult(CallSDNode *TheCall, CCAssignFn Fn) {
+  for (unsigned i = 0, e = TheCall->getNumRetVals(); i != e; ++i) {
+    MVT VT = TheCall->getRetValType(i);
     if (Fn(i, VT, VT, CCValAssign::Full, ISD::ArgFlagsTy(), *this)) {
       cerr << "Call result #" << i << " has unhandled type "
            << VT.getMVTString() << "\n";
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 6ebd514..921d7b0 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -595,13 +595,13 @@
 /// correspond to it.  This is useful when we're about to delete or repurpose
 /// the node.  We don't want future request for structurally identical nodes
 /// to return N anymore.
-void SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) {
+bool SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) {
   bool Erased = false;
   switch (N->getOpcode()) {
   case ISD::EntryToken:
     assert(0 && "EntryToken should not be in CSEMaps!");
-    return;
-  case ISD::HANDLENODE: return;  // noop.
+    return false;
+  case ISD::HANDLENODE: return false;  // noop.
   case ISD::CONDCODE:
     assert(CondCodeNodes[cast<CondCodeSDNode>(N)->get()] &&
            "Cond code doesn't exist!");
@@ -635,7 +635,8 @@
   // flag result (which cannot be CSE'd) or is one of the special cases that are
   // not subject to CSE.
   if (!Erased && N->getValueType(N->getNumValues()-1) != MVT::Flag &&
-      !N->isTargetOpcode() &&
+      !N->isMachineOpcode() &&
+      N->getOpcode() != ISD::CALL &&
       N->getOpcode() != ISD::DBG_LABEL &&
       N->getOpcode() != ISD::DBG_STOPPOINT &&
       N->getOpcode() != ISD::EH_LABEL &&
@@ -645,6 +646,7 @@
     assert(0 && "Node is not in map!");
   }
 #endif
+  return Erased;
 }
 
 /// AddNonLeafNodeToCSEMaps - Add the specified node back to the CSE maps.  It
@@ -660,6 +662,7 @@
 
   switch (N->getOpcode()) {
   default: break;
+  case ISD::CALL:
   case ISD::HANDLENODE:
   case ISD::DBG_LABEL:
   case ISD::DBG_STOPPOINT:
@@ -3304,6 +3307,21 @@
 }
 
 SDValue
+SelectionDAG::getCall(unsigned CallingConv, bool IsVarArgs, bool IsTailCall,
+                      SDVTList VTs,
+                      const SDValue *Operands, unsigned NumOperands) {
+  // Do not CSE calls. Note that in addition to being a compile-time
+  // optimization (since attempting CSE of calls is unlikely to be
+  // meaningful), we actually depend on this behavior. CallSDNode can
+  // be mutated, which is only safe if calls are not CSE'd.
+  SDNode *N = NodeAllocator.Allocate<CallSDNode>();
+  new (N) CallSDNode(CallingConv, IsVarArgs, IsTailCall,
+                     VTs, Operands, NumOperands);
+  AllNodes.push_back(N);
+  return SDValue(N, 0);
+}
+
+SDValue
 SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType,
                       MVT VT, SDValue Chain,
                       SDValue Ptr, SDValue Offset,
@@ -3761,7 +3779,8 @@
   
   // Nope it doesn't.  Remove the node from its current place in the maps.
   if (InsertPos)
-    RemoveNodeFromCSEMaps(N);
+    if (!RemoveNodeFromCSEMaps(N))
+      InsertPos = 0;
   
   // Now we update the operands.
   N->OperandList[0].getVal()->removeUser(0, N);
@@ -3790,7 +3809,8 @@
   
   // Nope it doesn't.  Remove the node from its current place in the maps.
   if (InsertPos)
-    RemoveNodeFromCSEMaps(N);
+    if (!RemoveNodeFromCSEMaps(N))
+      InsertPos = 0;
   
   // Now we update the operands.
   if (N->OperandList[0] != Op1) {
@@ -3856,7 +3876,8 @@
   
   // Nope it doesn't.  Remove the node from its current place in the maps.
   if (InsertPos)
-    RemoveNodeFromCSEMaps(N);
+    if (!RemoveNodeFromCSEMaps(N))
+      InsertPos = 0;
   
   // Now we update the operands.
   for (unsigned i = 0; i != NumOps; ++i) {
@@ -4079,7 +4100,8 @@
       return ON;
   }
 
-  RemoveNodeFromCSEMaps(N);
+  if (!RemoveNodeFromCSEMaps(N))
+    IP = 0;
 
   // Start the morphing.
   N->NodeType = Opc;
@@ -4582,6 +4604,7 @@
 void LoadSDNode::ANCHOR() {}
 void StoreSDNode::ANCHOR() {}
 void AtomicSDNode::ANCHOR() {}
+void CallSDNode::ANCHOR() {}
 
 HandleSDNode::~HandleSDNode() {
   DropOperands();
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
index a95a50b..599f0dd 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
@@ -5325,9 +5325,6 @@
                             ArgListTy &Args, SelectionDAG &DAG) {
   SmallVector<SDValue, 32> Ops;
   Ops.push_back(Chain);   // Op#0 - Chain
-  Ops.push_back(DAG.getConstant(CallingConv, getPointerTy())); // Op#1 - CC
-  Ops.push_back(DAG.getConstant(isVarArg, getPointerTy()));    // Op#2 - VarArg
-  Ops.push_back(DAG.getConstant(isTailCall, getPointerTy()));  // Op#3 - Tail
   Ops.push_back(Callee);
   
   // Handle all of the outgoing arguments.
@@ -5412,10 +5409,10 @@
   LoweredRetTys.push_back(MVT::Other);  // Always has a chain.
   
   // Create the CALL node.
-  SDValue Res = DAG.getNode(ISD::CALL,
-                              DAG.getVTList(&LoweredRetTys[0],
-                                            LoweredRetTys.size()),
-                              &Ops[0], Ops.size());
+  SDValue Res = DAG.getCall(CallingConv, isVarArg, isTailCall,
+                            DAG.getVTList(&LoweredRetTys[0],
+                                          LoweredRetTys.size()),
+                            &Ops[0], Ops.size());
   Chain = Res.getValue(LoweredRetTys.size() - 1);
 
   // Gather up the call result into a single value.
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 3159db4..fa17510 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -402,56 +402,45 @@
   for (SelectionDAG::allnodes_iterator BE = DAG.allnodes_begin(),
          BI = DAG.allnodes_end(); BI != BE; ) {
     --BI;
-    if (BI->getOpcode() == ISD::CALL) {
+    if (CallSDNode *TheCall = dyn_cast<CallSDNode>(BI)) {
       SDValue OpRet(Ret, 0);
       SDValue OpCall(BI, 0);
-      bool isMarkedTailCall = 
-        cast<ConstantSDNode>(OpCall.getOperand(3))->getZExtValue() != 0;
+      bool isMarkedTailCall = TheCall->isTailCall();
       // If CALL node has tail call attribute set to true and the call is not
       // eligible (no RET or the target rejects) the attribute is fixed to
       // false. The TargetLowering::IsEligibleForTailCallOptimization function
       // must correctly identify tail call optimizable calls.
       if (!isMarkedTailCall) continue;
       if (Ret==NULL ||
-          !TLI.IsEligibleForTailCallOptimization(OpCall, OpRet, DAG)) {
-        // Not eligible. Mark CALL node as non tail call.
-        SmallVector<SDValue, 32> Ops;
-        unsigned idx=0;
-        for(SDNode::op_iterator I =OpCall.getNode()->op_begin(),
-              E = OpCall.getNode()->op_end(); I != E; I++, idx++) {
-          if (idx!=3)
-            Ops.push_back(*I);
-          else
-            Ops.push_back(DAG.getConstant(false, TLI.getPointerTy()));
-        }
-        DAG.UpdateNodeOperands(OpCall, Ops.begin(), Ops.size());
+          !TLI.IsEligibleForTailCallOptimization(TheCall, OpRet, DAG)) {
+        // Not eligible. Mark CALL node as non tail call. Note that we
+        // can modify the call node in place since calls are not CSE'd.
+        TheCall->setNotTailCall();
       } else {
         // Look for tail call clobbered arguments. Emit a series of
         // copyto/copyfrom virtual register nodes to protect them.
         SmallVector<SDValue, 32> Ops;
-        SDValue Chain = OpCall.getOperand(0), InFlag;
-        unsigned idx=0;
-        for(SDNode::op_iterator I = OpCall.getNode()->op_begin(),
-              E = OpCall.getNode()->op_end(); I != E; I++, idx++) {
-          SDValue Arg = *I;
-          if (idx > 4 && (idx % 2)) {
-            bool isByVal = cast<ARG_FLAGSSDNode>(OpCall.getOperand(idx+1))->
-              getArgFlags().isByVal();
-            MachineFunction &MF = DAG.getMachineFunction();
-            MachineFrameInfo *MFI = MF.getFrameInfo();
-            if (!isByVal &&
-                IsPossiblyOverwrittenArgumentOfTailCall(Arg, MFI)) {
-              MVT VT = Arg.getValueType();
-              unsigned VReg = MF.getRegInfo().
-                createVirtualRegister(TLI.getRegClassFor(VT));
-              Chain = DAG.getCopyToReg(Chain, VReg, Arg, InFlag);
-              InFlag = Chain.getValue(1);
-              Arg = DAG.getCopyFromReg(Chain, VReg, VT, InFlag);
-              Chain = Arg.getValue(1);
-              InFlag = Arg.getValue(2);
-            }
+        SDValue Chain = TheCall->getChain(), InFlag;
+        Ops.push_back(Chain);
+        Ops.push_back(TheCall->getCallee());
+        for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; ++i) {
+          SDValue Arg = TheCall->getArg(i);
+          bool isByVal = TheCall->getArgFlags(i).isByVal();
+          MachineFunction &MF = DAG.getMachineFunction();
+          MachineFrameInfo *MFI = MF.getFrameInfo();
+          if (!isByVal &&
+              IsPossiblyOverwrittenArgumentOfTailCall(Arg, MFI)) {
+            MVT VT = Arg.getValueType();
+            unsigned VReg = MF.getRegInfo().
+              createVirtualRegister(TLI.getRegClassFor(VT));
+            Chain = DAG.getCopyToReg(Chain, VReg, Arg, InFlag);
+            InFlag = Chain.getValue(1);
+            Arg = DAG.getCopyFromReg(Chain, VReg, VT, InFlag);
+            Chain = Arg.getValue(1);
+            InFlag = Arg.getValue(2);
           }
           Ops.push_back(Arg);
+          Ops.push_back(TheCall->getArgFlagsVal(i));
         }
         // Link in chain of CopyTo/CopyFromReg.
         Ops[0] = Chain;
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp
index f2cd3c1..570caa9 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp
@@ -179,6 +179,12 @@
       Op += ":" + utostr(D->getColumn());
   } else if (const LabelSDNode *L = dyn_cast<LabelSDNode>(Node)) {
     Op += ": LabelID=" + utostr(L->getLabelID());
+  } else if (const CallSDNode *C = dyn_cast<CallSDNode>(Node)) {
+    Op += ": CallingConv=" + utostr(C->getCallingConv());
+    if (C->isVarArg())
+      Op += ", isVarArg";
+    if (C->isTailCall())
+      Op += ", isTailCall";
   } else if (const ExternalSymbolSDNode *ES =
              dyn_cast<ExternalSymbolSDNode>(Node)) {
     Op += "'" + std::string(ES->getSymbol()) + "'";