blob: 33cc017abaf36f5e1b7b2ff8ad5ed331b132eb2c [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 }
143}
144
145/// stringForOperandType - Like stringForContext, but for OperandTypes.
146static inline const char* stringForOperandType(OperandType type) {
147 switch (type) {
148 default:
149 llvm_unreachable("Unhandled type");
150#define ENUM_ENTRY(i, d) case i: return #i;
151 TYPES
152#undef ENUM_ENTRY
153 }
154}
155
156/// stringForOperandEncoding - like stringForContext, but for
157/// OperandEncodings.
158static inline const char* stringForOperandEncoding(OperandEncoding encoding) {
159 switch (encoding) {
160 default:
161 llvm_unreachable("Unhandled encoding");
162#define ENUM_ENTRY(i, d) case i: return #i;
163 ENCODINGS
164#undef ENUM_ENTRY
165 }
166}
167
168void DisassemblerTables::emitOneID(raw_ostream &o,
169 uint32_t &i,
170 InstrUID id,
171 bool addComma) const {
172 if (id)
173 o.indent(i * 2) << format("0x%hx", id);
174 else
175 o.indent(i * 2) << 0;
176
177 if (addComma)
178 o << ", ";
179 else
180 o << " ";
181
182 o << "/* ";
183 o << InstructionSpecifiers[id].name;
184 o << "*/";
185
186 o << "\n";
187}
188
189/// emitEmptyTable - Emits the modRMEmptyTable, which is used as a ID table by
190/// all ModR/M decisions for instructions that are invalid for all possible
191/// ModR/M byte values.
192///
193/// @param o - The output stream on which to emit the table.
194/// @param i - The indentation level for that output stream.
195static void emitEmptyTable(raw_ostream &o, uint32_t &i)
196{
Craig Topperce8f4c52012-02-09 07:45:30 +0000197 o.indent(i * 2) << "0x0, /* EmptyTable */\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000198}
199
200/// getDecisionType - Determines whether a ModRM decision with 255 entries can
201/// be compacted by eliminating redundant information.
202///
203/// @param decision - The decision to be compacted.
204/// @return - The compactest available representation for the decision.
205static ModRMDecisionType getDecisionType(ModRMDecision &decision)
206{
207 bool satisfiesOneEntry = true;
208 bool satisfiesSplitRM = true;
Craig Topperf41ab772012-02-09 08:58:07 +0000209 bool satisfiesSplitReg = true;
210
Sean Callanan8ed9f512009-12-19 02:59:52 +0000211 uint16_t index;
Craig Topperf41ab772012-02-09 08:58:07 +0000212
Sean Callanan8ed9f512009-12-19 02:59:52 +0000213 for (index = 0; index < 256; ++index) {
214 if (decision.instructionIDs[index] != decision.instructionIDs[0])
215 satisfiesOneEntry = false;
Craig Topperf41ab772012-02-09 08:58:07 +0000216
Sean Callanan8ed9f512009-12-19 02:59:52 +0000217 if (((index & 0xc0) == 0xc0) &&
218 (decision.instructionIDs[index] != decision.instructionIDs[0xc0]))
219 satisfiesSplitRM = false;
Craig Topperf41ab772012-02-09 08:58:07 +0000220
Sean Callanan8ed9f512009-12-19 02:59:52 +0000221 if (((index & 0xc0) != 0xc0) &&
222 (decision.instructionIDs[index] != decision.instructionIDs[0x00]))
223 satisfiesSplitRM = false;
Craig Topperf41ab772012-02-09 08:58:07 +0000224
225 if (((index & 0xc0) == 0xc0) &&
226 (decision.instructionIDs[index] != decision.instructionIDs[index&0xf8]))
227 satisfiesSplitReg = false;
228
229 if (((index & 0xc0) != 0xc0) &&
230 (decision.instructionIDs[index] != decision.instructionIDs[index&0x38]))
231 satisfiesSplitReg = false;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000232 }
Craig Topperf41ab772012-02-09 08:58:07 +0000233
Sean Callanan8ed9f512009-12-19 02:59:52 +0000234 if (satisfiesOneEntry)
235 return MODRM_ONEENTRY;
Craig Topperf41ab772012-02-09 08:58:07 +0000236
Sean Callanan8ed9f512009-12-19 02:59:52 +0000237 if (satisfiesSplitRM)
238 return MODRM_SPLITRM;
Craig Topperf41ab772012-02-09 08:58:07 +0000239
240 if (satisfiesSplitReg)
241 return MODRM_SPLITREG;
242
Sean Callanan8ed9f512009-12-19 02:59:52 +0000243 return MODRM_FULL;
244}
245
246/// stringForDecisionType - Returns a statically-allocated string corresponding
247/// to a particular decision type.
248///
249/// @param dt - The decision type.
250/// @return - A pointer to the statically-allocated string (e.g.,
251/// "MODRM_ONEENTRY" for MODRM_ONEENTRY).
252static const char* stringForDecisionType(ModRMDecisionType dt)
253{
254#define ENUM_ENTRY(n) case n: return #n;
255 switch (dt) {
256 default:
257 llvm_unreachable("Unknown decision type");
258 MODRMTYPES
259 };
260#undef ENUM_ENTRY
261}
262
263/// stringForModifierType - Returns a statically-allocated string corresponding
264/// to an opcode modifier type.
265///
266/// @param mt - The modifier type.
267/// @return - A pointer to the statically-allocated string (e.g.,
268/// "MODIFIER_NONE" for MODIFIER_NONE).
269static const char* stringForModifierType(ModifierType mt)
270{
271#define ENUM_ENTRY(n) case n: return #n;
272 switch(mt) {
273 default:
274 llvm_unreachable("Unknown modifier type");
275 MODIFIER_TYPES
276 };
277#undef ENUM_ENTRY
278}
279
280DisassemblerTables::DisassemblerTables() {
281 unsigned i;
282
Joerg Sonnenberger39d7cae2011-04-04 16:25:38 +0000283 for (i = 0; i < array_lengthof(Tables); i++) {
Sean Callanan8ed9f512009-12-19 02:59:52 +0000284 Tables[i] = new ContextDecision;
Daniel Dunbar87830872009-12-19 04:16:57 +0000285 memset(Tables[i], 0, sizeof(ContextDecision));
Sean Callanan8ed9f512009-12-19 02:59:52 +0000286 }
287
288 HasConflicts = false;
289}
290
291DisassemblerTables::~DisassemblerTables() {
292 unsigned i;
293
Joerg Sonnenberger39d7cae2011-04-04 16:25:38 +0000294 for (i = 0; i < array_lengthof(Tables); i++)
Sean Callanan8ed9f512009-12-19 02:59:52 +0000295 delete Tables[i];
296}
297
298void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
299 raw_ostream &o2,
300 uint32_t &i1,
301 uint32_t &i2,
302 ModRMDecision &decision)
303 const {
304 static uint64_t sTableNumber = 0;
Craig Topperce8f4c52012-02-09 07:45:30 +0000305 static uint64_t sEntryNumber = 1;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000306 ModRMDecisionType dt = getDecisionType(decision);
307 uint16_t index;
Craig Topperce8f4c52012-02-09 07:45:30 +0000308
Sean Callanan8ed9f512009-12-19 02:59:52 +0000309 if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
310 {
311 o2.indent(i2) << "{ /* ModRMDecision */" << "\n";
312 i2++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000313
Sean Callanan8ed9f512009-12-19 02:59:52 +0000314 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000315 o2.indent(i2) << 0 << " /* EmptyTable */\n";
316
Sean Callanan8ed9f512009-12-19 02:59:52 +0000317 i2--;
318 o2.indent(i2) << "}";
319 return;
320 }
Sean Callanan8ed9f512009-12-19 02:59:52 +0000321
Craig Topperce8f4c52012-02-09 07:45:30 +0000322 o1 << "/* Table" << sTableNumber << " */\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000323 i1++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000324
Sean Callanan8ed9f512009-12-19 02:59:52 +0000325 switch (dt) {
326 default:
327 llvm_unreachable("Unknown decision type");
328 case MODRM_ONEENTRY:
Craig Topperce8f4c52012-02-09 07:45:30 +0000329 emitOneID(o1, i1, decision.instructionIDs[0], true);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000330 break;
331 case MODRM_SPLITRM:
332 emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
Craig Topperce8f4c52012-02-09 07:45:30 +0000333 emitOneID(o1, i1, decision.instructionIDs[0xc0], true); // mod = 0b11
Sean Callanan8ed9f512009-12-19 02:59:52 +0000334 break;
Craig Topperf41ab772012-02-09 08:58:07 +0000335 case MODRM_SPLITREG:
336 for (index = 0; index < 64; index += 8)
337 emitOneID(o1, i1, decision.instructionIDs[index], true);
338 for (index = 0xc0; index < 256; index += 8)
339 emitOneID(o1, i1, decision.instructionIDs[index], true);
340 break;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000341 case MODRM_FULL:
342 for (index = 0; index < 256; ++index)
Craig Topperce8f4c52012-02-09 07:45:30 +0000343 emitOneID(o1, i1, decision.instructionIDs[index], true);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000344 break;
345 }
Craig Topperce8f4c52012-02-09 07:45:30 +0000346
Sean Callanan8ed9f512009-12-19 02:59:52 +0000347 i1--;
Craig Topperce8f4c52012-02-09 07:45:30 +0000348
Sean Callanan8ed9f512009-12-19 02:59:52 +0000349 o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
350 i2++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000351
Sean Callanan8ed9f512009-12-19 02:59:52 +0000352 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000353 o2.indent(i2) << sEntryNumber << " /* Table" << sTableNumber << " */\n";
354
Sean Callanan8ed9f512009-12-19 02:59:52 +0000355 i2--;
356 o2.indent(i2) << "}";
Craig Topperce8f4c52012-02-09 07:45:30 +0000357
358 switch (dt) {
359 default:
360 llvm_unreachable("Unknown decision type");
361 case MODRM_ONEENTRY:
362 sEntryNumber += 1;
363 break;
364 case MODRM_SPLITRM:
365 sEntryNumber += 2;
366 break;
Craig Topperf41ab772012-02-09 08:58:07 +0000367 case MODRM_SPLITREG:
368 sEntryNumber += 16;
369 break;
Craig Topperce8f4c52012-02-09 07:45:30 +0000370 case MODRM_FULL:
371 sEntryNumber += 256;
372 break;
373 }
374
Sean Callanan8ed9f512009-12-19 02:59:52 +0000375 ++sTableNumber;
376}
377
378void DisassemblerTables::emitOpcodeDecision(
379 raw_ostream &o1,
380 raw_ostream &o2,
381 uint32_t &i1,
382 uint32_t &i2,
383 OpcodeDecision &decision) const {
384 uint16_t index;
385
386 o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
387 i2++;
388 o2.indent(i2) << "{" << "\n";
389 i2++;
390
391 for (index = 0; index < 256; ++index) {
392 o2.indent(i2);
393
394 o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
395
396 emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]);
397
398 if (index < 255)
399 o2 << ",";
400
401 o2 << "\n";
402 }
403
404 i2--;
405 o2.indent(i2) << "}" << "\n";
406 i2--;
407 o2.indent(i2) << "}" << "\n";
408}
409
410void DisassemblerTables::emitContextDecision(
411 raw_ostream &o1,
412 raw_ostream &o2,
413 uint32_t &i1,
414 uint32_t &i2,
415 ContextDecision &decision,
416 const char* name) const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000417 o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000418 i2++;
419 o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
420 i2++;
421
422 unsigned index;
423
424 for (index = 0; index < IC_max; ++index) {
425 o2.indent(i2) << "/* ";
426 o2 << stringForContext((InstructionContext)index);
427 o2 << " */";
428 o2 << "\n";
429
430 emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]);
431
432 if (index + 1 < IC_max)
433 o2 << ", ";
434 }
435
436 i2--;
437 o2.indent(i2) << "}" << "\n";
438 i2--;
439 o2.indent(i2) << "};" << "\n";
440}
441
442void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
443 const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000444 o.indent(i * 2) << "static const struct InstructionSpecifier ";
445 o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000446
447 i++;
448
449 uint16_t numInstructions = InstructionSpecifiers.size();
450 uint16_t index, operandIndex;
451
452 for (index = 0; index < numInstructions; ++index) {
453 o.indent(i * 2) << "{ /* " << index << " */" << "\n";
454 i++;
455
456 o.indent(i * 2) <<
457 stringForModifierType(InstructionSpecifiers[index].modifierType);
458 o << "," << "\n";
459
460 o.indent(i * 2) << "0x";
461 o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
462 o << "," << "\n";
463
464 o.indent(i * 2) << "{" << "\n";
465 i++;
466
467 for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
468 o.indent(i * 2) << "{ ";
469 o << stringForOperandEncoding(InstructionSpecifiers[index]
470 .operands[operandIndex]
471 .encoding);
472 o << ", ";
473 o << stringForOperandType(InstructionSpecifiers[index]
474 .operands[operandIndex]
475 .type);
476 o << " }";
477
478 if (operandIndex < X86_MAX_OPERANDS - 1)
479 o << ",";
480
481 o << "\n";
482 }
483
484 i--;
485 o.indent(i * 2) << "}," << "\n";
486
Benjamin Kramer953362c2012-02-11 14:50:54 +0000487 o.indent(i * 2) << "/* " << InstructionSpecifiers[index].name << " */";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000488 o << "\n";
489
490 i--;
491 o.indent(i * 2) << "}";
492
493 if (index + 1 < numInstructions)
494 o << ",";
495
496 o << "\n";
497 }
498
499 i--;
500 o.indent(i * 2) << "};" << "\n";
501}
502
503void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
504 uint16_t index;
505
Benjamin Kramer86c69c52010-10-23 09:28:42 +0000506 o.indent(i * 2) << "static const InstructionContext " CONTEXTS_STR
507 "[256] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000508 i++;
509
510 for (index = 0; index < 256; ++index) {
511 o.indent(i * 2);
512
Craig Topperc8eb8802011-11-06 23:04:08 +0000513 if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
514 o << "IC_VEX_L_W_OPSIZE";
515 else if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE))
Sean Callanana21e2ea2011-03-15 01:23:15 +0000516 o << "IC_VEX_L_OPSIZE";
517 else if ((index & ATTR_VEXL) && (index & ATTR_XD))
518 o << "IC_VEX_L_XD";
519 else if ((index & ATTR_VEXL) && (index & ATTR_XS))
520 o << "IC_VEX_L_XS";
521 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
522 o << "IC_VEX_W_OPSIZE";
523 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XD))
524 o << "IC_VEX_W_XD";
525 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XS))
526 o << "IC_VEX_W_XS";
527 else if (index & ATTR_VEXL)
528 o << "IC_VEX_L";
529 else if ((index & ATTR_VEX) && (index & ATTR_REXW))
530 o << "IC_VEX_W";
531 else if ((index & ATTR_VEX) && (index & ATTR_OPSIZE))
532 o << "IC_VEX_OPSIZE";
533 else if ((index & ATTR_VEX) && (index & ATTR_XD))
534 o << "IC_VEX_XD";
535 else if ((index & ATTR_VEX) && (index & ATTR_XS))
536 o << "IC_VEX_XS";
Craig Topper113061d2011-08-25 07:42:00 +0000537 else if (index & ATTR_VEX)
538 o << "IC_VEX";
Sean Callanana21e2ea2011-03-15 01:23:15 +0000539 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
Sean Callanan8ed9f512009-12-19 02:59:52 +0000540 o << "IC_64BIT_REXW_XS";
541 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
542 o << "IC_64BIT_REXW_XD";
543 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
544 (index & ATTR_OPSIZE))
545 o << "IC_64BIT_REXW_OPSIZE";
Craig Toppere1b4a1a2011-10-01 19:54:56 +0000546 else if ((index & ATTR_64BIT) && (index & ATTR_XD) && (index & ATTR_OPSIZE))
547 o << "IC_64BIT_XD_OPSIZE";
Craig Topper29480fd2011-10-11 04:34:23 +0000548 else if ((index & ATTR_64BIT) && (index & ATTR_XS) && (index & ATTR_OPSIZE))
549 o << "IC_64BIT_XS_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000550 else if ((index & ATTR_64BIT) && (index & ATTR_XS))
551 o << "IC_64BIT_XS";
552 else if ((index & ATTR_64BIT) && (index & ATTR_XD))
553 o << "IC_64BIT_XD";
554 else if ((index & ATTR_64BIT) && (index & ATTR_OPSIZE))
555 o << "IC_64BIT_OPSIZE";
556 else if ((index & ATTR_64BIT) && (index & ATTR_REXW))
557 o << "IC_64BIT_REXW";
558 else if ((index & ATTR_64BIT))
559 o << "IC_64BIT";
Craig Topper29480fd2011-10-11 04:34:23 +0000560 else if ((index & ATTR_XS) && (index & ATTR_OPSIZE))
561 o << "IC_XS_OPSIZE";
Craig Toppere1b4a1a2011-10-01 19:54:56 +0000562 else if ((index & ATTR_XD) && (index & ATTR_OPSIZE))
563 o << "IC_XD_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000564 else if (index & ATTR_XS)
565 o << "IC_XS";
566 else if (index & ATTR_XD)
567 o << "IC_XD";
568 else if (index & ATTR_OPSIZE)
569 o << "IC_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000570 else
571 o << "IC";
572
573 if (index < 255)
574 o << ",";
575 else
576 o << " ";
577
578 o << " /* " << index << " */";
579
580 o << "\n";
581 }
582
583 i--;
584 o.indent(i * 2) << "};" << "\n";
585}
586
587void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
588 raw_ostream &o2,
589 uint32_t &i1,
590 uint32_t &i2)
591 const {
592 emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
593 emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
594 emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
595 emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR);
Joerg Sonnenberger4a8ac8d2011-04-04 16:58:13 +0000596 emitContextDecision(o1, o2, i1, i2, *Tables[4], THREEBYTEA6_STR);
597 emitContextDecision(o1, o2, i1, i2, *Tables[5], THREEBYTEA7_STR);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000598}
599
600void DisassemblerTables::emit(raw_ostream &o) const {
601 uint32_t i1 = 0;
602 uint32_t i2 = 0;
603
604 std::string s1;
605 std::string s2;
606
607 raw_string_ostream o1(s1);
608 raw_string_ostream o2(s2);
609
610 emitInstructionInfo(o, i2);
611 o << "\n";
612
613 emitContextTable(o, i2);
614 o << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000615
616 o << "static const InstrUID modRMTable[] = {\n";
617 i1++;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000618 emitEmptyTable(o1, i1);
Craig Topperce8f4c52012-02-09 07:45:30 +0000619 i1--;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000620 emitContextDecisions(o1, o2, i1, i2);
Craig Topperce8f4c52012-02-09 07:45:30 +0000621
Sean Callanan8ed9f512009-12-19 02:59:52 +0000622 o << o1.str();
Craig Topperce8f4c52012-02-09 07:45:30 +0000623 o << " 0x0\n";
624 o << "};\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000625 o << "\n";
626 o << o2.str();
627 o << "\n";
628 o << "\n";
629}
630
631void DisassemblerTables::setTableFields(ModRMDecision &decision,
632 const ModRMFilter &filter,
633 InstrUID uid,
634 uint8_t opcode) {
635 unsigned index;
636
637 for (index = 0; index < 256; ++index) {
638 if (filter.accepts(index)) {
639 if (decision.instructionIDs[index] == uid)
640 continue;
641
642 if (decision.instructionIDs[index] != 0) {
643 InstructionSpecifier &newInfo =
644 InstructionSpecifiers[uid];
645 InstructionSpecifier &previousInfo =
646 InstructionSpecifiers[decision.instructionIDs[index]];
647
648 if(newInfo.filtered)
649 continue; // filtered instructions get lowest priority
650
Craig Topper842f58f2011-09-11 20:23:20 +0000651 if(previousInfo.name == "NOOP" && (newInfo.name == "XCHG16ar" ||
652 newInfo.name == "XCHG32ar" ||
Craig Topper25f6dfd2011-10-07 05:35:38 +0000653 newInfo.name == "XCHG32ar64" ||
Craig Topper842f58f2011-09-11 20:23:20 +0000654 newInfo.name == "XCHG64ar"))
655 continue; // special case for XCHG*ar and NOOP
Sean Callanan8ed9f512009-12-19 02:59:52 +0000656
657 if (outranks(previousInfo.insnContext, newInfo.insnContext))
658 continue;
659
660 if (previousInfo.insnContext == newInfo.insnContext &&
661 !previousInfo.filtered) {
662 errs() << "Error: Primary decode conflict: ";
663 errs() << newInfo.name << " would overwrite " << previousInfo.name;
664 errs() << "\n";
665 errs() << "ModRM " << index << "\n";
666 errs() << "Opcode " << (uint16_t)opcode << "\n";
667 errs() << "Context " << stringForContext(newInfo.insnContext) << "\n";
668 HasConflicts = true;
669 }
670 }
671
672 decision.instructionIDs[index] = uid;
673 }
674 }
675}
676
677void DisassemblerTables::setTableFields(OpcodeType type,
678 InstructionContext insnContext,
679 uint8_t opcode,
680 const ModRMFilter &filter,
Craig Topper4da632e2011-09-23 06:57:25 +0000681 InstrUID uid,
Craig Topper6744a172011-10-04 06:30:42 +0000682 bool is32bit,
683 bool ignoresVEX_L) {
Sean Callanan8ed9f512009-12-19 02:59:52 +0000684 unsigned index;
685
686 ContextDecision &decision = *Tables[type];
687
688 for (index = 0; index < IC_max; ++index) {
Craig Topper4da632e2011-09-23 06:57:25 +0000689 if (is32bit && inheritsFrom((InstructionContext)index, IC_64BIT))
690 continue;
691
Sean Callanan8ed9f512009-12-19 02:59:52 +0000692 if (inheritsFrom((InstructionContext)index,
Craig Topper6744a172011-10-04 06:30:42 +0000693 InstructionSpecifiers[uid].insnContext, ignoresVEX_L))
Sean Callanan8ed9f512009-12-19 02:59:52 +0000694 setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],
695 filter,
696 uid,
697 opcode);
698 }
699}