Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/SDNodeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum SDNP {
SDNPOptInGlue,
SDNPMemOperand,
SDNPVariadic,
SDNPOptChain,
};

enum SDTC : uint8_t {
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/SDNodeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ def SDNPMayLoad : SDNodeProperty; // May read memory, sets 'mayLoad'.
def SDNPSideEffect : SDNodeProperty; // Sets 'HasUnmodelledSideEffects'.
def SDNPMemOperand : SDNodeProperty; // Touches memory, has assoc MemOperand
def SDNPVariadic : SDNodeProperty; // Node has variable arguments.
def SDNPOptChain : SDNodeProperty; // Optionally has chain operand/result.
4 changes: 3 additions & 1 deletion llvm/include/llvm/CodeGen/SelectionDAGISel.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class SelectionDAGISel {
OPC_RecordChild6,
OPC_RecordChild7,
OPC_RecordMemRef,
OPC_RecordOptionalChain,
OPC_CaptureGlueInput,
OPC_MoveChild,
OPC_MoveChild0,
Expand Down Expand Up @@ -493,7 +494,8 @@ class SelectionDAGISel {
private:
void DoInstructionSelection();
SDNode *MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList,
ArrayRef<SDValue> Ops, unsigned EmitNodeInfo);
ArrayRef<SDValue> Ops, unsigned EmitNodeInfo,
bool OptionalChain);

/// Prepares the landing pad to take incoming values or do other EH
/// personality specific tasks. Returns true if the block should be
Expand Down
12 changes: 12 additions & 0 deletions llvm/include/llvm/CodeGen/SelectionDAGNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,18 @@ END_TWO_BYTE_PACK()
}
}

/// Test if this node has a chain.
bool hasChain() const {
if (NumValues > 0) {
if (ValueList[NumValues - 1] == MVT::Other)
return true;
if (ValueList[NumValues - 1] == MVT::Glue)
if (NumValues > 1 && ValueList[NumValues - 2] == MVT::Other)
return true;
}
return false;
}

/// Test if this node is an assert operation.
bool isAssert() const {
switch (NodeType) {
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
bool HasInGlue = Desc.hasProperty(SDNPInGlue);
bool HasOptInGlue = Desc.hasProperty(SDNPOptInGlue);
bool IsVariadic = Desc.hasProperty(SDNPVariadic);
bool HasOptChain = Desc.hasProperty(SDNPOptChain);

if (HasChain && HasOptChain)
reportNodeError(DAG, N,
"Properties 'SDNPHasChain' and 'SDNPOptChain' cannot be "
"both specified");

if (HasOptChain && N->getNumOperands() > 0 &&
N->getOperand(0).getValueType() == MVT::Other) {
HasChain = true;
}

unsigned ActualNumResults = N->getNumValues();
unsigned ExpectedNumResults = Desc.NumResults + HasChain + HasOutGlue;
Expand Down
67 changes: 52 additions & 15 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2836,9 +2836,9 @@ HandleMergeInputChains(SmallVectorImpl<SDNode*> &ChainNodesMatched,
}

/// MorphNode - Handle morphing a node in place for the selector.
SDNode *SelectionDAGISel::
MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList,
ArrayRef<SDValue> Ops, unsigned EmitNodeInfo) {
SDNode *SelectionDAGISel::MorphNode(SDNode *Node, unsigned TargetOpc,
SDVTList VTList, ArrayRef<SDValue> Ops,
unsigned EmitNodeInfo, bool OptionalChain) {
// It is possible we're using MorphNodeTo to replace a node with no
// normal results with one that has a normal result (or we could be
// adding a chain) and the input could have glue and chains as well.
Expand Down Expand Up @@ -2880,7 +2880,7 @@ MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList,
--ResNumResults;

// Move the chain reference if needed.
if ((EmitNodeInfo & OPFL_Chain) && OldChainResultNo != -1 &&
if ((EmitNodeInfo & OPFL_Chain || OptionalChain) && OldChainResultNo != -1 &&
static_cast<unsigned>(OldChainResultNo) != ResNumResults - 1)
ReplaceUses(SDValue(Node, OldChainResultNo),
SDValue(Res, ResNumResults - 1));
Expand Down Expand Up @@ -3385,6 +3385,12 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
// update the chain results when the pattern is complete.
SmallVector<SDNode*, 3> ChainNodesMatched;

bool HasNodesWithOptionalChain = false;

// List of pattern matches nodes that may have input/output chains and
// actually have them.
SmallVector<SDNode *, 8> OptionalChainNodes;

LLVM_DEBUG(dbgs() << "ISEL: Starting pattern match\n");

// Determine where to start the interpreter. Normally we start at opcode #0,
Expand Down Expand Up @@ -3505,7 +3511,8 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
case OPC_RecordChild2: case OPC_RecordChild3:
case OPC_RecordChild4: case OPC_RecordChild5:
case OPC_RecordChild6: case OPC_RecordChild7: {
unsigned ChildNo = Opcode-OPC_RecordChild0;
unsigned ChildNo =
Opcode - OPC_RecordChild0 + !OptionalChainNodes.empty();
if (ChildNo >= N.getNumOperands())
break; // Match fails if out of range child #.

Expand All @@ -3523,6 +3530,17 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,

continue;

case OPC_RecordOptionalChain:
HasNodesWithOptionalChain = true;
// If the current node has input chain, record it.
if (N->getNumOperands() != 0) {
SDValue FirstOperand = N->getOperand(0);
if (FirstOperand.getValueType() == MVT::Other) {
OptionalChainNodes.push_back(N.getNode());
}
}
continue;

case OPC_CaptureGlueInput:
// If the current node has an input glue, capture it in InputGlue.
if (N->getNumOperands() != 0 &&
Expand All @@ -3531,7 +3549,8 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
continue;

case OPC_MoveChild: {
unsigned ChildNo = MatcherTable[MatcherIndex++];
unsigned ChildNo =
MatcherTable[MatcherIndex++] + !OptionalChainNodes.empty();
if (ChildNo >= N.getNumOperands())
break; // Match fails if out of range child #.
N = N.getOperand(ChildNo);
Expand All @@ -3543,7 +3562,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
case OPC_MoveChild2: case OPC_MoveChild3:
case OPC_MoveChild4: case OPC_MoveChild5:
case OPC_MoveChild6: case OPC_MoveChild7: {
unsigned ChildNo = Opcode-OPC_MoveChild0;
unsigned ChildNo = Opcode - OPC_MoveChild0 + !OptionalChainNodes.empty();
if (ChildNo >= N.getNumOperands())
break; // Match fails if out of range child #.
N = N.getOperand(ChildNo);
Expand All @@ -3568,6 +3587,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
unsigned SiblingNo = Opcode == OPC_MoveSibling
? MatcherTable[MatcherIndex++]
: Opcode - OPC_MoveSibling0;
SiblingNo += !OptionalChainNodes.empty();
if (SiblingNo >= N.getNumOperands())
break; // Match fails if out of range sibling #.
N = N.getOperand(SiblingNo);
Expand Down Expand Up @@ -3998,11 +4018,16 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
// Ignore these because the newly token factored chain should not refer to
// the old nodes.
unsigned NumChains = MatcherTable[MatcherIndex++];
assert(NumChains != 0 && "Can't TF zero chains");
assert((NumChains != 0 || HasNodesWithOptionalChain) &&
"Can't TF zero chains");

assert(ChainNodesMatched.empty() &&
"Should only have one EmitMergeInputChains per match");

if (NumChains == 0 && HasNodesWithOptionalChain &&
OptionalChainNodes.empty())
continue;

// Read all of the chained nodes.
for (unsigned i = 0; i != NumChains; ++i) {
unsigned RecNo = MatcherTable[MatcherIndex++];
Expand All @@ -4020,6 +4045,8 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
}
}

ChainNodesMatched.append(OptionalChainNodes);

// If the inner loop broke out, the match fails.
if (ChainNodesMatched.empty())
break;
Expand Down Expand Up @@ -4164,7 +4191,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
VTs.push_back(VT);
}

if (EmitNodeInfo & OPFL_Chain)
if (EmitNodeInfo & OPFL_Chain || !OptionalChainNodes.empty())
VTs.push_back(MVT::Other);
if (EmitNodeInfo & OPFL_GlueOutput)
VTs.push_back(MVT::Glue);
Expand All @@ -4186,6 +4213,10 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
unsigned RecNo = MatcherTable[MatcherIndex++];
if (RecNo & 128)
RecNo = GetVBR(RecNo, MatcherTable, MatcherIndex);
if (HasNodesWithOptionalChain) {
assert(RecNo > 0);
RecNo--;
}

assert(RecNo < RecordedNodes.size() && "Invalid EmitNode");
Ops.push_back(RecordedNodes[RecNo].first);
Expand All @@ -4209,7 +4240,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
}

// If this has chain/glue inputs, add them.
if (EmitNodeInfo & OPFL_Chain)
if (EmitNodeInfo & OPFL_Chain || !OptionalChainNodes.empty())
Ops.push_back(InputChain);
if ((EmitNodeInfo & OPFL_GlueInput) && InputGlue.getNode() != nullptr)
Ops.push_back(InputGlue);
Expand All @@ -4219,7 +4250,12 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
// We need to perform this check before potentially modifying one of the
// nodes via MorphNode.
bool MayRaiseFPException =
llvm::any_of(ChainNodesMatched, [this](SDNode *N) {
llvm::any_of(ChainNodesMatched,
[this](SDNode *N) {
return mayRaiseFPException(N) &&
!N->getFlags().hasNoFPExcept();
}) ||
llvm::any_of(OptionalChainNodes, [this](SDNode *N) {
return mayRaiseFPException(N) && !N->getFlags().hasNoFPExcept();
});

Expand Down Expand Up @@ -4251,8 +4287,9 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
"Chain node replaced during MorphNode");
llvm::erase(Chain, N);
});
Res = cast<MachineSDNode>(MorphNode(NodeToMatch, TargetOpc, VTList,
Ops, EmitNodeInfo));
Res = cast<MachineSDNode>(MorphNode(NodeToMatch, TargetOpc, VTList, Ops,
EmitNodeInfo,
!OptionalChainNodes.empty()));
}

// Set the NoFPExcept flag when no original matched node could
Expand All @@ -4264,9 +4301,9 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
// chain and glue.
if (EmitNodeInfo & OPFL_GlueOutput) {
InputGlue = SDValue(Res, VTs.size()-1);
if (EmitNodeInfo & OPFL_Chain)
if (EmitNodeInfo & OPFL_Chain || !OptionalChainNodes.empty())
InputChain = SDValue(Res, VTs.size()-2);
} else if (EmitNodeInfo & OPFL_Chain)
} else if (EmitNodeInfo & OPFL_Chain || !OptionalChainNodes.empty())
InputChain = SDValue(Res, VTs.size()-1);

// If the OPFL_MemRefs glue is set on this node, slap all of the
Expand Down
14 changes: 12 additions & 2 deletions llvm/test/TableGen/SDNodeInfoEmitter/advanced.td
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,22 @@ def my_node_3 : SDNode<
SDNPOutGlue, SDNPInGlue, SDNPOptInGlue]
>;

def my_node_4 : SDNode<
"MyTargetISD::NODE_4",
SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, f32>]>,
[SDNPOptChain]
>;

// CHECK: namespace llvm::MyTargetISD {
// CHECK-EMPTY:
// CHECK-NEXT: enum GenNodeType : unsigned {
// CHECK-NEXT: NODE_1 = ISD::BUILTIN_OP_END,
// CHECK-NEXT: NODE_2,
// CHECK-NEXT: NODE_3,
// CHECK-NEXT: NODE_4,
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NODE_3 + 1;
// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NODE_4 + 1;
// CHECK-EMPTY:
// CHECK-NEXT: } // namespace llvm::MyTargetISD

Expand All @@ -63,6 +70,7 @@ def my_node_3 : SDNode<
// CHECK-NEXT: "MyTargetISD::NODE_1\0"
// CHECK-NEXT: "MyTargetISD::NODE_2\0"
// CHECK-NEXT: "MyTargetISD::NODE_3\0"
// CHECK-NEXT: "MyTargetISD::NODE_4\0"
// CHECK-NEXT: ;

// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
Expand All @@ -81,14 +89,16 @@ def my_node_3 : SDNode<
// CHECK-SAME: {SDTCisInt, 2, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
// CHECK-SAME: {SDTCisPtrTy, 1, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
// CHECK-SAME: {SDTCisVT, 0, 0, MVT::i1},
// CHECK-NEXT: /* 15 */ {SDTCisVT, 1, 0, MVT::f32}, {SDTCisVT, 0, 0, MVT::f32},
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
// CHECK-NEXT: {1, 1, 0|1<<SDNPHasChain, 0, 0, 1, 0, 2}, // NODE_1
// CHECK-NEXT: {3, 1, 0|1<<SDNPVariadic|1<<SDNPMemOperand, 0, 42, 21, 11, 4}, // NODE_2
// CHECK-NEXT: {2, -1, 0|1<<SDNPHasChain|1<<SDNPOutGlue|1<<SDNPInGlue|1<<SDNPOptInGlue, 0|1<<SDNFIsStrictFP, 24, 41, 2, 13}, // NODE_3
// CHECK-NEXT: {1, 1, 0|1<<SDNPOptChain, 0, 0, 61, 15, 2}, // NODE_4
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
// CHECK-NEXT: /*NumOpcodes=*/3, MyTargetSDNodeDescs,
// CHECK-NEXT: /*NumOpcodes=*/4, MyTargetSDNodeDescs,
// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
46 changes: 46 additions & 0 deletions llvm/test/TableGen/optional-chain.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include %s 2>&1 | FileCheck %s

include "llvm/Target/Target.td"

def TestTargetInstrInfo : InstrInfo;


def TestTarget : Target {
let InstructionSet = TestTargetInstrInfo;
}

def R0 : Register<"r0"> { let Namespace = "MyTarget"; }
def GPR : RegisterClass<"MyTarget", [i32, f32], 32, (add R0)>;

def a_nearbyint : SDNode<
"MyTargetISD::A_NEARBYINT",
SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisFP<1>]>,
[SDNPOptChain]
>;

def I_NEARBYINT : Instruction {
let OutOperandList = (outs GPR:$out);
let InOperandList = (ins GPR:$x);
}

def : Pat<(a_nearbyint GPR:$x), (I_NEARBYINT GPR:$x)>;
def : Pat<(a_nearbyint (a_nearbyint GPR:$x)), (I_NEARBYINT GPR:$x)>;

// CHECK-LABEL: OPC_CheckOpcode, TARGET_VAL(MyTargetISD::A_NEARBYINT),
// CHECK-NEXT: OPC_RecordOptionalChain,
// CHECK-NEXT: OPC_Scope, 17
// CHECK-NEXT: OPC_MoveChild0,
// CHECK-NEXT: OPC_CheckOpcode, TARGET_VAL(MyTargetISD::A_NEARBYINT),
// CHECK-NEXT: OPC_RecordOptionalChain,
// CHECK-NEXT: OPC_CheckFoldableChainNode,
// CHECK-NEXT: OPC_RecordChild0,
// CHECK-NEXT: OPC_MoveParent,
// CHECK-NEXT: OPC_EmitMergeInputChains, 0,
// CHECK-NEXT: OPC_MorphNodeTo1, TARGET_VAL(::I_NEARBYINT), 0,
// CHECK-NEXT: /*MVT::f32*/12, 1/*#Ops*/, 2,

// CHECK: /*Scope*/ 10,
// CHECK-NEXT: OPC_RecordChild0,
// CHECK-NEXT: OPC_EmitMergeInputChains, 0,
// CHECK-NEXT: OPC_MorphNodeTo1, TARGET_VAL(::I_NEARBYINT), 0,
// CHECK-NEXT: /*MVT::f32*/12, 1/*#Ops*/, 1,
9 changes: 9 additions & 0 deletions llvm/utils/TableGen/Basic/SDNodeProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ unsigned llvm::parseSDPatternOperatorProperties(const Record *R) {
.Case("SDNPSideEffect", SDNPSideEffect)
.Case("SDNPMemOperand", SDNPMemOperand)
.Case("SDNPVariadic", SDNPVariadic)
.Case("SDNPOptChain", SDNPOptChain)
.Default(-1u);
if (Offset != -1u)
Properties |= 1 << Offset;
Expand All @@ -36,5 +37,13 @@ unsigned llvm::parseSDPatternOperatorProperties(const Record *R) {
Property->getName() + "' on node '" +
R->getName() + "'!");
}

// Make some consistency checks.
if (Properties & (1 << SDNPHasChain) && Properties & (1 << SDNPOptChain))
PrintFatalError(R->getLoc(),
"Properties 'SDNPHasChain' and 'SDNPOptChain' cannot be "
"both specified on node '" +
R->getName() + "'!");

return Properties;
}
1 change: 1 addition & 0 deletions llvm/utils/TableGen/Basic/SDNodeProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum SDNP {
SDNPSideEffect,
SDNPMemOperand,
SDNPVariadic,
SDNPOptChain,
};

unsigned parseSDPatternOperatorProperties(const Record *R);
Expand Down
3 changes: 3 additions & 0 deletions llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3681,6 +3681,7 @@ class InstAnalyzer {
bool isBitcast = false;
bool isVariadic = false;
bool hasChain = false;
bool mayHaveChain = false;

InstAnalyzer(const CodeGenDAGPatterns &cdp) : CDP(cdp) {}

Expand Down Expand Up @@ -3744,6 +3745,8 @@ class InstAnalyzer {
isVariadic = true;
if (N.NodeHasProperty(SDNPHasChain, CDP))
hasChain = true;
if (N.NodeHasProperty(SDNPOptChain, CDP))
mayHaveChain = true;

if (const CodeGenIntrinsic *IntInfo = N.getIntrinsicInfo(CDP)) {
ModRefInfo MR = IntInfo->ME.getModRef();
Expand Down
Loading