Skip to content

Commit

Permalink
Implement int->float convert instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Aug 6, 2020
1 parent c1e1647 commit 0e37d68
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 8 deletions.
54 changes: 46 additions & 8 deletions lib/fizzy/execute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,12 @@ inline bool trunc(OperandStack& stack) noexcept
return true;
}

template <typename SrcT, typename DstT>
inline void convert(OperandStack& stack) noexcept
{
stack.top() = static_cast<DstT>(stack.top().as<SrcT>());
}

template <typename DstT, typename SrcT = DstT>
inline bool load_from_memory(
bytes_view memory, OperandStack& stack, const uint8_t*& immediates) noexcept
Expand Down Expand Up @@ -1473,6 +1479,46 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, span<const Value>
}
break;
}
case Instr::f32_convert_i32_s:
{
convert<int32_t, float>(stack);
break;
}
case Instr::f32_convert_i32_u:
{
convert<uint32_t, float>(stack);
break;
}
case Instr::f32_convert_i64_s:
{
convert<int64_t, float>(stack);
break;
}
case Instr::f32_convert_i64_u:
{
convert<uint64_t, float>(stack);
break;
}
case Instr::f64_convert_i32_s:
{
convert<int32_t, double>(stack);
break;
}
case Instr::f64_convert_i32_u:
{
convert<uint32_t, double>(stack);
break;
}
case Instr::f64_convert_i64_s:
{
convert<int64_t, double>(stack);
break;
}
case Instr::f64_convert_i64_u:
{
convert<uint64_t, double>(stack);
break;
}
case Instr::f32_add:
{
binary_op(stack, std::plus<float>{});
Expand Down Expand Up @@ -1526,15 +1572,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, span<const Value>
case Instr::f64_min:
case Instr::f64_max:
case Instr::f64_copysign:
case Instr::f32_convert_i32_s:
case Instr::f32_convert_i32_u:
case Instr::f32_convert_i64_s:
case Instr::f32_convert_i64_u:
case Instr::f32_demote_f64:
case Instr::f64_convert_i32_s:
case Instr::f64_convert_i32_u:
case Instr::f64_convert_i64_s:
case Instr::f64_convert_i64_u:
case Instr::f64_promote_f32:
case Instr::i32_reinterpret_f32:
case Instr::i64_reinterpret_f64:
Expand Down
119 changes: 119 additions & 0 deletions test/unittests/execute_floating_point_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,70 @@ struct ConversionPairWasmTraits<double, uint64_t>
static constexpr auto src_valtype = ValType::f64;
static constexpr auto dst_valtype = ValType::i64;
};
template <>
struct ConversionPairWasmTraits<int32_t, float>
{
static constexpr auto opcode_name = "f32_convert_i32_s";
static constexpr auto opcode = Instr::f32_convert_i32_s;
static constexpr auto src_valtype = ValType::i32;
static constexpr auto dst_valtype = ValType::f32;
};
template <>
struct ConversionPairWasmTraits<uint32_t, float>
{
static constexpr auto opcode_name = "f32_convert_i32_u";
static constexpr auto opcode = Instr::f32_convert_i32_u;
static constexpr auto src_valtype = ValType::i32;
static constexpr auto dst_valtype = ValType::f32;
};
template <>
struct ConversionPairWasmTraits<int64_t, float>
{
static constexpr auto opcode_name = "f32_convert_i64_s";
static constexpr auto opcode = Instr::f32_convert_i64_s;
static constexpr auto src_valtype = ValType::i64;
static constexpr auto dst_valtype = ValType::f32;
};
template <>
struct ConversionPairWasmTraits<uint64_t, float>
{
static constexpr auto opcode_name = "f32_convert_i64_u";
static constexpr auto opcode = Instr::f32_convert_i64_u;
static constexpr auto src_valtype = ValType::i64;
static constexpr auto dst_valtype = ValType::f32;
};
template <>
struct ConversionPairWasmTraits<int32_t, double>
{
static constexpr auto opcode_name = "f64_convert_i32_s";
static constexpr auto opcode = Instr::f64_convert_i32_s;
static constexpr auto src_valtype = ValType::i32;
static constexpr auto dst_valtype = ValType::f64;
};
template <>
struct ConversionPairWasmTraits<uint32_t, double>
{
static constexpr auto opcode_name = "f64_convert_i32_u";
static constexpr auto opcode = Instr::f64_convert_i32_u;
static constexpr auto src_valtype = ValType::i32;
static constexpr auto dst_valtype = ValType::f64;
};
template <>
struct ConversionPairWasmTraits<int64_t, double>
{
static constexpr auto opcode_name = "f64_convert_i64_s";
static constexpr auto opcode = Instr::f64_convert_i64_s;
static constexpr auto src_valtype = ValType::i64;
static constexpr auto dst_valtype = ValType::f64;
};
template <>
struct ConversionPairWasmTraits<uint64_t, double>
{
static constexpr auto opcode_name = "f64_convert_i64_u";
static constexpr auto opcode = Instr::f64_convert_i64_u;
static constexpr auto src_valtype = ValType::i64;
static constexpr auto dst_valtype = ValType::f64;
};

template <typename SrcT, typename DstT>
struct ConversionPair : ConversionPairWasmTraits<SrcT, DstT>
Expand Down Expand Up @@ -273,3 +337,58 @@ TYPED_TEST(execute_floating_point_trunc, trunc)
EXPECT_EQ(result.value.template as<IntT>(), FloatT{-1});
}
}


template <typename T>
class execute_floating_point_convert : public testing::Test
{
};

using ConvertPairs = testing::Types<ConversionPair<int32_t, float>, ConversionPair<uint32_t, float>,
ConversionPair<int64_t, float>, ConversionPair<uint64_t, float>,
ConversionPair<int32_t, double>, ConversionPair<uint32_t, double>,
ConversionPair<int64_t, double>, ConversionPair<uint64_t, double>>;
TYPED_TEST_SUITE(execute_floating_point_convert, ConvertPairs, ConversionName);

TYPED_TEST(execute_floating_point_convert, convert)
{
using IntT = typename TypeParam::src_type;
using FloatT = typename TypeParam::dst_type;
using IntLimits = std::numeric_limits<IntT>;
using FloatLimits = std::numeric_limits<FloatT>;

/* wat2wasm
(func (param i32) (result f32)
local.get 0
f32.convert_i32_s
)
*/
auto wasm = from_hex("0061736d0100000001060160017f017d030201000a070105002000b20b");

// Find and replace changeable values: types and the conversion instruction.
auto& param_type = wasm[wasm.find(static_cast<uint8_t>(ValType::i32))];
auto& result_type = wasm[wasm.find(static_cast<uint8_t>(ValType::f32))];
auto& opcode = wasm[wasm.find(static_cast<uint8_t>(Instr::f32_convert_i32_s))];
param_type = static_cast<uint8_t>(TypeParam::src_valtype);
result_type = static_cast<uint8_t>(TypeParam::dst_valtype);
opcode = static_cast<uint8_t>(TypeParam::opcode);

auto instance = instantiate(parse(wasm));

EXPECT_THAT(execute(*instance, 0, {IntT{0}}), Result(FloatT{0}));
EXPECT_THAT(execute(*instance, 0, {IntT{1}}), Result(FloatT{1}));

const auto max = IntLimits::max();
const auto exact = IntLimits::digits < FloatLimits::digits;
const auto max_expected = std::pow(FloatT{2}, FloatT{IntLimits::digits}) - FloatT{exact};
EXPECT_THAT(execute(*instance, 0, {max}), Result(max_expected));

if constexpr (IntLimits::is_signed)
{
static_assert(std::is_same_v<decltype(-max), IntT>);
EXPECT_THAT(execute(*instance, 0, {-max}), Result(-max_expected));

const auto min_expected = -std::pow(FloatT{2}, FloatT{IntLimits::digits});
EXPECT_THAT(execute(*instance, 0, {IntLimits::min()}), Result(min_expected));
}
}

0 comments on commit 0e37d68

Please sign in to comment.