Add support for SIMD NaN directives (#686)
* Add support for SIMD NaN directives * Use is_*_nan helper methods for scalar NaN directives
This commit is contained in:
committed by
Alex Crichton
parent
e134505b90
commit
ec8144b87d
@@ -14,7 +14,7 @@ edition = "2018"
|
|||||||
wasmtime-jit = { path = "../jit" }
|
wasmtime-jit = { path = "../jit" }
|
||||||
wasmtime-runtime = { path = "../runtime" }
|
wasmtime-runtime = { path = "../runtime" }
|
||||||
wasmtime-environ = { path = "../environ" }
|
wasmtime-environ = { path = "../environ" }
|
||||||
wast = "3.0.0"
|
wast = "4.0.0"
|
||||||
anyhow = "1.0.19"
|
anyhow = "1.0.19"
|
||||||
target-lexicon = "0.9.0"
|
target-lexicon = "0.9.0"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::spectest::instantiate_spectest;
|
use crate::spectest::instantiate_spectest;
|
||||||
use anyhow::{bail, Context as _, Result};
|
use anyhow::{bail, Context as _, Result};
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str;
|
use std::str;
|
||||||
use wasmtime_jit::{
|
use wasmtime_jit::{
|
||||||
@@ -254,12 +255,12 @@ impl WastContext {
|
|||||||
bail!("{}\nunexpected vector in NaN test", context(span))
|
bail!("{}\nunexpected vector in NaN test", context(span))
|
||||||
}
|
}
|
||||||
RuntimeValue::F32(x) => {
|
RuntimeValue::F32(x) => {
|
||||||
if (x & 0x7fffffff) != 0x7fc00000 {
|
if !is_canonical_f32_nan(x) {
|
||||||
bail!("{}\nexpected canonical NaN", context(span))
|
bail!("{}\nexpected canonical NaN", context(span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RuntimeValue::F64(x) => {
|
RuntimeValue::F64(x) => {
|
||||||
if (x & 0x7fffffffffffffff) != 0x7ff8000000000000 {
|
if !is_canonical_f64_nan(x) {
|
||||||
bail!("{}\nexpected canonical NaN", context(span))
|
bail!("{}\nexpected canonical NaN", context(span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,6 +272,68 @@ impl WastContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AssertReturnCanonicalNanF32x4 { span, invoke } => {
|
||||||
|
match self.perform_invoke(invoke).with_context(|| context(span))? {
|
||||||
|
ActionOutcome::Returned { values } => {
|
||||||
|
for v in values.iter() {
|
||||||
|
match v {
|
||||||
|
RuntimeValue::I32(_) | RuntimeValue::I64(_) => {
|
||||||
|
bail!("{}\nunexpected integer in NaN test", context(span))
|
||||||
|
}
|
||||||
|
RuntimeValue::F32(_) | RuntimeValue::F64(_) => bail!(
|
||||||
|
"{}\nunexpected scalar float in vector NaN test",
|
||||||
|
context(span)
|
||||||
|
),
|
||||||
|
RuntimeValue::V128(x) => {
|
||||||
|
for l in 0..4 {
|
||||||
|
if !is_canonical_f32_nan(&extract_lane_as_u32(x, l)?) {
|
||||||
|
bail!(
|
||||||
|
"{}\nexpected f32x4 canonical NaN in lane {}",
|
||||||
|
context(span),
|
||||||
|
l
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActionOutcome::Trapped { message } => {
|
||||||
|
bail!("{}\nunexpected trap: {}", context(span), message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssertReturnCanonicalNanF64x2 { span, invoke } => {
|
||||||
|
match self.perform_invoke(invoke).with_context(|| context(span))? {
|
||||||
|
ActionOutcome::Returned { values } => {
|
||||||
|
for v in values.iter() {
|
||||||
|
match v {
|
||||||
|
RuntimeValue::I32(_) | RuntimeValue::I64(_) => {
|
||||||
|
bail!("{}\nunexpected integer in NaN test", context(span))
|
||||||
|
}
|
||||||
|
RuntimeValue::F32(_) | RuntimeValue::F64(_) => bail!(
|
||||||
|
"{}\nunexpected scalar float in vector NaN test",
|
||||||
|
context(span)
|
||||||
|
),
|
||||||
|
RuntimeValue::V128(x) => {
|
||||||
|
for l in 0..2 {
|
||||||
|
if !is_canonical_f64_nan(&extract_lane_as_u64(x, l)?) {
|
||||||
|
bail!(
|
||||||
|
"{}\nexpected f64x2 canonical NaN in lane {}",
|
||||||
|
context(span),
|
||||||
|
l
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActionOutcome::Trapped { message } => {
|
||||||
|
bail!("{}\nunexpected trap: {}", context(span), message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
AssertReturnArithmeticNan { span, invoke } => {
|
AssertReturnArithmeticNan { span, invoke } => {
|
||||||
match self.perform_invoke(invoke).with_context(|| context(span))? {
|
match self.perform_invoke(invoke).with_context(|| context(span))? {
|
||||||
ActionOutcome::Returned { values } => {
|
ActionOutcome::Returned { values } => {
|
||||||
@@ -283,12 +346,12 @@ impl WastContext {
|
|||||||
bail!("{}\nunexpected vector in NaN test", context(span))
|
bail!("{}\nunexpected vector in NaN test", context(span))
|
||||||
}
|
}
|
||||||
RuntimeValue::F32(x) => {
|
RuntimeValue::F32(x) => {
|
||||||
if (x & 0x00400000) != 0x00400000 {
|
if !is_arithmetic_f32_nan(x) {
|
||||||
bail!("{}\nexpected arithmetic NaN", context(span))
|
bail!("{}\nexpected arithmetic NaN", context(span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RuntimeValue::F64(x) => {
|
RuntimeValue::F64(x) => {
|
||||||
if (x & 0x0008000000000000) != 0x0008000000000000 {
|
if !is_arithmetic_f64_nan(x) {
|
||||||
bail!("{}\nexpected arithmetic NaN", context(span))
|
bail!("{}\nexpected arithmetic NaN", context(span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,6 +363,68 @@ impl WastContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AssertReturnArithmeticNanF32x4 { span, invoke } => {
|
||||||
|
match self.perform_invoke(invoke).with_context(|| context(span))? {
|
||||||
|
ActionOutcome::Returned { values } => {
|
||||||
|
for v in values.iter() {
|
||||||
|
match v {
|
||||||
|
RuntimeValue::I32(_) | RuntimeValue::I64(_) => {
|
||||||
|
bail!("{}\nunexpected integer in NaN test", context(span))
|
||||||
|
}
|
||||||
|
RuntimeValue::F32(_) | RuntimeValue::F64(_) => bail!(
|
||||||
|
"{}\nunexpected scalar float in vector NaN test",
|
||||||
|
context(span)
|
||||||
|
),
|
||||||
|
RuntimeValue::V128(x) => {
|
||||||
|
for l in 0..4 {
|
||||||
|
if !is_arithmetic_f32_nan(&extract_lane_as_u32(x, l)?) {
|
||||||
|
bail!(
|
||||||
|
"{}\nexpected f32x4 arithmetic NaN in lane {}",
|
||||||
|
context(span),
|
||||||
|
l
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActionOutcome::Trapped { message } => {
|
||||||
|
bail!("{}\nunexpected trap: {}", context(span), message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssertReturnArithmeticNanF64x2 { span, invoke } => {
|
||||||
|
match self.perform_invoke(invoke).with_context(|| context(span))? {
|
||||||
|
ActionOutcome::Returned { values } => {
|
||||||
|
for v in values.iter() {
|
||||||
|
match v {
|
||||||
|
RuntimeValue::I32(_) | RuntimeValue::I64(_) => {
|
||||||
|
bail!("{}\nunexpected integer in NaN test", context(span))
|
||||||
|
}
|
||||||
|
RuntimeValue::F32(_) | RuntimeValue::F64(_) => bail!(
|
||||||
|
"{}\nunexpected scalar float in vector NaN test",
|
||||||
|
context(span)
|
||||||
|
),
|
||||||
|
RuntimeValue::V128(x) => {
|
||||||
|
for l in 0..2 {
|
||||||
|
if !is_arithmetic_f64_nan(&extract_lane_as_u64(x, l)?) {
|
||||||
|
bail!(
|
||||||
|
"{}\nexpected f64x2 arithmetic NaN in lane {}",
|
||||||
|
context(span),
|
||||||
|
l
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActionOutcome::Trapped { message } => {
|
||||||
|
bail!("{}\nunexpected trap: {}", context(span), message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
AssertInvalid {
|
AssertInvalid {
|
||||||
span,
|
span,
|
||||||
mut module,
|
mut module,
|
||||||
@@ -384,3 +509,29 @@ impl WastContext {
|
|||||||
self.run_buffer(path.to_str().unwrap(), &bytes)
|
self.run_buffer(path.to_str().unwrap(), &bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extract_lane_as_u32(bytes: &[u8; 16], lane: usize) -> Result<u32> {
|
||||||
|
let i = lane * 4;
|
||||||
|
Ok(u32::from_le_bytes(bytes[i..i + 4].try_into()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_lane_as_u64(bytes: &[u8; 16], lane: usize) -> Result<u64> {
|
||||||
|
let i = lane * 8;
|
||||||
|
Ok(u64::from_le_bytes(bytes[i..i + 8].try_into()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_canonical_f32_nan(bits: &u32) -> bool {
|
||||||
|
return (bits & 0x7fffffff) == 0x7fc00000;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_canonical_f64_nan(bits: &u64) -> bool {
|
||||||
|
return (bits & 0x7fffffffffffffff) == 0x7ff8000000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_arithmetic_f32_nan(bits: &u32) -> bool {
|
||||||
|
return (bits & 0x00400000) == 0x00400000;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_arithmetic_f64_nan(bits: &u64) -> bool {
|
||||||
|
return (bits & 0x0008000000000000) == 0x0008000000000000;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user