-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[TableGen][GISel] Refactor node renderers emission #121071
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
[TableGen][GISel] Refactor node renderers emission #121071
Conversation
95185b4
to
81d1730
Compare
@llvm/pr-subscribers-tablegen @llvm/pr-subscribers-llvm-globalisel Author: Sergei Barannikov (s-barannikov) ChangesSplit importExplicitUseRenderer into several smaller functions and add a bunch of TODOs and FIXMEs. This is an NFCI change to simplify review of future functional changes. Full diff: https://github.com/llvm/llvm-project/pull/121071.diff 1 Files Affected:
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 4250b57581f63e..6872622af6ab3d 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -412,10 +412,23 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
importExplicitUseRenderers(action_iterator InsertPt, RuleMatcher &M,
BuildMIAction &DstMIBuilder,
const TreePatternNode &Dst) const;
- Expected<action_iterator>
- importExplicitUseRenderer(action_iterator InsertPt, RuleMatcher &Rule,
- BuildMIAction &DstMIBuilder,
- const TreePatternNode &Dst) const;
+
+ Error importNamedNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
+ const TreePatternNode &N) const;
+
+ Error importLeafNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
+ const TreePatternNode &N) const;
+
+ Error importXFormNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
+ const TreePatternNode &N) const;
+
+ Error importInstructionNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
+ const TreePatternNode &N,
+ action_iterator &InsertPt) const;
+
+ Error importNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
+ const TreePatternNode &N,
+ action_iterator &InsertPt) const;
Error importDefaultOperandRenderers(action_iterator InsertPt, RuleMatcher &M,
BuildMIAction &DstMIBuilder,
const DAGDefaultOperand &DefaultOp) const;
@@ -1192,162 +1205,207 @@ Error GlobalISelEmitter::importChildMatcher(
return failedImport("Src pattern child is an unsupported kind");
}
-Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
- action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
- const TreePatternNode &Dst) const {
+// Equivalent of MatcherGen::EmitResultOfNamedOperand.
+Error GlobalISelEmitter::importNamedNodeRenderer(
+ RuleMatcher &M, BuildMIAction &MIBuilder, const TreePatternNode &N) const {
+ StringRef NodeName = N.getName();
- const auto &SubOperand = Rule.getComplexSubOperand(Dst.getName());
- if (SubOperand) {
- DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
- *std::get<0>(*SubOperand), Dst.getName(), std::get<1>(*SubOperand),
- std::get<2>(*SubOperand));
- return InsertPt;
+ if (auto SubOperand = M.getComplexSubOperand(NodeName)) {
+ auto [ComplexPatternRec, RendererID, SubOperandIdx] = *SubOperand;
+ MIBuilder.addRenderer<RenderComplexPatternOperand>(
+ *ComplexPatternRec, NodeName, RendererID, SubOperandIdx);
+ return Error::success();
}
- if (!Dst.isLeaf()) {
- if (Dst.getOperator()->isSubClassOf("SDNodeXForm")) {
- auto &Child = Dst.getChild(0);
- auto I = SDNodeXFormEquivs.find(Dst.getOperator());
- if (I != SDNodeXFormEquivs.end()) {
- const Record *XFormOpc = Dst.getOperator()->getValueAsDef("Opcode");
- if (XFormOpc->getName() == "timm") {
- // If this is a TargetConstant, there won't be a corresponding
- // instruction to transform. Instead, this will refer directly to an
- // operand in an instruction's operand list.
- DstMIBuilder.addRenderer<CustomOperandRenderer>(*I->second,
- Child.getName());
- } else {
- DstMIBuilder.addRenderer<CustomRenderer>(*I->second, Child.getName());
- }
-
- return InsertPt;
- }
- return failedImport("SDNodeXForm " + Child.getName() +
- " has no custom renderer");
- }
+ if (!N.isLeaf()) {
+ StringRef OperatorName = N.getOperator()->getName();
- // We accept 'bb' here. It's an operator because BasicBlockSDNode isn't
- // inline, but in MI it's just another operand.
- if (Dst.getOperator()->isSubClassOf("SDNode")) {
- auto &ChildSDNI = CGP.getSDNodeInfo(Dst.getOperator());
- if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") {
- DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
- return InsertPt;
- }
+ if (OperatorName == "imm") {
+ MIBuilder.addRenderer<CopyConstantAsImmRenderer>(NodeName);
+ return Error::success();
}
- // Similarly, imm is an operator in TreePatternNode's view but must be
- // rendered as operands.
- // FIXME: The target should be able to choose sign-extended when appropriate
- // (e.g. on Mips).
- if (Dst.getOperator()->getName() == "timm") {
- DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
- return InsertPt;
- }
- if (Dst.getOperator()->getName() == "tframeindex") {
- DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
- return InsertPt;
- }
- if (Dst.getOperator()->getName() == "imm") {
- DstMIBuilder.addRenderer<CopyConstantAsImmRenderer>(Dst.getName());
- return InsertPt;
- }
- if (Dst.getOperator()->getName() == "fpimm") {
- DstMIBuilder.addRenderer<CopyFConstantAsFPImmRenderer>(Dst.getName());
- return InsertPt;
+ if (OperatorName == "fpimm") {
+ MIBuilder.addRenderer<CopyFConstantAsFPImmRenderer>(NodeName);
+ return Error::success();
}
- if (Dst.getOperator()->isSubClassOf("Instruction")) {
- auto OpTy = getInstResultType(Dst, Target);
- if (!OpTy)
- return OpTy.takeError();
-
- unsigned TempRegID = Rule.allocateTempRegID();
- InsertPt =
- Rule.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
- DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
-
- auto InsertPtOrError = createAndImportSubInstructionRenderer(
- ++InsertPt, Rule, Dst, TempRegID);
- if (auto Error = InsertPtOrError.takeError())
- return std::move(Error);
- return InsertPtOrError.get();
+ // TODO: 'imm' and 'fpimm' are the only nodes that need special treatment.
+ // Remove this check and add CopyRenderer unconditionally for other nodes.
+ if (OperatorName == "bb" || OperatorName == "timm" ||
+ OperatorName == "tframeindex") {
+ MIBuilder.addRenderer<CopyRenderer>(NodeName);
+ return Error::success();
}
- return failedImport("Dst pattern child isn't a leaf node or an MBB" +
- llvm::to_string(Dst));
+ return failedImport("node has unsupported operator " + to_string(N));
}
- // It could be a specific immediate in which case we should just check for
- // that immediate.
- if (const IntInit *ChildIntInit = dyn_cast<IntInit>(Dst.getLeafValue())) {
- DstMIBuilder.addRenderer<ImmRenderer>(ChildIntInit->getValue());
- return InsertPt;
- }
-
- // Otherwise, we're looking for a bog-standard RegisterClass operand.
- if (auto *ChildDefInit = dyn_cast<DefInit>(Dst.getLeafValue())) {
- auto *ChildRec = ChildDefInit->getDef();
+ if (const auto *DI = dyn_cast<DefInit>(N.getLeafValue())) {
+ const Record *R = DI->getDef();
- ArrayRef<TypeSetByHwMode> ChildTypes = Dst.getExtTypes();
- if (ChildTypes.size() != 1)
- return failedImport("Dst pattern child has multiple results");
+ if (N.getNumResults() != 1)
+ return failedImport("node does not have one result " + to_string(N));
std::optional<LLTCodeGen> OpTyOrNone;
+ ArrayRef<TypeSetByHwMode> ChildTypes = N.getExtTypes();
if (ChildTypes.front().isMachineValueType())
OpTyOrNone = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
+
+ // TODO: Remove this check. Types in the destination DAG should not matter.
if (!OpTyOrNone)
- return failedImport("Dst operand has an unsupported type");
+ return failedImport("node has unsupported type " + to_string(N));
- if (ChildRec->isSubClassOf("Register")) {
- DstMIBuilder.addRenderer<AddRegisterRenderer>(Target, ChildRec);
- return InsertPt;
- }
+ if (R->isSubClassOf("ComplexPattern")) {
+ auto I = ComplexPatternEquivs.find(R);
+ if (I == ComplexPatternEquivs.end())
+ return failedImport("ComplexPattern " + R->getName() +
+ " does not have GISel equivalent");
- if (ChildRec->isSubClassOf("RegisterClass") ||
- ChildRec->isSubClassOf("RegisterOperand") ||
- ChildRec->isSubClassOf("ValueType")) {
- if (ChildRec->isSubClassOf("RegisterOperand") &&
- !ChildRec->isValueUnset("GIZeroRegister")) {
- DstMIBuilder.addRenderer<CopyOrAddZeroRegRenderer>(
- Dst.getName(), ChildRec->getValueAsDef("GIZeroRegister"));
- return InsertPt;
- }
+ const OperandMatcher &OM = M.getOperandMatcher(NodeName);
+ MIBuilder.addRenderer<RenderComplexPatternOperand>(
+ *I->second, NodeName, OM.getAllocatedTemporariesBaseID());
+ return Error::success();
+ }
- DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
- return InsertPt;
+ if (R->isSubClassOf("RegisterOperand") &&
+ !R->isValueUnset("GIZeroRegister")) {
+ MIBuilder.addRenderer<CopyOrAddZeroRegRenderer>(
+ NodeName, R->getValueAsDef("GIZeroRegister"));
+ return Error::success();
}
- if (ChildRec->isSubClassOf("SubRegIndex")) {
- CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(ChildRec);
- DstMIBuilder.addRenderer<ImmRenderer>(SubIdx->EnumValue);
- return InsertPt;
+ // TODO: All special cases are handled above. Remove this check and add
+ // CopyRenderer unconditionally.
+ if (R->isSubClassOf("RegisterClass") ||
+ R->isSubClassOf("RegisterOperand") || R->isSubClassOf("ValueType")) {
+ MIBuilder.addRenderer<CopyRenderer>(NodeName);
+ return Error::success();
}
+ }
- if (ChildRec->isSubClassOf("ComplexPattern")) {
- const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec);
- if (ComplexPattern == ComplexPatternEquivs.end())
- return failedImport(
- "SelectionDAG ComplexPattern not mapped to GlobalISel");
+ // TODO: Change this to assert and move to the beginning of the function.
+ if (!M.hasOperand(NodeName))
+ return failedImport("could not find node $" + NodeName +
+ " in the source DAG");
- const OperandMatcher &OM = Rule.getOperandMatcher(Dst.getName());
- DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
- *ComplexPattern->second, Dst.getName(),
- OM.getAllocatedTemporariesBaseID());
- return InsertPt;
+ // TODO: Remove this check and add CopyRenderer unconditionally.
+ // TODO: Handle nodes with multiple results (provided they can reach here).
+ if (isa<UnsetInit>(N.getLeafValue())) {
+ MIBuilder.addRenderer<CopyRenderer>(NodeName);
+ return Error::success();
+ }
+
+ return failedImport("unsupported node " + to_string(N));
+}
+
+// Equivalent of MatcherGen::EmitResultLeafAsOperand.
+Error GlobalISelEmitter::importLeafNodeRenderer(
+ RuleMatcher &M, BuildMIAction &MIBuilder, const TreePatternNode &N) const {
+ if (const auto *II = dyn_cast<IntInit>(N.getLeafValue())) {
+ MIBuilder.addRenderer<ImmRenderer>(II->getValue());
+ return Error::success();
+ }
+
+ if (const auto *DI = dyn_cast<DefInit>(N.getLeafValue())) {
+ const Record *R = DI->getDef();
+
+ if (R->isSubClassOf("Register")) {
+ MIBuilder.addRenderer<AddRegisterRenderer>(Target, R);
+ return Error::success();
}
- return failedImport(
- "Dst pattern child def is an unsupported tablegen class");
+ if (R->isSubClassOf("SubRegIndex")) {
+ const CodeGenSubRegIndex *SubRegIndex = CGRegs.getSubRegIdx(R);
+ MIBuilder.addRenderer<ImmRenderer>(SubRegIndex->EnumValue);
+ return Error::success();
+ }
+
+ // There are also RegisterClass / RegisterOperand operands of REG_SEQUENCE /
+ // COPY_TO_REGCLASS, but these instructions are currently handled elsewhere.
}
- // Handle the case where the MVT/register class is omitted in the dest pattern
- // but MVT exists in the source pattern.
- if (isa<UnsetInit>(Dst.getLeafValue()) && Rule.hasOperand(Dst.getName())) {
- DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
- return InsertPt;
+ return failedImport("unrecognized node " + to_string(N));
+}
+
+// Equivalent of MatcherGen::EmitResultSDNodeXFormAsOperand.
+Error GlobalISelEmitter::importXFormNodeRenderer(
+ RuleMatcher &M, BuildMIAction &MIBuilder, const TreePatternNode &N) const {
+ const Record *XFormRec = N.getOperator();
+ auto I = SDNodeXFormEquivs.find(XFormRec);
+ if (I == SDNodeXFormEquivs.end())
+ return failedImport("SDNodeXForm " + XFormRec->getName() +
+ " does not have GISel equivalent");
+
+ // TODO: Fail to import if GISDNodeXForm does not have RendererFn.
+ // This currently results in a fatal error in emitRenderOpcodes.
+ const Record *XFormEquivRec = I->second;
+
+ // The node to apply the transformation function to.
+ // FIXME: The node may not have a name and may be a leaf. It should be
+ // rendered first, like any other nodes. This may or may not require
+ // introducing a temporary register, and we can tell that without inspecting
+ // the node (possibly recursively). This is a general drawback of appending
+ // renderers directly to BuildMIAction.
+ const TreePatternNode &Node = N.getChild(0);
+ StringRef NodeName = Node.getName();
+
+ const Record *XFormOpc = CGP.getSDNodeTransform(XFormRec).first;
+ if (XFormOpc->getName() == "timm") {
+ // If this is a TargetConstant, there won't be a corresponding
+ // instruction to transform. Instead, this will refer directly to an
+ // operand in an instruction's operand list.
+ MIBuilder.addRenderer<CustomOperandRenderer>(*XFormEquivRec, NodeName);
+ } else {
+ MIBuilder.addRenderer<CustomRenderer>(*XFormEquivRec, NodeName);
}
- return failedImport("Dst pattern child is an unsupported kind");
+
+ return Error::success();
+}
+
+// Equivalent of MatcherGen::EmitResultInstructionAsOperand.
+Error GlobalISelEmitter::importInstructionNodeRenderer(
+ RuleMatcher &M, BuildMIAction &MIBuilder, const TreePatternNode &N,
+ action_iterator &InsertPt) const {
+ Expected<LLTCodeGen> OpTy = getInstResultType(N, Target);
+ if (!OpTy)
+ return OpTy.takeError();
+
+ // TODO: See the comment in importXFormNodeRenderer. We rely on the node
+ // requiring a temporary register, which prevents us from using this
+ // function on the root of the destination DAG.
+ unsigned TempRegID = M.allocateTempRegID();
+ InsertPt = M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
+ MIBuilder.addRenderer<TempRegRenderer>(TempRegID);
+
+ auto InsertPtOrError =
+ createAndImportSubInstructionRenderer(++InsertPt, M, N, TempRegID);
+ if (!InsertPtOrError)
+ return InsertPtOrError.takeError();
+
+ InsertPt = *InsertPtOrError;
+ return Error::success();
+}
+
+// Equivalent of MatcherGen::EmitResultOperand.
+Error GlobalISelEmitter::importNodeRenderer(RuleMatcher &M,
+ BuildMIAction &MIBuilder,
+ const TreePatternNode &N,
+ action_iterator &InsertPt) const {
+ if (N.hasName())
+ return importNamedNodeRenderer(M, MIBuilder, N);
+
+ if (N.isLeaf())
+ return importLeafNodeRenderer(M, MIBuilder, N);
+
+ if (N.getOperator()->isSubClassOf("SDNodeXForm"))
+ return importXFormNodeRenderer(M, MIBuilder, N);
+
+ if (N.getOperator()->isSubClassOf("Instruction"))
+ return importInstructionNodeRenderer(M, MIBuilder, N, InsertPt);
+
+ // Should not reach here.
+ return failedImport("unrecognized node " + llvm::to_string(N));
}
/// Generates code that builds the resulting instruction(s) from the destination
@@ -1601,11 +1659,9 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
dyn_cast<DefInit>(SubRegChild.getLeafValue())) {
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
- auto InsertPtOrError =
- importExplicitUseRenderer(InsertPt, M, DstMIBuilder, ValChild);
- if (auto Error = InsertPtOrError.takeError())
- return std::move(Error);
- InsertPt = InsertPtOrError.get();
+ if (Error Err = importNodeRenderer(M, DstMIBuilder, ValChild, InsertPt))
+ return Err;
+
DstMIBuilder.addRenderer<SubRegIndexRenderer>(SubIdx);
}
}
@@ -1670,11 +1726,10 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
continue;
}
- auto InsertPtOrError = importExplicitUseRenderer(InsertPt, M, DstMIBuilder,
- Dst.getChild(Child));
- if (auto Error = InsertPtOrError.takeError())
- return std::move(Error);
- InsertPt = InsertPtOrError.get();
+ if (Error Err =
+ importNodeRenderer(M, DstMIBuilder, Dst.getChild(Child), InsertPt))
+ return Err;
+
++Child;
}
|
There are several commits that should make the review easier. |
8c10371
to
b06dc04
Compare
b06dc04
to
847fadd
Compare
Split importExplicitUseRenderer into several smaller functions and add a bunch of TODOs and FIXMEs. This is an NFCI change to simplify review of future functional changes. Pull Request: llvm/llvm-project#121071
Split importExplicitUseRenderer into several smaller functions and add a bunch of TODOs and FIXMEs.
This is an NFCI change to simplify review of future functional changes.