12dc09994c6413f6f2c5e978eb3fd76b35a965c7
[oota-llvm.git] / utils / TableGen / AsmWriterEmitter.cpp
1 //===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source 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 "AsmWriterEmitter.h"
16 #include "CodeGenTarget.h"
17 #include "Record.h"
18 #include <algorithm>
19 #include <ostream>
20 using namespace llvm;
21
22 static bool isIdentChar(char C) {
23   return (C >= 'a' && C <= 'z') ||
24          (C >= 'A' && C <= 'Z') ||
25          (C >= '0' && C <= '9') ||
26          C == '_';
27 }
28
29 namespace {
30   struct AsmWriterOperand {
31     enum { isLiteralTextOperand, isMachineInstrOperand } OperandType;
32
33     /// Str - For isLiteralTextOperand, this IS the literal text.  For
34     /// isMachineInstrOperand, this is the PrinterMethodName for the operand.
35     std::string Str;
36
37     /// MiOpNo - For isMachineInstrOperand, this is the operand number of the
38     /// machine instruction.
39     unsigned MIOpNo;
40
41     /// OpVT - For isMachineInstrOperand, this is the value type for the
42     /// operand.
43     MVT::ValueType OpVT;
44
45     AsmWriterOperand(const std::string &LitStr)
46       : OperandType(isLiteralTextOperand),  Str(LitStr) {}
47
48     AsmWriterOperand(const std::string &Printer, unsigned OpNo,
49                      MVT::ValueType VT) : OperandType(isMachineInstrOperand),
50                                           Str(Printer), MIOpNo(OpNo), OpVT(VT){}
51
52     bool operator!=(const AsmWriterOperand &Other) const {
53       if (OperandType != Other.OperandType || Str != Other.Str) return true;
54       if (OperandType == isMachineInstrOperand)
55         return MIOpNo != Other.MIOpNo || OpVT != Other.OpVT;
56       return false;
57     }
58     bool operator==(const AsmWriterOperand &Other) const {
59       return !operator!=(Other);
60     }
61     void EmitCode(std::ostream &OS) const;
62   };
63
64   struct AsmWriterInst {
65     std::vector<AsmWriterOperand> Operands;
66     const CodeGenInstruction *CGI;
67
68     AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant);
69
70     /// MatchesAllButOneOp - If this instruction is exactly identical to the
71     /// specified instruction except for one differing operand, return the
72     /// differing operand number.  Otherwise return ~0.
73     unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const;
74
75   private:
76     void AddLiteralString(const std::string &Str) {
77       // If the last operand was already a literal text string, append this to
78       // it, otherwise add a new operand.
79       if (!Operands.empty() &&
80           Operands.back().OperandType == AsmWriterOperand::isLiteralTextOperand)
81         Operands.back().Str.append(Str);
82       else
83         Operands.push_back(AsmWriterOperand(Str));
84     }
85   };
86 }
87
88
89 void AsmWriterOperand::EmitCode(std::ostream &OS) const {
90   if (OperandType == isLiteralTextOperand)
91     OS << "O << \"" << Str << "\"; ";
92   else
93     OS << Str << "(MI, " << MIOpNo << ", MVT::" << getEnumName(OpVT) << "); ";
94 }
95
96
97 /// ParseAsmString - Parse the specified Instruction's AsmString into this
98 /// AsmWriterInst.
99 ///
100 AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) {
101   this->CGI = &CGI;
102   bool inVariant = false;  // True if we are inside a {.|.|.} region.
103
104   const std::string &AsmString = CGI.AsmString;
105   std::string::size_type LastEmitted = 0;
106   while (LastEmitted != AsmString.size()) {
107     std::string::size_type DollarPos =
108       AsmString.find_first_of("${|}", LastEmitted);
109     if (DollarPos == std::string::npos) DollarPos = AsmString.size();
110
111     // Emit a constant string fragment.
112     if (DollarPos != LastEmitted) {
113       // TODO: this should eventually handle escaping.
114       AddLiteralString(std::string(AsmString.begin()+LastEmitted,
115                                    AsmString.begin()+DollarPos));
116       LastEmitted = DollarPos;
117     } else if (AsmString[DollarPos] == '{') {
118       if (inVariant)
119         throw "Nested variants found for instruction '" + 
120               CGI.TheDef->getName() + "'!";
121       LastEmitted = DollarPos+1;
122       inVariant = true;   // We are now inside of the variant!
123       for (unsigned i = 0; i != Variant; ++i) {
124         // Skip over all of the text for an irrelevant variant here.  The
125         // next variant starts at |, or there may not be text for this
126         // variant if we see a }.
127         std::string::size_type NP =
128           AsmString.find_first_of("|}", LastEmitted);
129         if (NP == std::string::npos)
130           throw "Incomplete variant for instruction '" + 
131                 CGI.TheDef->getName() + "'!";
132         LastEmitted = NP+1;
133         if (AsmString[NP] == '}') {
134           inVariant = false;        // No text for this variant.
135           break;
136         }
137       }
138     } else if (AsmString[DollarPos] == '|') {
139       if (!inVariant)
140         throw "'|' character found outside of a variant in instruction '"
141           + CGI.TheDef->getName() + "'!";
142       // Move to the end of variant list.
143       std::string::size_type NP = AsmString.find('}', LastEmitted);
144       if (NP == std::string::npos)
145         throw "Incomplete variant for instruction '" + 
146               CGI.TheDef->getName() + "'!";
147       LastEmitted = NP+1;
148       inVariant = false;
149     } else if (AsmString[DollarPos] == '}') {
150       if (!inVariant)
151         throw "'}' character found outside of a variant in instruction '"
152           + CGI.TheDef->getName() + "'!";
153       LastEmitted = DollarPos+1;
154       inVariant = false;
155     } else if (DollarPos+1 != AsmString.size() &&
156                AsmString[DollarPos+1] == '$') {
157       AddLiteralString("$");  // "$$" -> $
158       LastEmitted = DollarPos+2;
159     } else {
160       // Get the name of the variable.
161       std::string::size_type VarEnd = DollarPos+1;
162
163       // handle ${foo}bar as $foo by detecting whether the character following
164       // the dollar sign is a curly brace.  If so, advance VarEnd and DollarPos
165       // so the variable name does not contain the leading curly brace.
166       bool hasCurlyBraces = false;
167       if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) {
168         hasCurlyBraces = true;
169         ++DollarPos;
170         ++VarEnd;
171       }
172
173       while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
174         ++VarEnd;
175       std::string VarName(AsmString.begin()+DollarPos+1,
176                           AsmString.begin()+VarEnd);
177
178       // In order to avoid starting the next string at the terminating curly
179       // brace, advance the end position past it if we found an opening curly
180       // brace.
181       if (hasCurlyBraces) {
182         if (VarEnd >= AsmString.size())
183           throw "Reached end of string before terminating curly brace in '"
184                 + CGI.TheDef->getName() + "'";
185         if (AsmString[VarEnd] != '}')
186           throw "Variant name beginning with '{' did not end with '}' in '"
187                 + CGI.TheDef->getName() + "'";
188         ++VarEnd;
189       }
190       if (VarName.empty())
191         throw "Stray '$' in '" + CGI.TheDef->getName() + 
192               "' asm string, maybe you want $$?";
193
194       unsigned OpNo = CGI.getOperandNamed(VarName);
195       CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo];
196
197       // If this is a two-address instruction and we are not accessing the
198       // 0th operand, remove an operand.
199       unsigned MIOp = OpInfo.MIOperandNo;
200       if (CGI.isTwoAddress && MIOp != 0) {
201         if (MIOp == 1)
202           throw "Should refer to operand #0 instead of #1 for two-address"
203             " instruction '" + CGI.TheDef->getName() + "'!";
204         --MIOp;
205       }
206
207       Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName,
208                                           MIOp, OpInfo.Ty));
209       LastEmitted = VarEnd;
210     }
211   }
212
213   AddLiteralString("\\n");
214 }
215
216 /// MatchesAllButOneOp - If this instruction is exactly identical to the
217 /// specified instruction except for one differing operand, return the differing
218 /// operand number.  If more than one operand mismatches, return ~1, otherwise
219 /// if the instructions are identical return ~0.
220 unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{
221   if (Operands.size() != Other.Operands.size()) return ~1;
222
223   unsigned MismatchOperand = ~0U;
224   for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
225     if (Operands[i] != Other.Operands[i])
226       if (MismatchOperand != ~0U)  // Already have one mismatch?
227         return ~1U;
228       else
229         MismatchOperand = i;
230   }
231   return MismatchOperand;
232 }
233
234 static void PrintCases(std::vector<std::pair<std::string,
235                        AsmWriterOperand> > &OpsToPrint, std::ostream &O) {
236   O << "    case " << OpsToPrint.back().first << ": ";
237   AsmWriterOperand TheOp = OpsToPrint.back().second;
238   OpsToPrint.pop_back();
239
240   // Check to see if any other operands are identical in this list, and if so,
241   // emit a case label for them.
242   for (unsigned i = OpsToPrint.size(); i != 0; --i)
243     if (OpsToPrint[i-1].second == TheOp) {
244       O << "\n    case " << OpsToPrint[i-1].first << ": ";
245       OpsToPrint.erase(OpsToPrint.begin()+i-1);
246     }
247
248   // Finally, emit the code.
249   TheOp.EmitCode(O);
250   O << "break;\n";
251 }
252
253
254 /// EmitInstructions - Emit the last instruction in the vector and any other
255 /// instructions that are suitably similar to it.
256 static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
257                              std::ostream &O) {
258   AsmWriterInst FirstInst = Insts.back();
259   Insts.pop_back();
260
261   std::vector<AsmWriterInst> SimilarInsts;
262   unsigned DifferingOperand = ~0;
263   for (unsigned i = Insts.size(); i != 0; --i) {
264     unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst);
265     if (DiffOp != ~1U) {
266       if (DifferingOperand == ~0U)  // First match!
267         DifferingOperand = DiffOp;
268
269       // If this differs in the same operand as the rest of the instructions in
270       // this class, move it to the SimilarInsts list.
271       if (DifferingOperand == DiffOp || DiffOp == ~0U) {
272         SimilarInsts.push_back(Insts[i-1]);
273         Insts.erase(Insts.begin()+i-1);
274       }
275     }
276   }
277
278   std::string Namespace = FirstInst.CGI->Namespace;
279
280   O << "  case " << Namespace << "::"
281     << FirstInst.CGI->TheDef->getName() << ":\n";
282   for (unsigned i = 0, e = SimilarInsts.size(); i != e; ++i)
283     O << "  case " << Namespace << "::"
284       << SimilarInsts[i].CGI->TheDef->getName() << ":\n";
285   for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {
286     if (i != DifferingOperand) {
287       // If the operand is the same for all instructions, just print it.
288       O << "    ";
289       FirstInst.Operands[i].EmitCode(O);
290     } else {
291       // If this is the operand that varies between all of the instructions,
292       // emit a switch for just this operand now.
293       O << "    switch (MI->getOpcode()) {\n";
294       std::vector<std::pair<std::string, AsmWriterOperand> > OpsToPrint;
295       OpsToPrint.push_back(std::make_pair(Namespace+"::"+
296                                           FirstInst.CGI->TheDef->getName(),
297                                           FirstInst.Operands[i]));
298
299       for (unsigned si = 0, e = SimilarInsts.size(); si != e; ++si) {
300         AsmWriterInst &AWI = SimilarInsts[si];
301         OpsToPrint.push_back(std::make_pair(Namespace+"::"+
302                                             AWI.CGI->TheDef->getName(),
303                                             AWI.Operands[i]));
304       }
305       std::reverse(OpsToPrint.begin(), OpsToPrint.end());
306       while (!OpsToPrint.empty())
307         PrintCases(OpsToPrint, O);
308       O << "    }";
309     }
310     O << "\n";
311   }
312
313   O << "    break;\n";
314 }
315
316 void AsmWriterEmitter::run(std::ostream &O) {
317   EmitSourceFileHeader("Assembly Writer Source Fragment", O);
318
319   CodeGenTarget Target;
320   Record *AsmWriter = Target.getAsmWriter();
321   std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
322   unsigned Variant = AsmWriter->getValueAsInt("Variant");
323
324   O <<
325   "/// printInstruction - This method is automatically generated by tablegen\n"
326   "/// from the instruction set description.  This method returns true if the\n"
327   "/// machine instruction was sufficiently described to print it, otherwise\n"
328   "/// it returns false.\n"
329     "bool " << Target.getName() << ClassName
330             << "::printInstruction(const MachineInstr *MI) {\n";
331
332   std::string Namespace = Target.inst_begin()->second.Namespace;
333
334   std::vector<AsmWriterInst> Instructions;
335
336   for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
337          E = Target.inst_end(); I != E; ++I)
338     if (!I->second.AsmString.empty())
339       Instructions.push_back(AsmWriterInst(I->second, Variant));
340
341   // If all of the instructions start with a constant string (a very very common
342   // occurance), emit all of the constant strings as a big table lookup instead
343   // of requiring a switch for them.
344   bool AllStartWithString = true;
345
346   for (unsigned i = 0, e = Instructions.size(); i != e; ++i)
347     if (Instructions[i].Operands.empty() ||
348         Instructions[i].Operands[0].OperandType !=
349                           AsmWriterOperand::isLiteralTextOperand) {
350       AllStartWithString = false;
351       break;
352     }
353
354   if (AllStartWithString) {
355     // Compute the CodeGenInstruction -> AsmWriterInst mapping.  Note that not
356     // all machine instructions are necessarily being printed, so there may be
357     // target instructions not in this map.
358     std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap;
359     for (unsigned i = 0, e = Instructions.size(); i != e; ++i)
360       CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i]));
361
362     // Emit a table of constant strings.
363     std::vector<const CodeGenInstruction*> NumberedInstructions;
364     Target.getInstructionsByEnumValue(NumberedInstructions);
365
366     O << "  static const char * const OpStrs[] = {\n";
367     for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
368       AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]];
369       if (AWI == 0) {
370         // Something not handled by the asmwriter printer.
371         O << "    0,\t// ";
372       } else {
373         O << "    \"" << AWI->Operands[0].Str << "\",\t// ";
374         // Nuke the string from the operand list.  It is now handled!
375         AWI->Operands.erase(AWI->Operands.begin());
376       }
377       O << NumberedInstructions[i]->TheDef->getName() << "\n";
378     }
379     O << "  };\n\n"
380       << "  // Emit the opcode for the instruction.\n"
381       << "  if (const char *AsmStr = OpStrs[MI->getOpcode()])\n"
382       << "    O << AsmStr;\n\n";
383   }
384
385   // Because this is a vector we want to emit from the end.  Reverse all of the
386   // elements in the vector.
387   std::reverse(Instructions.begin(), Instructions.end());
388
389   O << "  switch (MI->getOpcode()) {\n"
390        "  default: return false;\n";
391
392   while (!Instructions.empty())
393     EmitInstructions(Instructions, O);
394
395   O << "  }\n"
396        "  return true;\n"
397        "}\n";
398 }