Use f32/f64::from_bits. (#72)

And also enable:

- "conversions",
- "float_exprs",
- "float_literals",
- "float_memory",

tests.
This commit is contained in:
Sergey Pepyakin 2018-03-12 12:37:43 +01:00 committed by GitHub
parent 0c277abacb
commit 9fa933ccd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 13 additions and 54 deletions

View File

@ -14,7 +14,7 @@ byteorder = "1.0"
memory_units = "0.3.0" memory_units = "0.3.0"
[dev-dependencies] [dev-dependencies]
wabt = "0.2.0" wabt = "~0.2.2"
[features] [features]
# 32-bit platforms are not supported and not tested. Use this flag if you really want to use # 32-bit platforms are not supported and not tested. Use this flag if you really want to use

View File

@ -134,12 +134,12 @@ impl RuntimeValue {
/// Creates new value by interpreting passed u32 as f32. /// Creates new value by interpreting passed u32 as f32.
pub fn decode_f32(val: u32) -> Self { pub fn decode_f32(val: u32) -> Self {
RuntimeValue::F32(f32_from_bits(val)) RuntimeValue::F32(f32::from_bits(val))
} }
/// Creates new value by interpreting passed u64 as f64. /// Creates new value by interpreting passed u64 as f64.
pub fn decode_f64(val: u64) -> Self { pub fn decode_f64(val: u64) -> Self {
RuntimeValue::F64(f64_from_bits(val)) RuntimeValue::F64(f64::from_bits(val))
} }
/// Get variable type for this value. /// Get variable type for this value.
@ -367,21 +367,20 @@ impl_transmute_into_as!(u32, i32);
impl_transmute_into_as!(i64, u64); impl_transmute_into_as!(i64, u64);
impl_transmute_into_as!(u64, i64); impl_transmute_into_as!(u64, i64);
// TODO: rewrite these safely when `f32/f32::to_bits/from_bits` stabilized.
impl TransmuteInto<i32> for f32 { impl TransmuteInto<i32> for f32 {
fn transmute_into(self) -> i32 { unsafe { ::std::mem::transmute(self) } } fn transmute_into(self) -> i32 { self.to_bits() as i32 }
} }
impl TransmuteInto<i64> for f64 { impl TransmuteInto<i64> for f64 {
fn transmute_into(self) -> i64 { unsafe { ::std::mem::transmute(self) } } fn transmute_into(self) -> i64 { self.to_bits() as i64 }
} }
impl TransmuteInto<f32> for i32 { impl TransmuteInto<f32> for i32 {
fn transmute_into(self) -> f32 { f32_from_bits(self as _) } fn transmute_into(self) -> f32 { f32::from_bits(self as u32) }
} }
impl TransmuteInto<f64> for i64 { impl TransmuteInto<f64> for i64 {
fn transmute_into(self) -> f64 { f64_from_bits(self as _) } fn transmute_into(self) -> f64 { f64::from_bits(self as u64) }
} }
impl LittleEndianConvert for i8 { impl LittleEndianConvert for i8 {
@ -488,7 +487,7 @@ impl LittleEndianConvert for f32 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_u32::<LittleEndian>() io::Cursor::new(buffer).read_u32::<LittleEndian>()
.map(f32_from_bits) .map(f32::from_bits)
.map_err(|_| Error::InvalidLittleEndianBuffer) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
@ -503,47 +502,11 @@ impl LittleEndianConvert for f64 {
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> { fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
io::Cursor::new(buffer).read_u64::<LittleEndian>() io::Cursor::new(buffer).read_u64::<LittleEndian>()
.map(f64_from_bits) .map(f64::from_bits)
.map_err(|_| Error::InvalidLittleEndianBuffer) .map_err(|_| Error::InvalidLittleEndianBuffer)
} }
} }
// Convert u32 to f32 safely, masking out sNAN
fn f32_from_bits(mut v: u32) -> f32 {
const EXP_MASK: u32 = 0x7F800000;
const QNAN_MASK: u32 = 0x00400000;
const FRACT_MASK: u32 = 0x007FFFFF;
if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 {
// If we have a NaN value, we
// convert signaling NaN values to quiet NaN
// by setting the the highest bit of the fraction
// TODO: remove when https://github.com/BurntSushi/byteorder/issues/71 closed.
// or `f32::from_bits` stabilized.
v |= QNAN_MASK;
}
unsafe { ::std::mem::transmute(v) }
}
// Convert u64 to f64 safely, masking out sNAN
fn f64_from_bits(mut v: u64) -> f64 {
const EXP_MASK: u64 = 0x7FF0000000000000;
const QNAN_MASK: u64 = 0x0001000000000000;
const FRACT_MASK: u64 = 0x000FFFFFFFFFFFFF;
if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 {
// If we have a NaN value, we
// convert signaling NaN values to quiet NaN
// by setting the the highest bit of the fraction
// TODO: remove when https://github.com/BurntSushi/byteorder/issues/71 closed.
// or `f64::from_bits` stabilized.
v |= QNAN_MASK;
}
unsafe { ::std::mem::transmute(v) }
}
macro_rules! impl_integer_arithmetic_ops { macro_rules! impl_integer_arithmetic_ops {
($type: ident) => { ($type: ident) => {
impl ArithmeticOps<$type> for $type { impl ArithmeticOps<$type> for $type {

View File

@ -21,9 +21,7 @@ run_test!("call", wasm_call);
run_test!("call_indirect", wasm_call_indirect); run_test!("call_indirect", wasm_call_indirect);
run_test!("comments", wasm_comments); run_test!("comments", wasm_comments);
run_test!("const", wasm_const); run_test!("const", wasm_const);
// TODO: commented out until sNaN issue is resolved: run_test!("conversions", wasm_conversions);
// https://github.com/NikVolf/parity-wasm/blob/b5aaf103cf28f1e36df832f4883f55043e67894b/src/interpreter/value.rs#L510
// run_test!("conversions", wasm_conversions);
run_test!("custom_section", wasm_custom_section); run_test!("custom_section", wasm_custom_section);
run_test!("elem", wasm_elem); run_test!("elem", wasm_elem);
run_test!("endianness", wasm_endianness); run_test!("endianness", wasm_endianness);
@ -35,11 +33,9 @@ run_test!("f64", wasm_f64);
run_test!("f64_bitwise", wasm_f64_bitwise); run_test!("f64_bitwise", wasm_f64_bitwise);
run_test!("f64_cmp", wasm_f64_cmp); run_test!("f64_cmp", wasm_f64_cmp);
run_test!("fac", wasm_fac); run_test!("fac", wasm_fac);
// TODO: commented out until sNaN issue is resolved: run_test!("float_exprs", wasm_float_exprs);
// https://github.com/NikVolf/parity-wasm/blob/b5aaf103cf28f1e36df832f4883f55043e67894b/src/interpreter/value.rs#L510 run_test!("float_literals", wasm_float_literals);
// run_test!("float_exprs", wasm_float_exprs); run_test!("float_memory", wasm_float_memory);
// run_test!("float_literals", wasm_float_literals);
// run_test!("float_memory", wasm_float_memory);
run_test!("float_misc", wasm_float_misc); run_test!("float_misc", wasm_float_misc);
run_test!("forward", wasm_forward); run_test!("forward", wasm_forward);
run_test!("func", wasm_func); run_test!("func", wasm_func);