[X86][3DNOW] Teach decoder about AMD 3DNow! instrs
Summary:
This patch makes the decoder understand old AMD 3DNow!
instructions that have never been properly supported in the X86
disassembler, despite being supported in other subsystems. Hopefully
this should make the X86 decoder more complete with respect to binaries
containing legacy code.
Reviewers: craig.topper
Reviewed By: craig.topper
Subscribers: llvm-commits, maksfb, bruno
Differential Revision: https://reviews.llvm.org/D43311
llvm-svn: 325295
diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
index 843d037..50d10fe 100644
--- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
+++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
@@ -588,11 +588,44 @@
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);
@@ -623,6 +656,8 @@
return 0;
}
+static int readModRM(struct InternalInstruction* insn);
+
/*
* readOpcode - Reads the opcode (excepting the ModR/M byte in the case of
* extended or escape opcodes).
@@ -690,6 +725,12 @@
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))
@@ -735,8 +776,6 @@
return 0;
}
-static int readModRM(struct InternalInstruction* insn);
-
/*
* getIDWithAttrMask - Determines the ID of an instruction, consuming
* the ModR/M byte as appropriate for extended and escape opcodes,
@@ -912,6 +951,8 @@
if (lFromXOP3of3(insn->vectorExtensionPrefix[2]))
attrMask |= ATTR_VEXL;
+ } else if (insn->vectorExtensionType == TYPE_3DNOW) {
+ attrMask |= ATTR_3DNOW;
} else {
return -1;
}
diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
index ecd9d8d..1be3c43 100644
--- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
+++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
@@ -493,7 +493,8 @@
TYPE_VEX_2B = 0x1,
TYPE_VEX_3B = 0x2,
TYPE_EVEX = 0x3,
- TYPE_XOP = 0x4
+ TYPE_XOP = 0x4,
+ TYPE_3DNOW = 0x5
};
/// \brief Type for the byte reader that the consumer must provide to
diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h
index ad14048..ffac6c9 100644
--- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h
+++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h
@@ -60,7 +60,8 @@
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_EVEXB, (0x1 << 13)) \
+ ENUM_ENTRY(ATTR_3DNOW, (0x1 << 14))
#define ENUM_ENTRY(n, v) n = v,
enum attributeBits {
@@ -270,7 +271,8 @@
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_EVEX_L2_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, W and OpSize") \
+ ENUM_ENTRY(IC_3DNOW, 8, "requires AMD 3DNow prefix 0f0f")
#define ENUM_ENTRY(n, r, d) n,
enum InstructionContext {
diff --git a/llvm/lib/Target/X86/X86Instr3DNow.td b/llvm/lib/Target/X86/X86Instr3DNow.td
index d2e5980..edb7dd6 100644
--- a/llvm/lib/Target/X86/X86Instr3DNow.td
+++ b/llvm/lib/Target/X86/X86Instr3DNow.td
@@ -52,8 +52,6 @@
: I3DNow<o, F, (outs VR64:$dst), ins,
!strconcat(Mnemonic, "\t{$src2, $dst|$dst, $src2}"), pat, itin>,
Has3DNow0F0FOpcode {
- // FIXME: The disassembler doesn't support Has3DNow0F0FOpcode yet.
- let isAsmParserOnly = 1;
let Constraints = "$src1 = $dst";
}
@@ -61,10 +59,7 @@
InstrItinClass itin>
: I3DNow<o, F, (outs VR64:$dst), ins,
!strconcat(Mnemonic, "\t{$src, $dst|$dst, $src}"), pat, itin>,
- Has3DNow0F0FOpcode {
- // FIXME: The disassembler doesn't support Has3DNow0F0FOpcode yet.
- let isAsmParserOnly = 1;
-}
+ Has3DNow0F0FOpcode;
multiclass I3DNow_binop_rm_int<bits<8> opc, string Mn, OpndItins itins,
bit Commutable = 0, string Ver = ""> {