Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/spectest-nan' into ci_spectests
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Aug 17, 2020
2 parents 4e17f95 + 0486a3c commit 06d5d04
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 54 deletions.
10 changes: 5 additions & 5 deletions test/smoketests/spectests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ add_test(
set_tests_properties(
fizzy/smoketests/spectests/default
PROPERTIES
PASS_REGULAR_EXPRESSION "PASSED 29, FAILED 0, SKIPPED 3"
PASS_REGULAR_EXPRESSION "PASSED 32, FAILED 0, SKIPPED 3"
)

add_test(
Expand All @@ -19,7 +19,7 @@ add_test(
set_tests_properties(
fizzy/smoketests/spectests/skipvalidation
PROPERTIES
PASS_REGULAR_EXPRESSION "PASSED 28, FAILED 0, SKIPPED 4"
PASS_REGULAR_EXPRESSION "PASSED 31, FAILED 0, SKIPPED 4"
)

add_test(
Expand All @@ -29,7 +29,7 @@ add_test(
set_tests_properties(
fizzy/smoketests/spectests/showpassed
PROPERTIES
PASS_REGULAR_EXPRESSION "PASSED 29, FAILED 0, SKIPPED 3"
PASS_REGULAR_EXPRESSION "PASSED 32, FAILED 0, SKIPPED 3"
)

add_test(
Expand All @@ -39,7 +39,7 @@ add_test(
set_tests_properties(
fizzy/smoketests/spectests/showskipped
PROPERTIES
PASS_REGULAR_EXPRESSION "PASSED 29, FAILED 0, SKIPPED 3"
PASS_REGULAR_EXPRESSION "PASSED 32, FAILED 0, SKIPPED 3"
)

add_test(
Expand All @@ -49,7 +49,7 @@ add_test(
set_tests_properties(
fizzy/smoketests/spectests/hidefailed
PROPERTIES
PASS_REGULAR_EXPRESSION "PASSED 29, FAILED 0, SKIPPED 3"
PASS_REGULAR_EXPRESSION "PASSED 32, FAILED 0, SKIPPED 3"
)

add_test(
Expand Down
Binary file modified test/smoketests/spectests/default/smoketest.12.wasm
Binary file not shown.
21 changes: 12 additions & 9 deletions test/smoketests/spectests/default/smoketest.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@
{"type": "assert_unlinkable", "line": 76, "filename": "smoketest.10.wasm", "text": "data segment does not fit", "module_type": "binary"},
{"type": "assert_uninstantiable", "line": 81, "filename": "smoketest.11.wasm", "text": "unreachable", "module_type": "binary"},
{"type": "module", "line": 86, "filename": "smoketest.12.wasm"},
{"type": "assert_return", "line": 95, "action": {"type": "invoke", "field": "foo.f32", "args": []}, "expected": [{"type": "f32", "value": "1067282596"}]},
{"type": "assert_return", "line": 96, "action": {"type": "invoke", "field": "foo.f64", "args": []}, "expected": [{"type": "f64", "value": "4616820122002590269"}]},
{"type": "action", "line": 97, "action": {"type": "invoke", "field": "param.f64", "args": [{"type": "f64", "value": "4607182418800017408"}]}, "expected": []},
{"type": "assert_return", "line": 98, "action": {"type": "invoke", "field": "f32.NaN", "args": []}, "expected": [{"type": "f32", "value": "2143289344"}]},
{"type": "assert_return", "line": 99, "action": {"type": "invoke", "field": "f64.NaN", "args": []}, "expected": [{"type": "f64", "value": "9221120237041090560"}]},
{"type": "assert_return", "line": 100, "action": {"type": "get", "field": "glob.f32"}, "expected": [{"type": "f32", "value": "1085276160"}]},
{"type": "register", "line": 104, "name": "$Mod-unknown", "as": "Mod-unknown"},
{"type": "assert_malformed", "line": 107, "filename": "smoketest.13.wat", "text": "error", "module_type": "text"},
{"type": "assert_unlinkable", "line": 108, "filename": "smoketest.14.wat", "text": "error", "module_type": "text"}]}
{"type": "assert_return", "line": 96, "action": {"type": "invoke", "field": "foo.f32", "args": []}, "expected": [{"type": "f32", "value": "1067282596"}]},
{"type": "assert_return", "line": 97, "action": {"type": "invoke", "field": "foo.f64", "args": []}, "expected": [{"type": "f64", "value": "4616820122002590269"}]},
{"type": "action", "line": 98, "action": {"type": "invoke", "field": "param.f32", "args": [{"type": "f32", "value": "1065353216"}]}, "expected": []},
{"type": "action", "line": 99, "action": {"type": "invoke", "field": "param.f64", "args": [{"type": "f64", "value": "4607182418800017408"}]}, "expected": []},
{"type": "assert_return", "line": 100, "action": {"type": "invoke", "field": "f32.NaN", "args": []}, "expected": [{"type": "f32", "value": "2143289344"}]},
{"type": "assert_return", "line": 101, "action": {"type": "invoke", "field": "f64.NaN", "args": []}, "expected": [{"type": "f64", "value": "9221120237041090560"}]},
{"type": "assert_return", "line": 102, "action": {"type": "invoke", "field": "f32.NaN", "args": []}, "expected": [{"type": "f32", "value": "nan:canonical"}]},
{"type": "assert_return", "line": 103, "action": {"type": "invoke", "field": "f32.NaN", "args": []}, "expected": [{"type": "f32", "value": "nan:arithmetic"}]},
{"type": "assert_return", "line": 104, "action": {"type": "get", "field": "glob.f32"}, "expected": [{"type": "f32", "value": "1085276160"}]},
{"type": "register", "line": 108, "name": "$Mod-unknown", "as": "Mod-unknown"},
{"type": "assert_malformed", "line": 111, "filename": "smoketest.13.wat", "text": "error", "module_type": "text"},
{"type": "assert_unlinkable", "line": 112, "filename": "smoketest.14.wat", "text": "error", "module_type": "text"}]}
4 changes: 4 additions & 0 deletions test/smoketests/spectests/default/smoketest.wast
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
(module
(func (export "foo.f32") (result f32) (f32.const 1.23))
(func (export "foo.f64") (result f64) (f64.const 4.56))
(func (export "param.f32") (param f32) (drop (local.get 0)))
(func (export "param.f64") (param f64) (drop (local.get 0)))
(func (export "f32.NaN") (result f32) (f32.const nan))
(func (export "f64.NaN") (result f64) (f64.const nan))
Expand All @@ -94,9 +95,12 @@

(assert_return (invoke "foo.f32") (f32.const 1.23))
(assert_return (invoke "foo.f64") (f64.const 4.56))
(invoke "param.f32" (f32.const 1))
(invoke "param.f64" (f64.const 1))
(assert_return (invoke "f32.NaN") (f32.const nan))
(assert_return (invoke "f64.NaN") (f64.const nan))
(assert_return (invoke "f32.NaN") (f32.const nan:canonical))
(assert_return (invoke "f32.NaN") (f32.const nan:arithmetic))
(assert_return (get "glob.f32") (f32.const 5.5))

;; cases that will be skipped
Expand Down
132 changes: 94 additions & 38 deletions test/spectests/spectests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,6 @@ fizzy::bytes load_wasm_file(const fs::path& json_file_path, std::string_view fil
std::istreambuf_iterator<char>{wasm_file}, std::istreambuf_iterator<char>{});
}

std::ostream& operator<<(std::ostream& out, std::pair<fizzy::Value, std::string> value_and_type)
{
const auto& [value, type] = value_and_type;

if (type == "i32" || type == "i64")
out << value.i64 << " (0x" << std::hex << value.i64 << ")";
else if (type == "f32")
out << value.f32 << " (0x" << std::hex << fizzy::test::FP{value.f32}.as_uint() << ")";
else if (type == "f64")
out << value.f64 << " (0x" << std::hex << fizzy::test::FP{value.f64}.as_uint() << ")";
else
assert(false);

out << std::dec;
return out;
}

struct test_settings
{
bool skip_validation = false;
Expand Down Expand Up @@ -420,26 +403,57 @@ class test_runner
return it_instance->second.get();
}

std::optional<fizzy::Value> read_value(const json& v)

static fizzy::Value read_integer_value(const json& v)
{
const auto type = v.at("type").get<std::string>();
assert(
v.at("type").get<std::string>() == "i32" || v.at("type").get<std::string>() == "i64");

// JSON tests have all values including floats serialized as 64-bit unsigned integers
return std::stoull(v.at("value").get<std::string>());
}

template <typename T>
static fizzy::Value read_floating_point_value(const json& v)
{
assert(
v.at("type").get<std::string>() == "f32" || v.at("type").get<std::string>() == "f64");
assert(!is_canonical_nan(v) && !is_arithmetic_nan(v));

// JSON tests have all values including floats serialized as 64-bit unsigned integers.
const uint64_t uint_value = std::stoull(v.at("value").get<std::string>());
/// The unsigned integer type matching the size of this floating-point type.
using UintType = std::conditional_t<std::is_same_v<T, float>, uint32_t, uint64_t>;
return fizzy::test::FP<T>{static_cast<UintType>(uint_value)}.value;
}

std::optional<fizzy::Value> read_value(const json& v)
{
const auto type = v.at("type").get<std::string>();

if (type == "i32" || type == "i64")
return uint_value;
return read_integer_value(v);
else if (type == "f32")
return fizzy::test::FP32{static_cast<uint32_t>(uint_value)}.value;
return read_floating_point_value<float>(v);
else if (type == "f64")
return fizzy::test::FP64{uint_value}.value;
return read_floating_point_value<double>(v);
else
{
skip("Unsupported value type '" + type + "'.");
return std::nullopt;
}
}

static bool is_canonical_nan(const json& v)
{
return v.at("value").get<std::string>() == "nan:canonical";
}

static bool is_arithmetic_nan(const json& v)
{
return v.at("value").get<std::string>() == "nan:arithmetic";
}

std::optional<fizzy::ExecutionResult> invoke(const json& action)
{
auto instance = find_instance_for_action(action);
Expand Down Expand Up @@ -475,36 +489,78 @@ class test_runner
}
}

bool check_result(fizzy::Value actual_value, const json& expected)
bool check_integer_result(fizzy::Value actual_value, const json& expected)
{
const auto value_type = expected.at("type").get<std::string>();
const auto expected_value = read_integer_value(expected);

const auto expected_value = read_value(expected);
if (!expected_value.has_value())
if (expected_value.i64 != actual_value.i64)
{
std::stringstream message;
message << "Incorrect returned value. Expected: " << expected_value.i64 << " (0x"
<< std::hex << expected_value.i64 << ")"
<< " Actual: " << actual_value.i64 << " (0x" << std::hex << actual_value.i64
<< ")";
fail(message.str());
return false;
}
return true;
}

bool is_equal = false;
if (value_type == "i32" || value_type == "i64")
is_equal = expected_value->i64 == actual_value.i64;
else if (value_type == "f32")
is_equal = fizzy::test::FP{expected_value->f32} == actual_value.f32;
else if (value_type == "f64")
is_equal = fizzy::test::FP{expected_value->f64} == actual_value.f64;
else
assert(false); // assuming type is already checked in read_value
template <typename T>
bool check_floating_point_result(fizzy::Value actual_value, const json& expected)
{
const auto fp_actual = fizzy::test::FP{actual_value.as<T>()};

if (!is_equal)
const bool is_canonical_nan_expected = is_canonical_nan(expected);
if (is_canonical_nan_expected && fp_actual.is_canonical_nan())
return true;
const bool is_arithmetic_nan_expected = is_arithmetic_nan(expected);
if (is_arithmetic_nan_expected && fp_actual.is_arithmetic_nan())
return true;

if (is_canonical_nan_expected || is_arithmetic_nan_expected)
{
std::stringstream message;
message << "Incorrect returned value. Expected: "
<< std::make_pair(*expected_value, value_type)
<< " Actual: " << std::make_pair(actual_value, value_type);
<< expected.at("value").get<std::string>()
<< " Actual: " << actual_value.as<T>() << " (0x" << std::hexfloat
<< actual_value.as<T>() << ")";
fail(message.str());
return false;
}

const auto expected_value = read_floating_point_value<T>(expected);

if (expected_value.template as<T>() != fp_actual)
{
std::stringstream message;
message << "Incorrect returned value. Expected: " << expected_value.template as<T>()
<< " (0x" << std::hexfloat << expected_value.template as<T>() << ")"
<< " Actual: " << actual_value.as<T>() << " (0x" << std::hexfloat
<< actual_value.as<T>() << ")";
fail(message.str());
return false;
}
return true;
}

bool check_result(fizzy::Value actual_value, const json& expected)
{
const auto type = expected.at("type").get<std::string>();

if (type == "i32" || type == "i64")
return check_integer_result(actual_value, expected);
else if (type == "f32")
return check_floating_point_result<float>(actual_value, expected);
else if (type == "f64")
return check_floating_point_result<double>(actual_value, expected);
else
{
skip("Unsupported value type '" + type + "'.");
return false;
}
}

std::pair<imports, std::string> create_imports(const fizzy::Module& module)
{
imports result;
Expand Down
4 changes: 2 additions & 2 deletions test/unittests/execute_floating_point_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ MATCHER_P(CanonicalNaN, value, "result with a canonical NaN")
return false;

const auto result_value = arg.value.template as<value_type>();
return FP<value_type>{result_value}.nan_payload() == FP<value_type>::canon;
return FP<value_type>{result_value}.is_canonical_nan();
}

MATCHER_P(ArithmeticNaN, value, "result with an arithmetic NaN")
Expand All @@ -33,7 +33,7 @@ MATCHER_P(ArithmeticNaN, value, "result with an arithmetic NaN")
return false;

const auto result_value = arg.value.template as<value_type>();
return FP<value_type>{result_value}.nan_payload() >= FP<value_type>::canon;
return FP<value_type>{result_value}.is_arithmetic_nan();
}

TEST(execute_floating_point, f32_const)
Expand Down
Loading

0 comments on commit 06d5d04

Please sign in to comment.