Skip to content

Commit

Permalink
feat + test: i32.div_u operation
Browse files Browse the repository at this point in the history
  • Loading branch information
nerodesu017 committed Jul 1, 2024
1 parent 095353d commit 999d969
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/execution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,25 @@ impl<'b> RuntimeInstance<'b> {
trace!("Instruction: i32.div_s [{divisor} {dividend}] -> [{res}]");
stack.push_value(res.into());
}
// i32.div_u: [i32 i32] -> [i32]
0x6E => {
let dividend: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
let divisor: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();

let dividend = dividend as u32;
let divisor = divisor as u32;

if dividend == 0 {
return Err(crate::Error::RuntimeError(
crate::core::error::RuntimeError::DivideBy0,
));
}

let res = (divisor / dividend) as i32;

trace!("Instruction: i32.div_u [{divisor} {dividend}] -> [{res}]");
stack.push_value(res.into());
}
other => {
trace!("Unknown instruction {other:#x}, skipping..");
}
Expand Down
7 changes: 7 additions & 0 deletions src/validation/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ fn read_instructions(

value_stack.push_back(ValType::NumType(NumType::I32));
}
// i32.div_u: [i32 i32] -> [i32]
0x6E => {
assert_pop_value_stack(value_stack, ValType::NumType(NumType::I32))?;
assert_pop_value_stack(value_stack, ValType::NumType(NumType::I32))?;

value_stack.push_back(ValType::NumType(NumType::I32));
}
// i32.const: [] -> [i32]
0x41 => {
let _num = wasm.read_var_i32()?;
Expand Down
62 changes: 62 additions & 0 deletions tests/arithmetic/division.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,65 @@ pub fn division_signed_panic_result_unrepresentable() {
wasm::Error::RuntimeError(wasm::RuntimeError::UnrepresentableResult)
);
}


/// A simple function to test unsigned division
#[test_log::test]
pub fn division_unsigned_simple() {
use wasm::{validate, RuntimeInstance};

let wat = r#"
(module
(func (export "unsigned_division") (param $divisor i32) (param $dividend i32) (result i32)
local.get $divisor
local.get $dividend
i32.div_u)
)
"#;

let wasm_bytes = wat::parse_str(wat).unwrap();

let validation_info = validate(&wasm_bytes).expect("validation failed");

let mut instance = RuntimeInstance::new(&validation_info).expect("instantiation failed");

assert_eq!(10, instance.invoke_func(0, (20, 2)).unwrap());
assert_eq!(9_001, instance.invoke_func(0, (81_018_001, 9_001)).unwrap());
assert_eq!(0, instance.invoke_func(0, (i32::MIN, -1)).unwrap());


assert_eq!(0, instance.invoke_func(0, (i32::MIN, -1)).unwrap());
assert_eq!(-20, instance.invoke_func(0, (-20, 1)).unwrap());
assert_eq!(2147483638, instance.invoke_func(0, (-20, 2)).unwrap());
assert_eq!(1431655758, instance.invoke_func(0, (-20, 3)).unwrap());
assert_eq!(1073741819, instance.invoke_func(0, (-20, 4)).unwrap());

}

/// A simple function to test unsigned division's RuntimeError when dividing by 0
#[test_log::test]
pub fn division_unsigned_panic_dividend_0() {
use wasm::{validate, RuntimeInstance};

let wat = r#"
(module
(func (export "unsigned_division") (param $divisor i32) (param $dividend i32) (result i32)
local.get $divisor
local.get $dividend
i32.div_u)
)
"#;

let wasm_bytes = wat::parse_str(wat).unwrap();

let validation_info = validate(&wasm_bytes).expect("validation failed");

let mut instance = RuntimeInstance::new(&validation_info).expect("instantiation failed");

let result = instance.invoke_func::<(i32, i32), i32>(0, (222, 0));

assert_eq!(
result.unwrap_err(),
wasm::Error::RuntimeError(wasm::RuntimeError::DivideBy0)
);
}

0 comments on commit 999d969

Please sign in to comment.