Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
35258 views
1
//===- PseudoLoweringEmitter.cpp - PseudoLowering Generator -----*- C++ -*-===//
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
#include "Common/CodeGenInstruction.h"
10
#include "Common/CodeGenTarget.h"
11
#include "llvm/ADT/IndexedMap.h"
12
#include "llvm/ADT/SmallVector.h"
13
#include "llvm/ADT/StringMap.h"
14
#include "llvm/Support/Debug.h"
15
#include "llvm/Support/ErrorHandling.h"
16
#include "llvm/TableGen/Error.h"
17
#include "llvm/TableGen/Record.h"
18
#include "llvm/TableGen/TableGenBackend.h"
19
#include <vector>
20
using namespace llvm;
21
22
#define DEBUG_TYPE "pseudo-lowering"
23
24
namespace {
25
class PseudoLoweringEmitter {
26
struct OpData {
27
enum MapKind { Operand, Imm, Reg };
28
MapKind Kind;
29
union {
30
unsigned Operand; // Operand number mapped to.
31
uint64_t Imm; // Integer immedate value.
32
Record *Reg; // Physical register.
33
} Data;
34
};
35
struct PseudoExpansion {
36
CodeGenInstruction Source; // The source pseudo instruction definition.
37
CodeGenInstruction Dest; // The destination instruction to lower to.
38
IndexedMap<OpData> OperandMap;
39
40
PseudoExpansion(CodeGenInstruction &s, CodeGenInstruction &d,
41
IndexedMap<OpData> &m)
42
: Source(s), Dest(d), OperandMap(m) {}
43
};
44
45
RecordKeeper &Records;
46
47
// It's overkill to have an instance of the full CodeGenTarget object,
48
// but it loads everything on demand, not in the constructor, so it's
49
// lightweight in performance, so it works out OK.
50
CodeGenTarget Target;
51
52
SmallVector<PseudoExpansion, 64> Expansions;
53
54
unsigned addDagOperandMapping(Record *Rec, DagInit *Dag,
55
CodeGenInstruction &Insn,
56
IndexedMap<OpData> &OperandMap,
57
unsigned BaseIdx);
58
void evaluateExpansion(Record *Pseudo);
59
void emitLoweringEmitter(raw_ostream &o);
60
61
public:
62
PseudoLoweringEmitter(RecordKeeper &R) : Records(R), Target(R) {}
63
64
/// run - Output the pseudo-lowerings.
65
void run(raw_ostream &o);
66
};
67
} // End anonymous namespace
68
69
// FIXME: This pass currently can only expand a pseudo to a single instruction.
70
// The pseudo expansion really should take a list of dags, not just
71
// a single dag, so we can do fancier things.
72
73
unsigned PseudoLoweringEmitter::addDagOperandMapping(
74
Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,
75
IndexedMap<OpData> &OperandMap, unsigned BaseIdx) {
76
unsigned OpsAdded = 0;
77
for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) {
78
if (DefInit *DI = dyn_cast<DefInit>(Dag->getArg(i))) {
79
// Physical register reference. Explicit check for the special case
80
// "zero_reg" definition.
81
if (DI->getDef()->isSubClassOf("Register") ||
82
DI->getDef()->getName() == "zero_reg") {
83
OperandMap[BaseIdx + i].Kind = OpData::Reg;
84
OperandMap[BaseIdx + i].Data.Reg = DI->getDef();
85
++OpsAdded;
86
continue;
87
}
88
89
// Normal operands should always have the same type, or we have a
90
// problem.
91
// FIXME: We probably shouldn't ever get a non-zero BaseIdx here.
92
assert(BaseIdx == 0 && "Named subargument in pseudo expansion?!");
93
// FIXME: Are the message operand types backward?
94
if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec) {
95
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
96
"', operand type '" + DI->getDef()->getName() +
97
"' does not match expansion operand type '" +
98
Insn.Operands[BaseIdx + i].Rec->getName() + "'");
99
PrintFatalNote(DI->getDef(),
100
"Value was assigned at the following location:");
101
}
102
// Source operand maps to destination operand. The Data element
103
// will be filled in later, just set the Kind for now. Do it
104
// for each corresponding MachineInstr operand, not just the first.
105
for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I)
106
OperandMap[BaseIdx + i + I].Kind = OpData::Operand;
107
OpsAdded += Insn.Operands[i].MINumOperands;
108
} else if (IntInit *II = dyn_cast<IntInit>(Dag->getArg(i))) {
109
OperandMap[BaseIdx + i].Kind = OpData::Imm;
110
OperandMap[BaseIdx + i].Data.Imm = II->getValue();
111
++OpsAdded;
112
} else if (auto *BI = dyn_cast<BitsInit>(Dag->getArg(i))) {
113
auto *II =
114
cast<IntInit>(BI->convertInitializerTo(IntRecTy::get(Records)));
115
OperandMap[BaseIdx + i].Kind = OpData::Imm;
116
OperandMap[BaseIdx + i].Data.Imm = II->getValue();
117
++OpsAdded;
118
} else if (DagInit *SubDag = dyn_cast<DagInit>(Dag->getArg(i))) {
119
// Just add the operands recursively. This is almost certainly
120
// a constant value for a complex operand (> 1 MI operand).
121
unsigned NewOps =
122
addDagOperandMapping(Rec, SubDag, Insn, OperandMap, BaseIdx + i);
123
OpsAdded += NewOps;
124
// Since we added more than one, we also need to adjust the base.
125
BaseIdx += NewOps - 1;
126
} else
127
llvm_unreachable("Unhandled pseudo-expansion argument type!");
128
}
129
return OpsAdded;
130
}
131
132
void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
133
LLVM_DEBUG(dbgs() << "Pseudo definition: " << Rec->getName() << "\n");
134
135
// Validate that the result pattern has the corrent number and types
136
// of arguments for the instruction it references.
137
DagInit *Dag = Rec->getValueAsDag("ResultInst");
138
assert(Dag && "Missing result instruction in pseudo expansion!");
139
LLVM_DEBUG(dbgs() << " Result: " << *Dag << "\n");
140
141
DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator());
142
if (!OpDef) {
143
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
144
"', result operator is not a record");
145
PrintFatalNote(Rec->getValue("ResultInst"),
146
"Result was assigned at the following location:");
147
}
148
Record *Operator = OpDef->getDef();
149
if (!Operator->isSubClassOf("Instruction")) {
150
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
151
"', result operator '" + Operator->getName() +
152
"' is not an instruction");
153
PrintFatalNote(Rec->getValue("ResultInst"),
154
"Result was assigned at the following location:");
155
}
156
157
CodeGenInstruction Insn(Operator);
158
159
if (Insn.isCodeGenOnly || Insn.isPseudo) {
160
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
161
"', result operator '" + Operator->getName() +
162
"' cannot be a pseudo instruction");
163
PrintFatalNote(Rec->getValue("ResultInst"),
164
"Result was assigned at the following location:");
165
}
166
167
if (Insn.Operands.size() != Dag->getNumArgs()) {
168
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
169
"', result operator '" + Operator->getName() +
170
"' has the wrong number of operands");
171
PrintFatalNote(Rec->getValue("ResultInst"),
172
"Result was assigned at the following location:");
173
}
174
175
unsigned NumMIOperands = 0;
176
for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i)
177
NumMIOperands += Insn.Operands[i].MINumOperands;
178
IndexedMap<OpData> OperandMap;
179
OperandMap.grow(NumMIOperands);
180
181
addDagOperandMapping(Rec, Dag, Insn, OperandMap, 0);
182
183
// If there are more operands that weren't in the DAG, they have to
184
// be operands that have default values, or we have an error. Currently,
185
// Operands that are a subclass of OperandWithDefaultOp have default values.
186
187
// Validate that each result pattern argument has a matching (by name)
188
// argument in the source instruction, in either the (outs) or (ins) list.
189
// Also check that the type of the arguments match.
190
//
191
// Record the mapping of the source to result arguments for use by
192
// the lowering emitter.
193
CodeGenInstruction SourceInsn(Rec);
194
StringMap<unsigned> SourceOperands;
195
for (unsigned i = 0, e = SourceInsn.Operands.size(); i != e; ++i)
196
SourceOperands[SourceInsn.Operands[i].Name] = i;
197
198
LLVM_DEBUG(dbgs() << " Operand mapping:\n");
199
for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i) {
200
// We've already handled constant values. Just map instruction operands
201
// here.
202
if (OperandMap[Insn.Operands[i].MIOperandNo].Kind != OpData::Operand)
203
continue;
204
StringMap<unsigned>::iterator SourceOp =
205
SourceOperands.find(Dag->getArgNameStr(i));
206
if (SourceOp == SourceOperands.end()) {
207
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
208
"', output operand '" + Dag->getArgNameStr(i) +
209
"' has no matching source operand");
210
PrintFatalNote(Rec->getValue("ResultInst"),
211
"Value was assigned at the following location:");
212
}
213
// Map the source operand to the destination operand index for each
214
// MachineInstr operand.
215
for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I)
216
OperandMap[Insn.Operands[i].MIOperandNo + I].Data.Operand =
217
SourceOp->getValue();
218
219
LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ==> " << i
220
<< "\n");
221
}
222
223
Expansions.push_back(PseudoExpansion(SourceInsn, Insn, OperandMap));
224
}
225
226
void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
227
// Emit file header.
228
emitSourceFileHeader("Pseudo-instruction MC lowering Source Fragment", o);
229
230
o << "bool " << Target.getName() + "AsmPrinter"
231
<< "::\n"
232
<< "emitPseudoExpansionLowering(MCStreamer &OutStreamer,\n"
233
<< " const MachineInstr *MI) {\n";
234
235
if (!Expansions.empty()) {
236
o << " switch (MI->getOpcode()) {\n"
237
<< " default: return false;\n";
238
for (auto &Expansion : Expansions) {
239
CodeGenInstruction &Source = Expansion.Source;
240
CodeGenInstruction &Dest = Expansion.Dest;
241
o << " case " << Source.Namespace << "::" << Source.TheDef->getName()
242
<< ": {\n"
243
<< " MCInst TmpInst;\n"
244
<< " MCOperand MCOp;\n"
245
<< " TmpInst.setOpcode(" << Dest.Namespace
246
<< "::" << Dest.TheDef->getName() << ");\n";
247
248
// Copy the operands from the source instruction.
249
// FIXME: Instruction operands with defaults values (predicates and cc_out
250
// in ARM, for example shouldn't need explicit values in the
251
// expansion DAG.
252
unsigned MIOpNo = 0;
253
for (const auto &DestOperand : Dest.Operands) {
254
o << " // Operand: " << DestOperand.Name << "\n";
255
for (unsigned i = 0, e = DestOperand.MINumOperands; i != e; ++i) {
256
switch (Expansion.OperandMap[MIOpNo + i].Kind) {
257
case OpData::Operand:
258
o << " lowerOperand(MI->getOperand("
259
<< Source.Operands[Expansion.OperandMap[MIOpNo].Data.Operand]
260
.MIOperandNo +
261
i
262
<< "), MCOp);\n"
263
<< " TmpInst.addOperand(MCOp);\n";
264
break;
265
case OpData::Imm:
266
o << " TmpInst.addOperand(MCOperand::createImm("
267
<< Expansion.OperandMap[MIOpNo + i].Data.Imm << "));\n";
268
break;
269
case OpData::Reg: {
270
Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg;
271
o << " TmpInst.addOperand(MCOperand::createReg(";
272
// "zero_reg" is special.
273
if (Reg->getName() == "zero_reg")
274
o << "0";
275
else
276
o << Reg->getValueAsString("Namespace") << "::" << Reg->getName();
277
o << "));\n";
278
break;
279
}
280
}
281
}
282
MIOpNo += DestOperand.MINumOperands;
283
}
284
if (Dest.Operands.isVariadic) {
285
MIOpNo = Source.Operands.size() + 1;
286
o << " // variable_ops\n";
287
o << " for (unsigned i = " << MIOpNo
288
<< ", e = MI->getNumOperands(); i != e; ++i)\n"
289
<< " if (lowerOperand(MI->getOperand(i), MCOp))\n"
290
<< " TmpInst.addOperand(MCOp);\n";
291
}
292
o << " EmitToStreamer(OutStreamer, TmpInst);\n"
293
<< " break;\n"
294
<< " }\n";
295
}
296
o << " }\n return true;";
297
} else
298
o << " return false;";
299
300
o << "\n}\n\n";
301
}
302
303
void PseudoLoweringEmitter::run(raw_ostream &o) {
304
StringRef Classes[] = {"PseudoInstExpansion", "Instruction"};
305
std::vector<Record *> Insts = Records.getAllDerivedDefinitions(Classes);
306
307
// Process the pseudo expansion definitions, validating them as we do so.
308
Records.startTimer("Process definitions");
309
for (unsigned i = 0, e = Insts.size(); i != e; ++i)
310
evaluateExpansion(Insts[i]);
311
312
// Generate expansion code to lower the pseudo to an MCInst of the real
313
// instruction.
314
Records.startTimer("Emit expansion code");
315
emitLoweringEmitter(o);
316
}
317
318
static TableGen::Emitter::OptClass<PseudoLoweringEmitter>
319
X("gen-pseudo-lowering", "Generate pseudo instruction lowering");
320
321