diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h --- a/llvm/include/llvm/CodeGen/ISDOpcodes.h +++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h @@ -1036,6 +1036,10 @@ GC_TRANSITION_START, GC_TRANSITION_END, + /// GC_STATEPOINT - Represent STATEPOINT instruction + /// [Relocates,] OUTCHAIN, Glue = GC_STATEPOINT(...) + GC_STATEPOINT, + /// GET_DYNAMIC_AREA_OFFSET - get offset from native SP to the address of /// the most recent dynamic alloca. For most targets that would be 0, but /// for some others (e.g. PowerPC, PowerPC64) that would be compile-time diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -927,6 +927,15 @@ return getNode(ISD::GLOBAL_OFFSET_TABLE, SDLoc(), VT); } + /// Return a GC_STATEPOINT node. + /// RetVal is the value of actuall call this statepoint wraps. + /// GCArgStart is index in Ops where GC arguments start. + /// NumVRegDefs is number of derived pointers passed in VRegs and + /// relocated by this statepoint. + SDValue getStatepoint(const SDLoc &dl, SDValue RetVal, + unsigned GCArgStart, unsigned NumVRegDefs, + ArrayRef Ops); + /// Gets or creates the specified node. /// SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h --- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h @@ -2462,6 +2462,29 @@ } }; +/// This class is used to represent a STATEPOINT node +class StatepointSDNode : public SDNode { +private: + friend class SelectionDAG; + + SDValue ActualRetVal; + unsigned GCStart; + +public: + StatepointSDNode(unsigned Order, const DebugLoc &DL, SDVTList VTs, + SDValue RetVal, unsigned GCArgStart) + : SDNode(ISD::GC_STATEPOINT, Order, DL, VTs), + ActualRetVal(RetVal), GCStart(GCArgStart) {} + + unsigned getGCArgStart() const { return GCStart; } + + SDValue getActualRetVal() const { return ActualRetVal; } + + static bool classof(const SDNode *N) { + return N->getOpcode() == ISD::GC_STATEPOINT; + } +}; + /// An SDNode that represents everything that will be needed /// to construct a MachineInstr. These nodes are created during the /// instruction selection proper phase. diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -7252,6 +7252,29 @@ return V; } +SDValue SelectionDAG::getStatepoint(const SDLoc &dl, + SDValue RetVal, + unsigned GCArgStart, unsigned NumVRegDefs, + ArrayRef Ops) { + SmallVector VTs; + assert(GCArgStart + 1 + 2 * NumVRegDefs < Ops.size() && + "GCArgStart/NumVRegDefs out of bounds"); + // Node's values are first `NumVRegDefs` relocated derived pointers. + for (unsigned i = 0, idx = GCArgStart + 1; i < NumVRegDefs; ++i, idx += 2) + VTs.push_back(Ops[idx].getValueType()); + + VTs.push_back(MVT::Other); + VTs.push_back(MVT::Glue); + + auto *N = newSDNode(dl.getIROrder(), dl.getDebugLoc(), + getVTList(VTs), RetVal, GCArgStart); + createOperands(N, Ops); + InsertNode(N); + SDValue V(N, 0); + NewSDValueDbgMsg(V, "Creating new node: ", this); + return V; +} + SDValue SelectionDAG::simplifySelect(SDValue Cond, SDValue T, SDValue F) { // select undef, T, F --> T (if T is a constant), otherwise F // select, ?, undef, F --> F diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -138,6 +138,7 @@ case ISD::TargetIndex: return "TargetIndex"; case ISD::ExternalSymbol: return "ExternalSymbol"; case ISD::BlockAddress: return "BlockAddress"; + case ISD::GC_STATEPOINT: return "STATEPOINT"; case ISD::INTRINSIC_WO_CHAIN: case ISD::INTRINSIC_VOID: case ISD::INTRINSIC_W_CHAIN: {