aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG2
-rw-r--r--src/long_mode/vex.rs34
-rw-r--r--test/long_mode/mod.rs2
-rw-r--r--test/long_mode/operand.rs4
4 files changed, 33 insertions, 9 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 7ceeef0..1aed610 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -26,6 +26,8 @@
vcvtph2ps, vbroadcastf128, vmaskmovps, vmaskmovpd, vpermd, vpbroadcast{b,w,d,q}, among others
* vpbroadcastb and vpbroadcastw should respect the L bit to select xmm/ymm vector width, but
always decoded as ymm.
+* vmaskmovqdu now reports a memory access size for the implied write to ds:[rdi/edi/di].
+* correct swapped operand order of 0xD6-opcode movq.
## 2.0.0
diff --git a/src/long_mode/vex.rs b/src/long_mode/vex.rs
index b43b0fe..1d94b3c 100644
--- a/src/long_mode/vex.rs
+++ b/src/long_mode/vex.rs
@@ -46,7 +46,7 @@ enum VEXOperandCode {
VMOVHPS_16,
M_G_xmm,
G_M_xmm,
- G_U_xmm,
+ G_U_xmm_vmaskmovdqu,
Gd_U_xmm,
E_G_xmm_imm8,
Ud_G_xmm_imm8,
@@ -857,17 +857,12 @@ fn read_vex_operands<
}
op @ VEXOperandCode::G_M_xmm |
- op @ VEXOperandCode::G_U_xmm |
op @ VEXOperandCode::G_E_xmm => {
if instruction.regs[3].num != 0 {
return Err(DecodeError::InvalidOperand);
}
let modrm = read_modrm(words)?;
match (op, modrm & 0xc0) {
- (VEXOperandCode::G_U_xmm, 0xc0) => {
- /* this is the only accepted operand */
- }
- (VEXOperandCode::G_U_xmm, _) |
(VEXOperandCode::G_M_xmm, 0xc0) => {
return Err(DecodeError::InvalidOperand);
}
@@ -893,6 +888,27 @@ fn read_vex_operands<
instruction.operand_count = 2;
Ok(())
}
+ VEXOperandCode::G_U_xmm_vmaskmovdqu => {
+ if instruction.regs[3].num != 0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(words)?;
+ if modrm & 0xc0 != 0xc0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.regs[0] =
+ RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X);
+ let mem_oper = read_E_xmm(words, instruction, modrm, sink)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ if instruction.prefixes.address_size() {
+ instruction.mem_size = 4;
+ } else {
+ instruction.mem_size = 8;
+ }
+ instruction.operand_count = 2;
+ Ok(())
+ }
VEXOperandCode::G_xmm_E_xmm => {
if instruction.regs[3].num != 0 {
return Err(DecodeError::InvalidOperand);
@@ -1113,7 +1129,7 @@ fn read_vex_operands<
RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), bank);
let mem_oper = read_E(words, instruction, modrm, bank, sink)?;
if mem_oper != OperandSpec::RegMMM {
- if instruction.opcode == Opcode::VMOVLPD || instruction.opcode == Opcode::VMOVHPD || instruction.opcode == Opcode::VMOVHPS {
+ if instruction.opcode == Opcode::VMOVLPD || instruction.opcode == Opcode::VMOVHPD || instruction.opcode == Opcode::VMOVHPS || instruction.opcode == Opcode::VMOVQ {
instruction.mem_size = 8;
} else {
if L {
@@ -1889,7 +1905,7 @@ fn read_vex_instruction<
0xD6 => (Opcode::VMOVQ, if L {
return Err(DecodeError::InvalidOpcode);
} else {
- VEXOperandCode::G_E_xmm
+ VEXOperandCode::E_G_xyLmm
}),
0xD7 => (Opcode::VPMOVMSKB, VEXOperandCode::Ud_G_xyLmm),
0xD8 => (Opcode::VPSUBUSB, VEXOperandCode::G_V_E_xyLmm),
@@ -1949,7 +1965,7 @@ fn read_vex_instruction<
0xF7 => (Opcode::VMASKMOVDQU, if L {
return Err(DecodeError::InvalidOpcode);
} else {
- VEXOperandCode::G_U_xmm
+ VEXOperandCode::G_U_xmm_vmaskmovdqu
}),
0xF8 => (Opcode::VPSUBB, VEXOperandCode::G_V_E_xyLmm),
0xF9 => (Opcode::VPSUBW, VEXOperandCode::G_V_E_xyLmm),
diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs
index 9ad0df4..1524868 100644
--- a/test/long_mode/mod.rs
+++ b/test/long_mode/mod.rs
@@ -2339,6 +2339,8 @@ fn test_vex() {
test_avx2(&[0xc4, 0b000_00001, 0b1_1111_101, 0x6d, 0b11_001_010], "vpunpckhqdq ymm9, ymm0, ymm10");
test_instr(&[0xc4, 0b000_00001, 0b1_1111_001, 0x6e, 0b11_001_010], "vmovq xmm9, r10");
test_instr(&[0xc4, 0b000_00001, 0b1_1111_001, 0x6e, 0b00_001_010], "vmovq xmm9, qword [r10]");
+ test_instr(&[0xc4, 0b000_00001, 0b1_1111_001, 0xd6, 0b00_001_010], "vmovq qword [r10], xmm9");
+ test_instr(&[0xc4, 0b000_00001, 0b1_1111_001, 0xd6, 0b11_001_010], "vmovq xmm10, xmm9");
test_invalid(&[0xc4, 0b000_00001, 0b1_1111_101, 0x6e, 0b11_001_010]);
test_instr(&[0xc4, 0b000_00001, 0b0_1111_001, 0x6f, 0b11_001_010], "vmovdqa xmm9, xmm10");
test_instr(&[0xc4, 0b000_00001, 0b0_1111_101, 0x6f, 0b11_001_010], "vmovdqa ymm9, ymm10");
diff --git a/test/long_mode/operand.rs b/test/long_mode/operand.rs
index fe64fb6..a1d80e8 100644
--- a/test/long_mode/operand.rs
+++ b/test/long_mode/operand.rs
@@ -37,6 +37,10 @@ fn memory_widths() {
// "maskmovdqu xmm0, xmm1"
assert_eq!(mem_size_of(&[0x66, 0x4f, 0x0f, 0xf7, 0xc1]).size_name(), "qword");
assert_eq!(mem_size_of(&[0x67, 0x66, 0x0f, 0xf7, 0xc1]).size_name(), "dword");
+
+ // "vmaskmovdqu xmm0, xmm1"
+ assert_eq!(mem_size_of(&[0xc4, 0xe1, 0x79, 0xf7, 0xc1]).size_name(), "qword");
+ assert_eq!(mem_size_of(&[0x67, 0xc4, 0xe1, 0x79, 0xf7, 0xc1]).size_name(), "dword");
}
#[test]