mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
wasm_interp: float rounding ops
This commit is contained in:
parent
714586fac1
commit
17810d5134
3 changed files with 148 additions and 10 deletions
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue