blob: 7db39b8481d631413bbf510f88414585aee2bf65 [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{
Craig Topperce8f4c52012-02-09 07:45:30 +0000199 o.indent(i * 2) << "0x0, /* EmptyTable */\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000200}
201
202/// getDecisionType - Determines whether a ModRM decision with 255 entries can
203/// be compacted by eliminating redundant information.
204///
205/// @param decision - The decision to be compacted.
206/// @return - The compactest available representation for the decision.
207static ModRMDecisionType getDecisionType(ModRMDecision &decision)
208{
209 bool satisfiesOneEntry = true;
210 bool satisfiesSplitRM = true;
211
212 uint16_t index;
213
214 for (index = 0; index < 256; ++index) {
215 if (decision.instructionIDs[index] != decision.instructionIDs[0])
216 satisfiesOneEntry = false;
217
218 if (((index & 0xc0) == 0xc0) &&
219 (decision.instructionIDs[index] != decision.instructionIDs[0xc0]))
220 satisfiesSplitRM = false;
221
222 if (((index & 0xc0) != 0xc0) &&
223 (decision.instructionIDs[index] != decision.instructionIDs[0x00]))
224 satisfiesSplitRM = false;
225 }
226
227 if (satisfiesOneEntry)
228 return MODRM_ONEENTRY;
229
230 if (satisfiesSplitRM)
231 return MODRM_SPLITRM;
232
233 return MODRM_FULL;
234}
235
236/// stringForDecisionType - Returns a statically-allocated string corresponding
237/// to a particular decision type.
238///
239/// @param dt - The decision type.
240/// @return - A pointer to the statically-allocated string (e.g.,
241/// "MODRM_ONEENTRY" for MODRM_ONEENTRY).
242static const char* stringForDecisionType(ModRMDecisionType dt)
243{
244#define ENUM_ENTRY(n) case n: return #n;
245 switch (dt) {
246 default:
247 llvm_unreachable("Unknown decision type");
248 MODRMTYPES
249 };
250#undef ENUM_ENTRY
251}
252
253/// stringForModifierType - Returns a statically-allocated string corresponding
254/// to an opcode modifier type.
255///
256/// @param mt - The modifier type.
257/// @return - A pointer to the statically-allocated string (e.g.,
258/// "MODIFIER_NONE" for MODIFIER_NONE).
259static const char* stringForModifierType(ModifierType mt)
260{
261#define ENUM_ENTRY(n) case n: return #n;
262 switch(mt) {
263 default:
264 llvm_unreachable("Unknown modifier type");
265 MODIFIER_TYPES
266 };
267#undef ENUM_ENTRY
268}
269
270DisassemblerTables::DisassemblerTables() {
271 unsigned i;
272
Joerg Sonnenberger39d7cae2011-04-04 16:25:38 +0000273 for (i = 0; i < array_lengthof(Tables); i++) {
Sean Callanan8ed9f512009-12-19 02:59:52 +0000274 Tables[i] = new ContextDecision;
Daniel Dunbar87830872009-12-19 04:16:57 +0000275 memset(Tables[i], 0, sizeof(ContextDecision));
Sean Callanan8ed9f512009-12-19 02:59:52 +0000276 }
277
278 HasConflicts = false;
279}
280
281DisassemblerTables::~DisassemblerTables() {
282 unsigned i;
283
Joerg Sonnenberger39d7cae2011-04-04 16:25:38 +0000284 for (i = 0; i < array_lengthof(Tables); i++)
Sean Callanan8ed9f512009-12-19 02:59:52 +0000285 delete Tables[i];
286}
287
288void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
289 raw_ostream &o2,
290 uint32_t &i1,
291 uint32_t &i2,
292 ModRMDecision &decision)
293 const {
294 static uint64_t sTableNumber = 0;
Craig Topperce8f4c52012-02-09 07:45:30 +0000295 static uint64_t sEntryNumber = 1;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000296 ModRMDecisionType dt = getDecisionType(decision);
297 uint16_t index;
Craig Topperce8f4c52012-02-09 07:45:30 +0000298
Sean Callanan8ed9f512009-12-19 02:59:52 +0000299 if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
300 {
301 o2.indent(i2) << "{ /* ModRMDecision */" << "\n";
302 i2++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000303
Sean Callanan8ed9f512009-12-19 02:59:52 +0000304 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000305 o2.indent(i2) << 0 << " /* EmptyTable */\n";
306
Sean Callanan8ed9f512009-12-19 02:59:52 +0000307 i2--;
308 o2.indent(i2) << "}";
309 return;
310 }
Sean Callanan8ed9f512009-12-19 02:59:52 +0000311
Craig Topperce8f4c52012-02-09 07:45:30 +0000312 o1 << "/* Table" << sTableNumber << " */\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000313 i1++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000314
Sean Callanan8ed9f512009-12-19 02:59:52 +0000315 switch (dt) {
316 default:
317 llvm_unreachable("Unknown decision type");
318 case MODRM_ONEENTRY:
Craig Topperce8f4c52012-02-09 07:45:30 +0000319 emitOneID(o1, i1, decision.instructionIDs[0], true);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000320 break;
321 case MODRM_SPLITRM:
322 emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
Craig Topperce8f4c52012-02-09 07:45:30 +0000323 emitOneID(o1, i1, decision.instructionIDs[0xc0], true); // mod = 0b11
Sean Callanan8ed9f512009-12-19 02:59:52 +0000324 break;
325 case MODRM_FULL:
326 for (index = 0; index < 256; ++index)
Craig Topperce8f4c52012-02-09 07:45:30 +0000327 emitOneID(o1, i1, decision.instructionIDs[index], true);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000328 break;
329 }
Craig Topperce8f4c52012-02-09 07:45:30 +0000330
Sean Callanan8ed9f512009-12-19 02:59:52 +0000331 i1--;
Craig Topperce8f4c52012-02-09 07:45:30 +0000332
Sean Callanan8ed9f512009-12-19 02:59:52 +0000333 o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
334 i2++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000335
Sean Callanan8ed9f512009-12-19 02:59:52 +0000336 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000337 o2.indent(i2) << sEntryNumber << " /* Table" << sTableNumber << " */\n";
338
Sean Callanan8ed9f512009-12-19 02:59:52 +0000339 i2--;
340 o2.indent(i2) << "}";
Craig Topperce8f4c52012-02-09 07:45:30 +0000341
342 switch (dt) {
343 default:
344 llvm_unreachable("Unknown decision type");
345 case MODRM_ONEENTRY:
346 sEntryNumber += 1;
347 break;
348 case MODRM_SPLITRM:
349 sEntryNumber += 2;
350 break;
351 case MODRM_FULL:
352 sEntryNumber += 256;
353 break;
354 }
355
Sean Callanan8ed9f512009-12-19 02:59:52 +0000356 ++sTableNumber;
357}
358
359void DisassemblerTables::emitOpcodeDecision(
360 raw_ostream &o1,
361 raw_ostream &o2,
362 uint32_t &i1,
363 uint32_t &i2,
364 OpcodeDecision &decision) const {
365 uint16_t index;
366
367 o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
368 i2++;
369 o2.indent(i2) << "{" << "\n";
370 i2++;
371
372 for (index = 0; index < 256; ++index) {
373 o2.indent(i2);
374
375 o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
376
377 emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]);
378
379 if (index < 255)
380 o2 << ",";
381
382 o2 << "\n";
383 }
384
385 i2--;
386 o2.indent(i2) << "}" << "\n";
387 i2--;
388 o2.indent(i2) << "}" << "\n";
389}
390
391void DisassemblerTables::emitContextDecision(
392 raw_ostream &o1,
393 raw_ostream &o2,
394 uint32_t &i1,
395 uint32_t &i2,
396 ContextDecision &decision,
397 const char* name) const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000398 o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000399 i2++;
400 o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
401 i2++;
402
403 unsigned index;
404
405 for (index = 0; index < IC_max; ++index) {
406 o2.indent(i2) << "/* ";
407 o2 << stringForContext((InstructionContext)index);
408 o2 << " */";
409 o2 << "\n";
410
411 emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]);
412
413 if (index + 1 < IC_max)
414 o2 << ", ";
415 }
416
417 i2--;
418 o2.indent(i2) << "}" << "\n";
419 i2--;
420 o2.indent(i2) << "};" << "\n";
421}
422
423void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
424 const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000425 o.indent(i * 2) << "static const struct InstructionSpecifier ";
426 o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000427
428 i++;
429
430 uint16_t numInstructions = InstructionSpecifiers.size();
431 uint16_t index, operandIndex;
432
433 for (index = 0; index < numInstructions; ++index) {
434 o.indent(i * 2) << "{ /* " << index << " */" << "\n";
435 i++;
436
437 o.indent(i * 2) <<
438 stringForModifierType(InstructionSpecifiers[index].modifierType);
439 o << "," << "\n";
440
441 o.indent(i * 2) << "0x";
442 o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
443 o << "," << "\n";
444
445 o.indent(i * 2) << "{" << "\n";
446 i++;
447
448 for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
449 o.indent(i * 2) << "{ ";
450 o << stringForOperandEncoding(InstructionSpecifiers[index]
451 .operands[operandIndex]
452 .encoding);
453 o << ", ";
454 o << stringForOperandType(InstructionSpecifiers[index]
455 .operands[operandIndex]
456 .type);
457 o << " }";
458
459 if (operandIndex < X86_MAX_OPERANDS - 1)
460 o << ",";
461
462 o << "\n";
463 }
464
465 i--;
466 o.indent(i * 2) << "}," << "\n";
467
468 o.indent(i * 2) << "\"" << InstructionSpecifiers[index].name << "\"";
469 o << "\n";
470
471 i--;
472 o.indent(i * 2) << "}";
473
474 if (index + 1 < numInstructions)
475 o << ",";
476
477 o << "\n";
478 }
479
480 i--;
481 o.indent(i * 2) << "};" << "\n";
482}
483
484void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
485 uint16_t index;
486
Benjamin Kramer86c69c52010-10-23 09:28:42 +0000487 o.indent(i * 2) << "static const InstructionContext " CONTEXTS_STR
488 "[256] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000489 i++;
490
491 for (index = 0; index < 256; ++index) {
492 o.indent(i * 2);
493
Craig Topperc8eb8802011-11-06 23:04:08 +0000494 if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
495 o << "IC_VEX_L_W_OPSIZE";
496 else if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE))
Sean Callanana21e2ea2011-03-15 01:23:15 +0000497 o << "IC_VEX_L_OPSIZE";
498 else if ((index & ATTR_VEXL) && (index & ATTR_XD))
499 o << "IC_VEX_L_XD";
500 else if ((index & ATTR_VEXL) && (index & ATTR_XS))
501 o << "IC_VEX_L_XS";
502 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
503 o << "IC_VEX_W_OPSIZE";
504 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XD))
505 o << "IC_VEX_W_XD";
506 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XS))
507 o << "IC_VEX_W_XS";
508 else if (index & ATTR_VEXL)
509 o << "IC_VEX_L";
510 else if ((index & ATTR_VEX) && (index & ATTR_REXW))
511 o << "IC_VEX_W";
512 else if ((index & ATTR_VEX) && (index & ATTR_OPSIZE))
513 o << "IC_VEX_OPSIZE";
514 else if ((index & ATTR_VEX) && (index & ATTR_XD))
515 o << "IC_VEX_XD";
516 else if ((index & ATTR_VEX) && (index & ATTR_XS))
517 o << "IC_VEX_XS";
Craig Topper113061d2011-08-25 07:42:00 +0000518 else if (index & ATTR_VEX)
519 o << "IC_VEX";
Sean Callanana21e2ea2011-03-15 01:23:15 +0000520 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
Sean Callanan8ed9f512009-12-19 02:59:52 +0000521 o << "IC_64BIT_REXW_XS";
522 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
523 o << "IC_64BIT_REXW_XD";
524 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
525 (index & ATTR_OPSIZE))
526 o << "IC_64BIT_REXW_OPSIZE";
Craig Toppere1b4a1a2011-10-01 19:54:56 +0000527 else if ((index & ATTR_64BIT) && (index & ATTR_XD) && (index & ATTR_OPSIZE))
528 o << "IC_64BIT_XD_OPSIZE";
Craig Topper29480fd2011-10-11 04:34:23 +0000529 else if ((index & ATTR_64BIT) && (index & ATTR_XS) && (index & ATTR_OPSIZE))
530 o << "IC_64BIT_XS_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000531 else if ((index & ATTR_64BIT) && (index & ATTR_XS))
532 o << "IC_64BIT_XS";
533 else if ((index & ATTR_64BIT) && (index & ATTR_XD))
534 o << "IC_64BIT_XD";
535 else if ((index & ATTR_64BIT) && (index & ATTR_OPSIZE))
536 o << "IC_64BIT_OPSIZE";
537 else if ((index & ATTR_64BIT) && (index & ATTR_REXW))
538 o << "IC_64BIT_REXW";
539 else if ((index & ATTR_64BIT))
540 o << "IC_64BIT";
Craig Topper29480fd2011-10-11 04:34:23 +0000541 else if ((index & ATTR_XS) && (index & ATTR_OPSIZE))
542 o << "IC_XS_OPSIZE";
Craig Toppere1b4a1a2011-10-01 19:54:56 +0000543 else if ((index & ATTR_XD) && (index & ATTR_OPSIZE))
544 o << "IC_XD_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000545 else if (index & ATTR_XS)
546 o << "IC_XS";
547 else if (index & ATTR_XD)
548 o << "IC_XD";
549 else if (index & ATTR_OPSIZE)
550 o << "IC_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000551 else
552 o << "IC";
553
554 if (index < 255)
555 o << ",";
556 else
557 o << " ";
558
559 o << " /* " << index << " */";
560
561 o << "\n";
562 }
563
564 i--;
565 o.indent(i * 2) << "};" << "\n";
566}
567
568void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
569 raw_ostream &o2,
570 uint32_t &i1,
571 uint32_t &i2)
572 const {
573 emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
574 emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
575 emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
576 emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR);
Joerg Sonnenberger4a8ac8d2011-04-04 16:58:13 +0000577 emitContextDecision(o1, o2, i1, i2, *Tables[4], THREEBYTEA6_STR);
578 emitContextDecision(o1, o2, i1, i2, *Tables[5], THREEBYTEA7_STR);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000579}
580
581void DisassemblerTables::emit(raw_ostream &o) const {
582 uint32_t i1 = 0;
583 uint32_t i2 = 0;
584
585 std::string s1;
586 std::string s2;
587
588 raw_string_ostream o1(s1);
589 raw_string_ostream o2(s2);
590
591 emitInstructionInfo(o, i2);
592 o << "\n";
593
594 emitContextTable(o, i2);
595 o << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000596
597 o << "static const InstrUID modRMTable[] = {\n";
598 i1++;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000599 emitEmptyTable(o1, i1);
Craig Topperce8f4c52012-02-09 07:45:30 +0000600 i1--;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000601 emitContextDecisions(o1, o2, i1, i2);
Craig Topperce8f4c52012-02-09 07:45:30 +0000602
Sean Callanan8ed9f512009-12-19 02:59:52 +0000603 o << o1.str();
Craig Topperce8f4c52012-02-09 07:45:30 +0000604 o << " 0x0\n";
605 o << "};\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000606 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}