Add {u,s}{add,sub,mul}_overflow instructions (#5784)
* add `{u,s}{add,sub,mul}_overflow` with interpreter
* add `{u,s}{add,sub,mul}_overflow` for x64
* add `{u,s}{add,sub,mul}_overflow` for aarch64
* 128bit filetests for `{u,s}{add,sub,mul}_overflow`
* `{u,s}{add,sub,mul}_overflow` emit tests for x64
* `{u,s}{add,sub,mul}_overflow` emit tests for aarch64
* Initial review changes
* add `with_flags_extended` helper
* add `with_flags_chained` helper
This commit is contained in:
@@ -154,35 +154,69 @@ pub(crate) fn emit(
|
||||
debug_assert_eq!(src1, reg_g);
|
||||
let src2 = src2.clone().to_reg_mem_imm().with_allocs(allocs);
|
||||
|
||||
let rex = RexFlags::from(*size);
|
||||
let prefix = if *size == OperandSize::Size16 {
|
||||
LegacyPrefixes::_66
|
||||
} else {
|
||||
LegacyPrefixes::None
|
||||
};
|
||||
|
||||
let mut rex = RexFlags::from(*size);
|
||||
if *op == AluRmiROpcode::Mul {
|
||||
// We kinda freeloaded Mul into RMI_R_Op, but it doesn't fit the usual pattern, so
|
||||
// we have to special-case it.
|
||||
match src2 {
|
||||
RegMemImm::Reg { reg: reg_e } => {
|
||||
emit_std_reg_reg(sink, LegacyPrefixes::None, 0x0FAF, 2, reg_g, reg_e, rex);
|
||||
}
|
||||
if *size == OperandSize::Size8 {
|
||||
match src2 {
|
||||
RegMemImm::Reg { reg: reg_e } => {
|
||||
debug_assert!(reg_e.is_real());
|
||||
rex.always_emit_if_8bit_needed(reg_e);
|
||||
let enc_e = int_reg_enc(reg_e);
|
||||
emit_std_enc_enc(sink, LegacyPrefixes::None, 0xF6, 1, 5, enc_e, rex);
|
||||
}
|
||||
|
||||
RegMemImm::Mem { addr } => {
|
||||
let amode = addr.finalize(state, sink);
|
||||
emit_std_reg_mem(
|
||||
sink,
|
||||
LegacyPrefixes::None,
|
||||
0x0FAF,
|
||||
2,
|
||||
reg_g,
|
||||
&amode,
|
||||
rex,
|
||||
0,
|
||||
);
|
||||
}
|
||||
RegMemImm::Mem { addr } => {
|
||||
let amode = addr.finalize(state, sink);
|
||||
emit_std_enc_mem(
|
||||
sink,
|
||||
LegacyPrefixes::None,
|
||||
0xF6,
|
||||
1,
|
||||
5,
|
||||
&amode,
|
||||
rex,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
RegMemImm::Imm { simm32 } => {
|
||||
let use_imm8 = low8_will_sign_extend_to_32(simm32);
|
||||
let opcode = if use_imm8 { 0x6B } else { 0x69 };
|
||||
// Yes, really, reg_g twice.
|
||||
emit_std_reg_reg(sink, LegacyPrefixes::None, opcode, 1, reg_g, reg_g, rex);
|
||||
emit_simm(sink, if use_imm8 { 1 } else { 4 }, simm32);
|
||||
RegMemImm::Imm { .. } => {
|
||||
panic!("Cannot emit 8bit imul with 8bit immediate");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match src2 {
|
||||
RegMemImm::Reg { reg: reg_e } => {
|
||||
emit_std_reg_reg(sink, prefix, 0x0FAF, 2, reg_g, reg_e, rex);
|
||||
}
|
||||
|
||||
RegMemImm::Mem { addr } => {
|
||||
let amode = addr.finalize(state, sink);
|
||||
emit_std_reg_mem(sink, prefix, 0x0FAF, 2, reg_g, &amode, rex, 0);
|
||||
}
|
||||
|
||||
RegMemImm::Imm { simm32 } => {
|
||||
let imm_size = if low8_will_sign_extend_to_32(simm32) {
|
||||
1
|
||||
} else {
|
||||
if *size == OperandSize::Size16 {
|
||||
2
|
||||
} else {
|
||||
4
|
||||
}
|
||||
};
|
||||
let opcode = if imm_size == 1 { 0x6B } else { 0x69 };
|
||||
// Yes, really, reg_g twice.
|
||||
emit_std_reg_reg(sink, prefix, opcode, 1, reg_g, reg_g, rex);
|
||||
emit_simm(sink, imm_size, simm32);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -197,52 +231,63 @@ pub(crate) fn emit(
|
||||
AluRmiROpcode::Mul => panic!("unreachable"),
|
||||
};
|
||||
|
||||
let (opcode_r, opcode_m) = if *size == OperandSize::Size8 {
|
||||
(opcode_r - 1, opcode_m - 1)
|
||||
} else {
|
||||
(opcode_r, opcode_m)
|
||||
};
|
||||
|
||||
if *size == OperandSize::Size8 {
|
||||
debug_assert!(reg_g.is_real());
|
||||
rex.always_emit_if_8bit_needed(reg_g);
|
||||
}
|
||||
|
||||
match src2 {
|
||||
RegMemImm::Reg { reg: reg_e } => {
|
||||
if *size == OperandSize::Size8 {
|
||||
debug_assert!(reg_e.is_real());
|
||||
rex.always_emit_if_8bit_needed(reg_e);
|
||||
}
|
||||
|
||||
// GCC/llvm use the swapped operand encoding (viz., the R/RM vs RM/R
|
||||
// duality). Do this too, so as to be able to compare generated machine
|
||||
// code easily.
|
||||
emit_std_reg_reg(
|
||||
sink,
|
||||
LegacyPrefixes::None,
|
||||
opcode_r,
|
||||
1,
|
||||
reg_e,
|
||||
reg_g,
|
||||
rex,
|
||||
);
|
||||
emit_std_reg_reg(sink, prefix, opcode_r, 1, reg_e, reg_g, rex);
|
||||
}
|
||||
|
||||
RegMemImm::Mem { addr } => {
|
||||
let amode = addr.finalize(state, sink);
|
||||
// Here we revert to the "normal" G-E ordering.
|
||||
emit_std_reg_mem(
|
||||
sink,
|
||||
LegacyPrefixes::None,
|
||||
opcode_m,
|
||||
1,
|
||||
reg_g,
|
||||
&amode,
|
||||
rex,
|
||||
0,
|
||||
);
|
||||
emit_std_reg_mem(sink, prefix, opcode_m, 1, reg_g, &amode, rex, 0);
|
||||
}
|
||||
|
||||
RegMemImm::Imm { simm32 } => {
|
||||
let use_imm8 = low8_will_sign_extend_to_32(simm32);
|
||||
let opcode = if use_imm8 { 0x83 } else { 0x81 };
|
||||
let imm_size = if *size == OperandSize::Size8 {
|
||||
1
|
||||
} else {
|
||||
if low8_will_sign_extend_to_32(simm32) {
|
||||
1
|
||||
} else {
|
||||
if *size == OperandSize::Size16 {
|
||||
2
|
||||
} else {
|
||||
4
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let opcode = if *size == OperandSize::Size8 {
|
||||
0x80
|
||||
} else if low8_will_sign_extend_to_32(simm32) {
|
||||
0x83
|
||||
} else {
|
||||
0x81
|
||||
};
|
||||
|
||||
// And also here we use the "normal" G-E ordering.
|
||||
let enc_g = int_reg_enc(reg_g);
|
||||
emit_std_enc_enc(
|
||||
sink,
|
||||
LegacyPrefixes::None,
|
||||
opcode,
|
||||
1,
|
||||
subopcode_i,
|
||||
enc_g,
|
||||
rex,
|
||||
);
|
||||
emit_simm(sink, if use_imm8 { 1 } else { 4 }, simm32);
|
||||
emit_std_enc_enc(sink, prefix, opcode, 1, subopcode_i, enc_g, rex);
|
||||
emit_simm(sink, imm_size, simm32);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,7 +319,6 @@ pub(crate) fn emit(
|
||||
let src2 = allocs.next(src2.to_reg());
|
||||
let src1_dst = src1_dst.finalize(state, sink).with_allocs(allocs);
|
||||
|
||||
assert!(*size == OperandSize::Size32 || *size == OperandSize::Size64);
|
||||
let opcode = match op {
|
||||
AluRmiROpcode::Add => 0x01,
|
||||
AluRmiROpcode::Sub => 0x29,
|
||||
@@ -283,17 +327,26 @@ pub(crate) fn emit(
|
||||
AluRmiROpcode::Xor => 0x31,
|
||||
_ => panic!("Unsupported read-modify-write ALU opcode"),
|
||||
};
|
||||
|
||||
let prefix = if *size == OperandSize::Size16 {
|
||||
LegacyPrefixes::_66
|
||||
} else {
|
||||
LegacyPrefixes::None
|
||||
};
|
||||
let opcode = if *size == OperandSize::Size8 {
|
||||
opcode - 1
|
||||
} else {
|
||||
opcode
|
||||
};
|
||||
|
||||
let mut rex = RexFlags::from(*size);
|
||||
if *size == OperandSize::Size8 {
|
||||
debug_assert!(src2.is_real());
|
||||
rex.always_emit_if_8bit_needed(src2);
|
||||
}
|
||||
|
||||
let enc_g = int_reg_enc(src2);
|
||||
emit_std_enc_mem(
|
||||
sink,
|
||||
LegacyPrefixes::None,
|
||||
opcode,
|
||||
1,
|
||||
enc_g,
|
||||
&src1_dst,
|
||||
RexFlags::from(*size),
|
||||
0,
|
||||
);
|
||||
emit_std_enc_mem(sink, prefix, opcode, 1, enc_g, &src1_dst, rex, 0);
|
||||
}
|
||||
|
||||
Inst::AluRmRVex {
|
||||
@@ -521,6 +574,45 @@ pub(crate) fn emit(
|
||||
}
|
||||
}
|
||||
|
||||
Inst::UMulLo {
|
||||
size,
|
||||
src1,
|
||||
src2,
|
||||
dst,
|
||||
} => {
|
||||
let src1 = allocs.next(src1.to_reg());
|
||||
let dst = allocs.next(dst.to_reg().to_reg());
|
||||
debug_assert_eq!(src1, regs::rax());
|
||||
debug_assert_eq!(dst, regs::rax());
|
||||
|
||||
let mut rex = RexFlags::from(*size);
|
||||
let prefix = match size {
|
||||
OperandSize::Size16 => LegacyPrefixes::_66,
|
||||
_ => LegacyPrefixes::None,
|
||||
};
|
||||
|
||||
let opcode = if *size == OperandSize::Size8 {
|
||||
0xF6
|
||||
} else {
|
||||
0xF7
|
||||
};
|
||||
|
||||
match src2.clone().to_reg_mem() {
|
||||
RegMem::Reg { reg } => {
|
||||
let reg = allocs.next(reg);
|
||||
if *size == OperandSize::Size8 {
|
||||
rex.always_emit_if_8bit_needed(reg);
|
||||
}
|
||||
let reg_e = int_reg_enc(reg);
|
||||
emit_std_enc_enc(sink, prefix, opcode, 1, 4, reg_e, rex);
|
||||
}
|
||||
RegMem::Mem { addr: src } => {
|
||||
let amode = src.finalize(state, sink).with_allocs(allocs);
|
||||
emit_std_enc_mem(sink, prefix, opcode, 1, 4, &amode, rex, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Inst::SignExtendData { size, src, dst } => {
|
||||
let src = allocs.next(src.to_reg());
|
||||
let dst = allocs.next(dst.to_reg().to_reg());
|
||||
|
||||
@@ -78,6 +78,15 @@ impl Inst {
|
||||
}
|
||||
}
|
||||
|
||||
fn umul_lo(size: OperandSize, operand: RegMem) -> Inst {
|
||||
Inst::UMulLo {
|
||||
size,
|
||||
src1: Gpr::new(regs::rax()).unwrap(),
|
||||
src2: GprMem::new(operand).unwrap(),
|
||||
dst: WritableGpr::from_reg(Gpr::new(regs::rax()).unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
fn xmm_rm_r_evex(op: Avx512Opcode, src1: RegMem, src2: Reg, dst: Writable<Reg>) -> Self {
|
||||
src1.assert_regclass_is(RegClass::Float);
|
||||
debug_assert!(src2.class() == RegClass::Float);
|
||||
@@ -1535,6 +1544,415 @@ fn test_x64_emit() {
|
||||
"imull %esi, $76543210, %esi",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::reg(rax),
|
||||
w_rdx,
|
||||
),
|
||||
"6601C2",
|
||||
"addw %dx, %ax, %dx",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::imm(10),
|
||||
w_rdx,
|
||||
),
|
||||
"6683C20A",
|
||||
"addw %dx, $10, %dx",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::imm(-512i32 as u32),
|
||||
w_rdx,
|
||||
),
|
||||
"6681C200FE",
|
||||
"addw %dx, $-512, %dx",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Sub,
|
||||
RegMemImm::reg(rax),
|
||||
w_r12,
|
||||
),
|
||||
"664129C4",
|
||||
"subw %r12w, %ax, %r12w",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::reg(r10),
|
||||
w_rcx,
|
||||
),
|
||||
"664431D1",
|
||||
"xorw %cx, %r10w, %cx",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::reg(r10),
|
||||
w_r14,
|
||||
),
|
||||
"664521D6",
|
||||
"andw %r14w, %r10w, %r14w",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::imm(10),
|
||||
w_r14,
|
||||
),
|
||||
"664183E60A",
|
||||
"andw %r14w, $10, %r14w",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::imm(-512i32 as u32),
|
||||
w_r14,
|
||||
),
|
||||
"664181E600FE",
|
||||
"andw %r14w, $-512, %r14w",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::imm(10),
|
||||
w_rax,
|
||||
),
|
||||
"666BC00A",
|
||||
"imulw %ax, $10, %ax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::imm(-512i32 as u32),
|
||||
w_rax,
|
||||
),
|
||||
"6669C000FE",
|
||||
"imulw %ax, $-512, %ax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::imm(10),
|
||||
w_r11,
|
||||
),
|
||||
"66456BDB0A",
|
||||
"imulw %r11w, $10, %r11w",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::imm(-512i32 as u32),
|
||||
w_r11,
|
||||
),
|
||||
"664569DB00FE",
|
||||
"imulw %r11w, $-512, %r11w",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::reg(rdx),
|
||||
w_rax,
|
||||
),
|
||||
"660FAFC2",
|
||||
"imulw %ax, %dx, %ax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::reg(r12),
|
||||
w_rax,
|
||||
),
|
||||
"66410FAFC4",
|
||||
"imulw %ax, %r12w, %ax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::reg(rdx),
|
||||
w_r11,
|
||||
),
|
||||
"66440FAFDA",
|
||||
"imulw %r11w, %dx, %r11w",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size16,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::reg(r12),
|
||||
w_r11,
|
||||
),
|
||||
"66450FAFDC",
|
||||
"imulw %r11w, %r12w, %r11w",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::imm(10),
|
||||
w_rax,
|
||||
),
|
||||
"80C00A", // there is theoretically 040A as a valid encoding also
|
||||
"addb %al, $10, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::reg(rcx),
|
||||
w_rax,
|
||||
),
|
||||
"00C8",
|
||||
"addb %al, %cl, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::reg(rsi),
|
||||
w_rax,
|
||||
),
|
||||
"4000F0",
|
||||
"addb %al, %sil, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::reg(r11),
|
||||
w_rax,
|
||||
),
|
||||
"4400D8",
|
||||
"addb %al, %r11b, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::reg(r15),
|
||||
w_rax,
|
||||
),
|
||||
"4400F8",
|
||||
"addb %al, %r15b, %al",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Sub,
|
||||
RegMemImm::imm(10),
|
||||
_w_rbp,
|
||||
),
|
||||
"4080ED0A",
|
||||
"subb %bpl, $10, %bpl",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Sub,
|
||||
RegMemImm::reg(rcx),
|
||||
_w_rbp,
|
||||
),
|
||||
"4028CD",
|
||||
"subb %bpl, %cl, %bpl",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Sub,
|
||||
RegMemImm::reg(rsi),
|
||||
_w_rbp,
|
||||
),
|
||||
"4028F5",
|
||||
"subb %bpl, %sil, %bpl",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Sub,
|
||||
RegMemImm::reg(r11),
|
||||
_w_rbp,
|
||||
),
|
||||
"4428DD",
|
||||
"subb %bpl, %r11b, %bpl",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Sub,
|
||||
RegMemImm::reg(r15),
|
||||
_w_rbp,
|
||||
),
|
||||
"4428FD",
|
||||
"subb %bpl, %r15b, %bpl",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::imm(10),
|
||||
_w_r10,
|
||||
),
|
||||
"4180F20A",
|
||||
"xorb %r10b, $10, %r10b",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::reg(rcx),
|
||||
_w_r10,
|
||||
),
|
||||
"4130CA",
|
||||
"xorb %r10b, %cl, %r10b",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::reg(rsi),
|
||||
_w_r10,
|
||||
),
|
||||
"4130F2",
|
||||
"xorb %r10b, %sil, %r10b",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::reg(r11),
|
||||
_w_r10,
|
||||
),
|
||||
"4530DA",
|
||||
"xorb %r10b, %r11b, %r10b",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::reg(r15),
|
||||
_w_r10,
|
||||
),
|
||||
"4530FA",
|
||||
"xorb %r10b, %r15b, %r10b",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::imm(10),
|
||||
w_r15,
|
||||
),
|
||||
"4180E70A",
|
||||
"andb %r15b, $10, %r15b",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::reg(rcx),
|
||||
w_r15,
|
||||
),
|
||||
"4120CF",
|
||||
"andb %r15b, %cl, %r15b",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::reg(rsi),
|
||||
w_r15,
|
||||
),
|
||||
"4120F7",
|
||||
"andb %r15b, %sil, %r15b",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::reg(r11),
|
||||
w_r15,
|
||||
),
|
||||
"4520DF",
|
||||
"andb %r15b, %r11b, %r15b",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::reg(r15),
|
||||
w_r15,
|
||||
),
|
||||
"4520FF",
|
||||
"andb %r15b, %r15b, %r15b",
|
||||
));
|
||||
|
||||
// the 8bit imul has rax as fixed dst
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::reg(rcx),
|
||||
w_rax,
|
||||
),
|
||||
"F6E9",
|
||||
"imulb %al, %cl, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::reg(rbp),
|
||||
w_rax,
|
||||
),
|
||||
"40F6ED",
|
||||
"imulb %al, %bpl, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::reg(r10),
|
||||
w_rax,
|
||||
),
|
||||
"41F6EA",
|
||||
"imulb %al, %r10b, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::alu_rmi_r(
|
||||
OperandSize::Size8,
|
||||
AluRmiROpcode::Mul,
|
||||
RegMemImm::reg(r15),
|
||||
w_rax,
|
||||
),
|
||||
"41F6EF",
|
||||
"imulb %al, %r15b, %al",
|
||||
));
|
||||
|
||||
// ========================================================
|
||||
// AluRM
|
||||
|
||||
@@ -1654,6 +2072,68 @@ fn test_x64_emit() {
|
||||
"xorq %rax, 0(%rbp)",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::AluRM {
|
||||
size: OperandSize::Size16,
|
||||
op: AluRmiROpcode::Add,
|
||||
src1_dst: Amode::imm_reg(0, rbp).into(),
|
||||
src2: Gpr::new(rax).unwrap(),
|
||||
},
|
||||
"66014500",
|
||||
"addw %ax, 0(%rbp)",
|
||||
));
|
||||
insns.push((
|
||||
Inst::AluRM {
|
||||
size: OperandSize::Size16,
|
||||
op: AluRmiROpcode::Sub,
|
||||
src1_dst: Amode::imm_reg(0, rbp).into(),
|
||||
src2: Gpr::new(r12).unwrap(),
|
||||
},
|
||||
"6644296500",
|
||||
"subw %r12w, 0(%rbp)",
|
||||
));
|
||||
|
||||
insns.push((
|
||||
Inst::AluRM {
|
||||
size: OperandSize::Size8,
|
||||
op: AluRmiROpcode::Add,
|
||||
src1_dst: Amode::imm_reg(0, rbp).into(),
|
||||
src2: Gpr::new(rax).unwrap(),
|
||||
},
|
||||
"004500",
|
||||
"addb %al, 0(%rbp)",
|
||||
));
|
||||
insns.push((
|
||||
Inst::AluRM {
|
||||
size: OperandSize::Size8,
|
||||
op: AluRmiROpcode::Sub,
|
||||
src1_dst: Amode::imm_reg(0, rbp).into(),
|
||||
src2: Gpr::new(rbp).unwrap(),
|
||||
},
|
||||
"40286D00",
|
||||
"subb %bpl, 0(%rbp)",
|
||||
));
|
||||
insns.push((
|
||||
Inst::AluRM {
|
||||
size: OperandSize::Size8,
|
||||
op: AluRmiROpcode::Xor,
|
||||
src1_dst: Amode::imm_reg(0, rbp).into(),
|
||||
src2: Gpr::new(r10).unwrap(),
|
||||
},
|
||||
"44305500",
|
||||
"xorb %r10b, 0(%rbp)",
|
||||
));
|
||||
insns.push((
|
||||
Inst::AluRM {
|
||||
size: OperandSize::Size8,
|
||||
op: AluRmiROpcode::And,
|
||||
src1_dst: Amode::imm_reg(0, rbp).into(),
|
||||
src2: Gpr::new(r15).unwrap(),
|
||||
},
|
||||
"44207D00",
|
||||
"andb %r15b, 0(%rbp)",
|
||||
));
|
||||
|
||||
// ========================================================
|
||||
// UnaryRmR
|
||||
|
||||
@@ -1864,6 +2344,59 @@ fn test_x64_emit() {
|
||||
"mul %rax, %rdi, %rax, %rdx",
|
||||
));
|
||||
|
||||
// ========================================================
|
||||
// UMulLo
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size64, RegMem::reg(regs::rdx())),
|
||||
"48F7E2",
|
||||
"mulq %rax, %rdx, %rax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size64, RegMem::reg(regs::r12())),
|
||||
"49F7E4",
|
||||
"mulq %rax, %r12, %rax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size32, RegMem::reg(regs::rdx())),
|
||||
"F7E2",
|
||||
"mull %eax, %edx, %eax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size32, RegMem::reg(regs::r12())),
|
||||
"41F7E4",
|
||||
"mull %eax, %r12d, %eax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size16, RegMem::reg(regs::rdx())),
|
||||
"66F7E2",
|
||||
"mulw %ax, %dx, %ax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size16, RegMem::reg(regs::r12())),
|
||||
"6641F7E4",
|
||||
"mulw %ax, %r12w, %ax",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size8, RegMem::reg(regs::rdx())),
|
||||
"F6E2",
|
||||
"mulb %al, %dl, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size8, RegMem::reg(regs::rdi())),
|
||||
"40F6E7",
|
||||
"mulb %al, %dil, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size8, RegMem::reg(regs::r9())),
|
||||
"41F6E1",
|
||||
"mulb %al, %r9b, %al",
|
||||
));
|
||||
insns.push((
|
||||
Inst::umul_lo(OperandSize::Size8, RegMem::reg(regs::r12())),
|
||||
"41F6E4",
|
||||
"mulb %al, %r12b, %al",
|
||||
));
|
||||
|
||||
// ========================================================
|
||||
// Imm_R
|
||||
//
|
||||
|
||||
@@ -101,6 +101,7 @@ impl Inst {
|
||||
| Inst::MovsxRmR { .. }
|
||||
| Inst::MovzxRmR { .. }
|
||||
| Inst::MulHi { .. }
|
||||
| Inst::UMulLo { .. }
|
||||
| Inst::Neg { .. }
|
||||
| Inst::Not { .. }
|
||||
| Inst::Nop { .. }
|
||||
@@ -180,7 +181,6 @@ impl Inst {
|
||||
src: RegMemImm,
|
||||
dst: Writable<Reg>,
|
||||
) -> Self {
|
||||
debug_assert!(size.is_one_of(&[OperandSize::Size32, OperandSize::Size64]));
|
||||
src.assert_regclass_is(RegClass::Int);
|
||||
debug_assert!(dst.to_reg().class() == RegClass::Int);
|
||||
Self::AluRmiR {
|
||||
@@ -657,6 +657,7 @@ impl PrettyPrint for Inst {
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn suffix_lqb(size: OperandSize) -> String {
|
||||
match size {
|
||||
OperandSize::Size32 => "l",
|
||||
@@ -691,7 +692,7 @@ impl PrettyPrint for Inst {
|
||||
let src2 = src2.pretty_print(size_bytes, allocs);
|
||||
format!(
|
||||
"{} {}, {}, {}",
|
||||
ljustify2(op.to_string(), suffix_lqb(*size)),
|
||||
ljustify2(op.to_string(), suffix_bwlq(*size)),
|
||||
src1,
|
||||
src2,
|
||||
dst
|
||||
@@ -716,7 +717,7 @@ impl PrettyPrint for Inst {
|
||||
let src1_dst = src1_dst.pretty_print(size_bytes, allocs);
|
||||
format!(
|
||||
"{} {}, {}",
|
||||
ljustify2(op.to_string(), suffix_lqb(*size)),
|
||||
ljustify2(op.to_string(), suffix_bwlq(*size)),
|
||||
src2,
|
||||
src1_dst,
|
||||
)
|
||||
@@ -849,6 +850,24 @@ impl PrettyPrint for Inst {
|
||||
)
|
||||
}
|
||||
|
||||
Inst::UMulLo {
|
||||
size,
|
||||
src1,
|
||||
src2,
|
||||
dst,
|
||||
} => {
|
||||
let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes(), allocs);
|
||||
let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes(), allocs);
|
||||
let src2 = src2.pretty_print(size.to_bytes(), allocs);
|
||||
format!(
|
||||
"{} {}, {}, {}",
|
||||
ljustify2("mul".to_string(), suffix_bwlq(*size)),
|
||||
src1,
|
||||
src2,
|
||||
dst,
|
||||
)
|
||||
}
|
||||
|
||||
Inst::CheckedSRemSeq {
|
||||
size,
|
||||
divisor,
|
||||
@@ -1854,11 +1873,23 @@ fn x64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandCol
|
||||
// method above.
|
||||
match inst {
|
||||
Inst::AluRmiR {
|
||||
src1, src2, dst, ..
|
||||
size,
|
||||
op,
|
||||
src1,
|
||||
src2,
|
||||
dst,
|
||||
..
|
||||
} => {
|
||||
collector.reg_use(src1.to_reg());
|
||||
collector.reg_reuse_def(dst.to_writable_reg(), 0);
|
||||
src2.get_operands(collector);
|
||||
if *size == OperandSize::Size8 && *op == AluRmiROpcode::Mul {
|
||||
// 8-bit imul has RAX as a fixed input/output
|
||||
collector.reg_fixed_use(src1.to_reg(), regs::rax());
|
||||
collector.reg_fixed_def(dst.to_writable_reg(), regs::rax());
|
||||
src2.get_operands(collector);
|
||||
} else {
|
||||
collector.reg_use(src1.to_reg());
|
||||
collector.reg_reuse_def(dst.to_writable_reg(), 0);
|
||||
src2.get_operands(collector);
|
||||
}
|
||||
}
|
||||
Inst::AluConstOp { dst, .. } => collector.reg_def(dst.to_writable_reg()),
|
||||
Inst::AluRM { src1_dst, src2, .. } => {
|
||||
@@ -1925,6 +1956,20 @@ fn x64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandCol
|
||||
collector.reg_fixed_def(dst_hi.to_writable_reg(), regs::rdx());
|
||||
src2.get_operands(collector);
|
||||
}
|
||||
Inst::UMulLo {
|
||||
size,
|
||||
src1,
|
||||
src2,
|
||||
dst,
|
||||
..
|
||||
} => {
|
||||
collector.reg_fixed_use(src1.to_reg(), regs::rax());
|
||||
collector.reg_fixed_def(dst.to_writable_reg(), regs::rax());
|
||||
if *size != OperandSize::Size8 {
|
||||
collector.reg_clobbers(PRegSet::empty().with(regs::gpr_preg(regs::ENC_RDX)));
|
||||
}
|
||||
src2.get_operands(collector);
|
||||
}
|
||||
Inst::SignExtendData { size, src, dst } => {
|
||||
match size {
|
||||
OperandSize::Size8 => {
|
||||
|
||||
Reference in New Issue
Block a user