]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This tablegen backend is emits an assembly printer for the current target. | |
11 | // Note that this is currently fairly skeletal, but will grow over time. | |
12 | // | |
13 | //===----------------------------------------------------------------------===// | |
14 | ||
15 | #include "AsmWriterInst.h" | |
16 | #include "CodeGenTarget.h" | |
17 | #include "SequenceToOffsetTable.h" | |
1a4d82fc | 18 | #include "llvm/ADT/SmallString.h" |
223e47cc LB |
19 | #include "llvm/ADT/StringExtras.h" |
20 | #include "llvm/ADT/Twine.h" | |
21 | #include "llvm/Support/Debug.h" | |
1a4d82fc | 22 | #include "llvm/Support/Format.h" |
223e47cc LB |
23 | #include "llvm/Support/MathExtras.h" |
24 | #include "llvm/TableGen/Error.h" | |
25 | #include "llvm/TableGen/Record.h" | |
26 | #include "llvm/TableGen/TableGenBackend.h" | |
27 | #include <algorithm> | |
28 | #include <cassert> | |
29 | #include <map> | |
30 | #include <vector> | |
31 | using namespace llvm; | |
32 | ||
1a4d82fc JJ |
33 | #define DEBUG_TYPE "asm-writer-emitter" |
34 | ||
223e47cc LB |
35 | namespace { |
36 | class AsmWriterEmitter { | |
37 | RecordKeeper &Records; | |
1a4d82fc | 38 | CodeGenTarget Target; |
223e47cc | 39 | std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap; |
1a4d82fc JJ |
40 | const std::vector<const CodeGenInstruction*> *NumberedInstructions; |
41 | std::vector<AsmWriterInst> Instructions; | |
42 | std::vector<std::string> PrintMethods; | |
223e47cc | 43 | public: |
1a4d82fc | 44 | AsmWriterEmitter(RecordKeeper &R); |
223e47cc LB |
45 | |
46 | void run(raw_ostream &o); | |
47 | ||
48 | private: | |
49 | void EmitPrintInstruction(raw_ostream &o); | |
50 | void EmitGetRegisterName(raw_ostream &o); | |
51 | void EmitPrintAliasInstruction(raw_ostream &O); | |
52 | ||
53 | AsmWriterInst *getAsmWriterInstByID(unsigned ID) const { | |
1a4d82fc | 54 | assert(ID < NumberedInstructions->size()); |
223e47cc | 55 | std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I = |
1a4d82fc | 56 | CGIAWIMap.find(NumberedInstructions->at(ID)); |
223e47cc LB |
57 | assert(I != CGIAWIMap.end() && "Didn't find inst!"); |
58 | return I->second; | |
59 | } | |
60 | void FindUniqueOperandCommands(std::vector<std::string> &UOC, | |
61 | std::vector<unsigned> &InstIdxs, | |
62 | std::vector<unsigned> &InstOpsUsed) const; | |
63 | }; | |
64 | } // end anonymous namespace | |
65 | ||
66 | static void PrintCases(std::vector<std::pair<std::string, | |
67 | AsmWriterOperand> > &OpsToPrint, raw_ostream &O) { | |
68 | O << " case " << OpsToPrint.back().first << ": "; | |
69 | AsmWriterOperand TheOp = OpsToPrint.back().second; | |
70 | OpsToPrint.pop_back(); | |
71 | ||
72 | // Check to see if any other operands are identical in this list, and if so, | |
73 | // emit a case label for them. | |
74 | for (unsigned i = OpsToPrint.size(); i != 0; --i) | |
75 | if (OpsToPrint[i-1].second == TheOp) { | |
76 | O << "\n case " << OpsToPrint[i-1].first << ": "; | |
77 | OpsToPrint.erase(OpsToPrint.begin()+i-1); | |
78 | } | |
79 | ||
80 | // Finally, emit the code. | |
81 | O << TheOp.getCode(); | |
82 | O << "break;\n"; | |
83 | } | |
84 | ||
85 | ||
86 | /// EmitInstructions - Emit the last instruction in the vector and any other | |
87 | /// instructions that are suitably similar to it. | |
88 | static void EmitInstructions(std::vector<AsmWriterInst> &Insts, | |
89 | raw_ostream &O) { | |
90 | AsmWriterInst FirstInst = Insts.back(); | |
91 | Insts.pop_back(); | |
92 | ||
93 | std::vector<AsmWriterInst> SimilarInsts; | |
94 | unsigned DifferingOperand = ~0; | |
95 | for (unsigned i = Insts.size(); i != 0; --i) { | |
96 | unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst); | |
97 | if (DiffOp != ~1U) { | |
98 | if (DifferingOperand == ~0U) // First match! | |
99 | DifferingOperand = DiffOp; | |
100 | ||
101 | // If this differs in the same operand as the rest of the instructions in | |
102 | // this class, move it to the SimilarInsts list. | |
103 | if (DifferingOperand == DiffOp || DiffOp == ~0U) { | |
104 | SimilarInsts.push_back(Insts[i-1]); | |
105 | Insts.erase(Insts.begin()+i-1); | |
106 | } | |
107 | } | |
108 | } | |
109 | ||
110 | O << " case " << FirstInst.CGI->Namespace << "::" | |
111 | << FirstInst.CGI->TheDef->getName() << ":\n"; | |
112 | for (unsigned i = 0, e = SimilarInsts.size(); i != e; ++i) | |
113 | O << " case " << SimilarInsts[i].CGI->Namespace << "::" | |
114 | << SimilarInsts[i].CGI->TheDef->getName() << ":\n"; | |
115 | for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) { | |
116 | if (i != DifferingOperand) { | |
117 | // If the operand is the same for all instructions, just print it. | |
118 | O << " " << FirstInst.Operands[i].getCode(); | |
119 | } else { | |
120 | // If this is the operand that varies between all of the instructions, | |
121 | // emit a switch for just this operand now. | |
122 | O << " switch (MI->getOpcode()) {\n"; | |
123 | std::vector<std::pair<std::string, AsmWriterOperand> > OpsToPrint; | |
124 | OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace + "::" + | |
125 | FirstInst.CGI->TheDef->getName(), | |
126 | FirstInst.Operands[i])); | |
127 | ||
128 | for (unsigned si = 0, e = SimilarInsts.size(); si != e; ++si) { | |
129 | AsmWriterInst &AWI = SimilarInsts[si]; | |
130 | OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace+"::"+ | |
131 | AWI.CGI->TheDef->getName(), | |
132 | AWI.Operands[i])); | |
133 | } | |
134 | std::reverse(OpsToPrint.begin(), OpsToPrint.end()); | |
135 | while (!OpsToPrint.empty()) | |
136 | PrintCases(OpsToPrint, O); | |
137 | O << " }"; | |
138 | } | |
139 | O << "\n"; | |
140 | } | |
141 | O << " break;\n"; | |
142 | } | |
143 | ||
144 | void AsmWriterEmitter:: | |
145 | FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, | |
146 | std::vector<unsigned> &InstIdxs, | |
147 | std::vector<unsigned> &InstOpsUsed) const { | |
1a4d82fc | 148 | InstIdxs.assign(NumberedInstructions->size(), ~0U); |
223e47cc LB |
149 | |
150 | // This vector parallels UniqueOperandCommands, keeping track of which | |
151 | // instructions each case are used for. It is a comma separated string of | |
152 | // enums. | |
153 | std::vector<std::string> InstrsForCase; | |
154 | InstrsForCase.resize(UniqueOperandCommands.size()); | |
155 | InstOpsUsed.assign(UniqueOperandCommands.size(), 0); | |
156 | ||
1a4d82fc | 157 | for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { |
223e47cc | 158 | const AsmWriterInst *Inst = getAsmWriterInstByID(i); |
1a4d82fc JJ |
159 | if (!Inst) |
160 | continue; // PHI, INLINEASM, CFI_INSTRUCTION, etc. | |
223e47cc LB |
161 | |
162 | std::string Command; | |
163 | if (Inst->Operands.empty()) | |
164 | continue; // Instruction already done. | |
165 | ||
166 | Command = " " + Inst->Operands[0].getCode() + "\n"; | |
167 | ||
168 | // Check to see if we already have 'Command' in UniqueOperandCommands. | |
169 | // If not, add it. | |
170 | bool FoundIt = false; | |
171 | for (unsigned idx = 0, e = UniqueOperandCommands.size(); idx != e; ++idx) | |
172 | if (UniqueOperandCommands[idx] == Command) { | |
173 | InstIdxs[i] = idx; | |
174 | InstrsForCase[idx] += ", "; | |
175 | InstrsForCase[idx] += Inst->CGI->TheDef->getName(); | |
176 | FoundIt = true; | |
177 | break; | |
178 | } | |
179 | if (!FoundIt) { | |
180 | InstIdxs[i] = UniqueOperandCommands.size(); | |
181 | UniqueOperandCommands.push_back(Command); | |
182 | InstrsForCase.push_back(Inst->CGI->TheDef->getName()); | |
183 | ||
184 | // This command matches one operand so far. | |
185 | InstOpsUsed.push_back(1); | |
186 | } | |
187 | } | |
188 | ||
189 | // For each entry of UniqueOperandCommands, there is a set of instructions | |
190 | // that uses it. If the next command of all instructions in the set are | |
191 | // identical, fold it into the command. | |
192 | for (unsigned CommandIdx = 0, e = UniqueOperandCommands.size(); | |
193 | CommandIdx != e; ++CommandIdx) { | |
194 | ||
195 | for (unsigned Op = 1; ; ++Op) { | |
196 | // Scan for the first instruction in the set. | |
197 | std::vector<unsigned>::iterator NIT = | |
198 | std::find(InstIdxs.begin(), InstIdxs.end(), CommandIdx); | |
199 | if (NIT == InstIdxs.end()) break; // No commonality. | |
200 | ||
201 | // If this instruction has no more operands, we isn't anything to merge | |
202 | // into this command. | |
203 | const AsmWriterInst *FirstInst = | |
204 | getAsmWriterInstByID(NIT-InstIdxs.begin()); | |
205 | if (!FirstInst || FirstInst->Operands.size() == Op) | |
206 | break; | |
207 | ||
208 | // Otherwise, scan to see if all of the other instructions in this command | |
209 | // set share the operand. | |
210 | bool AllSame = true; | |
223e47cc LB |
211 | |
212 | for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx); | |
213 | NIT != InstIdxs.end(); | |
214 | NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) { | |
215 | // Okay, found another instruction in this command set. If the operand | |
216 | // matches, we're ok, otherwise bail out. | |
217 | const AsmWriterInst *OtherInst = | |
218 | getAsmWriterInstByID(NIT-InstIdxs.begin()); | |
219 | ||
223e47cc LB |
220 | if (!OtherInst || OtherInst->Operands.size() == Op || |
221 | OtherInst->Operands[Op] != FirstInst->Operands[Op]) { | |
222 | AllSame = false; | |
223 | break; | |
224 | } | |
225 | } | |
226 | if (!AllSame) break; | |
227 | ||
228 | // Okay, everything in this command set has the same next operand. Add it | |
229 | // to UniqueOperandCommands and remember that it was consumed. | |
230 | std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n"; | |
231 | ||
232 | UniqueOperandCommands[CommandIdx] += Command; | |
233 | InstOpsUsed[CommandIdx]++; | |
234 | } | |
235 | } | |
236 | ||
237 | // Prepend some of the instructions each case is used for onto the case val. | |
238 | for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) { | |
239 | std::string Instrs = InstrsForCase[i]; | |
240 | if (Instrs.size() > 70) { | |
241 | Instrs.erase(Instrs.begin()+70, Instrs.end()); | |
242 | Instrs += "..."; | |
243 | } | |
244 | ||
245 | if (!Instrs.empty()) | |
246 | UniqueOperandCommands[i] = " // " + Instrs + "\n" + | |
247 | UniqueOperandCommands[i]; | |
248 | } | |
249 | } | |
250 | ||
251 | ||
252 | static void UnescapeString(std::string &Str) { | |
253 | for (unsigned i = 0; i != Str.size(); ++i) { | |
254 | if (Str[i] == '\\' && i != Str.size()-1) { | |
255 | switch (Str[i+1]) { | |
256 | default: continue; // Don't execute the code after the switch. | |
257 | case 'a': Str[i] = '\a'; break; | |
258 | case 'b': Str[i] = '\b'; break; | |
259 | case 'e': Str[i] = 27; break; | |
260 | case 'f': Str[i] = '\f'; break; | |
261 | case 'n': Str[i] = '\n'; break; | |
262 | case 'r': Str[i] = '\r'; break; | |
263 | case 't': Str[i] = '\t'; break; | |
264 | case 'v': Str[i] = '\v'; break; | |
265 | case '"': Str[i] = '\"'; break; | |
266 | case '\'': Str[i] = '\''; break; | |
267 | case '\\': Str[i] = '\\'; break; | |
268 | } | |
269 | // Nuke the second character. | |
270 | Str.erase(Str.begin()+i+1); | |
271 | } | |
272 | } | |
273 | } | |
274 | ||
275 | /// EmitPrintInstruction - Generate the code for the "printInstruction" method | |
1a4d82fc JJ |
276 | /// implementation. Destroys all instances of AsmWriterInst information, by |
277 | /// clearing the Instructions vector. | |
223e47cc | 278 | void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { |
223e47cc LB |
279 | Record *AsmWriter = Target.getAsmWriter(); |
280 | std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); | |
223e47cc LB |
281 | |
282 | O << | |
283 | "/// printInstruction - This method is automatically generated by tablegen\n" | |
284 | "/// from the instruction set description.\n" | |
285 | "void " << Target.getName() << ClassName | |
1a4d82fc | 286 | << "::printInstruction(const MCInst *MI, raw_ostream &O) {\n"; |
223e47cc LB |
287 | |
288 | // Build an aggregate string, and build a table of offsets into it. | |
289 | SequenceToOffsetTable<std::string> StringTable; | |
290 | ||
291 | /// OpcodeInfo - This encodes the index of the string to use for the first | |
292 | /// chunk of the output as well as indices used for operand printing. | |
293 | /// To reduce the number of unhandled cases, we expand the size from 32-bit | |
294 | /// to 32+16 = 48-bit. | |
295 | std::vector<uint64_t> OpcodeInfo; | |
296 | ||
297 | // Add all strings to the string table upfront so it can generate an optimized | |
298 | // representation. | |
1a4d82fc JJ |
299 | for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { |
300 | AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions->at(i)]; | |
301 | if (AWI && | |
223e47cc LB |
302 | AWI->Operands[0].OperandType == |
303 | AsmWriterOperand::isLiteralTextOperand && | |
304 | !AWI->Operands[0].Str.empty()) { | |
305 | std::string Str = AWI->Operands[0].Str; | |
306 | UnescapeString(Str); | |
307 | StringTable.add(Str); | |
308 | } | |
309 | } | |
310 | ||
311 | StringTable.layout(); | |
312 | ||
313 | unsigned MaxStringIdx = 0; | |
1a4d82fc JJ |
314 | for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { |
315 | AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions->at(i)]; | |
223e47cc | 316 | unsigned Idx; |
1a4d82fc | 317 | if (!AWI) { |
223e47cc LB |
318 | // Something not handled by the asmwriter printer. |
319 | Idx = ~0U; | |
320 | } else if (AWI->Operands[0].OperandType != | |
321 | AsmWriterOperand::isLiteralTextOperand || | |
322 | AWI->Operands[0].Str.empty()) { | |
323 | // Something handled by the asmwriter printer, but with no leading string. | |
324 | Idx = StringTable.get(""); | |
325 | } else { | |
326 | std::string Str = AWI->Operands[0].Str; | |
327 | UnescapeString(Str); | |
328 | Idx = StringTable.get(Str); | |
329 | MaxStringIdx = std::max(MaxStringIdx, Idx); | |
330 | ||
331 | // Nuke the string from the operand list. It is now handled! | |
332 | AWI->Operands.erase(AWI->Operands.begin()); | |
333 | } | |
334 | ||
335 | // Bias offset by one since we want 0 as a sentinel. | |
336 | OpcodeInfo.push_back(Idx+1); | |
337 | } | |
338 | ||
339 | // Figure out how many bits we used for the string index. | |
340 | unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2); | |
341 | ||
342 | // To reduce code size, we compactify common instructions into a few bits | |
343 | // in the opcode-indexed table. | |
344 | unsigned BitsLeft = 64-AsmStrBits; | |
345 | ||
85aaf69f | 346 | std::vector<std::vector<std::string>> TableDrivenOperandPrinters; |
223e47cc LB |
347 | |
348 | while (1) { | |
349 | std::vector<std::string> UniqueOperandCommands; | |
350 | std::vector<unsigned> InstIdxs; | |
351 | std::vector<unsigned> NumInstOpsHandled; | |
352 | FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs, | |
353 | NumInstOpsHandled); | |
354 | ||
355 | // If we ran out of operands to print, we're done. | |
356 | if (UniqueOperandCommands.empty()) break; | |
357 | ||
358 | // Compute the number of bits we need to represent these cases, this is | |
359 | // ceil(log2(numentries)). | |
360 | unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size()); | |
361 | ||
362 | // If we don't have enough bits for this operand, don't include it. | |
363 | if (NumBits > BitsLeft) { | |
364 | DEBUG(errs() << "Not enough bits to densely encode " << NumBits | |
365 | << " more bits\n"); | |
366 | break; | |
367 | } | |
368 | ||
369 | // Otherwise, we can include this in the initial lookup table. Add it in. | |
370 | for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i) | |
371 | if (InstIdxs[i] != ~0U) { | |
372 | OpcodeInfo[i] |= (uint64_t)InstIdxs[i] << (64-BitsLeft); | |
373 | } | |
374 | BitsLeft -= NumBits; | |
375 | ||
376 | // Remove the info about this operand. | |
1a4d82fc | 377 | for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { |
223e47cc LB |
378 | if (AsmWriterInst *Inst = getAsmWriterInstByID(i)) |
379 | if (!Inst->Operands.empty()) { | |
380 | unsigned NumOps = NumInstOpsHandled[InstIdxs[i]]; | |
381 | assert(NumOps <= Inst->Operands.size() && | |
382 | "Can't remove this many ops!"); | |
383 | Inst->Operands.erase(Inst->Operands.begin(), | |
384 | Inst->Operands.begin()+NumOps); | |
385 | } | |
386 | } | |
387 | ||
388 | // Remember the handlers for this set of operands. | |
85aaf69f | 389 | TableDrivenOperandPrinters.push_back(std::move(UniqueOperandCommands)); |
223e47cc LB |
390 | } |
391 | ||
392 | ||
393 | // We always emit at least one 32-bit table. A second table is emitted if | |
394 | // more bits are needed. | |
395 | O<<" static const uint32_t OpInfo[] = {\n"; | |
1a4d82fc | 396 | for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { |
223e47cc | 397 | O << " " << (OpcodeInfo[i] & 0xffffffff) << "U,\t// " |
1a4d82fc | 398 | << NumberedInstructions->at(i)->TheDef->getName() << "\n"; |
223e47cc LB |
399 | } |
400 | // Add a dummy entry so the array init doesn't end with a comma. | |
401 | O << " 0U\n"; | |
402 | O << " };\n\n"; | |
403 | ||
404 | if (BitsLeft < 32) { | |
405 | // Add a second OpInfo table only when it is necessary. | |
406 | // Adjust the type of the second table based on the number of bits needed. | |
407 | O << " static const uint" | |
408 | << ((BitsLeft < 16) ? "32" : (BitsLeft < 24) ? "16" : "8") | |
409 | << "_t OpInfo2[] = {\n"; | |
1a4d82fc | 410 | for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { |
223e47cc | 411 | O << " " << (OpcodeInfo[i] >> 32) << "U,\t// " |
1a4d82fc | 412 | << NumberedInstructions->at(i)->TheDef->getName() << "\n"; |
223e47cc LB |
413 | } |
414 | // Add a dummy entry so the array init doesn't end with a comma. | |
415 | O << " 0U\n"; | |
416 | O << " };\n\n"; | |
417 | } | |
418 | ||
419 | // Emit the string itself. | |
1a4d82fc | 420 | O << " static const char AsmStrs[] = {\n"; |
223e47cc LB |
421 | StringTable.emit(O, printChar); |
422 | O << " };\n\n"; | |
423 | ||
424 | O << " O << \"\\t\";\n\n"; | |
425 | ||
426 | O << " // Emit the opcode for the instruction.\n"; | |
427 | if (BitsLeft < 32) { | |
428 | // If we have two tables then we need to perform two lookups and combine | |
429 | // the results into a single 64-bit value. | |
430 | O << " uint64_t Bits1 = OpInfo[MI->getOpcode()];\n" | |
431 | << " uint64_t Bits2 = OpInfo2[MI->getOpcode()];\n" | |
432 | << " uint64_t Bits = (Bits2 << 32) | Bits1;\n"; | |
433 | } else { | |
434 | // If only one table is used we just need to perform a single lookup. | |
435 | O << " uint32_t Bits = OpInfo[MI->getOpcode()];\n"; | |
436 | } | |
437 | O << " assert(Bits != 0 && \"Cannot print this instruction.\");\n" | |
438 | << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ")-1;\n\n"; | |
439 | ||
440 | // Output the table driven operand information. | |
441 | BitsLeft = 64-AsmStrBits; | |
442 | for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) { | |
443 | std::vector<std::string> &Commands = TableDrivenOperandPrinters[i]; | |
444 | ||
445 | // Compute the number of bits we need to represent these cases, this is | |
446 | // ceil(log2(numentries)). | |
447 | unsigned NumBits = Log2_32_Ceil(Commands.size()); | |
448 | assert(NumBits <= BitsLeft && "consistency error"); | |
449 | ||
450 | // Emit code to extract this field from Bits. | |
451 | O << "\n // Fragment " << i << " encoded into " << NumBits | |
452 | << " bits for " << Commands.size() << " unique commands.\n"; | |
453 | ||
454 | if (Commands.size() == 2) { | |
455 | // Emit two possibilitys with if/else. | |
456 | O << " if ((Bits >> " | |
457 | << (64-BitsLeft) << ") & " | |
458 | << ((1 << NumBits)-1) << ") {\n" | |
459 | << Commands[1] | |
460 | << " } else {\n" | |
461 | << Commands[0] | |
462 | << " }\n\n"; | |
463 | } else if (Commands.size() == 1) { | |
464 | // Emit a single possibility. | |
465 | O << Commands[0] << "\n\n"; | |
466 | } else { | |
467 | O << " switch ((Bits >> " | |
468 | << (64-BitsLeft) << ") & " | |
469 | << ((1 << NumBits)-1) << ") {\n" | |
85aaf69f | 470 | << " default: llvm_unreachable(\"Invalid command number.\");\n"; |
223e47cc LB |
471 | |
472 | // Print out all the cases. | |
473 | for (unsigned i = 0, e = Commands.size(); i != e; ++i) { | |
474 | O << " case " << i << ":\n"; | |
475 | O << Commands[i]; | |
476 | O << " break;\n"; | |
477 | } | |
478 | O << " }\n\n"; | |
479 | } | |
480 | BitsLeft -= NumBits; | |
481 | } | |
482 | ||
483 | // Okay, delete instructions with no operand info left. | |
484 | for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { | |
485 | // Entire instruction has been emitted? | |
486 | AsmWriterInst &Inst = Instructions[i]; | |
487 | if (Inst.Operands.empty()) { | |
488 | Instructions.erase(Instructions.begin()+i); | |
489 | --i; --e; | |
490 | } | |
491 | } | |
492 | ||
493 | ||
494 | // Because this is a vector, we want to emit from the end. Reverse all of the | |
495 | // elements in the vector. | |
496 | std::reverse(Instructions.begin(), Instructions.end()); | |
497 | ||
498 | ||
499 | // Now that we've emitted all of the operand info that fit into 32 bits, emit | |
500 | // information for those instructions that are left. This is a less dense | |
501 | // encoding, but we expect the main 32-bit table to handle the majority of | |
502 | // instructions. | |
503 | if (!Instructions.empty()) { | |
504 | // Find the opcode # of inline asm. | |
505 | O << " switch (MI->getOpcode()) {\n"; | |
506 | while (!Instructions.empty()) | |
507 | EmitInstructions(Instructions, O); | |
508 | ||
509 | O << " }\n"; | |
510 | O << " return;\n"; | |
511 | } | |
512 | ||
513 | O << "}\n"; | |
514 | } | |
515 | ||
85aaf69f SL |
516 | static const char *getMinimalTypeForRange(uint64_t Range) { |
517 | assert(Range < 0xFFFFFFFFULL && "Enum too large"); | |
518 | if (Range > 0xFFFF) | |
519 | return "uint32_t"; | |
520 | if (Range > 0xFF) | |
521 | return "uint16_t"; | |
522 | return "uint8_t"; | |
523 | } | |
524 | ||
223e47cc LB |
525 | static void |
526 | emitRegisterNameString(raw_ostream &O, StringRef AltName, | |
85aaf69f | 527 | const std::deque<CodeGenRegister> &Registers) { |
223e47cc LB |
528 | SequenceToOffsetTable<std::string> StringTable; |
529 | SmallVector<std::string, 4> AsmNames(Registers.size()); | |
85aaf69f SL |
530 | unsigned i = 0; |
531 | for (const auto &Reg : Registers) { | |
532 | std::string &AsmName = AsmNames[i++]; | |
223e47cc LB |
533 | |
534 | // "NoRegAltName" is special. We don't need to do a lookup for that, | |
535 | // as it's just a reference to the default register name. | |
536 | if (AltName == "" || AltName == "NoRegAltName") { | |
537 | AsmName = Reg.TheDef->getValueAsString("AsmName"); | |
538 | if (AsmName.empty()) | |
539 | AsmName = Reg.getName(); | |
540 | } else { | |
541 | // Make sure the register has an alternate name for this index. | |
542 | std::vector<Record*> AltNameList = | |
543 | Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices"); | |
544 | unsigned Idx = 0, e; | |
545 | for (e = AltNameList.size(); | |
546 | Idx < e && (AltNameList[Idx]->getName() != AltName); | |
547 | ++Idx) | |
548 | ; | |
549 | // If the register has an alternate name for this index, use it. | |
550 | // Otherwise, leave it empty as an error flag. | |
551 | if (Idx < e) { | |
552 | std::vector<std::string> AltNames = | |
553 | Reg.TheDef->getValueAsListOfStrings("AltNames"); | |
554 | if (AltNames.size() <= Idx) | |
970d7e83 | 555 | PrintFatalError(Reg.TheDef->getLoc(), |
1a4d82fc JJ |
556 | "Register definition missing alt name for '" + |
557 | AltName + "'."); | |
223e47cc LB |
558 | AsmName = AltNames[Idx]; |
559 | } | |
560 | } | |
561 | StringTable.add(AsmName); | |
562 | } | |
563 | ||
564 | StringTable.layout(); | |
565 | O << " static const char AsmStrs" << AltName << "[] = {\n"; | |
566 | StringTable.emit(O, printChar); | |
567 | O << " };\n\n"; | |
568 | ||
85aaf69f SL |
569 | O << " static const " << getMinimalTypeForRange(StringTable.size()-1) |
570 | << " RegAsmOffset" << AltName << "[] = {"; | |
223e47cc LB |
571 | for (unsigned i = 0, e = Registers.size(); i != e; ++i) { |
572 | if ((i % 14) == 0) | |
573 | O << "\n "; | |
574 | O << StringTable.get(AsmNames[i]) << ", "; | |
575 | } | |
576 | O << "\n };\n" | |
577 | << "\n"; | |
578 | } | |
579 | ||
580 | void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { | |
223e47cc LB |
581 | Record *AsmWriter = Target.getAsmWriter(); |
582 | std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); | |
85aaf69f | 583 | const auto &Registers = Target.getRegBank().getRegisters(); |
223e47cc LB |
584 | std::vector<Record*> AltNameIndices = Target.getRegAltNameIndices(); |
585 | bool hasAltNames = AltNameIndices.size() > 1; | |
586 | ||
587 | O << | |
588 | "\n\n/// getRegisterName - This method is automatically generated by tblgen\n" | |
589 | "/// from the register set description. This returns the assembler name\n" | |
590 | "/// for the specified register.\n" | |
591 | "const char *" << Target.getName() << ClassName << "::"; | |
592 | if (hasAltNames) | |
593 | O << "\ngetRegisterName(unsigned RegNo, unsigned AltIdx) {\n"; | |
594 | else | |
595 | O << "getRegisterName(unsigned RegNo) {\n"; | |
596 | O << " assert(RegNo && RegNo < " << (Registers.size()+1) | |
597 | << " && \"Invalid register number!\");\n" | |
598 | << "\n"; | |
599 | ||
600 | if (hasAltNames) { | |
601 | for (unsigned i = 0, e = AltNameIndices.size(); i < e; ++i) | |
602 | emitRegisterNameString(O, AltNameIndices[i]->getName(), Registers); | |
603 | } else | |
604 | emitRegisterNameString(O, "", Registers); | |
605 | ||
606 | if (hasAltNames) { | |
85aaf69f | 607 | O << " switch(AltIdx) {\n" |
223e47cc LB |
608 | << " default: llvm_unreachable(\"Invalid register alt name index!\");\n"; |
609 | for (unsigned i = 0, e = AltNameIndices.size(); i < e; ++i) { | |
1a4d82fc JJ |
610 | std::string Namespace = AltNameIndices[1]->getValueAsString("Namespace"); |
611 | std::string AltName(AltNameIndices[i]->getName()); | |
85aaf69f SL |
612 | O << " case " << Namespace << "::" << AltName << ":\n" |
613 | << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" | |
614 | << AltName << "[RegNo-1]) &&\n" | |
615 | << " \"Invalid alt name index for register!\");\n" | |
616 | << " return AsmStrs" << AltName << "+RegAsmOffset" | |
617 | << AltName << "[RegNo-1];\n"; | |
223e47cc | 618 | } |
85aaf69f SL |
619 | O << " }\n"; |
620 | } else { | |
621 | O << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n" | |
622 | << " \"Invalid alt name index for register!\");\n" | |
623 | << " return AsmStrs+RegAsmOffset[RegNo-1];\n"; | |
223e47cc | 624 | } |
85aaf69f | 625 | O << "}\n"; |
223e47cc LB |
626 | } |
627 | ||
628 | namespace { | |
629 | // IAPrinter - Holds information about an InstAlias. Two InstAliases match if | |
630 | // they both have the same conditionals. In which case, we cannot print out the | |
631 | // alias for that pattern. | |
632 | class IAPrinter { | |
633 | std::vector<std::string> Conds; | |
1a4d82fc JJ |
634 | std::map<StringRef, std::pair<int, int>> OpMap; |
635 | SmallVector<Record*, 4> ReqFeatures; | |
636 | ||
223e47cc LB |
637 | std::string Result; |
638 | std::string AsmString; | |
223e47cc | 639 | public: |
1a4d82fc | 640 | IAPrinter(std::string R, std::string AS) : Result(R), AsmString(AS) {} |
223e47cc LB |
641 | |
642 | void addCond(const std::string &C) { Conds.push_back(C); } | |
643 | ||
1a4d82fc JJ |
644 | void addOperand(StringRef Op, int OpIdx, int PrintMethodIdx = -1) { |
645 | assert(OpIdx >= 0 && OpIdx < 0xFE && "Idx out of range"); | |
646 | assert(PrintMethodIdx >= -1 && PrintMethodIdx < 0xFF && | |
647 | "Idx out of range"); | |
648 | OpMap[Op] = std::make_pair(OpIdx, PrintMethodIdx); | |
649 | } | |
650 | ||
223e47cc | 651 | bool isOpMapped(StringRef Op) { return OpMap.find(Op) != OpMap.end(); } |
1a4d82fc JJ |
652 | int getOpIndex(StringRef Op) { return OpMap[Op].first; } |
653 | std::pair<int, int> &getOpData(StringRef Op) { return OpMap[Op]; } | |
654 | ||
655 | std::pair<StringRef, StringRef::iterator> parseName(StringRef::iterator Start, | |
656 | StringRef::iterator End) { | |
657 | StringRef::iterator I = Start; | |
85aaf69f | 658 | StringRef::iterator Next; |
1a4d82fc JJ |
659 | if (*I == '{') { |
660 | // ${some_name} | |
661 | Start = ++I; | |
662 | while (I != End && *I != '}') | |
663 | ++I; | |
85aaf69f SL |
664 | Next = I; |
665 | // eat the final '}' | |
666 | if (Next != End) | |
667 | ++Next; | |
1a4d82fc JJ |
668 | } else { |
669 | // $name, just eat the usual suspects. | |
670 | while (I != End && | |
671 | ((*I >= 'a' && *I <= 'z') || (*I >= 'A' && *I <= 'Z') || | |
672 | (*I >= '0' && *I <= '9') || *I == '_')) | |
673 | ++I; | |
85aaf69f | 674 | Next = I; |
1a4d82fc JJ |
675 | } |
676 | ||
85aaf69f | 677 | return std::make_pair(StringRef(Start, I - Start), Next); |
1a4d82fc | 678 | } |
223e47cc LB |
679 | |
680 | void print(raw_ostream &O) { | |
681 | if (Conds.empty() && ReqFeatures.empty()) { | |
682 | O.indent(6) << "return true;\n"; | |
683 | return; | |
684 | } | |
685 | ||
686 | O << "if ("; | |
687 | ||
688 | for (std::vector<std::string>::iterator | |
689 | I = Conds.begin(), E = Conds.end(); I != E; ++I) { | |
690 | if (I != Conds.begin()) { | |
691 | O << " &&\n"; | |
692 | O.indent(8); | |
693 | } | |
694 | ||
695 | O << *I; | |
696 | } | |
697 | ||
698 | O << ") {\n"; | |
699 | O.indent(6) << "// " << Result << "\n"; | |
223e47cc | 700 | |
1a4d82fc JJ |
701 | // Directly mangle mapped operands into the string. Each operand is |
702 | // identified by a '$' sign followed by a byte identifying the number of the | |
703 | // operand. We add one to the index to avoid zero bytes. | |
704 | StringRef ASM(AsmString); | |
705 | SmallString<128> OutString; | |
706 | raw_svector_ostream OS(OutString); | |
707 | for (StringRef::iterator I = ASM.begin(), E = ASM.end(); I != E;) { | |
708 | OS << *I; | |
709 | if (*I == '$') { | |
710 | StringRef Name; | |
711 | std::tie(Name, I) = parseName(++I, E); | |
712 | assert(isOpMapped(Name) && "Unmapped operand!"); | |
713 | ||
714 | int OpIndex, PrintIndex; | |
715 | std::tie(OpIndex, PrintIndex) = getOpData(Name); | |
716 | if (PrintIndex == -1) { | |
717 | // Can use the default printOperand route. | |
718 | OS << format("\\x%02X", (unsigned char)OpIndex + 1); | |
719 | } else | |
720 | // 3 bytes if a PrintMethod is needed: 0xFF, the MCInst operand | |
721 | // number, and which of our pre-detected Methods to call. | |
722 | OS << format("\\xFF\\x%02X\\x%02X", OpIndex + 1, PrintIndex + 1); | |
723 | } else { | |
724 | ++I; | |
725 | } | |
726 | } | |
727 | OS.flush(); | |
728 | ||
729 | // Emit the string. | |
730 | O.indent(6) << "AsmString = \"" << OutString.str() << "\";\n"; | |
223e47cc LB |
731 | |
732 | O.indent(6) << "break;\n"; | |
733 | O.indent(4) << '}'; | |
734 | } | |
735 | ||
736 | bool operator==(const IAPrinter &RHS) { | |
737 | if (Conds.size() != RHS.Conds.size()) | |
738 | return false; | |
739 | ||
740 | unsigned Idx = 0; | |
741 | for (std::vector<std::string>::iterator | |
742 | I = Conds.begin(), E = Conds.end(); I != E; ++I) | |
743 | if (*I != RHS.Conds[Idx++]) | |
744 | return false; | |
745 | ||
746 | return true; | |
747 | } | |
223e47cc LB |
748 | }; |
749 | ||
750 | } // end anonymous namespace | |
751 | ||
1a4d82fc JJ |
752 | static unsigned CountNumOperands(StringRef AsmString, unsigned Variant) { |
753 | std::string FlatAsmString = | |
754 | CodeGenInstruction::FlattenAsmStringVariants(AsmString, Variant); | |
755 | AsmString = FlatAsmString; | |
223e47cc | 756 | |
1a4d82fc | 757 | return AsmString.count(' ') + AsmString.count('\t'); |
223e47cc LB |
758 | } |
759 | ||
1a4d82fc JJ |
760 | namespace { |
761 | struct AliasPriorityComparator { | |
762 | typedef std::pair<CodeGenInstAlias *, int> ValueType; | |
763 | bool operator()(const ValueType &LHS, const ValueType &RHS) { | |
764 | if (LHS.second == RHS.second) { | |
765 | // We don't actually care about the order, but for consistency it | |
766 | // shouldn't depend on pointer comparisons. | |
767 | return LHS.first->TheDef->getName() < RHS.first->TheDef->getName(); | |
768 | } | |
223e47cc | 769 | |
1a4d82fc JJ |
770 | // Aliases with larger priorities should be considered first. |
771 | return LHS.second > RHS.second; | |
223e47cc | 772 | } |
1a4d82fc | 773 | }; |
223e47cc LB |
774 | } |
775 | ||
1a4d82fc | 776 | |
223e47cc | 777 | void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { |
223e47cc LB |
778 | Record *AsmWriter = Target.getAsmWriter(); |
779 | ||
223e47cc LB |
780 | O << "\n#ifdef PRINT_ALIAS_INSTR\n"; |
781 | O << "#undef PRINT_ALIAS_INSTR\n\n"; | |
782 | ||
1a4d82fc JJ |
783 | ////////////////////////////// |
784 | // Gather information about aliases we need to print | |
785 | ////////////////////////////// | |
786 | ||
223e47cc LB |
787 | // Emit the method that prints the alias instruction. |
788 | std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); | |
1a4d82fc | 789 | unsigned Variant = AsmWriter->getValueAsInt("Variant"); |
223e47cc LB |
790 | |
791 | std::vector<Record*> AllInstAliases = | |
792 | Records.getAllDerivedDefinitions("InstAlias"); | |
793 | ||
794 | // Create a map from the qualified name to a list of potential matches. | |
1a4d82fc JJ |
795 | typedef std::set<std::pair<CodeGenInstAlias*, int>, AliasPriorityComparator> |
796 | AliasWithPriority; | |
797 | std::map<std::string, AliasWithPriority> AliasMap; | |
223e47cc LB |
798 | for (std::vector<Record*>::iterator |
799 | I = AllInstAliases.begin(), E = AllInstAliases.end(); I != E; ++I) { | |
1a4d82fc | 800 | CodeGenInstAlias *Alias = new CodeGenInstAlias(*I, Variant, Target); |
223e47cc | 801 | const Record *R = *I; |
1a4d82fc JJ |
802 | int Priority = R->getValueAsInt("EmitPriority"); |
803 | if (Priority < 1) | |
804 | continue; // Aliases with priority 0 are never emitted. | |
805 | ||
223e47cc | 806 | const DagInit *DI = R->getValueAsDag("ResultInst"); |
970d7e83 | 807 | const DefInit *Op = cast<DefInit>(DI->getOperator()); |
1a4d82fc JJ |
808 | AliasMap[getQualifiedName(Op->getDef())].insert(std::make_pair(Alias, |
809 | Priority)); | |
223e47cc LB |
810 | } |
811 | ||
812 | // A map of which conditions need to be met for each instruction operand | |
813 | // before it can be matched to the mnemonic. | |
814 | std::map<std::string, std::vector<IAPrinter*> > IAPrinterMap; | |
815 | ||
1a4d82fc JJ |
816 | // A list of MCOperandPredicates for all operands in use, and the reverse map |
817 | std::vector<const Record*> MCOpPredicates; | |
818 | DenseMap<const Record*, unsigned> MCOpPredicateMap; | |
223e47cc | 819 | |
1a4d82fc JJ |
820 | for (auto &Aliases : AliasMap) { |
821 | for (auto &Alias : Aliases.second) { | |
822 | const CodeGenInstAlias *CGA = Alias.first; | |
223e47cc LB |
823 | unsigned LastOpNo = CGA->ResultInstOperandIndex.size(); |
824 | unsigned NumResultOps = | |
1a4d82fc | 825 | CountNumOperands(CGA->ResultInst->AsmString, Variant); |
223e47cc LB |
826 | |
827 | // Don't emit the alias if it has more operands than what it's aliasing. | |
1a4d82fc | 828 | if (NumResultOps < CountNumOperands(CGA->AsmString, Variant)) |
223e47cc LB |
829 | continue; |
830 | ||
831 | IAPrinter *IAP = new IAPrinter(CGA->Result->getAsString(), | |
832 | CGA->AsmString); | |
833 | ||
1a4d82fc JJ |
834 | unsigned NumMIOps = 0; |
835 | for (auto &Operand : CGA->ResultOperands) | |
836 | NumMIOps += Operand.getMINumOperands(); | |
837 | ||
223e47cc | 838 | std::string Cond; |
1a4d82fc | 839 | Cond = std::string("MI->getNumOperands() == ") + llvm::utostr(NumMIOps); |
223e47cc LB |
840 | IAP->addCond(Cond); |
841 | ||
223e47cc LB |
842 | bool CantHandle = false; |
843 | ||
1a4d82fc | 844 | unsigned MIOpNum = 0; |
223e47cc | 845 | for (unsigned i = 0, e = LastOpNo; i != e; ++i) { |
1a4d82fc JJ |
846 | std::string Op = "MI->getOperand(" + llvm::utostr(MIOpNum) + ")"; |
847 | ||
223e47cc LB |
848 | const CodeGenInstAlias::ResultOperand &RO = CGA->ResultOperands[i]; |
849 | ||
850 | switch (RO.Kind) { | |
851 | case CodeGenInstAlias::ResultOperand::K_Record: { | |
852 | const Record *Rec = RO.getRecord(); | |
853 | StringRef ROName = RO.getName(); | |
1a4d82fc JJ |
854 | int PrintMethodIdx = -1; |
855 | ||
856 | // These two may have a PrintMethod, which we want to record (if it's | |
857 | // the first time we've seen it) and provide an index for the aliasing | |
858 | // code to use. | |
859 | if (Rec->isSubClassOf("RegisterOperand") || | |
860 | Rec->isSubClassOf("Operand")) { | |
861 | std::string PrintMethod = Rec->getValueAsString("PrintMethod"); | |
862 | if (PrintMethod != "" && PrintMethod != "printOperand") { | |
863 | PrintMethodIdx = std::find(PrintMethods.begin(), | |
864 | PrintMethods.end(), PrintMethod) - | |
865 | PrintMethods.begin(); | |
866 | if (static_cast<unsigned>(PrintMethodIdx) == PrintMethods.size()) | |
867 | PrintMethods.push_back(PrintMethod); | |
868 | } | |
869 | } | |
223e47cc LB |
870 | |
871 | if (Rec->isSubClassOf("RegisterOperand")) | |
872 | Rec = Rec->getValueAsDef("RegClass"); | |
873 | if (Rec->isSubClassOf("RegisterClass")) { | |
1a4d82fc | 874 | IAP->addCond(Op + ".isReg()"); |
223e47cc LB |
875 | |
876 | if (!IAP->isOpMapped(ROName)) { | |
1a4d82fc | 877 | IAP->addOperand(ROName, MIOpNum, PrintMethodIdx); |
970d7e83 LB |
878 | Record *R = CGA->ResultOperands[i].getRecord(); |
879 | if (R->isSubClassOf("RegisterOperand")) | |
880 | R = R->getValueAsDef("RegClass"); | |
223e47cc | 881 | Cond = std::string("MRI.getRegClass(") + Target.getName() + "::" + |
1a4d82fc JJ |
882 | R->getName() + "RegClassID)" |
883 | ".contains(" + Op + ".getReg())"; | |
223e47cc | 884 | } else { |
1a4d82fc | 885 | Cond = Op + ".getReg() == MI->getOperand(" + |
223e47cc | 886 | llvm::utostr(IAP->getOpIndex(ROName)) + ").getReg()"; |
223e47cc LB |
887 | } |
888 | } else { | |
1a4d82fc JJ |
889 | // Assume all printable operands are desired for now. This can be |
890 | // overridden in the InstAlias instantiation if necessary. | |
891 | IAP->addOperand(ROName, MIOpNum, PrintMethodIdx); | |
892 | ||
893 | // There might be an additional predicate on the MCOperand | |
894 | unsigned Entry = MCOpPredicateMap[Rec]; | |
895 | if (!Entry) { | |
896 | if (!Rec->isValueUnset("MCOperandPredicate")) { | |
897 | MCOpPredicates.push_back(Rec); | |
898 | Entry = MCOpPredicates.size(); | |
899 | MCOpPredicateMap[Rec] = Entry; | |
900 | } else | |
901 | break; // No conditions on this operand at all | |
902 | } | |
903 | Cond = Target.getName() + ClassName + "ValidateMCOperand(" + | |
904 | Op + ", " + llvm::utostr(Entry) + ")"; | |
223e47cc | 905 | } |
1a4d82fc JJ |
906 | // for all subcases of ResultOperand::K_Record: |
907 | IAP->addCond(Cond); | |
223e47cc LB |
908 | break; |
909 | } | |
970d7e83 | 910 | case CodeGenInstAlias::ResultOperand::K_Imm: { |
970d7e83 LB |
911 | // Just because the alias has an immediate result, doesn't mean the |
912 | // MCInst will. An MCExpr could be present, for example. | |
913 | IAP->addCond(Op + ".isImm()"); | |
914 | ||
915 | Cond = Op + ".getImm() == " | |
916 | + llvm::utostr(CGA->ResultOperands[i].getImm()); | |
223e47cc LB |
917 | IAP->addCond(Cond); |
918 | break; | |
970d7e83 | 919 | } |
223e47cc LB |
920 | case CodeGenInstAlias::ResultOperand::K_Reg: |
921 | // If this is zero_reg, something's playing tricks we're not | |
922 | // equipped to handle. | |
923 | if (!CGA->ResultOperands[i].getRegister()) { | |
924 | CantHandle = true; | |
925 | break; | |
926 | } | |
927 | ||
1a4d82fc | 928 | Cond = Op + ".getReg() == " + Target.getName() + |
223e47cc LB |
929 | "::" + CGA->ResultOperands[i].getRegister()->getName(); |
930 | IAP->addCond(Cond); | |
931 | break; | |
932 | } | |
933 | ||
934 | if (!IAP) break; | |
1a4d82fc | 935 | MIOpNum += RO.getMINumOperands(); |
223e47cc LB |
936 | } |
937 | ||
938 | if (CantHandle) continue; | |
1a4d82fc | 939 | IAPrinterMap[Aliases.first].push_back(IAP); |
223e47cc LB |
940 | } |
941 | } | |
942 | ||
1a4d82fc JJ |
943 | ////////////////////////////// |
944 | // Write out the printAliasInstr function | |
945 | ////////////////////////////// | |
946 | ||
223e47cc LB |
947 | std::string Header; |
948 | raw_string_ostream HeaderO(Header); | |
949 | ||
950 | HeaderO << "bool " << Target.getName() << ClassName | |
951 | << "::printAliasInstr(const MCInst" | |
952 | << " *MI, raw_ostream &OS) {\n"; | |
953 | ||
954 | std::string Cases; | |
955 | raw_string_ostream CasesO(Cases); | |
956 | ||
957 | for (std::map<std::string, std::vector<IAPrinter*> >::iterator | |
958 | I = IAPrinterMap.begin(), E = IAPrinterMap.end(); I != E; ++I) { | |
959 | std::vector<IAPrinter*> &IAPs = I->second; | |
960 | std::vector<IAPrinter*> UniqueIAPs; | |
961 | ||
962 | for (std::vector<IAPrinter*>::iterator | |
963 | II = IAPs.begin(), IE = IAPs.end(); II != IE; ++II) { | |
964 | IAPrinter *LHS = *II; | |
965 | bool IsDup = false; | |
966 | for (std::vector<IAPrinter*>::iterator | |
967 | III = IAPs.begin(), IIE = IAPs.end(); III != IIE; ++III) { | |
968 | IAPrinter *RHS = *III; | |
969 | if (LHS != RHS && *LHS == *RHS) { | |
970 | IsDup = true; | |
971 | break; | |
972 | } | |
973 | } | |
974 | ||
975 | if (!IsDup) UniqueIAPs.push_back(LHS); | |
976 | } | |
977 | ||
978 | if (UniqueIAPs.empty()) continue; | |
979 | ||
980 | CasesO.indent(2) << "case " << I->first << ":\n"; | |
981 | ||
982 | for (std::vector<IAPrinter*>::iterator | |
983 | II = UniqueIAPs.begin(), IE = UniqueIAPs.end(); II != IE; ++II) { | |
984 | IAPrinter *IAP = *II; | |
985 | CasesO.indent(4); | |
986 | IAP->print(CasesO); | |
987 | CasesO << '\n'; | |
988 | } | |
989 | ||
990 | CasesO.indent(4) << "return false;\n"; | |
991 | } | |
992 | ||
993 | if (CasesO.str().empty()) { | |
994 | O << HeaderO.str(); | |
995 | O << " return false;\n"; | |
996 | O << "}\n\n"; | |
997 | O << "#endif // PRINT_ALIAS_INSTR\n"; | |
998 | return; | |
999 | } | |
1000 | ||
1a4d82fc JJ |
1001 | if (MCOpPredicates.size()) |
1002 | O << "static bool " << Target.getName() << ClassName | |
1003 | << "ValidateMCOperand(\n" | |
1004 | << " const MCOperand &MCOp, unsigned PredicateIndex);\n"; | |
223e47cc LB |
1005 | |
1006 | O << HeaderO.str(); | |
1a4d82fc | 1007 | O.indent(2) << "const char *AsmString;\n"; |
223e47cc LB |
1008 | O.indent(2) << "switch (MI->getOpcode()) {\n"; |
1009 | O.indent(2) << "default: return false;\n"; | |
1010 | O << CasesO.str(); | |
1011 | O.indent(2) << "}\n\n"; | |
1012 | ||
1013 | // Code that prints the alias, replacing the operands with the ones from the | |
1014 | // MCInst. | |
1a4d82fc JJ |
1015 | O << " unsigned I = 0;\n"; |
1016 | O << " while (AsmString[I] != ' ' && AsmString[I] != '\t' &&\n"; | |
1017 | O << " AsmString[I] != '\\0')\n"; | |
1018 | O << " ++I;\n"; | |
1019 | O << " OS << '\\t' << StringRef(AsmString, I);\n"; | |
223e47cc | 1020 | |
1a4d82fc | 1021 | O << " if (AsmString[I] != '\\0') {\n"; |
223e47cc | 1022 | O << " OS << '\\t';\n"; |
1a4d82fc JJ |
1023 | O << " do {\n"; |
1024 | O << " if (AsmString[I] == '$') {\n"; | |
1025 | O << " ++I;\n"; | |
1026 | O << " if (AsmString[I] == (char)0xff) {\n"; | |
223e47cc | 1027 | O << " ++I;\n"; |
1a4d82fc JJ |
1028 | O << " int OpIdx = AsmString[I++] - 1;\n"; |
1029 | O << " int PrintMethodIdx = AsmString[I++] - 1;\n"; | |
1030 | O << " printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, OS);\n"; | |
1031 | O << " } else\n"; | |
1032 | O << " printOperand(MI, unsigned(AsmString[I++]) - 1, OS);\n"; | |
223e47cc | 1033 | O << " } else {\n"; |
1a4d82fc | 1034 | O << " OS << AsmString[I++];\n"; |
223e47cc | 1035 | O << " }\n"; |
1a4d82fc | 1036 | O << " } while (AsmString[I] != '\\0');\n"; |
223e47cc LB |
1037 | O << " }\n\n"; |
1038 | ||
1039 | O << " return true;\n"; | |
1040 | O << "}\n\n"; | |
1041 | ||
1a4d82fc JJ |
1042 | ////////////////////////////// |
1043 | // Write out the printCustomAliasOperand function | |
1044 | ////////////////////////////// | |
1045 | ||
1046 | O << "void " << Target.getName() << ClassName << "::" | |
1047 | << "printCustomAliasOperand(\n" | |
1048 | << " const MCInst *MI, unsigned OpIdx,\n" | |
1049 | << " unsigned PrintMethodIdx, raw_ostream &OS) {\n"; | |
1050 | if (PrintMethods.empty()) | |
1051 | O << " llvm_unreachable(\"Unknown PrintMethod kind\");\n"; | |
1052 | else { | |
1053 | O << " switch (PrintMethodIdx) {\n" | |
1054 | << " default:\n" | |
1055 | << " llvm_unreachable(\"Unknown PrintMethod kind\");\n" | |
1056 | << " break;\n"; | |
1057 | ||
1058 | for (unsigned i = 0; i < PrintMethods.size(); ++i) { | |
1059 | O << " case " << i << ":\n" | |
1060 | << " " << PrintMethods[i] << "(MI, OpIdx, OS);\n" | |
1061 | << " break;\n"; | |
1062 | } | |
1063 | O << " }\n"; | |
1064 | } | |
1065 | O << "}\n\n"; | |
1066 | ||
1067 | if (MCOpPredicates.size()) { | |
1068 | O << "static bool " << Target.getName() << ClassName | |
1069 | << "ValidateMCOperand(\n" | |
1070 | << " const MCOperand &MCOp, unsigned PredicateIndex) {\n" | |
1071 | << " switch (PredicateIndex) {\n" | |
1072 | << " default:\n" | |
1073 | << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" | |
1074 | << " break;\n"; | |
1075 | ||
1076 | for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { | |
1077 | Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); | |
1078 | if (StringInit *SI = dyn_cast<StringInit>(MCOpPred)) { | |
1079 | O << " case " << i + 1 << ": {\n" | |
1080 | << SI->getValue() << "\n" | |
1081 | << " }\n"; | |
1082 | } else | |
1083 | llvm_unreachable("Unexpected MCOperandPredicate field!"); | |
1084 | } | |
1085 | O << " }\n" | |
1086 | << "}\n\n"; | |
1087 | } | |
1088 | ||
223e47cc LB |
1089 | O << "#endif // PRINT_ALIAS_INSTR\n"; |
1090 | } | |
1091 | ||
1a4d82fc JJ |
1092 | AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) { |
1093 | Record *AsmWriter = Target.getAsmWriter(); | |
85aaf69f SL |
1094 | for (const CodeGenInstruction *I : Target.instructions()) |
1095 | if (!I->AsmString.empty() && I->TheDef->getName() != "PHI") | |
1a4d82fc | 1096 | Instructions.push_back( |
85aaf69f | 1097 | AsmWriterInst(*I, AsmWriter->getValueAsInt("Variant"))); |
1a4d82fc JJ |
1098 | |
1099 | // Get the instruction numbering. | |
1100 | NumberedInstructions = &Target.getInstructionsByEnumValue(); | |
1101 | ||
1102 | // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not | |
1103 | // all machine instructions are necessarily being printed, so there may be | |
1104 | // target instructions not in this map. | |
1105 | for (unsigned i = 0, e = Instructions.size(); i != e; ++i) | |
1106 | CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i])); | |
1107 | } | |
1108 | ||
223e47cc LB |
1109 | void AsmWriterEmitter::run(raw_ostream &O) { |
1110 | EmitPrintInstruction(O); | |
1111 | EmitGetRegisterName(O); | |
1112 | EmitPrintAliasInstruction(O); | |
1113 | } | |
1114 | ||
1115 | ||
1116 | namespace llvm { | |
1117 | ||
1118 | void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS) { | |
1119 | emitSourceFileHeader("Assembly Writer Source Fragment", OS); | |
1120 | AsmWriterEmitter(RK).run(OS); | |
1121 | } | |
1122 | ||
1123 | } // End llvm namespace |