wasm_interp: float rounding ops

This commit is contained in:
Brian Carroll 2022-11-29 08:43:56 +00:00
parent 714586fac1
commit 17810d5134
No known key found for this signature in database
GPG key ID: 5C7B2EC4101703C0
3 changed files with 148 additions and 10 deletions

View file

@ -1051,11 +1051,42 @@ impl<'a> Instance<'a> {
let arg = self.value_stack.pop_f32(); let arg = self.value_stack.pop_f32();
self.value_stack.push(Value::F32(-arg)); self.value_stack.push(Value::F32(-arg));
} }
F32CEIL => todo!("{:?} @ {:#x}", op_code, file_offset), F32CEIL => {
F32FLOOR => todo!("{:?} @ {:#x}", op_code, file_offset), let arg = self.value_stack.pop_f32();
F32TRUNC => todo!("{:?} @ {:#x}", op_code, file_offset), self.value_stack.push(Value::F32(arg.ceil()));
F32NEAREST => todo!("{:?} @ {:#x}", op_code, file_offset), }
F32SQRT => todo!("{:?} @ {:#x}", op_code, file_offset), F32FLOOR => {
let arg = self.value_stack.pop_f32();
self.value_stack.push(Value::F32(arg.floor()));
}
F32TRUNC => {
let arg = self.value_stack.pop_f32();
self.value_stack.push(Value::F32(arg.trunc()));
}
F32NEAREST => {
// https://webassembly.github.io/spec/core/exec/numerics.html#op-fnearest
let arg = self.value_stack.pop_f32();
let rounded = arg.round(); // "Rounds half-way cases away from 0.0"
let frac = arg - rounded;
let result = if frac == 0.5 || frac == -0.5 {
let rounded_half = rounded / 2.0;
let is_rounded_even = rounded_half.trunc() == rounded_half;
if is_rounded_even {
rounded
} else if rounded < arg {
rounded + 1.0
} else {
rounded - 1.0
}
} else {
rounded
};
self.value_stack.push(Value::F32(result));
}
F32SQRT => {
let arg = self.value_stack.pop_f32();
self.value_stack.push(Value::F32(arg.sqrt()));
}
F32ADD => { F32ADD => {
let arg2 = self.value_stack.pop_f32(); let arg2 = self.value_stack.pop_f32();
let arg1 = self.value_stack.pop_f32(); let arg1 = self.value_stack.pop_f32();
@ -1088,11 +1119,42 @@ impl<'a> Instance<'a> {
let arg = self.value_stack.pop_f64(); let arg = self.value_stack.pop_f64();
self.value_stack.push(Value::F64(-arg)); self.value_stack.push(Value::F64(-arg));
} }
F64CEIL => todo!("{:?} @ {:#x}", op_code, file_offset), F64CEIL => {
F64FLOOR => todo!("{:?} @ {:#x}", op_code, file_offset), let arg = self.value_stack.pop_f64();
F64TRUNC => todo!("{:?} @ {:#x}", op_code, file_offset), self.value_stack.push(Value::F64(arg.ceil()));
F64NEAREST => todo!("{:?} @ {:#x}", op_code, file_offset), }
F64SQRT => todo!("{:?} @ {:#x}", op_code, file_offset), F64FLOOR => {
let arg = self.value_stack.pop_f64();
self.value_stack.push(Value::F64(arg.floor()));
}
F64TRUNC => {
let arg = self.value_stack.pop_f64();
self.value_stack.push(Value::F64(arg.trunc()));
}
F64NEAREST => {
// https://webassembly.github.io/spec/core/exec/numerics.html#op-fnearest
let arg = self.value_stack.pop_f64();
let rounded = arg.round(); // "Rounds half-way cases away from 0.0"
let frac = arg - rounded;
let result = if frac == 0.5 || frac == -0.5 {
let rounded_half = rounded / 2.0;
let is_rounded_even = rounded_half.trunc() == rounded_half;
if is_rounded_even {
rounded
} else if rounded < arg {
rounded + 1.0
} else {
rounded - 1.0
}
} else {
rounded
};
self.value_stack.push(Value::F64(result));
}
F64SQRT => {
let arg = self.value_stack.pop_f64();
self.value_stack.push(Value::F64(arg.sqrt()));
}
F64ADD => { F64ADD => {
let arg2 = self.value_stack.pop_f64(); let arg2 = self.value_stack.pop_f64();
let arg1 = self.value_stack.pop_f64(); let arg1 = self.value_stack.pop_f64();

View file

@ -85,6 +85,44 @@ fn test_f32neg() {
test_f32_unop(op, -1.1, 1.1); test_f32_unop(op, -1.1, 1.1);
} }
#[test]
fn test_f32ceil() {
let op = F32CEIL;
test_f32_unop(op, 1.1, 2.0);
test_f32_unop(op, -1.1, -1.0);
}
#[test]
fn test_f32floor() {
let op = F32FLOOR;
test_f32_unop(op, 1.1, 1.0);
test_f32_unop(op, -1.1, -2.0);
}
#[test]
fn test_f32trunc() {
let op = F32TRUNC;
test_f32_unop(op, 1.1, 1.0);
test_f32_unop(op, -1.1, -1.0);
}
#[test]
fn test_f32nearest() {
let op = F32NEAREST;
test_f32_unop(op, 1.4, 1.0);
test_f32_unop(op, 1.6, 2.0);
test_f32_unop(op, -1.4, -1.0);
test_f32_unop(op, -1.6, -2.0);
test_f32_unop(op, 1.5, 2.0);
test_f32_unop(op, 2.5, 2.0);
}
#[test]
fn test_f32sqrt() {
let op = F32SQRT;
test_f32_unop(op, 4.0, 2.0);
}
#[test] #[test]
fn test_f32add() { fn test_f32add() {
let op = F32ADD; let op = F32ADD;

View file

@ -85,6 +85,44 @@ fn test_f64neg() {
test_f64_unop(op, -1.1, 1.1); test_f64_unop(op, -1.1, 1.1);
} }
#[test]
fn test_f64ceil() {
let op = F64CEIL;
test_f64_unop(op, 1.1, 2.0);
test_f64_unop(op, -1.1, -1.0);
}
#[test]
fn test_f64floor() {
let op = F64FLOOR;
test_f64_unop(op, 1.1, 1.0);
test_f64_unop(op, -1.1, -2.0);
}
#[test]
fn test_f64trunc() {
let op = F64TRUNC;
test_f64_unop(op, 1.1, 1.0);
test_f64_unop(op, -1.1, -1.0);
}
#[test]
fn test_f64nearest() {
let op = F64NEAREST;
test_f64_unop(op, 1.4, 1.0);
test_f64_unop(op, 1.6, 2.0);
test_f64_unop(op, -1.4, -1.0);
test_f64_unop(op, -1.6, -2.0);
test_f64_unop(op, 1.5, 2.0);
test_f64_unop(op, 2.5, 2.0);
}
#[test]
fn test_f64sqrt() {
let op = F64SQRT;
test_f64_unop(op, 4.0, 2.0);
}
#[test] #[test]
fn test_f64add() { fn test_f64add() {
let op = F64ADD; let op = F64ADD;