// Copyright 2021 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 #include #include "src/base/macros.h" #include "src/wasm/compilation-environment.h" #include "src/wasm/wasm-opcodes.h" #include "test/cctest/wasm/wasm-run-utils.h" #include "test/common/wasm/wasm-macro-gen.h" namespace v8 { namespace internal { namespace wasm { using Int8UnOp = int8_t (*)(int8_t); using Int8BinOp = int8_t (*)(int8_t, int8_t); using Uint8BinOp = uint8_t (*)(uint8_t, uint8_t); using Int8CompareOp = int (*)(int8_t, int8_t); using Int8ShiftOp = int8_t (*)(int8_t, int); using Int16UnOp = int16_t (*)(int16_t); using Int16BinOp = int16_t (*)(int16_t, int16_t); using Uint16BinOp = uint16_t (*)(uint16_t, uint16_t); using Int16ShiftOp = int16_t (*)(int16_t, int); using Int32UnOp = int32_t (*)(int32_t); using Int32BinOp = int32_t (*)(int32_t, int32_t); using Int32ShiftOp = int32_t (*)(int32_t, int); using Int64UnOp = int64_t (*)(int64_t); using Int64BinOp = int64_t (*)(int64_t, int64_t); using Int64ShiftOp = int64_t (*)(int64_t, int); using FloatUnOp = float (*)(float); using FloatBinOp = float (*)(float, float); using FloatCompareOp = int32_t (*)(float, float); using DoubleUnOp = double (*)(double); using DoubleBinOp = double (*)(double, double); using DoubleCompareOp = int64_t (*)(double, double); void RunI8x16UnOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int8UnOp expected_op); template void RunI8x16BinOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, OpType expected_op); void RunI8x16ShiftOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int8ShiftOp expected_op); void RunI8x16MixedRelationalOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int8BinOp expected_op); void RunI16x8UnOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int16UnOp expected_op); template void RunI16x8BinOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, OpType expected_op); void RunI16x8ShiftOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int16ShiftOp expected_op); void RunI16x8MixedRelationalOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int16BinOp expected_op); void RunI32x4UnOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int32UnOp expected_op); void RunI32x4BinOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int32BinOp expected_op); void RunI32x4ShiftOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int32ShiftOp expected_op); void RunI64x2UnOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int64UnOp expected_op); void RunI64x2BinOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int64BinOp expected_op); void RunI64x2ShiftOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, Int64ShiftOp expected_op); // Generic expected value functions. template ::value>::type> T Negate(T a) { return -a; } #if V8_OS_AIX template bool MightReverseSign(T float_op) { return float_op == static_cast(Negate) || float_op == static_cast(std::abs); } #endif // Test some values not included in the float inputs from value_helper. These // tests are useful for opcodes that are synthesized during code gen, like Min // and Max on ia32 and x64. static constexpr uint32_t nan_test_array[] = { // Bit patterns of quiet NaNs and signaling NaNs, with or without // additional payload. 0x7FC00000, 0xFFC00000, 0x7FFFFFFF, 0xFFFFFFFF, 0x7F876543, 0xFF876543, // NaN with top payload bit unset. 0x7FA00000, // Both Infinities. 0x7F800000, 0xFF800000, // Some "normal" numbers, 1 and -1. 0x3F800000, 0xBF800000}; #define FOR_FLOAT32_NAN_INPUTS(i) \ for (size_t i = 0; i < arraysize(nan_test_array); ++i) // Test some values not included in the double inputs from value_helper. These // tests are useful for opcodes that are synthesized during code gen, like Min // and Max on ia32 and x64. static constexpr uint64_t double_nan_test_array[] = { // quiet NaNs, + and - 0x7FF8000000000001, 0xFFF8000000000001, // with payload 0x7FF8000000000011, 0xFFF8000000000011, // signaling NaNs, + and - 0x7FF0000000000001, 0xFFF0000000000001, // with payload 0x7FF0000000000011, 0xFFF0000000000011, // Both Infinities. 0x7FF0000000000000, 0xFFF0000000000000, // Some "normal" numbers, 1 and -1. 0x3FF0000000000000, 0xBFF0000000000000}; #define FOR_FLOAT64_NAN_INPUTS(i) \ for (size_t i = 0; i < arraysize(double_nan_test_array); ++i) // Returns true if the platform can represent the result. template bool PlatformCanRepresent(T x) { #if V8_TARGET_ARCH_ARM return std::fpclassify(x) != FP_SUBNORMAL; #else return true; #endif } // Returns true for very small and very large numbers. We skip these test // values for the approximation instructions, which don't work at the extremes. bool IsExtreme(float x); bool IsSameNan(float expected, float actual); bool IsCanonical(float actual); void CheckFloatResult(float x, float y, float expected, float actual, bool exact = true); bool IsExtreme(double x); bool IsSameNan(double expected, double actual); bool IsCanonical(double actual); void CheckDoubleResult(double x, double y, double expected, double actual, bool exact = true); void RunF32x4UnOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, FloatUnOp expected_op, bool exact = true); void RunF32x4BinOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, FloatBinOp expected_op); void RunF32x4CompareOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, FloatCompareOp expected_op); void RunF64x2UnOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, DoubleUnOp expected_op, bool exact = true); void RunF64x2BinOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, DoubleBinOp expected_op); void RunF64x2CompareOpTest(TestExecutionTier execution_tier, WasmOpcode opcode, DoubleCompareOp expected_op); } // namespace wasm } // namespace internal } // namespace v8