Newer
Older
//===- X86RecognizableInstr.cpp - Disassembler instruction spec --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is part of the X86 Disassembler Emitter.
// It contains the implementation of a single recognizable instruction.
// Documentation for the disassembler emitter in general can be found in
// X86DisasemblerEmitter.h.
//
//===----------------------------------------------------------------------===//
#include "X86RecognizableInstr.h"
#include "X86DisassemblerShared.h"
#include "X86ModRMFilters.h"
#include "llvm/Support/ErrorHandling.h"
#include <string>
using namespace llvm;
#define MRM_MAPPING \
MAP(C1, 33) \
MAP(C2, 34) \
MAP(C3, 35) \
MAP(C4, 36) \
MAP(C8, 37) \
MAP(C9, 38) \
MAP(CA, 39) \
MAP(CB, 40) \
MAP(E8, 41) \
MAP(F0, 42) \
MAP(F8, 45) \
MAP(F9, 46) \
MAP(D0, 47) \
MAP(D1, 48) \
MAP(D4, 49) \
MAP(D5, 50) \
MAP(D6, 51) \
MAP(D8, 52) \
MAP(D9, 53) \
MAP(DA, 54) \
MAP(DB, 55) \
MAP(DC, 56) \
MAP(DD, 57) \
MAP(DE, 58) \
MAP(DF, 59)
// A clone of X86 since we can't depend on something that is generated.
namespace X86Local {
enum {
Pseudo = 0,
RawFrm = 1,
AddRegFrm = 2,
MRMDestReg = 3,
MRMDestMem = 4,
MRMSrcReg = 5,
MRMSrcMem = 6,
MRM0r = 16, MRM1r = 17, MRM2r = 18, MRM3r = 19,
MRM4r = 20, MRM5r = 21, MRM6r = 22, MRM7r = 23,
MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27,
MRM4m = 28, MRM5m = 29, MRM6m = 30, MRM7m = 31,
Richard Trieu
committed
RawFrmImm8 = 43,
RawFrmImm16 = 44,
#define MAP(from, to) MRM_##from = to,
MRM_MAPPING
#undef MAP
lastMRM
};
enum {
TB = 1,
REP = 2,
D8 = 3, D9 = 4, DA = 5, DB = 6,
DC = 7, DD = 8, DE = 9, DF = 10,
XD = 11, XS = 12,
T8 = 13, P_TA = 14,
A6 = 15, A7 = 16, T8XD = 17, T8XS = 18, TAXD = 19,
XOP8 = 20, XOP9 = 21, XOPA = 22
};
}
// If rows are added to the opcode extension tables, then corresponding entries
//
// If the row corresponds to a single byte (i.e., 8f), then add an entry for
// that byte to ONE_BYTE_EXTENSION_TABLES.
//
// If the row corresponds to two bytes where the first is 0f, add an entry for
// the second byte to TWO_BYTE_EXTENSION_TABLES.
//
// If the row corresponds to some other set of bytes, you will need to modify
// the code in RecognizableInstr::emitDecodePath() as well, and add new prefixes
// to the X86 TD files, except in two cases: if the first two bytes of such a
// new combination are 0f 38 or 0f 3a, you just have to add maps called
// THREE_BYTE_38_EXTENSION_TABLES and THREE_BYTE_3A_EXTENSION_TABLES and add a
// switch(Opcode) just below the case X86Local::T8: or case X86Local::TA: line
// in RecognizableInstr::emitDecodePath().
#define ONE_BYTE_EXTENSION_TABLES \
EXTENSION_TABLE(80) \
EXTENSION_TABLE(81) \
EXTENSION_TABLE(82) \
EXTENSION_TABLE(83) \
EXTENSION_TABLE(8f) \
EXTENSION_TABLE(c0) \
EXTENSION_TABLE(c1) \
EXTENSION_TABLE(c6) \
EXTENSION_TABLE(c7) \
EXTENSION_TABLE(d0) \
EXTENSION_TABLE(d1) \
EXTENSION_TABLE(d2) \
EXTENSION_TABLE(d3) \
EXTENSION_TABLE(f6) \
EXTENSION_TABLE(f7) \
EXTENSION_TABLE(fe) \
EXTENSION_TABLE(ff)
#define TWO_BYTE_EXTENSION_TABLES \
EXTENSION_TABLE(00) \
EXTENSION_TABLE(01) \
EXTENSION_TABLE(0d) \
EXTENSION_TABLE(18) \
EXTENSION_TABLE(71) \
EXTENSION_TABLE(72) \
EXTENSION_TABLE(73) \
EXTENSION_TABLE(ae) \
EXTENSION_TABLE(ba) \
EXTENSION_TABLE(c7)
Craig Topper
committed
#define THREE_BYTE_38_EXTENSION_TABLES \
EXTENSION_TABLE(F3)
#define XOP9_MAP_EXTENSION_TABLES \
EXTENSION_TABLE(01) \
EXTENSION_TABLE(02)
using namespace X86Disassembler;
/// needsModRMForDecode - Indicates whether a particular instruction requires a
/// ModR/M byte for the instruction to be properly decoded. For example, a
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/// MRMDestReg instruction needs the Mod field in the ModR/M byte to be set to
/// 0b11.
///
/// @param form - The form of the instruction.
/// @return - true if the form implies that a ModR/M byte is required, false
/// otherwise.
static bool needsModRMForDecode(uint8_t form) {
if (form == X86Local::MRMDestReg ||
form == X86Local::MRMDestMem ||
form == X86Local::MRMSrcReg ||
form == X86Local::MRMSrcMem ||
(form >= X86Local::MRM0r && form <= X86Local::MRM7r) ||
(form >= X86Local::MRM0m && form <= X86Local::MRM7m))
return true;
else
return false;
}
/// isRegFormat - Indicates whether a particular form requires the Mod field of
/// the ModR/M byte to be 0b11.
///
/// @param form - The form of the instruction.
/// @return - true if the form implies that Mod must be 0b11, false
/// otherwise.
static bool isRegFormat(uint8_t form) {
if (form == X86Local::MRMDestReg ||
form == X86Local::MRMSrcReg ||
(form >= X86Local::MRM0r && form <= X86Local::MRM7r))
return true;
else
return false;
}
/// byteFromBitsInit - Extracts a value at most 8 bits in width from a BitsInit.
/// Useful for switch statements and the like.
///
/// @param init - A reference to the BitsInit to be decoded.
/// @return - The field, with the first bit in the BitsInit as the lowest
/// order bit.
int width = init.getNumBits();
assert(width <= 8 && "Field is too large for uint8_t!");
int index;
uint8_t mask = 0x01;
uint8_t ret = 0;
for (index = 0; index < width; index++) {
if (static_cast<BitInit*>(init.getBit(index))->getValue())
ret |= mask;
mask <<= 1;
}
return ret;
}
/// byteFromRec - Extract a value at most 8 bits in with from a Record given the
/// name of the field.
///
/// @param rec - The record from which to extract the value.
/// @param name - The name of the field in the record.
/// @return - The field, as translated by byteFromBitsInit().
static uint8_t byteFromRec(const Record* rec, const std::string &name) {
return byteFromBitsInit(*bits);
}
RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
const CodeGenInstruction &insn,
InstrUID uid) {
UID = uid;
Rec = insn.TheDef;
Name = Rec->getName();
Spec = &tables.specForUID(UID);
if (!Rec->isSubClassOf("X86Inst")) {
ShouldBeEmitted = false;
return;
}
Prefix = byteFromRec(Rec, "Prefix");
Opcode = byteFromRec(Rec, "Opcode");
Form = byteFromRec(Rec, "FormBits");
SegOvr = byteFromRec(Rec, "SegOvrBits");
HasOpSizePrefix = Rec->getValueAsBit("hasOpSizePrefix");
Craig Topper
committed
HasAdSizePrefix = Rec->getValueAsBit("hasAdSizePrefix");
HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix");
HasVEXPrefix = Rec->getValueAsBit("hasVEXPrefix");
HasVEX_4VPrefix = Rec->getValueAsBit("hasVEX_4VPrefix");
HasVEX_4VOp3Prefix = Rec->getValueAsBit("hasVEX_4VOp3Prefix");
HasVEX_WPrefix = Rec->getValueAsBit("hasVEX_WPrefix");
HasMemOp4Prefix = Rec->getValueAsBit("hasMemOp4Prefix");
IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L");
HasEVEXPrefix = Rec->getValueAsBit("hasEVEXPrefix");
HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2");
HasEVEX_K = Rec->getValueAsBit("hasEVEX_K");
HasEVEX_B = Rec->getValueAsBit("hasEVEX_B");
HasLockPrefix = Rec->getValueAsBit("hasLockPrefix");
IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly");
Name = Rec->getName();
AsmString = Rec->getValueAsString("AsmString");
Operands = &insn.Operands.OperandList;
IsSSE = (HasOpSizePrefix && (Name.find("16") == Name.npos)) ||
(Name.find("CRC32") != Name.npos);
HasFROperands = hasFROperands();
Craig Topper
committed
HasVEX_LPrefix = Rec->getValueAsBit("hasVEX_L");
Craig Topper
committed
Eli Friedman
committed
// Check for 64-bit inst which does not require REX
Craig Topper
committed
Is32Bit = false;
Eli Friedman
committed
Is64Bit = false;
// FIXME: Is there some better way to check for In64BitMode?
std::vector<Record*> Predicates = Rec->getValueAsListOfDefs("Predicates");
for (unsigned i = 0, e = Predicates.size(); i != e; ++i) {
Craig Topper
committed
if (Predicates[i]->getName().find("32Bit") != Name.npos) {
Is32Bit = true;
break;
}
Eli Friedman
committed
if (Predicates[i]->getName().find("64Bit") != Name.npos) {
Is64Bit = true;
break;
}
}
// FIXME: These instructions aren't marked as 64-bit in any way
Is64Bit |= Rec->getName() == "JMP64pcrel32" ||
Rec->getName() == "MASKMOVDQU64" ||
Rec->getName() == "POPFS64" ||
Rec->getName() == "POPGS64" ||
Rec->getName() == "PUSHFS64" ||
Eli Friedman
committed
Rec->getName() == "PUSHGS64" ||
Rec->getName() == "REX64_PREFIX" ||
Eli Friedman
committed
Rec->getName().find("PUSH64") != Name.npos ||
Rec->getName().find("POP64") != Name.npos;
ShouldBeEmitted = true;
}
void RecognizableInstr::processInstr(DisassemblerTables &tables,
Craig Topper
committed
const CodeGenInstruction &insn,
InstrUID uid)
{
Daniel Dunbar
committed
// Ignore "asm parser only" instructions.
if (insn.TheDef->getValueAsBit("isAsmParserOnly"))
return;
RecognizableInstr recogInstr(tables, insn, uid);
recogInstr.emitInstructionSpecifier(tables);
if (recogInstr.shouldBeEmitted())
recogInstr.emitDecodePath(tables);
}
#define EVEX_KB(n) (HasEVEX_K && HasEVEX_B? n##_K_B : \
(HasEVEX_K? n##_K : (HasEVEX_B ? n##_B : n)))
InstructionContext RecognizableInstr::insnContext() const {
InstructionContext insnContext;
if (HasEVEXPrefix) {
if (HasVEX_LPrefix && HasEVEX_L2Prefix) {
Craig Topper
committed
errs() << "Don't support VEX.L if EVEX_L2 is enabled: " << Name << "\n";
llvm_unreachable("Don't support VEX.L if EVEX_L2 is enabled");
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
}
// VEX_L & VEX_W
if (HasVEX_LPrefix && HasVEX_WPrefix) {
if (HasOpSizePrefix)
insnContext = EVEX_KB(IC_EVEX_L_W_OPSIZE);
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = EVEX_KB(IC_EVEX_L_W_XS);
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = EVEX_KB(IC_EVEX_L_W_XD);
else
insnContext = EVEX_KB(IC_EVEX_L_W);
} else if (HasVEX_LPrefix) {
// VEX_L
if (HasOpSizePrefix)
insnContext = EVEX_KB(IC_EVEX_L_OPSIZE);
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = EVEX_KB(IC_EVEX_L_XS);
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = EVEX_KB(IC_EVEX_L_XD);
else
insnContext = EVEX_KB(IC_EVEX_L);
}
else if (HasEVEX_L2Prefix && HasVEX_WPrefix) {
// EVEX_L2 & VEX_W
if (HasOpSizePrefix)
insnContext = EVEX_KB(IC_EVEX_L2_W_OPSIZE);
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = EVEX_KB(IC_EVEX_L2_W_XS);
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = EVEX_KB(IC_EVEX_L2_W_XD);
else
insnContext = EVEX_KB(IC_EVEX_L2_W);
} else if (HasEVEX_L2Prefix) {
// EVEX_L2
if (HasOpSizePrefix)
insnContext = EVEX_KB(IC_EVEX_L2_OPSIZE);
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = EVEX_KB(IC_EVEX_L2_XD);
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = EVEX_KB(IC_EVEX_L2_XS);
else
insnContext = EVEX_KB(IC_EVEX_L2);
}
else if (HasVEX_WPrefix) {
// VEX_W
if (HasOpSizePrefix)
insnContext = EVEX_KB(IC_EVEX_W_OPSIZE);
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = EVEX_KB(IC_EVEX_W_XS);
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = EVEX_KB(IC_EVEX_W_XD);
else
insnContext = EVEX_KB(IC_EVEX_W);
}
// No L, no W
else if (HasOpSizePrefix)
insnContext = EVEX_KB(IC_EVEX_OPSIZE);
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = EVEX_KB(IC_EVEX_XD);
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = EVEX_KB(IC_EVEX_XS);
else
insnContext = EVEX_KB(IC_EVEX);
/// eof EVEX
} else if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix|| HasVEXPrefix) {
if (HasVEX_LPrefix && HasVEX_WPrefix) {
if (HasOpSizePrefix)
insnContext = IC_VEX_L_W_OPSIZE;
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = IC_VEX_L_W_XS;
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = IC_VEX_L_W_XD;
insnContext = IC_VEX_L_W;
} else if (HasOpSizePrefix && HasVEX_LPrefix)
insnContext = IC_VEX_L_OPSIZE;
else if (HasOpSizePrefix && HasVEX_WPrefix)
insnContext = IC_VEX_W_OPSIZE;
else if (HasOpSizePrefix)
insnContext = IC_VEX_OPSIZE;
else if (HasVEX_LPrefix &&
(Prefix == X86Local::XS || Prefix == X86Local::T8XS))
insnContext = IC_VEX_L_XS;
else if (HasVEX_LPrefix && (Prefix == X86Local::XD ||
Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD))
insnContext = IC_VEX_L_XD;
else if (HasVEX_WPrefix &&
(Prefix == X86Local::XS || Prefix == X86Local::T8XS))
insnContext = IC_VEX_W_XS;
else if (HasVEX_WPrefix && (Prefix == X86Local::XD ||
Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD))
insnContext = IC_VEX_W_XD;
else if (HasVEX_WPrefix)
insnContext = IC_VEX_W;
else if (HasVEX_LPrefix)
insnContext = IC_VEX_L;
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = IC_VEX_XD;
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = IC_VEX_XS;
else
insnContext = IC_VEX;
Eli Friedman
committed
} else if (Is64Bit || HasREX_WPrefix) {
if (HasREX_WPrefix && HasOpSizePrefix)
insnContext = IC_64BIT_REXW_OPSIZE;
else if (HasOpSizePrefix && (Prefix == X86Local::XD ||
Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD))
Craig Topper
committed
insnContext = IC_64BIT_XD_OPSIZE;
else if (HasOpSizePrefix &&
(Prefix == X86Local::XS || Prefix == X86Local::T8XS))
Craig Topper
committed
insnContext = IC_64BIT_XS_OPSIZE;
else if (HasOpSizePrefix)
insnContext = IC_64BIT_OPSIZE;
Craig Topper
committed
else if (HasAdSizePrefix)
insnContext = IC_64BIT_ADSIZE;
else if (HasREX_WPrefix &&
(Prefix == X86Local::XS || Prefix == X86Local::T8XS))
insnContext = IC_64BIT_REXW_XS;
else if (HasREX_WPrefix && (Prefix == X86Local::XD ||
Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD))
insnContext = IC_64BIT_REXW_XD;
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = IC_64BIT_XD;
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = IC_64BIT_XS;
else if (HasREX_WPrefix)
insnContext = IC_64BIT_REXW;
else
insnContext = IC_64BIT;
} else {
if (HasOpSizePrefix && (Prefix == X86Local::XD ||
Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD))
Craig Topper
committed
insnContext = IC_XD_OPSIZE;
else if (HasOpSizePrefix &&
(Prefix == X86Local::XS || Prefix == X86Local::T8XS))
Craig Topper
committed
insnContext = IC_XS_OPSIZE;
else if (HasOpSizePrefix)
insnContext = IC_OPSIZE;
Craig Topper
committed
else if (HasAdSizePrefix)
insnContext = IC_ADSIZE;
else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
Prefix == X86Local::TAXD)
insnContext = IC_XD;
else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS ||
Prefix == X86Local::REP)
insnContext = IC_XS;
else
insnContext = IC;
}
return insnContext;
}
RecognizableInstr::filter_ret RecognizableInstr::filter() const {
///////////////////
// FILTER_STRONG
//
// Filter out intrinsics
assert(Rec->isSubClassOf("X86Inst") && "Can only filter X86 instructions");
if (Form == X86Local::Pseudo ||
(IsCodeGenOnly && Name.find("_REV") == Name.npos &&
Name.find("INC32") == Name.npos && Name.find("DEC32") == Name.npos))
return FILTER_STRONG;
Kevin Enderby
committed
// Filter out artificial instructions but leave in the LOCK_PREFIX so it is
// printed as a separate "instruction".
if (Name.find("_Int") != Name.npos ||
Craig Topper
committed
Name.find("Int_") != Name.npos)
return FILTER_STRONG;
// Filter out instructions with segment override prefixes.
// They're too messy to handle now and we'll special case them if needed.
if (SegOvr)
return FILTER_STRONG;
/////////////////
// FILTER_WEAK
//
// Filter out instructions with a LOCK prefix;
// prefer forms that do not have the prefix
if (HasLockPrefix)
return FILTER_WEAK;
// Filter out alternate forms of AVX instructions
if (Name.find("_alt") != Name.npos ||
Name.find("XrYr") != Name.npos ||
Craig Topper
committed
(Name.find("r64r") != Name.npos && Name.find("r64r64") == Name.npos) ||
Name.find("_64mr") != Name.npos ||
Name.find("Xrr") != Name.npos ||
Name.find("rr64") != Name.npos)
return FILTER_WEAK;
// Special cases.
if (Name.find("PCMPISTRI") != Name.npos && Name != "PCMPISTRI")
return FILTER_WEAK;
if (Name.find("PCMPESTRI") != Name.npos && Name != "PCMPESTRI")
return FILTER_WEAK;
if (Name.find("MOV") != Name.npos && Name.find("r0") != Name.npos)
return FILTER_WEAK;
Craig Topper
committed
if (Name.find("MOVZ") != Name.npos && Name.find("MOVZX") == Name.npos &&
Name != "MOVZPQILo2PQIrr")
return FILTER_WEAK;
if (Name.find("Fs") != Name.npos)
return FILTER_WEAK;
if (Name == "PUSH64i16" ||
Name == "MOVPQI2QImr" ||
Name == "VMOVPQI2QImr" ||
Name == "MMX_MOVD64rrv164" ||
Name == "MOV64ri64i32" ||
Name == "VMASKMOVDQU64" ||
Name == "VEXTRACTPSrr64" ||
Name == "VMOVQd64rr" ||
Name == "VMOVQs64rr")
return FILTER_WEAK;
// XACQUIRE and XRELEASE reuse REPNE and REP respectively.
// For now, just prefer the REP versions.
if (Name == "XACQUIRE_PREFIX" ||
Name == "XRELEASE_PREFIX")
return FILTER_WEAK;
if (HasFROperands && Name.find("MOV") != Name.npos &&
((Name.find("2") != Name.npos && Name.find("32") == Name.npos) ||
(Name.find("to") != Name.npos)))
Craig Topper
committed
return FILTER_STRONG;
return FILTER_NORMAL;
}
bool RecognizableInstr::hasFROperands() const {
const std::vector<CGIOperandList::OperandInfo> &OperandList = *Operands;
unsigned numOperands = OperandList.size();
for (unsigned operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
const std::string &recName = OperandList[operandIndex].Rec->getName();
if (recName.find("FR") != recName.npos)
return true;
}
return false;
}
Craig Topper
committed
void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex,
unsigned &physicalOperandIndex,
unsigned &numPhysicalOperands,
const unsigned *operandMapping,
OperandEncoding (*encodingFromString)
(const std::string&,
bool hasOpSizePrefix)) {
if (optional) {
if (physicalOperandIndex >= numPhysicalOperands)
return;
} else {
assert(physicalOperandIndex < numPhysicalOperands);
}
while (operandMapping[operandIndex] != operandIndex) {
Spec->operands[operandIndex].encoding = ENCODING_DUP;
Spec->operands[operandIndex].type =
(OperandType)(TYPE_DUP0 + operandMapping[operandIndex]);
++operandIndex;
}
const std::string &typeName = (*Operands)[operandIndex].Rec->getName();
Spec->operands[operandIndex].encoding = encodingFromString(typeName,
HasOpSizePrefix);
Spec->operands[operandIndex].type = typeFromString(typeName,
IsSSE,
HasREX_WPrefix,
HasOpSizePrefix);
++operandIndex;
++physicalOperandIndex;
}
void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
Spec->name = Name;
if (!ShouldBeEmitted)
return;
switch (filter()) {
case FILTER_WEAK:
Spec->filtered = true;
break;
case FILTER_STRONG:
ShouldBeEmitted = false;
return;
case FILTER_NORMAL:
break;
}
Spec->insnContext = insnContext();
const std::vector<CGIOperandList::OperandInfo> &OperandList = *Operands;
unsigned numOperands = OperandList.size();
unsigned numPhysicalOperands = 0;
// operandMapping maps from operands in OperandList to their originals.
// If operandMapping[i] != i, then the entry is a duplicate.
unsigned operandMapping[X86_MAX_OPERANDS];
assert(numOperands <= X86_MAX_OPERANDS && "X86_MAX_OPERANDS is not large enough");
Craig Topper
committed
for (unsigned operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
if (OperandList[operandIndex].Constraints.size()) {
const CGIOperandList::ConstraintInfo &Constraint =
OperandList[operandIndex].Constraints[0];
if (Constraint.isTied()) {
Craig Topper
committed
operandMapping[operandIndex] = operandIndex;
operandMapping[Constraint.getTiedOperand()] = operandIndex;
} else {
++numPhysicalOperands;
operandMapping[operandIndex] = operandIndex;
}
} else {
++numPhysicalOperands;
operandMapping[operandIndex] = operandIndex;
}
}
#define HANDLE_OPERAND(class) \
handleOperand(false, \
operandIndex, \
physicalOperandIndex, \
numPhysicalOperands, \
operandMapping, \
class##EncodingFromString);
#define HANDLE_OPTIONAL(class) \
handleOperand(true, \
operandIndex, \
physicalOperandIndex, \
numPhysicalOperands, \
operandMapping, \
class##EncodingFromString);
// operandIndex should always be < numOperands
Craig Topper
committed
unsigned operandIndex = 0;
// physicalOperandIndex should always be < numPhysicalOperands
unsigned physicalOperandIndex = 0;
switch (Form) {
case X86Local::RawFrm:
// Operand 1 (optional) is an address or immediate.
// Operand 2 (optional) is an immediate.
"Unexpected number of operands for RawFrm");
HANDLE_OPTIONAL(relocation)
HANDLE_OPTIONAL(immediate)
break;
case X86Local::AddRegFrm:
// Operand 1 is added to the opcode.
// Operand 2 (optional) is an address.
assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 &&
"Unexpected number of operands for AddRegFrm");
HANDLE_OPERAND(opcodeModifier)
HANDLE_OPTIONAL(relocation)
break;
case X86Local::MRMDestReg:
// Operand 1 is a register operand in the R/M field.
// Operand 2 is a register operand in the Reg/Opcode field.
// - In AVX, there is a register operand in the VEX.vvvv field here -
// Operand 3 (optional) is an immediate.
if (HasVEX_4VPrefix)
assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 4 &&
"Unexpected number of operands for MRMDestRegFrm with VEX_4V");
else
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMDestRegFrm");
HANDLE_OPERAND(rmRegister)
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
HANDLE_OPERAND(roRegister)
HANDLE_OPTIONAL(immediate)
break;
case X86Local::MRMDestMem:
// Operand 1 is a memory operand (possibly SIB-extended)
// Operand 2 is a register operand in the Reg/Opcode field.
// - In AVX, there is a register operand in the VEX.vvvv field here -
// Operand 3 (optional) is an immediate.
if (HasVEX_4VPrefix)
assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 4 &&
"Unexpected number of operands for MRMDestMemFrm with VEX_4V");
else
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMDestMemFrm");
HANDLE_OPERAND(memory)
if (HasEVEX_K)
HANDLE_OPERAND(writemaskRegister)
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
HANDLE_OPERAND(roRegister)
HANDLE_OPTIONAL(immediate)
break;
case X86Local::MRMSrcReg:
// Operand 1 is a register operand in the Reg/Opcode field.
// Operand 2 is a register operand in the R/M field.
// - In AVX, there is a register operand in the VEX.vvvv field here -
// Operand 3 (optional) is an immediate.
Benjamin Kramer
committed
// Operand 4 (optional) is an immediate.
if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix)
assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 5 &&
"Unexpected number of operands for MRMSrcRegFrm with VEX_4V");
Benjamin Kramer
committed
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 4 &&
"Unexpected number of operands for MRMSrcRegFrm");
HANDLE_OPERAND(roRegister)
Craig Topper
committed
if (HasEVEX_K)
HANDLE_OPERAND(writemaskRegister)
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
Craig Topper
committed
if (HasMemOp4Prefix)
HANDLE_OPERAND(immediate)
HANDLE_OPERAND(rmRegister)
Craig Topper
committed
if (HasVEX_4VOp3Prefix)
Craig Topper
committed
HANDLE_OPERAND(vvvvRegister)
if (!HasMemOp4Prefix)
HANDLE_OPTIONAL(immediate)
HANDLE_OPTIONAL(immediate) // above might be a register in 7:4
Benjamin Kramer
committed
HANDLE_OPTIONAL(immediate)
break;
case X86Local::MRMSrcMem:
// Operand 1 is a register operand in the Reg/Opcode field.
// Operand 2 is a memory operand (possibly SIB-extended)
// - In AVX, there is a register operand in the VEX.vvvv field here -
// Operand 3 (optional) is an immediate.
if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix)
assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 5 &&
"Unexpected number of operands for MRMSrcMemFrm with VEX_4V");
else
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMSrcMemFrm");
HANDLE_OPERAND(roRegister)
if (HasEVEX_K)
HANDLE_OPERAND(writemaskRegister)
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
if (HasMemOp4Prefix)
HANDLE_OPERAND(immediate)
HANDLE_OPERAND(memory)
Craig Topper
committed
if (HasVEX_4VOp3Prefix)
Craig Topper
committed
HANDLE_OPERAND(vvvvRegister)
if (!HasMemOp4Prefix)
HANDLE_OPTIONAL(immediate)
HANDLE_OPTIONAL(immediate) // above might be a register in 7:4
break;
case X86Local::MRM0r:
case X86Local::MRM1r:
case X86Local::MRM2r:
case X86Local::MRM3r:
case X86Local::MRM4r:
case X86Local::MRM5r:
case X86Local::MRM6r:
case X86Local::MRM7r:
{
// Operand 1 is a register operand in the R/M field.
// Operand 2 (optional) is an immediate or relocation.
// Operand 3 (optional) is an immediate.
unsigned kOp = (HasEVEX_K) ? 1:0;
unsigned Op4v = (HasVEX_4VPrefix) ? 1:0;
if (numPhysicalOperands > 3 + kOp + Op4v)
llvm_unreachable("Unexpected number of operands for MRMnr");
}
if (HasVEX_4VPrefix)
Craig Topper
committed
HANDLE_OPERAND(vvvvRegister)
if (HasEVEX_K)
HANDLE_OPERAND(writemaskRegister)
HANDLE_OPTIONAL(rmRegister)
HANDLE_OPTIONAL(relocation)
Benjamin Kramer
committed
HANDLE_OPTIONAL(immediate)
break;
case X86Local::MRM0m:
case X86Local::MRM1m:
case X86Local::MRM2m:
case X86Local::MRM3m:
case X86Local::MRM4m:
case X86Local::MRM5m:
case X86Local::MRM6m:
case X86Local::MRM7m:
{
// Operand 1 is a memory operand (possibly SIB-extended)
// Operand 2 (optional) is an immediate or relocation.
unsigned kOp = (HasEVEX_K) ? 1:0;
unsigned Op4v = (HasVEX_4VPrefix) ? 1:0;
if (numPhysicalOperands < 1 + kOp + Op4v ||
numPhysicalOperands > 2 + kOp + Op4v)
llvm_unreachable("Unexpected number of operands for MRMnm");
}
Craig Topper
committed
if (HasVEX_4VPrefix)
HANDLE_OPERAND(vvvvRegister)
if (HasEVEX_K)
HANDLE_OPERAND(writemaskRegister)
HANDLE_OPERAND(memory)
HANDLE_OPTIONAL(relocation)
break;
case X86Local::RawFrmImm8:
// operand 1 is a 16-bit immediate
// operand 2 is an 8-bit immediate
assert(numPhysicalOperands == 2 &&
"Unexpected number of operands for X86Local::RawFrmImm8");
HANDLE_OPERAND(immediate)
HANDLE_OPERAND(immediate)
break;
case X86Local::RawFrmImm16:
// operand 1 is a 16-bit immediate
// operand 2 is a 16-bit immediate
HANDLE_OPERAND(immediate)
HANDLE_OPERAND(immediate)
break;
case X86Local::MRM_F8:
if (Opcode == 0xc6) {
assert(numPhysicalOperands == 1 &&
"Unexpected number of operands for X86Local::MRM_F8");
HANDLE_OPERAND(immediate)
} else if (Opcode == 0xc7) {
assert(numPhysicalOperands == 1 &&
"Unexpected number of operands for X86Local::MRM_F8");
HANDLE_OPERAND(relocation)
}
break;
case X86Local::MRMInitReg:
// Ignored.
break;
}
#undef HANDLE_OPERAND
#undef HANDLE_OPTIONAL
}
void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
// Special cases where the LLVM tables are not complete
#define MAP(from, to) \
case X86Local::MRM_##from: \
filter = new ExactFilter(0x##from); \
break;
OpcodeType opcodeType = (OpcodeType)-1;
uint8_t opcodeToSet = 0;
switch (Prefix) {
default: llvm_unreachable("Invalid prefix!");
// Extended two-byte opcodes can start with f2 0f, f3 0f, or 0f
case X86Local::XD:
case X86Local::XS:
case X86Local::TB:
opcodeType = TWOBYTE;
switch (Opcode) {
default:
if (needsModRMForDecode(Form))
filter = new ModFilter(isRegFormat(Form));
else
filter = new DumbFilter();
break;
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
#define EXTENSION_TABLE(n) case 0x##n:
TWO_BYTE_EXTENSION_TABLES
#undef EXTENSION_TABLE
switch (Form) {
default:
llvm_unreachable("Unhandled two-byte extended opcode");
case X86Local::MRM0r:
case X86Local::MRM1r:
case X86Local::MRM2r:
case X86Local::MRM3r:
case X86Local::MRM4r:
case X86Local::MRM5r:
case X86Local::MRM6r:
case X86Local::MRM7r:
filter = new ExtendedFilter(true, Form - X86Local::MRM0r);
break;
case X86Local::MRM0m:
case X86Local::MRM1m:
case X86Local::MRM2m:
case X86Local::MRM3m:
case X86Local::MRM4m:
case X86Local::MRM5m:
case X86Local::MRM6m:
case X86Local::MRM7m:
filter = new ExtendedFilter(false, Form - X86Local::MRM0m);
break;
} // switch (Form)
break;
opcodeToSet = Opcode;
break;
case X86Local::T8:
case X86Local::T8XD:
case X86Local::T8XS:
opcodeType = THREEBYTE_38;
Craig Topper
committed
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
switch (Opcode) {
default:
if (needsModRMForDecode(Form))
filter = new ModFilter(isRegFormat(Form));
else
filter = new DumbFilter();
break;
#define EXTENSION_TABLE(n) case 0x##n:
THREE_BYTE_38_EXTENSION_TABLES
#undef EXTENSION_TABLE
switch (Form) {
default:
llvm_unreachable("Unhandled two-byte extended opcode");
case X86Local::MRM0r:
case X86Local::MRM1r:
case X86Local::MRM2r:
case X86Local::MRM3r:
case X86Local::MRM4r:
case X86Local::MRM5r:
case X86Local::MRM6r:
case X86Local::MRM7r:
filter = new ExtendedFilter(true, Form - X86Local::MRM0r);
break;
case X86Local::MRM0m:
case X86Local::MRM1m:
case X86Local::MRM2m:
case X86Local::MRM3m:
case X86Local::MRM4m:
case X86Local::MRM5m:
case X86Local::MRM6m:
case X86Local::MRM7m:
filter = new ExtendedFilter(false, Form - X86Local::MRM0m);
break;