1
//===- X86DisassemblerTables.cpp - Disassembler tables ----------*- C++ -*-===//
3
// The LLVM Compiler Infrastructure
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
8
//===----------------------------------------------------------------------===//
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.
15
//===----------------------------------------------------------------------===//
17
#include "X86DisassemblerShared.h"
18
#include "X86DisassemblerTables.h"
20
#include "TableGenBackend.h"
21
#include "llvm/Support/ErrorHandling.h"
22
#include "llvm/Support/Format.h"
25
using namespace X86Disassembler;
27
/// inheritsFrom - Indicates whether all instructions in one class also belong
30
/// @param child - The class that may be the subset
31
/// @param parent - The class that may be the superset
32
/// @return - True if child is a subset of parent, false otherwise.
33
static inline bool inheritsFrom(InstructionContext child,
34
InstructionContext parent) {
42
return(inheritsFrom(child, IC_64BIT_REXW) ||
43
inheritsFrom(child, IC_64BIT_OPSIZE) ||
44
inheritsFrom(child, IC_64BIT_XD) ||
45
inheritsFrom(child, IC_64BIT_XS));
47
return(inheritsFrom(child, IC_64BIT_OPSIZE));
49
return(inheritsFrom(child, IC_64BIT_XD));
51
return(inheritsFrom(child, IC_64BIT_XS));
53
return(inheritsFrom(child, IC_64BIT_REXW_XS) ||
54
inheritsFrom(child, IC_64BIT_REXW_XD) ||
55
inheritsFrom(child, IC_64BIT_REXW_OPSIZE));
57
return(inheritsFrom(child, IC_64BIT_REXW_OPSIZE));
59
return(inheritsFrom(child, IC_64BIT_REXW_XD));
61
return(inheritsFrom(child, IC_64BIT_REXW_XS));
62
case IC_64BIT_REXW_XD:
64
case IC_64BIT_REXW_XS:
66
case IC_64BIT_REXW_OPSIZE:
73
/// outranks - Indicates whether, if an instruction has two different applicable
74
/// classes, which class should be preferred when performing decode. This
75
/// imposes a total ordering (ties are resolved toward "lower")
77
/// @param upper - The class that may be preferable
78
/// @param lower - The class that may be less preferable
79
/// @return - True if upper is to be preferred, false otherwise.
80
static inline bool outranks(InstructionContext upper,
81
InstructionContext lower) {
82
assert(upper < IC_max);
83
assert(lower < IC_max);
85
#define ENUM_ENTRY(n, r, d) r,
86
static int ranks[IC_max] = {
91
return (ranks[upper] > ranks[lower]);
94
/// stringForContext - Returns a string containing the name of a particular
95
/// InstructionContext, usually for diagnostic purposes.
97
/// @param insnContext - The instruction class to transform to a string.
98
/// @return - A statically-allocated string constant that contains the
99
/// name of the instruction class.
100
static inline const char* stringForContext(InstructionContext insnContext) {
101
switch (insnContext) {
103
llvm_unreachable("Unhandled instruction class");
104
#define ENUM_ENTRY(n, r, d) case n: return #n; break;
112
/// stringForOperandType - Like stringForContext, but for OperandTypes.
113
static inline const char* stringForOperandType(OperandType type) {
116
llvm_unreachable("Unhandled type");
117
#define ENUM_ENTRY(i, d) case i: return #i;
123
/// stringForOperandEncoding - like stringForContext, but for
124
/// OperandEncodings.
125
static inline const char* stringForOperandEncoding(OperandEncoding encoding) {
128
llvm_unreachable("Unhandled encoding");
129
#define ENUM_ENTRY(i, d) case i: return #i;
135
void DisassemblerTables::emitOneID(raw_ostream &o,
138
bool addComma) const {
140
o.indent(i * 2) << format("0x%hx", id);
142
o.indent(i * 2) << 0;
150
o << InstructionSpecifiers[id].name;
156
/// emitEmptyTable - Emits the modRMEmptyTable, which is used as a ID table by
157
/// all ModR/M decisions for instructions that are invalid for all possible
158
/// ModR/M byte values.
160
/// @param o - The output stream on which to emit the table.
161
/// @param i - The indentation level for that output stream.
162
static void emitEmptyTable(raw_ostream &o, uint32_t &i)
164
o.indent(i * 2) << "static InstrUID modRMEmptyTable[1] = { 0 };" << "\n";
168
/// getDecisionType - Determines whether a ModRM decision with 255 entries can
169
/// be compacted by eliminating redundant information.
171
/// @param decision - The decision to be compacted.
172
/// @return - The compactest available representation for the decision.
173
static ModRMDecisionType getDecisionType(ModRMDecision &decision)
175
bool satisfiesOneEntry = true;
176
bool satisfiesSplitRM = true;
180
for (index = 0; index < 256; ++index) {
181
if (decision.instructionIDs[index] != decision.instructionIDs[0])
182
satisfiesOneEntry = false;
184
if (((index & 0xc0) == 0xc0) &&
185
(decision.instructionIDs[index] != decision.instructionIDs[0xc0]))
186
satisfiesSplitRM = false;
188
if (((index & 0xc0) != 0xc0) &&
189
(decision.instructionIDs[index] != decision.instructionIDs[0x00]))
190
satisfiesSplitRM = false;
193
if (satisfiesOneEntry)
194
return MODRM_ONEENTRY;
196
if (satisfiesSplitRM)
197
return MODRM_SPLITRM;
202
/// stringForDecisionType - Returns a statically-allocated string corresponding
203
/// to a particular decision type.
205
/// @param dt - The decision type.
206
/// @return - A pointer to the statically-allocated string (e.g.,
207
/// "MODRM_ONEENTRY" for MODRM_ONEENTRY).
208
static const char* stringForDecisionType(ModRMDecisionType dt)
210
#define ENUM_ENTRY(n) case n: return #n;
213
llvm_unreachable("Unknown decision type");
219
/// stringForModifierType - Returns a statically-allocated string corresponding
220
/// to an opcode modifier type.
222
/// @param mt - The modifier type.
223
/// @return - A pointer to the statically-allocated string (e.g.,
224
/// "MODIFIER_NONE" for MODIFIER_NONE).
225
static const char* stringForModifierType(ModifierType mt)
227
#define ENUM_ENTRY(n) case n: return #n;
230
llvm_unreachable("Unknown modifier type");
236
DisassemblerTables::DisassemblerTables() {
239
for (i = 0; i < 4; i++) {
240
Tables[i] = new ContextDecision;
241
memset(Tables[i], 0, sizeof(ContextDecision));
244
HasConflicts = false;
247
DisassemblerTables::~DisassemblerTables() {
250
for (i = 0; i < 4; i++)
254
void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
258
ModRMDecision &decision)
260
static uint64_t sTableNumber = 0;
261
uint64_t thisTableNumber = sTableNumber;
262
ModRMDecisionType dt = getDecisionType(decision);
265
if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
267
o2.indent(i2) << "{ /* ModRMDecision */" << "\n";
270
o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
271
o2.indent(i2) << "modRMEmptyTable";
274
o2.indent(i2) << "}";
278
o1.indent(i1) << "static InstrUID modRMTable" << thisTableNumber;
282
llvm_unreachable("Unknown decision type");
294
o1 << " = {" << "\n";
299
llvm_unreachable("Unknown decision type");
301
emitOneID(o1, i1, decision.instructionIDs[0], false);
304
emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
305
emitOneID(o1, i1, decision.instructionIDs[0xc0], false); // mod = 0b11
308
for (index = 0; index < 256; ++index)
309
emitOneID(o1, i1, decision.instructionIDs[index], index < 255);
314
o1.indent(i1) << "};" << "\n";
317
o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
320
o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
321
o2.indent(i2) << "modRMTable" << sTableNumber << "\n";
324
o2.indent(i2) << "}";
329
void DisassemblerTables::emitOpcodeDecision(
334
OpcodeDecision &decision) const {
337
o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
339
o2.indent(i2) << "{" << "\n";
342
for (index = 0; index < 256; ++index) {
345
o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
347
emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]);
356
o2.indent(i2) << "}" << "\n";
358
o2.indent(i2) << "}" << "\n";
361
void DisassemblerTables::emitContextDecision(
366
ContextDecision &decision,
367
const char* name) const {
368
o2.indent(i2) << "struct ContextDecision " << name << " = {" << "\n";
370
o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
375
for (index = 0; index < IC_max; ++index) {
376
o2.indent(i2) << "/* ";
377
o2 << stringForContext((InstructionContext)index);
381
emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]);
383
if (index + 1 < IC_max)
388
o2.indent(i2) << "}" << "\n";
390
o2.indent(i2) << "};" << "\n";
393
void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
395
o.indent(i * 2) << "struct InstructionSpecifier ";
396
o << INSTRUCTIONS_STR << "[";
397
o << InstructionSpecifiers.size();
398
o << "] = {" << "\n";
402
uint16_t numInstructions = InstructionSpecifiers.size();
403
uint16_t index, operandIndex;
405
for (index = 0; index < numInstructions; ++index) {
406
o.indent(i * 2) << "{ /* " << index << " */" << "\n";
410
stringForModifierType(InstructionSpecifiers[index].modifierType);
413
o.indent(i * 2) << "0x";
414
o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
417
o.indent(i * 2) << "{" << "\n";
420
for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
421
o.indent(i * 2) << "{ ";
422
o << stringForOperandEncoding(InstructionSpecifiers[index]
423
.operands[operandIndex]
426
o << stringForOperandType(InstructionSpecifiers[index]
427
.operands[operandIndex]
431
if (operandIndex < X86_MAX_OPERANDS - 1)
438
o.indent(i * 2) << "}," << "\n";
440
o.indent(i * 2) << "\"" << InstructionSpecifiers[index].name << "\"";
444
o.indent(i * 2) << "}";
446
if (index + 1 < numInstructions)
453
o.indent(i * 2) << "};" << "\n";
456
void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
459
o.indent(i * 2) << "InstructionContext ";
460
o << CONTEXTS_STR << "[256] = {" << "\n";
463
for (index = 0; index < 256; ++index) {
466
if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
467
o << "IC_64BIT_REXW_XS";
468
else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
469
o << "IC_64BIT_REXW_XD";
470
else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
471
(index & ATTR_OPSIZE))
472
o << "IC_64BIT_REXW_OPSIZE";
473
else if ((index & ATTR_64BIT) && (index & ATTR_XS))
475
else if ((index & ATTR_64BIT) && (index & ATTR_XD))
477
else if ((index & ATTR_64BIT) && (index & ATTR_OPSIZE))
478
o << "IC_64BIT_OPSIZE";
479
else if ((index & ATTR_64BIT) && (index & ATTR_REXW))
480
o << "IC_64BIT_REXW";
481
else if ((index & ATTR_64BIT))
483
else if (index & ATTR_XS)
485
else if (index & ATTR_XD)
487
else if (index & ATTR_OPSIZE)
497
o << " /* " << index << " */";
503
o.indent(i * 2) << "};" << "\n";
506
void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
511
emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
512
emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
513
emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
514
emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR);
517
void DisassemblerTables::emit(raw_ostream &o) const {
524
raw_string_ostream o1(s1);
525
raw_string_ostream o2(s2);
527
emitInstructionInfo(o, i2);
530
emitContextTable(o, i2);
533
emitEmptyTable(o1, i1);
534
emitContextDecisions(o1, o2, i1, i2);
543
void DisassemblerTables::setTableFields(ModRMDecision &decision,
544
const ModRMFilter &filter,
549
for (index = 0; index < 256; ++index) {
550
if (filter.accepts(index)) {
551
if (decision.instructionIDs[index] == uid)
554
if (decision.instructionIDs[index] != 0) {
555
InstructionSpecifier &newInfo =
556
InstructionSpecifiers[uid];
557
InstructionSpecifier &previousInfo =
558
InstructionSpecifiers[decision.instructionIDs[index]];
561
continue; // filtered instructions get lowest priority
563
if(previousInfo.name == "NOOP")
564
continue; // special case for XCHG32ar and NOOP
566
if (outranks(previousInfo.insnContext, newInfo.insnContext))
569
if (previousInfo.insnContext == newInfo.insnContext &&
570
!previousInfo.filtered) {
571
errs() << "Error: Primary decode conflict: ";
572
errs() << newInfo.name << " would overwrite " << previousInfo.name;
574
errs() << "ModRM " << index << "\n";
575
errs() << "Opcode " << (uint16_t)opcode << "\n";
576
errs() << "Context " << stringForContext(newInfo.insnContext) << "\n";
581
decision.instructionIDs[index] = uid;
586
void DisassemblerTables::setTableFields(OpcodeType type,
587
InstructionContext insnContext,
589
const ModRMFilter &filter,
593
ContextDecision &decision = *Tables[type];
595
for (index = 0; index < IC_max; ++index) {
596
if (inheritsFrom((InstructionContext)index,
597
InstructionSpecifiers[uid].insnContext))
598
setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],