Refactor x64::Inst to use OperandSize instead of u8s.

TODO: some types take a 'is_64_bit' bool. Those are left unchanged for now.
This commit is contained in:
Kasey Carrothers
2021-01-30 18:39:10 -08:00
committed by Andrew Brown
parent b12d41bfe9
commit 3306408100
6 changed files with 780 additions and 458 deletions

View File

@@ -3,7 +3,7 @@
use super::regs::{self, show_ireg_sized};
use super::EmitState;
use crate::ir::condcodes::{FloatCC, IntCC};
use crate::ir::MemFlags;
use crate::ir::{MemFlags, Type};
use crate::isa::x64::inst::Inst;
use crate::machinst::*;
use regalloc::{
@@ -1336,10 +1336,16 @@ impl OperandSize {
2 => OperandSize::Size16,
4 => OperandSize::Size32,
8 => OperandSize::Size64,
_ => unreachable!(),
_ => unreachable!("Invalid OperandSize: {}", num_bytes),
}
}
// Computes the OperandSize for a given type.
// For vectors, the OperandSize of the lanes is returned.
pub(crate) fn from_ty(ty: Type) -> Self {
Self::from_bytes(ty.lane_type().bytes())
}
// Check that the value of self is one of the allowed sizes.
pub(crate) fn is_size(&self, sizes: &[Self]) -> bool {
for val in sizes.iter() {

View File

@@ -676,18 +676,18 @@ pub(crate) fn emit(
Inst::UnaryRmR { size, op, src, dst } => {
let rex_flags = match size {
2 | 4 => RexFlags::clear_w(),
8 => RexFlags::set_w(),
OperandSize::Size16 | OperandSize::Size32 => RexFlags::clear_w(),
OperandSize::Size64 => RexFlags::set_w(),
_ => unreachable!(),
};
use UnaryRmROpcode::*;
let prefix = match size {
2 => match op {
OperandSize::Size16 => match op {
Bsr | Bsf => LegacyPrefixes::_66,
Lzcnt | Tzcnt | Popcnt => LegacyPrefixes::_66F3,
},
4 | 8 => match op {
OperandSize::Size32 | OperandSize::Size64 => match op {
Bsr | Bsf => LegacyPrefixes::None,
Lzcnt | Tzcnt | Popcnt => LegacyPrefixes::_F3,
},
@@ -732,15 +732,14 @@ pub(crate) fn emit(
Inst::Not { size, src } => {
let src = int_reg_enc(src.to_reg());
let (opcode, prefix, rex_flags) = match size {
1 => (
OperandSize::Size8 => (
0xF6,
LegacyPrefixes::None,
*RexFlags::clear_w().always_emit_if_8bit_needed(src),
),
2 => (0xF7, LegacyPrefixes::_66, RexFlags::clear_w()),
4 => (0xF7, LegacyPrefixes::None, RexFlags::clear_w()),
8 => (0xF7, LegacyPrefixes::None, RexFlags::set_w()),
_ => unreachable!("{}", size),
OperandSize::Size16 => (0xF7, LegacyPrefixes::_66, RexFlags::clear_w()),
OperandSize::Size32 => (0xF7, LegacyPrefixes::None, RexFlags::clear_w()),
OperandSize::Size64 => (0xF7, LegacyPrefixes::None, RexFlags::set_w()),
};
let subopcode = 2;
@@ -750,15 +749,14 @@ pub(crate) fn emit(
Inst::Neg { size, src } => {
let src = int_reg_enc(src.to_reg());
let (opcode, prefix, rex_flags) = match size {
1 => (
OperandSize::Size8 => (
0xF6,
LegacyPrefixes::None,
*RexFlags::clear_w().always_emit_if_8bit_needed(src),
),
2 => (0xF7, LegacyPrefixes::_66, RexFlags::clear_w()),
4 => (0xF7, LegacyPrefixes::None, RexFlags::clear_w()),
8 => (0xF7, LegacyPrefixes::None, RexFlags::set_w()),
_ => unreachable!("{}", size),
OperandSize::Size16 => (0xF7, LegacyPrefixes::_66, RexFlags::clear_w()),
OperandSize::Size32 => (0xF7, LegacyPrefixes::None, RexFlags::clear_w()),
OperandSize::Size64 => (0xF7, LegacyPrefixes::None, RexFlags::set_w()),
};
let subopcode = 3;
@@ -771,11 +769,10 @@ pub(crate) fn emit(
divisor,
} => {
let (opcode, prefix, mut rex_flags) = match size {
1 => (0xF6, LegacyPrefixes::None, RexFlags::clear_w()),
2 => (0xF7, LegacyPrefixes::_66, RexFlags::clear_w()),
4 => (0xF7, LegacyPrefixes::None, RexFlags::clear_w()),
8 => (0xF7, LegacyPrefixes::None, RexFlags::set_w()),
_ => unreachable!("{}", size),
OperandSize::Size8 => (0xF6, LegacyPrefixes::None, RexFlags::clear_w()),
OperandSize::Size16 => (0xF7, LegacyPrefixes::_66, RexFlags::clear_w()),
OperandSize::Size32 => (0xF7, LegacyPrefixes::None, RexFlags::clear_w()),
OperandSize::Size64 => (0xF7, LegacyPrefixes::None, RexFlags::set_w()),
};
let loc = state.cur_srcloc();
@@ -785,7 +782,7 @@ pub(crate) fn emit(
match divisor {
RegMem::Reg { reg } => {
let src = int_reg_enc(*reg);
if *size == 1 {
if *size == OperandSize::Size8 {
rex_flags.always_emit_if_8bit_needed(src);
}
emit_std_enc_enc(sink, prefix, opcode, 1, subopcode, src, rex_flags)
@@ -801,9 +798,9 @@ pub(crate) fn emit(
Inst::MulHi { size, signed, rhs } => {
let (prefix, rex_flags) = match size {
2 => (LegacyPrefixes::_66, RexFlags::clear_w()),
4 => (LegacyPrefixes::None, RexFlags::clear_w()),
8 => (LegacyPrefixes::None, RexFlags::set_w()),
OperandSize::Size16 => (LegacyPrefixes::_66, RexFlags::clear_w()),
OperandSize::Size32 => (LegacyPrefixes::None, RexFlags::clear_w()),
OperandSize::Size64 => (LegacyPrefixes::None, RexFlags::set_w()),
_ => unreachable!(),
};
@@ -823,20 +820,19 @@ pub(crate) fn emit(
}
Inst::SignExtendData { size } => match size {
1 => {
OperandSize::Size8 => {
sink.put1(0x66);
sink.put1(0x98);
}
2 => {
OperandSize::Size16 => {
sink.put1(0x66);
sink.put1(0x99);
}
4 => sink.put1(0x99),
8 => {
OperandSize::Size32 => sink.put1(0x99),
OperandSize::Size64 => {
sink.put1(0x48);
sink.put1(0x99);
}
_ => unreachable!(),
},
Inst::CheckedDivOrRemSeq {
@@ -896,11 +892,7 @@ pub(crate) fn emit(
// x % -1 = 0; put the result into the destination, $rdx.
let done_label = sink.get_label();
let inst = Inst::imm(
OperandSize::from_bytes(*size as u32),
0,
Writable::from_reg(regs::rdx()),
);
let inst = Inst::imm(*size, 0, Writable::from_reg(regs::rdx()));
inst.emit(sink, info, state);
let inst = Inst::jmp_known(done_label);
@@ -909,13 +901,17 @@ pub(crate) fn emit(
(Some(do_op), Some(done_label))
} else {
// Check for integer overflow.
if *size == 8 {
if *size == OperandSize::Size64 {
let tmp = tmp.expect("temporary for i64 sdiv");
let inst = Inst::imm(OperandSize::Size64, 0x8000000000000000, tmp);
inst.emit(sink, info, state);
let inst = Inst::cmp_rmi_r(8, RegMemImm::reg(tmp.to_reg()), regs::rax());
let inst = Inst::cmp_rmi_r(
OperandSize::Size64,
RegMemImm::reg(tmp.to_reg()),
regs::rax(),
);
inst.emit(sink, info, state);
} else {
let inst = Inst::cmp_rmi_r(*size, RegMemImm::imm(0x80000000), regs::rax());
@@ -937,7 +933,7 @@ pub(crate) fn emit(
}
assert!(
*size > 1,
*size != OperandSize::Size8,
"CheckedDivOrRemSeq for i8 is not yet implemented"
);
@@ -1175,7 +1171,7 @@ pub(crate) fn emit(
let dst = &dst.finalize(state, sink);
match size {
1 => {
OperandSize::Size8 => {
// This is one of the few places where the presence of a
// redundant REX prefix changes the meaning of the
// instruction.
@@ -1198,7 +1194,7 @@ pub(crate) fn emit(
)
}
2 => {
OperandSize::Size16 => {
// MOV r16, r/m16 is 66 (REX.W==0) 89 /r
emit_std_reg_mem(
sink,
@@ -1213,7 +1209,7 @@ pub(crate) fn emit(
)
}
4 => {
OperandSize::Size32 => {
// MOV r32, r/m32 is (REX.W==0) 89 /r
emit_std_reg_mem(
sink,
@@ -1228,7 +1224,7 @@ pub(crate) fn emit(
)
}
8 => {
OperandSize::Size64 => {
// MOV r64, r/m64 is (REX.W==1) 89 /r
emit_std_reg_mem(
sink,
@@ -1242,8 +1238,6 @@ pub(crate) fn emit(
RexFlags::set_w(),
)
}
_ => panic!("x64::Inst::Mov_R_M::emit: unreachable"),
}
}
@@ -1265,15 +1259,14 @@ pub(crate) fn emit(
match num_bits {
None => {
let (opcode, prefix, rex_flags) = match size {
1 => (
OperandSize::Size8 => (
0xD2,
LegacyPrefixes::None,
*RexFlags::clear_w().always_emit_if_8bit_needed(enc_dst),
),
2 => (0xD3, LegacyPrefixes::_66, RexFlags::clear_w()),
4 => (0xD3, LegacyPrefixes::None, RexFlags::clear_w()),
8 => (0xD3, LegacyPrefixes::None, RexFlags::set_w()),
_ => unreachable!("{}", size),
OperandSize::Size16 => (0xD3, LegacyPrefixes::_66, RexFlags::clear_w()),
OperandSize::Size32 => (0xD3, LegacyPrefixes::None, RexFlags::clear_w()),
OperandSize::Size64 => (0xD3, LegacyPrefixes::None, RexFlags::set_w()),
};
// SHL/SHR/SAR %cl, reg8 is (REX.W==0) D2 /subopcode
@@ -1285,15 +1278,14 @@ pub(crate) fn emit(
Some(num_bits) => {
let (opcode, prefix, rex_flags) = match size {
1 => (
OperandSize::Size8 => (
0xC0,
LegacyPrefixes::None,
*RexFlags::clear_w().always_emit_if_8bit_needed(enc_dst),
),
2 => (0xC1, LegacyPrefixes::_66, RexFlags::clear_w()),
4 => (0xC1, LegacyPrefixes::None, RexFlags::clear_w()),
8 => (0xC1, LegacyPrefixes::None, RexFlags::set_w()),
_ => unreachable!("{}", size),
OperandSize::Size16 => (0xC1, LegacyPrefixes::_66, RexFlags::clear_w()),
OperandSize::Size32 => (0xC1, LegacyPrefixes::None, RexFlags::clear_w()),
OperandSize::Size64 => (0xC1, LegacyPrefixes::None, RexFlags::set_w()),
};
// SHL/SHR/SAR $ib, reg8 is (REX.W==0) C0 /subopcode
@@ -1377,26 +1369,25 @@ pub(crate) fn emit(
};
let mut prefix = LegacyPrefixes::None;
if *size == 2 {
if *size == OperandSize::Size16 {
prefix = LegacyPrefixes::_66;
}
let mut rex = match size {
8 => RexFlags::set_w(),
4 | 2 => RexFlags::clear_w(),
1 => {
OperandSize::Size64 => RexFlags::set_w(),
OperandSize::Size16 | OperandSize::Size32 => RexFlags::clear_w(),
OperandSize::Size8 => {
let mut rex = RexFlags::clear_w();
// Here, a redundant REX prefix changes the meaning of the instruction.
let enc_g = int_reg_enc(*reg_g);
rex.always_emit_if_8bit_needed(enc_g);
rex
}
_ => panic!("x64::Inst::Cmp_RMI_R::emit: unreachable"),
};
match src_e {
RegMemImm::Reg { reg: reg_e } => {
if *size == 1 {
if *size == OperandSize::Size8 {
// Check whether the E register forces the use of a redundant REX.
let enc_e = int_reg_enc(*reg_e);
rex.always_emit_if_8bit_needed(enc_e);
@@ -1405,9 +1396,9 @@ pub(crate) fn emit(
// Use the swapped operands encoding for CMP, to stay consistent with the output of
// gcc/llvm.
let opcode = match (*size, is_cmp) {
(1, true) => 0x38,
(OperandSize::Size8, true) => 0x38,
(_, true) => 0x39,
(1, false) => 0x84,
(OperandSize::Size8, false) => 0x84,
(_, false) => 0x85,
};
emit_std_reg_reg(sink, prefix, opcode, 1, *reg_e, *reg_g, rex);
@@ -1417,9 +1408,9 @@ pub(crate) fn emit(
let addr = &addr.finalize(state, sink);
// Whereas here we revert to the "normal" G-E ordering for CMP.
let opcode = match (*size, is_cmp) {
(1, true) => 0x3A,
(OperandSize::Size8, true) => 0x3A,
(_, true) => 0x3B,
(1, false) => 0x84,
(OperandSize::Size8, false) => 0x84,
(_, false) => 0x85,
};
emit_std_reg_mem(sink, state, info, prefix, opcode, 1, *reg_g, addr, rex);
@@ -1432,7 +1423,7 @@ pub(crate) fn emit(
// And also here we use the "normal" G-E ordering.
let opcode = if is_cmp {
if *size == 1 {
if *size == OperandSize::Size8 {
0x80
} else if use_imm8 {
0x83
@@ -1440,7 +1431,7 @@ pub(crate) fn emit(
0x81
}
} else {
if *size == 1 {
if *size == OperandSize::Size8 {
0xF6
} else {
0xF7
@@ -1450,7 +1441,7 @@ pub(crate) fn emit(
let enc_g = int_reg_enc(*reg_g);
emit_std_enc_enc(sink, prefix, opcode, 1, subopcode, enc_g, rex);
emit_simm(sink, if use_imm8 { 1 } else { *size }, *simm32);
emit_simm(sink, if use_imm8 { 1 } else { size.to_bytes() }, *simm32);
}
}
}
@@ -1477,9 +1468,9 @@ pub(crate) fn emit(
dst: reg_g,
} => {
let (prefix, rex_flags) = match size {
2 => (LegacyPrefixes::_66, RexFlags::clear_w()),
4 => (LegacyPrefixes::None, RexFlags::clear_w()),
8 => (LegacyPrefixes::None, RexFlags::set_w()),
OperandSize::Size16 => (LegacyPrefixes::_66, RexFlags::clear_w()),
OperandSize::Size32 => (LegacyPrefixes::None, RexFlags::clear_w()),
OperandSize::Size64 => (LegacyPrefixes::None, RexFlags::set_w()),
_ => unreachable!("invalid size spec for cmove"),
};
let opcode = 0x0F40 + cc.get_enc() as u32;
@@ -2338,7 +2329,7 @@ pub(crate) fn emit(
// If x seen as a signed int64 is not negative, a signed-conversion will do the right
// thing.
// TODO use tst src, src here.
let inst = Inst::cmp_rmi_r(8, RegMemImm::imm(0), src.to_reg());
let inst = Inst::cmp_rmi_r(OperandSize::Size64, RegMemImm::imm(0), src.to_reg());
inst.emit(sink, info, state);
one_way_jmp(sink, CC::L, handle_negative);
@@ -2358,7 +2349,12 @@ pub(crate) fn emit(
inst.emit(sink, info, state);
// tmp_gpr1 := src >> 1
let inst = Inst::shift_r(8, ShiftKind::ShiftRightLogical, Some(1), *tmp_gpr1);
let inst = Inst::shift_r(
OperandSize::Size64,
ShiftKind::ShiftRightLogical,
Some(1),
*tmp_gpr1,
);
inst.emit(sink, info, state);
let inst = Inst::gen_move(*tmp_gpr2, src.to_reg(), types::I64);
@@ -2464,7 +2460,7 @@ pub(crate) fn emit(
inst.emit(sink, info, state);
// Compare against 1, in case of overflow the dst operand was INT_MIN.
let inst = Inst::cmp_rmi_r(dst_size.to_bytes(), RegMemImm::imm(1), dst.to_reg());
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(1), dst.to_reg());
inst.emit(sink, info, state);
one_way_jmp(sink, CC::NO, done); // no overflow => done
@@ -2693,7 +2689,7 @@ pub(crate) fn emit(
let inst = Inst::xmm_to_gpr(trunc_op, src.to_reg(), *dst, *dst_size);
inst.emit(sink, info, state);
let inst = Inst::cmp_rmi_r(dst_size.to_bytes(), RegMemImm::imm(0), dst.to_reg());
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(0), dst.to_reg());
inst.emit(sink, info, state);
one_way_jmp(sink, CC::NL, done); // if dst >= 0, jump to done
@@ -2727,7 +2723,7 @@ pub(crate) fn emit(
let inst = Inst::xmm_to_gpr(trunc_op, src.to_reg(), *dst, *dst_size);
inst.emit(sink, info, state);
let inst = Inst::cmp_rmi_r(dst_size.to_bytes(), RegMemImm::imm(0), dst.to_reg());
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(0), dst.to_reg());
inst.emit(sink, info, state);
let next_is_large = sink.get_label();

File diff suppressed because it is too large Load Diff

View File

@@ -50,7 +50,7 @@ pub enum Inst {
/// Instructions on GPR that only read src and defines dst (dst is not modified): bsr, etc.
UnaryRmR {
size: u8, // 2, 4 or 8
size: OperandSize, // 2, 4 or 8
op: UnaryRmROpcode,
src: RegMem,
dst: Writable<Reg>,
@@ -58,25 +58,29 @@ pub enum Inst {
/// Bitwise not
Not {
size: u8, // 1, 2, 4 or 8
size: OperandSize, // 1, 2, 4 or 8
src: Writable<Reg>,
},
/// Integer negation
Neg {
size: u8, // 1, 2, 4 or 8
size: OperandSize, // 1, 2, 4 or 8
src: Writable<Reg>,
},
/// Integer quotient and remainder: (div idiv) $rax $rdx (reg addr)
Div {
size: u8, // 1, 2, 4 or 8
size: OperandSize, // 1, 2, 4 or 8
signed: bool,
divisor: RegMem,
},
/// The high bits (RDX) of a (un)signed multiply: RDX:RAX := RAX * rhs.
MulHi { size: u8, signed: bool, rhs: RegMem },
MulHi {
size: OperandSize, // 2, 4, or 8
signed: bool,
rhs: RegMem,
},
/// A synthetic sequence to implement the right inline checks for remainder and division,
/// assuming the dividend is in %rax.
@@ -91,7 +95,7 @@ pub enum Inst {
/// def!
CheckedDivOrRemSeq {
kind: DivOrRemKind,
size: u8,
size: OperandSize,
/// The divisor operand. Note it's marked as modified so that it gets assigned a register
/// different from the temporary.
divisor: Writable<Reg>,
@@ -101,7 +105,7 @@ pub enum Inst {
/// Do a sign-extend based on the sign of the value in rax into rdx: (cwd cdq cqo)
/// or al into ah: (cbw)
SignExtendData {
size: u8, // 1, 2, 4 or 8
size: OperandSize, // 1, 2, 4 or 8
},
/// Constant materialization: (imm32 imm64) reg.
@@ -149,14 +153,14 @@ pub enum Inst {
/// Integer stores: mov (b w l q) reg addr.
MovRM {
size: u8, // 1, 2, 4 or 8.
size: OperandSize, // 1, 2, 4 or 8.
src: Reg,
dst: SyntheticAmode,
},
/// Arithmetic shifts: (shl shr sar) (b w l q) imm reg.
ShiftR {
size: u8, // 1, 2, 4 or 8
size: OperandSize, // 1, 2, 4 or 8
kind: ShiftKind,
/// shift count: Some(0 .. #bits-in-type - 1), or None to mean "%cl".
num_bits: Option<u8>,
@@ -172,7 +176,7 @@ pub enum Inst {
/// Integer comparisons/tests: cmp or test (b w l q) (reg addr imm) reg.
CmpRmiR {
size: u8, // 1, 2, 4 or 8
size: OperandSize, // 1, 2, 4 or 8
opcode: CmpOpcode,
src: RegMemImm,
dst: Reg,
@@ -184,8 +188,7 @@ pub enum Inst {
/// Integer conditional move.
/// Overwrites the destination register.
Cmove {
/// Possible values are 2, 4 or 8. Checked in the related factory.
size: u8,
size: OperandSize, // 2, 4, or 8
cc: CC,
src: RegMem,
dst: Writable<Reg>,
@@ -588,32 +591,33 @@ impl Inst {
}
pub(crate) fn unary_rm_r(
size: u8,
size: OperandSize,
op: UnaryRmROpcode,
src: RegMem,
dst: Writable<Reg>,
) -> Self {
src.assert_regclass_is(RegClass::I64);
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
debug_assert!(size == 8 || size == 4 || size == 2);
debug_assert!(size.is_size(&[
OperandSize::Size16,
OperandSize::Size32,
OperandSize::Size64
]));
Self::UnaryRmR { size, op, src, dst }
}
pub(crate) fn not(size: u8, src: Writable<Reg>) -> Inst {
pub(crate) fn not(size: OperandSize, src: Writable<Reg>) -> Inst {
debug_assert_eq!(src.to_reg().get_class(), RegClass::I64);
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
Inst::Not { size, src }
}
pub(crate) fn neg(size: u8, src: Writable<Reg>) -> Inst {
pub(crate) fn neg(size: OperandSize, src: Writable<Reg>) -> Inst {
debug_assert_eq!(src.to_reg().get_class(), RegClass::I64);
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
Inst::Neg { size, src }
}
pub(crate) fn div(size: u8, signed: bool, divisor: RegMem) -> Inst {
pub(crate) fn div(size: OperandSize, signed: bool, divisor: RegMem) -> Inst {
divisor.assert_regclass_is(RegClass::I64);
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
Inst::Div {
size,
signed,
@@ -621,19 +625,22 @@ impl Inst {
}
}
pub(crate) fn mul_hi(size: u8, signed: bool, rhs: RegMem) -> Inst {
pub(crate) fn mul_hi(size: OperandSize, signed: bool, rhs: RegMem) -> Inst {
debug_assert!(size.is_size(&[
OperandSize::Size16,
OperandSize::Size32,
OperandSize::Size64
]));
rhs.assert_regclass_is(RegClass::I64);
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
Inst::MulHi { size, signed, rhs }
}
pub(crate) fn checked_div_or_rem_seq(
kind: DivOrRemKind,
size: u8,
size: OperandSize,
divisor: Writable<Reg>,
tmp: Option<Writable<Reg>>,
) -> Inst {
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
debug_assert!(divisor.to_reg().get_class() == RegClass::I64);
debug_assert!(tmp
.map(|tmp| tmp.to_reg().get_class() == RegClass::I64)
@@ -646,8 +653,7 @@ impl Inst {
}
}
pub(crate) fn sign_extend_data(size: u8) -> Inst {
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
pub(crate) fn sign_extend_data(size: OperandSize) -> Inst {
Inst::SignExtendData { size }
}
@@ -889,12 +895,7 @@ impl Inst {
}
}
pub(crate) fn mov_r_m(
size: u8, // 1, 2, 4 or 8
src: Reg,
dst: impl Into<SyntheticAmode>,
) -> Inst {
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
pub(crate) fn mov_r_m(size: OperandSize, src: Reg, dst: impl Into<SyntheticAmode>) -> Inst {
debug_assert!(src.get_class() == RegClass::I64);
Inst::MovRM {
size,
@@ -912,14 +913,13 @@ impl Inst {
}
pub(crate) fn shift_r(
size: u8,
size: OperandSize,
kind: ShiftKind,
num_bits: Option<u8>,
dst: Writable<Reg>,
) -> Inst {
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
debug_assert!(if let Some(num_bits) = num_bits {
num_bits < size * 8
num_bits < size.to_bits()
} else {
true
});
@@ -934,13 +934,8 @@ impl Inst {
/// Does a comparison of dst - src for operands of size `size`, as stated by the machine
/// instruction semantics. Be careful with the order of parameters!
pub(crate) fn cmp_rmi_r(
size: u8, // 1, 2, 4 or 8
src: RegMemImm,
dst: Reg,
) -> Inst {
pub(crate) fn cmp_rmi_r(size: OperandSize, src: RegMemImm, dst: Reg) -> Inst {
src.assert_regclass_is(RegClass::I64);
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
debug_assert_eq!(dst.get_class(), RegClass::I64);
Inst::CmpRmiR {
size,
@@ -951,13 +946,8 @@ impl Inst {
}
/// Does a comparison of dst & src for operands of size `size`.
pub(crate) fn test_rmi_r(
size: u8, // 1, 2, 4 or 8
src: RegMemImm,
dst: Reg,
) -> Inst {
pub(crate) fn test_rmi_r(size: OperandSize, src: RegMemImm, dst: Reg) -> Inst {
src.assert_regclass_is(RegClass::I64);
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
debug_assert_eq!(dst.get_class(), RegClass::I64);
Inst::CmpRmiR {
size,
@@ -978,8 +968,12 @@ impl Inst {
Inst::Setcc { cc, dst }
}
pub(crate) fn cmove(size: u8, cc: CC, src: RegMem, dst: Writable<Reg>) -> Inst {
debug_assert!(size == 8 || size == 4 || size == 2);
pub(crate) fn cmove(size: OperandSize, cc: CC, src: RegMem, dst: Writable<Reg>) -> Inst {
debug_assert!(size.is_size(&[
OperandSize::Size16,
OperandSize::Size32,
OperandSize::Size64
]));
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
Inst::Cmove { size, cc, src, dst }
}
@@ -1127,7 +1121,7 @@ impl Inst {
RegClass::I64 => {
// Always store the full register, to ensure that the high bits are properly set
// when doing a full reload.
Inst::mov_r_m(8 /* bytes */, from_reg, to_addr)
Inst::mov_r_m(OperandSize::Size64, from_reg, to_addr)
}
RegClass::V128 => {
let opcode = match ty {
@@ -1293,13 +1287,12 @@ impl PrettyPrint for Inst {
}
}
fn suffix_bwlq(size: u8) -> String {
fn suffix_bwlq(size: OperandSize) -> String {
match size {
1 => "b".to_string(),
2 => "w".to_string(),
4 => "l".to_string(),
8 => "q".to_string(),
_ => panic!("Inst(x64).show.suffixBWLQ: size={}", size),
OperandSize::Size8 => "b".to_string(),
OperandSize::Size16 => "w".to_string(),
OperandSize::Size32 => "l".to_string(),
OperandSize::Size64 => "q".to_string(),
}
}
@@ -1321,20 +1314,20 @@ impl PrettyPrint for Inst {
Inst::UnaryRmR { src, dst, op, size } => format!(
"{} {}, {}",
ljustify2(op.to_string(), suffix_bwlq(*size)),
src.show_rru_sized(mb_rru, *size),
show_ireg_sized(dst.to_reg(), mb_rru, *size),
src.show_rru_sized(mb_rru, size.to_bytes()),
show_ireg_sized(dst.to_reg(), mb_rru, size.to_bytes()),
),
Inst::Not { size, src } => format!(
"{} {}",
ljustify2("not".to_string(), suffix_bwlq(*size)),
show_ireg_sized(src.to_reg(), mb_rru, *size)
show_ireg_sized(src.to_reg(), mb_rru, size.to_bytes())
),
Inst::Neg { size, src } => format!(
"{} {}",
ljustify2("neg".to_string(), suffix_bwlq(*size)),
show_ireg_sized(src.to_reg(), mb_rru, *size)
show_ireg_sized(src.to_reg(), mb_rru, size.to_bytes())
),
Inst::Div {
@@ -1349,7 +1342,7 @@ impl PrettyPrint for Inst {
} else {
"div".into()
}),
divisor.show_rru_sized(mb_rru, *size)
divisor.show_rru_sized(mb_rru, size.to_bytes())
),
Inst::MulHi {
@@ -1361,7 +1354,7 @@ impl PrettyPrint for Inst {
} else {
"mul".to_string()
}),
rhs.show_rru_sized(mb_rru, *size)
rhs.show_rru_sized(mb_rru, size.to_bytes())
),
Inst::CheckedDivOrRemSeq {
@@ -1377,15 +1370,14 @@ impl PrettyPrint for Inst {
DivOrRemKind::SignedRem => "srem",
DivOrRemKind::UnsignedRem => "urem",
},
show_ireg_sized(divisor.to_reg(), mb_rru, *size),
show_ireg_sized(divisor.to_reg(), mb_rru, size.to_bytes()),
),
Inst::SignExtendData { size } => match size {
1 => "cbw",
2 => "cwd",
4 => "cdq",
8 => "cqo",
_ => unreachable!(),
OperandSize::Size8 => "cbw",
OperandSize::Size16 => "cwd",
OperandSize::Size32 => "cdq",
OperandSize::Size64 => "cqo",
}
.into(),
@@ -1611,7 +1603,7 @@ impl PrettyPrint for Inst {
Inst::MovRM { size, src, dst, .. } => format!(
"{} {}, {}",
ljustify2("mov".to_string(), suffix_bwlq(*size)),
show_ireg_sized(*src, mb_rru, *size),
show_ireg_sized(*src, mb_rru, size.to_bytes()),
dst.show_rru(mb_rru)
),
@@ -1624,14 +1616,14 @@ impl PrettyPrint for Inst {
None => format!(
"{} %cl, {}",
ljustify2(kind.to_string(), suffix_bwlq(*size)),
show_ireg_sized(dst.to_reg(), mb_rru, *size)
show_ireg_sized(dst.to_reg(), mb_rru, size.to_bytes())
),
Some(num_bits) => format!(
"{} ${}, {}",
ljustify2(kind.to_string(), suffix_bwlq(*size)),
num_bits,
show_ireg_sized(dst.to_reg(), mb_rru, *size)
show_ireg_sized(dst.to_reg(), mb_rru, size.to_bytes())
),
},
@@ -1655,8 +1647,8 @@ impl PrettyPrint for Inst {
format!(
"{} {}, {}",
ljustify2(op.to_string(), suffix_bwlq(*size)),
src.show_rru_sized(mb_rru, *size),
show_ireg_sized(*dst, mb_rru, *size)
src.show_rru_sized(mb_rru, size.to_bytes()),
show_ireg_sized(*dst, mb_rru, size.to_bytes())
)
}
@@ -1669,8 +1661,8 @@ impl PrettyPrint for Inst {
Inst::Cmove { size, cc, src, dst } => format!(
"{} {}, {}",
ljustify(format!("cmov{}{}", cc.to_string(), suffix_bwlq(*size))),
src.show_rru_sized(mb_rru, *size),
show_ireg_sized(dst.to_reg(), mb_rru, *size)
src.show_rru_sized(mb_rru, size.to_bytes()),
show_ireg_sized(dst.to_reg(), mb_rru, size.to_bytes())
),
Inst::XmmCmove {
@@ -1758,7 +1750,7 @@ impl PrettyPrint for Inst {
let size = ty.bytes() as u8;
format!(
"lock cmpxchg{} {}, {}",
suffix_bwlq(size),
suffix_bwlq(OperandSize::from_bytes(size as u32)),
show_ireg_sized(*src, mb_rru, size),
dst.show_rru(mb_rru)
)
@@ -1828,7 +1820,7 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
}
Inst::Div { size, divisor, .. } => {
collector.add_mod(Writable::from_reg(regs::rax()));
if *size == 1 {
if *size == OperandSize::Size8 {
collector.add_def(Writable::from_reg(regs::rdx()));
} else {
collector.add_mod(Writable::from_reg(regs::rdx()));
@@ -1852,12 +1844,11 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
}
}
Inst::SignExtendData { size } => match size {
1 => collector.add_mod(Writable::from_reg(regs::rax())),
2 | 4 | 8 => {
OperandSize::Size8 => collector.add_mod(Writable::from_reg(regs::rax())),
_ => {
collector.add_use(regs::rax());
collector.add_def(Writable::from_reg(regs::rdx()));
}
_ => unreachable!(),
},
Inst::UnaryRmR { src, dst, .. } | Inst::XmmUnaryRmR { src, dst, .. } => {
src.get_regs_as_uses(collector);
@@ -2547,7 +2538,7 @@ impl MachInst for Inst {
match self {
Self::VirtualSPOffsetAdj { offset } => Some(MachInstStackOpInfo::NomSPAdj(*offset)),
Self::MovRM {
size: 8,
size: OperandSize::Size8,
src,
dst: SyntheticAmode::NominalSPOffset { simm32 },
} => Some(MachInstStackOpInfo::StoreNomSPOff(*src, *simm32 as i64)),