mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-03 00:47:07 +00:00
[X86] Add a new disassembler opcode map for 3DNow. Stop treating 3DNow as an attribute.
This reduces the size of llvm-mc by at least 150k since we no longer have to multiply the attribute across 7 tables. llvm-svn: 328416
This commit is contained in:
parent
55eeee33ff
commit
16ecfc9764
@ -31,6 +31,7 @@ namespace X86Disassembler {
|
||||
#define XOP8_MAP_SYM x86DisassemblerXOP8Opcodes
|
||||
#define XOP9_MAP_SYM x86DisassemblerXOP9Opcodes
|
||||
#define XOPA_MAP_SYM x86DisassemblerXOPAOpcodes
|
||||
#define THREEDNOW_MAP_SYM x86Disassembler3DNowOpcodes
|
||||
|
||||
#define INSTRUCTIONS_STR "x86DisassemblerInstrSpecifiers"
|
||||
#define CONTEXTS_STR "x86DisassemblerContexts"
|
||||
@ -41,6 +42,7 @@ namespace X86Disassembler {
|
||||
#define XOP8_MAP_STR "x86DisassemblerXOP8Opcodes"
|
||||
#define XOP9_MAP_STR "x86DisassemblerXOP9Opcodes"
|
||||
#define XOPA_MAP_STR "x86DisassemblerXOPAOpcodes"
|
||||
#define THREEDNOW_MAP_STR "x86Disassembler3DNowOpcodes"
|
||||
|
||||
// Attributes of an instruction that must be known before the opcode can be
|
||||
// processed correctly. Most of these indicate the presence of particular
|
||||
@ -60,8 +62,7 @@ namespace X86Disassembler {
|
||||
ENUM_ENTRY(ATTR_EVEXL2, (0x1 << 10)) \
|
||||
ENUM_ENTRY(ATTR_EVEXK, (0x1 << 11)) \
|
||||
ENUM_ENTRY(ATTR_EVEXKZ, (0x1 << 12)) \
|
||||
ENUM_ENTRY(ATTR_EVEXB, (0x1 << 13)) \
|
||||
ENUM_ENTRY(ATTR_3DNOW, (0x1 << 14))
|
||||
ENUM_ENTRY(ATTR_EVEXB, (0x1 << 13))
|
||||
|
||||
#define ENUM_ENTRY(n, v) n = v,
|
||||
enum attributeBits {
|
||||
@ -271,8 +272,7 @@ enum attributeBits {
|
||||
ENUM_ENTRY(IC_EVEX_L2_W_KZ, 3, "requires EVEX_KZ, L2 and W") \
|
||||
ENUM_ENTRY(IC_EVEX_L2_W_XS_KZ, 4, "requires EVEX_KZ, L2, W and XS prefix") \
|
||||
ENUM_ENTRY(IC_EVEX_L2_W_XD_KZ, 4, "requires EVEX_KZ, L2, W and XD prefix") \
|
||||
ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, W and OpSize") \
|
||||
ENUM_ENTRY(IC_3DNOW, 8, "requires AMD 3DNow prefix 0f0f")
|
||||
ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, W and OpSize")
|
||||
|
||||
#define ENUM_ENTRY(n, r, d) n,
|
||||
enum InstructionContext {
|
||||
@ -290,7 +290,8 @@ enum OpcodeType {
|
||||
THREEBYTE_3A = 3,
|
||||
XOP8_MAP = 4,
|
||||
XOP9_MAP = 5,
|
||||
XOPA_MAP = 6
|
||||
XOPA_MAP = 6,
|
||||
THREEDNOW_MAP = 7
|
||||
};
|
||||
|
||||
// The following structs are used for the hierarchical decode table. After
|
||||
|
@ -103,6 +103,9 @@ static int modRMRequired(OpcodeType type,
|
||||
case XOPA_MAP:
|
||||
decision = &XOPA_MAP_SYM;
|
||||
break;
|
||||
case THREEDNOW_MAP:
|
||||
decision = &THREEDNOW_MAP_SYM;
|
||||
break;
|
||||
}
|
||||
|
||||
return decision->opcodeDecisions[insnContext].modRMDecisions[opcode].
|
||||
@ -147,6 +150,9 @@ static InstrUID decode(OpcodeType type,
|
||||
case XOPA_MAP:
|
||||
dec = &XOPA_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
|
||||
break;
|
||||
case THREEDNOW_MAP:
|
||||
dec = &THREEDNOW_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dec->modrm_type) {
|
||||
@ -588,44 +594,11 @@ static int readPrefixes(struct InternalInstruction* insn) {
|
||||
insn->vectorExtensionPrefix[0], insn->vectorExtensionPrefix[1],
|
||||
insn->vectorExtensionPrefix[2]);
|
||||
}
|
||||
} else if (byte == 0x0f) {
|
||||
uint8_t byte1;
|
||||
|
||||
// Check for AMD 3DNow without a REX prefix
|
||||
if (consumeByte(insn, &byte1)) {
|
||||
unconsumeByte(insn);
|
||||
} else {
|
||||
if (byte1 != 0x0f) {
|
||||
unconsumeByte(insn);
|
||||
unconsumeByte(insn);
|
||||
} else {
|
||||
dbgprintf(insn, "Found AMD 3DNow prefix 0f0f");
|
||||
insn->vectorExtensionType = TYPE_3DNOW;
|
||||
}
|
||||
}
|
||||
} else if (isREX(insn, byte)) {
|
||||
if (lookAtByte(insn, &nextByte))
|
||||
return -1;
|
||||
insn->rexPrefix = byte;
|
||||
dbgprintf(insn, "Found REX prefix 0x%hhx", byte);
|
||||
|
||||
// Check for AMD 3DNow with a REX prefix
|
||||
if (nextByte == 0x0f) {
|
||||
consumeByte(insn, &nextByte);
|
||||
uint8_t byte1;
|
||||
|
||||
if (consumeByte(insn, &byte1)) {
|
||||
unconsumeByte(insn);
|
||||
} else {
|
||||
if (byte1 != 0x0f) {
|
||||
unconsumeByte(insn);
|
||||
unconsumeByte(insn);
|
||||
} else {
|
||||
dbgprintf(insn, "Found AMD 3DNow prefix 0f0f");
|
||||
insn->vectorExtensionType = TYPE_3DNOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
unconsumeByte(insn);
|
||||
|
||||
@ -725,12 +698,6 @@ static int readOpcode(struct InternalInstruction* insn) {
|
||||
insn->opcodeType = XOPA_MAP;
|
||||
return consumeByte(insn, &insn->opcode);
|
||||
}
|
||||
} else if (insn->vectorExtensionType == TYPE_3DNOW) {
|
||||
// Consume operands before the opcode to comply with the 3DNow encoding
|
||||
if (readModRM(insn))
|
||||
return -1;
|
||||
insn->opcodeType = TWOBYTE;
|
||||
return consumeByte(insn, &insn->opcode);
|
||||
}
|
||||
|
||||
if (consumeByte(insn, ¤t))
|
||||
@ -756,6 +723,17 @@ static int readOpcode(struct InternalInstruction* insn) {
|
||||
return -1;
|
||||
|
||||
insn->opcodeType = THREEBYTE_3A;
|
||||
} else if (current == 0x0f) {
|
||||
dbgprintf(insn, "Found a 3dnow escape prefix (0x%hhx)", current);
|
||||
|
||||
// Consume operands before the opcode to comply with the 3DNow encoding
|
||||
if (readModRM(insn))
|
||||
return -1;
|
||||
|
||||
if (consumeByte(insn, ¤t))
|
||||
return -1;
|
||||
|
||||
insn->opcodeType = THREEDNOW_MAP;
|
||||
} else {
|
||||
dbgprintf(insn, "Didn't find a three-byte escape prefix");
|
||||
|
||||
@ -951,8 +929,6 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) {
|
||||
|
||||
if (lFromXOP3of3(insn->vectorExtensionPrefix[2]))
|
||||
attrMask |= ATTR_VEXL;
|
||||
} else if (insn->vectorExtensionType == TYPE_3DNOW) {
|
||||
attrMask |= ATTR_3DNOW;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
@ -493,8 +493,7 @@ enum VectorExtensionType {
|
||||
TYPE_VEX_2B = 0x1,
|
||||
TYPE_VEX_3B = 0x2,
|
||||
TYPE_EVEX = 0x3,
|
||||
TYPE_XOP = 0x4,
|
||||
TYPE_3DNOW = 0x5
|
||||
TYPE_XOP = 0x4
|
||||
};
|
||||
|
||||
/// \brief Type for the byte reader that the consumer must provide to
|
||||
|
@ -546,8 +546,6 @@ static inline bool inheritsFrom(InstructionContext child,
|
||||
case IC_EVEX_L2_W_XD_KZ_B:
|
||||
case IC_EVEX_L2_W_OPSIZE_KZ_B:
|
||||
return false;
|
||||
case IC_3DNOW:
|
||||
return false;
|
||||
default:
|
||||
errs() << "Unknown instruction class: " <<
|
||||
stringForContext((InstructionContext)parent) << "\n";
|
||||
@ -882,7 +880,7 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o,
|
||||
}
|
||||
|
||||
void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
|
||||
const unsigned int tableSize = 32768;
|
||||
const unsigned int tableSize = 16384;
|
||||
o.indent(i * 2) << "static const uint8_t " CONTEXTS_STR
|
||||
"[" << tableSize << "] = {\n";
|
||||
i++;
|
||||
@ -890,9 +888,7 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
|
||||
for (unsigned index = 0; index < tableSize; ++index) {
|
||||
o.indent(i * 2);
|
||||
|
||||
if (index & ATTR_3DNOW)
|
||||
o << "IC_3DNOW";
|
||||
else if (index & ATTR_EVEX) {
|
||||
if (index & ATTR_EVEX) {
|
||||
o << "IC_EVEX";
|
||||
if (index & ATTR_EVEXL2)
|
||||
o << "_L2";
|
||||
@ -1015,6 +1011,7 @@ void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2,
|
||||
emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[4], XOP8_MAP_STR);
|
||||
emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[5], XOP9_MAP_STR);
|
||||
emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[6], XOPA_MAP_STR);
|
||||
emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[7], THREEDNOW_MAP_STR);
|
||||
}
|
||||
|
||||
void DisassemblerTables::emit(raw_ostream &o) const {
|
||||
|
@ -41,7 +41,8 @@ private:
|
||||
/// [4] XOP8 map opcode
|
||||
/// [5] XOP9 map opcode
|
||||
/// [6] XOPA map opcode
|
||||
std::unique_ptr<ContextDecision> Tables[7];
|
||||
/// [7] 3dnow map opcode
|
||||
std::unique_ptr<ContextDecision> Tables[8];
|
||||
|
||||
// Table of ModRM encodings.
|
||||
typedef std::map<std::vector<unsigned>, unsigned> ModRMMapTy;
|
||||
|
@ -288,8 +288,6 @@ InstructionContext RecognizableInstr::insnContext() const {
|
||||
errs() << "Instruction does not use a prefix: " << Name << "\n";
|
||||
llvm_unreachable("Invalid prefix");
|
||||
}
|
||||
} else if (OpMap == X86Local::ThreeDNow) {
|
||||
insnContext = IC_3DNOW;
|
||||
} else if (Is64Bit || HasREX_WPrefix || AdSize == X86Local::AdSize64) {
|
||||
if (HasREX_WPrefix && (OpSize == X86Local::OpSize16 || OpPrefix == X86Local::PD))
|
||||
insnContext = IC_64BIT_REXW_OPSIZE;
|
||||
@ -685,14 +683,14 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
|
||||
llvm::Optional<OpcodeType> opcodeType;
|
||||
switch (OpMap) {
|
||||
default: llvm_unreachable("Invalid map!");
|
||||
case X86Local::OB: opcodeType = ONEBYTE; break;
|
||||
case X86Local::TB: opcodeType = TWOBYTE; break;
|
||||
case X86Local::T8: opcodeType = THREEBYTE_38; break;
|
||||
case X86Local::TA: opcodeType = THREEBYTE_3A; break;
|
||||
case X86Local::XOP8: opcodeType = XOP8_MAP; break;
|
||||
case X86Local::XOP9: opcodeType = XOP9_MAP; break;
|
||||
case X86Local::XOPA: opcodeType = XOPA_MAP; break;
|
||||
case X86Local::ThreeDNow: opcodeType = TWOBYTE; break;
|
||||
case X86Local::OB: opcodeType = ONEBYTE; break;
|
||||
case X86Local::TB: opcodeType = TWOBYTE; break;
|
||||
case X86Local::T8: opcodeType = THREEBYTE_38; break;
|
||||
case X86Local::TA: opcodeType = THREEBYTE_3A; break;
|
||||
case X86Local::XOP8: opcodeType = XOP8_MAP; break;
|
||||
case X86Local::XOP9: opcodeType = XOP9_MAP; break;
|
||||
case X86Local::XOPA: opcodeType = XOPA_MAP; break;
|
||||
case X86Local::ThreeDNow: opcodeType = THREEDNOW_MAP; break;
|
||||
}
|
||||
|
||||
std::unique_ptr<ModRMFilter> filter;
|
||||
|
Loading…
Reference in New Issue
Block a user