-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[SelectionDAG] Wire up -gen-sdnode-info TableGen backend #125358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
4b2c60b
c233ee9
1f9d21d
ae09fa6
1c2529d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
//==------------------------------------------------------------------------==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_INCLUDE_LLVM_CODEGEN_SDNODEINFO_H | ||
#define LLVM_INCLUDE_LLVM_CODEGEN_SDNODEINFO_H | ||
|
||
#include "ISDOpcodes.h" | ||
#include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/ADT/StringTable.h" | ||
#include "llvm/CodeGenTypes/MachineValueType.h" | ||
|
||
namespace llvm { | ||
|
||
class SDNode; | ||
class SelectionDAG; | ||
|
||
enum SDNP { | ||
SDNPHasChain, | ||
SDNPOutGlue, | ||
SDNPInGlue, | ||
SDNPOptInGlue, | ||
SDNPMemOperand, | ||
SDNPVariadic, | ||
}; | ||
|
||
enum SDTC { | ||
topperc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
SDTCisVT, | ||
SDTCisPtrTy, | ||
SDTCisInt, | ||
SDTCisFP, | ||
SDTCisVec, | ||
SDTCisSameAs, | ||
SDTCisVTSmallerThanOp, | ||
SDTCisOpSmallerThanOp, | ||
SDTCisEltOfVec, | ||
SDTCisSubVecOfVec, | ||
SDTCVecEltisVT, | ||
SDTCisSameNumEltsAs, | ||
SDTCisSameSizeAs, | ||
}; | ||
|
||
enum SDNF { | ||
SDNFIsStrictFP, | ||
}; | ||
|
||
struct SDTypeConstraint { | ||
SDTC Kind; | ||
uint8_t OpNo; | ||
uint8_t OtherOpNo; | ||
MVT::SimpleValueType VT; | ||
}; | ||
|
||
struct SDNodeDesc { | ||
unsigned NumResults; | ||
topperc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
int NumOperands; | ||
uint32_t Properties; | ||
uint32_t Flags; | ||
uint32_t TSFlags; | ||
unsigned NameOffset; | ||
unsigned ConstraintOffset; | ||
unsigned ConstraintCount; | ||
|
||
bool hasProperty(SDNP Property) const { return Properties & (1 << Property); } | ||
|
||
bool hasFlag(SDNF Flag) const { return Flags & (1 << Flag); } | ||
}; | ||
|
||
class SDNodeInfo final { | ||
unsigned NumOpcodes; | ||
const SDNodeDesc *Descs; | ||
StringTable Names; | ||
const SDTypeConstraint *Constraints; | ||
|
||
public: | ||
constexpr SDNodeInfo(unsigned NumOpcodes, const SDNodeDesc *Descs, | ||
StringTable Names, const SDTypeConstraint *Constraints) | ||
: NumOpcodes(NumOpcodes), Descs(Descs), Names(Names), | ||
Constraints(Constraints) {} | ||
|
||
/// Returns true if there is a generated description for a node with the given | ||
/// target-specific opcode. | ||
bool hasDesc(unsigned Opcode) const { | ||
assert(Opcode >= ISD::BUILTIN_OP_END && "Expected target-specific opcode"); | ||
return Opcode < ISD::BUILTIN_OP_END + NumOpcodes; | ||
} | ||
|
||
/// Returns the description of a node with the given opcode. | ||
const SDNodeDesc &getDesc(unsigned Opcode) const { | ||
assert(hasDesc(Opcode)); | ||
return Descs[Opcode - ISD::BUILTIN_OP_END]; | ||
} | ||
|
||
/// Returns operand constraints for a node with the given opcode. | ||
ArrayRef<SDTypeConstraint> getConstraints(unsigned Opcode) const { | ||
const SDNodeDesc &Desc = getDesc(Opcode); | ||
return ArrayRef(&Constraints[Desc.ConstraintOffset], Desc.ConstraintCount); | ||
} | ||
|
||
/// Returns the name of the given target-specific opcode, suitable for | ||
/// debug printing. | ||
StringRef getName(unsigned Opcode) const { | ||
return Names[getDesc(Opcode).NameOffset]; | ||
} | ||
|
||
void verifyNode(const SelectionDAG &DAG, const SDNode *N) const; | ||
}; | ||
|
||
} // namespace llvm | ||
|
||
#endif // LLVM_INCLUDE_LLVM_CODEGEN_SDNODEINFO_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
//==------------------------------------------------------------------------==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "llvm/CodeGen/SDNodeInfo.h" | ||
#include "llvm/CodeGen/SelectionDAGNodes.h" | ||
|
||
using namespace llvm; | ||
|
||
static void reportNodeError(const SelectionDAG &DAG, const SDNode *N, | ||
const Twine &Msg) { | ||
std::string S; | ||
raw_string_ostream SS(S); | ||
SS << "invalid node: " << Msg << '\n'; | ||
N->printrWithDepth(SS, &DAG, 2); | ||
report_fatal_error(StringRef(S)); | ||
} | ||
|
||
static void checkResultType(const SelectionDAG &DAG, const SDNode *N, | ||
unsigned ResIdx, EVT ExpectedVT) { | ||
EVT ActualVT = N->getValueType(ResIdx); | ||
if (ActualVT != ExpectedVT) | ||
reportNodeError( | ||
DAG, N, | ||
"result #" + Twine(ResIdx) + " has invalid type; expected " + | ||
ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString()); | ||
} | ||
|
||
static void checkOperandType(const SelectionDAG &DAG, const SDNode *N, | ||
unsigned OpIdx, EVT ExpectedVT) { | ||
EVT ActualVT = N->getOperand(OpIdx).getValueType(); | ||
if (ActualVT != ExpectedVT) | ||
reportNodeError( | ||
DAG, N, | ||
"operand #" + Twine(OpIdx) + " has invalid type; expected " + | ||
ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString()); | ||
} | ||
|
||
void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently this only verifies basic SDNode "prototype" -- the number of operands/results and the types of chain/glue operands/results. I refrained from making use of the imported SDTypeProfile in this patch to keep it smaller (and I need to spend more time on implementing proper type profile checking anyway). |
||
const SDNodeDesc &Desc = getDesc(N->getOpcode()); | ||
bool HasChain = Desc.hasProperty(SDNPHasChain); | ||
bool HasOutGlue = Desc.hasProperty(SDNPOutGlue); | ||
bool HasInGlue = Desc.hasProperty(SDNPInGlue); | ||
bool HasOptInGlue = Desc.hasProperty(SDNPOptInGlue); | ||
bool IsVariadic = Desc.hasProperty(SDNPVariadic); | ||
|
||
unsigned ActualNumResults = N->getNumValues(); | ||
unsigned ExpectedNumResults = Desc.NumResults + HasChain + HasOutGlue; | ||
|
||
if (ActualNumResults != ExpectedNumResults) | ||
reportNodeError(DAG, N, | ||
"invalid number of results; expected " + | ||
Twine(ExpectedNumResults) + ", got " + | ||
Twine(ActualNumResults)); | ||
|
||
// Chain result comes after all normal results. | ||
if (HasChain) { | ||
unsigned ChainResIdx = Desc.NumResults; | ||
checkResultType(DAG, N, ChainResIdx, MVT::Other); | ||
} | ||
|
||
// Glue result comes last. | ||
if (HasOutGlue) { | ||
unsigned GlueResIdx = Desc.NumResults + HasChain; | ||
checkResultType(DAG, N, GlueResIdx, MVT::Glue); | ||
} | ||
|
||
// In the most general case, the operands of a node go in the following order: | ||
// chain, fix#0, ..., fix#M-1, var#0, ... var#N-1, glue | ||
// If the number of operands is < 0, M can be any; | ||
// If the node has SDNPVariadic property, N can be any. | ||
bool HasOptionalOperands = Desc.NumOperands < 0 || IsVariadic; | ||
|
||
unsigned ActualNumOperands = N->getNumOperands(); | ||
unsigned ExpectedMinNumOperands = | ||
(Desc.NumOperands >= 0 ? Desc.NumOperands : 0) + HasChain + HasInGlue; | ||
|
||
// Check the lower bound. | ||
if (ActualNumOperands < ExpectedMinNumOperands) { | ||
StringRef How = HasOptionalOperands ? "at least " : ""; | ||
reportNodeError(DAG, N, | ||
"invalid number of operands; expected " + How + | ||
Twine(ExpectedMinNumOperands) + ", got " + | ||
Twine(ActualNumOperands)); | ||
} | ||
|
||
// Check the upper bound. We can only do this if the number of fixed operands | ||
// is known and there are no variadic operands. | ||
if (Desc.NumOperands >= 0 && !IsVariadic) { | ||
// Account for optional input glue. | ||
unsigned ExpectedMaxNumOperands = ExpectedMinNumOperands + HasOptInGlue; | ||
if (ActualNumOperands > ExpectedMaxNumOperands) { | ||
StringRef How = HasOptInGlue ? "at most " : ""; | ||
reportNodeError(DAG, N, | ||
"invalid number of operands; expected " + How + | ||
Twine(ExpectedMaxNumOperands) + ", got " + | ||
Twine(ActualNumOperands)); | ||
} | ||
} | ||
|
||
// Chain operand comes first. | ||
if (HasChain) | ||
checkOperandType(DAG, N, 0, MVT::Other); | ||
|
||
// Glue operand comes last. | ||
if (HasInGlue) | ||
checkOperandType(DAG, N, ActualNumOperands - 1, MVT::Glue); | ||
if (HasOptInGlue && ActualNumOperands >= 1 && | ||
N->getOperand(ActualNumOperands - 1).getValueType() == MVT::Glue) | ||
HasInGlue = true; | ||
|
||
// Check variadic operands. These should be Register or RegisterMask. | ||
if (IsVariadic && Desc.NumOperands >= 0) { | ||
unsigned VarOpStart = HasChain + Desc.NumOperands; | ||
unsigned VarOpEnd = ActualNumOperands - HasInGlue; | ||
for (unsigned OpIdx = VarOpStart; OpIdx != VarOpEnd; ++OpIdx) { | ||
unsigned OpOpcode = N->getOperand(OpIdx).getOpcode(); | ||
if (OpOpcode != ISD::Register && OpOpcode != ISD::RegisterMask) | ||
reportNodeError(DAG, N, | ||
"variadic operand #" + Twine(OpIdx) + | ||
" must be Register or RegisterMask"); | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.