Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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,
SDNPMayHaveChain
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SDNPMayHaveChain
SDNPMayHaveChain,

};

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 SDNPMayHaveChain: SDNodeProperty; // Optionally has chain operand/result.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a correlation with SDNode::IsStrictFP flag. Do we still need it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To align with SDNPOptInGlue:

Suggested change
def SDNPMayHaveChain: SDNodeProperty; // Optionally has chain operand/result.
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
18 changes: 18 additions & 0 deletions llvm/include/llvm/CodeGen/SelectionDAGNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -717,13 +717,31 @@ END_TWO_BYTE_PACK()
case ISD::STRICT_FP_TO_FP16:
case ISD::STRICT_BF16_TO_FP:
case ISD::STRICT_FP_TO_BF16:
#define FP_OPERATION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
#define DAG_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \
case ISD::STRICT_##DAGN:
#include "llvm/IR/ConstrainedOps.def"
return true;
}
}

/// Test if this node is a floating-point operation which can exist in two
/// forms, - with chain or without it.
bool isFPOperation() const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there FP operations that exist in one form? If so, the method name should be more specific.

switch (NodeType) {
default:
return false;
#define FP_OPERATION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) case ISD::DAGN:
#include "llvm/IR/ConstrainedOps.def"
return true;
}
}

/// Test if this node has an input chain.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Test if this node has an input chain.
/// Test if this node has a chain.

bool hasChain() const {
return NumOperands > 0 && OperandList[0].getValueType() == MVT::Other;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are other operands that have MVT::Other type. In particular, setcc predicates. Some targets may use this type for other custom operands.
I wish we had a dedicated MVT::Chain type, like we have MVT::Glue.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should be checking for a chain result? I don't think that's ambiguous. Unfortunately, there might be a Glue result after the chain result so it requires checking the last and possibly second to last result.

}

/// Test if this node is an assert operation.
bool isAssert() const {
switch (NodeType) {
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ 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 MayHaveChain = Desc.hasProperty(SDNPMayHaveChain);

if (HasChain && MayHaveChain)
reportNodeError(
DAG, N, "Flags 'HasChain' and 'MayHaveChain' cannot be both specified");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be diagnosed in TableGen when parsing SDNode (and asserted here).


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

unsigned ActualNumResults = N->getNumValues();
unsigned ExpectedNumResults = Desc.NumResults + HasChain + HasOutGlue;
Expand Down
69 changes: 53 additions & 16 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 Expand Up @@ -4430,7 +4467,7 @@ bool SelectionDAGISel::mayRaiseFPException(SDNode *N) const {
const SelectionDAGTargetInfo &TSI = CurDAG->getSelectionDAGInfo();
return TSI.mayRaiseFPException(N->getOpcode());
}
return N->isStrictFPOpcode();
return N->isStrictFPOpcode() || N->isFPOperation();
}

bool SelectionDAGISel::isOrEquivalentToAdd(const SDNode *N) const {
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>]>,
[SDNPMayHaveChain]
>;

// 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// CHECK-NEXT: NODE_4
// 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<<SDNPMayHaveChain, 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>]>,
[SDNPMayHaveChain]
>;

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,
1 change: 1 addition & 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("SDNPMayHaveChain", SDNPMayHaveChain)
.Default(-1u);
if (Offset != -1u)
Properties |= 1 << Offset;
Expand Down
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,
SDNPMayHaveChain
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SDNPMayHaveChain
SDNPMayHaveChain,

};

unsigned parseSDPatternOperatorProperties(const Record *R);
Expand Down
Loading
Loading