blob: 1336eed80153046a42e912deed299de502a543ad [file] [log] [blame]
Sean Callanan8ed9f512009-12-19 02:59:52 +00001//===- X86DisassemblerTables.cpp - Disassembler tables ----------*- C++ -*-===//
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 file is part of the X86 Disassembler Emitter.
11// It contains the implementation of the disassembler tables.
12// Documentation for the disassembler emitter in general can be found in
13// X86DisasemblerEmitter.h.
14//
15//===----------------------------------------------------------------------===//
16
17#include "X86DisassemblerShared.h"
18#include "X86DisassemblerTables.h"
19
Peter Collingbourne7c788882011-10-01 16:41:13 +000020#include "llvm/TableGen/TableGenBackend.h"
Joerg Sonnenberger39d7cae2011-04-04 16:25:38 +000021#include "llvm/ADT/STLExtras.h"
Sean Callanan8ed9f512009-12-19 02:59:52 +000022#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/Format.h"
24
Sean Callanan8ed9f512009-12-19 02:59:52 +000025using namespace llvm;
26using namespace X86Disassembler;
27
28/// inheritsFrom - Indicates whether all instructions in one class also belong
29/// to another class.
30///
31/// @param child - The class that may be the subset
32/// @param parent - The class that may be the superset
33/// @return - True if child is a subset of parent, false otherwise.
34static inline bool inheritsFrom(InstructionContext child,
Craig Topper6744a172011-10-04 06:30:42 +000035 InstructionContext parent,
36 bool VEX_LIG = false) {
Sean Callanan8ed9f512009-12-19 02:59:52 +000037 if (child == parent)
38 return true;
39
40 switch (parent) {
41 case IC:
Craig Topper5ffedb92011-09-02 04:17:54 +000042 return(inheritsFrom(child, IC_64BIT) ||
43 inheritsFrom(child, IC_OPSIZE) ||
44 inheritsFrom(child, IC_XD) ||
45 inheritsFrom(child, IC_XS));
Sean Callanan8ed9f512009-12-19 02:59:52 +000046 case IC_64BIT:
47 return(inheritsFrom(child, IC_64BIT_REXW) ||
48 inheritsFrom(child, IC_64BIT_OPSIZE) ||
49 inheritsFrom(child, IC_64BIT_XD) ||
50 inheritsFrom(child, IC_64BIT_XS));
51 case IC_OPSIZE:
Craig Topper5ffedb92011-09-02 04:17:54 +000052 return inheritsFrom(child, IC_64BIT_OPSIZE);
Sean Callanan8ed9f512009-12-19 02:59:52 +000053 case IC_XD:
Craig Topper5ffedb92011-09-02 04:17:54 +000054 return inheritsFrom(child, IC_64BIT_XD);
Sean Callanan8ed9f512009-12-19 02:59:52 +000055 case IC_XS:
Craig Topper5ffedb92011-09-02 04:17:54 +000056 return inheritsFrom(child, IC_64BIT_XS);
Craig Toppere1b4a1a2011-10-01 19:54:56 +000057 case IC_XD_OPSIZE:
58 return inheritsFrom(child, IC_64BIT_XD_OPSIZE);
Craig Topper29480fd2011-10-11 04:34:23 +000059 case IC_XS_OPSIZE:
60 return inheritsFrom(child, IC_64BIT_XS_OPSIZE);
Sean Callanan8ed9f512009-12-19 02:59:52 +000061 case IC_64BIT_REXW:
62 return(inheritsFrom(child, IC_64BIT_REXW_XS) ||
63 inheritsFrom(child, IC_64BIT_REXW_XD) ||
64 inheritsFrom(child, IC_64BIT_REXW_OPSIZE));
65 case IC_64BIT_OPSIZE:
66 return(inheritsFrom(child, IC_64BIT_REXW_OPSIZE));
67 case IC_64BIT_XD:
68 return(inheritsFrom(child, IC_64BIT_REXW_XD));
69 case IC_64BIT_XS:
70 return(inheritsFrom(child, IC_64BIT_REXW_XS));
Craig Toppere1b4a1a2011-10-01 19:54:56 +000071 case IC_64BIT_XD_OPSIZE:
Craig Topper29480fd2011-10-11 04:34:23 +000072 case IC_64BIT_XS_OPSIZE:
Craig Toppere1b4a1a2011-10-01 19:54:56 +000073 return false;
Sean Callanan8ed9f512009-12-19 02:59:52 +000074 case IC_64BIT_REXW_XD:
Sean Callanan8ed9f512009-12-19 02:59:52 +000075 case IC_64BIT_REXW_XS:
Sean Callanan8ed9f512009-12-19 02:59:52 +000076 case IC_64BIT_REXW_OPSIZE:
77 return false;
Sean Callanana21e2ea2011-03-15 01:23:15 +000078 case IC_VEX:
Craig Topper6744a172011-10-04 06:30:42 +000079 return inheritsFrom(child, IC_VEX_W) ||
80 (VEX_LIG && inheritsFrom(child, IC_VEX_L));
Sean Callanana21e2ea2011-03-15 01:23:15 +000081 case IC_VEX_XS:
Craig Topper6744a172011-10-04 06:30:42 +000082 return inheritsFrom(child, IC_VEX_W_XS) ||
83 (VEX_LIG && inheritsFrom(child, IC_VEX_L_XS));
Sean Callanana21e2ea2011-03-15 01:23:15 +000084 case IC_VEX_XD:
Craig Topper6744a172011-10-04 06:30:42 +000085 return inheritsFrom(child, IC_VEX_W_XD) ||
86 (VEX_LIG && inheritsFrom(child, IC_VEX_L_XD));
Craig Topper5ffedb92011-09-02 04:17:54 +000087 case IC_VEX_OPSIZE:
Craig Topper6744a172011-10-04 06:30:42 +000088 return inheritsFrom(child, IC_VEX_W_OPSIZE) ||
89 (VEX_LIG && inheritsFrom(child, IC_VEX_L_OPSIZE));
Sean Callanana21e2ea2011-03-15 01:23:15 +000090 case IC_VEX_W:
Sean Callanana21e2ea2011-03-15 01:23:15 +000091 case IC_VEX_W_XS:
Sean Callanana21e2ea2011-03-15 01:23:15 +000092 case IC_VEX_W_XD:
Craig Topper5ffedb92011-09-02 04:17:54 +000093 case IC_VEX_W_OPSIZE:
94 return false;
95 case IC_VEX_L:
Craig Topper5ffedb92011-09-02 04:17:54 +000096 case IC_VEX_L_XS:
Craig Topper5ffedb92011-09-02 04:17:54 +000097 case IC_VEX_L_XD:
Craig Topperc8eb8802011-11-06 23:04:08 +000098 return false;
Craig Topper5ffedb92011-09-02 04:17:54 +000099 case IC_VEX_L_OPSIZE:
Craig Topperc8eb8802011-11-06 23:04:08 +0000100 return inheritsFrom(child, IC_VEX_L_W_OPSIZE);
101 case IC_VEX_L_W_OPSIZE:
Craig Topper5ffedb92011-09-02 04:17:54 +0000102 return false;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000103 default:
Craig Topper5ffedb92011-09-02 04:17:54 +0000104 llvm_unreachable("Unknown instruction class");
Sean Callanan8ed9f512009-12-19 02:59:52 +0000105 }
106}
107
108/// outranks - Indicates whether, if an instruction has two different applicable
109/// classes, which class should be preferred when performing decode. This
110/// imposes a total ordering (ties are resolved toward "lower")
111///
112/// @param upper - The class that may be preferable
113/// @param lower - The class that may be less preferable
114/// @return - True if upper is to be preferred, false otherwise.
115static inline bool outranks(InstructionContext upper,
116 InstructionContext lower) {
117 assert(upper < IC_max);
118 assert(lower < IC_max);
119
120#define ENUM_ENTRY(n, r, d) r,
121 static int ranks[IC_max] = {
122 INSTRUCTION_CONTEXTS
123 };
124#undef ENUM_ENTRY
125
126 return (ranks[upper] > ranks[lower]);
127}
128
129/// stringForContext - Returns a string containing the name of a particular
130/// InstructionContext, usually for diagnostic purposes.
131///
132/// @param insnContext - The instruction class to transform to a string.
133/// @return - A statically-allocated string constant that contains the
134/// name of the instruction class.
135static inline const char* stringForContext(InstructionContext insnContext) {
136 switch (insnContext) {
137 default:
138 llvm_unreachable("Unhandled instruction class");
139#define ENUM_ENTRY(n, r, d) case n: return #n; break;
140 INSTRUCTION_CONTEXTS
141#undef ENUM_ENTRY
142 }
Daniel Dunbare5976b82009-12-23 00:45:10 +0000143
144 return 0;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000145}
146
147/// stringForOperandType - Like stringForContext, but for OperandTypes.
148static inline const char* stringForOperandType(OperandType type) {
149 switch (type) {
150 default:
151 llvm_unreachable("Unhandled type");
152#define ENUM_ENTRY(i, d) case i: return #i;
153 TYPES
154#undef ENUM_ENTRY
155 }
156}
157
158/// stringForOperandEncoding - like stringForContext, but for
159/// OperandEncodings.
160static inline const char* stringForOperandEncoding(OperandEncoding encoding) {
161 switch (encoding) {
162 default:
163 llvm_unreachable("Unhandled encoding");
164#define ENUM_ENTRY(i, d) case i: return #i;
165 ENCODINGS
166#undef ENUM_ENTRY
167 }
168}
169
170void DisassemblerTables::emitOneID(raw_ostream &o,
171 uint32_t &i,
172 InstrUID id,
173 bool addComma) const {
174 if (id)
175 o.indent(i * 2) << format("0x%hx", id);
176 else
177 o.indent(i * 2) << 0;
178
179 if (addComma)
180 o << ", ";
181 else
182 o << " ";
183
184 o << "/* ";
185 o << InstructionSpecifiers[id].name;
186 o << "*/";
187
188 o << "\n";
189}
190
191/// emitEmptyTable - Emits the modRMEmptyTable, which is used as a ID table by
192/// all ModR/M decisions for instructions that are invalid for all possible
193/// ModR/M byte values.
194///
195/// @param o - The output stream on which to emit the table.
196/// @param i - The indentation level for that output stream.
197static void emitEmptyTable(raw_ostream &o, uint32_t &i)
198{
Benjamin Kramer86c69c52010-10-23 09:28:42 +0000199 o.indent(i * 2) << "static const InstrUID modRMEmptyTable[1] = { 0 };\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000200 o << "\n";
201}
202
203/// getDecisionType - Determines whether a ModRM decision with 255 entries can
204/// be compacted by eliminating redundant information.
205///
206/// @param decision - The decision to be compacted.
207/// @return - The compactest available representation for the decision.
208static ModRMDecisionType getDecisionType(ModRMDecision &decision)
209{
210 bool satisfiesOneEntry = true;
211 bool satisfiesSplitRM = true;
212
213 uint16_t index;
214
215 for (index = 0; index < 256; ++index) {
216 if (decision.instructionIDs[index] != decision.instructionIDs[0])
217 satisfiesOneEntry = false;
218
219 if (((index & 0xc0) == 0xc0) &&
220 (decision.instructionIDs[index] != decision.instructionIDs[0xc0]))
221 satisfiesSplitRM = false;
222
223 if (((index & 0xc0) != 0xc0) &&
224 (decision.instructionIDs[index] != decision.instructionIDs[0x00]))
225 satisfiesSplitRM = false;
226 }
227
228 if (satisfiesOneEntry)
229 return MODRM_ONEENTRY;
230
231 if (satisfiesSplitRM)
232 return MODRM_SPLITRM;
233
234 return MODRM_FULL;
235}
236
237/// stringForDecisionType - Returns a statically-allocated string corresponding
238/// to a particular decision type.
239///
240/// @param dt - The decision type.
241/// @return - A pointer to the statically-allocated string (e.g.,
242/// "MODRM_ONEENTRY" for MODRM_ONEENTRY).
243static const char* stringForDecisionType(ModRMDecisionType dt)
244{
245#define ENUM_ENTRY(n) case n: return #n;
246 switch (dt) {
247 default:
248 llvm_unreachable("Unknown decision type");
249 MODRMTYPES
250 };
251#undef ENUM_ENTRY
252}
253
254/// stringForModifierType - Returns a statically-allocated string corresponding
255/// to an opcode modifier type.
256///
257/// @param mt - The modifier type.
258/// @return - A pointer to the statically-allocated string (e.g.,
259/// "MODIFIER_NONE" for MODIFIER_NONE).
260static const char* stringForModifierType(ModifierType mt)
261{
262#define ENUM_ENTRY(n) case n: return #n;
263 switch(mt) {
264 default:
265 llvm_unreachable("Unknown modifier type");
266 MODIFIER_TYPES
267 };
268#undef ENUM_ENTRY
269}
270
271DisassemblerTables::DisassemblerTables() {
272 unsigned i;
273
Joerg Sonnenberger39d7cae2011-04-04 16:25:38 +0000274 for (i = 0; i < array_lengthof(Tables); i++) {
Sean Callanan8ed9f512009-12-19 02:59:52 +0000275 Tables[i] = new ContextDecision;
Daniel Dunbar87830872009-12-19 04:16:57 +0000276 memset(Tables[i], 0, sizeof(ContextDecision));
Sean Callanan8ed9f512009-12-19 02:59:52 +0000277 }
278
279 HasConflicts = false;
280}
281
282DisassemblerTables::~DisassemblerTables() {
283 unsigned i;
284
Joerg Sonnenberger39d7cae2011-04-04 16:25:38 +0000285 for (i = 0; i < array_lengthof(Tables); i++)
Sean Callanan8ed9f512009-12-19 02:59:52 +0000286 delete Tables[i];
287}
288
289void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
290 raw_ostream &o2,
291 uint32_t &i1,
292 uint32_t &i2,
293 ModRMDecision &decision)
294 const {
295 static uint64_t sTableNumber = 0;
296 uint64_t thisTableNumber = sTableNumber;
297 ModRMDecisionType dt = getDecisionType(decision);
298 uint16_t index;
299
300 if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
301 {
302 o2.indent(i2) << "{ /* ModRMDecision */" << "\n";
303 i2++;
304
305 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
306 o2.indent(i2) << "modRMEmptyTable";
307
308 i2--;
309 o2.indent(i2) << "}";
310 return;
311 }
312
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000313 o1.indent(i1) << "static const InstrUID modRMTable" << thisTableNumber;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000314
315 switch (dt) {
316 default:
317 llvm_unreachable("Unknown decision type");
318 case MODRM_ONEENTRY:
319 o1 << "[1]";
320 break;
321 case MODRM_SPLITRM:
322 o1 << "[2]";
323 break;
324 case MODRM_FULL:
325 o1 << "[256]";
326 break;
327 }
328
329 o1 << " = {" << "\n";
330 i1++;
331
332 switch (dt) {
333 default:
334 llvm_unreachable("Unknown decision type");
335 case MODRM_ONEENTRY:
336 emitOneID(o1, i1, decision.instructionIDs[0], false);
337 break;
338 case MODRM_SPLITRM:
339 emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
340 emitOneID(o1, i1, decision.instructionIDs[0xc0], false); // mod = 0b11
341 break;
342 case MODRM_FULL:
343 for (index = 0; index < 256; ++index)
344 emitOneID(o1, i1, decision.instructionIDs[index], index < 255);
345 break;
346 }
347
348 i1--;
349 o1.indent(i1) << "};" << "\n";
350 o1 << "\n";
351
352 o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
353 i2++;
354
355 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
356 o2.indent(i2) << "modRMTable" << sTableNumber << "\n";
357
358 i2--;
359 o2.indent(i2) << "}";
360
361 ++sTableNumber;
362}
363
364void DisassemblerTables::emitOpcodeDecision(
365 raw_ostream &o1,
366 raw_ostream &o2,
367 uint32_t &i1,
368 uint32_t &i2,
369 OpcodeDecision &decision) const {
370 uint16_t index;
371
372 o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
373 i2++;
374 o2.indent(i2) << "{" << "\n";
375 i2++;
376
377 for (index = 0; index < 256; ++index) {
378 o2.indent(i2);
379
380 o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
381
382 emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]);
383
384 if (index < 255)
385 o2 << ",";
386
387 o2 << "\n";
388 }
389
390 i2--;
391 o2.indent(i2) << "}" << "\n";
392 i2--;
393 o2.indent(i2) << "}" << "\n";
394}
395
396void DisassemblerTables::emitContextDecision(
397 raw_ostream &o1,
398 raw_ostream &o2,
399 uint32_t &i1,
400 uint32_t &i2,
401 ContextDecision &decision,
402 const char* name) const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000403 o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000404 i2++;
405 o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
406 i2++;
407
408 unsigned index;
409
410 for (index = 0; index < IC_max; ++index) {
411 o2.indent(i2) << "/* ";
412 o2 << stringForContext((InstructionContext)index);
413 o2 << " */";
414 o2 << "\n";
415
416 emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]);
417
418 if (index + 1 < IC_max)
419 o2 << ", ";
420 }
421
422 i2--;
423 o2.indent(i2) << "}" << "\n";
424 i2--;
425 o2.indent(i2) << "};" << "\n";
426}
427
428void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
429 const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000430 o.indent(i * 2) << "static const struct InstructionSpecifier ";
431 o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000432
433 i++;
434
435 uint16_t numInstructions = InstructionSpecifiers.size();
436 uint16_t index, operandIndex;
437
438 for (index = 0; index < numInstructions; ++index) {
439 o.indent(i * 2) << "{ /* " << index << " */" << "\n";
440 i++;
441
442 o.indent(i * 2) <<
443 stringForModifierType(InstructionSpecifiers[index].modifierType);
444 o << "," << "\n";
445
446 o.indent(i * 2) << "0x";
447 o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
448 o << "," << "\n";
449
450 o.indent(i * 2) << "{" << "\n";
451 i++;
452
453 for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
454 o.indent(i * 2) << "{ ";
455 o << stringForOperandEncoding(InstructionSpecifiers[index]
456 .operands[operandIndex]
457 .encoding);
458 o << ", ";
459 o << stringForOperandType(InstructionSpecifiers[index]
460 .operands[operandIndex]
461 .type);
462 o << " }";
463
464 if (operandIndex < X86_MAX_OPERANDS - 1)
465 o << ",";
466
467 o << "\n";
468 }
469
470 i--;
471 o.indent(i * 2) << "}," << "\n";
472
473 o.indent(i * 2) << "\"" << InstructionSpecifiers[index].name << "\"";
474 o << "\n";
475
476 i--;
477 o.indent(i * 2) << "}";
478
479 if (index + 1 < numInstructions)
480 o << ",";
481
482 o << "\n";
483 }
484
485 i--;
486 o.indent(i * 2) << "};" << "\n";
487}
488
489void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
490 uint16_t index;
491
Benjamin Kramer86c69c52010-10-23 09:28:42 +0000492 o.indent(i * 2) << "static const InstructionContext " CONTEXTS_STR
493 "[256] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000494 i++;
495
496 for (index = 0; index < 256; ++index) {
497 o.indent(i * 2);
498
Craig Topperc8eb8802011-11-06 23:04:08 +0000499 if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
500 o << "IC_VEX_L_W_OPSIZE";
501 else if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE))
Sean Callanana21e2ea2011-03-15 01:23:15 +0000502 o << "IC_VEX_L_OPSIZE";
503 else if ((index & ATTR_VEXL) && (index & ATTR_XD))
504 o << "IC_VEX_L_XD";
505 else if ((index & ATTR_VEXL) && (index & ATTR_XS))
506 o << "IC_VEX_L_XS";
507 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
508 o << "IC_VEX_W_OPSIZE";
509 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XD))
510 o << "IC_VEX_W_XD";
511 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XS))
512 o << "IC_VEX_W_XS";
513 else if (index & ATTR_VEXL)
514 o << "IC_VEX_L";
515 else if ((index & ATTR_VEX) && (index & ATTR_REXW))
516 o << "IC_VEX_W";
517 else if ((index & ATTR_VEX) && (index & ATTR_OPSIZE))
518 o << "IC_VEX_OPSIZE";
519 else if ((index & ATTR_VEX) && (index & ATTR_XD))
520 o << "IC_VEX_XD";
521 else if ((index & ATTR_VEX) && (index & ATTR_XS))
522 o << "IC_VEX_XS";
Craig Topper113061d2011-08-25 07:42:00 +0000523 else if (index & ATTR_VEX)
524 o << "IC_VEX";
Sean Callanana21e2ea2011-03-15 01:23:15 +0000525 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
Sean Callanan8ed9f512009-12-19 02:59:52 +0000526 o << "IC_64BIT_REXW_XS";
527 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
528 o << "IC_64BIT_REXW_XD";
529 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
530 (index & ATTR_OPSIZE))
531 o << "IC_64BIT_REXW_OPSIZE";
Craig Toppere1b4a1a2011-10-01 19:54:56 +0000532 else if ((index & ATTR_64BIT) && (index & ATTR_XD) && (index & ATTR_OPSIZE))
533 o << "IC_64BIT_XD_OPSIZE";
Craig Topper29480fd2011-10-11 04:34:23 +0000534 else if ((index & ATTR_64BIT) && (index & ATTR_XS) && (index & ATTR_OPSIZE))
535 o << "IC_64BIT_XS_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000536 else if ((index & ATTR_64BIT) && (index & ATTR_XS))
537 o << "IC_64BIT_XS";
538 else if ((index & ATTR_64BIT) && (index & ATTR_XD))
539 o << "IC_64BIT_XD";
540 else if ((index & ATTR_64BIT) && (index & ATTR_OPSIZE))
541 o << "IC_64BIT_OPSIZE";
542 else if ((index & ATTR_64BIT) && (index & ATTR_REXW))
543 o << "IC_64BIT_REXW";
544 else if ((index & ATTR_64BIT))
545 o << "IC_64BIT";
Craig Topper29480fd2011-10-11 04:34:23 +0000546 else if ((index & ATTR_XS) && (index & ATTR_OPSIZE))
547 o << "IC_XS_OPSIZE";
Craig Toppere1b4a1a2011-10-01 19:54:56 +0000548 else if ((index & ATTR_XD) && (index & ATTR_OPSIZE))
549 o << "IC_XD_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000550 else if (index & ATTR_XS)
551 o << "IC_XS";
552 else if (index & ATTR_XD)
553 o << "IC_XD";
554 else if (index & ATTR_OPSIZE)
555 o << "IC_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000556 else
557 o << "IC";
558
559 if (index < 255)
560 o << ",";
561 else
562 o << " ";
563
564 o << " /* " << index << " */";
565
566 o << "\n";
567 }
568
569 i--;
570 o.indent(i * 2) << "};" << "\n";
571}
572
573void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
574 raw_ostream &o2,
575 uint32_t &i1,
576 uint32_t &i2)
577 const {
578 emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
579 emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
580 emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
581 emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR);
Joerg Sonnenberger4a8ac8d2011-04-04 16:58:13 +0000582 emitContextDecision(o1, o2, i1, i2, *Tables[4], THREEBYTEA6_STR);
583 emitContextDecision(o1, o2, i1, i2, *Tables[5], THREEBYTEA7_STR);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000584}
585
586void DisassemblerTables::emit(raw_ostream &o) const {
587 uint32_t i1 = 0;
588 uint32_t i2 = 0;
589
590 std::string s1;
591 std::string s2;
592
593 raw_string_ostream o1(s1);
594 raw_string_ostream o2(s2);
595
596 emitInstructionInfo(o, i2);
597 o << "\n";
598
599 emitContextTable(o, i2);
600 o << "\n";
601
602 emitEmptyTable(o1, i1);
603 emitContextDecisions(o1, o2, i1, i2);
604
605 o << o1.str();
606 o << "\n";
607 o << o2.str();
608 o << "\n";
609 o << "\n";
610}
611
612void DisassemblerTables::setTableFields(ModRMDecision &decision,
613 const ModRMFilter &filter,
614 InstrUID uid,
615 uint8_t opcode) {
616 unsigned index;
617
618 for (index = 0; index < 256; ++index) {
619 if (filter.accepts(index)) {
620 if (decision.instructionIDs[index] == uid)
621 continue;
622
623 if (decision.instructionIDs[index] != 0) {
624 InstructionSpecifier &newInfo =
625 InstructionSpecifiers[uid];
626 InstructionSpecifier &previousInfo =
627 InstructionSpecifiers[decision.instructionIDs[index]];
628
629 if(newInfo.filtered)
630 continue; // filtered instructions get lowest priority
631
Craig Topper842f58f2011-09-11 20:23:20 +0000632 if(previousInfo.name == "NOOP" && (newInfo.name == "XCHG16ar" ||
633 newInfo.name == "XCHG32ar" ||
Craig Topper25f6dfd2011-10-07 05:35:38 +0000634 newInfo.name == "XCHG32ar64" ||
Craig Topper842f58f2011-09-11 20:23:20 +0000635 newInfo.name == "XCHG64ar"))
636 continue; // special case for XCHG*ar and NOOP
Sean Callanan8ed9f512009-12-19 02:59:52 +0000637
638 if (outranks(previousInfo.insnContext, newInfo.insnContext))
639 continue;
640
641 if (previousInfo.insnContext == newInfo.insnContext &&
642 !previousInfo.filtered) {
643 errs() << "Error: Primary decode conflict: ";
644 errs() << newInfo.name << " would overwrite " << previousInfo.name;
645 errs() << "\n";
646 errs() << "ModRM " << index << "\n";
647 errs() << "Opcode " << (uint16_t)opcode << "\n";
648 errs() << "Context " << stringForContext(newInfo.insnContext) << "\n";
649 HasConflicts = true;
650 }
651 }
652
653 decision.instructionIDs[index] = uid;
654 }
655 }
656}
657
658void DisassemblerTables::setTableFields(OpcodeType type,
659 InstructionContext insnContext,
660 uint8_t opcode,
661 const ModRMFilter &filter,
Craig Topper4da632e2011-09-23 06:57:25 +0000662 InstrUID uid,
Craig Topper6744a172011-10-04 06:30:42 +0000663 bool is32bit,
664 bool ignoresVEX_L) {
Sean Callanan8ed9f512009-12-19 02:59:52 +0000665 unsigned index;
666
667 ContextDecision &decision = *Tables[type];
668
669 for (index = 0; index < IC_max; ++index) {
Craig Topper4da632e2011-09-23 06:57:25 +0000670 if (is32bit && inheritsFrom((InstructionContext)index, IC_64BIT))
671 continue;
672
Sean Callanan8ed9f512009-12-19 02:59:52 +0000673 if (inheritsFrom((InstructionContext)index,
Craig Topper6744a172011-10-04 06:30:42 +0000674 InstructionSpecifiers[uid].insnContext, ignoresVEX_L))
Sean Callanan8ed9f512009-12-19 02:59:52 +0000675 setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],
676 filter,
677 uid,
678 opcode);
679 }
680}