machinst x64: lower Ctz using the Bsf x86 instruction
This commit is contained in:
@@ -293,12 +293,15 @@ impl ToString for AluRmiROpcode {
|
|||||||
pub enum ReadOnlyGprRmROpcode {
|
pub enum ReadOnlyGprRmROpcode {
|
||||||
/// Bit-scan reverse.
|
/// Bit-scan reverse.
|
||||||
Bsr,
|
Bsr,
|
||||||
|
/// Bit-scan forward.
|
||||||
|
Bsf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ReadOnlyGprRmROpcode {
|
impl fmt::Debug for ReadOnlyGprRmROpcode {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ReadOnlyGprRmROpcode::Bsr => write!(fmt, "bsr"),
|
ReadOnlyGprRmROpcode::Bsr => write!(fmt, "bsr"),
|
||||||
|
ReadOnlyGprRmROpcode::Bsf => write!(fmt, "bsf"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -566,6 +566,7 @@ pub(crate) fn emit(
|
|||||||
|
|
||||||
let (opcode, num_opcodes) = match op {
|
let (opcode, num_opcodes) = match op {
|
||||||
ReadOnlyGprRmROpcode::Bsr => (0x0fbd, 2),
|
ReadOnlyGprRmROpcode::Bsr => (0x0fbd, 2),
|
||||||
|
ReadOnlyGprRmROpcode::Bsf => (0x0fbc, 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
match src {
|
match src {
|
||||||
|
|||||||
@@ -358,6 +358,38 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opcode::Ctz => {
|
||||||
|
// TODO when the x86 flags have use_bmi1, we can use TZCNT.
|
||||||
|
|
||||||
|
// General formula using bit-scan forward (BSF):
|
||||||
|
// bsf %src, %dst
|
||||||
|
// mov $(size_bits), %tmp
|
||||||
|
// cmovz %tmp, %dst
|
||||||
|
let ty = ctx.input_ty(insn, 0);
|
||||||
|
let ty = if ty.bits() < 32 { I32 } else { ty };
|
||||||
|
debug_assert!(ty == I32 || ty == I64);
|
||||||
|
|
||||||
|
let src = input_to_reg_mem(ctx, inputs[0]);
|
||||||
|
let dst = output_to_reg(ctx, outputs[0]);
|
||||||
|
|
||||||
|
let tmp = ctx.alloc_tmp(RegClass::I64, ty);
|
||||||
|
ctx.emit(Inst::imm_r(false /* 64 bits */, ty.bits() as u64, tmp));
|
||||||
|
|
||||||
|
ctx.emit(Inst::read_only_gpr_rm_r(
|
||||||
|
ty.bytes() as u8,
|
||||||
|
ReadOnlyGprRmROpcode::Bsf,
|
||||||
|
src,
|
||||||
|
dst,
|
||||||
|
));
|
||||||
|
|
||||||
|
ctx.emit(Inst::cmove(
|
||||||
|
ty.bytes() as u8,
|
||||||
|
CC::Z,
|
||||||
|
RegMem::reg(tmp.to_reg()),
|
||||||
|
dst,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Opcode::Uextend
|
Opcode::Uextend
|
||||||
| Opcode::Sextend
|
| Opcode::Sextend
|
||||||
| Opcode::Bint
|
| Opcode::Bint
|
||||||
|
|||||||
Reference in New Issue
Block a user