Skip to content

Commit a0e6b7c

Browse files
authored
[TableGen] Add a backend to generate MacroFusion predicators (#72222)
`FusionPredicate` is used to predicate if target instruction matches the requirement. The targets can be firstMI, secondMI or both. The `Fusion` contains a list of `FusionPredicate`. The generated code will be like: ``` bool isNAME(const TargetInstrInfo &TII, const TargetSubtargetInfo &STI, const MachineInstr *FirstMI, const MachineInstr &SecondMI) { auto &MRI = SecondMI.getMF()->getRegInfo(); /* Predicates */ return true; } ``` A boilerplate class called `SimpleFusion` is added. `SimpleFusion` has a predefined structure of predicates and accepts predicate for `firstMI`, predicate for `secondMI` and epilog/prolog as arguments. The generated code for `SimpleFusion` will be like: ``` bool isNAME(const TargetInstrInfo &TII, const TargetSubtargetInfo &STI, const MachineInstr *FirstMI, const MachineInstr &SecondMI) { auto &MRI = SecondMI.getMF()->getRegInfo(); /* Prolog */ /* Predicate for `SecondMI` */ /* Wildcard */ /* Predicate for `FirstMI` */ /* Check One Use */ /* Tie registers */ /* Epilog */ return true; } ```
1 parent 65df696 commit a0e6b7c

File tree

7 files changed

+462
-0
lines changed

7 files changed

+462
-0
lines changed

llvm/include/llvm/Target/TargetInstrPredicate.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ class MCOperandPredicate<int Index> : MCInstPredicate {
9595
// Return true if machine operand at position `Index` is a register operand.
9696
class CheckIsRegOperand<int Index> : MCOperandPredicate<Index>;
9797

98+
// Return true if machine operand at position `Index` is a virtual register operand.
99+
class CheckIsVRegOperand<int Index> : MCOperandPredicate<Index>;
100+
101+
// Return true if machine operand at position `Index` is not a virtual register operand.
102+
class CheckIsNotVRegOperand<int Index> : CheckNot<CheckIsVRegOperand<Index>>;
103+
98104
// Return true if machine operand at position `Index` is an immediate operand.
99105
class CheckIsImmOperand<int Index> : MCOperandPredicate<Index>;
100106

llvm/include/llvm/Target/TargetSchedule.td

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,3 +584,116 @@ class MemoryQueue<ProcResourceKind PR> {
584584

585585
class LoadQueue<ProcResourceKind LDQueue> : MemoryQueue<LDQueue>;
586586
class StoreQueue<ProcResourceKind STQueue> : MemoryQueue<STQueue>;
587+
588+
// The target instruction that FusionPredicate will be evaluated on.
589+
class FusionTarget;
590+
def first_fusion_target : FusionTarget;
591+
def second_fusion_target : FusionTarget;
592+
def both_fusion_target : FusionTarget;
593+
594+
// Base class of FusionPredicate, etc. The avaliable variables are:
595+
// * const TargetInstrInfo &TII
596+
// * const TargetSubtargetInfo &STI
597+
// * const MachineRegisterInfo &MRI
598+
// * const MachineInstr *FirstMI
599+
// * const MachineInstr &SecondMI
600+
class FusionPredicate<FusionTarget target> {
601+
FusionTarget Target = target;
602+
}
603+
class FirstFusionPredicate: FusionPredicate<first_fusion_target>;
604+
class SecondFusionPredicate: FusionPredicate<second_fusion_target>;
605+
class BothFusionPredicate: FusionPredicate<both_fusion_target>;
606+
607+
// FusionPredicate with raw code predicate.
608+
class FusionPredicateWithCode<code pred> : FusionPredicate<both_fusion_target> {
609+
code Predicate = pred;
610+
}
611+
612+
// FusionPredicate with MCInstPredicate.
613+
class FusionPredicateWithMCInstPredicate<FusionTarget target, MCInstPredicate pred>
614+
: FusionPredicate<target> {
615+
MCInstPredicate Predicate = pred;
616+
}
617+
class FirstFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
618+
: FusionPredicateWithMCInstPredicate<first_fusion_target, pred>;
619+
class SecondFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
620+
: FusionPredicateWithMCInstPredicate<second_fusion_target, pred>;
621+
// The pred will be applied on both firstMI and secondMI.
622+
class BothFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
623+
: FusionPredicateWithMCInstPredicate<second_fusion_target, pred>;
624+
625+
// Tie firstOpIdx and secondOpIdx. The operand of `FirstMI` at position
626+
// `firstOpIdx` should be the same as the operand of `SecondMI` at position
627+
// `secondOpIdx`.
628+
class TieReg<int firstOpIdx, int secondOpIdx> : BothFusionPredicate {
629+
int FirstOpIdx = firstOpIdx;
630+
int SecondOpIdx = secondOpIdx;
631+
}
632+
633+
// A predicate for wildcard. The generated code will be like:
634+
// ```
635+
// if (!FirstMI)
636+
// return ReturnValue;
637+
// ```
638+
class WildcardPred<bit ret> : FirstFusionPredicate {
639+
bit ReturnValue = ret;
640+
}
641+
def WildcardFalse : WildcardPred<0>;
642+
def WildcardTrue : WildcardPred<1>;
643+
644+
// Indicates that the destination register of `FirstMI` should have one use if
645+
// it is a virtual register.
646+
class OneUsePred : FirstFusionPredicate;
647+
def OneUse : OneUsePred;
648+
649+
// Handled by MacroFusionPredicatorEmitter backend.
650+
// The generated predicator will be like:
651+
// ```
652+
// bool isNAME(const TargetInstrInfo &TII,
653+
// const TargetSubtargetInfo &STI,
654+
// const MachineInstr *FirstMI,
655+
// const MachineInstr &SecondMI) {
656+
// auto &MRI = SecondMI.getMF()->getRegInfo();
657+
// /* Predicates */
658+
// return true;
659+
// }
660+
// ```
661+
class Fusion<list<FusionPredicate> predicates> {
662+
list<FusionPredicate> Predicates = predicates;
663+
}
664+
665+
// The generated predicator will be like:
666+
// ```
667+
// bool isNAME(const TargetInstrInfo &TII,
668+
// const TargetSubtargetInfo &STI,
669+
// const MachineInstr *FirstMI,
670+
// const MachineInstr &SecondMI) {
671+
// auto &MRI = SecondMI.getMF()->getRegInfo();
672+
// /* Prolog */
673+
// /* Predicate for `SecondMI` */
674+
// /* Wildcard */
675+
// /* Predicate for `FirstMI` */
676+
// /* Check One Use */
677+
// /* Tie registers */
678+
// /* Epilog */
679+
// return true;
680+
// }
681+
// ```
682+
class SimpleFusion<MCInstPredicate firstPred, MCInstPredicate secondPred,
683+
list<FusionPredicate> prolog = [],
684+
list<FusionPredicate> epilog = []>
685+
: Fusion<!listconcat(
686+
prolog,
687+
[
688+
SecondFusionPredicateWithMCInstPredicate<secondPred>,
689+
WildcardTrue,
690+
FirstFusionPredicateWithMCInstPredicate<firstPred>,
691+
SecondFusionPredicateWithMCInstPredicate<
692+
CheckAny<[
693+
CheckIsVRegOperand<0>,
694+
CheckSameRegOperand<0, 1>
695+
]>>,
696+
OneUse,
697+
TieReg<0, 1>,
698+
],
699+
epilog)>;

llvm/test/TableGen/MacroFusion.td

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// RUN: llvm-tblgen -gen-macro-fusion-pred -I %p/../../include %s | FileCheck %s --check-prefix=CHECK-PREDICATOR
2+
3+
include "llvm/Target/Target.td"
4+
5+
def TestInstrInfo : InstrInfo { }
6+
def TestAsmWriter : AsmWriter {
7+
int PassSubtarget = 1;
8+
}
9+
10+
def Test : Target {
11+
let InstructionSet = TestInstrInfo;
12+
let AssemblyWriters = [TestAsmWriter];
13+
}
14+
15+
let Namespace = "Test" in {
16+
foreach i = 0-32 in {
17+
def X#i : Register<"x"#i>;
18+
}
19+
20+
def GPR : RegisterClass<"GPR", [i32], 32, (sequence "X%u", 0, 32)>;
21+
22+
class TestInst<int Opc> : Instruction {
23+
field bits<32> Inst;
24+
field bits<32> SoftFail = 0;
25+
let Size = 4;
26+
let Inst = Opc;
27+
let OutOperandList = (outs);
28+
let InOperandList = (ins);
29+
let AsmString = NAME;
30+
}
31+
}
32+
33+
def Inst0 : TestInst<0>;
34+
def Inst1 : TestInst<1>;
35+
36+
def TestFusion: SimpleFusion<CheckOpcode<[Inst0]>,
37+
CheckAll<[
38+
CheckOpcode<[Inst1]>,
39+
CheckRegOperand<0, X0>
40+
]>>;
41+
42+
// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_DECL
43+
// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_DECL
44+
// CHECK-PREDICATOR-EMPTY:
45+
// CHECK-PREDICATOR-NEXT: namespace llvm {
46+
// CHECK-PREDICATOR-NEXT: bool isTestFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
47+
// CHECK-PREDICATOR-NEXT: } // end namespace llvm
48+
// CHECK-PREDICATOR-EMPTY:
49+
// CHECK-PREDICATOR-NEXT: #endif
50+
51+
// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_IMPL
52+
// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_IMPL
53+
// CHECK-PREDICATOR-EMPTY:
54+
// CHECK-PREDICATOR-NEXT: namespace llvm {
55+
// CHECK-PREDICATOR-NEXT: bool isTestFusion(
56+
// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
57+
// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
58+
// CHECK-PREDICATOR-NEXT: const MachineInstr *FirstMI,
59+
// CHECK-PREDICATOR-NEXT: const MachineInstr &SecondMI) {
60+
// CHECK-PREDICATOR-NEXT: auto &MRI = SecondMI.getMF()->getRegInfo();
61+
// CHECK-PREDICATOR-NEXT: {
62+
// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = &SecondMI;
63+
// CHECK-PREDICATOR-NEXT: if (!(
64+
// CHECK-PREDICATOR-NEXT: ( MI->getOpcode() == Test::Inst1 )
65+
// CHECK-PREDICATOR-NEXT: && MI->getOperand(0).getReg() == Test::X0
66+
// CHECK-PREDICATOR-NEXT: ))
67+
// CHECK-PREDICATOR-NEXT: return false;
68+
// CHECK-PREDICATOR-NEXT: }
69+
// CHECK-PREDICATOR-NEXT: if (!FirstMI)
70+
// CHECK-PREDICATOR-NEXT: return true;
71+
// CHECK-PREDICATOR-NEXT: {
72+
// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = FirstMI;
73+
// CHECK-PREDICATOR-NEXT: if (( MI->getOpcode() != Test::Inst0 ))
74+
// CHECK-PREDICATOR-NEXT: return false;
75+
// CHECK-PREDICATOR-NEXT: }
76+
// CHECK-PREDICATOR-NEXT: {
77+
// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = &SecondMI;
78+
// CHECK-PREDICATOR-NEXT: if (!(
79+
// CHECK-PREDICATOR-NEXT: MI->getOperand(0).getReg().isVirtual()
80+
// CHECK-PREDICATOR-NEXT: || MI->getOperand(0).getReg() == MI->getOperand(1).getReg()
81+
// CHECK-PREDICATOR-NEXT: ))
82+
// CHECK-PREDICATOR-NEXT: return false;
83+
// CHECK-PREDICATOR-NEXT: }
84+
// CHECK-PREDICATOR-NEXT: {
85+
// CHECK-PREDICATOR-NEXT: Register FirstDest = FirstMI->getOperand(0).getReg();
86+
// CHECK-PREDICATOR-NEXT: if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))
87+
// CHECK-PREDICATOR-NEXT: return false;
88+
// CHECK-PREDICATOR-NEXT: }
89+
// CHECK-PREDICATOR-NEXT: if (!(FirstMI->getOperand(0).isReg() &&
90+
// CHECK-PREDICATOR-NEXT: SecondMI.getOperand(1).isReg() &&
91+
// CHECK-PREDICATOR-NEXT: FirstMI->getOperand(0).getReg() == SecondMI.getOperand(1).getReg()))
92+
// CHECK-PREDICATOR-NEXT: return false;
93+
// CHECK-PREDICATOR-NEXT: return true;
94+
// CHECK-PREDICATOR-NEXT: }
95+
// CHECK-PREDICATOR-NEXT: } // end namespace llvm
96+
// CHECK-PREDICATOR-EMPTY:
97+
// CHECK-PREDICATOR-NEXT: #endif

llvm/utils/TableGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ add_tablegen(llvm-tblgen LLVM
7272
PredicateExpander.cpp
7373
PseudoLoweringEmitter.cpp
7474
CompressInstEmitter.cpp
75+
MacroFusionPredicatorEmitter.cpp
7576
RegisterBankEmitter.cpp
7677
RegisterInfoEmitter.cpp
7778
SearchableTableEmitter.cpp

0 commit comments

Comments
 (0)