Skip to content

Commit 2bbdce9

Browse files
authored
[GlobalISel] Support physical register inputs in nested patterns (#121239)
When importing nested patterns, we create InsnMatcher for each pattern and miss them if consider only the top level InsnMatcher. Iterate PhysRegOperands instead. Change the type of PhysRegOperands from DenseMap to SmallMapVector to have stable generation. Also drop PhysRegInputs member from InsnMatcher as there are no users of it.
1 parent a738d81 commit 2bbdce9

File tree

4 files changed

+94
-17
lines changed

4 files changed

+94
-17
lines changed

llvm/test/TableGen/GlobalISelEmitter/gisel-physreg-input.td

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,86 @@ class I<dag OOps, dag IOps, list<dag> Pat>
2222
let Pattern = Pat;
2323
}
2424

25+
// Try a nested physical register
26+
27+
// GISEL: GIM_Try,
28+
// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
29+
// GISEL-NEXT: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_STORE),
30+
// GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
31+
// GISEL-NEXT: // MIs[0] src0
32+
// GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,
33+
// GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
34+
// GISEL-NEXT: // MIs[0] Operand 1
35+
// GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
36+
// GISEL-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
37+
// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
38+
// GISEL-NEXT: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_MUL),
39+
// GISEL-NEXT: // MIs[1] Operand 0
40+
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
41+
// GISEL-NEXT: // MIs[1] src1
42+
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
43+
// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
44+
// GISEL-NEXT: // MIs[1] Operand 2
45+
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
46+
// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/GIMT_Encode2(MyTarget::Special32RegClassID),
47+
// GISEL-NEXT: GIM_CheckIsSafeToFold, /*NumInsns*/1,
48+
// GISEL-NEXT: // (st GPR32:{ *:[i32] }:$src0, (mul:{ *:[i32] } GPR32:{ *:[i32] }:$src1, SPECIAL:{ *:[i32] })) => (MULM_PHYS GPR32:{ *:[i32] }:$src0, GPR32:{ *:[i32] }:$src1)
49+
// GISEL-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
50+
// GISEL-NEXT: GIR_AddRegister, /*InsnID*/1, GIMT_Encode2(MyTarget::SPECIAL), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define),
51+
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/2, // SPECIAL
52+
// GISEL-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::MULM_PHYS),
53+
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // src0
54+
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
55+
// GISEL-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
56+
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
57+
// GISEL-NEXT: // GIR_Coverage, 0,
58+
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
59+
def MULM_PHYS : I<(outs), (ins GPR32:$src0, GPR32:$src1),
60+
[(st GPR32:$src0, (mul GPR32:$src1, SPECIAL))]> {
61+
let Uses = [SPECIAL];
62+
}
63+
64+
// Try nested physical registers and check on duplicated copies
65+
66+
// GISEL: GIM_Try,
67+
// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
68+
// GISEL-NEXT: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_STORE),
69+
// GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
70+
// GISEL-NEXT: // MIs[0] src0
71+
// GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,
72+
// GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
73+
// GISEL-NEXT: // MIs[0] Operand 1
74+
// GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
75+
// GISEL-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
76+
// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
77+
// GISEL-NEXT: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_MUL),
78+
// GISEL-NEXT: // MIs[1] Operand 0
79+
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
80+
// GISEL-NEXT: // MIs[1] Operand 1
81+
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
82+
// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
83+
// GISEL-NEXT: // MIs[1] Operand 2
84+
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
85+
// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/GIMT_Encode2(MyTarget::Special32RegClassID),
86+
// GISEL-NEXT: GIM_CheckIsSafeToFold, /*NumInsns*/1,
87+
// GISEL-NEXT: // (st GPR32:{ *:[i32] }:$src0, (mul:{ *:[i32] } R0:{ *:[i32] }, SPECIAL:{ *:[i32] })) => (MULMR0_PHYS GPR32:{ *:[i32] }:$src0)
88+
// GISEL-NEXT: GIR_BuildMI, /*InsnID*/2, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
89+
// GISEL-NEXT: GIR_AddRegister, /*InsnID*/2, GIMT_Encode2(MyTarget::SPECIAL), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define),
90+
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/2, /*OldInsnID*/1, /*OpIdx*/2, // SPECIAL
91+
// GISEL-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
92+
// GISEL-NEXT: GIR_AddRegister, /*InsnID*/1, GIMT_Encode2(MyTarget::R0), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define),
93+
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/1, // R0
94+
// GISEL-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::MULMR0_PHYS),
95+
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // src0
96+
// GISEL-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
97+
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
98+
// GISEL-NEXT: // GIR_Coverage, 1,
99+
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
100+
def MULMR0_PHYS : I<(outs), (ins GPR32:$src0),
101+
[(st GPR32:$src0, (mul R0, SPECIAL))]> {
102+
let Uses = [R0, SPECIAL];
103+
}
104+
25105
// Try a normal physical register use.
26106

27107
// GISEL: GIM_Try,
@@ -44,7 +124,7 @@ class I<dag OOps, dag IOps, list<dag> Pat>
44124
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
45125
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/1, // src0
46126
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
47-
// GISEL-NEXT: // GIR_Coverage, 0,
127+
// GISEL-NEXT: // GIR_Coverage, 2,
48128
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
49129
def ADD_PHYS : I<(outs GPR32:$dst), (ins GPR32:$src0),
50130
[(set GPR32:$dst, (add GPR32:$src0, SPECIAL))]> {
@@ -73,7 +153,7 @@ def ADD_PHYS : I<(outs GPR32:$dst), (ins GPR32:$src0),
73153
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
74154
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/1, // SPECIAL
75155
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
76-
// GISEL-NEXT: // GIR_Coverage, 1,
156+
// GISEL-NEXT: // GIR_Coverage, 3,
77157
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
78158
def MUL_PHYS : I<(outs GPR32:$dst), (ins GPR32:$SPECIAL),
79159
[(set GPR32:$dst, (mul GPR32:$SPECIAL, SPECIAL))]> {

llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1723,7 +1723,6 @@ OperandMatcher &InstructionMatcher::addPhysRegInput(const Record *Reg,
17231723
OperandMatcher *OM = new OperandMatcher(*this, OpIdx, "", TempOpIdx);
17241724
Operands.emplace_back(OM);
17251725
Rule.definePhysRegOperand(Reg, *OM);
1726-
PhysRegInputs.emplace_back(Reg, OpIdx);
17271726
return *OM;
17281727
}
17291728

llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "Common/CodeGenDAGPatterns.h"
2020
#include "llvm/ADT/ArrayRef.h"
2121
#include "llvm/ADT/DenseMap.h"
22+
#include "llvm/ADT/MapVector.h"
2223
#include "llvm/ADT/SmallPtrSet.h"
2324
#include "llvm/ADT/StringMap.h"
2425
#include "llvm/ADT/StringRef.h"
@@ -492,9 +493,11 @@ class RuleMatcher : public Matcher {
492493
/// the renderers.
493494
StringMap<OperandMatcher *> DefinedOperands;
494495

496+
using PhysRegOperandsTy = SmallMapVector<const Record *, OperandMatcher *, 1>;
497+
495498
/// A map of anonymous physical register operands defined by the matchers that
496499
/// may be referenced by the renderers.
497-
DenseMap<const Record *, OperandMatcher *> PhysRegOperands;
500+
PhysRegOperandsTy PhysRegOperands;
498501

499502
/// ID for the next instruction variable defined with
500503
/// implicitlyDefineInsnVar()
@@ -695,6 +698,10 @@ class RuleMatcher : public Matcher {
695698
unsigned allocateOutputInsnID() { return NextOutputInsnID++; }
696699
unsigned allocateTempRegID() { return NextTempRegID++; }
697700

701+
iterator_range<PhysRegOperandsTy::const_iterator> physoperands() const {
702+
return make_range(PhysRegOperands.begin(), PhysRegOperands.end());
703+
}
704+
698705
iterator_range<MatchersTy::iterator> insnmatchers() {
699706
return make_range(Matchers.begin(), Matchers.end());
700707
}
@@ -1756,11 +1763,6 @@ class InstructionMatcher final : public PredicateListMatcher<PredicateMatcher> {
17561763
unsigned InsnVarID;
17571764
bool AllowNumOpsCheck;
17581765

1759-
/// PhysRegInputs - List list has an entry for each explicitly specified
1760-
/// physreg input to the pattern. The first elt is the Register node, the
1761-
/// second is the recorded slot number the input pattern match saved it in.
1762-
SmallVector<std::pair<const Record *, unsigned>, 2> PhysRegInputs;
1763-
17641766
bool canAddNumOperandsCheck() const {
17651767
// Add if it's allowed, and:
17661768
// - We don't have a variadic operand
@@ -1802,10 +1804,6 @@ class InstructionMatcher final : public PredicateListMatcher<PredicateMatcher> {
18021804
OperandMatcher &addPhysRegInput(const Record *Reg, unsigned OpIdx,
18031805
unsigned TempOpIdx);
18041806

1805-
ArrayRef<std::pair<const Record *, unsigned>> getPhysRegInputs() const {
1806-
return PhysRegInputs;
1807-
}
1808-
18091807
StringRef getSymbolicName() const { return SymbolicName; }
18101808

18111809
unsigned getNumOperandMatchers() const { return Operands.size(); }

llvm/utils/TableGen/GlobalISelEmitter.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,15 +1429,15 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
14291429
action_iterator InsertPt = InsertPtOrError.get();
14301430
BuildMIAction &DstMIBuilder = *static_cast<BuildMIAction *>(InsertPt->get());
14311431

1432-
for (auto PhysInput : InsnMatcher.getPhysRegInputs()) {
1432+
for (auto PhysOp : M.physoperands()) {
14331433
InsertPt = M.insertAction<BuildMIAction>(
14341434
InsertPt, M.allocateOutputInsnID(),
14351435
&Target.getInstruction(RK.getDef("COPY")));
14361436
BuildMIAction &CopyToPhysRegMIBuilder =
14371437
*static_cast<BuildMIAction *>(InsertPt->get());
1438-
CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(
1439-
Target, PhysInput.first, true);
1440-
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
1438+
CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(Target,
1439+
PhysOp.first, true);
1440+
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysOp.first);
14411441
}
14421442

14431443
if (auto Error = importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Dst,

0 commit comments

Comments
 (0)