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