"llvm/git@repo.hca.bsc.es:rferrer/llvm-epi-0.8.git" did not exist on "f3f4ad9dd6124555f58b5dae1b6dd46cd8f42ed0"
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
};
}
// 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)
using namespace X86Disassembler;
/// needsModRMForDecode - Indicates whether a particular instruction requires a
/// ModR/M byte for the instruction to be properly decoded. For example, a
141
142
143
144
145
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
/// 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");
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);
}
InstructionContext RecognizableInstr::insnContext() const {
InstructionContext insnContext;
if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix|| HasVEXPrefix) {
if (HasVEX_LPrefix && HasVEX_WPrefix) {
if (HasOpSizePrefix)
insnContext = IC_VEX_L_W_OPSIZE;
else
llvm_unreachable("Don't support VEX.L and VEX.W together");
} 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 ||
Craig Topper
committed
(IsCodeGenOnly && Name.find("_REV") == 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;
if (Name.find("MOVZ") != Name.npos && Name.find("MOVZX") == Name.npos)
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 (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 (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 (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.
Benjamin Kramer
committed
// Operand 3 (optional) is an immediate.
if (HasVEX_4VPrefix)
assert(numPhysicalOperands <= 3 &&
Craig Topper
committed
"Unexpected number of operands for MRMnRFrm with VEX_4V");
Benjamin Kramer
committed
assert(numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMnRFrm");
if (HasVEX_4VPrefix)
Craig Topper
committed
HANDLE_OPERAND(vvvvRegister)
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.
Craig Topper
committed
if (HasVEX_4VPrefix)
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMnMFrm");
else
assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 &&
"Unexpected number of operands for MRMnMFrm");
if (HasVEX_4VPrefix)
HANDLE_OPERAND(vvvvRegister)
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) {
// 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;
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
#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
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
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;
MRM_MAPPING
} // switch (Form)
break;
} // switch (Opcode)
opcodeToSet = Opcode;
break;
case X86Local::P_TA:
opcodeType = THREEBYTE_3A;
if (needsModRMForDecode(Form))
filter = new ModFilter(isRegFormat(Form));
else
filter = new DumbFilter();
opcodeToSet = Opcode;
break;
case X86Local::A6:
opcodeType = THREEBYTE_A6;
if (needsModRMForDecode(Form))
filter = new ModFilter(isRegFormat(Form));
else
filter = new DumbFilter();
opcodeToSet = Opcode;
break;
case X86Local::A7:
opcodeType = THREEBYTE_A7;
if (needsModRMForDecode(Form))
filter = new ModFilter(isRegFormat(Form));
else
filter = new DumbFilter();
opcodeToSet = Opcode;
break;
case X86Local::D8:
case X86Local::D9:
case X86Local::DA:
case X86Local::DB:
case X86Local::DC:
case X86Local::DD:
case X86Local::DE:
case X86Local::DF:
assert(Opcode >= 0xc0 && "Unexpected opcode for an escape opcode");
opcodeType = ONEBYTE;
if (Form == X86Local::AddRegFrm) {
Spec->modifierType = MODIFIER_MODRM;
Spec->modifierBase = Opcode;
filter = new AddRegEscapeFilter(Opcode);
} else {
filter = new EscapeFilter(true, Opcode);
}
opcodeToSet = 0xd8 + (Prefix - X86Local::D8);
break;
case X86Local::REP:
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
default:
opcodeType = ONEBYTE;
switch (Opcode) {
#define EXTENSION_TABLE(n) case 0x##n:
ONE_BYTE_EXTENSION_TABLES
#undef EXTENSION_TABLE
switch (Form) {
default:
llvm_unreachable("Fell through the cracks of a single-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;
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 (Form)
break;
case 0xd8:
case 0xd9:
case 0xda:
case 0xdb:
case 0xdc:
case 0xdd:
case 0xde:
case 0xdf:
filter = new EscapeFilter(false, Form - X86Local::MRM0m);
break;
default:
if (needsModRMForDecode(Form))
filter = new ModFilter(isRegFormat(Form));
else
filter = new DumbFilter();
break;
} // switch (Opcode)
opcodeToSet = Opcode;
} // switch (Prefix)
assert(opcodeType != (OpcodeType)-1 &&
"Opcode type not set");
assert(filter && "Filter not set");
if (Form == X86Local::AddRegFrm) {