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:
T0b1-iOS
2023-04-11 22:16:04 +02:00
committed by GitHub
parent 4c32dd7786
commit 569089e473
27 changed files with 2195 additions and 99 deletions

View File

@@ -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());

View File

@@ -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
//

View File

@@ -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 => {