move with sign extension

This commit is contained in:
Folkert 2023-04-27 19:40:57 +02:00
parent 0bf3eefbf2
commit 5363b95c5f
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
4 changed files with 59 additions and 52 deletions

View file

@ -769,7 +769,6 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
fn movsx_reg_reg(
_buf: &mut Vec<'_, u8>,
_input_width: RegisterWidth,
_output_width: RegisterWidth,
_dst: AArch64GeneralReg,
_src: AArch64GeneralReg,
) {

View file

@ -292,7 +292,6 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
fn movsx_reg_reg(
buf: &mut Vec<'_, u8>,
input_width: RegisterWidth,
output_width: RegisterWidth,
dst: GeneralReg,
src: GeneralReg,
);
@ -2998,18 +2997,10 @@ impl<
ASM::mov_reg_reg(buf, RegisterWidth::W32, dst_reg, src_reg);
}
(I8, I16 | I32 | I64) => {
// zero out the register
ASM::xor_reg64_reg64_reg64(buf, dst_reg, dst_reg, dst_reg);
// move the 8-bit integer
ASM::movsx_reg_reg(
buf,
RegisterWidth::W8,
RegisterWidth::W16,
dst_reg,
src_reg,
);
ASM::movsx_reg_reg(buf, RegisterWidth::W8, dst_reg, src_reg)
}
(I16, I32 | I64) => ASM::movsx_reg_reg(buf, RegisterWidth::W16, dst_reg, src_reg),
(I32, I64) => ASM::movsx_reg_reg(buf, RegisterWidth::W32, dst_reg, src_reg),
// -- CASTING DOWN --
(U64 | I64, I32 | U32) => {
// move as a 32-bit integer (leaving any other bits behind)

View file

@ -1494,11 +1494,10 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
fn movsx_reg_reg(
buf: &mut Vec<'_, u8>,
input_width: RegisterWidth,
output_width: RegisterWidth,
dst: X86_64GeneralReg,
src: X86_64GeneralReg,
) {
raw_movsx_reg_reg(buf, input_width, output_width, dst, src);
raw_movsx_reg_reg(buf, input_width, dst, src);
}
#[inline(always)]
@ -2564,46 +2563,31 @@ fn raw_mov_reg_reg(
fn raw_movsx_reg_reg(
buf: &mut Vec<u8>,
input_width: RegisterWidth,
output_width: RegisterWidth,
dst: X86_64GeneralReg,
src: X86_64GeneralReg,
) {
match (input_width, output_width) {
(RegisterWidth::W8, RegisterWidth::W16) => {
buf.push(0x0F);
buf.push(0xBE);
binop_reg8_reg8(0x89, buf, dst, src);
let dst_high = dst as u8 > 7;
let dst_mod = dst as u8 % 8;
let src_high = src as u8 > 7;
let src_mod = src as u8 % 8;
// NOTE src and dst seem to be flipped here. It works this way though
let mod_rm = 0xC0 | (dst_mod << 3) | src_mod;
let rex = add_rm_extension(src, REX_W);
let rex = add_reg_extension(dst, rex);
match input_width {
RegisterWidth::W8 => {
buf.extend([rex, 0x0f, 0xbe, mod_rm]);
}
(RegisterWidth::W8, RegisterWidth::W32) => {
buf.push(0x0F);
buf.push(0xBF);
binop_reg8_reg8(0x89, buf, dst, src);
RegisterWidth::W16 => {
buf.extend([rex, 0x0f, 0xbf, mod_rm]);
}
(RegisterWidth::W8, RegisterWidth::W64) => {
buf.push(0x48);
buf.push(0x0F);
buf.push(0xBE);
binop_reg8_reg8(0x89, buf, dst, src);
RegisterWidth::W32 => {
buf.extend([rex, 0x63, mod_rm]);
}
(RegisterWidth::W16, RegisterWidth::W32) => {
buf.push(0x66);
buf.push(0x0F);
buf.push(0xBF);
binop_reg16_reg16(0x89, buf, dst, src);
}
(RegisterWidth::W16, RegisterWidth::W64) => {
buf.push(0x48);
buf.push(0x0F);
buf.push(0xBF);
binop_reg16_reg16(0x89, buf, dst, src);
}
(RegisterWidth::W32, RegisterWidth::W64) => {
buf.push(0x48);
buf.push(0x0F);
buf.push(0xBF);
binop_reg32_reg32(0x89, buf, dst, src);
}
_ => panic!("Invalid input/output register width combination"),
RegisterWidth::W64 => { /* do nothing */ }
}
}
@ -3694,6 +3678,36 @@ mod tests {
);
}
#[test]
fn test_movsx_reg64_reg64() {
disassembler_test!(
raw_movsx_reg_reg,
|w, reg1, reg2| {
match w {
RegisterWidth::W8 => format!(
"movsx {}, {}",
reg1,
X86_64GeneralReg::low_8bits_string(&reg2)
),
RegisterWidth::W16 => format!(
"movsx {}, {}",
reg1,
X86_64GeneralReg::low_16bits_string(&reg2)
),
RegisterWidth::W32 => format!(
"movsxd {}, {}",
reg1,
X86_64GeneralReg::low_32bits_string(&reg2)
),
RegisterWidth::W64 => String::new(),
}
},
ALL_REGISTER_WIDTHS,
ALL_GENERAL_REGS,
ALL_GENERAL_REGS
);
}
#[test]
fn test_movsd_freg64_base64_offset32() {
disassembler_test!(