Skip to content

Commit

Permalink
Merge pull request #424 from wasmx/value_f32
Browse files Browse the repository at this point in the history
Implement floating point const and add
  • Loading branch information
chfast authored Jul 31, 2020
2 parents 40c459e + a788c5f commit ad0592c
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 22 deletions.
17 changes: 9 additions & 8 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ jobs:
./wat2wasm4cpp.py test/unittests/end_to_end_test.cpp
./wat2wasm4cpp.py test/unittests/execute_call_test.cpp
./wat2wasm4cpp.py test/unittests/execute_control_test.cpp
./wat2wasm4cpp.py test/unittests/execute_floating_point_test.cpp
./wat2wasm4cpp.py test/unittests/execute_numeric_test.cpp
./wat2wasm4cpp.py test/unittests/execute_test.cpp
./wat2wasm4cpp.py test/unittests/instantiate_test.cpp
Expand Down Expand Up @@ -270,9 +271,9 @@ jobs:
- benchmark:
min_time: "0.01"
- spectest:
expected_passed: 5423
expected_passed: 5468
expected_failed: 9
expected_skipped: 6381
expected_skipped: 6336

sanitizers-macos:
executor: macos
Expand All @@ -288,9 +289,9 @@ jobs:
- benchmark:
min_time: "0.01"
- spectest:
expected_passed: 5423
expected_passed: 5468
expected_failed: 9
expected_skipped: 6381
expected_skipped: 6336

benchmark:
machine:
Expand Down Expand Up @@ -396,13 +397,13 @@ jobs:
at: ~/build
- spectest:
skip_validation: true
expected_passed: 4481
expected_passed: 4526
expected_failed: 9
expected_skipped: 7323
expected_skipped: 7278
- spectest:
expected_passed: 5423
expected_passed: 5468
expected_failed: 9
expected_skipped: 6381
expected_skipped: 6336
- collect_coverage_data

workflows:
Expand Down
17 changes: 13 additions & 4 deletions lib/fizzy/execute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1002,12 +1002,14 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, span<const Value>
break;
}
case Instr::i32_const:
case Instr::f32_const:
{
const auto value = read<uint32_t>(immediates);
stack.push(value);
break;
}
case Instr::i64_const:
case Instr::f64_const:
{
const auto value = read<uint64_t>(immediates);
stack.push(value);
Expand Down Expand Up @@ -1384,12 +1386,21 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, span<const Value>
// effectively no-op
break;
}
case Instr::f32_add:
{
binary_op(stack, std::plus<float>{});
break;
}
case Instr::f64_add:
{
binary_op(stack, std::plus<double>{});
break;
}

case Instr::f32_load:
case Instr::f64_load:
case Instr::f32_store:
case Instr::f64_store:
case Instr::f32_const:
case Instr::f64_const:
case Instr::f32_eq:
case Instr::f32_ne:
case Instr::f32_lt:
Expand All @@ -1409,7 +1420,6 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, span<const Value>
case Instr::f32_trunc:
case Instr::f32_nearest:
case Instr::f32_sqrt:
case Instr::f32_add:
case Instr::f32_sub:
case Instr::f32_mul:
case Instr::f32_div:
Expand All @@ -1423,7 +1433,6 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, span<const Value>
case Instr::f64_trunc:
case Instr::f64_nearest:
case Instr::f64_sqrt:
case Instr::f64_add:
case Instr::f64_sub:
case Instr::f64_mul:
case Instr::f64_div:
Expand Down
33 changes: 26 additions & 7 deletions lib/fizzy/parser_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ inline void push(bytes& b, T value)
b.append(storage, sizeof(storage));
}

template <typename T>
inline parser_result<T> read_const(const uint8_t* pos, const uint8_t* end)
{
constexpr auto size = sizeof(T);
if (pos + size > end)
throw parser_error{"unexpected EOF"};

T value;
__builtin_memcpy(&value, pos, size);
return {value, pos + size};
}

/// The control frame to keep information about labels and blocks as defined in
/// Wasm Validation Algorithm https://webassembly.github.io/spec/core/appendix/algorithm.html.
struct ControlFrame
Expand Down Expand Up @@ -305,12 +317,6 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
throw parser_error{"invalid instruction " + std::to_string(*(pos - 1))};

// Floating point instructions are unsupported
case Instr::f32_const:
pos = skip(4, pos, end);
break;
case Instr::f64_const:
pos = skip(8, pos, end);
break;
case Instr::f32_eq:
case Instr::f32_ne:
case Instr::f32_lt:
Expand Down Expand Up @@ -799,14 +805,27 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
push(code.immediates, static_cast<uint32_t>(value));
break;
}

case Instr::i64_const:
{
int64_t value;
std::tie(value, pos) = leb128s_decode<int64_t>(pos, end);
push(code.immediates, static_cast<uint64_t>(value));
break;
}
case Instr::f32_const:
{
uint32_t value;
std::tie(value, pos) = read_const<uint32_t>(pos, end);
push(code.immediates, value);
break;
}
case Instr::f64_const:
{
uint64_t value;
std::tie(value, pos) = read_const<uint64_t>(pos, end);
push(code.immediates, value);
break;
}

case Instr::i32_load:
case Instr::i64_load:
Expand Down
17 changes: 17 additions & 0 deletions lib/fizzy/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace fizzy
union Value
{
uint64_t i64;
float f32;
double f64;

Value() = default;

Expand All @@ -25,6 +27,9 @@ union Value
constexpr Value(int64_t v) noexcept : i64{static_cast<uint64_t>(v)} {}
constexpr Value(int32_t v) noexcept : i64{static_cast<uint32_t>(v)} {}

constexpr Value(float v) noexcept : f32{v} {}
constexpr Value(double v) noexcept : f64{v} {}

/// Converting constructor from any other type (including smaller integer types) is deleted.
template <typename T>
constexpr Value(T) = delete;
Expand Down Expand Up @@ -60,4 +65,16 @@ constexpr int32_t Value::as<int32_t>() const noexcept
{
return static_cast<int32_t>(i64);
}

template <>
constexpr float Value::as() const noexcept
{
return f32;
}

template <>
constexpr double Value::as() const noexcept
{
return f64;
}
} // namespace fizzy
1 change: 1 addition & 0 deletions test/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ target_sources(
end_to_end_test.cpp
execute_call_test.cpp
execute_control_test.cpp
execute_floating_point_test.cpp
execute_numeric_test.cpp
execute_test.cpp
instantiate_test.cpp
Expand Down
72 changes: 72 additions & 0 deletions test/unittests/execute_floating_point_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Fizzy: A fast WebAssembly interpreter
// Copyright 2020 The Fizzy Authors.
// SPDX-License-Identifier: Apache-2.0

#include "execute.hpp"
#include "parser.hpp"
#include <gtest/gtest.h>
#include <test/utils/hex.hpp>

using namespace fizzy;
using namespace fizzy::test;

TEST(execute_floating_point, f32_const)
{
/* wat2wasm
(func (result f32)
f32.const 4194304.1
)
*/
const auto wasm = from_hex("0061736d010000000105016000017d030201000a09010700430000804a0b");

auto instance = instantiate(parse(wasm));
const auto result = execute(*instance, 0, {});
EXPECT_EQ(result.value.f32, 4194304.1f);
}

TEST(execute_floating_point, f64_const)
{
/* wat2wasm
(func (result f64)
f64.const 8589934592.1
)
*/
const auto wasm =
from_hex("0061736d010000000105016000017c030201000a0d010b0044cdcc0000000000420b");

auto instance = instantiate(parse(wasm));
const auto result = execute(*instance, 0, {});
EXPECT_EQ(result.value.f64, 8589934592.1);
}

TEST(execute_floating_point, f32_add)
{
/* wat2wasm
(func (param f32 f32) (result f32)
local.get 0
local.get 1
f32.add
)
*/
const auto wasm = from_hex("0061736d0100000001070160027d7d017d030201000a0901070020002001920b");

auto instance = instantiate(parse(wasm));
const auto result = execute(*instance, 0, {1.001f, 6.006f});
EXPECT_EQ(result.value.f32, 7.007f);
}

TEST(execute_floating_point, f64_add)
{
/* wat2wasm
(func (param f64 f64) (result f64)
local.get 0
local.get 1
f64.add
)
*/
const auto wasm = from_hex("0061736d0100000001070160027c7c017c030201000a0901070020002001a00b");

auto instance = instantiate(parse(wasm));
const auto result = execute(*instance, 0, {1.0011, 6.0066});
EXPECT_EQ(result.value.f64, 7.0077);
}
6 changes: 3 additions & 3 deletions test/unittests/parser_expr_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ TEST(parser_expr, instr_loop)
const auto [code3, pos3] = parse_expr(loop_f32);
EXPECT_EQ(code3.instructions,
(std::vector{Instr::loop, Instr::f32_const, Instr::end, Instr::drop, Instr::end}));
EXPECT_EQ(code3.immediates.size(), 0);
EXPECT_EQ(code3.immediates.size(), 4);
EXPECT_EQ(code3.max_stack_height, 1);

const auto loop_f64 = "037c4400000000000000000b1a0b"_bytes;
const auto [code4, pos4] = parse_expr(loop_f64);
EXPECT_EQ(code4.instructions,
(std::vector{Instr::loop, Instr::f64_const, Instr::end, Instr::drop, Instr::end}));
EXPECT_EQ(code4.immediates.size(), 0);
EXPECT_EQ(code4.immediates.size(), 8);
EXPECT_EQ(code4.max_stack_height, 1);
}

Expand Down Expand Up @@ -81,7 +81,7 @@ TEST(parser_expr, instr_block)
const auto [code3, pos3] = parse_expr(block_f64);
EXPECT_EQ(code3.instructions,
(std::vector{Instr::block, Instr::f64_const, Instr::end, Instr::drop, Instr::end}));
EXPECT_TRUE(code3.immediates.empty());
EXPECT_EQ(code2.immediates, "0000000000000000"_bytes);
}

TEST(parser_expr, instr_block_input_buffer_overflow)
Expand Down
46 changes: 46 additions & 0 deletions test/unittests/value_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ TEST(value, constructor_from_signed_ints)
EXPECT_EQ(Value{int64_t{-3}}.i64, 0xfffffffffffffffd);
}

TEST(value, constructor_from_floating_points)
{
EXPECT_EQ(Value{123.456f}.f32, 123.456f);
EXPECT_EQ(Value{123.456789001}.f64, 123.456789001);
}

TEST(value, as_integer)
{
const Value v{0xfffffffffffffffe};
Expand All @@ -50,6 +56,46 @@ TEST(value, as_integer)
EXPECT_EQ(v.as<int32_t>(), -2);
}

TEST(value, as_floating_point)
{
EXPECT_EQ(Value{123.456f}.as<float>(), 123.456f);
EXPECT_EQ(Value{123.456789001}.as<double>(), 123.456789001);

float f;
f = std::numeric_limits<float>::infinity();
EXPECT_EQ(Value{f}.f32, f);
EXPECT_EQ(Value{f}.as<float>(), f);
f = std::numeric_limits<float>::min();
EXPECT_EQ(Value{f}.f32, f);
EXPECT_EQ(Value{f}.as<float>(), f);
f = std::numeric_limits<float>::max();
EXPECT_EQ(Value{f}.f32, f);
EXPECT_EQ(Value{f}.as<float>(), f);
f = std::numeric_limits<float>::denorm_min();
EXPECT_EQ(Value{f}.f32, f);
EXPECT_EQ(Value{f}.as<float>(), f);
f = std::numeric_limits<float>::lowest();
EXPECT_EQ(Value{f}.f32, f);
EXPECT_EQ(Value{f}.as<float>(), f);

double d;
d = std::numeric_limits<double>::infinity();
EXPECT_EQ(Value{d}.f64, d);
EXPECT_EQ(Value{d}.as<double>(), d);
d = std::numeric_limits<double>::min();
EXPECT_EQ(Value{d}.f64, d);
EXPECT_EQ(Value{d}.as<double>(), d);
d = std::numeric_limits<double>::max();
EXPECT_EQ(Value{d}.f64, d);
EXPECT_EQ(Value{d}.as<double>(), d);
d = std::numeric_limits<double>::denorm_min();
EXPECT_EQ(Value{d}.f64, d);
EXPECT_EQ(Value{d}.as<double>(), d);
d = std::numeric_limits<double>::lowest();
EXPECT_EQ(Value{d}.f64, d);
EXPECT_EQ(Value{d}.as<double>(), d);
}

TEST(value, implicit_conversion_to_i64)
{
const Value v{1};
Expand Down

0 comments on commit ad0592c

Please sign in to comment.