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/TGTimer.h" |
19 | #include "llvm/TableGen/TableGenBackend.h" |
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 | const 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 | const 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 | const CodeGenTarget Target; |
51 | |
52 | SmallVector<PseudoExpansion, 64> Expansions; |
53 | |
54 | void addOperandMapping(unsigned MIOpNo, unsigned NumOps, const Record *Rec, |
55 | const DagInit *Dag, unsigned DagIdx, |
56 | const Record *OpRec, IndexedMap<OpData> &OperandMap, |
57 | const StringMap<unsigned> &SourceOperands, |
58 | const CodeGenInstruction &SourceInsn); |
59 | void evaluateExpansion(const Record *Pseudo); |
60 | void emitLoweringEmitter(raw_ostream &o); |
61 | |
62 | public: |
63 | PseudoLoweringEmitter(const RecordKeeper &R) : Records(R), Target(R) {} |
64 | |
65 | /// run - Output the pseudo-lowerings. |
66 | void run(raw_ostream &o); |
67 | }; |
68 | } // End anonymous namespace |
69 | |
70 | void PseudoLoweringEmitter::addOperandMapping( |
71 | unsigned MIOpNo, unsigned NumOps, const Record *Rec, const DagInit *Dag, |
72 | unsigned DagIdx, const Record *OpRec, IndexedMap<OpData> &OperandMap, |
73 | const StringMap<unsigned> &SourceOperands, |
74 | const CodeGenInstruction &SourceInsn) { |
75 | const Init *DagArg = Dag->getArg(Num: DagIdx); |
76 | if (const DefInit *DI = dyn_cast<DefInit>(Val: DagArg)) { |
77 | // Physical register reference. Explicit check for the special case |
78 | // "zero_reg" definition. |
79 | if (DI->getDef()->isSubClassOf(Name: "Register" ) || |
80 | DI->getDef()->getName() == "zero_reg" ) { |
81 | auto &Entry = OperandMap[MIOpNo]; |
82 | Entry.Kind = OpData::Reg; |
83 | Entry.Data.Reg = DI->getDef(); |
84 | return; |
85 | } |
86 | |
87 | if (DI->getDef() != OpRec) |
88 | PrintFatalError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
89 | "', operand type '" + DI->getDef()->getName() + |
90 | "' does not match expansion operand type '" + |
91 | OpRec->getName() + "'" ); |
92 | |
93 | StringMap<unsigned>::const_iterator SourceOp = |
94 | SourceOperands.find(Key: Dag->getArgNameStr(Num: DagIdx)); |
95 | if (SourceOp == SourceOperands.end()) |
96 | PrintFatalError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
97 | "', output operand '" + |
98 | Dag->getArgNameStr(Num: DagIdx) + |
99 | "' has no matching source operand" ); |
100 | const auto &SrcOpnd = SourceInsn.Operands[SourceOp->getValue()]; |
101 | if (NumOps != SrcOpnd.MINumOperands) |
102 | PrintFatalError( |
103 | Rec, |
104 | Msg: "In pseudo instruction '" + Rec->getName() + "', output operand '" + |
105 | OpRec->getName() + |
106 | "' has a different number of sub operands than source operand '" + |
107 | SrcOpnd.Rec->getName() + "'" ); |
108 | |
109 | // Source operand maps to destination operand. Do it for each corresponding |
110 | // MachineInstr operand, not just the first. |
111 | for (unsigned I = 0, E = NumOps; I != E; ++I) { |
112 | auto &Entry = OperandMap[MIOpNo + I]; |
113 | Entry.Kind = OpData::Operand; |
114 | Entry.Data.Operand = SrcOpnd.MIOperandNo + I; |
115 | } |
116 | |
117 | LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ==> " << DagIdx |
118 | << "\n" ); |
119 | } else if (const auto *II = dyn_cast<IntInit>(Val: DagArg)) { |
120 | assert(NumOps == 1); |
121 | auto &Entry = OperandMap[MIOpNo]; |
122 | Entry.Kind = OpData::Imm; |
123 | Entry.Data.Imm = II->getValue(); |
124 | } else if (const auto *BI = dyn_cast<BitsInit>(Val: DagArg)) { |
125 | assert(NumOps == 1); |
126 | auto &Entry = OperandMap[MIOpNo]; |
127 | Entry.Kind = OpData::Imm; |
128 | Entry.Data.Imm = *BI->convertInitializerToInt(); |
129 | } else { |
130 | llvm_unreachable("Unhandled pseudo-expansion argument type!" ); |
131 | } |
132 | } |
133 | |
134 | void PseudoLoweringEmitter::evaluateExpansion(const Record *Rec) { |
135 | LLVM_DEBUG(dbgs() << "Pseudo definition: " << Rec->getName() << "\n" ); |
136 | |
137 | // Validate that the result pattern has the corrent number and types |
138 | // of arguments for the instruction it references. |
139 | const DagInit *Dag = Rec->getValueAsDag(FieldName: "ResultInst" ); |
140 | assert(Dag && "Missing result instruction in pseudo expansion!" ); |
141 | LLVM_DEBUG(dbgs() << " Result: " << *Dag << "\n" ); |
142 | |
143 | const DefInit *OpDef = dyn_cast<DefInit>(Val: Dag->getOperator()); |
144 | if (!OpDef) |
145 | PrintFatalError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
146 | "', result operator is not a record" ); |
147 | const Record *Operator = OpDef->getDef(); |
148 | if (!Operator->isSubClassOf(Name: "Instruction" )) |
149 | PrintFatalError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
150 | "', result operator '" + Operator->getName() + |
151 | "' is not an instruction" ); |
152 | |
153 | CodeGenInstruction Insn(Operator); |
154 | |
155 | if (Insn.isCodeGenOnly || Insn.isPseudo) |
156 | PrintFatalError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
157 | "', result operator '" + Operator->getName() + |
158 | "' cannot be a pseudo instruction" ); |
159 | |
160 | if (Insn.Operands.size() != Dag->getNumArgs()) |
161 | PrintFatalError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
162 | "', result operator '" + Operator->getName() + |
163 | "' has the wrong number of operands" ); |
164 | |
165 | // If there are more operands that weren't in the DAG, they have to |
166 | // be operands that have default values, or we have an error. Currently, |
167 | // Operands that are a subclass of OperandWithDefaultOp have default values. |
168 | |
169 | // Validate that each result pattern argument has a matching (by name) |
170 | // argument in the source instruction, in either the (outs) or (ins) list. |
171 | // Also check that the type of the arguments match. |
172 | // |
173 | // Record the mapping of the source to result arguments for use by |
174 | // the lowering emitter. |
175 | CodeGenInstruction SourceInsn(Rec); |
176 | StringMap<unsigned> SourceOperands; |
177 | for (const auto &[Idx, SrcOp] : enumerate(First&: SourceInsn.Operands)) |
178 | SourceOperands[SrcOp.Name] = Idx; |
179 | |
180 | unsigned NumMIOperands = 0; |
181 | for (const auto &Op : Insn.Operands) |
182 | NumMIOperands += Op.MINumOperands; |
183 | IndexedMap<OpData> OperandMap; |
184 | OperandMap.grow(n: NumMIOperands); |
185 | |
186 | // FIXME: This pass currently can only expand a pseudo to a single |
187 | // instruction. The pseudo expansion really should take a list of dags, not |
188 | // just a single dag, so we can do fancier things. |
189 | LLVM_DEBUG(dbgs() << " Operand mapping:\n" ); |
190 | for (const auto &[Idx, DstOp] : enumerate(First&: Insn.Operands)) { |
191 | unsigned MIOpNo = DstOp.MIOperandNo; |
192 | |
193 | if (const auto *SubDag = dyn_cast<DagInit>(Val: Dag->getArg(Num: Idx))) { |
194 | if (!DstOp.MIOperandInfo || DstOp.MIOperandInfo->getNumArgs() == 0) |
195 | PrintFatalError(Rec, Msg: "In pseudo instruction '" + Rec->getName() + |
196 | "', operand '" + DstOp.Rec->getName() + |
197 | "' does not have suboperands" ); |
198 | if (DstOp.MINumOperands != SubDag->getNumArgs()) { |
199 | PrintFatalError( |
200 | Rec, Msg: "In pseudo instruction '" + Rec->getName() + "', '" + |
201 | SubDag->getAsString() + |
202 | "' has wrong number of operands for operand type '" + |
203 | DstOp.Rec->getName() + "'" ); |
204 | } |
205 | for (unsigned I = 0, E = DstOp.MINumOperands; I != E; ++I) { |
206 | auto *OpndRec = cast<DefInit>(Val: DstOp.MIOperandInfo->getArg(Num: I))->getDef(); |
207 | addOperandMapping(MIOpNo: MIOpNo + I, NumOps: 1, Rec, Dag: SubDag, DagIdx: I, OpRec: OpndRec, OperandMap, |
208 | SourceOperands, SourceInsn); |
209 | } |
210 | } else { |
211 | addOperandMapping(MIOpNo, NumOps: DstOp.MINumOperands, Rec, Dag, DagIdx: Idx, OpRec: DstOp.Rec, |
212 | OperandMap, SourceOperands, SourceInsn); |
213 | } |
214 | } |
215 | |
216 | Expansions.emplace_back(Args&: SourceInsn, Args&: Insn, Args&: OperandMap); |
217 | } |
218 | |
219 | void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { |
220 | // Emit file header. |
221 | emitSourceFileHeader(Desc: "Pseudo-instruction MC lowering Source Fragment" , OS&: o); |
222 | |
223 | o << "bool " << Target.getName() + "AsmPrinter::\n" |
224 | << "lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst) {\n" ; |
225 | |
226 | if (!Expansions.empty()) { |
227 | o << " Inst.clear();\n" |
228 | << " switch (MI->getOpcode()) {\n" |
229 | << " default: return false;\n" ; |
230 | for (auto &Expansion : Expansions) { |
231 | CodeGenInstruction &Source = Expansion.Source; |
232 | CodeGenInstruction &Dest = Expansion.Dest; |
233 | o << " case " << Source.Namespace << "::" << Source.TheDef->getName() |
234 | << ": {\n" |
235 | << " MCOperand MCOp;\n" |
236 | << " Inst.setOpcode(" << Dest.Namespace |
237 | << "::" << Dest.TheDef->getName() << ");\n" ; |
238 | |
239 | // Copy the operands from the source instruction. |
240 | // FIXME: Instruction operands with defaults values (predicates and cc_out |
241 | // in ARM, for example shouldn't need explicit values in the |
242 | // expansion DAG. |
243 | for (const auto &DestOperand : Dest.Operands) { |
244 | o << " // Operand: " << DestOperand.Name << "\n" ; |
245 | unsigned MIOpNo = DestOperand.MIOperandNo; |
246 | for (unsigned i = 0, e = DestOperand.MINumOperands; i != e; ++i) { |
247 | switch (Expansion.OperandMap[MIOpNo + i].Kind) { |
248 | case OpData::Operand: |
249 | o << " lowerOperand(MI->getOperand(" |
250 | << Expansion.OperandMap[MIOpNo + i].Data.Operand << "), MCOp);\n" |
251 | << " Inst.addOperand(MCOp);\n" ; |
252 | break; |
253 | case OpData::Imm: |
254 | o << " Inst.addOperand(MCOperand::createImm(" |
255 | << Expansion.OperandMap[MIOpNo + i].Data.Imm << "));\n" ; |
256 | break; |
257 | case OpData::Reg: { |
258 | const Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg; |
259 | o << " Inst.addOperand(MCOperand::createReg(" ; |
260 | // "zero_reg" is special. |
261 | if (Reg->getName() == "zero_reg" ) |
262 | o << "0" ; |
263 | else |
264 | o << Reg->getValueAsString(FieldName: "Namespace" ) << "::" << Reg->getName(); |
265 | o << "));\n" ; |
266 | break; |
267 | } |
268 | } |
269 | } |
270 | } |
271 | if (Dest.Operands.isVariadic) { |
272 | unsigned LastOpNo = 0; |
273 | for (const auto &Op : Source.Operands) |
274 | LastOpNo += Op.MINumOperands; |
275 | o << " // variable_ops\n" ; |
276 | o << " for (unsigned i = " << LastOpNo |
277 | << ", e = MI->getNumOperands(); i != e; ++i)\n" |
278 | << " if (lowerOperand(MI->getOperand(i), MCOp))\n" |
279 | << " Inst.addOperand(MCOp);\n" ; |
280 | } |
281 | o << " break;\n" |
282 | << " }\n" ; |
283 | } |
284 | o << " }\n return true;" ; |
285 | } else { |
286 | o << " return false;" ; |
287 | } |
288 | |
289 | o << "\n}\n\n" ; |
290 | } |
291 | |
292 | void PseudoLoweringEmitter::run(raw_ostream &OS) { |
293 | StringRef Classes[] = {"PseudoInstExpansion" , "Instruction" }; |
294 | |
295 | // Process the pseudo expansion definitions, validating them as we do so. |
296 | TGTimer &Timer = Records.getTimer(); |
297 | Timer.startTimer(Name: "Process definitions" ); |
298 | for (const Record *Inst : Records.getAllDerivedDefinitions(ClassNames: Classes)) |
299 | evaluateExpansion(Rec: Inst); |
300 | |
301 | // Generate expansion code to lower the pseudo to an MCInst of the real |
302 | // instruction. |
303 | Timer.startTimer(Name: "Emit expansion code" ); |
304 | emitLoweringEmitter(o&: OS); |
305 | } |
306 | |
307 | static TableGen::Emitter::OptClass<PseudoLoweringEmitter> |
308 | X("gen-pseudo-lowering" , "Generate pseudo instruction lowering" ); |
309 | |