Skip to content

Commit a0e1fcc

Browse files
authored
[TableGen][GISel] Refactor node renderers emission (#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. Pull Request: #121071
1 parent 6f72d28 commit a0e1fcc

File tree

1 file changed

+195
-136
lines changed

1 file changed

+195
-136
lines changed

llvm/utils/TableGen/GlobalISelEmitter.cpp

Lines changed: 195 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,24 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
413413
importExplicitUseRenderers(action_iterator InsertPt, RuleMatcher &M,
414414
BuildMIAction &DstMIBuilder,
415415
const TreePatternNode &Dst) const;
416-
Expected<action_iterator>
417-
importExplicitUseRenderer(action_iterator InsertPt, RuleMatcher &Rule,
418-
BuildMIAction &DstMIBuilder,
419-
const TreePatternNode &Dst) const;
416+
417+
Error importNamedNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
418+
const TreePatternNode &N) const;
419+
420+
Error importLeafNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
421+
const TreePatternNode &N) const;
422+
423+
Error importXFormNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
424+
const TreePatternNode &N) const;
425+
426+
Error importInstructionNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
427+
const TreePatternNode &N,
428+
action_iterator &InsertPt) const;
429+
430+
Error importNodeRenderer(RuleMatcher &M, BuildMIAction &MIBuilder,
431+
const TreePatternNode &N,
432+
action_iterator &InsertPt) const;
433+
420434
Error importDefaultOperandRenderers(action_iterator InsertPt, RuleMatcher &M,
421435
BuildMIAction &DstMIBuilder,
422436
const DAGDefaultOperand &DefaultOp) const;
@@ -1190,159 +1204,207 @@ Error GlobalISelEmitter::importChildMatcher(
11901204
return failedImport("Src pattern child is an unsupported kind");
11911205
}
11921206

1193-
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
1194-
action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
1195-
const TreePatternNode &Dst) const {
1207+
// Equivalent of MatcherGen::EmitResultOfNamedOperand.
1208+
Error GlobalISelEmitter::importNamedNodeRenderer(
1209+
RuleMatcher &M, BuildMIAction &MIBuilder, const TreePatternNode &N) const {
1210+
StringRef NodeName = N.getName();
11961211

1197-
const auto &SubOperand = Rule.getComplexSubOperand(Dst.getName());
1198-
if (SubOperand) {
1199-
DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
1200-
*std::get<0>(*SubOperand), Dst.getName(), std::get<1>(*SubOperand),
1201-
std::get<2>(*SubOperand));
1202-
return InsertPt;
1212+
if (auto SubOperand = M.getComplexSubOperand(NodeName)) {
1213+
auto [ComplexPatternRec, RendererID, SubOperandIdx] = *SubOperand;
1214+
MIBuilder.addRenderer<RenderComplexPatternOperand>(
1215+
*ComplexPatternRec, NodeName, RendererID, SubOperandIdx);
1216+
return Error::success();
12031217
}
12041218

1205-
if (!Dst.isLeaf()) {
1206-
if (Dst.getOperator()->isSubClassOf("SDNodeXForm")) {
1207-
auto &Child = Dst.getChild(0);
1208-
auto I = SDNodeXFormEquivs.find(Dst.getOperator());
1209-
if (I != SDNodeXFormEquivs.end()) {
1210-
const Record *XFormOpc = Dst.getOperator()->getValueAsDef("Opcode");
1211-
if (XFormOpc->getName() == "timm") {
1212-
// If this is a TargetConstant, there won't be a corresponding
1213-
// instruction to transform. Instead, this will refer directly to an
1214-
// operand in an instruction's operand list.
1215-
DstMIBuilder.addRenderer<CustomOperandRenderer>(*I->second,
1216-
Child.getName());
1217-
} else {
1218-
DstMIBuilder.addRenderer<CustomRenderer>(*I->second, Child.getName());
1219-
}
1220-
1221-
return InsertPt;
1222-
}
1223-
return failedImport("SDNodeXForm " + Child.getName() +
1224-
" has no custom renderer");
1225-
}
1219+
if (!N.isLeaf()) {
1220+
StringRef OperatorName = N.getOperator()->getName();
12261221

1227-
// We accept 'bb' here. It's an operator because BasicBlockSDNode isn't
1228-
// inline, but in MI it's just another operand.
1229-
if (Dst.getOperator()->getName() == "bb") {
1230-
DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
1231-
return InsertPt;
1222+
if (OperatorName == "imm") {
1223+
MIBuilder.addRenderer<CopyConstantAsImmRenderer>(NodeName);
1224+
return Error::success();
12321225
}
12331226

1234-
// Similarly, imm is an operator in TreePatternNode's view but must be
1235-
// rendered as operands.
1236-
// FIXME: The target should be able to choose sign-extended when appropriate
1237-
// (e.g. on Mips).
1238-
if (Dst.getOperator()->getName() == "timm") {
1239-
DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
1240-
return InsertPt;
1241-
}
1242-
if (Dst.getOperator()->getName() == "tframeindex") {
1243-
DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
1244-
return InsertPt;
1245-
}
1246-
if (Dst.getOperator()->getName() == "imm") {
1247-
DstMIBuilder.addRenderer<CopyConstantAsImmRenderer>(Dst.getName());
1248-
return InsertPt;
1249-
}
1250-
if (Dst.getOperator()->getName() == "fpimm") {
1251-
DstMIBuilder.addRenderer<CopyFConstantAsFPImmRenderer>(Dst.getName());
1252-
return InsertPt;
1227+
if (OperatorName == "fpimm") {
1228+
MIBuilder.addRenderer<CopyFConstantAsFPImmRenderer>(NodeName);
1229+
return Error::success();
12531230
}
12541231

1255-
if (Dst.getOperator()->isSubClassOf("Instruction")) {
1256-
auto OpTy = getInstResultType(Dst, Target);
1257-
if (!OpTy)
1258-
return OpTy.takeError();
1259-
1260-
unsigned TempRegID = Rule.allocateTempRegID();
1261-
InsertPt =
1262-
Rule.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
1263-
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
1264-
1265-
auto InsertPtOrError = createAndImportSubInstructionRenderer(
1266-
++InsertPt, Rule, Dst, TempRegID);
1267-
if (auto Error = InsertPtOrError.takeError())
1268-
return std::move(Error);
1269-
return InsertPtOrError.get();
1232+
// TODO: 'imm' and 'fpimm' are the only nodes that need special treatment.
1233+
// Remove this check and add CopyRenderer unconditionally for other nodes.
1234+
if (OperatorName == "bb" || OperatorName == "timm" ||
1235+
OperatorName == "tframeindex") {
1236+
MIBuilder.addRenderer<CopyRenderer>(NodeName);
1237+
return Error::success();
12701238
}
12711239

1272-
return failedImport("Dst pattern child isn't a leaf node or an MBB" +
1273-
llvm::to_string(Dst));
1274-
}
1275-
1276-
// It could be a specific immediate in which case we should just check for
1277-
// that immediate.
1278-
if (const IntInit *ChildIntInit = dyn_cast<IntInit>(Dst.getLeafValue())) {
1279-
DstMIBuilder.addRenderer<ImmRenderer>(ChildIntInit->getValue());
1280-
return InsertPt;
1240+
return failedImport("node has unsupported operator " + to_string(N));
12811241
}
12821242

1283-
// Otherwise, we're looking for a bog-standard RegisterClass operand.
1284-
if (auto *ChildDefInit = dyn_cast<DefInit>(Dst.getLeafValue())) {
1285-
auto *ChildRec = ChildDefInit->getDef();
1243+
if (const auto *DI = dyn_cast<DefInit>(N.getLeafValue())) {
1244+
const Record *R = DI->getDef();
12861245

1287-
ArrayRef<TypeSetByHwMode> ChildTypes = Dst.getExtTypes();
1288-
if (ChildTypes.size() != 1)
1289-
return failedImport("Dst pattern child has multiple results");
1246+
if (N.getNumResults() != 1)
1247+
return failedImport("node does not have one result " + to_string(N));
12901248

12911249
std::optional<LLTCodeGen> OpTyOrNone;
1250+
ArrayRef<TypeSetByHwMode> ChildTypes = N.getExtTypes();
12921251
if (ChildTypes.front().isMachineValueType())
12931252
OpTyOrNone = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
1253+
1254+
// TODO: Remove this check. Types in the destination DAG should not matter.
12941255
if (!OpTyOrNone)
1295-
return failedImport("Dst operand has an unsupported type");
1256+
return failedImport("node has unsupported type " + to_string(N));
12961257

1297-
if (ChildRec->isSubClassOf("Register")) {
1298-
DstMIBuilder.addRenderer<AddRegisterRenderer>(Target, ChildRec);
1299-
return InsertPt;
1300-
}
1258+
if (R->isSubClassOf("ComplexPattern")) {
1259+
auto I = ComplexPatternEquivs.find(R);
1260+
if (I == ComplexPatternEquivs.end())
1261+
return failedImport("ComplexPattern " + R->getName() +
1262+
" does not have GISel equivalent");
13011263

1302-
if (ChildRec->isSubClassOf("RegisterClass") ||
1303-
ChildRec->isSubClassOf("RegisterOperand") ||
1304-
ChildRec->isSubClassOf("ValueType")) {
1305-
if (ChildRec->isSubClassOf("RegisterOperand") &&
1306-
!ChildRec->isValueUnset("GIZeroRegister")) {
1307-
DstMIBuilder.addRenderer<CopyOrAddZeroRegRenderer>(
1308-
Dst.getName(), ChildRec->getValueAsDef("GIZeroRegister"));
1309-
return InsertPt;
1310-
}
1264+
const OperandMatcher &OM = M.getOperandMatcher(NodeName);
1265+
MIBuilder.addRenderer<RenderComplexPatternOperand>(
1266+
*I->second, NodeName, OM.getAllocatedTemporariesBaseID());
1267+
return Error::success();
1268+
}
13111269

1312-
DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
1313-
return InsertPt;
1270+
if (R->isSubClassOf("RegisterOperand") &&
1271+
!R->isValueUnset("GIZeroRegister")) {
1272+
MIBuilder.addRenderer<CopyOrAddZeroRegRenderer>(
1273+
NodeName, R->getValueAsDef("GIZeroRegister"));
1274+
return Error::success();
13141275
}
13151276

1316-
if (ChildRec->isSubClassOf("SubRegIndex")) {
1317-
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(ChildRec);
1318-
DstMIBuilder.addRenderer<ImmRenderer>(SubIdx->EnumValue);
1319-
return InsertPt;
1277+
// TODO: All special cases are handled above. Remove this check and add
1278+
// CopyRenderer unconditionally.
1279+
if (R->isSubClassOf("RegisterClass") ||
1280+
R->isSubClassOf("RegisterOperand") || R->isSubClassOf("ValueType")) {
1281+
MIBuilder.addRenderer<CopyRenderer>(NodeName);
1282+
return Error::success();
13201283
}
1284+
}
13211285

1322-
if (ChildRec->isSubClassOf("ComplexPattern")) {
1323-
const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec);
1324-
if (ComplexPattern == ComplexPatternEquivs.end())
1325-
return failedImport(
1326-
"SelectionDAG ComplexPattern not mapped to GlobalISel");
1286+
// TODO: Change this to assert and move to the beginning of the function.
1287+
if (!M.hasOperand(NodeName))
1288+
return failedImport("could not find node $" + NodeName +
1289+
" in the source DAG");
13271290

1328-
const OperandMatcher &OM = Rule.getOperandMatcher(Dst.getName());
1329-
DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
1330-
*ComplexPattern->second, Dst.getName(),
1331-
OM.getAllocatedTemporariesBaseID());
1332-
return InsertPt;
1291+
// TODO: Remove this check and add CopyRenderer unconditionally.
1292+
// TODO: Handle nodes with multiple results (provided they can reach here).
1293+
if (isa<UnsetInit>(N.getLeafValue())) {
1294+
MIBuilder.addRenderer<CopyRenderer>(NodeName);
1295+
return Error::success();
1296+
}
1297+
1298+
return failedImport("unsupported node " + to_string(N));
1299+
}
1300+
1301+
// Equivalent of MatcherGen::EmitResultLeafAsOperand.
1302+
Error GlobalISelEmitter::importLeafNodeRenderer(
1303+
RuleMatcher &M, BuildMIAction &MIBuilder, const TreePatternNode &N) const {
1304+
if (const auto *II = dyn_cast<IntInit>(N.getLeafValue())) {
1305+
MIBuilder.addRenderer<ImmRenderer>(II->getValue());
1306+
return Error::success();
1307+
}
1308+
1309+
if (const auto *DI = dyn_cast<DefInit>(N.getLeafValue())) {
1310+
const Record *R = DI->getDef();
1311+
1312+
if (R->isSubClassOf("Register")) {
1313+
MIBuilder.addRenderer<AddRegisterRenderer>(Target, R);
1314+
return Error::success();
13331315
}
13341316

1335-
return failedImport(
1336-
"Dst pattern child def is an unsupported tablegen class");
1317+
if (R->isSubClassOf("SubRegIndex")) {
1318+
const CodeGenSubRegIndex *SubRegIndex = CGRegs.getSubRegIdx(R);
1319+
MIBuilder.addRenderer<ImmRenderer>(SubRegIndex->EnumValue);
1320+
return Error::success();
1321+
}
1322+
1323+
// There are also RegisterClass / RegisterOperand operands of REG_SEQUENCE /
1324+
// COPY_TO_REGCLASS, but these instructions are currently handled elsewhere.
13371325
}
13381326

1339-
// Handle the case where the MVT/register class is omitted in the dest pattern
1340-
// but MVT exists in the source pattern.
1341-
if (isa<UnsetInit>(Dst.getLeafValue()) && Rule.hasOperand(Dst.getName())) {
1342-
DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
1343-
return InsertPt;
1327+
return failedImport("unrecognized node " + to_string(N));
1328+
}
1329+
1330+
// Equivalent of MatcherGen::EmitResultSDNodeXFormAsOperand.
1331+
Error GlobalISelEmitter::importXFormNodeRenderer(
1332+
RuleMatcher &M, BuildMIAction &MIBuilder, const TreePatternNode &N) const {
1333+
const Record *XFormRec = N.getOperator();
1334+
auto I = SDNodeXFormEquivs.find(XFormRec);
1335+
if (I == SDNodeXFormEquivs.end())
1336+
return failedImport("SDNodeXForm " + XFormRec->getName() +
1337+
" does not have GISel equivalent");
1338+
1339+
// TODO: Fail to import if GISDNodeXForm does not have RendererFn.
1340+
// This currently results in a fatal error in emitRenderOpcodes.
1341+
const Record *XFormEquivRec = I->second;
1342+
1343+
// The node to apply the transformation function to.
1344+
// FIXME: The node may not have a name and may be a leaf. It should be
1345+
// rendered first, like any other nodes. This may or may not require
1346+
// introducing a temporary register, and we can't tell that without
1347+
// inspecting the node (possibly recursively). This is a general drawback
1348+
// of appending renderers directly to BuildMIAction.
1349+
const TreePatternNode &Node = N.getChild(0);
1350+
StringRef NodeName = Node.getName();
1351+
1352+
const Record *XFormOpc = CGP.getSDNodeTransform(XFormRec).first;
1353+
if (XFormOpc->getName() == "timm") {
1354+
// If this is a TargetConstant, there won't be a corresponding
1355+
// instruction to transform. Instead, this will refer directly to an
1356+
// operand in an instruction's operand list.
1357+
MIBuilder.addRenderer<CustomOperandRenderer>(*XFormEquivRec, NodeName);
1358+
} else {
1359+
MIBuilder.addRenderer<CustomRenderer>(*XFormEquivRec, NodeName);
13441360
}
1345-
return failedImport("Dst pattern child is an unsupported kind");
1361+
1362+
return Error::success();
1363+
}
1364+
1365+
// Equivalent of MatcherGen::EmitResultInstructionAsOperand.
1366+
Error GlobalISelEmitter::importInstructionNodeRenderer(
1367+
RuleMatcher &M, BuildMIAction &MIBuilder, const TreePatternNode &N,
1368+
action_iterator &InsertPt) const {
1369+
Expected<LLTCodeGen> OpTy = getInstResultType(N, Target);
1370+
if (!OpTy)
1371+
return OpTy.takeError();
1372+
1373+
// TODO: See the comment in importXFormNodeRenderer. We rely on the node
1374+
// requiring a temporary register, which prevents us from using this
1375+
// function on the root of the destination DAG.
1376+
unsigned TempRegID = M.allocateTempRegID();
1377+
InsertPt = M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
1378+
MIBuilder.addRenderer<TempRegRenderer>(TempRegID);
1379+
1380+
auto InsertPtOrError =
1381+
createAndImportSubInstructionRenderer(++InsertPt, M, N, TempRegID);
1382+
if (!InsertPtOrError)
1383+
return InsertPtOrError.takeError();
1384+
1385+
InsertPt = *InsertPtOrError;
1386+
return Error::success();
1387+
}
1388+
1389+
// Equivalent of MatcherGen::EmitResultOperand.
1390+
Error GlobalISelEmitter::importNodeRenderer(RuleMatcher &M,
1391+
BuildMIAction &MIBuilder,
1392+
const TreePatternNode &N,
1393+
action_iterator &InsertPt) const {
1394+
if (N.hasName())
1395+
return importNamedNodeRenderer(M, MIBuilder, N);
1396+
1397+
if (N.isLeaf())
1398+
return importLeafNodeRenderer(M, MIBuilder, N);
1399+
1400+
if (N.getOperator()->isSubClassOf("SDNodeXForm"))
1401+
return importXFormNodeRenderer(M, MIBuilder, N);
1402+
1403+
if (N.getOperator()->isSubClassOf("Instruction"))
1404+
return importInstructionNodeRenderer(M, MIBuilder, N, InsertPt);
1405+
1406+
// Should not reach here.
1407+
return failedImport("unrecognized node " + llvm::to_string(N));
13461408
}
13471409

13481410
/// Generates code that builds the resulting instruction(s) from the destination
@@ -1597,11 +1659,9 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
15971659
dyn_cast<DefInit>(SubRegChild.getLeafValue())) {
15981660
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
15991661

1600-
auto InsertPtOrError =
1601-
importExplicitUseRenderer(InsertPt, M, DstMIBuilder, ValChild);
1602-
if (auto Error = InsertPtOrError.takeError())
1603-
return std::move(Error);
1604-
InsertPt = InsertPtOrError.get();
1662+
if (Error Err = importNodeRenderer(M, DstMIBuilder, ValChild, InsertPt))
1663+
return Err;
1664+
16051665
DstMIBuilder.addRenderer<SubRegIndexRenderer>(SubIdx);
16061666
}
16071667
}
@@ -1666,11 +1726,10 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
16661726
continue;
16671727
}
16681728

1669-
auto InsertPtOrError = importExplicitUseRenderer(InsertPt, M, DstMIBuilder,
1670-
Dst.getChild(Child));
1671-
if (auto Error = InsertPtOrError.takeError())
1672-
return std::move(Error);
1673-
InsertPt = InsertPtOrError.get();
1729+
if (Error Err =
1730+
importNodeRenderer(M, DstMIBuilder, Dst.getChild(Child), InsertPt))
1731+
return Err;
1732+
16741733
++Child;
16751734
}
16761735

0 commit comments

Comments
 (0)