blob: 611d470a46d4fe658060161e4ff35b7db836a9d6 [file] [log] [blame]
Daniel Dunbar3f6e3ff2009-07-11 19:39:44 +00001//===- 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"
Daniel Dunbara54716c2009-07-31 02:32:59 +000018#include "llvm/ADT/SmallVector.h"
19#include "llvm/Support/Debug.h"
20#include <set>
21#include <list>
Daniel Dunbar3f6e3ff2009-07-11 19:39:44 +000022using namespace llvm;
23
Daniel Dunbara54716c2009-07-31 02:32:59 +000024/// 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
Daniel Dunbar2f9876b2009-07-17 18:51:11 +000083void AsmMatcherEmitter::run(raw_ostream &OS) {
Daniel Dunbar3f6e3ff2009-07-11 19:39:44 +000084 CodeGenTarget Target;
Daniel Dunbar2f9876b2009-07-17 18:51:11 +000085 const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
Daniel Dunbar85f1b392009-07-29 00:02:19 +000086 Record *AsmParser = Target.getAsmParser();
87 std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");
Daniel Dunbar2f9876b2009-07-17 18:51:11 +000088
89 std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");
90
91 EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);
Daniel Dunbar2f9876b2009-07-17 18:51:11 +000092
93 // Emit the function to match a register name to number.
94
Daniel Dunbar85f1b392009-07-29 00:02:19 +000095 OS << "bool " << Target.getName() << ClassName
96 << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n";
Daniel Dunbar2f9876b2009-07-17 18:51:11 +000097
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";
Daniel Dunbara54716c2009-07-31 02:32:59 +0000110
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";
Daniel Dunbar3f6e3ff2009-07-11 19:39:44 +0000286}