Reimplement I32Clz without relying on LZCNT.

This commit is contained in:
Nick Lewycky
2019-10-15 12:50:33 -07:00
parent caae21c065
commit cf3d2a830d
2 changed files with 61 additions and 6 deletions

View File

@ -2341,12 +2341,57 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
Condition::Equal, Condition::Equal,
Location::Imm32(0), Location::Imm32(0),
), ),
Operator::I32Clz => Self::emit_xcnt_i32( Operator::I32Clz => {
a, let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
&mut self.machine, let src = match loc {
&mut self.value_stack, Location::Imm32(_) | Location::Memory(_, _) => {
Assembler::emit_lzcnt, let tmp = self.machine.acquire_temp_gpr().unwrap();
), a.emit_mov(Size::S32, loc, Location::GPR(tmp));
tmp
},
Location::GPR(reg) => reg,
_ => unreachable!(),
};
let ret = self.machine.acquire_locations(
a,
&[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))],
false,
)[0];
self.value_stack.push(ret);
let dst = match ret {
Location::Memory(_, _) => { self.machine.acquire_temp_gpr().unwrap() },
Location::GPR(reg) => reg,
_ => unreachable!(),
};
let zero_path = a.get_label();
let end = a.get_label();
a.emit_test_gpr_64(src);
a.emit_jmp(Condition::Equal, zero_path);
a.emit_bsr(Size::S32, Location::GPR(src), Location::GPR(dst));
a.emit_xor(Size::S32, Location::Imm32(31), Location::GPR(dst));
a.emit_jmp(Condition::None, end);
a.emit_label(zero_path);
a.emit_mov(Size::S32, Location::Imm32(32), Location::GPR(dst));
a.emit_label(end);
match loc {
Location::Imm32(_) | Location::Memory(_, _) => {
self.machine.release_temp_gpr(src);
},
_ => {}
};
match ret {
Location::Memory(_, _) => {
a.emit_mov(Size::S32, Location::GPR(dst), ret);
self.machine.release_temp_gpr(dst);
},
_ => {}
};
},
Operator::I32Ctz => Self::emit_xcnt_i32( Operator::I32Ctz => Self::emit_xcnt_i32(
a, a,
&mut self.machine, &mut self.machine,

View File

@ -90,6 +90,7 @@ pub trait Emitter {
fn emit_ror(&mut self, sz: Size, src: Location, dst: Location); fn emit_ror(&mut self, sz: Size, src: Location, dst: Location);
fn emit_and(&mut self, sz: Size, src: Location, dst: Location); fn emit_and(&mut self, sz: Size, src: Location, dst: Location);
fn emit_or(&mut self, sz: Size, src: Location, dst: Location); fn emit_or(&mut self, sz: Size, src: Location, dst: Location);
fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location);
fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location);
fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location);
fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location);
@ -753,6 +754,15 @@ impl Emitter for Assembler {
panic!("singlepass can't emit OR {:?} {:?} {:?}", sz, src, dst) panic!("singlepass can't emit OR {:?} {:?} {:?}", sz, src, dst)
}); });
} }
fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) {
binop_gpr_gpr!(bsr, self, sz, src, dst, {
binop_mem_gpr!(bsr, self, sz, src, dst, {
panic!("singlepass can't emit BSR {:?} {:?} {:?}", sz, src, dst)
})
});
}
fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) {
binop_gpr_gpr!(lzcnt, self, sz, src, dst, { binop_gpr_gpr!(lzcnt, self, sz, src, dst, {
binop_mem_gpr!(lzcnt, self, sz, src, dst, { binop_mem_gpr!(lzcnt, self, sz, src, dst, {