mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-23 03:31:56 +00:00
f32 && f64 tests
This commit is contained in:
@ -8,3 +8,5 @@ macro_rules! run_test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
run_test!("i32", wasm_i32);
|
run_test!("i32", wasm_i32);
|
||||||
|
run_test!("f32", wasm_f32);
|
||||||
|
run_test!("f64", wasm_f64);
|
||||||
|
@ -10,6 +10,7 @@ use serde_json;
|
|||||||
use test;
|
use test;
|
||||||
use parity_wasm;
|
use parity_wasm;
|
||||||
use parity_wasm::interpreter::{
|
use parity_wasm::interpreter::{
|
||||||
|
RuntimeValue,
|
||||||
ProgramInstance, ModuleInstance, ModuleInstanceInterface,
|
ProgramInstance, ModuleInstance, ModuleInstanceInterface,
|
||||||
Error as InterpreterError,
|
Error as InterpreterError,
|
||||||
};
|
};
|
||||||
@ -30,6 +31,18 @@ fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue {
|
|||||||
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
||||||
parity_wasm::RuntimeValue::I32(unsigned as i32)
|
parity_wasm::RuntimeValue::I32(unsigned as i32)
|
||||||
},
|
},
|
||||||
|
"i64" => {
|
||||||
|
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
||||||
|
parity_wasm::RuntimeValue::I64(unsigned as i64)
|
||||||
|
},
|
||||||
|
"f32" => {
|
||||||
|
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
||||||
|
parity_wasm::RuntimeValue::decode_f32(unsigned)
|
||||||
|
},
|
||||||
|
"f64" => {
|
||||||
|
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
||||||
|
parity_wasm::RuntimeValue::decode_f64(unsigned)
|
||||||
|
},
|
||||||
_ => panic!("Unknwon runtime value type"),
|
_ => panic!("Unknwon runtime value type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,6 +116,24 @@ pub fn spec(name: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
&test::Command::AssertReturnCanonicalNan { line, ref action } | &test::Command::AssertReturnArithmeticNan { line, ref action } => {
|
||||||
|
let result = run_action(&*module, action);
|
||||||
|
match result {
|
||||||
|
Ok(result) => {
|
||||||
|
for actual_result in result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>() {
|
||||||
|
match actual_result {
|
||||||
|
RuntimeValue::F32(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) },
|
||||||
|
RuntimeValue::F64(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) },
|
||||||
|
val @ _ => panic!("Expected action to return float value, got {:?}", val),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("assert_return_nan at line {} - success", line);
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
panic!("Expected action to return value, got error: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
&test::Command::AssertTrap { line, ref action, .. } => {
|
&test::Command::AssertTrap { line, ref action, .. } => {
|
||||||
let result = run_action(&*module, action);
|
let result = run_action(&*module, action);
|
||||||
match result {
|
match result {
|
||||||
|
@ -25,6 +25,16 @@ pub enum Command {
|
|||||||
action: Action,
|
action: Action,
|
||||||
expected: Vec<RuntimeValue>,
|
expected: Vec<RuntimeValue>,
|
||||||
},
|
},
|
||||||
|
#[serde(rename = "assert_return_canonical_nan")]
|
||||||
|
AssertReturnCanonicalNan {
|
||||||
|
line: u64,
|
||||||
|
action: Action,
|
||||||
|
},
|
||||||
|
#[serde(rename = "assert_return_arithmetic_nan")]
|
||||||
|
AssertReturnArithmeticNan {
|
||||||
|
line: u64,
|
||||||
|
action: Action,
|
||||||
|
},
|
||||||
#[serde(rename = "assert_trap")]
|
#[serde(rename = "assert_trap")]
|
||||||
AssertTrap {
|
AssertTrap {
|
||||||
line: u64,
|
line: u64,
|
||||||
|
@ -758,7 +758,7 @@ impl Interpreter {
|
|||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_as::<T>()
|
.pop_as::<T>()
|
||||||
.map(|v| v.round())
|
.map(|v| v.nearest())
|
||||||
.map(|v| context.value_stack_mut().push(v.into()))
|
.map(|v| context.value_stack_mut().push(v.into()))
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,8 @@ pub trait Float<T>: ArithmeticOps<T> {
|
|||||||
fn trunc(self) -> T;
|
fn trunc(self) -> T;
|
||||||
/// Returns the nearest integer to a number. Round half-way cases away from 0.0.
|
/// Returns the nearest integer to a number. Round half-way cases away from 0.0.
|
||||||
fn round(self) -> T;
|
fn round(self) -> T;
|
||||||
|
/// Returns the nearest integer to a number. Ties are round to even number.
|
||||||
|
fn nearest(self) -> T;
|
||||||
/// Takes the square root of a number.
|
/// Takes the square root of a number.
|
||||||
fn sqrt(self) -> T;
|
fn sqrt(self) -> T;
|
||||||
/// Returns the minimum of the two numbers.
|
/// Returns the minimum of the two numbers.
|
||||||
@ -604,17 +606,40 @@ macro_rules! impl_float {
|
|||||||
fn ceil(self) -> $type { self.ceil() }
|
fn ceil(self) -> $type { self.ceil() }
|
||||||
fn trunc(self) -> $type { self.trunc() }
|
fn trunc(self) -> $type { self.trunc() }
|
||||||
fn round(self) -> $type { self.round() }
|
fn round(self) -> $type { self.round() }
|
||||||
|
fn nearest(self) -> $type {
|
||||||
|
let round = self.round();
|
||||||
|
if self.fract().abs() != 0.5 {
|
||||||
|
return round;
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::ops::Rem;
|
||||||
|
if round.rem(2.0) == 1.0 {
|
||||||
|
self.floor()
|
||||||
|
} else if round.rem(2.0) == -1.0 {
|
||||||
|
self.ceil()
|
||||||
|
} else {
|
||||||
|
round
|
||||||
|
}
|
||||||
|
}
|
||||||
fn sqrt(self) -> $type { self.sqrt() }
|
fn sqrt(self) -> $type { self.sqrt() }
|
||||||
// TODO
|
|
||||||
// This instruction corresponds to what is sometimes called "minNaN" in other languages.
|
// This instruction corresponds to what is sometimes called "minNaN" in other languages.
|
||||||
// This differs from the IEEE 754-2008 minNum operation in that it returns a NaN if either operand is a NaN, and in that the behavior when the operands are zeros of differing signs is fully specified.
|
fn min(self, other: $type) -> $type {
|
||||||
// This differs from the common x<y?x:y expansion in its handling of negative zero and NaN values.
|
if self.is_nan() || other.is_nan() {
|
||||||
fn min(self, other: $type) -> $type { self.min(other) }
|
use std::$type;
|
||||||
// TODO
|
return $type::NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.min(other)
|
||||||
|
}
|
||||||
// This instruction corresponds to what is sometimes called "maxNaN" in other languages.
|
// This instruction corresponds to what is sometimes called "maxNaN" in other languages.
|
||||||
// This differs from the IEEE 754-2008 maxNum operation in that it returns a NaN if either operand is a NaN, and in that the behavior when the operands are zeros of differing signs is fully specified.
|
fn max(self, other: $type) -> $type {
|
||||||
// This differs from the common x>y?x:y expansion in its handling of negative zero and NaN values.
|
if self.is_nan() || other.is_nan() {
|
||||||
fn max(self, other: $type) -> $type { self.max(other) }
|
use std::$type;
|
||||||
|
return $type::NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.max(other)
|
||||||
|
}
|
||||||
fn copysign(self, other: $type) -> $type {
|
fn copysign(self, other: $type) -> $type {
|
||||||
// TODO: this may be buggy for edge cases
|
// TODO: this may be buggy for edge cases
|
||||||
if self.is_sign_positive() == other.is_sign_positive() {
|
if self.is_sign_positive() == other.is_sign_positive() {
|
||||||
|
Reference in New Issue
Block a user