clz/ctz/popcnt

This commit is contained in:
Jef
2019-01-17 13:51:18 +01:00
parent 74d168ec4b
commit e0f032a0e5
4 changed files with 141 additions and 22 deletions

View File

@@ -453,9 +453,9 @@ type Stack = Vec<StackValue>;
pub enum MemoryAccessMode {
/// This is slower than using `Unchecked` mode, but works in
/// any scenario, running on a system that can't index more
/// memory than the compiled Wasm can being the most important
/// one.
/// any scenario (the most important scenario being when we're
/// running on a system that can't index much more memory than
/// the Wasm).
Checked,
/// This means that checks are _not emitted by the compiler_!
/// If you're using WebAssembly to run untrusted code, you
@@ -491,6 +491,35 @@ impl StackDepth {
}
}
macro_rules! unop {
($name:ident, $instr:ident, $reg_ty:ident, $typ:ty, $const_fallback:expr) => {
pub fn $name(&mut self) {
let val = self.pop();
let out_val = match val.location(&self.block_state.locals) {
ValueLocation::Immediate(imm) => Value::Immediate($const_fallback(imm as $typ) as _),
ValueLocation::Stack(offset) => {
let offset = self.adjusted_offset(offset);
let temp = self.block_state.regs.take_scratch_gpr();
dynasm!(self.asm
; $instr $reg_ty(temp), [rsp + offset]
);
Value::Temp(temp)
}
ValueLocation::Reg(reg) => {
let temp = self.block_state.regs.take_scratch_gpr();
dynasm!(self.asm
; $instr $reg_ty(temp), $reg_ty(reg)
);
Value::Temp(temp)
}
};
self.push(out_val);
}
}
}
macro_rules! cmp_i32 {
($name:ident, $instr:ident, $reverse_instr:ident, $const_fallback:expr) => {
pub fn $name(&mut self) {
@@ -1476,6 +1505,13 @@ impl Context<'_> {
}
}
unop!(i32_clz, lzcnt, Rd, u32, u32::leading_zeros);
unop!(i64_clz, lzcnt, Rq, u64, |a: u64| a.leading_zeros() as u64);
unop!(i32_ctz, tzcnt, Rd, u32, u32::trailing_zeros);
unop!(i64_ctz, tzcnt, Rq, u64, |a: u64| a.trailing_zeros() as u64);
unop!(i32_popcnt, popcnt, Rd, u32, u32::count_ones);
unop!(i64_popcnt, popcnt, Rq, u64, |a: u64| a.count_ones() as u64);
// TODO: Use `lea` when the LHS operand isn't a temporary but both of the operands
// are in registers.
commutative_binop_i32!(i32_add, add, |a, b| (a as i32).wrapping_add(b as i32));