machinst x64: implement bsr and lower Clz;
This commit is contained in:
@@ -289,6 +289,26 @@ impl ToString for AluRmiROpcode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum ReadOnlyGprRmROpcode {
|
||||
/// Bit-scan reverse.
|
||||
Bsr,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ReadOnlyGprRmROpcode {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ReadOnlyGprRmROpcode::Bsr => write!(fmt, "bsr"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for ReadOnlyGprRmROpcode {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum InstructionSet {
|
||||
SSE,
|
||||
SSE2,
|
||||
|
||||
@@ -556,6 +556,40 @@ pub(crate) fn emit(
|
||||
}
|
||||
}
|
||||
|
||||
Inst::ReadOnly_Gpr_Rm_R { size, op, src, dst } => {
|
||||
let (prefix, rex_flags) = match size {
|
||||
2 => (LegacyPrefix::_66, RexFlags::clear_w()),
|
||||
4 => (LegacyPrefix::None, RexFlags::clear_w()),
|
||||
8 => (LegacyPrefix::None, RexFlags::set_w()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let (opcode, num_opcodes) = match op {
|
||||
ReadOnlyGprRmROpcode::Bsr => (0x0fbd, 2),
|
||||
};
|
||||
|
||||
match src {
|
||||
RegMem::Reg { reg: src } => emit_std_reg_reg(
|
||||
sink,
|
||||
prefix,
|
||||
opcode,
|
||||
num_opcodes,
|
||||
dst.to_reg(),
|
||||
*src,
|
||||
rex_flags,
|
||||
),
|
||||
RegMem::Mem { addr: src } => emit_std_reg_mem(
|
||||
sink,
|
||||
prefix,
|
||||
opcode,
|
||||
num_opcodes,
|
||||
dst.to_reg(),
|
||||
&src.finalize(state),
|
||||
rex_flags,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
Inst::Div {
|
||||
size,
|
||||
signed,
|
||||
|
||||
@@ -1154,6 +1154,20 @@ fn test_x64_emit() {
|
||||
"imull $76543210, %esi",
|
||||
));
|
||||
|
||||
// ========================================================
|
||||
// ReadOnly_Gpr_Rm_R
|
||||
|
||||
insns.push((
|
||||
Inst::read_only_gpr_rm_r(4, ReadOnlyGprRmROpcode::Bsr, RegMem::reg(rsi), w_rdi),
|
||||
"0FBDFE",
|
||||
"bsrl %esi, %edi",
|
||||
));
|
||||
insns.push((
|
||||
Inst::read_only_gpr_rm_r(8, ReadOnlyGprRmROpcode::Bsr, RegMem::reg(r15), w_rax),
|
||||
"490FBDC7",
|
||||
"bsrq %r15, %rax",
|
||||
));
|
||||
|
||||
// ========================================================
|
||||
// Div
|
||||
insns.push((
|
||||
|
||||
@@ -49,6 +49,14 @@ pub enum Inst {
|
||||
dst: Writable<Reg>,
|
||||
},
|
||||
|
||||
/// Instructions on GPR that only read src and defines dst (dst is not modified): bsr, etc.
|
||||
ReadOnly_Gpr_Rm_R {
|
||||
size: u8, // 2, 4 or 8
|
||||
op: ReadOnlyGprRmROpcode,
|
||||
src: RegMem,
|
||||
dst: Writable<Reg>,
|
||||
},
|
||||
|
||||
/// Integer quotient and remainder: (div idiv) $rax $rdx (reg addr)
|
||||
Div {
|
||||
size: u8, // 1, 2, 4 or 8
|
||||
@@ -295,6 +303,17 @@ impl Inst {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_only_gpr_rm_r(
|
||||
size: u8,
|
||||
op: ReadOnlyGprRmROpcode,
|
||||
src: RegMem,
|
||||
dst: Writable<Reg>,
|
||||
) -> Self {
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
|
||||
debug_assert!(size == 8 || size == 4 || size == 2);
|
||||
Self::ReadOnly_Gpr_Rm_R { size, op, src, dst }
|
||||
}
|
||||
|
||||
pub(crate) fn div(size: u8, signed: bool, divisor: RegMem, loc: SourceLoc) -> Inst {
|
||||
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
|
||||
Inst::Div {
|
||||
@@ -357,6 +376,11 @@ impl Inst {
|
||||
Inst::MovZX_RM_R { ext_mode, src, dst }
|
||||
}
|
||||
|
||||
pub(crate) fn movsx_rm_r(ext_mode: ExtMode, src: RegMem, dst: Writable<Reg>) -> Inst {
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
|
||||
Inst::MovSX_RM_R { ext_mode, src, dst }
|
||||
}
|
||||
|
||||
pub(crate) fn mov64_m_r(src: impl Into<SyntheticAmode>, dst: Writable<Reg>) -> Inst {
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
|
||||
Inst::Mov64_M_R {
|
||||
@@ -373,11 +397,6 @@ impl Inst {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn movsx_rm_r(ext_mode: ExtMode, src: RegMem, dst: Writable<Reg>) -> Inst {
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
|
||||
Inst::MovSX_RM_R { ext_mode, src, dst }
|
||||
}
|
||||
|
||||
pub(crate) fn mov_r_m(
|
||||
size: u8, // 1, 2, 4 or 8
|
||||
src: Reg,
|
||||
@@ -565,6 +584,7 @@ impl ShowWithRRU for Inst {
|
||||
|
||||
match self {
|
||||
Inst::Nop { len } => format!("{} len={}", ljustify("nop".to_string()), len),
|
||||
|
||||
Inst::Alu_RMI_R {
|
||||
is_64,
|
||||
op,
|
||||
@@ -576,6 +596,14 @@ impl ShowWithRRU for Inst {
|
||||
src.show_rru_sized(mb_rru, sizeLQ(*is_64)),
|
||||
show_ireg_sized(dst.to_reg(), mb_rru, sizeLQ(*is_64)),
|
||||
),
|
||||
|
||||
Inst::ReadOnly_Gpr_Rm_R { src, dst, op, size } => format!(
|
||||
"{} {}, {}",
|
||||
ljustify2(op.to_string(), suffixBWLQ(*size)),
|
||||
src.show_rru_sized(mb_rru, *size),
|
||||
show_ireg_sized(dst.to_reg(), mb_rru, *size),
|
||||
),
|
||||
|
||||
Inst::Div {
|
||||
size,
|
||||
signed,
|
||||
@@ -830,7 +858,7 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
||||
collector.add_use(regs::rax());
|
||||
collector.add_mod(Writable::from_reg(regs::rdx()));
|
||||
}
|
||||
Inst::XMM_Mov_RM_R { src, dst, .. } => {
|
||||
Inst::ReadOnly_Gpr_Rm_R { src, dst, .. } | Inst::XMM_Mov_RM_R { src, dst, .. } => {
|
||||
src.get_regs_as_uses(collector);
|
||||
collector.add_def(*dst);
|
||||
}
|
||||
@@ -1010,10 +1038,9 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
||||
match inst {
|
||||
// ** Nop
|
||||
Inst::Alu_RMI_R {
|
||||
is_64: _,
|
||||
op: _,
|
||||
ref mut src,
|
||||
ref mut dst,
|
||||
..
|
||||
} => {
|
||||
src.map_uses(mapper);
|
||||
map_mod(mapper, dst);
|
||||
@@ -1028,6 +1055,11 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
||||
ref mut src,
|
||||
ref mut dst,
|
||||
..
|
||||
}
|
||||
| Inst::ReadOnly_Gpr_Rm_R {
|
||||
ref mut src,
|
||||
ref mut dst,
|
||||
..
|
||||
} => {
|
||||
src.map_uses(mapper);
|
||||
map_def(mapper, dst);
|
||||
|
||||
Reference in New Issue
Block a user