blob: b5f970d3548cfe4df94ec427ec5ef19044e006dc [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;
Craig Topperf41ab772012-02-09 08:58:07 +0000211 bool satisfiesSplitReg = true;
212
Sean Callanan8ed9f512009-12-19 02:59:52 +0000213 uint16_t index;
Craig Topperf41ab772012-02-09 08:58:07 +0000214
Sean Callanan8ed9f512009-12-19 02:59:52 +0000215 for (index = 0; index < 256; ++index) {
216 if (decision.instructionIDs[index] != decision.instructionIDs[0])
217 satisfiesOneEntry = false;
Craig Topperf41ab772012-02-09 08:58:07 +0000218
Sean Callanan8ed9f512009-12-19 02:59:52 +0000219 if (((index & 0xc0) == 0xc0) &&
220 (decision.instructionIDs[index] != decision.instructionIDs[0xc0]))
221 satisfiesSplitRM = false;
Craig Topperf41ab772012-02-09 08:58:07 +0000222
Sean Callanan8ed9f512009-12-19 02:59:52 +0000223 if (((index & 0xc0) != 0xc0) &&
224 (decision.instructionIDs[index] != decision.instructionIDs[0x00]))
225 satisfiesSplitRM = false;
Craig Topperf41ab772012-02-09 08:58:07 +0000226
227 if (((index & 0xc0) == 0xc0) &&
228 (decision.instructionIDs[index] != decision.instructionIDs[index&0xf8]))
229 satisfiesSplitReg = false;
230
231 if (((index & 0xc0) != 0xc0) &&
232 (decision.instructionIDs[index] != decision.instructionIDs[index&0x38]))
233 satisfiesSplitReg = false;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000234 }
Craig Topperf41ab772012-02-09 08:58:07 +0000235
Sean Callanan8ed9f512009-12-19 02:59:52 +0000236 if (satisfiesOneEntry)
237 return MODRM_ONEENTRY;
Craig Topperf41ab772012-02-09 08:58:07 +0000238
Sean Callanan8ed9f512009-12-19 02:59:52 +0000239 if (satisfiesSplitRM)
240 return MODRM_SPLITRM;
Craig Topperf41ab772012-02-09 08:58:07 +0000241
242 if (satisfiesSplitReg)
243 return MODRM_SPLITREG;
244
Sean Callanan8ed9f512009-12-19 02:59:52 +0000245 return MODRM_FULL;
246}
247
248/// stringForDecisionType - Returns a statically-allocated string corresponding
249/// to a particular decision type.
250///
251/// @param dt - The decision type.
252/// @return - A pointer to the statically-allocated string (e.g.,
253/// "MODRM_ONEENTRY" for MODRM_ONEENTRY).
254static const char* stringForDecisionType(ModRMDecisionType dt)
255{
256#define ENUM_ENTRY(n) case n: return #n;
257 switch (dt) {
258 default:
259 llvm_unreachable("Unknown decision type");
260 MODRMTYPES
261 };
262#undef ENUM_ENTRY
263}
264
265/// stringForModifierType - Returns a statically-allocated string corresponding
266/// to an opcode modifier type.
267///
268/// @param mt - The modifier type.
269/// @return - A pointer to the statically-allocated string (e.g.,
270/// "MODIFIER_NONE" for MODIFIER_NONE).
271static const char* stringForModifierType(ModifierType mt)
272{
273#define ENUM_ENTRY(n) case n: return #n;
274 switch(mt) {
275 default:
276 llvm_unreachable("Unknown modifier type");
277 MODIFIER_TYPES
278 };
279#undef ENUM_ENTRY
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 Tables[i] = new ContextDecision;
Daniel Dunbar87830872009-12-19 04:16:57 +0000287 memset(Tables[i], 0, sizeof(ContextDecision));
Sean Callanan8ed9f512009-12-19 02:59:52 +0000288 }
289
290 HasConflicts = false;
291}
292
293DisassemblerTables::~DisassemblerTables() {
294 unsigned i;
295
Joerg Sonnenberger39d7cae2011-04-04 16:25:38 +0000296 for (i = 0; i < array_lengthof(Tables); i++)
Sean Callanan8ed9f512009-12-19 02:59:52 +0000297 delete Tables[i];
298}
299
300void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
301 raw_ostream &o2,
302 uint32_t &i1,
303 uint32_t &i2,
304 ModRMDecision &decision)
305 const {
306 static uint64_t sTableNumber = 0;
Craig Topperce8f4c52012-02-09 07:45:30 +0000307 static uint64_t sEntryNumber = 1;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000308 ModRMDecisionType dt = getDecisionType(decision);
309 uint16_t index;
Craig Topperce8f4c52012-02-09 07:45:30 +0000310
Sean Callanan8ed9f512009-12-19 02:59:52 +0000311 if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
312 {
313 o2.indent(i2) << "{ /* ModRMDecision */" << "\n";
314 i2++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000315
Sean Callanan8ed9f512009-12-19 02:59:52 +0000316 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000317 o2.indent(i2) << 0 << " /* EmptyTable */\n";
318
Sean Callanan8ed9f512009-12-19 02:59:52 +0000319 i2--;
320 o2.indent(i2) << "}";
321 return;
322 }
Sean Callanan8ed9f512009-12-19 02:59:52 +0000323
Craig Topperce8f4c52012-02-09 07:45:30 +0000324 o1 << "/* Table" << sTableNumber << " */\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000325 i1++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000326
Sean Callanan8ed9f512009-12-19 02:59:52 +0000327 switch (dt) {
328 default:
329 llvm_unreachable("Unknown decision type");
330 case MODRM_ONEENTRY:
Craig Topperce8f4c52012-02-09 07:45:30 +0000331 emitOneID(o1, i1, decision.instructionIDs[0], true);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000332 break;
333 case MODRM_SPLITRM:
334 emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
Craig Topperce8f4c52012-02-09 07:45:30 +0000335 emitOneID(o1, i1, decision.instructionIDs[0xc0], true); // mod = 0b11
Sean Callanan8ed9f512009-12-19 02:59:52 +0000336 break;
Craig Topperf41ab772012-02-09 08:58:07 +0000337 case MODRM_SPLITREG:
338 for (index = 0; index < 64; index += 8)
339 emitOneID(o1, i1, decision.instructionIDs[index], true);
340 for (index = 0xc0; index < 256; index += 8)
341 emitOneID(o1, i1, decision.instructionIDs[index], true);
342 break;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000343 case MODRM_FULL:
344 for (index = 0; index < 256; ++index)
Craig Topperce8f4c52012-02-09 07:45:30 +0000345 emitOneID(o1, i1, decision.instructionIDs[index], true);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000346 break;
347 }
Craig Topperce8f4c52012-02-09 07:45:30 +0000348
Sean Callanan8ed9f512009-12-19 02:59:52 +0000349 i1--;
Craig Topperce8f4c52012-02-09 07:45:30 +0000350
Sean Callanan8ed9f512009-12-19 02:59:52 +0000351 o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
352 i2++;
Craig Topperce8f4c52012-02-09 07:45:30 +0000353
Sean Callanan8ed9f512009-12-19 02:59:52 +0000354 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000355 o2.indent(i2) << sEntryNumber << " /* Table" << sTableNumber << " */\n";
356
Sean Callanan8ed9f512009-12-19 02:59:52 +0000357 i2--;
358 o2.indent(i2) << "}";
Craig Topperce8f4c52012-02-09 07:45:30 +0000359
360 switch (dt) {
361 default:
362 llvm_unreachable("Unknown decision type");
363 case MODRM_ONEENTRY:
364 sEntryNumber += 1;
365 break;
366 case MODRM_SPLITRM:
367 sEntryNumber += 2;
368 break;
Craig Topperf41ab772012-02-09 08:58:07 +0000369 case MODRM_SPLITREG:
370 sEntryNumber += 16;
371 break;
Craig Topperce8f4c52012-02-09 07:45:30 +0000372 case MODRM_FULL:
373 sEntryNumber += 256;
374 break;
375 }
376
Sean Callanan8ed9f512009-12-19 02:59:52 +0000377 ++sTableNumber;
378}
379
380void DisassemblerTables::emitOpcodeDecision(
381 raw_ostream &o1,
382 raw_ostream &o2,
383 uint32_t &i1,
384 uint32_t &i2,
385 OpcodeDecision &decision) const {
386 uint16_t index;
387
388 o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
389 i2++;
390 o2.indent(i2) << "{" << "\n";
391 i2++;
392
393 for (index = 0; index < 256; ++index) {
394 o2.indent(i2);
395
396 o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
397
398 emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]);
399
400 if (index < 255)
401 o2 << ",";
402
403 o2 << "\n";
404 }
405
406 i2--;
407 o2.indent(i2) << "}" << "\n";
408 i2--;
409 o2.indent(i2) << "}" << "\n";
410}
411
412void DisassemblerTables::emitContextDecision(
413 raw_ostream &o1,
414 raw_ostream &o2,
415 uint32_t &i1,
416 uint32_t &i2,
417 ContextDecision &decision,
418 const char* name) const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000419 o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000420 i2++;
421 o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
422 i2++;
423
424 unsigned index;
425
426 for (index = 0; index < IC_max; ++index) {
427 o2.indent(i2) << "/* ";
428 o2 << stringForContext((InstructionContext)index);
429 o2 << " */";
430 o2 << "\n";
431
432 emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]);
433
434 if (index + 1 < IC_max)
435 o2 << ", ";
436 }
437
438 i2--;
439 o2.indent(i2) << "}" << "\n";
440 i2--;
441 o2.indent(i2) << "};" << "\n";
442}
443
444void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
445 const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000446 o.indent(i * 2) << "static const struct InstructionSpecifier ";
447 o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000448
449 i++;
450
451 uint16_t numInstructions = InstructionSpecifiers.size();
452 uint16_t index, operandIndex;
453
454 for (index = 0; index < numInstructions; ++index) {
455 o.indent(i * 2) << "{ /* " << index << " */" << "\n";
456 i++;
457
458 o.indent(i * 2) <<
459 stringForModifierType(InstructionSpecifiers[index].modifierType);
460 o << "," << "\n";
461
462 o.indent(i * 2) << "0x";
463 o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
464 o << "," << "\n";
465
466 o.indent(i * 2) << "{" << "\n";
467 i++;
468
469 for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
470 o.indent(i * 2) << "{ ";
471 o << stringForOperandEncoding(InstructionSpecifiers[index]
472 .operands[operandIndex]
473 .encoding);
474 o << ", ";
475 o << stringForOperandType(InstructionSpecifiers[index]
476 .operands[operandIndex]
477 .type);
478 o << " }";
479
480 if (operandIndex < X86_MAX_OPERANDS - 1)
481 o << ",";
482
483 o << "\n";
484 }
485
486 i--;
487 o.indent(i * 2) << "}," << "\n";
488
489 o.indent(i * 2) << "\"" << InstructionSpecifiers[index].name << "\"";
490 o << "\n";
491
492 i--;
493 o.indent(i * 2) << "}";
494
495 if (index + 1 < numInstructions)
496 o << ",";
497
498 o << "\n";
499 }
500
501 i--;
502 o.indent(i * 2) << "};" << "\n";
503}
504
505void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
506 uint16_t index;
507
Benjamin Kramer86c69c52010-10-23 09:28:42 +0000508 o.indent(i * 2) << "static const InstructionContext " CONTEXTS_STR
509 "[256] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000510 i++;
511
512 for (index = 0; index < 256; ++index) {
513 o.indent(i * 2);
514
Craig Topperc8eb8802011-11-06 23:04:08 +0000515 if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
516 o << "IC_VEX_L_W_OPSIZE";
517 else if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE))
Sean Callanana21e2ea2011-03-15 01:23:15 +0000518 o << "IC_VEX_L_OPSIZE";
519 else if ((index & ATTR_VEXL) && (index & ATTR_XD))
520 o << "IC_VEX_L_XD";
521 else if ((index & ATTR_VEXL) && (index & ATTR_XS))
522 o << "IC_VEX_L_XS";
523 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
524 o << "IC_VEX_W_OPSIZE";
525 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XD))
526 o << "IC_VEX_W_XD";
527 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XS))
528 o << "IC_VEX_W_XS";
529 else if (index & ATTR_VEXL)
530 o << "IC_VEX_L";
531 else if ((index & ATTR_VEX) && (index & ATTR_REXW))
532 o << "IC_VEX_W";
533 else if ((index & ATTR_VEX) && (index & ATTR_OPSIZE))
534 o << "IC_VEX_OPSIZE";
535 else if ((index & ATTR_VEX) && (index & ATTR_XD))
536 o << "IC_VEX_XD";
537 else if ((index & ATTR_VEX) && (index & ATTR_XS))
538 o << "IC_VEX_XS";
Craig Topper113061d2011-08-25 07:42:00 +0000539 else if (index & ATTR_VEX)
540 o << "IC_VEX";
Sean Callanana21e2ea2011-03-15 01:23:15 +0000541 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
Sean Callanan8ed9f512009-12-19 02:59:52 +0000542 o << "IC_64BIT_REXW_XS";
543 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
544 o << "IC_64BIT_REXW_XD";
545 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
546 (index & ATTR_OPSIZE))
547 o << "IC_64BIT_REXW_OPSIZE";
Craig Toppere1b4a1a2011-10-01 19:54:56 +0000548 else if ((index & ATTR_64BIT) && (index & ATTR_XD) && (index & ATTR_OPSIZE))
549 o << "IC_64BIT_XD_OPSIZE";
Craig Topper29480fd2011-10-11 04:34:23 +0000550 else if ((index & ATTR_64BIT) && (index & ATTR_XS) && (index & ATTR_OPSIZE))
551 o << "IC_64BIT_XS_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000552 else if ((index & ATTR_64BIT) && (index & ATTR_XS))
553 o << "IC_64BIT_XS";
554 else if ((index & ATTR_64BIT) && (index & ATTR_XD))
555 o << "IC_64BIT_XD";
556 else if ((index & ATTR_64BIT) && (index & ATTR_OPSIZE))
557 o << "IC_64BIT_OPSIZE";
558 else if ((index & ATTR_64BIT) && (index & ATTR_REXW))
559 o << "IC_64BIT_REXW";
560 else if ((index & ATTR_64BIT))
561 o << "IC_64BIT";
Craig Topper29480fd2011-10-11 04:34:23 +0000562 else if ((index & ATTR_XS) && (index & ATTR_OPSIZE))
563 o << "IC_XS_OPSIZE";
Craig Toppere1b4a1a2011-10-01 19:54:56 +0000564 else if ((index & ATTR_XD) && (index & ATTR_OPSIZE))
565 o << "IC_XD_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000566 else if (index & ATTR_XS)
567 o << "IC_XS";
568 else if (index & ATTR_XD)
569 o << "IC_XD";
570 else if (index & ATTR_OPSIZE)
571 o << "IC_OPSIZE";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000572 else
573 o << "IC";
574
575 if (index < 255)
576 o << ",";
577 else
578 o << " ";
579
580 o << " /* " << index << " */";
581
582 o << "\n";
583 }
584
585 i--;
586 o.indent(i * 2) << "};" << "\n";
587}
588
589void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
590 raw_ostream &o2,
591 uint32_t &i1,
592 uint32_t &i2)
593 const {
594 emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
595 emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
596 emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
597 emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR);
Joerg Sonnenberger4a8ac8d2011-04-04 16:58:13 +0000598 emitContextDecision(o1, o2, i1, i2, *Tables[4], THREEBYTEA6_STR);
599 emitContextDecision(o1, o2, i1, i2, *Tables[5], THREEBYTEA7_STR);
Sean Callanan8ed9f512009-12-19 02:59:52 +0000600}
601
602void DisassemblerTables::emit(raw_ostream &o) const {
603 uint32_t i1 = 0;
604 uint32_t i2 = 0;
605
606 std::string s1;
607 std::string s2;
608
609 raw_string_ostream o1(s1);
610 raw_string_ostream o2(s2);
611
612 emitInstructionInfo(o, i2);
613 o << "\n";
614
615 emitContextTable(o, i2);
616 o << "\n";
Craig Topperce8f4c52012-02-09 07:45:30 +0000617
618 o << "static const InstrUID modRMTable[] = {\n";
619 i1++;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000620 emitEmptyTable(o1, i1);
Craig Topperce8f4c52012-02-09 07:45:30 +0000621 i1--;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000622 emitContextDecisions(o1, o2, i1, i2);
Craig Topperce8f4c52012-02-09 07:45:30 +0000623
Sean Callanan8ed9f512009-12-19 02:59:52 +0000624 o << o1.str();
Craig Topperce8f4c52012-02-09 07:45:30 +0000625 o << " 0x0\n";
626 o << "};\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000627 o << "\n";
628 o << o2.str();
629 o << "\n";
630 o << "\n";
631}
632
633void DisassemblerTables::setTableFields(ModRMDecision &decision,
634 const ModRMFilter &filter,
635 InstrUID uid,
636 uint8_t opcode) {
637 unsigned index;
638
639 for (index = 0; index < 256; ++index) {
640 if (filter.accepts(index)) {
641 if (decision.instructionIDs[index] == uid)
642 continue;
643
644 if (decision.instructionIDs[index] != 0) {
645 InstructionSpecifier &newInfo =
646 InstructionSpecifiers[uid];
647 InstructionSpecifier &previousInfo =
648 InstructionSpecifiers[decision.instructionIDs[index]];
649
650 if(newInfo.filtered)
651 continue; // filtered instructions get lowest priority
652
Craig Topper842f58f2011-09-11 20:23:20 +0000653 if(previousInfo.name == "NOOP" && (newInfo.name == "XCHG16ar" ||
654 newInfo.name == "XCHG32ar" ||
Craig Topper25f6dfd2011-10-07 05:35:38 +0000655 newInfo.name == "XCHG32ar64" ||
Craig Topper842f58f2011-09-11 20:23:20 +0000656 newInfo.name == "XCHG64ar"))
657 continue; // special case for XCHG*ar and NOOP
Sean Callanan8ed9f512009-12-19 02:59:52 +0000658
659 if (outranks(previousInfo.insnContext, newInfo.insnContext))
660 continue;
661
662 if (previousInfo.insnContext == newInfo.insnContext &&
663 !previousInfo.filtered) {
664 errs() << "Error: Primary decode conflict: ";
665 errs() << newInfo.name << " would overwrite " << previousInfo.name;
666 errs() << "\n";
667 errs() << "ModRM " << index << "\n";
668 errs() << "Opcode " << (uint16_t)opcode << "\n";
669 errs() << "Context " << stringForContext(newInfo.insnContext) << "\n";
670 HasConflicts = true;
671 }
672 }
673
674 decision.instructionIDs[index] = uid;
675 }
676 }
677}
678
679void DisassemblerTables::setTableFields(OpcodeType type,
680 InstructionContext insnContext,
681 uint8_t opcode,
682 const ModRMFilter &filter,
Craig Topper4da632e2011-09-23 06:57:25 +0000683 InstrUID uid,
Craig Topper6744a172011-10-04 06:30:42 +0000684 bool is32bit,
685 bool ignoresVEX_L) {
Sean Callanan8ed9f512009-12-19 02:59:52 +0000686 unsigned index;
687
688 ContextDecision &decision = *Tables[type];
689
690 for (index = 0; index < IC_max; ++index) {
Craig Topper4da632e2011-09-23 06:57:25 +0000691 if (is32bit && inheritsFrom((InstructionContext)index, IC_64BIT))
692 continue;
693
Sean Callanan8ed9f512009-12-19 02:59:52 +0000694 if (inheritsFrom((InstructionContext)index,
Craig Topper6744a172011-10-04 06:30:42 +0000695 InstructionSpecifiers[uid].insnContext, ignoresVEX_L))
Sean Callanan8ed9f512009-12-19 02:59:52 +0000696 setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],
697 filter,
698 uid,
699 opcode);
700 }
701}