Skip to content

Commit a99b8b1

Browse files
committed
Allow physical registers in patterns
Most of the heavy lifting was already done in importExplicitDefRenderers, so I just added an operand for the physical register defs. The logic introduced in llvm#112673 was indeed subtly broken; it was only supposed to count the physical register defs present in the pattern rather than all physical register defs. Remove importImplicitDefRenderers since it was unimplemented anyway, and I don't see a way that it could be implemented satisfactorily. Also, the name was rather misleading; it should've been called something like importPhysRegDefRenderers
1 parent 173907b commit a99b8b1

File tree

1 file changed

+50
-45
lines changed

1 file changed

+50
-45
lines changed

llvm/utils/TableGen/GlobalISelEmitter.cpp

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -398,19 +398,19 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
398398

399399
Expected<BuildMIAction &> createAndImportInstructionRenderer(
400400
RuleMatcher &M, InstructionMatcher &InsnMatcher,
401-
const TreePatternNode &Src, const TreePatternNode &Dst);
401+
const TreePatternNode &Src, const TreePatternNode &Dst,
402+
ArrayRef<const Record *> DstPhysDefs);
402403
Expected<action_iterator> createAndImportSubInstructionRenderer(
403404
action_iterator InsertPt, RuleMatcher &M, const TreePatternNode &Dst,
404405
const TreePatternNode &Src, unsigned TempReg);
405406
Expected<action_iterator>
406407
createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M,
407408
const TreePatternNode &Dst);
408409

409-
Expected<action_iterator>
410-
importExplicitDefRenderers(action_iterator InsertPt, RuleMatcher &M,
411-
BuildMIAction &DstMIBuilder,
412-
const TreePatternNode &Src,
413-
const TreePatternNode &Dst, unsigned Start = 0);
410+
Expected<action_iterator> importExplicitDefRenderers(
411+
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
412+
const TreePatternNode &Src, const TreePatternNode &Dst,
413+
ArrayRef<const Record *> DstPhysDefs = {}, unsigned Start = 0);
414414

415415
Expected<action_iterator> importExplicitUseRenderers(
416416
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
@@ -421,8 +421,6 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
421421
Error importDefaultOperandRenderers(action_iterator InsertPt, RuleMatcher &M,
422422
BuildMIAction &DstMIBuilder,
423423
const DAGDefaultOperand &DefaultOp) const;
424-
Error importImplicitDefRenderers(BuildMIAction &DstMIBuilder,
425-
ArrayRef<const Record *> ImplicitDefs) const;
426424

427425
/// Analyze pattern \p P, returning a matcher for it if possible.
428426
/// Otherwise, return an Error explaining why we don't support it.
@@ -1348,7 +1346,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
13481346

13491347
Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
13501348
RuleMatcher &M, InstructionMatcher &InsnMatcher, const TreePatternNode &Src,
1351-
const TreePatternNode &Dst) {
1349+
const TreePatternNode &Dst, ArrayRef<const Record *> DstPhysDefs) {
13521350
auto InsertPtOrError = createInstructionRenderer(M.actions_end(), M, Dst);
13531351
if (auto Error = InsertPtOrError.takeError())
13541352
return std::move(Error);
@@ -1367,9 +1365,9 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
13671365
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
13681366
}
13691367

1370-
if (auto Error =
1371-
importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Src, Dst)
1372-
.takeError())
1368+
if (auto Error = importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Src,
1369+
Dst, DstPhysDefs)
1370+
.takeError())
13731371
return std::move(Error);
13741372

13751373
if (auto Error =
@@ -1399,8 +1397,9 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
13991397

14001398
// Handle additional (ignored) results.
14011399
if (DstMIBuilder.getCGI()->Operands.NumDefs > 1) {
1402-
InsertPtOrError = importExplicitDefRenderers(
1403-
std::prev(*InsertPtOrError), M, DstMIBuilder, Src, Dst, /*Start=*/1);
1400+
InsertPtOrError =
1401+
importExplicitDefRenderers(std::prev(*InsertPtOrError), M, DstMIBuilder,
1402+
Src, Dst, /*DstPhysDefs=*/{}, /*Start=*/1);
14041403
if (auto Error = InsertPtOrError.takeError())
14051404
return std::move(Error);
14061405
}
@@ -1533,19 +1532,29 @@ Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer(
15331532

15341533
Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
15351534
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
1536-
const TreePatternNode &Src, const TreePatternNode &Dst, unsigned Start) {
1535+
const TreePatternNode &Src, const TreePatternNode &Dst,
1536+
ArrayRef<const Record *> DstPhysDefs, unsigned Start) {
15371537
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
15381538
const unsigned SrcNumDefs = Src.getExtTypes().size();
1539-
const unsigned DstNumDefs = DstI->Operands.NumDefs;
1539+
const unsigned DstNumVirtDefs = DstI->Operands.NumDefs,
1540+
DstNumDefs = DstNumVirtDefs + DstPhysDefs.size();
15401541
if (DstNumDefs == 0)
15411542
return InsertPt;
15421543

15431544
for (unsigned I = Start; I < SrcNumDefs; ++I) {
1544-
std::string OpName = getMangledRootDefName(DstI->Operands[I].Name);
1545-
// CopyRenderer saves a StringRef, so cannot pass OpName itself -
1546-
// let's use a string with an appropriate lifetime.
1547-
StringRef PermanentRef = M.getOperandMatcher(OpName).getSymbolicName();
1548-
DstMIBuilder.addRenderer<CopyRenderer>(PermanentRef);
1545+
if (I < DstNumVirtDefs) {
1546+
std::string OpName = getMangledRootDefName(DstI->Operands[I].Name);
1547+
// CopyRenderer saves a StringRef, so cannot pass OpName itself -
1548+
// let's use a string with an appropriate lifetime.
1549+
StringRef PermanentRef = M.getOperandMatcher(OpName).getSymbolicName();
1550+
DstMIBuilder.addRenderer<CopyRenderer>(PermanentRef);
1551+
} else if (I < DstNumDefs) {
1552+
const auto *PhysReg = DstPhysDefs[I - DstNumVirtDefs];
1553+
DstMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysReg);
1554+
} else {
1555+
return failedImport("number of defs in src exceeds number of implicit "
1556+
"and explicit defs in dst");
1557+
}
15491558
}
15501559

15511560
// Some instructions have multiple defs, but are missing a type entry
@@ -1788,13 +1797,6 @@ Error GlobalISelEmitter::importDefaultOperandRenderers(
17881797
return Error::success();
17891798
}
17901799

1791-
Error GlobalISelEmitter::importImplicitDefRenderers(
1792-
BuildMIAction &DstMIBuilder, ArrayRef<const Record *> ImplicitDefs) const {
1793-
if (!ImplicitDefs.empty())
1794-
return failedImport("Pattern defines a physical register");
1795-
return Error::success();
1796-
}
1797-
17981800
std::optional<const CodeGenRegisterClass *>
17991801
GlobalISelEmitter::getRegClassFromLeaf(const TreePatternNode &Leaf) {
18001802
assert(Leaf.isLeaf() && "Expected leaf?");
@@ -2022,11 +2024,9 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
20222024

20232025
auto &DstI = Target.getInstruction(DstOp);
20242026
StringRef DstIName = DstI.TheDef->getName();
2025-
2026-
// Count both implicit and explicit defs in the dst instruction.
2027-
// This avoids errors importing patterns that have inherent implicit defs.
2028-
unsigned DstExpDefs = DstI.Operands.NumDefs,
2029-
DstNumDefs = DstI.ImplicitDefs.size() + DstExpDefs,
2027+
const auto &DstPhysDefs = P.getDstRegs();
2028+
unsigned DstNumVirtDefs = DstI.Operands.NumDefs,
2029+
DstNumDefs = DstNumVirtDefs + DstPhysDefs.size(),
20302030
SrcNumDefs = Src.getExtTypes().size();
20312031
if (DstNumDefs < SrcNumDefs) {
20322032
if (DstNumDefs != 0)
@@ -2048,13 +2048,13 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
20482048
// The root of the match also has constraints on the register bank so that it
20492049
// matches the result instruction.
20502050
unsigned OpIdx = 0;
2051-
unsigned N = std::min(DstExpDefs, SrcNumDefs);
2051+
unsigned N = std::min(DstNumDefs, SrcNumDefs);
20522052
for (unsigned I = 0; I < N; ++I) {
20532053
const TypeSetByHwMode &VTy = Src.getExtType(I);
20542054

2055-
const auto &DstIOperand = DstI.Operands[OpIdx];
20562055
PointerUnion<const Record *, const CodeGenRegisterClass *> MatchedRC =
2057-
DstIOperand.Rec;
2056+
OpIdx < DstNumVirtDefs ? DstI.Operands[OpIdx].Rec
2057+
: DstPhysDefs[OpIdx - DstNumVirtDefs];
20582058
if (DstIName == "COPY_TO_REGCLASS") {
20592059
MatchedRC = getInitValueAsRegClass(Dst.getChild(1).getLeafValue());
20602060

@@ -2092,16 +2092,26 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
20922092
MatchedRC = *MaybeRegClass;
20932093
} else if (MatchedRC.get<const Record *>()->isSubClassOf("RegisterOperand"))
20942094
MatchedRC = MatchedRC.get<const Record *>()->getValueAsDef("RegClass");
2095-
else if (!MatchedRC.get<const Record *>()->isSubClassOf("RegisterClass"))
2095+
else if (MatchedRC.get<const Record *>()->isSubClassOf("Register")) {
2096+
auto MaybeRegClass =
2097+
CGRegs.getRegClassForRegister(MatchedRC.get<const Record *>());
2098+
if (!MaybeRegClass)
2099+
return failedImport("Cannot infer register class for register");
2100+
MatchedRC = MaybeRegClass;
2101+
} else if (!MatchedRC.get<const Record *>()->isSubClassOf("RegisterClass"))
20962102
return failedImport("Dst MI def isn't a register class" + to_string(Dst));
20972103

20982104
OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
20992105
// The operand names declared in the DstI instruction are unrelated to
21002106
// those used in pattern's source and destination DAGs, so mangle the
21012107
// former to prevent implicitly adding unexpected
21022108
// GIM_CheckIsSameOperand predicates by the defineOperand method.
2103-
OM.setSymbolicName(getMangledRootDefName(DstIOperand.Name));
2104-
M.defineOperand(OM.getSymbolicName(), OM);
2109+
if (OpIdx < DstNumVirtDefs) {
2110+
OM.setSymbolicName(getMangledRootDefName(DstI.Operands[OpIdx].Name));
2111+
M.defineOperand(OM.getSymbolicName(), OM);
2112+
} else {
2113+
M.definePhysRegOperand(DstPhysDefs[OpIdx - DstNumVirtDefs], OM);
2114+
}
21052115
if (MatchedRC.is<const Record *>())
21062116
MatchedRC = &Target.getRegisterClass(MatchedRC.get<const Record *>());
21072117
OM.addPredicate<RegisterBankOperandMatcher>(
@@ -2110,16 +2120,11 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
21102120
}
21112121

21122122
auto DstMIBuilderOrError =
2113-
createAndImportInstructionRenderer(M, InsnMatcher, Src, Dst);
2123+
createAndImportInstructionRenderer(M, InsnMatcher, Src, Dst, DstPhysDefs);
21142124
if (auto Error = DstMIBuilderOrError.takeError())
21152125
return std::move(Error);
21162126
BuildMIAction &DstMIBuilder = DstMIBuilderOrError.get();
21172127

2118-
// Render the implicit defs.
2119-
// These are only added to the root of the result.
2120-
if (auto Error = importImplicitDefRenderers(DstMIBuilder, P.getDstRegs()))
2121-
return std::move(Error);
2122-
21232128
DstMIBuilder.chooseInsnToMutate(M);
21242129

21252130
// Constrain the registers to classes. This is normally derived from the

0 commit comments

Comments
 (0)