machinst x64: implement bsr and lower Clz;

This commit is contained in:
Benjamin Bouvier
2020-07-03 17:11:03 +02:00
parent eda2d143ed
commit ec2209665a
5 changed files with 210 additions and 39 deletions

View File

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

View File

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

View File

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

View File

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