blob: 081b5771cdbabc658599fe00350b32484013726d [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
20#include "TableGenBackend.h"
21#include "llvm/Support/ErrorHandling.h"
22#include "llvm/Support/Format.h"
23
Sean Callanan8ed9f512009-12-19 02:59:52 +000024using namespace llvm;
25using namespace X86Disassembler;
26
27/// inheritsFrom - Indicates whether all instructions in one class also belong
28/// to another class.
29///
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.
33static inline bool inheritsFrom(InstructionContext child,
34 InstructionContext parent) {
35 if (child == parent)
36 return true;
37
38 switch (parent) {
39 case IC:
40 return true;
41 case IC_64BIT:
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));
46 case IC_OPSIZE:
47 return(inheritsFrom(child, IC_64BIT_OPSIZE));
48 case IC_XD:
Sean Callanana21e2ea2011-03-15 01:23:15 +000049 return(inheritsFrom(child, IC_64BIT_XD) ||
50 inheritsFrom(child, IC_VEX_XD));
Sean Callanan8ed9f512009-12-19 02:59:52 +000051 case IC_XS:
Sean Callanana21e2ea2011-03-15 01:23:15 +000052 return(inheritsFrom(child, IC_64BIT_XS) ||
53 inheritsFrom(child, IC_VEX_XS));
Sean Callanan8ed9f512009-12-19 02:59:52 +000054 case IC_64BIT_REXW:
55 return(inheritsFrom(child, IC_64BIT_REXW_XS) ||
56 inheritsFrom(child, IC_64BIT_REXW_XD) ||
57 inheritsFrom(child, IC_64BIT_REXW_OPSIZE));
58 case IC_64BIT_OPSIZE:
59 return(inheritsFrom(child, IC_64BIT_REXW_OPSIZE));
60 case IC_64BIT_XD:
61 return(inheritsFrom(child, IC_64BIT_REXW_XD));
62 case IC_64BIT_XS:
63 return(inheritsFrom(child, IC_64BIT_REXW_XS));
64 case IC_64BIT_REXW_XD:
65 return false;
66 case IC_64BIT_REXW_XS:
67 return false;
68 case IC_64BIT_REXW_OPSIZE:
69 return false;
Sean Callanana21e2ea2011-03-15 01:23:15 +000070 case IC_VEX:
71 return(inheritsFrom(child, IC_VEX_XS) ||
72 inheritsFrom(child, IC_VEX_XD) ||
73 inheritsFrom(child, IC_VEX_L) ||
74 inheritsFrom(child, IC_VEX_W) ||
75 inheritsFrom(child, IC_VEX_OPSIZE));
76 case IC_VEX_XS:
77 return(inheritsFrom(child, IC_VEX_L_XS) ||
78 inheritsFrom(child, IC_VEX_W_XS));
79 case IC_VEX_XD:
80 return(inheritsFrom(child, IC_VEX_L_XD) ||
81 inheritsFrom(child, IC_VEX_W_XD));
82 case IC_VEX_L:
83 return(inheritsFrom(child, IC_VEX_L_XS) ||
84 inheritsFrom(child, IC_VEX_L_XD));
85 case IC_VEX_L_XS:
86 return false;
87 case IC_VEX_L_XD:
88 return false;
89 case IC_VEX_W:
90 return(inheritsFrom(child, IC_VEX_W_XS) ||
91 inheritsFrom(child, IC_VEX_W_XD) ||
92 inheritsFrom(child, IC_VEX_W_OPSIZE));
93 case IC_VEX_W_XS:
94 return false;
95 case IC_VEX_W_XD:
96 return false;
97 case IC_VEX_OPSIZE:
98 return inheritsFrom(child, IC_VEX_W_OPSIZE);
Sean Callanan8ed9f512009-12-19 02:59:52 +000099 default:
100 return false;
101 }
102}
103
104/// outranks - Indicates whether, if an instruction has two different applicable
105/// classes, which class should be preferred when performing decode. This
106/// imposes a total ordering (ties are resolved toward "lower")
107///
108/// @param upper - The class that may be preferable
109/// @param lower - The class that may be less preferable
110/// @return - True if upper is to be preferred, false otherwise.
111static inline bool outranks(InstructionContext upper,
112 InstructionContext lower) {
113 assert(upper < IC_max);
114 assert(lower < IC_max);
115
116#define ENUM_ENTRY(n, r, d) r,
117 static int ranks[IC_max] = {
118 INSTRUCTION_CONTEXTS
119 };
120#undef ENUM_ENTRY
121
122 return (ranks[upper] > ranks[lower]);
123}
124
125/// stringForContext - Returns a string containing the name of a particular
126/// InstructionContext, usually for diagnostic purposes.
127///
128/// @param insnContext - The instruction class to transform to a string.
129/// @return - A statically-allocated string constant that contains the
130/// name of the instruction class.
131static inline const char* stringForContext(InstructionContext insnContext) {
132 switch (insnContext) {
133 default:
134 llvm_unreachable("Unhandled instruction class");
135#define ENUM_ENTRY(n, r, d) case n: return #n; break;
136 INSTRUCTION_CONTEXTS
137#undef ENUM_ENTRY
138 }
Daniel Dunbare5976b82009-12-23 00:45:10 +0000139
140 return 0;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000141}
142
143/// stringForOperandType - Like stringForContext, but for OperandTypes.
144static inline const char* stringForOperandType(OperandType type) {
145 switch (type) {
146 default:
147 llvm_unreachable("Unhandled type");
148#define ENUM_ENTRY(i, d) case i: return #i;
149 TYPES
150#undef ENUM_ENTRY
151 }
152}
153
154/// stringForOperandEncoding - like stringForContext, but for
155/// OperandEncodings.
156static inline const char* stringForOperandEncoding(OperandEncoding encoding) {
157 switch (encoding) {
158 default:
159 llvm_unreachable("Unhandled encoding");
160#define ENUM_ENTRY(i, d) case i: return #i;
161 ENCODINGS
162#undef ENUM_ENTRY
163 }
164}
165
166void DisassemblerTables::emitOneID(raw_ostream &o,
167 uint32_t &i,
168 InstrUID id,
169 bool addComma) const {
170 if (id)
171 o.indent(i * 2) << format("0x%hx", id);
172 else
173 o.indent(i * 2) << 0;
174
175 if (addComma)
176 o << ", ";
177 else
178 o << " ";
179
180 o << "/* ";
181 o << InstructionSpecifiers[id].name;
182 o << "*/";
183
184 o << "\n";
185}
186
187/// emitEmptyTable - Emits the modRMEmptyTable, which is used as a ID table by
188/// all ModR/M decisions for instructions that are invalid for all possible
189/// ModR/M byte values.
190///
191/// @param o - The output stream on which to emit the table.
192/// @param i - The indentation level for that output stream.
193static void emitEmptyTable(raw_ostream &o, uint32_t &i)
194{
Benjamin Kramer86c69c52010-10-23 09:28:42 +0000195 o.indent(i * 2) << "static const InstrUID modRMEmptyTable[1] = { 0 };\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000196 o << "\n";
197}
198
199/// getDecisionType - Determines whether a ModRM decision with 255 entries can
200/// be compacted by eliminating redundant information.
201///
202/// @param decision - The decision to be compacted.
203/// @return - The compactest available representation for the decision.
204static ModRMDecisionType getDecisionType(ModRMDecision &decision)
205{
206 bool satisfiesOneEntry = true;
207 bool satisfiesSplitRM = true;
208
209 uint16_t index;
210
211 for (index = 0; index < 256; ++index) {
212 if (decision.instructionIDs[index] != decision.instructionIDs[0])
213 satisfiesOneEntry = false;
214
215 if (((index & 0xc0) == 0xc0) &&
216 (decision.instructionIDs[index] != decision.instructionIDs[0xc0]))
217 satisfiesSplitRM = false;
218
219 if (((index & 0xc0) != 0xc0) &&
220 (decision.instructionIDs[index] != decision.instructionIDs[0x00]))
221 satisfiesSplitRM = false;
222 }
223
224 if (satisfiesOneEntry)
225 return MODRM_ONEENTRY;
226
227 if (satisfiesSplitRM)
228 return MODRM_SPLITRM;
229
230 return MODRM_FULL;
231}
232
233/// stringForDecisionType - Returns a statically-allocated string corresponding
234/// to a particular decision type.
235///
236/// @param dt - The decision type.
237/// @return - A pointer to the statically-allocated string (e.g.,
238/// "MODRM_ONEENTRY" for MODRM_ONEENTRY).
239static const char* stringForDecisionType(ModRMDecisionType dt)
240{
241#define ENUM_ENTRY(n) case n: return #n;
242 switch (dt) {
243 default:
244 llvm_unreachable("Unknown decision type");
245 MODRMTYPES
246 };
247#undef ENUM_ENTRY
248}
249
250/// stringForModifierType - Returns a statically-allocated string corresponding
251/// to an opcode modifier type.
252///
253/// @param mt - The modifier type.
254/// @return - A pointer to the statically-allocated string (e.g.,
255/// "MODIFIER_NONE" for MODIFIER_NONE).
256static const char* stringForModifierType(ModifierType mt)
257{
258#define ENUM_ENTRY(n) case n: return #n;
259 switch(mt) {
260 default:
261 llvm_unreachable("Unknown modifier type");
262 MODIFIER_TYPES
263 };
264#undef ENUM_ENTRY
265}
266
267DisassemblerTables::DisassemblerTables() {
268 unsigned i;
269
270 for (i = 0; i < 4; i++) {
271 Tables[i] = new ContextDecision;
Daniel Dunbar87830872009-12-19 04:16:57 +0000272 memset(Tables[i], 0, sizeof(ContextDecision));
Sean Callanan8ed9f512009-12-19 02:59:52 +0000273 }
274
275 HasConflicts = false;
276}
277
278DisassemblerTables::~DisassemblerTables() {
279 unsigned i;
280
281 for (i = 0; i < 4; i++)
282 delete Tables[i];
283}
284
285void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
286 raw_ostream &o2,
287 uint32_t &i1,
288 uint32_t &i2,
289 ModRMDecision &decision)
290 const {
291 static uint64_t sTableNumber = 0;
292 uint64_t thisTableNumber = sTableNumber;
293 ModRMDecisionType dt = getDecisionType(decision);
294 uint16_t index;
295
296 if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
297 {
298 o2.indent(i2) << "{ /* ModRMDecision */" << "\n";
299 i2++;
300
301 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
302 o2.indent(i2) << "modRMEmptyTable";
303
304 i2--;
305 o2.indent(i2) << "}";
306 return;
307 }
308
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000309 o1.indent(i1) << "static const InstrUID modRMTable" << thisTableNumber;
Sean Callanan8ed9f512009-12-19 02:59:52 +0000310
311 switch (dt) {
312 default:
313 llvm_unreachable("Unknown decision type");
314 case MODRM_ONEENTRY:
315 o1 << "[1]";
316 break;
317 case MODRM_SPLITRM:
318 o1 << "[2]";
319 break;
320 case MODRM_FULL:
321 o1 << "[256]";
322 break;
323 }
324
325 o1 << " = {" << "\n";
326 i1++;
327
328 switch (dt) {
329 default:
330 llvm_unreachable("Unknown decision type");
331 case MODRM_ONEENTRY:
332 emitOneID(o1, i1, decision.instructionIDs[0], false);
333 break;
334 case MODRM_SPLITRM:
335 emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
336 emitOneID(o1, i1, decision.instructionIDs[0xc0], false); // mod = 0b11
337 break;
338 case MODRM_FULL:
339 for (index = 0; index < 256; ++index)
340 emitOneID(o1, i1, decision.instructionIDs[index], index < 255);
341 break;
342 }
343
344 i1--;
345 o1.indent(i1) << "};" << "\n";
346 o1 << "\n";
347
348 o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
349 i2++;
350
351 o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
352 o2.indent(i2) << "modRMTable" << sTableNumber << "\n";
353
354 i2--;
355 o2.indent(i2) << "}";
356
357 ++sTableNumber;
358}
359
360void DisassemblerTables::emitOpcodeDecision(
361 raw_ostream &o1,
362 raw_ostream &o2,
363 uint32_t &i1,
364 uint32_t &i2,
365 OpcodeDecision &decision) const {
366 uint16_t index;
367
368 o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
369 i2++;
370 o2.indent(i2) << "{" << "\n";
371 i2++;
372
373 for (index = 0; index < 256; ++index) {
374 o2.indent(i2);
375
376 o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
377
378 emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]);
379
380 if (index < 255)
381 o2 << ",";
382
383 o2 << "\n";
384 }
385
386 i2--;
387 o2.indent(i2) << "}" << "\n";
388 i2--;
389 o2.indent(i2) << "}" << "\n";
390}
391
392void DisassemblerTables::emitContextDecision(
393 raw_ostream &o1,
394 raw_ostream &o2,
395 uint32_t &i1,
396 uint32_t &i2,
397 ContextDecision &decision,
398 const char* name) const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000399 o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000400 i2++;
401 o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
402 i2++;
403
404 unsigned index;
405
406 for (index = 0; index < IC_max; ++index) {
407 o2.indent(i2) << "/* ";
408 o2 << stringForContext((InstructionContext)index);
409 o2 << " */";
410 o2 << "\n";
411
412 emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]);
413
414 if (index + 1 < IC_max)
415 o2 << ", ";
416 }
417
418 i2--;
419 o2.indent(i2) << "}" << "\n";
420 i2--;
421 o2.indent(i2) << "};" << "\n";
422}
423
424void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
425 const {
Benjamin Kramer4d1dca92010-10-23 09:10:44 +0000426 o.indent(i * 2) << "static const struct InstructionSpecifier ";
427 o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000428
429 i++;
430
431 uint16_t numInstructions = InstructionSpecifiers.size();
432 uint16_t index, operandIndex;
433
434 for (index = 0; index < numInstructions; ++index) {
435 o.indent(i * 2) << "{ /* " << index << " */" << "\n";
436 i++;
437
438 o.indent(i * 2) <<
439 stringForModifierType(InstructionSpecifiers[index].modifierType);
440 o << "," << "\n";
441
442 o.indent(i * 2) << "0x";
443 o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
444 o << "," << "\n";
445
446 o.indent(i * 2) << "{" << "\n";
447 i++;
448
449 for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
450 o.indent(i * 2) << "{ ";
451 o << stringForOperandEncoding(InstructionSpecifiers[index]
452 .operands[operandIndex]
453 .encoding);
454 o << ", ";
455 o << stringForOperandType(InstructionSpecifiers[index]
456 .operands[operandIndex]
457 .type);
458 o << " }";
459
460 if (operandIndex < X86_MAX_OPERANDS - 1)
461 o << ",";
462
463 o << "\n";
464 }
465
466 i--;
467 o.indent(i * 2) << "}," << "\n";
468
469 o.indent(i * 2) << "\"" << InstructionSpecifiers[index].name << "\"";
470 o << "\n";
471
472 i--;
473 o.indent(i * 2) << "}";
474
475 if (index + 1 < numInstructions)
476 o << ",";
477
478 o << "\n";
479 }
480
481 i--;
482 o.indent(i * 2) << "};" << "\n";
483}
484
485void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
486 uint16_t index;
487
Benjamin Kramer86c69c52010-10-23 09:28:42 +0000488 o.indent(i * 2) << "static const InstructionContext " CONTEXTS_STR
489 "[256] = {\n";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000490 i++;
491
492 for (index = 0; index < 256; ++index) {
493 o.indent(i * 2);
494
Sean Callanana21e2ea2011-03-15 01:23:15 +0000495 if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE))
496 o << "IC_VEX_L_OPSIZE";
497 else if ((index & ATTR_VEXL) && (index & ATTR_XD))
498 o << "IC_VEX_L_XD";
499 else if ((index & ATTR_VEXL) && (index & ATTR_XS))
500 o << "IC_VEX_L_XS";
501 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
502 o << "IC_VEX_W_OPSIZE";
503 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XD))
504 o << "IC_VEX_W_XD";
505 else if ((index & ATTR_VEX) && (index & ATTR_REXW) && (index & ATTR_XS))
506 o << "IC_VEX_W_XS";
507 else if (index & ATTR_VEXL)
508 o << "IC_VEX_L";
509 else if ((index & ATTR_VEX) && (index & ATTR_REXW))
510 o << "IC_VEX_W";
511 else if ((index & ATTR_VEX) && (index & ATTR_OPSIZE))
512 o << "IC_VEX_OPSIZE";
513 else if ((index & ATTR_VEX) && (index & ATTR_XD))
514 o << "IC_VEX_XD";
515 else if ((index & ATTR_VEX) && (index & ATTR_XS))
516 o << "IC_VEX_XS";
517 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
Sean Callanan8ed9f512009-12-19 02:59:52 +0000518 o << "IC_64BIT_REXW_XS";
519 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
520 o << "IC_64BIT_REXW_XD";
521 else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
522 (index & ATTR_OPSIZE))
523 o << "IC_64BIT_REXW_OPSIZE";
524 else if ((index & ATTR_64BIT) && (index & ATTR_XS))
525 o << "IC_64BIT_XS";
526 else if ((index & ATTR_64BIT) && (index & ATTR_XD))
527 o << "IC_64BIT_XD";
528 else if ((index & ATTR_64BIT) && (index & ATTR_OPSIZE))
529 o << "IC_64BIT_OPSIZE";
530 else if ((index & ATTR_64BIT) && (index & ATTR_REXW))
531 o << "IC_64BIT_REXW";
532 else if ((index & ATTR_64BIT))
533 o << "IC_64BIT";
534 else if (index & ATTR_XS)
535 o << "IC_XS";
536 else if (index & ATTR_XD)
537 o << "IC_XD";
538 else if (index & ATTR_OPSIZE)
539 o << "IC_OPSIZE";
Sean Callanana21e2ea2011-03-15 01:23:15 +0000540 else if (index & ATTR_VEX)
541 o << "IC_VEX";
Sean Callanan8ed9f512009-12-19 02:59:52 +0000542 else
543 o << "IC";
544
545 if (index < 255)
546 o << ",";
547 else
548 o << " ";
549
550 o << " /* " << index << " */";
551
552 o << "\n";
553 }
554
555 i--;
556 o.indent(i * 2) << "};" << "\n";
557}
558
559void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
560 raw_ostream &o2,
561 uint32_t &i1,
562 uint32_t &i2)
563 const {
564 emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
565 emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
566 emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
567 emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR);
568}
569
570void DisassemblerTables::emit(raw_ostream &o) const {
571 uint32_t i1 = 0;
572 uint32_t i2 = 0;
573
574 std::string s1;
575 std::string s2;
576
577 raw_string_ostream o1(s1);
578 raw_string_ostream o2(s2);
579
580 emitInstructionInfo(o, i2);
581 o << "\n";
582
583 emitContextTable(o, i2);
584 o << "\n";
585
586 emitEmptyTable(o1, i1);
587 emitContextDecisions(o1, o2, i1, i2);
588
589 o << o1.str();
590 o << "\n";
591 o << o2.str();
592 o << "\n";
593 o << "\n";
594}
595
596void DisassemblerTables::setTableFields(ModRMDecision &decision,
597 const ModRMFilter &filter,
598 InstrUID uid,
599 uint8_t opcode) {
600 unsigned index;
601
602 for (index = 0; index < 256; ++index) {
603 if (filter.accepts(index)) {
604 if (decision.instructionIDs[index] == uid)
605 continue;
606
607 if (decision.instructionIDs[index] != 0) {
608 InstructionSpecifier &newInfo =
609 InstructionSpecifiers[uid];
610 InstructionSpecifier &previousInfo =
611 InstructionSpecifiers[decision.instructionIDs[index]];
612
613 if(newInfo.filtered)
614 continue; // filtered instructions get lowest priority
615
616 if(previousInfo.name == "NOOP")
617 continue; // special case for XCHG32ar and NOOP
618
619 if (outranks(previousInfo.insnContext, newInfo.insnContext))
620 continue;
621
622 if (previousInfo.insnContext == newInfo.insnContext &&
623 !previousInfo.filtered) {
624 errs() << "Error: Primary decode conflict: ";
625 errs() << newInfo.name << " would overwrite " << previousInfo.name;
626 errs() << "\n";
627 errs() << "ModRM " << index << "\n";
628 errs() << "Opcode " << (uint16_t)opcode << "\n";
629 errs() << "Context " << stringForContext(newInfo.insnContext) << "\n";
630 HasConflicts = true;
631 }
632 }
633
634 decision.instructionIDs[index] = uid;
635 }
636 }
637}
638
639void DisassemblerTables::setTableFields(OpcodeType type,
640 InstructionContext insnContext,
641 uint8_t opcode,
642 const ModRMFilter &filter,
643 InstrUID uid) {
644 unsigned index;
645
646 ContextDecision &decision = *Tables[type];
647
648 for (index = 0; index < IC_max; ++index) {
649 if (inheritsFrom((InstructionContext)index,
650 InstructionSpecifiers[uid].insnContext))
651 setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],
652 filter,
653 uid,
654 opcode);
655 }
656}