Browse Source

machinst x64: lower Ctz using the Bsf x86 instruction

pull/2034/head
Benjamin Bouvier 4 years ago
parent
commit
6f5403a94b
  1. 3
      cranelift/codegen/src/isa/x64/inst/args.rs
  2. 1
      cranelift/codegen/src/isa/x64/inst/emit.rs
  3. 32
      cranelift/codegen/src/isa/x64/lower.rs

3
cranelift/codegen/src/isa/x64/inst/args.rs

@ -293,12 +293,15 @@ impl ToString for AluRmiROpcode {
pub enum ReadOnlyGprRmROpcode {
/// Bit-scan reverse.
Bsr,
/// Bit-scan forward.
Bsf,
}
impl fmt::Debug for ReadOnlyGprRmROpcode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
ReadOnlyGprRmROpcode::Bsr => write!(fmt, "bsr"),
ReadOnlyGprRmROpcode::Bsf => write!(fmt, "bsf"),
}
}
}

1
cranelift/codegen/src/isa/x64/inst/emit.rs

@ -566,6 +566,7 @@ pub(crate) fn emit(
let (opcode, num_opcodes) = match op {
ReadOnlyGprRmROpcode::Bsr => (0x0fbd, 2),
ReadOnlyGprRmROpcode::Bsf => (0x0fbc, 2),
};
match src {

32
cranelift/codegen/src/isa/x64/lower.rs

@ -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::Sextend
| Opcode::Bint

Loading…
Cancel
Save