// 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-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 void TestExternalReference_ConvertOp( BufferedRawMachineAssemblerTester* 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
(buffer); Node* function = m->ExternalConstant(ref); m->CallCFunction1(MachineType::Pointer(), MachineType::Pointer(), function, m->PointerConstant(buffer)); m->Return(m->Int32Constant(4356)); for (InType input : inputs) { WriteUnalignedValue(buffer_addr, input); CHECK_EQ(4356, m->Call()); OutType output = ReadUnalignedValue(buffer_addr); WriteUnalignedValue(buffer_addr, input); wrapper(buffer_addr); OutType expected_output = ReadUnalignedValue(buffer_addr); CHECK_EQ(expected_output, output); } } template void TestExternalReference_ConvertOpWithOutputAndReturn( BufferedRawMachineAssemblerTester* 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
(buffer); Node* function = m->ExternalConstant(ref); m->Return(m->CallCFunction1(MachineType::Int32(), MachineType::Pointer(), function, m->PointerConstant(buffer))); for (InType input : inputs) { WriteUnalignedValue(buffer_addr, input); int32_t ret = m->Call(); OutType output = ReadUnalignedValue(buffer_addr); WriteUnalignedValue(buffer_addr, input); int32_t expected_ret = wrapper(buffer_addr); OutType expected_output = ReadUnalignedValue(buffer_addr); CHECK_EQ(expected_ret, ret); CHECK_EQ(expected_output, output); } } template void TestExternalReference_ConvertOpWithReturn( BufferedRawMachineAssemblerTester* m, ExternalReference ref, OutType (*wrapper)(Address), Iterable inputs) { constexpr size_t kBufferSize = sizeof(InType); uint8_t buffer[kBufferSize] = {0}; Address buffer_addr = reinterpret_cast
(buffer); Node* function = m->ExternalConstant(ref); m->Return(m->CallCFunction1(MachineType::Int32(), MachineType::Pointer(), function, m->PointerConstant(buffer))); for (InType input : inputs) { WriteUnalignedValue(buffer_addr, input); OutType ret = m->Call(); WriteUnalignedValue(buffer_addr, input); OutType expected_ret = wrapper(buffer_addr); CHECK_EQ(expected_ret, ret); } } template bool isnan(Type value) { return false; } template <> bool isnan(float value) { return std::isnan(value); } template <> bool isnan(double value) { return std::isnan(value); } template void TestExternalReference_UnOp(BufferedRawMachineAssemblerTester* m, ExternalReference ref, void (*wrapper)(Address), Iterable inputs) { constexpr size_t kBufferSize = sizeof(Type); uint8_t buffer[kBufferSize] = {0}; Address buffer_addr = reinterpret_cast
(buffer); Node* function = m->ExternalConstant(ref); m->CallCFunction1(MachineType::Int32(), MachineType::Pointer(), function, m->PointerConstant(buffer)); m->Return(m->Int32Constant(4356)); for (Type input : inputs) { WriteUnalignedValue(buffer_addr, input); CHECK_EQ(4356, m->Call()); Type output = ReadUnalignedValue(buffer_addr); WriteUnalignedValue(buffer_addr, input); wrapper(buffer_addr); Type expected_output = ReadUnalignedValue(buffer_addr); if (isnan(expected_output) && isnan(output)) continue; CHECK_EQ(expected_output, output); } } template void TestExternalReference_BinOp(BufferedRawMachineAssemblerTester* 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
(buffer); Node* function = m->ExternalConstant(ref); m->CallCFunction1(MachineType::Int32(), MachineType::Pointer(), function, m->PointerConstant(buffer)); m->Return(m->Int32Constant(4356)); for (Type input1 : inputs) { for (Type input2 : inputs) { WriteUnalignedValue(buffer_addr, input1); WriteUnalignedValue(buffer_addr + sizeof(Type), input2); CHECK_EQ(4356, m->Call()); Type output = ReadUnalignedValue(buffer_addr); WriteUnalignedValue(buffer_addr, input1); WriteUnalignedValue(buffer_addr + sizeof(Type), input2); wrapper(buffer_addr); Type expected_output = ReadUnalignedValue(buffer_addr); if (isnan(expected_output) && isnan(output)) continue; CHECK_EQ(expected_output, output); } } } template void TestExternalReference_BinOpWithReturn( BufferedRawMachineAssemblerTester* 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
(buffer); Node* function = m->ExternalConstant(ref); m->Return(m->CallCFunction1(MachineType::Int32(), MachineType::Pointer(), function, m->PointerConstant(buffer))); for (Type input1 : inputs) { for (Type input2 : inputs) { WriteUnalignedValue(buffer_addr, input1); WriteUnalignedValue(buffer_addr + sizeof(Type), input2); int32_t ret = m->Call(); Type output = ReadUnalignedValue(buffer_addr); WriteUnalignedValue(buffer_addr, input1); WriteUnalignedValue(buffer_addr + sizeof(Type), input2); int32_t expected_ret = wrapper(buffer_addr); Type expected_output = ReadUnalignedValue(buffer_addr); CHECK_EQ(expected_ret, ret); if (isnan(expected_output) && isnan(output)) continue; CHECK_EQ(expected_output, output); } } } TEST(RunCallF32Trunc) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_f32_trunc(); TestExternalReference_UnOp(&m, ref, wasm::f32_trunc_wrapper, ValueHelper::float32_vector()); } TEST(RunCallF32Floor) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_f32_floor(); TestExternalReference_UnOp(&m, ref, wasm::f32_floor_wrapper, ValueHelper::float32_vector()); } TEST(RunCallF32Ceil) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_f32_ceil(); TestExternalReference_UnOp(&m, ref, wasm::f32_ceil_wrapper, ValueHelper::float32_vector()); } TEST(RunCallF32RoundTiesEven) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_f32_nearest_int(); TestExternalReference_UnOp(&m, ref, wasm::f32_nearest_int_wrapper, ValueHelper::float32_vector()); } TEST(RunCallF64Trunc) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_f64_trunc(); TestExternalReference_UnOp(&m, ref, wasm::f64_trunc_wrapper, ValueHelper::float64_vector()); } TEST(RunCallF64Floor) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_f64_floor(); TestExternalReference_UnOp(&m, ref, wasm::f64_floor_wrapper, ValueHelper::float64_vector()); } TEST(RunCallF64Ceil) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_f64_ceil(); TestExternalReference_UnOp(&m, ref, wasm::f64_ceil_wrapper, ValueHelper::float64_vector()); } TEST(RunCallF64RoundTiesEven) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_f64_nearest_int(); TestExternalReference_UnOp(&m, ref, wasm::f64_nearest_int_wrapper, ValueHelper::float64_vector()); } TEST(RunCallInt64ToFloat32) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_int64_to_float32(); TestExternalReference_ConvertOp( &m, ref, wasm::int64_to_float32_wrapper, ValueHelper::int64_vector()); } TEST(RunCallUint64ToFloat32) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_uint64_to_float32(); TestExternalReference_ConvertOp( &m, ref, wasm::uint64_to_float32_wrapper, ValueHelper::uint64_vector()); } TEST(RunCallInt64ToFloat64) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_int64_to_float64(); TestExternalReference_ConvertOp( &m, ref, wasm::int64_to_float64_wrapper, ValueHelper::int64_vector()); } TEST(RunCallUint64ToFloat64) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_uint64_to_float64(); TestExternalReference_ConvertOp( &m, ref, wasm::uint64_to_float64_wrapper, ValueHelper::uint64_vector()); } TEST(RunCallFloat32ToInt64) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_float32_to_int64(); TestExternalReference_ConvertOpWithOutputAndReturn( &m, ref, wasm::float32_to_int64_wrapper, ValueHelper::float32_vector()); } TEST(RunCallFloat32ToUint64) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_float32_to_uint64(); TestExternalReference_ConvertOpWithOutputAndReturn( &m, ref, wasm::float32_to_uint64_wrapper, ValueHelper::float32_vector()); } TEST(RunCallFloat64ToInt64) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_float64_to_int64(); TestExternalReference_ConvertOpWithOutputAndReturn( &m, ref, wasm::float64_to_int64_wrapper, ValueHelper::float64_vector()); } TEST(RunCallFloat64ToUint64) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_float64_to_uint64(); TestExternalReference_ConvertOpWithOutputAndReturn( &m, ref, wasm::float64_to_uint64_wrapper, ValueHelper::float64_vector()); } TEST(RunCallInt64Div) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_int64_div(); TestExternalReference_BinOpWithReturn( &m, ref, wasm::int64_div_wrapper, ValueHelper::int64_vector()); } TEST(RunCallInt64Mod) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_int64_mod(); TestExternalReference_BinOpWithReturn( &m, ref, wasm::int64_mod_wrapper, ValueHelper::int64_vector()); } TEST(RunCallUint64Div) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_uint64_div(); TestExternalReference_BinOpWithReturn( &m, ref, wasm::uint64_div_wrapper, ValueHelper::uint64_vector()); } TEST(RunCallUint64Mod) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_uint64_mod(); TestExternalReference_BinOpWithReturn( &m, ref, wasm::uint64_mod_wrapper, ValueHelper::uint64_vector()); } TEST(RunCallWord32Ctz) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_word32_ctz(); TestExternalReference_ConvertOpWithReturn( &m, ref, wasm::word32_ctz_wrapper, ValueHelper::int32_vector()); } TEST(RunCallWord64Ctz) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_word64_ctz(); TestExternalReference_ConvertOpWithReturn( &m, ref, wasm::word64_ctz_wrapper, ValueHelper::int64_vector()); } TEST(RunCallWord32Popcnt) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_word32_popcnt(); TestExternalReference_ConvertOpWithReturn( &m, ref, wasm::word32_popcnt_wrapper, ValueHelper::int32_vector()); } TEST(RunCallWord64Popcnt) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_word64_popcnt(); TestExternalReference_ConvertOpWithReturn( &m, ref, wasm::word64_popcnt_wrapper, ValueHelper::int64_vector()); } TEST(RunCallFloat64Pow) { BufferedRawMachineAssemblerTester m; ExternalReference ref = ExternalReference::wasm_float64_pow(); TestExternalReference_BinOp(&m, ref, wasm::float64_pow_wrapper, ValueHelper::float64_vector()); } } // namespace compiler } // namespace internal } // namespace v8