diff --git a/cranelift/codegen/src/isa/x64/inst/args.rs b/cranelift/codegen/src/isa/x64/inst/args.rs index f7bd6a2fef..9c6adef11d 100644 --- a/cranelift/codegen/src/isa/x64/inst/args.rs +++ b/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"), } } } diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs index f27bfa8b31..4497d26c99 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit.rs +++ b/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 { diff --git a/cranelift/codegen/src/isa/x64/lower.rs b/cranelift/codegen/src/isa/x64/lower.rs index 2f7aa6774d..cde9054619 100644 --- a/cranelift/codegen/src/isa/x64/lower.rs +++ b/cranelift/codegen/src/isa/x64/lower.rs @@ -358,6 +358,38 @@ fn lower_insn_to_regs>( )); } + 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