wasm_interp: Implement lots of i64 ops by copy-pasting from i32

This commit is contained in:
Brian Carroll 2022-11-28 17:10:28 +00:00
parent 56ddd1f29b
commit 3881296fb4
No known key found for this signature in database
GPG Key ID: 5C7B2EC4101703C0
3 changed files with 360 additions and 11 deletions

View File

@ -646,6 +646,7 @@ impl<'a> ExecutionState<'a> {
self.value_stack.push(Value::F64(value));
self.program_counter += 8;
}
I32EQZ => {
let arg = self.value_stack.pop_i32();
let result: bool = arg == 0;
@ -712,17 +713,71 @@ impl<'a> ExecutionState<'a> {
self.value_stack.push(Value::I32(result as i32));
}
I64EQZ => todo!("{:?} @ {:#x}", op_code, file_offset),
I64EQ => todo!("{:?} @ {:#x}", op_code, file_offset),
I64NE => todo!("{:?} @ {:#x}", op_code, file_offset),
I64LTS => todo!("{:?} @ {:#x}", op_code, file_offset),
I64LTU => todo!("{:?} @ {:#x}", op_code, file_offset),
I64GTS => todo!("{:?} @ {:#x}", op_code, file_offset),
I64GTU => todo!("{:?} @ {:#x}", op_code, file_offset),
I64LES => todo!("{:?} @ {:#x}", op_code, file_offset),
I64LEU => todo!("{:?} @ {:#x}", op_code, file_offset),
I64GES => todo!("{:?} @ {:#x}", op_code, file_offset),
I64GEU => todo!("{:?} @ {:#x}", op_code, file_offset),
I64EQZ => {
let arg = self.value_stack.pop_i64();
let result: bool = arg == 0;
self.value_stack.push(Value::I64(result as i64));
}
I64EQ => {
let arg2 = self.value_stack.pop_i64();
let arg1 = self.value_stack.pop_i64();
let result: bool = arg1 == arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64NE => {
let arg2 = self.value_stack.pop_i64();
let arg1 = self.value_stack.pop_i64();
let result: bool = arg1 != arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64LTS => {
let arg2 = self.value_stack.pop_i64();
let arg1 = self.value_stack.pop_i64();
let result: bool = arg1 < arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64LTU => {
let arg2 = self.value_stack.pop_u64();
let arg1 = self.value_stack.pop_u64();
let result: bool = arg1 < arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64GTS => {
let arg2 = self.value_stack.pop_i64();
let arg1 = self.value_stack.pop_i64();
let result: bool = arg1 > arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64GTU => {
let arg2 = self.value_stack.pop_u64();
let arg1 = self.value_stack.pop_u64();
let result: bool = arg1 > arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64LES => {
let arg2 = self.value_stack.pop_i64();
let arg1 = self.value_stack.pop_i64();
let result: bool = arg1 <= arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64LEU => {
let arg2 = self.value_stack.pop_u64();
let arg1 = self.value_stack.pop_u64();
let result: bool = arg1 <= arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64GES => {
let arg2 = self.value_stack.pop_i64();
let arg1 = self.value_stack.pop_i64();
let result: bool = arg1 >= arg2;
self.value_stack.push(Value::I64(result as i64));
}
I64GEU => {
let arg2 = self.value_stack.pop_u64();
let arg1 = self.value_stack.pop_u64();
let result: bool = arg1 >= arg2;
self.value_stack.push(Value::I64(result as i64));
}
F32EQ => todo!("{:?} @ {:#x}", op_code, file_offset),
F32NE => todo!("{:?} @ {:#x}", op_code, file_offset),

View File

@ -126,6 +126,17 @@ impl<'a> ValueStack<'a> {
}
}
pub fn pop_u64(&mut self) -> u64 {
match (self.is_float.pop(), self.is_64.pop()) {
(Some(false), Some(true)) => pop_bytes!(u64, self.bytes),
(Some(is_float), Some(is_64)) => panic!(
"Expected I64 but found {:?}",
type_from_flags(is_float, is_64)
),
_ => panic!("Expected I64 but value stack was empty"),
}
}
pub fn pop_i64(&mut self) -> i64 {
match (self.is_float.pop(), self.is_64.pop()) {
(Some(false), Some(true)) => pop_bytes!(i64, self.bytes),

View File

@ -0,0 +1,283 @@
#![cfg(test)]
use roc_wasm_interp::test_utils::test_op_example;
use roc_wasm_module::{opcodes::OpCode, opcodes::OpCode::*, Value};
fn test_i64_binop(op: OpCode, arg1: i64, arg2: i64, expected: i64) {
test_op_example(
op,
[Value::from(arg1), Value::from(arg2)],
Value::from(expected),
)
}
fn test_u64_binop(op: OpCode, arg1: u64, arg2: u64, expected: u64) {
test_op_example(
op,
[Value::from(arg1), Value::from(arg2)],
Value::from(expected),
)
}
fn test_i64_unop(op: OpCode, arg: i64, expected: i64) {
test_op_example(op, [Value::from(arg)], Value::from(expected))
}
#[test]
fn test_i64eqz() {
let op = I64EQZ;
test_i64_unop(op, 0, 1);
test_i64_unop(op, i64::MIN, 0);
test_i64_unop(op, i64::MAX, 0);
}
#[test]
fn test_i64eq() {
let op = I64EQ;
test_i64_binop(op, 0, 0, 1);
test_i64_binop(op, i64::MIN, i64::MIN, 1);
test_i64_binop(op, i64::MAX, i64::MAX, 1);
test_i64_binop(op, i64::MIN, i64::MAX, 0);
test_i64_binop(op, i64::MAX, i64::MIN, 0);
}
#[test]
fn test_i64ne() {
let op = I64NE;
test_i64_binop(op, 0, 0, 0);
test_i64_binop(op, i64::MIN, i64::MIN, 0);
test_i64_binop(op, i64::MAX, i64::MAX, 0);
test_i64_binop(op, i64::MIN, i64::MAX, 1);
test_i64_binop(op, i64::MAX, i64::MIN, 1);
}
#[test]
fn test_i64lts() {
let op = I64LTS;
test_i64_binop(op, 0, 0, 0);
test_i64_binop(op, i64::MIN, i64::MIN, 0);
test_i64_binop(op, i64::MAX, i64::MAX, 0);
test_i64_binop(op, i64::MIN, i64::MAX, 1);
test_i64_binop(op, i64::MAX, i64::MIN, 0);
}
#[test]
fn test_i64ltu() {
let op = I64LTU;
test_u64_binop(op, 0, 0, 0);
test_u64_binop(op, u64::MIN, u64::MIN, 0);
test_u64_binop(op, u64::MAX, u64::MAX, 0);
test_u64_binop(op, u64::MIN, u64::MAX, 1);
test_u64_binop(op, u64::MAX, u64::MIN, 0);
}
#[test]
fn test_i64gts() {
let op = I64GTS;
test_i64_binop(op, 0, 0, 0);
test_i64_binop(op, i64::MIN, i64::MIN, 0);
test_i64_binop(op, i64::MAX, i64::MAX, 0);
test_i64_binop(op, i64::MIN, i64::MAX, 0);
test_i64_binop(op, i64::MAX, i64::MIN, 1);
}
#[test]
fn test_i64gtu() {
let op = I64GTU;
test_u64_binop(op, 0, 0, 0);
test_u64_binop(op, u64::MIN, u64::MIN, 0);
test_u64_binop(op, u64::MAX, u64::MAX, 0);
test_u64_binop(op, u64::MIN, u64::MAX, 0);
test_u64_binop(op, u64::MAX, u64::MIN, 1);
}
#[test]
fn test_i64les() {
let op = I64LES;
test_i64_binop(op, 0, 0, 1);
test_i64_binop(op, i64::MIN, i64::MIN, 1);
test_i64_binop(op, i64::MAX, i64::MAX, 1);
test_i64_binop(op, i64::MIN, i64::MAX, 1);
test_i64_binop(op, i64::MAX, i64::MIN, 0);
}
#[test]
fn test_i64leu() {
let op = I64LEU;
test_u64_binop(op, 0, 0, 1);
test_u64_binop(op, u64::MIN, u64::MIN, 1);
test_u64_binop(op, u64::MAX, u64::MAX, 1);
test_u64_binop(op, u64::MIN, u64::MAX, 1);
test_u64_binop(op, u64::MAX, u64::MIN, 0);
}
#[test]
fn test_i64ges() {
let op = I64GES;
test_i64_binop(op, 0, 0, 1);
test_i64_binop(op, i64::MIN, i64::MIN, 1);
test_i64_binop(op, i64::MAX, i64::MAX, 1);
test_i64_binop(op, i64::MIN, i64::MAX, 0);
test_i64_binop(op, i64::MAX, i64::MIN, 1);
}
#[test]
fn test_i64geu() {
let op = I64GEU;
test_u64_binop(op, 0, 0, 1);
test_u64_binop(op, u64::MIN, u64::MIN, 1);
test_u64_binop(op, u64::MAX, u64::MAX, 1);
test_u64_binop(op, u64::MIN, u64::MAX, 0);
test_u64_binop(op, u64::MAX, u64::MIN, 1);
}
// #[test]
// fn test_i64clz() {
// let op = I64CLZ;
// test_i64_unop(op, 0, 64);
// test_i64_unop(op, -1, 0);
// test_i64_unop(op, 1, 31);
// test_i64_unop(op, 1024, 21);
// }
// #[test]
// fn test_i64ctz() {
// let op = I64CTZ;
// test_i64_unop(op, 0, 64);
// test_i64_unop(op, -1, 0);
// test_i64_unop(op, 2, 1);
// test_i64_unop(op, 1024, 10);
// }
// #[test]
// fn test_i64popcnt() {
// let op = I64POPCNT;
// test_i64_unop(op, 0, 0);
// test_i64_unop(op, -1, 64);
// test_i64_unop(op, 2, 1);
// test_i64_unop(op, 96, 2);
// }
// #[test]
// fn test_i64add() {
// let op = I64ADD;
// test_i64_binop(op, 0, 0, 0);
// test_i64_binop(op, -1, -1, -2);
// test_i64_binop(op, 1, 1, 2);
// test_i64_binop(op, i64::MAX, 1, i64::MIN);
// }
// #[test]
// fn test_i64sub() {
// let op = I64SUB;
// test_i64_binop(op, 0, 0, 0);
// test_i64_binop(op, -1, 1, -2);
// test_i64_binop(op, 1, 1, 0);
// test_i64_binop(op, i64::MIN, 1, i64::MAX);
// }
// #[test]
// fn test_i64mul() {
// let op = I64MUL;
// test_i64_binop(op, 0, 0, 0);
// test_i64_binop(op, -1, -1, 1);
// test_i64_binop(op, 2, 3, 6);
// test_i64_binop(op, i64::MAX, 2, -2);
// }
// #[test]
// fn test_i64divs() {
// let op = I64DIVS;
// test_i64_binop(op, -1, -1, 1);
// test_i64_binop(op, 6, 3, 2);
// test_i64_binop(op, i64::MIN, -1, i64::MIN);
// }
// #[test]
// #[should_panic(expected = "divide by zero")]
// fn test_i64divs_zero() {
// test_i64_binop(I64DIVS, 1, 0, -1);
// }
// #[test]
// fn test_i64divu() {
// let op = I64DIVU;
// test_u64_binop(op, 1, 1, 1);
// test_u64_binop(op, 6, 3, 2);
// }
// #[test]
// #[should_panic(expected = "divide by zero")]
// fn test_i64divu_zero() {
// test_i64_binop(I64DIVU, 1, 0, -1);
// }
// #[test]
// fn test_i64rems() {
// let op = I64REMS;
// test_i64_binop(op, 5, 2, 1);
// // test_i64_binop(op, 5, -2, 1); // TODO: we don't match Wasmer, we get 0
// test_i64_binop(op, -5, 2, -1);
// // test_i64_binop(op, -5, -2, -1); // TODO: we don't match Wasmer, we get 0
// }
// #[test]
// #[should_panic(expected = "divisor of zero")]
// fn test_i64rems_zero() {
// test_i64_binop(I64REMS, 1, 0, -1);
// }
// #[test]
// fn test_i64remu() {
// let op = I64REMU;
// test_i64_binop(op, 5, 2, 1);
// }
// #[test]
// #[should_panic(expected = "divisor of zero")]
// fn test_i64remu_zero() {
// test_i64_binop(I64REMU, 1, 0, -1);
// }
// #[test]
// fn test_i64and() {
// test_u64_binop(I64AND, 0x0000_ffff, 0x00ff_00ff, 0x0000_00ff);
// }
// #[test]
// fn test_i64or() {
// test_u64_binop(I64OR, 0x0000_ffff, 0x00ff_00ff, 0x00ff_ffff);
// }
// #[test]
// fn test_i64xor() {
// test_u64_binop(I64XOR, 0x0000_ffff, 0x00ff_00ff, 0x00ff_ff00);
// }
// #[test]
// fn test_i64shl() {
// test_u64_binop(I64SHL, 0xffff_ffff, 8, 0xffff_ff00);
// test_u64_binop(I64SHL, 0xffff_ffff, 40, 0xffff_ff00);
// }
// #[test]
// fn test_i64shrs() {
// test_u64_binop(I64SHRS, 0xffff_0000, 8, 0xffff_ff00);
// test_u64_binop(I64SHRS, 0xffff_0000, 40, 0xffff_ff00);
// }
// #[test]
// fn test_i64shru() {
// test_u64_binop(I64SHRU, 0xffff_0000, 8, 0x00ff_ff00);
// test_u64_binop(I64SHRU, 0xffff_0000, 40, 0x00ff_ff00);
// }
// #[test]
// fn test_i64rotl() {
// test_u64_binop(I64ROTL, 0xff00_0000, 4, 0xf000_000f);
// }
// #[test]
// fn test_i64rotr() {
// test_u64_binop(I64ROTR, 0x0000_00ff, 4, 0xf000_000f);
// }