-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
[GlobalISel] Support physical register inputs in nested patterns #121239
Conversation
When importing nested patterns, we create InsnMatcher for each pattern and miss them if consider only the top level InsnMatcher. Iterate all InsnMatchers of PhysRegOperands when generating COPYs for physical registers.
@llvm/pr-subscribers-tablegen @llvm/pr-subscribers-llvm-globalisel Author: Evgenii Kudriashov (e-kud) ChangesWhen importing nested patterns, we create InsnMatcher for each pattern and miss them if consider only the top level InsnMatcher. Iterate all InsnMatchers of PhysRegOperands when generating COPYs for physical registers. Full diff: https://github.com/llvm/llvm-project/pull/121239.diff 3 Files Affected:
diff --git a/llvm/test/TableGen/GlobalISelEmitter/gisel-physreg-input.td b/llvm/test/TableGen/GlobalISelEmitter/gisel-physreg-input.td
index a05f364eb3f054..dbee154e31c9a6 100644
--- a/llvm/test/TableGen/GlobalISelEmitter/gisel-physreg-input.td
+++ b/llvm/test/TableGen/GlobalISelEmitter/gisel-physreg-input.td
@@ -22,6 +22,45 @@ class I<dag OOps, dag IOps, list<dag> Pat>
let Pattern = Pat;
}
+// Try a nested physical register
+
+// GISEL: GIM_Try,
+// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+// GISEL-NEXT: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_STORE),
+// GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
+// GISEL-NEXT: // MIs[0] src0
+// GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,
+// GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
+// GISEL-NEXT: // MIs[0] Operand 1
+// GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
+// GISEL-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
+// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
+// GISEL-NEXT: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_MUL),
+// GISEL-NEXT: // MIs[1] Operand 0
+// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
+// GISEL-NEXT: // MIs[1] src1
+// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
+// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
+// GISEL-NEXT: // MIs[1] Operand 2
+// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
+// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/GIMT_Encode2(MyTarget::Special32RegClassID),
+// GISEL-NEXT: GIM_CheckIsSafeToFold, /*NumInsns*/1,
+// GISEL-NEXT: // (st GPR32:{ *:[i32] }:$src0, (mul:{ *:[i32] } GPR32:{ *:[i32] }:$src1, SPECIAL:{ *:[i32] })) => (MULM_PHYS GPR32:{ *:[i32] }:$src0, GPR32:{ *:[i32] }:$src1)
+// GISEL-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
+// GISEL-NEXT: GIR_AddRegister, /*InsnID*/1, GIMT_Encode2(MyTarget::SPECIAL), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define),
+// GISEL-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/2, // SPECIAL
+// GISEL-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::MULM_PHYS),
+// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // src0
+// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
+// GISEL-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
+// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
+// GISEL-NEXT: // GIR_Coverage, 0,
+// GISEL-NEXT: GIR_EraseRootFromParent_Done,
+def MULM_PHYS : I<(outs), (ins GPR32:$src0, GPR32:$src1),
+ [(st GPR32:$src0, (mul GPR32:$src1, SPECIAL))]> {
+ let Uses = [SPECIAL];
+}
+
// Try a normal physical register use.
// GISEL: GIM_Try,
@@ -44,7 +83,7 @@ class I<dag OOps, dag IOps, list<dag> Pat>
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/1, // src0
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
-// GISEL-NEXT: // GIR_Coverage, 0,
+// GISEL-NEXT: // GIR_Coverage, 1,
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
def ADD_PHYS : I<(outs GPR32:$dst), (ins GPR32:$src0),
[(set GPR32:$dst, (add GPR32:$src0, SPECIAL))]> {
@@ -73,7 +112,7 @@ def ADD_PHYS : I<(outs GPR32:$dst), (ins GPR32:$src0),
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/1, // SPECIAL
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
-// GISEL-NEXT: // GIR_Coverage, 1,
+// GISEL-NEXT: // GIR_Coverage, 2,
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
def MUL_PHYS : I<(outs GPR32:$dst), (ins GPR32:$SPECIAL),
[(set GPR32:$dst, (mul GPR32:$SPECIAL, SPECIAL))]> {
diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
index 48ce71be677c08..abf145a2507c0a 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
+++ b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
@@ -492,9 +492,11 @@ class RuleMatcher : public Matcher {
/// the renderers.
StringMap<OperandMatcher *> DefinedOperands;
+ using PhysRegOperandsTy = DenseMap<const Record *, OperandMatcher *>;
+
/// A map of anonymous physical register operands defined by the matchers that
/// may be referenced by the renderers.
- DenseMap<const Record *, OperandMatcher *> PhysRegOperands;
+ PhysRegOperandsTy PhysRegOperands;
/// ID for the next instruction variable defined with
/// implicitlyDefineInsnVar()
@@ -695,6 +697,10 @@ class RuleMatcher : public Matcher {
unsigned allocateOutputInsnID() { return NextOutputInsnID++; }
unsigned allocateTempRegID() { return NextTempRegID++; }
+ iterator_range<PhysRegOperandsTy::const_iterator> physoperands() const {
+ return make_range(PhysRegOperands.begin(), PhysRegOperands.end());
+ }
+
iterator_range<MatchersTy::iterator> insnmatchers() {
return make_range(Matchers.begin(), Matchers.end());
}
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index f0fb11625883ea..62ee6e735be740 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -1412,15 +1412,18 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
action_iterator InsertPt = InsertPtOrError.get();
BuildMIAction &DstMIBuilder = *static_cast<BuildMIAction *>(InsertPt->get());
- for (auto PhysInput : InsnMatcher.getPhysRegInputs()) {
- InsertPt = M.insertAction<BuildMIAction>(
- InsertPt, M.allocateOutputInsnID(),
- &Target.getInstruction(RK.getDef("COPY")));
- BuildMIAction &CopyToPhysRegMIBuilder =
- *static_cast<BuildMIAction *>(InsertPt->get());
- CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(
- Target, PhysInput.first, true);
- CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
+ for (auto PhysOp : M.physoperands()) {
+ auto &OpInsnMatcher = PhysOp.second->getInstructionMatcher();
+ for (auto PhysInput : OpInsnMatcher.getPhysRegInputs()) {
+ InsertPt = M.insertAction<BuildMIAction>(
+ InsertPt, M.allocateOutputInsnID(),
+ &Target.getInstruction(RK.getDef("COPY")));
+ BuildMIAction &CopyToPhysRegMIBuilder =
+ *static_cast<BuildMIAction *>(InsertPt->get());
+ CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(
+ Target, PhysInput.first, true);
+ CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
+ }
}
if (auto Error = importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Dst,
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@s-barannikov thank you for the review! |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/73/builds/11158 Here is the relevant piece of the build log for the reference
|
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.