Skip to content

Commit 3787fed

Browse files
committed
[TableGen] Add a backend to generate MacroFusion predicators
`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 e910bae commit 3787fed

File tree

6 files changed

+333
-0
lines changed

6 files changed

+333
-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 : FusionTarget;
591+
def second : FusionTarget;
592+
def both : 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>;
604+
class SecondFusionPredicate: FusionPredicate<second>;
605+
class BothFusionPredicate: FusionPredicate<both>;
606+
607+
// FusionPredicate with raw code predicate.
608+
class FusionPredicateWithCode<code pred> : FusionPredicate<both> {
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, pred>;
619+
class SecondFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
620+
: FusionPredicateWithMCInstPredicate<second, pred>;
621+
// The pred will be applied on both firstMI and secondMI.
622+
class BothFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
623+
: FusionPredicateWithMCInstPredicate<second, 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/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
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
//===------ MacroFusionPredicatorEmitter.cpp - Generator for Fusion ------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===---------------------------------------------------------------------===//
8+
//
9+
// MacroFusionPredicatorEmitter implements a TableGen-driven predicators
10+
// generator for macro-op fusions.
11+
//
12+
//===---------------------------------------------------------------------===//
13+
14+
#include "CodeGenTarget.h"
15+
#include "PredicateExpander.h"
16+
#include "llvm/ADT/SmallVector.h"
17+
#include "llvm/Support/Debug.h"
18+
#include "llvm/TableGen/Error.h"
19+
#include "llvm/TableGen/Record.h"
20+
#include "llvm/TableGen/TableGenBackend.h"
21+
#include <set>
22+
#include <vector>
23+
24+
using namespace llvm;
25+
26+
#define DEBUG_TYPE "macro-fusion-predicator"
27+
28+
namespace {
29+
class MacroFusionPredicatorEmitter {
30+
RecordKeeper &Records;
31+
CodeGenTarget Target;
32+
33+
void emitMacroFusionDecl(std::vector<Record *> Fusions, PredicateExpander &PE,
34+
raw_ostream &OS);
35+
void emitMacroFusionImpl(std::vector<Record *> Fusions, PredicateExpander &PE,
36+
raw_ostream &OS);
37+
void emitPredicates(std::vector<Record *> &FirstPredicate,
38+
PredicateExpander &PE, raw_ostream &OS);
39+
void emitFirstPredicate(Record *SecondPredicate, PredicateExpander &PE,
40+
raw_ostream &OS);
41+
void emitSecondPredicate(Record *SecondPredicate, PredicateExpander &PE,
42+
raw_ostream &OS);
43+
void emitBothPredicate(Record *Predicates, PredicateExpander &PE,
44+
raw_ostream &OS);
45+
46+
public:
47+
MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {}
48+
49+
void run(raw_ostream &OS);
50+
};
51+
} // End anonymous namespace.
52+
53+
void MacroFusionPredicatorEmitter::emitMacroFusionDecl(
54+
std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
55+
OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n";
56+
57+
for (Record *Fusion : Fusions) {
58+
OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, "
59+
<< "const TargetSubtargetInfo &, "
60+
<< "const MachineInstr *, "
61+
<< "const MachineInstr &);\n";
62+
}
63+
64+
OS << "\n#endif\n";
65+
OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n";
66+
}
67+
68+
void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
69+
std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
70+
OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n";
71+
72+
for (Record *Fusion : Fusions) {
73+
std::vector<Record *> Predicates =
74+
Fusion->getValueAsListOfDefs("Predicates");
75+
76+
OS << "bool is" << Fusion->getName() << "(\n";
77+
OS.indent(5) << "const TargetInstrInfo &TII,\n";
78+
OS.indent(5) << "const TargetSubtargetInfo &STI,\n";
79+
OS.indent(5) << "const MachineInstr *FirstMI,\n";
80+
OS.indent(5) << "const MachineInstr &SecondMI) {\n";
81+
OS.indent(2) << "auto &MRI = SecondMI.getMF()->getRegInfo();\n";
82+
83+
emitPredicates(Predicates, PE, OS);
84+
85+
OS.indent(2) << "return true;\n";
86+
OS << "}\n";
87+
}
88+
89+
OS << "\n#endif\n";
90+
OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n";
91+
}
92+
93+
void MacroFusionPredicatorEmitter::emitPredicates(
94+
std::vector<Record *> &Predicates, PredicateExpander &PE, raw_ostream &OS) {
95+
for (Record *Predicate : Predicates) {
96+
Record *Target = Predicate->getValueAsDef("Target");
97+
if (Target->getName() == "first")
98+
emitFirstPredicate(Predicate, PE, OS);
99+
else if (Target->getName() == "second")
100+
emitSecondPredicate(Predicate, PE, OS);
101+
else if (Target->getName() == "both")
102+
emitBothPredicate(Predicate, PE, OS);
103+
else
104+
PrintFatalError(Target->getLoc(),
105+
"Unsupported 'FusionTarget': " + Target->getName());
106+
}
107+
}
108+
109+
void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
110+
PredicateExpander &PE,
111+
raw_ostream &OS) {
112+
if (Predicate->isSubClassOf("WildcardPred")) {
113+
OS.indent(2) << "if (!FirstMI)\n";
114+
OS.indent(2) << " return "
115+
<< (Predicate->getValueAsBit("ReturnValue") ? "true" : "false")
116+
<< ";\n";
117+
} else if (Predicate->isSubClassOf("OneUsePred")) {
118+
OS.indent(2) << "{\n";
119+
OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";
120+
OS.indent(4)
121+
<< "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
122+
OS.indent(4) << " return false;\n";
123+
OS.indent(2) << "}\n";
124+
} else if (Predicate->isSubClassOf(
125+
"FirstFusionPredicateWithMCInstPredicate")) {
126+
OS.indent(2) << "{\n";
127+
OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
128+
OS.indent(4) << "if (";
129+
PE.setNegatePredicate(true);
130+
PE.setIndentLevel(3);
131+
PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
132+
OS << ")\n";
133+
OS.indent(4) << " return false;\n";
134+
OS.indent(2) << "}\n";
135+
} else {
136+
PrintFatalError(Predicate->getLoc(),
137+
"Unsupported predicate for first instruction: " +
138+
Predicate->getType()->getAsString());
139+
}
140+
}
141+
142+
void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
143+
PredicateExpander &PE,
144+
raw_ostream &OS) {
145+
if (Predicate->isSubClassOf("SecondFusionPredicateWithMCInstPredicate")) {
146+
OS.indent(2) << "{\n";
147+
OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
148+
OS.indent(4) << "if (";
149+
PE.setNegatePredicate(true);
150+
PE.setIndentLevel(3);
151+
PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
152+
OS << ")\n";
153+
OS.indent(4) << " return false;\n";
154+
OS.indent(2) << "}\n";
155+
} else {
156+
PrintFatalError(Predicate->getLoc(),
157+
"Unsupported predicate for first instruction: " +
158+
Predicate->getType()->getAsString());
159+
}
160+
}
161+
162+
void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,
163+
PredicateExpander &PE,
164+
raw_ostream &OS) {
165+
if (Predicate->isSubClassOf("FusionPredicateWithCode"))
166+
OS << Predicate->getValueAsString("Predicate");
167+
else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
168+
Record *MCPred = Predicate->getValueAsDef("Predicate");
169+
emitFirstPredicate(MCPred, PE, OS);
170+
emitSecondPredicate(MCPred, PE, OS);
171+
} else if (Predicate->isSubClassOf("TieReg")) {
172+
int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
173+
int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
174+
OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx
175+
<< ").isReg() &&\n";
176+
OS.indent(2) << " SecondMI.getOperand(" << SecondOpIdx
177+
<< ").isReg() &&\n";
178+
OS.indent(2) << " FirstMI->getOperand(" << FirstOpIdx
179+
<< ").getReg() == SecondMI.getOperand(" << SecondOpIdx
180+
<< ").getReg()))\n";
181+
OS.indent(2) << " return false;\n";
182+
} else
183+
PrintFatalError(Predicate->getLoc(),
184+
"Unsupported predicate for both instruction: " +
185+
Predicate->getType()->getAsString());
186+
}
187+
188+
void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
189+
// Emit file header.
190+
emitSourceFileHeader("Macro Fusion Predicators", OS);
191+
192+
PredicateExpander PE(Target.getName());
193+
PE.setByRef(false);
194+
PE.setExpandForMC(false);
195+
196+
std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion");
197+
// Sort macro fusions by name.
198+
sort(Fusions, LessRecord());
199+
emitMacroFusionDecl(Fusions, PE, OS);
200+
emitMacroFusionImpl(Fusions, PE, OS);
201+
}
202+
203+
static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>
204+
X("gen-macro-fusion-pred", "Generate macro fusion predicators.");

llvm/utils/TableGen/PredicateExpander.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ void PredicateExpander::expandCheckIsRegOperand(raw_ostream &OS, int OpIndex) {
194194
<< "getOperand(" << OpIndex << ").isReg() ";
195195
}
196196

197+
void PredicateExpander::expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) {
198+
OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->")
199+
<< "getOperand(" << OpIndex << ").getReg().isVirtual()";
200+
}
201+
197202
void PredicateExpander::expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) {
198203
OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->")
199204
<< "getOperand(" << OpIndex << ").isImm() ";
@@ -319,6 +324,9 @@ void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) {
319324
if (Rec->isSubClassOf("CheckIsRegOperand"))
320325
return expandCheckIsRegOperand(OS, Rec->getValueAsInt("OpIndex"));
321326

327+
if (Rec->isSubClassOf("CheckIsVRegOperand"))
328+
return expandCheckIsVRegOperand(OS, Rec->getValueAsInt("OpIndex"));
329+
322330
if (Rec->isSubClassOf("CheckIsImmOperand"))
323331
return expandCheckIsImmOperand(OS, Rec->getValueAsInt("OpIndex"));
324332

llvm/utils/TableGen/PredicateExpander.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class PredicateExpander {
7575
bool IsCheckAll);
7676
void expandTIIFunctionCall(raw_ostream &OS, StringRef MethodName);
7777
void expandCheckIsRegOperand(raw_ostream &OS, int OpIndex);
78+
void expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex);
7879
void expandCheckIsImmOperand(raw_ostream &OS, int OpIndex);
7980
void expandCheckInvalidRegOperand(raw_ostream &OS, int OpIndex);
8081
void expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn,

0 commit comments

Comments
 (0)