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>(Val: Dag->getArg(Num: i))) { |
79 | // Physical register reference. Explicit check for the special case |
80 | // "zero_reg" definition. |
81 | if (DI->getDef()->isSubClassOf(Name: "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, Msg: "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(Rec: DI->getDef(), |
100 | Msg: "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>(Val: Dag->getArg(Num: 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>(Val: Dag->getArg(Num: i))) { |
113 | auto *II = |
114 | cast<IntInit>(Val: BI->convertInitializerTo(Ty: IntRecTy::get(RK&: 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>(Val: Dag->getArg(Num: 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, Dag: SubDag, Insn, OperandMap, BaseIdx: 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(FieldName: "ResultInst" ); |
138 | assert(Dag && "Missing result instruction in pseudo expansion!" ); |
139 | LLVM_DEBUG(dbgs() << " Result: " << *Dag << "\n" ); |
140 | |
141 | DefInit *OpDef = dyn_cast<DefInit>(Val: Dag->getOperator()); |
142 | if (!OpDef) { |
143 | PrintError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
144 | "', result operator is not a record" ); |
145 | PrintFatalNote(RecVal: Rec->getValue(Name: "ResultInst" ), |
146 | Msg: "Result was assigned at the following location:" ); |
147 | } |
148 | Record *Operator = OpDef->getDef(); |
149 | if (!Operator->isSubClassOf(Name: "Instruction" )) { |
150 | PrintError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
151 | "', result operator '" + Operator->getName() + |
152 | "' is not an instruction" ); |
153 | PrintFatalNote(RecVal: Rec->getValue(Name: "ResultInst" ), |
154 | Msg: "Result was assigned at the following location:" ); |
155 | } |
156 | |
157 | CodeGenInstruction Insn(Operator); |
158 | |
159 | if (Insn.isCodeGenOnly || Insn.isPseudo) { |
160 | PrintError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
161 | "', result operator '" + Operator->getName() + |
162 | "' cannot be a pseudo instruction" ); |
163 | PrintFatalNote(RecVal: Rec->getValue(Name: "ResultInst" ), |
164 | Msg: "Result was assigned at the following location:" ); |
165 | } |
166 | |
167 | if (Insn.Operands.size() != Dag->getNumArgs()) { |
168 | PrintError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
169 | "', result operator '" + Operator->getName() + |
170 | "' has the wrong number of operands" ); |
171 | PrintFatalNote(RecVal: Rec->getValue(Name: "ResultInst" ), |
172 | Msg: "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(n: NumMIOperands); |
180 | |
181 | addDagOperandMapping(Rec, Dag, Insn, OperandMap, BaseIdx: 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(Key: Dag->getArgNameStr(Num: i)); |
206 | if (SourceOp == SourceOperands.end()) { |
207 | PrintError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
208 | "', output operand '" + Dag->getArgNameStr(Num: i) + |
209 | "' has no matching source operand" ); |
210 | PrintFatalNote(RecVal: Rec->getValue(Name: "ResultInst" ), |
211 | Msg: "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(Elt: PseudoExpansion(SourceInsn, Insn, OperandMap)); |
224 | } |
225 | |
226 | void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { |
227 | // Emit file header. |
228 | emitSourceFileHeader(Desc: "Pseudo-instruction MC lowering Source Fragment" , OS&: 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(FieldName: "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(ClassNames: Classes); |
306 | |
307 | // Process the pseudo expansion definitions, validating them as we do so. |
308 | Records.startTimer(Name: "Process definitions" ); |
309 | for (unsigned i = 0, e = Insts.size(); i != e; ++i) |
310 | evaluateExpansion(Rec: Insts[i]); |
311 | |
312 | // Generate expansion code to lower the pseudo to an MCInst of the real |
313 | // instruction. |
314 | Records.startTimer(Name: "Emit expansion code" ); |
315 | emitLoweringEmitter(o); |
316 | } |
317 | |
318 | static TableGen::Emitter::OptClass<PseudoLoweringEmitter> |
319 | X("gen-pseudo-lowering" , "Generate pseudo instruction lowering" ); |
320 | |