blob: 966946ef99620d230104446e07074ff72860b931 [file] [log] [blame]
// Copyright 2014 the V8 project authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
#include "src/objects/objects-inl.h"
#include "src/wasm/wasm-external-refs.h"
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/codegen-tester.h"
#include "test/cctest/compiler/value-helper.h"
namespace v8 {
namespace internal {
namespace compiler {
template <typename InType, typename OutType, typename Iterable>
void TestExternalReference_ConvertOp(
BufferedRawMachineAssemblerTester<int32_t>* m, ExternalReference ref,
void (*wrapper)(Address), Iterable inputs) {
constexpr size_t kBufferSize = Max(sizeof(InType), sizeof(OutType));
uint8_t buffer[kBufferSize] = {0};
Address buffer_addr = reinterpret_cast<Address>(buffer);
Node* function = m->ExternalConstant(ref);
m->CallCFunction(
function, MachineType::Pointer(),
std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer)));
m->Return(m->Int32Constant(4356));
for (InType input : inputs) {
WriteUnalignedValue<InType>(buffer_addr, input);
CHECK_EQ(4356, m->Call());
OutType output = ReadUnalignedValue<OutType>(buffer_addr);
WriteUnalignedValue<InType>(buffer_addr, input);
wrapper(buffer_addr);
OutType expected_output = ReadUnalignedValue<OutType>(buffer_addr);
CHECK_EQ(expected_output, output);
}
}
template <typename InType, typename OutType, typename Iterable>
void TestExternalReference_ConvertOpWithOutputAndReturn(
BufferedRawMachineAssemblerTester<int32_t>* m, ExternalReference ref,
int32_t (*wrapper)(Address), Iterable inputs) {
constexpr size_t kBufferSize = Max(sizeof(InType), sizeof(OutType));
uint8_t buffer[kBufferSize] = {0};
Address buffer_addr = reinterpret_cast<Address>(buffer);
Node* function = m->ExternalConstant(ref);
m->Return(m->CallCFunction(
function, MachineType::Int32(),
std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer))));
for (InType input : inputs) {
WriteUnalignedValue<InType>(buffer_addr, input);
int32_t ret = m->Call();
OutType output = ReadUnalignedValue<OutType>(buffer_addr);
WriteUnalignedValue<InType>(buffer_addr, input);
int32_t expected_ret = wrapper(buffer_addr);
OutType expected_output = ReadUnalignedValue<OutType>(buffer_addr);
CHECK_EQ(expected_ret, ret);
CHECK_EQ(expected_output, output);
}
}
template <typename InType, typename OutType, typename Iterable>
void TestExternalReference_ConvertOpWithReturn(
BufferedRawMachineAssemblerTester<OutType>* m, ExternalReference ref,
OutType (*wrapper)(Address), Iterable inputs) {
constexpr size_t kBufferSize = sizeof(InType);
uint8_t buffer[kBufferSize] = {0};
Address buffer_addr = reinterpret_cast<Address>(buffer);
Node* function = m->ExternalConstant(ref);
m->Return(m->CallCFunction(
function, MachineType::Int32(),
std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer))));
for (InType input : inputs) {
WriteUnalignedValue<InType>(buffer_addr, input);
OutType ret = m->Call();
WriteUnalignedValue<InType>(buffer_addr, input);
OutType expected_ret = wrapper(buffer_addr);
CHECK_EQ(expected_ret, ret);
}
}
template <typename Type>
bool isnan(Type value) {
return false;
}
template <>
bool isnan<float>(float value) {
return std::isnan(value);
}
template <>
bool isnan<double>(double value) {
return std::isnan(value);
}
template <typename Type, typename Iterable>
void TestExternalReference_UnOp(BufferedRawMachineAssemblerTester<int32_t>* m,
ExternalReference ref, void (*wrapper)(Address),
Iterable inputs) {
constexpr size_t kBufferSize = sizeof(Type);
uint8_t buffer[kBufferSize] = {0};
Address buffer_addr = reinterpret_cast<Address>(buffer);
Node* function = m->ExternalConstant(ref);
m->CallCFunction(
function, MachineType::Int32(),
std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer)));
m->Return(m->Int32Constant(4356));
for (Type input : inputs) {
WriteUnalignedValue<Type>(buffer_addr, input);
CHECK_EQ(4356, m->Call());
Type output = ReadUnalignedValue<Type>(buffer_addr);
WriteUnalignedValue<Type>(buffer_addr, input);
wrapper(buffer_addr);
Type expected_output = ReadUnalignedValue<Type>(buffer_addr);
if (isnan(expected_output) && isnan(output)) continue;
CHECK_EQ(expected_output, output);
}
}
template <typename Type, typename Iterable>
void TestExternalReference_BinOp(BufferedRawMachineAssemblerTester<int32_t>* m,
ExternalReference ref,
void (*wrapper)(Address), Iterable inputs) {
constexpr size_t kBufferSize = 2 * sizeof(Type);
uint8_t buffer[kBufferSize] = {0};
Address buffer_addr = reinterpret_cast<Address>(buffer);
Node* function = m->ExternalConstant(ref);
m->CallCFunction(
function, MachineType::Int32(),
std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer)));
m->Return(m->Int32Constant(4356));
for (Type input1 : inputs) {
for (Type input2 : inputs) {
WriteUnalignedValue<Type>(buffer_addr, input1);
WriteUnalignedValue<Type>(buffer_addr + sizeof(Type), input2);
CHECK_EQ(4356, m->Call());
Type output = ReadUnalignedValue<Type>(buffer_addr);
WriteUnalignedValue<Type>(buffer_addr, input1);
WriteUnalignedValue<Type>(buffer_addr + sizeof(Type), input2);
wrapper(buffer_addr);
Type expected_output = ReadUnalignedValue<Type>(buffer_addr);
if (isnan(expected_output) && isnan(output)) continue;
CHECK_EQ(expected_output, output);
}
}
}
template <typename Type, typename Iterable>
void TestExternalReference_BinOpWithReturn(
BufferedRawMachineAssemblerTester<int32_t>* m, ExternalReference ref,
int32_t (*wrapper)(Address), Iterable inputs) {
constexpr size_t kBufferSize = 2 * sizeof(Type);
uint8_t buffer[kBufferSize] = {0};
Address buffer_addr = reinterpret_cast<Address>(buffer);
Node* function = m->ExternalConstant(ref);
m->Return(m->CallCFunction(
function, MachineType::Int32(),
std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer))));
for (Type input1 : inputs) {
for (Type input2 : inputs) {
WriteUnalignedValue<Type>(buffer_addr, input1);
WriteUnalignedValue<Type>(buffer_addr + sizeof(Type), input2);
int32_t ret = m->Call();
Type output = ReadUnalignedValue<Type>(buffer_addr);
WriteUnalignedValue<Type>(buffer_addr, input1);
WriteUnalignedValue<Type>(buffer_addr + sizeof(Type), input2);
int32_t expected_ret = wrapper(buffer_addr);
Type expected_output = ReadUnalignedValue<Type>(buffer_addr);
CHECK_EQ(expected_ret, ret);
if (isnan(expected_output) && isnan(output)) continue;
CHECK_EQ(expected_output, output);
}
}
}
TEST(RunCallF32Trunc) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_f32_trunc();
TestExternalReference_UnOp<float>(&m, ref, wasm::f32_trunc_wrapper,
ValueHelper::float32_vector());
}
TEST(RunCallF32Floor) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_f32_floor();
TestExternalReference_UnOp<float>(&m, ref, wasm::f32_floor_wrapper,
ValueHelper::float32_vector());
}
TEST(RunCallF32Ceil) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_f32_ceil();
TestExternalReference_UnOp<float>(&m, ref, wasm::f32_ceil_wrapper,
ValueHelper::float32_vector());
}
TEST(RunCallF32RoundTiesEven) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_f32_nearest_int();
TestExternalReference_UnOp<float>(&m, ref, wasm::f32_nearest_int_wrapper,
ValueHelper::float32_vector());
}
TEST(RunCallF64Trunc) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_f64_trunc();
TestExternalReference_UnOp<double>(&m, ref, wasm::f64_trunc_wrapper,
ValueHelper::float64_vector());
}
TEST(RunCallF64Floor) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_f64_floor();
TestExternalReference_UnOp<double>(&m, ref, wasm::f64_floor_wrapper,
ValueHelper::float64_vector());
}
TEST(RunCallF64Ceil) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_f64_ceil();
TestExternalReference_UnOp<double>(&m, ref, wasm::f64_ceil_wrapper,
ValueHelper::float64_vector());
}
TEST(RunCallF64RoundTiesEven) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_f64_nearest_int();
TestExternalReference_UnOp<double>(&m, ref, wasm::f64_nearest_int_wrapper,
ValueHelper::float64_vector());
}
TEST(RunCallInt64ToFloat32) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_int64_to_float32();
TestExternalReference_ConvertOp<int64_t, float>(
&m, ref, wasm::int64_to_float32_wrapper, ValueHelper::int64_vector());
}
TEST(RunCallUint64ToFloat32) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_uint64_to_float32();
TestExternalReference_ConvertOp<uint64_t, float>(
&m, ref, wasm::uint64_to_float32_wrapper, ValueHelper::uint64_vector());
}
TEST(RunCallInt64ToFloat64) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_int64_to_float64();
TestExternalReference_ConvertOp<int64_t, double>(
&m, ref, wasm::int64_to_float64_wrapper, ValueHelper::int64_vector());
}
TEST(RunCallUint64ToFloat64) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_uint64_to_float64();
TestExternalReference_ConvertOp<uint64_t, double>(
&m, ref, wasm::uint64_to_float64_wrapper, ValueHelper::uint64_vector());
}
TEST(RunCallFloat32ToInt64) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_float32_to_int64();
TestExternalReference_ConvertOpWithOutputAndReturn<float, int64_t>(
&m, ref, wasm::float32_to_int64_wrapper, ValueHelper::float32_vector());
}
TEST(RunCallFloat32ToUint64) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_float32_to_uint64();
TestExternalReference_ConvertOpWithOutputAndReturn<float, uint64_t>(
&m, ref, wasm::float32_to_uint64_wrapper, ValueHelper::float32_vector());
}
TEST(RunCallFloat64ToInt64) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_float64_to_int64();
TestExternalReference_ConvertOpWithOutputAndReturn<double, int64_t>(
&m, ref, wasm::float64_to_int64_wrapper, ValueHelper::float64_vector());
}
TEST(RunCallFloat64ToUint64) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_float64_to_uint64();
TestExternalReference_ConvertOpWithOutputAndReturn<double, uint64_t>(
&m, ref, wasm::float64_to_uint64_wrapper, ValueHelper::float64_vector());
}
TEST(RunCallInt64Div) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_int64_div();
TestExternalReference_BinOpWithReturn<int64_t>(
&m, ref, wasm::int64_div_wrapper, ValueHelper::int64_vector());
}
TEST(RunCallInt64Mod) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_int64_mod();
TestExternalReference_BinOpWithReturn<int64_t>(
&m, ref, wasm::int64_mod_wrapper, ValueHelper::int64_vector());
}
TEST(RunCallUint64Div) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_uint64_div();
TestExternalReference_BinOpWithReturn<uint64_t>(
&m, ref, wasm::uint64_div_wrapper, ValueHelper::uint64_vector());
}
TEST(RunCallUint64Mod) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_uint64_mod();
TestExternalReference_BinOpWithReturn<uint64_t>(
&m, ref, wasm::uint64_mod_wrapper, ValueHelper::uint64_vector());
}
TEST(RunCallWord32Ctz) {
BufferedRawMachineAssemblerTester<uint32_t> m;
ExternalReference ref = ExternalReference::wasm_word32_ctz();
TestExternalReference_ConvertOpWithReturn<int32_t, uint32_t>(
&m, ref, wasm::word32_ctz_wrapper, ValueHelper::int32_vector());
}
TEST(RunCallWord64Ctz) {
BufferedRawMachineAssemblerTester<uint32_t> m;
ExternalReference ref = ExternalReference::wasm_word64_ctz();
TestExternalReference_ConvertOpWithReturn<int64_t, uint32_t>(
&m, ref, wasm::word64_ctz_wrapper, ValueHelper::int64_vector());
}
TEST(RunCallWord32Popcnt) {
BufferedRawMachineAssemblerTester<uint32_t> m;
ExternalReference ref = ExternalReference::wasm_word32_popcnt();
TestExternalReference_ConvertOpWithReturn<uint32_t, uint32_t>(
&m, ref, wasm::word32_popcnt_wrapper, ValueHelper::int32_vector());
}
TEST(RunCallWord64Popcnt) {
BufferedRawMachineAssemblerTester<uint32_t> m;
ExternalReference ref = ExternalReference::wasm_word64_popcnt();
TestExternalReference_ConvertOpWithReturn<int64_t, uint32_t>(
&m, ref, wasm::word64_popcnt_wrapper, ValueHelper::int64_vector());
}
TEST(RunCallFloat64Pow) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_float64_pow();
TestExternalReference_BinOp<double>(&m, ref, wasm::float64_pow_wrapper,
ValueHelper::float64_vector());
}
} // namespace compiler
} // namespace internal
} // namespace v8