blob: 3d0739f180c84e4dadbe44ad76598abd0dcf8014 [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 (;;) {
Daniel Dunbar815c7ab2009-08-04 20:36:45 +000032 // Find the start of the next variant string.
33 size_t VariantsStart = 0;
34 for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart)
35 if (Cur[VariantsStart] == '{' &&
36 (VariantsStart == 0 || Cur[VariantsStart-1] != '$'))
37 break;
Daniel Dunbara54716c2009-07-31 02:32:59 +000038
Daniel Dunbar815c7ab2009-08-04 20:36:45 +000039 // Add the prefix to the result.
40 Res += Cur.slice(0, VariantsStart);
41 if (VariantsStart == Cur.size())
Daniel Dunbara54716c2009-07-31 02:32:59 +000042 break;
43
Daniel Dunbar815c7ab2009-08-04 20:36:45 +000044 ++VariantsStart; // Skip the '{'.
45
46 // Scan to the end of the variants string.
47 size_t VariantsEnd = VariantsStart;
48 unsigned NestedBraces = 1;
49 for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) {
50 if (Cur[VariantsEnd] == '}') {
51 if (--NestedBraces == 0)
52 break;
53 } else if (Cur[VariantsEnd] == '{')
54 ++NestedBraces;
55 }
Daniel Dunbara54716c2009-07-31 02:32:59 +000056
57 // Select the Nth variant (or empty).
Daniel Dunbar815c7ab2009-08-04 20:36:45 +000058 StringRef Selection = Cur.slice(VariantsStart, VariantsEnd);
Daniel Dunbara54716c2009-07-31 02:32:59 +000059 for (unsigned i = 0; i != N; ++i)
60 Selection = Selection.split('|').second;
61 Res += Selection.split('|').first;
62
Daniel Dunbar815c7ab2009-08-04 20:36:45 +000063 assert(VariantsEnd != Cur.size() &&
64 "Unterminated variants in assembly string!");
65 Cur = Cur.substr(VariantsEnd + 1);
Daniel Dunbara54716c2009-07-31 02:32:59 +000066 }
67
68 return Res;
69}
70
71/// TokenizeAsmString - Tokenize a simplified assembly string.
72static void TokenizeAsmString(const std::string &AsmString,
73 SmallVectorImpl<StringRef> &Tokens) {
74 unsigned Prev = 0;
75 bool InTok = true;
76 for (unsigned i = 0, e = AsmString.size(); i != e; ++i) {
77 switch (AsmString[i]) {
78 case '*':
79 case '!':
80 case ' ':
81 case '\t':
82 case ',':
83 if (InTok) {
84 Tokens.push_back(StringRef(&AsmString[Prev], i - Prev));
85 InTok = false;
86 }
87 if (AsmString[i] == '*' || AsmString[i] == '!')
88 Tokens.push_back(StringRef(&AsmString[i], 1));
89 Prev = i + 1;
90 break;
91
92 default:
93 InTok = true;
94 }
95 }
96 if (InTok && Prev != AsmString.size())
97 Tokens.push_back(StringRef(&AsmString[Prev], AsmString.size() - Prev));
98}
99
Daniel Dunbar2f9876b2009-07-17 18:51:11 +0000100void AsmMatcherEmitter::run(raw_ostream &OS) {
Daniel Dunbar3f6e3ff2009-07-11 19:39:44 +0000101 CodeGenTarget Target;
Daniel Dunbar2f9876b2009-07-17 18:51:11 +0000102 const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
Daniel Dunbar85f1b392009-07-29 00:02:19 +0000103 Record *AsmParser = Target.getAsmParser();
104 std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");
Daniel Dunbar2f9876b2009-07-17 18:51:11 +0000105
106 std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");
107
108 EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);
Daniel Dunbar2f9876b2009-07-17 18:51:11 +0000109
110 // Emit the function to match a register name to number.
111
Daniel Dunbar85f1b392009-07-29 00:02:19 +0000112 OS << "bool " << Target.getName() << ClassName
113 << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n";
Daniel Dunbar2f9876b2009-07-17 18:51:11 +0000114
115 // FIXME: TableGen should have a fast string matcher generator.
116 for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
117 const CodeGenRegister &Reg = Registers[i];
118 if (Reg.TheDef->getValueAsString("AsmName").empty())
119 continue;
120
121 OS << " if (Name == \""
122 << Reg.TheDef->getValueAsString("AsmName") << "\")\n"
123 << " return RegNo=" << i + 1 << ", false;\n";
124 }
125 OS << " return true;\n";
126 OS << "}\n";
Daniel Dunbara54716c2009-07-31 02:32:59 +0000127
128 // Emit the function to match instructions.
129 std::vector<const CodeGenInstruction*> NumberedInstructions;
130 Target.getInstructionsByEnumValue(NumberedInstructions);
131
132 std::list<std::string> MatchFns;
133
134 OS << "\n";
135 const std::map<std::string, CodeGenInstruction> &Instructions =
136 Target.getInstructions();
137 for (std::map<std::string, CodeGenInstruction>::const_iterator
138 it = Instructions.begin(), ie = Instructions.end(); it != ie; ++it) {
139 const CodeGenInstruction &CGI = it->second;
140
141 // Ignore psuedo ops.
142 //
143 // FIXME: This is a hack.
144 if (const RecordVal *Form = CGI.TheDef->getValue("Form"))
145 if (Form->getValue()->getAsString() == "Pseudo")
146 continue;
147
Daniel Dunbar815c7ab2009-08-04 20:36:45 +0000148 // Ignore "PHI" node.
149 //
150 // FIXME: This is also a hack.
151 if (it->first == "PHI")
152 continue;
153
Daniel Dunbara54716c2009-07-31 02:32:59 +0000154 // Ignore instructions with no .s string.
155 //
156 // FIXME: What are these?
157 if (CGI.AsmString.empty())
158 continue;
159
160 // FIXME: Hack; ignore "lock".
161 if (StringRef(CGI.AsmString).startswith("lock"))
162 continue;
163
Daniel Dunbara54716c2009-07-31 02:32:59 +0000164 std::string Flattened = FlattenVariants(CGI.AsmString, 0);
165 SmallVector<StringRef, 8> Tokens;
166
167 TokenizeAsmString(Flattened, Tokens);
168
169 DEBUG({
170 outs() << it->first << " -- flattened:\""
171 << Flattened << "\", tokens:[";
172 for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
173 outs() << Tokens[i];
174 if (i + 1 != e)
175 outs() << ", ";
176 }
177 outs() << "]\n";
178
179 for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
180 const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
181 outs() << " op[" << i << "] = " << OI.Name
182 << " " << OI.Rec->getName()
183 << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
184 }
185 });
186
Daniel Dunbar815c7ab2009-08-04 20:36:45 +0000187 // FIXME: Ignore prefixes with non-literal tokens.
188 if (std::find(Tokens[0].begin(), Tokens[0].end(), '$') != Tokens[0].end()) {
189 DEBUG({
190 errs() << "warning: '" << it->first << "': "
191 << "ignoring non-literal token '" << Tokens[0] << "', \n";
192 });
Daniel Dunbara54716c2009-07-31 02:32:59 +0000193 continue;
Daniel Dunbar815c7ab2009-08-04 20:36:45 +0000194 }
195
196 // Ignore instructions with subreg specifiers, these are always fake
197 // instructions for simplifying codegen.
198 //
199 // FIXME: Is this true?
200 //
201 // Also, we ignore instructions which reference the operand multiple times;
202 // this implies a constraint we would not currently honor. These are
203 // currently always fake instructions for simplifying codegen.
204 //
205 // FIXME: Encode this assumption in the .td, so we can error out here.
206 std::set<std::string> OperandNames;
207 unsigned HasSubreg = 0, HasDuplicate = 0;
208 for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
209 if (Tokens[i][0] == '$' &&
210 std::find(Tokens[i].begin(),
211 Tokens[i].end(), ':') != Tokens[i].end())
212 HasSubreg = i;
213 if (Tokens[i][0] == '$' && !OperandNames.insert(Tokens[i]).second)
214 HasDuplicate = i;
215 }
216 if (HasSubreg) {
217 DEBUG({
218 errs() << "warning: '" << it->first << "': "
219 << "ignoring instruction; operand with subreg attribute '"
220 << Tokens[HasSubreg] << "', \n";
221 });
222 continue;
223 } else if (HasDuplicate) {
224 DEBUG({
225 errs() << "warning: '" << it->first << "': "
226 << "ignoring instruction; tied operand '"
227 << Tokens[HasSubreg] << "', \n";
228 });
229 continue;
230 }
Daniel Dunbara54716c2009-07-31 02:32:59 +0000231
232 std::string FnName = "Match_" + Target.getName() + "_Inst_" + it->first;
233 MatchFns.push_back(FnName);
234
235 OS << "static bool " << FnName
236 << "(const StringRef &Name,"
237 << " SmallVectorImpl<X86Operand> &Operands,"
238 << " MCInst &Inst) {\n\n";
239
240 OS << " // Match name.\n";
241 OS << " if (Name != \"" << Tokens[0] << "\")\n";
242 OS << " return true;\n\n";
243
244 OS << " // Match number of operands.\n";
245 OS << " if (Operands.size() != " << Tokens.size() - 1 << ")\n";
246 OS << " return true;\n\n";
247
248 // Compute the total number of MCOperands.
249 //
250 // FIXME: Isn't this somewhere else?
251 unsigned NumMIOperands = 0;
252 for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
253 const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
254 NumMIOperands = std::max(NumMIOperands,
255 OI.MIOperandNo + OI.MINumOperands);
256 }
257
258 std::set<unsigned> MatchedOperands;
259 // This the list of operands we need to fill in.
260 if (NumMIOperands)
261 OS << " MCOperand Ops[" << NumMIOperands << "];\n\n";
262
263 unsigned ParsedOpIdx = 0;
264 for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
265 // FIXME: Can only match simple operands.
266 if (Tokens[i][0] != '$') {
267 OS << " // FIXME: unable to match token: '" << Tokens[i] << "'!\n";
268 OS << " return true;\n\n";
269 continue;
270 }
271
272 // Map this token to an operand. FIXME: Move elsewhere.
273
274 unsigned Idx;
275 try {
276 Idx = CGI.getOperandNamed(Tokens[i].substr(1));
277 } catch(...) {
278 OS << " // FIXME: unable to find operand: '" << Tokens[i] << "'!\n";
279 OS << " return true;\n\n";
280 continue;
281 }
282
283 // FIXME: Each match routine should always end up filling the same number
284 // of operands, we should just check that the number matches what the
285 // match routine expects here instead of passing it. We can do this once
286 // we start generating the class match functions.
287 const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[Idx];
288
289 // Track that we have matched these operands.
290 //
291 // FIXME: Verify that we don't parse something to the same operand twice.
292 for (unsigned j = 0; j != OI.MINumOperands; ++j)
293 MatchedOperands.insert(OI.MIOperandNo + j);
294
295 OS << " // Match '" << Tokens[i] << "' (parsed operand " << ParsedOpIdx
296 << ") to machine operands [" << OI.MIOperandNo << ", "
297 << OI.MIOperandNo + OI.MINumOperands << ").\n";
298 OS << " if (Match_" << Target.getName()
299 << "_Op_" << OI.Rec->getName() << "("
300 << "Operands[" << ParsedOpIdx << "], "
301 << "&Ops[" << OI.MIOperandNo << "], "
302 << OI.MINumOperands << "))\n";
303 OS << " return true;\n\n";
304
305 ++ParsedOpIdx;
306 }
307
308 // Generate code to construct the MCInst.
309
310 OS << " // Construct MCInst.\n";
311 OS << " Inst.setOpcode(" << Target.getName() << "::"
312 << it->first << ");\n";
313 for (unsigned i = 0, e = NumMIOperands; i != e; ++i) {
314 // FIXME: Oops! Ignore this for now, the instruction should print ok. If
315 // we need to evaluate the constraints.
316 if (!MatchedOperands.count(i)) {
317 OS << "\n";
318 OS << " // FIXME: Nothing matched Ops[" << i << "]!\n";
Daniel Dunbar511f4492009-08-02 00:09:22 +0000319 OS << " Ops[" << i << "] = MCOperand::CreateReg(0);\n";
Daniel Dunbara54716c2009-07-31 02:32:59 +0000320 OS << "\n";
321 }
322
323 OS << " Inst.addOperand(Ops[" << i << "]);\n";
324 }
325 OS << "\n";
326 OS << " return false;\n";
327 OS << "}\n\n";
328 }
329
330 // Generate the top level match function.
331
332 OS << "bool " << Target.getName() << ClassName
333 << "::MatchInstruction(const StringRef &Name, "
334 << "SmallVectorImpl<" << Target.getName() << "Operand> &Operands, "
335 << "MCInst &Inst) {\n";
336 for (std::list<std::string>::iterator it = MatchFns.begin(),
337 ie = MatchFns.end(); it != ie; ++it) {
338 OS << " if (!" << *it << "(Name, Operands, Inst))\n";
339 OS << " return false;\n\n";
340 }
341
342 OS << " return true;\n";
343 OS << "}\n\n";
Daniel Dunbar3f6e3ff2009-07-11 19:39:44 +0000344}