Skip to content

Commit 0a17427

Browse files
authored
[SelectionDAG] Wire up -gen-sdnode-info TableGen backend (#125358)
This patch introduces SelectionDAGGenTargetInfo and SDNodeInfo classes, which provide methods for accessing the generated SDNode descriptions. Pull Request: #125358 Draft PR: #119709 RFC: https://discourse.llvm.org/t/rfc-tablegen-erating-sdnode-descriptions
1 parent 7013b51 commit 0a17427

13 files changed

+387
-93
lines changed
+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//==------------------------------------------------------------------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CODEGEN_SDNODEINFO_H
10+
#define LLVM_CODEGEN_SDNODEINFO_H
11+
12+
#include "llvm/ADT/ArrayRef.h"
13+
#include "llvm/ADT/StringTable.h"
14+
#include "llvm/CodeGen/ISDOpcodes.h"
15+
#include "llvm/CodeGenTypes/MachineValueType.h"
16+
17+
namespace llvm {
18+
19+
class SDNode;
20+
class SelectionDAG;
21+
22+
enum SDNP {
23+
SDNPHasChain,
24+
SDNPOutGlue,
25+
SDNPInGlue,
26+
SDNPOptInGlue,
27+
SDNPMemOperand,
28+
SDNPVariadic,
29+
};
30+
31+
enum SDTC : uint8_t {
32+
SDTCisVT,
33+
SDTCisPtrTy,
34+
SDTCisInt,
35+
SDTCisFP,
36+
SDTCisVec,
37+
SDTCisSameAs,
38+
SDTCisVTSmallerThanOp,
39+
SDTCisOpSmallerThanOp,
40+
SDTCisEltOfVec,
41+
SDTCisSubVecOfVec,
42+
SDTCVecEltisVT,
43+
SDTCisSameNumEltsAs,
44+
SDTCisSameSizeAs,
45+
};
46+
47+
enum SDNF {
48+
SDNFIsStrictFP,
49+
};
50+
51+
struct SDTypeConstraint {
52+
SDTC Kind;
53+
uint8_t OpNo;
54+
uint8_t OtherOpNo;
55+
MVT::SimpleValueType VT;
56+
};
57+
58+
struct SDNodeDesc {
59+
uint16_t NumResults;
60+
int16_t NumOperands;
61+
uint32_t Properties;
62+
uint32_t Flags;
63+
uint32_t TSFlags;
64+
unsigned NameOffset;
65+
unsigned ConstraintOffset;
66+
unsigned ConstraintCount;
67+
68+
bool hasProperty(SDNP Property) const { return Properties & (1 << Property); }
69+
70+
bool hasFlag(SDNF Flag) const { return Flags & (1 << Flag); }
71+
};
72+
73+
class SDNodeInfo final {
74+
unsigned NumOpcodes;
75+
const SDNodeDesc *Descs;
76+
StringTable Names;
77+
const SDTypeConstraint *Constraints;
78+
79+
public:
80+
constexpr SDNodeInfo(unsigned NumOpcodes, const SDNodeDesc *Descs,
81+
StringTable Names, const SDTypeConstraint *Constraints)
82+
: NumOpcodes(NumOpcodes), Descs(Descs), Names(Names),
83+
Constraints(Constraints) {}
84+
85+
/// Returns true if there is a generated description for a node with the given
86+
/// target-specific opcode.
87+
bool hasDesc(unsigned Opcode) const {
88+
assert(Opcode >= ISD::BUILTIN_OP_END && "Expected target-specific opcode");
89+
return Opcode < ISD::BUILTIN_OP_END + NumOpcodes;
90+
}
91+
92+
/// Returns the description of a node with the given opcode.
93+
const SDNodeDesc &getDesc(unsigned Opcode) const {
94+
assert(hasDesc(Opcode));
95+
return Descs[Opcode - ISD::BUILTIN_OP_END];
96+
}
97+
98+
/// Returns operand constraints for a node with the given opcode.
99+
ArrayRef<SDTypeConstraint> getConstraints(unsigned Opcode) const {
100+
const SDNodeDesc &Desc = getDesc(Opcode);
101+
return ArrayRef(&Constraints[Desc.ConstraintOffset], Desc.ConstraintCount);
102+
}
103+
104+
/// Returns the name of the given target-specific opcode, suitable for
105+
/// debug printing.
106+
StringRef getName(unsigned Opcode) const {
107+
return Names[getDesc(Opcode).NameOffset];
108+
}
109+
110+
void verifyNode(const SelectionDAG &DAG, const SDNode *N) const;
111+
};
112+
113+
} // namespace llvm
114+
115+
#endif // LLVM_CODEGEN_SDNODEINFO_H

llvm/include/llvm/CodeGen/SelectionDAG.h

+3
Original file line numberDiff line numberDiff line change
@@ -2445,6 +2445,9 @@ class SelectionDAG {
24452445
const SDLoc &DLoc);
24462446

24472447
private:
2448+
#ifndef NDEBUG
2449+
void verifyNode(SDNode *N) const;
2450+
#endif
24482451
void InsertNode(SDNode *N);
24492452
bool RemoveNodeFromCSEMaps(SDNode *N);
24502453
void AddModifiedNodeToCSEMaps(SDNode *N);

llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h

+48
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H
1717

1818
#include "llvm/CodeGen/MachineMemOperand.h"
19+
#include "llvm/CodeGen/SDNodeInfo.h"
1920
#include "llvm/CodeGen/SelectionDAGNodes.h"
2021
#include "llvm/Support/CodeGen.h"
2122
#include <utility>
@@ -35,6 +36,12 @@ class SelectionDAGTargetInfo {
3536
SelectionDAGTargetInfo &operator=(const SelectionDAGTargetInfo &) = delete;
3637
virtual ~SelectionDAGTargetInfo();
3738

39+
/// Returns the name of the given target-specific opcode, suitable for
40+
/// debug printing.
41+
virtual const char *getTargetNodeName(unsigned Opcode) const {
42+
return nullptr;
43+
}
44+
3845
/// Returns true if a node with the given target-specific opcode has
3946
/// a memory operand. Nodes with such opcodes can only be created with
4047
/// `SelectionDAG::getMemIntrinsicNode`.
@@ -48,6 +55,10 @@ class SelectionDAGTargetInfo {
4855
/// may raise a floating-point exception.
4956
virtual bool mayRaiseFPException(unsigned Opcode) const;
5057

58+
/// Checks that the given target-specific node is valid. Aborts if it is not.
59+
virtual void verifyTargetNode(const SelectionDAG &DAG,
60+
const SDNode *N) const {}
61+
5162
/// Emit target-specific code that performs a memcpy.
5263
/// This can be used by targets to provide code sequences for cases
5364
/// that don't fit the target's parameters for simple loads/stores and can be
@@ -176,6 +187,43 @@ class SelectionDAGTargetInfo {
176187
}
177188
};
178189

190+
/// Proxy class that targets should inherit from if they wish to use
191+
/// the generated node descriptions.
192+
class SelectionDAGGenTargetInfo : public SelectionDAGTargetInfo {
193+
protected:
194+
const SDNodeInfo &GenNodeInfo;
195+
196+
explicit SelectionDAGGenTargetInfo(const SDNodeInfo &GenNodeInfo)
197+
: GenNodeInfo(GenNodeInfo) {}
198+
199+
public:
200+
~SelectionDAGGenTargetInfo() override;
201+
202+
const char *getTargetNodeName(unsigned Opcode) const override {
203+
assert(GenNodeInfo.hasDesc(Opcode) &&
204+
"The name should be provided by the derived class");
205+
return GenNodeInfo.getName(Opcode).data();
206+
}
207+
208+
bool isTargetMemoryOpcode(unsigned Opcode) const override {
209+
if (GenNodeInfo.hasDesc(Opcode))
210+
return GenNodeInfo.getDesc(Opcode).hasProperty(SDNPMemOperand);
211+
return false;
212+
}
213+
214+
bool isTargetStrictFPOpcode(unsigned Opcode) const override {
215+
if (GenNodeInfo.hasDesc(Opcode))
216+
return GenNodeInfo.getDesc(Opcode).hasFlag(SDNFIsStrictFP);
217+
return false;
218+
}
219+
220+
void verifyTargetNode(const SelectionDAG &DAG,
221+
const SDNode *N) const override {
222+
if (GenNodeInfo.hasDesc(N->getOpcode()))
223+
GenNodeInfo.verifyNode(DAG, N);
224+
}
225+
};
226+
179227
} // end namespace llvm
180228

181229
#endif // LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H

llvm/include/llvm/CodeGen/TargetLowering.h

-5
Original file line numberDiff line numberDiff line change
@@ -4989,11 +4989,6 @@ class TargetLowering : public TargetLoweringBase {
49894989
bool verifyReturnAddressArgumentIsConstant(SDValue Op,
49904990
SelectionDAG &DAG) const;
49914991

4992-
#ifndef NDEBUG
4993-
/// Check the given SDNode. Aborts if it is invalid.
4994-
virtual void verifyTargetSDNode(const SDNode *N) const {};
4995-
#endif
4996-
49974992
//===--------------------------------------------------------------------===//
49984993
// Inline Asm Support hooks
49994994
//

llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_llvm_component_library(LLVMSelectionDAG
1111
LegalizeVectorOps.cpp
1212
LegalizeVectorTypes.cpp
1313
ResourcePriorityQueue.cpp
14+
SDNodeInfo.cpp
1415
ScheduleDAGFast.cpp
1516
ScheduleDAGRRList.cpp
1617
ScheduleDAGSDNodes.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//==------------------------------------------------------------------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/CodeGen/SDNodeInfo.h"
10+
#include "llvm/CodeGen/SelectionDAGNodes.h"
11+
12+
using namespace llvm;
13+
14+
static void reportNodeError(const SelectionDAG &DAG, const SDNode *N,
15+
const Twine &Msg) {
16+
std::string S;
17+
raw_string_ostream SS(S);
18+
SS << "invalid node: " << Msg << '\n';
19+
N->printrWithDepth(SS, &DAG, 2);
20+
report_fatal_error(StringRef(S));
21+
}
22+
23+
static void checkResultType(const SelectionDAG &DAG, const SDNode *N,
24+
unsigned ResIdx, EVT ExpectedVT) {
25+
EVT ActualVT = N->getValueType(ResIdx);
26+
if (ActualVT != ExpectedVT)
27+
reportNodeError(
28+
DAG, N,
29+
"result #" + Twine(ResIdx) + " has invalid type; expected " +
30+
ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString());
31+
}
32+
33+
static void checkOperandType(const SelectionDAG &DAG, const SDNode *N,
34+
unsigned OpIdx, EVT ExpectedVT) {
35+
EVT ActualVT = N->getOperand(OpIdx).getValueType();
36+
if (ActualVT != ExpectedVT)
37+
reportNodeError(
38+
DAG, N,
39+
"operand #" + Twine(OpIdx) + " has invalid type; expected " +
40+
ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString());
41+
}
42+
43+
void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
44+
const SDNodeDesc &Desc = getDesc(N->getOpcode());
45+
bool HasChain = Desc.hasProperty(SDNPHasChain);
46+
bool HasOutGlue = Desc.hasProperty(SDNPOutGlue);
47+
bool HasInGlue = Desc.hasProperty(SDNPInGlue);
48+
bool HasOptInGlue = Desc.hasProperty(SDNPOptInGlue);
49+
bool IsVariadic = Desc.hasProperty(SDNPVariadic);
50+
51+
unsigned ActualNumResults = N->getNumValues();
52+
unsigned ExpectedNumResults = Desc.NumResults + HasChain + HasOutGlue;
53+
54+
if (ActualNumResults != ExpectedNumResults)
55+
reportNodeError(DAG, N,
56+
"invalid number of results; expected " +
57+
Twine(ExpectedNumResults) + ", got " +
58+
Twine(ActualNumResults));
59+
60+
// Chain result comes after all normal results.
61+
if (HasChain) {
62+
unsigned ChainResIdx = Desc.NumResults;
63+
checkResultType(DAG, N, ChainResIdx, MVT::Other);
64+
}
65+
66+
// Glue result comes last.
67+
if (HasOutGlue) {
68+
unsigned GlueResIdx = Desc.NumResults + HasChain;
69+
checkResultType(DAG, N, GlueResIdx, MVT::Glue);
70+
}
71+
72+
// In the most general case, the operands of a node go in the following order:
73+
// chain, fix#0, ..., fix#M-1, var#0, ... var#N-1, glue
74+
// If the number of operands is < 0, M can be any;
75+
// If the node has SDNPVariadic property, N can be any.
76+
bool HasOptionalOperands = Desc.NumOperands < 0 || IsVariadic;
77+
78+
unsigned ActualNumOperands = N->getNumOperands();
79+
unsigned ExpectedMinNumOperands =
80+
(Desc.NumOperands >= 0 ? Desc.NumOperands : 0) + HasChain + HasInGlue;
81+
82+
// Check the lower bound.
83+
if (ActualNumOperands < ExpectedMinNumOperands) {
84+
StringRef How = HasOptionalOperands ? "at least " : "";
85+
reportNodeError(DAG, N,
86+
"invalid number of operands; expected " + How +
87+
Twine(ExpectedMinNumOperands) + ", got " +
88+
Twine(ActualNumOperands));
89+
}
90+
91+
// Check the upper bound. We can only do this if the number of fixed operands
92+
// is known and there are no variadic operands.
93+
if (Desc.NumOperands >= 0 && !IsVariadic) {
94+
// Account for optional input glue.
95+
unsigned ExpectedMaxNumOperands = ExpectedMinNumOperands + HasOptInGlue;
96+
if (ActualNumOperands > ExpectedMaxNumOperands) {
97+
StringRef How = HasOptInGlue ? "at most " : "";
98+
reportNodeError(DAG, N,
99+
"invalid number of operands; expected " + How +
100+
Twine(ExpectedMaxNumOperands) + ", got " +
101+
Twine(ActualNumOperands));
102+
}
103+
}
104+
105+
// Chain operand comes first.
106+
if (HasChain)
107+
checkOperandType(DAG, N, 0, MVT::Other);
108+
109+
// Glue operand comes last.
110+
if (HasInGlue)
111+
checkOperandType(DAG, N, ActualNumOperands - 1, MVT::Glue);
112+
if (HasOptInGlue && ActualNumOperands >= 1 &&
113+
N->getOperand(ActualNumOperands - 1).getValueType() == MVT::Glue)
114+
HasInGlue = true;
115+
116+
// Check variadic operands. These should be Register or RegisterMask.
117+
if (IsVariadic && Desc.NumOperands >= 0) {
118+
unsigned VarOpStart = HasChain + Desc.NumOperands;
119+
unsigned VarOpEnd = ActualNumOperands - HasInGlue;
120+
for (unsigned OpIdx = VarOpStart; OpIdx != VarOpEnd; ++OpIdx) {
121+
unsigned OpOpcode = N->getOperand(OpIdx).getOpcode();
122+
if (OpOpcode != ISD::Register && OpOpcode != ISD::RegisterMask)
123+
reportNodeError(DAG, N,
124+
"variadic operand #" + Twine(OpIdx) +
125+
" must be Register or RegisterMask");
126+
}
127+
}
128+
}

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -1146,11 +1146,11 @@ void SelectionDAG::DeallocateNode(SDNode *N) {
11461146

11471147
#ifndef NDEBUG
11481148
/// VerifySDNode - Check the given SDNode. Aborts if it is invalid.
1149-
static void VerifySDNode(SDNode *N, const TargetLowering *TLI) {
1149+
void SelectionDAG::verifyNode(SDNode *N) const {
11501150
switch (N->getOpcode()) {
11511151
default:
1152-
if (N->getOpcode() > ISD::BUILTIN_OP_END)
1153-
TLI->verifyTargetSDNode(N);
1152+
if (N->isTargetOpcode())
1153+
getSelectionDAGInfo().verifyTargetNode(*this, N);
11541154
break;
11551155
case ISD::BUILD_PAIR: {
11561156
EVT VT = N->getValueType(0);
@@ -1194,7 +1194,7 @@ void SelectionDAG::InsertNode(SDNode *N) {
11941194
AllNodes.push_back(N);
11951195
#ifndef NDEBUG
11961196
N->PersistentId = NextPersistentId++;
1197-
VerifySDNode(N, TLI);
1197+
verifyNode(N);
11981198
#endif
11991199
for (DAGUpdateListener *DUL = UpdateListeners; DUL; DUL = DUL->Next)
12001200
DUL->NodeInserted(N);

llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/CodeGen/MachineMemOperand.h"
2222
#include "llvm/CodeGen/SelectionDAG.h"
2323
#include "llvm/CodeGen/SelectionDAGNodes.h"
24+
#include "llvm/CodeGen/SelectionDAGTargetInfo.h"
2425
#include "llvm/CodeGen/TargetInstrInfo.h"
2526
#include "llvm/CodeGen/TargetLowering.h"
2627
#include "llvm/CodeGen/TargetRegisterInfo.h"
@@ -67,6 +68,9 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
6768
return "<<Unknown Machine Node #" + utostr(getOpcode()) + ">>";
6869
}
6970
if (G) {
71+
const SelectionDAGTargetInfo &TSI = G->getSelectionDAGInfo();
72+
if (const char *Name = TSI.getTargetNodeName(getOpcode()))
73+
return Name;
7074
const TargetLowering &TLI = G->getTargetLoweringInfo();
7175
const char *Name = TLI.getTargetNodeName(getOpcode());
7276
if (Name) return Name;

0 commit comments

Comments
 (0)