mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 15:59:20 +03:00
wasm_interp: Implement float ops that have int equivalents
This commit is contained in:
parent
fc10c520b1
commit
284eeb5537
@ -779,19 +779,79 @@ impl<'a> Instance<'a> {
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
|
||||
F32EQ => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32NE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32LT => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32GT => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32LE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32GE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32EQ => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
let result: bool = arg1 == arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F32NE => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
let result: bool = arg1 != arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F32LT => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
let result: bool = arg1 < arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F32GT => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
let result: bool = arg1 > arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F32LE => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
let result: bool = arg1 <= arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F32GE => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
let result: bool = arg1 >= arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
|
||||
F64EQ => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64NE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64LT => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64GT => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64LE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64GE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64EQ => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
let result: bool = arg1 == arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F64NE => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
let result: bool = arg1 != arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F64LT => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
let result: bool = arg1 < arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F64GT => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
let result: bool = arg1 > arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F64LE => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
let result: bool = arg1 <= arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
F64GE => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
let result: bool = arg1 >= arg2;
|
||||
self.value_stack.push(Value::I32(result as i32));
|
||||
}
|
||||
|
||||
I32CLZ => {
|
||||
let arg = self.value_stack.pop_u32();
|
||||
@ -990,10 +1050,26 @@ impl<'a> Instance<'a> {
|
||||
F32TRUNC => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32NEAREST => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32SQRT => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32ADD => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32SUB => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32MUL => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32DIV => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32ADD => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
self.value_stack.push(Value::F32(arg1 + arg2));
|
||||
}
|
||||
F32SUB => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
self.value_stack.push(Value::F32(arg1 - arg2));
|
||||
}
|
||||
F32MUL => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
self.value_stack.push(Value::F32(arg1 * arg2));
|
||||
}
|
||||
F32DIV => {
|
||||
let arg2 = self.value_stack.pop_f32();
|
||||
let arg1 = self.value_stack.pop_f32();
|
||||
self.value_stack.push(Value::F32(arg1 / arg2));
|
||||
}
|
||||
F32MIN => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32MAX => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F32COPYSIGN => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
@ -1005,10 +1081,26 @@ impl<'a> Instance<'a> {
|
||||
F64TRUNC => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64NEAREST => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64SQRT => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64ADD => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64SUB => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64MUL => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64DIV => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64ADD => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
self.value_stack.push(Value::F64(arg1 + arg2));
|
||||
}
|
||||
F64SUB => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
self.value_stack.push(Value::F64(arg1 - arg2));
|
||||
}
|
||||
F64MUL => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
self.value_stack.push(Value::F64(arg1 * arg2));
|
||||
}
|
||||
F64DIV => {
|
||||
let arg2 = self.value_stack.pop_f64();
|
||||
let arg1 = self.value_stack.pop_f64();
|
||||
self.value_stack.push(Value::F64(arg1 / arg2));
|
||||
}
|
||||
F64MIN => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64MAX => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
F64COPYSIGN => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||
|
108
crates/wasm_interp/tests/test_f32.rs
Normal file
108
crates/wasm_interp/tests/test_f32.rs
Normal file
@ -0,0 +1,108 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use roc_wasm_interp::test_utils::test_op_example;
|
||||
use roc_wasm_module::{opcodes::OpCode, opcodes::OpCode::*, Value};
|
||||
|
||||
fn test_f32_comparison(op: OpCode, arg1: f32, arg2: f32, expected: bool) {
|
||||
test_op_example(
|
||||
op,
|
||||
[Value::F32(arg1), Value::F32(arg2)],
|
||||
Value::I32(expected as i32),
|
||||
)
|
||||
}
|
||||
|
||||
fn test_f32_binop(op: OpCode, arg1: f32, arg2: f32, expected: f32) {
|
||||
test_op_example(
|
||||
op,
|
||||
[Value::F32(arg1), Value::F32(arg2)],
|
||||
Value::F32(expected),
|
||||
)
|
||||
}
|
||||
|
||||
// fn test_f32_unop(op: OpCode, arg: f32, expected: f32) {
|
||||
// test_op_example(op, [Value::F32(arg)], Value::F32(expected))
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_f32eq() {
|
||||
let op = F32EQ;
|
||||
test_f32_comparison(op, 1.1, 1.1, true);
|
||||
test_f32_comparison(op, 1.1, -1.1, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32ne() {
|
||||
let op = F32NE;
|
||||
test_f32_comparison(op, 1.1, 1.1, false);
|
||||
test_f32_comparison(op, 1.1, -1.1, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32lt() {
|
||||
let op = F32LT;
|
||||
test_f32_comparison(op, 1.1, 1.1, false);
|
||||
test_f32_comparison(op, 1.1, -1.1, false);
|
||||
test_f32_comparison(op, -1.1, 1.1, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32gt() {
|
||||
let op = F32GT;
|
||||
test_f32_comparison(op, 1.1, 1.1, false);
|
||||
test_f32_comparison(op, 1.1, -1.1, true);
|
||||
test_f32_comparison(op, -1.1, 1.1, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32le() {
|
||||
let op = F32LE;
|
||||
test_f32_comparison(op, 1.1, 1.1, true);
|
||||
test_f32_comparison(op, 1.1, -1.1, false);
|
||||
test_f32_comparison(op, -1.1, 1.1, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32ge() {
|
||||
let op = F32GE;
|
||||
test_f32_comparison(op, 1.1, 1.1, true);
|
||||
test_f32_comparison(op, 1.1, -1.1, true);
|
||||
test_f32_comparison(op, -1.1, 1.1, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32add() {
|
||||
let op = F32ADD;
|
||||
test_f32_binop(op, 0.0, 0.0, 0.0);
|
||||
test_f32_binop(op, -1.1, -1.1, -2.2);
|
||||
test_f32_binop(op, 1.1, 1.1, 2.2);
|
||||
test_f32_binop(op, 1.1, -1.1, 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32sub() {
|
||||
let op = F32SUB;
|
||||
test_f32_binop(op, 0.0, 0.0, 0.0);
|
||||
test_f32_binop(op, -1.1, -1.1, 0.0);
|
||||
test_f32_binop(op, 1.1, -1.1, 2.2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32mul() {
|
||||
let op = F32MUL;
|
||||
test_f32_binop(op, 1.1, 0.0, 0.0);
|
||||
test_f32_binop(op, -1.5, -1.5, 2.25);
|
||||
test_f32_binop(op, 1.5, 1.5, 2.25);
|
||||
test_f32_binop(op, 1.5, -1.5, -2.25);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32div() {
|
||||
let op = F32DIV;
|
||||
test_f32_binop(op, -1.1, -1.1, 1.0);
|
||||
test_f32_binop(op, 1.1, -1.1, -1.0);
|
||||
test_f32_binop(op, 5.0, 2.0, 2.5);
|
||||
|
||||
test_f32_binop(op, 1.0, 0.0, f32::INFINITY);
|
||||
test_f32_binop(op, -1.0, 0.0, f32::NEG_INFINITY);
|
||||
// test_f32_binop(op, 0.0, 0.0, f32::NAN); // can't check NaN for equality! LOL
|
||||
}
|
108
crates/wasm_interp/tests/test_f64.rs
Normal file
108
crates/wasm_interp/tests/test_f64.rs
Normal file
@ -0,0 +1,108 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use roc_wasm_interp::test_utils::test_op_example;
|
||||
use roc_wasm_module::{opcodes::OpCode, opcodes::OpCode::*, Value};
|
||||
|
||||
fn test_f64_comparison(op: OpCode, arg1: f64, arg2: f64, expected: bool) {
|
||||
test_op_example(
|
||||
op,
|
||||
[Value::F64(arg1), Value::F64(arg2)],
|
||||
Value::I32(expected as i32),
|
||||
)
|
||||
}
|
||||
|
||||
fn test_f64_binop(op: OpCode, arg1: f64, arg2: f64, expected: f64) {
|
||||
test_op_example(
|
||||
op,
|
||||
[Value::F64(arg1), Value::F64(arg2)],
|
||||
Value::F64(expected),
|
||||
)
|
||||
}
|
||||
|
||||
// fn test_f64_unop(op: OpCode, arg: f64, expected: f64) {
|
||||
// test_op_example(op, [Value::F64(arg)], Value::F64(expected))
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_f64eq() {
|
||||
let op = F64EQ;
|
||||
test_f64_comparison(op, 1.1, 1.1, true);
|
||||
test_f64_comparison(op, 1.1, -1.1, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64ne() {
|
||||
let op = F64NE;
|
||||
test_f64_comparison(op, 1.1, 1.1, false);
|
||||
test_f64_comparison(op, 1.1, -1.1, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64lt() {
|
||||
let op = F64LT;
|
||||
test_f64_comparison(op, 1.1, 1.1, false);
|
||||
test_f64_comparison(op, 1.1, -1.1, false);
|
||||
test_f64_comparison(op, -1.1, 1.1, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64gt() {
|
||||
let op = F64GT;
|
||||
test_f64_comparison(op, 1.1, 1.1, false);
|
||||
test_f64_comparison(op, 1.1, -1.1, true);
|
||||
test_f64_comparison(op, -1.1, 1.1, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64le() {
|
||||
let op = F64LE;
|
||||
test_f64_comparison(op, 1.1, 1.1, true);
|
||||
test_f64_comparison(op, 1.1, -1.1, false);
|
||||
test_f64_comparison(op, -1.1, 1.1, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64ge() {
|
||||
let op = F64GE;
|
||||
test_f64_comparison(op, 1.1, 1.1, true);
|
||||
test_f64_comparison(op, 1.1, -1.1, true);
|
||||
test_f64_comparison(op, -1.1, 1.1, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64add() {
|
||||
let op = F64ADD;
|
||||
test_f64_binop(op, 0.0, 0.0, 0.0);
|
||||
test_f64_binop(op, -1.1, -1.1, -2.2);
|
||||
test_f64_binop(op, 1.1, 1.1, 2.2);
|
||||
test_f64_binop(op, 1.1, -1.1, 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64sub() {
|
||||
let op = F64SUB;
|
||||
test_f64_binop(op, 0.0, 0.0, 0.0);
|
||||
test_f64_binop(op, -1.1, -1.1, 0.0);
|
||||
test_f64_binop(op, 1.1, -1.1, 2.2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64mul() {
|
||||
let op = F64MUL;
|
||||
test_f64_binop(op, 1.1, 0.0, 0.0);
|
||||
test_f64_binop(op, -1.5, -1.5, 2.25);
|
||||
test_f64_binop(op, 1.5, 1.5, 2.25);
|
||||
test_f64_binop(op, 1.5, -1.5, -2.25);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64div() {
|
||||
let op = F64DIV;
|
||||
test_f64_binop(op, -1.1, -1.1, 1.0);
|
||||
test_f64_binop(op, 1.1, -1.1, -1.0);
|
||||
test_f64_binop(op, 5.0, 2.0, 2.5);
|
||||
|
||||
test_f64_binop(op, 1.0, 0.0, f64::INFINITY);
|
||||
test_f64_binop(op, -1.0, 0.0, f64::NEG_INFINITY);
|
||||
// test_f64_binop(op, 0.0, 0.0, f64::NAN); // can't check NaN for equality! LOL
|
||||
}
|
Loading…
Reference in New Issue
Block a user