Skip to content

Commit

Permalink
Value i32
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Nov 23, 2020
1 parent 78b39a0 commit 1cfb307
Show file tree
Hide file tree
Showing 15 changed files with 144 additions and 97 deletions.
3 changes: 1 addition & 2 deletions include/fizzy/fizzy.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ typedef struct FizzyModule FizzyModule;
typedef struct FizzyInstance FizzyInstance;

/// The data type representing numeric values.
///
/// i64 member is used to represent values of both i32 and i64 type.
typedef union FizzyValue
{
uint32_t i32;
uint64_t i64;
float f32;
double f64;
Expand Down
5 changes: 3 additions & 2 deletions lib/fizzy/execute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1199,7 +1199,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
goto trap;
const auto lhs = stack.top().as<int64_t>();
if (lhs == std::numeric_limits<int64_t>::min() && rhs == -1)
stack.top() = 0;
stack.top().i64 = 0; // FIXME: Review all cases like this.
else
stack.top() = rem(lhs, rhs);
break;
Expand Down Expand Up @@ -1429,12 +1429,13 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
}
case Instr::i64_extend_i32_s:
{
// FIXME: Add more tests and make sure this is correct.
stack.top() = int64_t{stack.top().as<int32_t>()};
break;
}
case Instr::i64_extend_i32_u:
{
// effectively no-op
stack.top().i64 = uint64_t{stack.top().i32};
break;
}
case Instr::i64_trunc_f32_s:
Expand Down
4 changes: 2 additions & 2 deletions lib/fizzy/instantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ std::unique_ptr<Instance> instantiate(std::unique_ptr<const Module> module,
{
// Offset is validated to be i32, but it's used in 64-bit calculation below.
const uint64_t offset =
eval_constant_expression(data.offset, imported_globals, globals).i64;
eval_constant_expression(data.offset, imported_globals, globals).i32;

if (offset + data.init.size() > memory->size())
throw instantiate_error{"data segment is out of memory bounds"};
Expand All @@ -298,7 +298,7 @@ std::unique_ptr<Instance> instantiate(std::unique_ptr<const Module> module,
{
// Offset is validated to be i32, but it's used in 64-bit calculation below.
const uint64_t offset =
eval_constant_expression(element.offset, imported_globals, globals).i64;
eval_constant_expression(element.offset, imported_globals, globals).i32;

if (offset + element.init.size() > table->size())
throw instantiate_error{"element segment is out of table bounds"};
Expand Down
12 changes: 5 additions & 7 deletions lib/fizzy/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

#pragma once

#include <cassert>
#include <cstdint>
#include <limits>

namespace fizzy
{
union Value
{
uint32_t i32;
uint64_t i64;
float f32;
double f64;
Expand All @@ -26,11 +26,11 @@ union Value
/// We need to support {signed,unsigned} x {32,64} integers. However, due to uint64_t being
/// defined differently in different implementations we need to avoid the alias and provide
/// constructors for unsigned long and unsigned long long independently.
constexpr Value(unsigned int v) noexcept : i64{v} {}
constexpr Value(unsigned int v) noexcept : i32{v} {}
constexpr Value(unsigned long v) noexcept : i64{v} {}
constexpr Value(unsigned long long v) noexcept : i64{v} {}
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(int32_t v) noexcept : i32{static_cast<uint32_t>(v)} {}

constexpr Value(float v) noexcept : f32{v} {}
constexpr Value(double v) noexcept : f64{v} {}
Expand All @@ -54,8 +54,7 @@ constexpr uint64_t Value::as<uint64_t>() const noexcept
template <>
constexpr uint32_t Value::as<uint32_t>() const noexcept
{
assert((i64 & 0xffffffff00000000) == 0);
return static_cast<uint32_t>(i64);
return i32;
}

template <>
Expand All @@ -67,8 +66,7 @@ constexpr int64_t Value::as<int64_t>() const noexcept
template <>
constexpr int32_t Value::as<int32_t>() const noexcept
{
assert((i64 & 0xffffffff00000000) == 0);
return static_cast<int32_t>(i64);
return static_cast<int32_t>(i32);
}

template <>
Expand Down
25 changes: 22 additions & 3 deletions test/spectests/spectests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,24 @@ class test_runner
return fizzy::execute(*instance, *func_idx, args.data());
}

bool check_integer_result(fizzy::Value actual_value, const json& expected)
bool check_i32_result(fizzy::Value actual_value, const json& expected)
{
const auto expected_value = read_integer_value(expected);

if (expected_value.i32 != actual_value.i32)
{
std::stringstream message;
message << "Incorrect returned value. Expected: " << expected_value.i32 << " (0x"
<< std::hex << expected_value.i32 << ")"
<< " Actual: " << std::dec << actual_value.i32 << " (0x" << std::hex
<< actual_value.i32 << ")";
fail(message.str());
return false;
}
return true;
}

bool check_i64_result(fizzy::Value actual_value, const json& expected)
{
const auto expected_value = read_integer_value(expected);

Expand Down Expand Up @@ -544,8 +561,10 @@ class test_runner
{
const auto type = expected.at("type").get<std::string>();

if (type == "i32" || type == "i64")
return check_integer_result(actual_value, expected);
if (type == "i32")
return check_i32_result(actual_value, expected);
else if (type == "i64")
return check_i64_result(actual_value, expected);
else if (type == "f32")
return check_floating_point_result<float>(actual_value, expected);
else if (type == "f64")
Expand Down
1 change: 1 addition & 0 deletions test/testfloat/testfloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ bool eq(TypedValue v, uint64_t expected_bits, bool ignore_nans)
switch (v.type)
{
case ValType::i32:
return v.value.i32 == expected_bits;
case ValType::i64:
return v.value.i64 == expected_bits;
case ValType::f32:
Expand Down
16 changes: 9 additions & 7 deletions test/unittests/capi_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ TEST(capi, find_exported_function)
EXPECT_EQ(function.type.output, FizzyValueTypeI32);
EXPECT_NE(function.context, nullptr);
ASSERT_NE(function.function, nullptr);
EXPECT_THAT(function.function(function.context, instance, nullptr, 0), CResult(42));
EXPECT_THAT(function.function(function.context, instance, nullptr, 0), CResult(42_u32));

fizzy_free_exported_function(&function);

Expand Down Expand Up @@ -278,7 +278,7 @@ TEST(capi, find_exported_global)
ASSERT_TRUE(fizzy_find_exported_global(instance, "g1", &global));
EXPECT_EQ(global.type.value_type, FizzyValueTypeI32);
EXPECT_FALSE(global.type.is_mutable);
EXPECT_EQ(global.value->i64, 42);
EXPECT_EQ(global.value->i32, 42);

EXPECT_FALSE(fizzy_find_exported_global(instance, "g2", &global));
EXPECT_FALSE(fizzy_find_exported_global(instance, "foo", &global));
Expand Down Expand Up @@ -593,7 +593,7 @@ TEST(capi, memory_access)
memory[0] = 0xaa;
memory[1] = 0xbb;

EXPECT_EQ(fizzy_execute(instance, 0, nullptr, 0).value.i64, 0x22bbaa);
EXPECT_EQ(fizzy_execute(instance, 0, nullptr, 0).value.i32, 0x22bbaa);

fizzy_free_instance(instance);
}
Expand Down Expand Up @@ -661,7 +661,9 @@ TEST(capi, execute_with_host_function)
nullptr},
{{FizzyValueTypeI32, &inputs[0], 2},
[](void*, FizzyInstance*, const FizzyValue* args, int) {
return FizzyExecutionResult{false, true, {args[0].i64 / args[1].i64}};
FizzyValue v;
v.i64 = args[0].i64 / args[1].i64;
return FizzyExecutionResult{false, true, {v}};
},
nullptr}};

Expand Down Expand Up @@ -815,7 +817,7 @@ TEST(capi, imported_table_from_another_module)
auto instance2 = fizzy_instantiate(module2, nullptr, 0, &table, nullptr, nullptr, 0);
ASSERT_NE(instance2, nullptr);

EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, 0), CResult(42));
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, 0), CResult(42_u32));

fizzy_free_instance(instance2);
fizzy_free_instance(instance1);
Expand Down Expand Up @@ -851,7 +853,7 @@ TEST(capi, imported_memory_from_another_module)
auto instance2 = fizzy_instantiate(module2, nullptr, 0, nullptr, &memory, nullptr, 0);
ASSERT_NE(instance2, nullptr);

EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, 0), CResult(0x00ffaa00));
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, 0), CResult(0x00ffaa00_u32));

fizzy_free_instance(instance2);
fizzy_free_instance(instance1);
Expand Down Expand Up @@ -887,7 +889,7 @@ TEST(capi, imported_global_from_another_module)
auto instance2 = fizzy_instantiate(module2, nullptr, 0, nullptr, nullptr, &global, 1);
ASSERT_NE(instance2, nullptr);

EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, 0), CResult(42));
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, 0), CResult(42_u32));

fizzy_free_instance(instance2);
fizzy_free_instance(instance1);
Expand Down
6 changes: 3 additions & 3 deletions test/unittests/cxx20_span_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ TEST(cxx20_span, stack)
constexpr auto num_items = 2;
span<const Value> s(stack.rend() - num_items, num_items);
EXPECT_EQ(s.size(), 2);
EXPECT_EQ(s[0].i64, 12);
EXPECT_EQ(s[1].i64, 13);
EXPECT_EQ(s[0].i32, 12);
EXPECT_EQ(s[1].i32, 13);

stack[0] = 0;
EXPECT_EQ(s[1].i64, 0);
EXPECT_EQ(s[1].i32, 0);
}

TEST(cxx20_span, initializer_list)
Expand Down
26 changes: 25 additions & 1 deletion test/unittests/execute_numeric_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,11 +478,35 @@ TEST(execute_numeric, i64_extend_i32_s_1)

TEST(execute_numeric, i64_extend_i32_u)
{
TypedValue v{ValType::i32, {}};
v.value.i64 = 0xdeaddeaddeaddead;
v.value.i32 = 0xff000000;
EXPECT_THAT(
execute_unary_operation(Instr::i64_extend_i32_u, 0xff000000), Result(0x00000000ff000000));
execute_unary_operation(Instr::i64_extend_i32_u, v), Result(uint64_t{0x00000000ff000000}));
}

TEST(execute_numeric, i64_extend_i32_u_2)
{
/* wat2wasm
(func (param i32) (result i64)
i64.const 0xdeadbeefdeadbeef
drop
local.get 0
i64.extend_i32_u
)
*/
const auto wasm = from_hex(
"0061736d0100000001060160017f017e030201000a1201100042effdb6f5fdddefd65e1a2000ad0b");

auto instance = instantiate(parse(wasm));
TypedValue v{ValType::i32, {}};
v.value.i64 = 0xfefefefefefefefe;
v.value.i32 = 0xff000000;
const auto r = execute(*instance, 0, {v});
EXPECT_THAT(r, Result(uint64_t{0x00000000ff000000}));
}

TEST(execute_numeric, i64_extend_i32_u_3)
{
/* wat2wasm
(func (param i32) (result i64)
Expand Down
Loading

0 comments on commit 1cfb307

Please sign in to comment.