[TableGen][MacroFusion] Predicate if the first inst has the same register (#137778)

We rename `SameReg` to `SecondInstHasSameReg ` and add
`FirstInstHasSameReg `
which has the logic but applies to the first instruction.

We have some cases that require the first instruction has the same
input/output register.
This commit is contained in:
Pengcheng Wang 2025-05-13 19:05:42 +08:00 committed by GitHub
parent c14acb7442
commit 9570bf978d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 6 deletions

View File

@ -55,11 +55,20 @@ class TieReg<int firstOpIdx, int secondOpIdx> : BothFusionPredicate {
int SecondOpIdx = secondOpIdx; int SecondOpIdx = secondOpIdx;
} }
// The operand of `FirstMI` at position `firstOpIdx` should be the same as the
// operand at position `secondOpIdx`.
// If the fusion has `IsCommutable` being true and the operand at `secondOpIdx`
// has commutable operand, then the commutable operand will be checked too.
class FirstInstHasSameReg<int firstOpIdx, int secondOpIdx> : FirstFusionPredicate {
int FirstOpIdx = firstOpIdx;
int SecondOpIdx = secondOpIdx;
}
// The operand of `SecondMI` at position `firstOpIdx` should be the same as the // The operand of `SecondMI` at position `firstOpIdx` should be the same as the
// operand at position `secondOpIdx`. // operand at position `secondOpIdx`.
// If the fusion has `IsCommutable` being true and the operand at `secondOpIdx` // If the fusion has `IsCommutable` being true and the operand at `secondOpIdx`
// has commutable operand, then the commutable operand will be checked too. // has commutable operand, then the commutable operand will be checked too.
class SameReg<int firstOpIdx, int secondOpIdx> : SecondFusionPredicate { class SecondInstHasSameReg<int firstOpIdx, int secondOpIdx> : SecondFusionPredicate {
int FirstOpIdx = firstOpIdx; int FirstOpIdx = firstOpIdx;
int SecondOpIdx = secondOpIdx; int SecondOpIdx = secondOpIdx;
} }
@ -129,7 +138,7 @@ class SimpleFusion<string name, string fieldName, string desc,
SecondFusionPredicateWithMCInstPredicate<secondPred>, SecondFusionPredicateWithMCInstPredicate<secondPred>,
WildcardTrue, WildcardTrue,
FirstFusionPredicateWithMCInstPredicate<firstPred>, FirstFusionPredicateWithMCInstPredicate<firstPred>,
SameReg<0, 1>, SecondInstHasSameReg<0, 1>,
OneUse, OneUse,
TieReg<0, 1>, TieReg<0, 1>,
], ],

View File

@ -62,12 +62,19 @@ def TestSingleFusion: SingleFusion<"test-single-fusion", "HasTestSingleFusion",
Inst0, Inst2, Inst0, Inst2,
secondInstPred=CheckRegOperand<0, X0>>; secondInstPred=CheckRegOperand<0, X0>>;
def TestFirstSameRegFusion: Fusion<"test-first-same-reg-fusion", "HasTestFirstSameRegFusion",
"Test FirstSameReg",
[FirstInstHasSameReg<0, 1>]> {
bit IsCommutable = 1;
}
// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_DECL // CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_DECL
// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_DECL // CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_DECL
// CHECK-PREDICATOR-EMPTY: // CHECK-PREDICATOR-EMPTY:
// CHECK-PREDICATOR-NEXT: namespace llvm { // CHECK-PREDICATOR-NEXT: namespace llvm {
// CHECK-PREDICATOR-NEXT: bool isTestBothFusionPredicate(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &); // CHECK-PREDICATOR-NEXT: bool isTestBothFusionPredicate(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestCommutableFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &); // CHECK-PREDICATOR-NEXT: bool isTestCommutableFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestFirstSameRegFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &); // CHECK-PREDICATOR-NEXT: bool isTestFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestSingleFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &); // CHECK-PREDICATOR-NEXT: bool isTestSingleFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: } // end namespace llvm // CHECK-PREDICATOR-NEXT: } // end namespace llvm
@ -144,6 +151,24 @@ def TestSingleFusion: SingleFusion<"test-single-fusion", "HasTestSingleFusion",
// CHECK-PREDICATOR-NEXT: } // CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: return true; // CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: } // CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: bool isTestFirstSameRegFusion(
// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
// CHECK-PREDICATOR-NEXT: const MachineInstr *FirstMI,
// CHECK-PREDICATOR-NEXT: const MachineInstr &SecondMI) {
// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} auto &MRI = SecondMI.getMF()->getRegInfo();
// CHECK-PREDICATOR-NEXT: if (!FirstMI->getOperand(0).getReg().isVirtual()) {
// CHECK-PREDICATOR-NEXT: if (FirstMI->getOperand(0).getReg() != FirstMI->getOperand(1).getReg()) {
// CHECK-PREDICATOR-NEXT: if (!FirstMI->getDesc().isCommutable())
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: unsigned SrcOpIdx1 = 1, SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;
// CHECK-PREDICATOR-NEXT: if (TII.findCommutedOpIndices(FirstMI, SrcOpIdx1, SrcOpIdx2))
// CHECK-PREDICATOR-NEXT: if (FirstMI->getOperand(0).getReg() != FirstMI->getOperand(SrcOpIdx2).getReg())
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: bool isTestFusion( // CHECK-PREDICATOR-NEXT: bool isTestFusion(
// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII, // CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI, // CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
@ -238,6 +263,7 @@ def TestSingleFusion: SingleFusion<"test-single-fusion", "HasTestSingleFusion",
// Check that we have generated target subfeature. // Check that we have generated target subfeature.
// CHECK-SUBTARGET: { "test-both-fusion-predicate", "Test BothFusionPredicate", Test::TestBothFusionPredicate // CHECK-SUBTARGET: { "test-both-fusion-predicate", "Test BothFusionPredicate", Test::TestBothFusionPredicate
// CHECK-SUBTARGET: { "test-commutable-fusion", "Test Commutable Fusion", Test::TestCommutableFusion // CHECK-SUBTARGET: { "test-commutable-fusion", "Test Commutable Fusion", Test::TestCommutableFusion
// CHECK-SUBTARGET: { "test-first-same-reg-fusion", "Test FirstSameReg", Test::TestFirstSameRegFusion
// CHECK-SUBTARGET: { "test-fusion", "Test Fusion", Test::TestFusion // CHECK-SUBTARGET: { "test-fusion", "Test Fusion", Test::TestFusion
// CHECK-SUBTARGET: { "test-single-fusion", "Test SingleFusion", Test::TestSingleFusion // CHECK-SUBTARGET: { "test-single-fusion", "Test SingleFusion", Test::TestSingleFusion
@ -246,8 +272,9 @@ def TestSingleFusion: SingleFusion<"test-single-fusion", "HasTestSingleFusion",
// CHECK-SUBTARGET: std::vector<MacroFusionPredTy> TestGenSubtargetInfo::getMacroFusions() const { // CHECK-SUBTARGET: std::vector<MacroFusionPredTy> TestGenSubtargetInfo::getMacroFusions() const {
// CHECK-SUBTARGET-NEXT: std::vector<MacroFusionPredTy> Fusions; // CHECK-SUBTARGET-NEXT: std::vector<MacroFusionPredTy> Fusions;
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestBothFusionPredicate)) Fusions.push_back(llvm::isTestBothFusionPredicate); // CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestBothFusionPredicate)) Fusions.push_back(llvm::isTestBothFusionPredicate);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestCommutableFusion)) Fusions.push_back(llvm::isTestCommutableFusion); // CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestCommutableFusion)) Fusions.push_back(llvm::isTestCommutableFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestFirstSameRegFusion)) Fusions.push_back(llvm::isTestFirstSameRegFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestFusion)) Fusions.push_back(llvm::isTestFusion); // CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestFusion)) Fusions.push_back(llvm::isTestFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestSingleFusion)) Fusions.push_back(llvm::isTestSingleFusion); // CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestSingleFusion)) Fusions.push_back(llvm::isTestSingleFusion);
// CHECK-SUBTARGET-NEXT: return Fusions; // CHECK-SUBTARGET-NEXT: return Fusions;

View File

@ -155,6 +155,36 @@ void MacroFusionPredicatorEmitter::emitFirstPredicate(const Record *Predicate,
<< "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n"; << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
OS.indent(4) << " return false;\n"; OS.indent(4) << " return false;\n";
OS.indent(2) << "}\n"; OS.indent(2) << "}\n";
} else if (Predicate->isSubClassOf("FirstInstHasSameReg")) {
int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
OS.indent(2) << "if (!FirstMI->getOperand(" << FirstOpIdx
<< ").getReg().isVirtual()) {\n";
OS.indent(4) << "if (FirstMI->getOperand(" << FirstOpIdx
<< ").getReg() != FirstMI->getOperand(" << SecondOpIdx
<< ").getReg())";
if (IsCommutable) {
OS << " {\n";
OS.indent(6) << "if (!FirstMI->getDesc().isCommutable())\n";
OS.indent(6) << " return false;\n";
OS.indent(6)
<< "unsigned SrcOpIdx1 = " << SecondOpIdx
<< ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
OS.indent(6)
<< "if (TII.findCommutedOpIndices(FirstMI, SrcOpIdx1, SrcOpIdx2))\n";
OS.indent(6)
<< " if (FirstMI->getOperand(" << FirstOpIdx
<< ").getReg() != FirstMI->getOperand(SrcOpIdx2).getReg())\n";
OS.indent(6) << " return false;\n";
OS.indent(4) << "}\n";
} else {
OS << "\n";
OS.indent(4) << " return false;\n";
}
OS.indent(2) << "}\n";
} else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) { } else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
OS.indent(2) << "{\n"; OS.indent(2) << "{\n";
OS.indent(4) << "const MachineInstr *MI = FirstMI;\n"; OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
@ -186,7 +216,7 @@ void MacroFusionPredicatorEmitter::emitSecondPredicate(const Record *Predicate,
OS << ")\n"; OS << ")\n";
OS.indent(4) << " return false;\n"; OS.indent(4) << " return false;\n";
OS.indent(2) << "}\n"; OS.indent(2) << "}\n";
} else if (Predicate->isSubClassOf("SameReg")) { } else if (Predicate->isSubClassOf("SecondInstHasSameReg")) {
int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx"); int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx"); int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");