AsmMatcherEmitter.cpp revision a027d222e18ea9028e9e12ae2f5cd566889b599a
1//===- AsmMatcherEmitter.cpp - Generate an assembly matcher ---------------===//
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 emits a target specifier matcher for converting parsed
11// assembly operands in the MCInst structures.
12//
13//===----------------------------------------------------------------------===//
14
15#include "AsmMatcherEmitter.h"
16#include "CodeGenTarget.h"
17#include "Record.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/Support/Debug.h"
20#include <set>
21#include <list>
22using namespace llvm;
23
24/// FlattenVariants - Flatten an .td file assembly string by selecting the
25/// variant at index \arg N.
26static std::string FlattenVariants(const std::string &AsmString,
27                                   unsigned N) {
28  StringRef Cur = AsmString;
29  std::string Res = "";
30
31  for (;;) {
32    // Add the prefix until the next '{', and split out the contents in the
33    // braces.
34    std::pair<StringRef, StringRef> Inner, Split = Cur.split('{');
35
36    Res += Split.first;
37    if (Split.second.empty())
38      break;
39
40    Inner = Split.second.split('}');
41
42    // Select the Nth variant (or empty).
43    StringRef Selection = Inner.first;
44    for (unsigned i = 0; i != N; ++i)
45      Selection = Selection.split('|').second;
46    Res += Selection.split('|').first;
47
48    Cur = Inner.second;
49  }
50
51  return Res;
52}
53
54/// TokenizeAsmString - Tokenize a simplified assembly string.
55static void TokenizeAsmString(const std::string &AsmString,
56                              SmallVectorImpl<StringRef> &Tokens) {
57  unsigned Prev = 0;
58  bool InTok = true;
59  for (unsigned i = 0, e = AsmString.size(); i != e; ++i) {
60    switch (AsmString[i]) {
61    case '*':
62    case '!':
63    case ' ':
64    case '\t':
65    case ',':
66      if (InTok) {
67        Tokens.push_back(StringRef(&AsmString[Prev], i - Prev));
68        InTok = false;
69      }
70      if (AsmString[i] == '*' || AsmString[i] == '!')
71        Tokens.push_back(StringRef(&AsmString[i], 1));
72      Prev = i + 1;
73      break;
74
75    default:
76      InTok = true;
77    }
78  }
79  if (InTok && Prev != AsmString.size())
80    Tokens.push_back(StringRef(&AsmString[Prev], AsmString.size() - Prev));
81}
82
83void AsmMatcherEmitter::run(raw_ostream &OS) {
84  CodeGenTarget Target;
85  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
86  Record *AsmParser = Target.getAsmParser();
87  std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");
88
89  std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");
90
91  EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);
92
93  // Emit the function to match a register name to number.
94
95  OS << "bool " << Target.getName() << ClassName
96     << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n";
97
98  // FIXME: TableGen should have a fast string matcher generator.
99  for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
100    const CodeGenRegister &Reg = Registers[i];
101    if (Reg.TheDef->getValueAsString("AsmName").empty())
102      continue;
103
104    OS << "  if (Name == \""
105       << Reg.TheDef->getValueAsString("AsmName") << "\")\n"
106       << "    return RegNo=" << i + 1 << ", false;\n";
107  }
108  OS << "  return true;\n";
109  OS << "}\n";
110
111  // Emit the function to match instructions.
112  std::vector<const CodeGenInstruction*> NumberedInstructions;
113  Target.getInstructionsByEnumValue(NumberedInstructions);
114
115  std::list<std::string> MatchFns;
116
117  OS << "\n";
118  const std::map<std::string, CodeGenInstruction> &Instructions =
119    Target.getInstructions();
120  for (std::map<std::string, CodeGenInstruction>::const_iterator
121         it = Instructions.begin(), ie = Instructions.end(); it != ie; ++it) {
122    const CodeGenInstruction &CGI = it->second;
123
124    // Ignore psuedo ops.
125    //
126    // FIXME: This is a hack.
127    if (const RecordVal *Form = CGI.TheDef->getValue("Form"))
128      if (Form->getValue()->getAsString() == "Pseudo")
129        continue;
130
131    // Ignore instructions with no .s string.
132    //
133    // FIXME: What are these?
134    if (CGI.AsmString.empty())
135      continue;
136
137    // FIXME: Hack; ignore "lock".
138    if (StringRef(CGI.AsmString).startswith("lock"))
139      continue;
140
141    // FIXME: Hack.
142#if 0
143    if (1 && it->first != "SUB8mr")
144      continue;
145#endif
146
147    std::string Flattened = FlattenVariants(CGI.AsmString, 0);
148    SmallVector<StringRef, 8> Tokens;
149
150    TokenizeAsmString(Flattened, Tokens);
151
152    DEBUG({
153        outs() << it->first << " -- flattened:\""
154               << Flattened << "\", tokens:[";
155        for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
156          outs() << Tokens[i];
157          if (i + 1 != e)
158            outs() << ", ";
159        }
160        outs() << "]\n";
161
162        for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
163          const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
164          outs() << "  op[" << i << "] = " << OI.Name
165                 << " " << OI.Rec->getName()
166                 << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
167        }
168      });
169
170    // FIXME: Ignore non-literal tokens.
171    if (std::find(Tokens[0].begin(), Tokens[0].end(), '$') != Tokens[0].end())
172      continue;
173
174    std::string FnName = "Match_" + Target.getName() + "_Inst_" + it->first;
175    MatchFns.push_back(FnName);
176
177    OS << "static bool " << FnName
178       << "(const StringRef &Name,"
179       << " SmallVectorImpl<X86Operand> &Operands,"
180       << " MCInst &Inst) {\n\n";
181
182    OS << "  // Match name.\n";
183    OS << "  if (Name != \"" << Tokens[0] << "\")\n";
184    OS << "    return true;\n\n";
185
186    OS << "  // Match number of operands.\n";
187    OS << "  if (Operands.size() != " << Tokens.size() - 1 << ")\n";
188    OS << "    return true;\n\n";
189
190    // Compute the total number of MCOperands.
191    //
192    // FIXME: Isn't this somewhere else?
193    unsigned NumMIOperands = 0;
194    for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
195      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
196      NumMIOperands = std::max(NumMIOperands,
197                               OI.MIOperandNo + OI.MINumOperands);
198    }
199
200    std::set<unsigned> MatchedOperands;
201    // This the list of operands we need to fill in.
202    if (NumMIOperands)
203      OS << "  MCOperand Ops[" << NumMIOperands << "];\n\n";
204
205    unsigned ParsedOpIdx = 0;
206    for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
207      // FIXME: Can only match simple operands.
208      if (Tokens[i][0] != '$') {
209        OS << "  // FIXME: unable to match token: '" << Tokens[i] << "'!\n";
210        OS << "  return true;\n\n";
211        continue;
212      }
213
214      // Map this token to an operand. FIXME: Move elsewhere.
215
216      unsigned Idx;
217      try {
218        Idx = CGI.getOperandNamed(Tokens[i].substr(1));
219      } catch(...) {
220        OS << "  // FIXME: unable to find operand: '" << Tokens[i] << "'!\n";
221        OS << "  return true;\n\n";
222        continue;
223      }
224
225      // FIXME: Each match routine should always end up filling the same number
226      // of operands, we should just check that the number matches what the
227      // match routine expects here instead of passing it. We can do this once
228      // we start generating the class match functions.
229      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[Idx];
230
231      // Track that we have matched these operands.
232      //
233      // FIXME: Verify that we don't parse something to the same operand twice.
234      for (unsigned j = 0; j != OI.MINumOperands; ++j)
235        MatchedOperands.insert(OI.MIOperandNo + j);
236
237      OS << "  // Match '" << Tokens[i] << "' (parsed operand " << ParsedOpIdx
238         << ") to machine operands [" << OI.MIOperandNo << ", "
239         << OI.MIOperandNo + OI.MINumOperands << ").\n";
240      OS << "  if (Match_" << Target.getName()
241         << "_Op_" << OI.Rec->getName()  << "("
242         << "Operands[" << ParsedOpIdx << "], "
243         << "&Ops[" << OI.MIOperandNo << "], "
244         << OI.MINumOperands << "))\n";
245      OS << "    return true;\n\n";
246
247      ++ParsedOpIdx;
248    }
249
250    // Generate code to construct the MCInst.
251
252    OS << "  // Construct MCInst.\n";
253    OS << "  Inst.setOpcode(" << Target.getName() << "::"
254       << it->first << ");\n";
255    for (unsigned i = 0, e = NumMIOperands; i != e; ++i) {
256      // FIXME: Oops! Ignore this for now, the instruction should print ok. If
257      // we need to evaluate the constraints.
258      if (!MatchedOperands.count(i)) {
259        OS << "\n";
260        OS << "  // FIXME: Nothing matched Ops[" << i << "]!\n";
261        OS << "  Ops[" << i << "].MakeReg(0);\n";
262        OS << "\n";
263      }
264
265      OS << "  Inst.addOperand(Ops[" << i << "]);\n";
266    }
267    OS << "\n";
268    OS << "  return false;\n";
269    OS << "}\n\n";
270  }
271
272  // Generate the top level match function.
273
274  OS << "bool " << Target.getName() << ClassName
275     << "::MatchInstruction(const StringRef &Name, "
276     << "SmallVectorImpl<" << Target.getName() << "Operand> &Operands, "
277     << "MCInst &Inst) {\n";
278  for (std::list<std::string>::iterator it = MatchFns.begin(),
279         ie = MatchFns.end(); it != ie; ++it) {
280    OS << "  if (!" << *it << "(Name, Operands, Inst))\n";
281    OS << "    return false;\n\n";
282  }
283
284  OS << "  return true;\n";
285  OS << "}\n\n";
286}
287