Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
35258 views
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
// This TableGen backend processes `Fusion` definitions and generates
13
// predicators for checking if input instructions can be fused. These
14
// predicators can used in `MacroFusion` DAG mutation.
15
//
16
// The generated header file contains two parts: one for predicator
17
// declarations and one for predicator implementations. The user can get them
18
// by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or
19
// `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated
20
// header file.
21
//
22
// The generated predicator will be like:
23
//
24
// ```
25
// bool isNAME(const TargetInstrInfo &TII,
26
// const TargetSubtargetInfo &STI,
27
// const MachineInstr *FirstMI,
28
// const MachineInstr &SecondMI) {
29
// auto &MRI = SecondMI.getMF()->getRegInfo();
30
// /* Predicates */
31
// return true;
32
// }
33
// ```
34
//
35
// The `Predicates` part is generated from a list of `FusionPredicate`, which
36
// can be predefined predicates, a raw code string or `MCInstPredicate` defined
37
// in TargetInstrPredicate.td.
38
//
39
//===---------------------------------------------------------------------===//
40
41
#include "Common/CodeGenTarget.h"
42
#include "Common/PredicateExpander.h"
43
#include "llvm/Support/Debug.h"
44
#include "llvm/TableGen/Error.h"
45
#include "llvm/TableGen/Record.h"
46
#include "llvm/TableGen/TableGenBackend.h"
47
#include <vector>
48
49
using namespace llvm;
50
51
#define DEBUG_TYPE "macro-fusion-predicator"
52
53
namespace {
54
class MacroFusionPredicatorEmitter {
55
RecordKeeper &Records;
56
CodeGenTarget Target;
57
58
void emitMacroFusionDecl(ArrayRef<Record *> Fusions, PredicateExpander &PE,
59
raw_ostream &OS);
60
void emitMacroFusionImpl(ArrayRef<Record *> Fusions, PredicateExpander &PE,
61
raw_ostream &OS);
62
void emitPredicates(ArrayRef<Record *> FirstPredicate, bool IsCommutable,
63
PredicateExpander &PE, raw_ostream &OS);
64
void emitFirstPredicate(Record *SecondPredicate, bool IsCommutable,
65
PredicateExpander &PE, raw_ostream &OS);
66
void emitSecondPredicate(Record *SecondPredicate, bool IsCommutable,
67
PredicateExpander &PE, raw_ostream &OS);
68
void emitBothPredicate(Record *Predicates, bool IsCommutable,
69
PredicateExpander &PE, raw_ostream &OS);
70
71
public:
72
MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {}
73
74
void run(raw_ostream &OS);
75
};
76
} // End anonymous namespace.
77
78
void MacroFusionPredicatorEmitter::emitMacroFusionDecl(
79
ArrayRef<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
80
OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n";
81
OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n";
82
OS << "namespace llvm {\n";
83
84
for (Record *Fusion : Fusions) {
85
OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, "
86
<< "const TargetSubtargetInfo &, "
87
<< "const MachineInstr *, "
88
<< "const MachineInstr &);\n";
89
}
90
91
OS << "} // end namespace llvm\n";
92
OS << "\n#endif\n";
93
}
94
95
void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
96
ArrayRef<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
97
OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n";
98
OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n";
99
OS << "namespace llvm {\n";
100
101
for (Record *Fusion : Fusions) {
102
std::vector<Record *> Predicates =
103
Fusion->getValueAsListOfDefs("Predicates");
104
bool IsCommutable = Fusion->getValueAsBit("IsCommutable");
105
106
OS << "bool is" << Fusion->getName() << "(\n";
107
OS.indent(4) << "const TargetInstrInfo &TII,\n";
108
OS.indent(4) << "const TargetSubtargetInfo &STI,\n";
109
OS.indent(4) << "const MachineInstr *FirstMI,\n";
110
OS.indent(4) << "const MachineInstr &SecondMI) {\n";
111
OS.indent(2)
112
<< "[[maybe_unused]] auto &MRI = SecondMI.getMF()->getRegInfo();\n";
113
114
emitPredicates(Predicates, IsCommutable, PE, OS);
115
116
OS.indent(2) << "return true;\n";
117
OS << "}\n";
118
}
119
120
OS << "} // end namespace llvm\n";
121
OS << "\n#endif\n";
122
}
123
124
void MacroFusionPredicatorEmitter::emitPredicates(ArrayRef<Record *> Predicates,
125
bool IsCommutable,
126
PredicateExpander &PE,
127
raw_ostream &OS) {
128
for (Record *Predicate : Predicates) {
129
Record *Target = Predicate->getValueAsDef("Target");
130
if (Target->getName() == "first_fusion_target")
131
emitFirstPredicate(Predicate, IsCommutable, PE, OS);
132
else if (Target->getName() == "second_fusion_target")
133
emitSecondPredicate(Predicate, IsCommutable, PE, OS);
134
else if (Target->getName() == "both_fusion_target")
135
emitBothPredicate(Predicate, IsCommutable, PE, OS);
136
else
137
PrintFatalError(Target->getLoc(),
138
"Unsupported 'FusionTarget': " + Target->getName());
139
}
140
}
141
142
void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
143
bool IsCommutable,
144
PredicateExpander &PE,
145
raw_ostream &OS) {
146
if (Predicate->isSubClassOf("WildcardPred")) {
147
OS.indent(2) << "if (!FirstMI)\n";
148
OS.indent(2) << " return "
149
<< (Predicate->getValueAsBit("ReturnValue") ? "true" : "false")
150
<< ";\n";
151
} else if (Predicate->isSubClassOf("OneUsePred")) {
152
OS.indent(2) << "{\n";
153
OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";
154
OS.indent(4)
155
<< "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
156
OS.indent(4) << " return false;\n";
157
OS.indent(2) << "}\n";
158
} else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
159
OS.indent(2) << "{\n";
160
OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
161
OS.indent(4) << "if (";
162
PE.setNegatePredicate(true);
163
PE.setIndentLevel(3);
164
PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
165
OS << ")\n";
166
OS.indent(4) << " return false;\n";
167
OS.indent(2) << "}\n";
168
} else {
169
PrintFatalError(Predicate->getLoc(),
170
"Unsupported predicate for first instruction: " +
171
Predicate->getType()->getAsString());
172
}
173
}
174
175
void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
176
bool IsCommutable,
177
PredicateExpander &PE,
178
raw_ostream &OS) {
179
if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
180
OS.indent(2) << "{\n";
181
OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
182
OS.indent(4) << "if (";
183
PE.setNegatePredicate(true);
184
PE.setIndentLevel(3);
185
PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
186
OS << ")\n";
187
OS.indent(4) << " return false;\n";
188
OS.indent(2) << "}\n";
189
} else if (Predicate->isSubClassOf("SameReg")) {
190
int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
191
int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
192
193
OS.indent(2) << "if (!SecondMI.getOperand(" << FirstOpIdx
194
<< ").getReg().isVirtual()) {\n";
195
OS.indent(4) << "if (SecondMI.getOperand(" << FirstOpIdx
196
<< ").getReg() != SecondMI.getOperand(" << SecondOpIdx
197
<< ").getReg())";
198
199
if (IsCommutable) {
200
OS << " {\n";
201
OS.indent(6) << "if (!SecondMI.getDesc().isCommutable())\n";
202
OS.indent(6) << " return false;\n";
203
204
OS.indent(6)
205
<< "unsigned SrcOpIdx1 = " << SecondOpIdx
206
<< ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
207
OS.indent(6)
208
<< "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
209
OS.indent(6)
210
<< " if (SecondMI.getOperand(" << FirstOpIdx
211
<< ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
212
OS.indent(6) << " return false;\n";
213
OS.indent(4) << "}\n";
214
} else {
215
OS << "\n";
216
OS.indent(4) << " return false;\n";
217
}
218
OS.indent(2) << "}\n";
219
} else {
220
PrintFatalError(Predicate->getLoc(),
221
"Unsupported predicate for second instruction: " +
222
Predicate->getType()->getAsString());
223
}
224
}
225
226
void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,
227
bool IsCommutable,
228
PredicateExpander &PE,
229
raw_ostream &OS) {
230
if (Predicate->isSubClassOf("FusionPredicateWithCode"))
231
OS << Predicate->getValueAsString("Predicate");
232
else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
233
emitFirstPredicate(Predicate, IsCommutable, PE, OS);
234
emitSecondPredicate(Predicate, IsCommutable, PE, OS);
235
} else if (Predicate->isSubClassOf("TieReg")) {
236
int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
237
int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
238
OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx
239
<< ").isReg() &&\n";
240
OS.indent(2) << " SecondMI.getOperand(" << SecondOpIdx
241
<< ").isReg() &&\n";
242
OS.indent(2) << " FirstMI->getOperand(" << FirstOpIdx
243
<< ").getReg() == SecondMI.getOperand(" << SecondOpIdx
244
<< ").getReg()))";
245
246
if (IsCommutable) {
247
OS << " {\n";
248
OS.indent(4) << "if (!SecondMI.getDesc().isCommutable())\n";
249
OS.indent(4) << " return false;\n";
250
251
OS.indent(4)
252
<< "unsigned SrcOpIdx1 = " << SecondOpIdx
253
<< ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
254
OS.indent(4)
255
<< "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
256
OS.indent(4)
257
<< " if (FirstMI->getOperand(" << FirstOpIdx
258
<< ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
259
OS.indent(4) << " return false;\n";
260
OS.indent(2) << "}";
261
} else {
262
OS << "\n";
263
OS.indent(2) << " return false;";
264
}
265
OS << "\n";
266
} else
267
PrintFatalError(Predicate->getLoc(),
268
"Unsupported predicate for both instruction: " +
269
Predicate->getType()->getAsString());
270
}
271
272
void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
273
// Emit file header.
274
emitSourceFileHeader("Macro Fusion Predicators", OS);
275
276
PredicateExpander PE(Target.getName());
277
PE.setByRef(false);
278
PE.setExpandForMC(false);
279
280
std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion");
281
// Sort macro fusions by name.
282
sort(Fusions, LessRecord());
283
emitMacroFusionDecl(Fusions, PE, OS);
284
OS << "\n";
285
emitMacroFusionImpl(Fusions, PE, OS);
286
}
287
288
static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>
289
X("gen-macro-fusion-pred", "Generate macro fusion predicators.");
290
291