diff --git a/test/cctest/wasm/test-run-wasm-simd.cc b/test/cctest/wasm/test-run-wasm-simd.cc index d324ec969d..bcd6f4f12d 100644 --- a/test/cctest/wasm/test-run-wasm-simd.cc +++ b/test/cctest/wasm/test-run-wasm-simd.cc @@ -46,26 +46,6 @@ namespace test_run_wasm_simd { namespace { -using DoubleUnOp = double (*)(double); -using DoubleBinOp = double (*)(double, double); -using DoubleCompareOp = int64_t (*)(double, double); -using FloatBinOp = float (*)(float, float); -using FloatCompareOp = int (*)(float, float); -using Int64UnOp = int64_t (*)(int64_t); -using Int64BinOp = int64_t (*)(int64_t, int64_t); -using Int64ShiftOp = int64_t (*)(int64_t, int); -using Int32UnOp = int32_t (*)(int32_t); -using Int32BinOp = int32_t (*)(int32_t, int32_t); -using Int32CompareOp = int (*)(int32_t, int32_t); -using Int32ShiftOp = int32_t (*)(int32_t, int); -using Int16UnOp = int16_t (*)(int16_t); -using Int16BinOp = int16_t (*)(int16_t, int16_t); -using Int16CompareOp = int (*)(int16_t, int16_t); -using Int16ShiftOp = int16_t (*)(int16_t, int); -using Int8UnOp = int8_t (*)(int8_t); -using Int8BinOp = int8_t (*)(int8_t, int8_t); -using Int8CompareOp = int (*)(int8_t, int8_t); -using Int8ShiftOp = int8_t (*)(int8_t, int); using Shuffle = std::array; #define WASM_SIMD_TEST(name) \ @@ -129,45 +109,93 @@ T UnsignedMaximum(T a, T b) { return static_cast(a) >= static_cast(b) ? a : b; } -int Equal(float a, float b) { return a == b ? -1 : 0; } - -template -T Equal(T a, T b) { +template +U Equal(T a, T b) { return a == b ? -1 : 0; } -int NotEqual(float a, float b) { return a != b ? -1 : 0; } +template <> +int32_t Equal(float a, float b) { + return a == b ? -1 : 0; +} -template -T NotEqual(T a, T b) { +template <> +int64_t Equal(double a, double b) { + return a == b ? -1 : 0; +} + +template +U NotEqual(T a, T b) { return a != b ? -1 : 0; } -int Less(float a, float b) { return a < b ? -1 : 0; } +template <> +int32_t NotEqual(float a, float b) { + return a != b ? -1 : 0; +} -template -T Less(T a, T b) { +template <> +int64_t NotEqual(double a, double b) { + return a != b ? -1 : 0; +} + +template +U Less(T a, T b) { return a < b ? -1 : 0; } -int LessEqual(float a, float b) { return a <= b ? -1 : 0; } +template <> +int32_t Less(float a, float b) { + return a < b ? -1 : 0; +} -template -T LessEqual(T a, T b) { +template <> +int64_t Less(double a, double b) { + return a < b ? -1 : 0; +} + +template +U LessEqual(T a, T b) { return a <= b ? -1 : 0; } -int Greater(float a, float b) { return a > b ? -1 : 0; } +template <> +int32_t LessEqual(float a, float b) { + return a <= b ? -1 : 0; +} -template -T Greater(T a, T b) { +template <> +int64_t LessEqual(double a, double b) { + return a <= b ? -1 : 0; +} + +template +U Greater(T a, T b) { return a > b ? -1 : 0; } -int GreaterEqual(float a, float b) { return a >= b ? -1 : 0; } +template <> +int32_t Greater(float a, float b) { + return a > b ? -1 : 0; +} -template -T GreaterEqual(T a, T b) { +template <> +int64_t Greater(double a, double b) { + return a > b ? -1 : 0; +} + +template +U GreaterEqual(T a, T b) { + return a >= b ? -1 : 0; +} + +template <> +int32_t GreaterEqual(float a, float b) { + return a >= b ? -1 : 0; +} + +template <> +int64_t GreaterEqual(double a, double b) { return a >= b ? -1 : 0; } @@ -218,19 +246,6 @@ template T Abs(T a) { return std::abs(a); } - -// only used for F64x2 tests below -int64_t Equal(double a, double b) { return a == b ? -1 : 0; } - -int64_t NotEqual(double a, double b) { return a != b ? -1 : 0; } - -int64_t Greater(double a, double b) { return a > b ? -1 : 0; } - -int64_t GreaterEqual(double a, double b) { return a >= b ? -1 : 0; } - -int64_t Less(double a, double b) { return a < b ? -1 : 0; } - -int64_t LessEqual(double a, double b) { return a <= b ? -1 : 0; } } // namespace #define WASM_SIMD_CHECK_LANE_S(TYPE, value, LANE_TYPE, lane_value, lane_index) \ @@ -367,52 +382,6 @@ WASM_SIMD_TEST(F32x4NearestInt) { true); } -void RunF32x4BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, FloatBinOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - float* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test values, perform binop, and write the result. - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(value2))), - WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_ONE); - - FOR_FLOAT32_INPUTS(x) { - if (!PlatformCanRepresent(x)) continue; - FOR_FLOAT32_INPUTS(y) { - if (!PlatformCanRepresent(y)) continue; - float expected = expected_op(x, y); - if (!PlatformCanRepresent(expected)) continue; - r.Call(x, y); - for (int i = 0; i < 4; i++) { - float actual = ReadLittleEndianValue(&g[i]); - CheckFloatResult(x, y, expected, actual, true /* exact */); - } - } - } - - FOR_FLOAT32_NAN_INPUTS(i) { - float x = bit_cast(nan_test_array[i]); - if (!PlatformCanRepresent(x)) continue; - FOR_FLOAT32_NAN_INPUTS(j) { - float y = bit_cast(nan_test_array[j]); - if (!PlatformCanRepresent(y)) continue; - float expected = expected_op(x, y); - if (!PlatformCanRepresent(expected)) continue; - r.Call(x, y); - for (int i = 0; i < 4; i++) { - float actual = ReadLittleEndianValue(&g[i]); - CheckFloatResult(x, y, expected, actual, true /* exact */); - } - } - } -} - WASM_SIMD_TEST(F32x4Add) { RunF32x4BinOpTest(execution_tier, lower_simd, kExprF32x4Add, Add); } @@ -440,37 +409,6 @@ WASM_SIMD_TEST(F32x4Pmax) { RunF32x4BinOpTest(execution_tier, lower_simd, kExprF32x4Pmax, Maximum); } -void RunF32x4CompareOpTest(TestExecutionTier execution_tier, - LowerSimd lower_simd, WasmOpcode opcode, - FloatCompareOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Set up global to hold mask output. - int32_t* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test values, perform compare op, and write the result. - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(value2))), - WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_ONE); - - FOR_FLOAT32_INPUTS(x) { - if (!PlatformCanRepresent(x)) continue; - FOR_FLOAT32_INPUTS(y) { - if (!PlatformCanRepresent(y)) continue; - float diff = x - y; // Model comparison as subtraction. - if (!PlatformCanRepresent(diff)) continue; - r.Call(x, y); - int32_t expected = expected_op(x, y); - for (int i = 0; i < 4; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } - } -} - WASM_SIMD_TEST(F32x4Eq) { RunF32x4CompareOpTest(execution_tier, lower_simd, kExprF32x4Eq, Equal); } @@ -545,27 +483,6 @@ WASM_SIMD_TEST(I64x2ReplaceLane) { } } -void RunI64x2UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int64UnOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - int64_t* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test value, perform unop, and write the result. - byte value = 0; - byte temp1 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I64x2_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), - WASM_ONE); - - FOR_INT64_INPUTS(x) { - r.Call(x); - int64_t expected = expected_op(x); - for (int i = 0; i < 2; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } -} - WASM_SIMD_TEST(I64x2Neg) { RunI64x2UnOpTest(execution_tier, lower_simd, kExprI64x2Neg, base::NegateWithWraparound); @@ -575,38 +492,6 @@ WASM_SIMD_TEST(I64x2Abs) { RunI64x2UnOpTest(execution_tier, lower_simd, kExprI64x2Abs, std::abs); } -void RunI64x2ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int64ShiftOp expected_op) { - // Intentionally shift by 64, should be no-op. - for (int shift = 1; shift <= 64; shift++) { - WasmRunner r(execution_tier, lower_simd); - int32_t* memory = r.builder().AddMemoryElems(1); - int64_t* g_imm = r.builder().AddGlobal(kWasmS128); - int64_t* g_mem = r.builder().AddGlobal(kWasmS128); - byte value = 0; - byte simd = r.AllocateLocal(kWasmS128); - // Shift using an immediate, and shift using a value loaded from memory. - BUILD( - r, WASM_LOCAL_SET(simd, WASM_SIMD_I64x2_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_SHIFT_OP(opcode, WASM_LOCAL_GET(simd), - WASM_I32V(shift))), - WASM_GLOBAL_SET(1, WASM_SIMD_SHIFT_OP( - opcode, WASM_LOCAL_GET(simd), - WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))), - WASM_ONE); - - r.builder().WriteMemory(&memory[0], shift); - FOR_INT64_INPUTS(x) { - r.Call(x); - int64_t expected = expected_op(x, shift); - for (int i = 0; i < 2; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g_imm[i])); - CHECK_EQ(expected, ReadLittleEndianValue(&g_mem[i])); - } - } - } -} - WASM_SIMD_TEST(I64x2Shl) { RunI64x2ShiftOpTest(execution_tier, lower_simd, kExprI64x2Shl, LogicalShiftLeft); @@ -622,32 +507,6 @@ WASM_SIMD_TEST(I64x2ShrU) { LogicalShiftRight); } -void RunI64x2BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int64BinOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - int64_t* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test values, perform binop, and write the result. - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I64x2_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_I64x2_SPLAT(WASM_LOCAL_GET(value2))), - WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_ONE); - - FOR_INT64_INPUTS(x) { - FOR_INT64_INPUTS(y) { - r.Call(x, y); - int64_t expected = expected_op(x, y); - for (int i = 0; i < 2; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } - } -} - WASM_SIMD_TEST(I64x2Add) { RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Add, base::AddWithWraparound); @@ -768,50 +627,6 @@ WASM_SIMD_TEST(I64x2ExtractWithF64x2) { WASM_I64V(1), WASM_I64V(0))); CHECK_EQ(1, r.Call()); } -void RunF64x2UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, DoubleUnOp expected_op, - bool exact = true) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - double* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test value, perform unop, and write the result. - byte value = 0; - byte temp1 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), - WASM_ONE); - - FOR_FLOAT64_INPUTS(x) { - if (!PlatformCanRepresent(x)) continue; - // Extreme values have larger errors so skip them for approximation tests. - if (!exact && IsExtreme(x)) continue; - double expected = expected_op(x); -#if V8_OS_AIX - if (!MightReverseSign(expected_op)) - expected = FpOpWorkaround(x, expected); -#endif - if (!PlatformCanRepresent(expected)) continue; - r.Call(x); - for (int i = 0; i < 2; i++) { - double actual = ReadLittleEndianValue(&g[i]); - CheckDoubleResult(x, x, expected, actual, exact); - } - } - - FOR_FLOAT64_NAN_INPUTS(i) { - double x = bit_cast(double_nan_test_array[i]); - if (!PlatformCanRepresent(x)) continue; - // Extreme values have larger errors so skip them for approximation tests. - if (!exact && IsExtreme(x)) continue; - double expected = expected_op(x); - if (!PlatformCanRepresent(expected)) continue; - r.Call(x); - for (int i = 0; i < 2; i++) { - double actual = ReadLittleEndianValue(&g[i]); - CheckDoubleResult(x, x, expected, actual, exact); - } - } -} WASM_SIMD_TEST(F64x2Abs) { RunF64x2UnOpTest(execution_tier, lower_simd, kExprF64x2Abs, std::abs); @@ -954,51 +769,6 @@ WASM_SIMD_TEST(F64x2PromoteLowF32x4) { } } -void RunF64x2BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, DoubleBinOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - double* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test value, perform binop, and write the result. - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value2))), - WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_ONE); - - FOR_FLOAT64_INPUTS(x) { - if (!PlatformCanRepresent(x)) continue; - FOR_FLOAT64_INPUTS(y) { - if (!PlatformCanRepresent(x)) continue; - double expected = expected_op(x, y); - if (!PlatformCanRepresent(expected)) continue; - r.Call(x, y); - for (int i = 0; i < 2; i++) { - double actual = ReadLittleEndianValue(&g[i]); - CheckDoubleResult(x, y, expected, actual, true /* exact */); - } - } - } - - FOR_FLOAT64_NAN_INPUTS(i) { - double x = bit_cast(double_nan_test_array[i]); - if (!PlatformCanRepresent(x)) continue; - FOR_FLOAT64_NAN_INPUTS(j) { - double y = bit_cast(double_nan_test_array[j]); - double expected = expected_op(x, y); - if (!PlatformCanRepresent(expected)) continue; - r.Call(x, y); - for (int i = 0; i < 2; i++) { - double actual = ReadLittleEndianValue(&g[i]); - CheckDoubleResult(x, y, expected, actual, true /* exact */); - } - } - } -} - WASM_SIMD_TEST(F64x2Add) { RunF64x2BinOpTest(execution_tier, lower_simd, kExprF64x2Add, Add); } @@ -1023,42 +793,6 @@ WASM_SIMD_TEST(F64x2Pmax) { RunF64x2BinOpTest(execution_tier, lower_simd, kExprF64x2Pmax, Maximum); } -void RunF64x2CompareOpTest(TestExecutionTier execution_tier, - LowerSimd lower_simd, WasmOpcode opcode, - DoubleCompareOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Set up global to hold mask output. - int64_t* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test values, perform compare op, and write the result. - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - // Make the lanes of each temp compare differently: - // temp1 = y, x and temp2 = y, y. - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp1, - WASM_SIMD_F64x2_REPLACE_LANE(1, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(value2))), - WASM_LOCAL_SET(temp2, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value2))), - WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_ONE); - - FOR_FLOAT64_INPUTS(x) { - if (!PlatformCanRepresent(x)) continue; - FOR_FLOAT64_INPUTS(y) { - if (!PlatformCanRepresent(y)) continue; - double diff = x - y; // Model comparison as subtraction. - if (!PlatformCanRepresent(diff)) continue; - r.Call(x, y); - int64_t expected0 = expected_op(x, y); - int64_t expected1 = expected_op(y, y); - CHECK_EQ(expected0, ReadLittleEndianValue(&g[0])); - CHECK_EQ(expected1, ReadLittleEndianValue(&g[1])); - } - } -} - WASM_SIMD_TEST(F64x2Eq) { RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Eq, Equal); } @@ -1458,27 +1192,6 @@ WASM_SIMD_TEST(I64x2ConvertI32x4) { } } -void RunI32x4UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int32UnOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - int32_t* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test value, perform unop, and write the result. - byte value = 0; - byte temp1 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), - WASM_ONE); - - FOR_INT32_INPUTS(x) { - r.Call(x); - int32_t expected = expected_op(x); - for (int i = 0; i < 4; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } -} - WASM_SIMD_TEST(I32x4Neg) { RunI32x4UnOpTest(execution_tier, lower_simd, kExprI32x4Neg, base::NegateWithWraparound); @@ -1548,32 +1261,6 @@ WASM_SIMD_TEST(I16x8ExtAddPairwiseI8x16U) { kExprI8x16Splat, interleave_8x16_shuffle); } -void RunI32x4BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int32BinOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - int32_t* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test values, perform binop, and write the result. - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value2))), - WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_ONE); - - FOR_INT32_INPUTS(x) { - FOR_INT32_INPUTS(y) { - r.Call(x, y); - int32_t expected = expected_op(x, y); - for (int i = 0; i < 4; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } - } -} - WASM_SIMD_TEST(I32x4Add) { RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Add, base::AddWithWraparound); @@ -1670,38 +1357,6 @@ WASM_SIMD_TEST(I32x4GeU) { UnsignedGreaterEqual); } -void RunI32x4ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int32ShiftOp expected_op) { - // Intentionally shift by 32, should be no-op. - for (int shift = 1; shift <= 32; shift++) { - WasmRunner r(execution_tier, lower_simd); - int32_t* memory = r.builder().AddMemoryElems(1); - int32_t* g_imm = r.builder().AddGlobal(kWasmS128); - int32_t* g_mem = r.builder().AddGlobal(kWasmS128); - byte value = 0; - byte simd = r.AllocateLocal(kWasmS128); - // Shift using an immediate, and shift using a value loaded from memory. - BUILD( - r, WASM_LOCAL_SET(simd, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_SHIFT_OP(opcode, WASM_LOCAL_GET(simd), - WASM_I32V(shift))), - WASM_GLOBAL_SET(1, WASM_SIMD_SHIFT_OP( - opcode, WASM_LOCAL_GET(simd), - WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))), - WASM_ONE); - - r.builder().WriteMemory(&memory[0], shift); - FOR_INT32_INPUTS(x) { - r.Call(x); - int32_t expected = expected_op(x, shift); - for (int i = 0; i < 4; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g_imm[i])); - CHECK_EQ(expected, ReadLittleEndianValue(&g_mem[i])); - } - } - } -} - WASM_SIMD_TEST(I32x4Shl) { RunI32x4ShiftOpTest(execution_tier, lower_simd, kExprI32x4Shl, LogicalShiftLeft); @@ -1781,27 +1436,6 @@ WASM_SIMD_TEST(I16x8ConvertI32x4) { } } -void RunI16x8UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int16UnOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - int16_t* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test value, perform unop, and write the result. - byte value = 0; - byte temp1 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), - WASM_ONE); - - FOR_INT16_INPUTS(x) { - r.Call(x); - int16_t expected = expected_op(x); - for (int i = 0; i < 8; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } -} - WASM_SIMD_TEST(I16x8Neg) { RunI16x8UnOpTest(execution_tier, lower_simd, kExprI16x8Neg, base::NegateWithWraparound); @@ -1811,33 +1445,6 @@ WASM_SIMD_TEST(I16x8Abs) { RunI16x8UnOpTest(execution_tier, lower_simd, kExprI16x8Abs, Abs); } -template -void RunI16x8BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, OpType expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - T* g = r.builder().template AddGlobal(kWasmS128); - // Build fn to splat test values, perform binop, and write the result. - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value2))), - WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_ONE); - - for (T x : compiler::ValueHelper::GetVector()) { - for (T y : compiler::ValueHelper::GetVector()) { - r.Call(x, y); - T expected = expected_op(x, y); - for (int i = 0; i < 8; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } - } -} - WASM_SIMD_TEST(I16x8Add) { RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Add, base::AddWithWraparound); @@ -1872,13 +1479,13 @@ WASM_SIMD_TEST(I16x8MaxS) { } WASM_SIMD_TEST(I16x8AddSatU) { - RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8AddSatU, - SaturateAdd); + RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8AddSatU, + SaturateAdd); } WASM_SIMD_TEST(I16x8SubSatU) { - RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8SubSatU, - SaturateSub); + RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8SubSatU, + SaturateSub); } WASM_SIMD_TEST(I16x8MinU) { @@ -2079,38 +1686,6 @@ WASM_SIMD_TEST(I32x4DotI16x8S) { } } -void RunI16x8ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int16ShiftOp expected_op) { - // Intentionally shift by 16, should be no-op. - for (int shift = 1; shift <= 16; shift++) { - WasmRunner r(execution_tier, lower_simd); - int32_t* memory = r.builder().AddMemoryElems(1); - int16_t* g_imm = r.builder().AddGlobal(kWasmS128); - int16_t* g_mem = r.builder().AddGlobal(kWasmS128); - byte value = 0; - byte simd = r.AllocateLocal(kWasmS128); - // Shift using an immediate, and shift using a value loaded from memory. - BUILD( - r, WASM_LOCAL_SET(simd, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_SHIFT_OP(opcode, WASM_LOCAL_GET(simd), - WASM_I32V(shift))), - WASM_GLOBAL_SET(1, WASM_SIMD_SHIFT_OP( - opcode, WASM_LOCAL_GET(simd), - WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))), - WASM_ONE); - - r.builder().WriteMemory(&memory[0], shift); - FOR_INT16_INPUTS(x) { - r.Call(x); - int16_t expected = expected_op(x, shift); - for (int i = 0; i < 8; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g_imm[i])); - CHECK_EQ(expected, ReadLittleEndianValue(&g_mem[i])); - } - } - } -} - WASM_SIMD_TEST(I16x8Shl) { RunI16x8ShiftOpTest(execution_tier, lower_simd, kExprI16x8Shl, LogicalShiftLeft); @@ -2126,27 +1701,6 @@ WASM_SIMD_TEST(I16x8ShrU) { LogicalShiftRight); } -void RunI8x16UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int8UnOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - int8_t* g = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test value, perform unop, and write the result. - byte value = 0; - byte temp1 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), - WASM_ONE); - - FOR_INT8_INPUTS(x) { - r.Call(x); - int8_t expected = expected_op(x); - for (int i = 0; i < 16; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } -} - WASM_SIMD_TEST(I8x16Neg) { RunI8x16UnOpTest(execution_tier, lower_simd, kExprI8x16Neg, base::NegateWithWraparound); @@ -2206,33 +1760,6 @@ WASM_SIMD_TEST(I8x16ConvertI16x8) { } } -template -void RunI8x16BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, OpType expected_op) { - WasmRunner r(execution_tier, lower_simd); - // Global to hold output. - T* g = r.builder().template AddGlobal(kWasmS128); - // Build fn to splat test values, perform binop, and write the result. - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value2))), - WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_ONE); - - for (T x : compiler::ValueHelper::GetVector()) { - for (T y : compiler::ValueHelper::GetVector()) { - r.Call(x, y); - T expected = expected_op(x, y); - for (int i = 0; i < 16; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); - } - } - } -} - WASM_SIMD_TEST(I8x16Add) { RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Add, base::AddWithWraparound); @@ -2262,13 +1789,13 @@ WASM_SIMD_TEST(I8x16MaxS) { } WASM_SIMD_TEST(I8x16AddSatU) { - RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16AddSatU, - SaturateAdd); + RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16AddSatU, + SaturateAdd); } WASM_SIMD_TEST(I8x16SubSatU) { - RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16SubSatU, - SaturateSub); + RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16SubSatU, + SaturateSub); } WASM_SIMD_TEST(I8x16MinU) { @@ -2329,38 +1856,6 @@ WASM_SIMD_TEST(I8x16RoundingAverageU) { RoundingAverageUnsigned); } -void RunI8x16ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, - WasmOpcode opcode, Int8ShiftOp expected_op) { - // Intentionally shift by 8, should be no-op. - for (int shift = 1; shift <= 8; shift++) { - WasmRunner r(execution_tier, lower_simd); - int32_t* memory = r.builder().AddMemoryElems(1); - int8_t* g_imm = r.builder().AddGlobal(kWasmS128); - int8_t* g_mem = r.builder().AddGlobal(kWasmS128); - byte value = 0; - byte simd = r.AllocateLocal(kWasmS128); - // Shift using an immediate, and shift using a value loaded from memory. - BUILD( - r, WASM_LOCAL_SET(simd, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_SHIFT_OP(opcode, WASM_LOCAL_GET(simd), - WASM_I32V(shift))), - WASM_GLOBAL_SET(1, WASM_SIMD_SHIFT_OP( - opcode, WASM_LOCAL_GET(simd), - WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))), - WASM_ONE); - - r.builder().WriteMemory(&memory[0], shift); - FOR_INT8_INPUTS(x) { - r.Call(x); - int8_t expected = expected_op(x, shift); - for (int i = 0; i < 16; i++) { - CHECK_EQ(expected, ReadLittleEndianValue(&g_imm[i])); - CHECK_EQ(expected, ReadLittleEndianValue(&g_mem[i])); - } - } - } -} - WASM_SIMD_TEST(I8x16Shl) { RunI8x16ShiftOpTest(execution_tier, lower_simd, kExprI8x16Shl, LogicalShiftLeft); @@ -3824,28 +3319,6 @@ WASM_SIMD_TEST(S128ConstAllOnes) { RunSimdConstTest(execution_tier, lower_simd, expected); } -void RunI8x16MixedRelationalOpTest(TestExecutionTier execution_tier, - LowerSimd lower_simd, WasmOpcode opcode, - Int8BinOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - byte temp3 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value2))), - WASM_LOCAL_SET(temp3, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_SIMD_I8x16_EXTRACT_LANE(0, WASM_LOCAL_GET(temp3))); - - CHECK_EQ(expected_op(0xff, static_cast(0x7fff)), - r.Call(0xff, 0x7fff)); - CHECK_EQ(expected_op(0xfe, static_cast(0x7fff)), - r.Call(0xfe, 0x7fff)); - CHECK_EQ(expected_op(0xff, static_cast(0x7ffe)), - r.Call(0xff, 0x7ffe)); -} - WASM_SIMD_TEST(I8x16LeUMixed) { RunI8x16MixedRelationalOpTest(execution_tier, lower_simd, kExprI8x16LeU, UnsignedLessEqual); @@ -3863,28 +3336,6 @@ WASM_SIMD_TEST(I8x16GtUMixed) { UnsignedGreater); } -void RunI16x8MixedRelationalOpTest(TestExecutionTier execution_tier, - LowerSimd lower_simd, WasmOpcode opcode, - Int16BinOp expected_op) { - WasmRunner r(execution_tier, lower_simd); - byte value1 = 0, value2 = 1; - byte temp1 = r.AllocateLocal(kWasmS128); - byte temp2 = r.AllocateLocal(kWasmS128); - byte temp3 = r.AllocateLocal(kWasmS128); - BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value1))), - WASM_LOCAL_SET(temp2, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value2))), - WASM_LOCAL_SET(temp3, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), - WASM_LOCAL_GET(temp2))), - WASM_SIMD_I16x8_EXTRACT_LANE(0, WASM_LOCAL_GET(temp3))); - - CHECK_EQ(expected_op(0xffff, static_cast(0x7fffffff)), - r.Call(0xffff, 0x7fffffff)); - CHECK_EQ(expected_op(0xfeff, static_cast(0x7fffffff)), - r.Call(0xfeff, 0x7fffffff)); - CHECK_EQ(expected_op(0xffff, static_cast(0x7ffffeff)), - r.Call(0xffff, 0x7ffffeff)); -} - WASM_SIMD_TEST(I16x8LeUMixed) { RunI16x8MixedRelationalOpTest(execution_tier, lower_simd, kExprI16x8LeU, UnsignedLessEqual); diff --git a/test/cctest/wasm/wasm-simd-utils.cc b/test/cctest/wasm/wasm-simd-utils.cc index 718916904c..64a3e63aaa 100644 --- a/test/cctest/wasm/wasm-simd-utils.cc +++ b/test/cctest/wasm/wasm-simd-utils.cc @@ -20,6 +20,380 @@ namespace v8 { namespace internal { namespace wasm { +void RunI8x16UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int8UnOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + int8_t* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test value, perform unop, and write the result. + byte value = 0; + byte temp1 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), + WASM_ONE); + + FOR_INT8_INPUTS(x) { + r.Call(x); + int8_t expected = expected_op(x); + for (int i = 0; i < 16; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } +} + +template +void RunI8x16BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, OpType expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + T* g = r.builder().template AddGlobal(kWasmS128); + // Build fn to splat test values, perform binop, and write the result. + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value2))), + WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_ONE); + + for (T x : compiler::ValueHelper::GetVector()) { + for (T y : compiler::ValueHelper::GetVector()) { + r.Call(x, y); + T expected = expected_op(x, y); + for (int i = 0; i < 16; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } + } +} + +// Explicit instantiations of uses. +template void RunI8x16BinOpTest(TestExecutionTier, LowerSimd, + WasmOpcode, Int8BinOp); + +template void RunI8x16BinOpTest(TestExecutionTier, LowerSimd, + WasmOpcode, Uint8BinOp); + +void RunI8x16ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int8ShiftOp expected_op) { + // Intentionally shift by 8, should be no-op. + for (int shift = 1; shift <= 8; shift++) { + WasmRunner r(execution_tier, lower_simd); + int32_t* memory = r.builder().AddMemoryElems(1); + int8_t* g_imm = r.builder().AddGlobal(kWasmS128); + int8_t* g_mem = r.builder().AddGlobal(kWasmS128); + byte value = 0; + byte simd = r.AllocateLocal(kWasmS128); + // Shift using an immediate, and shift using a value loaded from memory. + BUILD( + r, WASM_LOCAL_SET(simd, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_SHIFT_OP(opcode, WASM_LOCAL_GET(simd), + WASM_I32V(shift))), + WASM_GLOBAL_SET(1, WASM_SIMD_SHIFT_OP( + opcode, WASM_LOCAL_GET(simd), + WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))), + WASM_ONE); + + r.builder().WriteMemory(&memory[0], shift); + FOR_INT8_INPUTS(x) { + r.Call(x); + int8_t expected = expected_op(x, shift); + for (int i = 0; i < 16; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g_imm[i])); + CHECK_EQ(expected, ReadLittleEndianValue(&g_mem[i])); + } + } + } +} + +void RunI8x16MixedRelationalOpTest(TestExecutionTier execution_tier, + LowerSimd lower_simd, WasmOpcode opcode, + Int8BinOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + byte temp3 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I8x16_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value2))), + WASM_LOCAL_SET(temp3, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_SIMD_I8x16_EXTRACT_LANE(0, WASM_LOCAL_GET(temp3))); + + CHECK_EQ(expected_op(0xff, static_cast(0x7fff)), + r.Call(0xff, 0x7fff)); + CHECK_EQ(expected_op(0xfe, static_cast(0x7fff)), + r.Call(0xfe, 0x7fff)); + CHECK_EQ(expected_op(0xff, static_cast(0x7ffe)), + r.Call(0xff, 0x7ffe)); +} + +void RunI16x8UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int16UnOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + int16_t* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test value, perform unop, and write the result. + byte value = 0; + byte temp1 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), + WASM_ONE); + + FOR_INT16_INPUTS(x) { + r.Call(x); + int16_t expected = expected_op(x); + for (int i = 0; i < 8; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } +} + +template +void RunI16x8BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, OpType expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + T* g = r.builder().template AddGlobal(kWasmS128); + // Build fn to splat test values, perform binop, and write the result. + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value2))), + WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_ONE); + + for (T x : compiler::ValueHelper::GetVector()) { + for (T y : compiler::ValueHelper::GetVector()) { + r.Call(x, y); + T expected = expected_op(x, y); + for (int i = 0; i < 8; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } + } +} + +// Explicit instantiations of uses. +template void RunI16x8BinOpTest(TestExecutionTier, LowerSimd, + WasmOpcode, Int16BinOp); +template void RunI16x8BinOpTest(TestExecutionTier, LowerSimd, + WasmOpcode, Uint16BinOp); + +void RunI16x8ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int16ShiftOp expected_op) { + // Intentionally shift by 16, should be no-op. + for (int shift = 1; shift <= 16; shift++) { + WasmRunner r(execution_tier, lower_simd); + int32_t* memory = r.builder().AddMemoryElems(1); + int16_t* g_imm = r.builder().AddGlobal(kWasmS128); + int16_t* g_mem = r.builder().AddGlobal(kWasmS128); + byte value = 0; + byte simd = r.AllocateLocal(kWasmS128); + // Shift using an immediate, and shift using a value loaded from memory. + BUILD( + r, WASM_LOCAL_SET(simd, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_SHIFT_OP(opcode, WASM_LOCAL_GET(simd), + WASM_I32V(shift))), + WASM_GLOBAL_SET(1, WASM_SIMD_SHIFT_OP( + opcode, WASM_LOCAL_GET(simd), + WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))), + WASM_ONE); + + r.builder().WriteMemory(&memory[0], shift); + FOR_INT16_INPUTS(x) { + r.Call(x); + int16_t expected = expected_op(x, shift); + for (int i = 0; i < 8; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g_imm[i])); + CHECK_EQ(expected, ReadLittleEndianValue(&g_mem[i])); + } + } + } +} + +void RunI16x8MixedRelationalOpTest(TestExecutionTier execution_tier, + LowerSimd lower_simd, WasmOpcode opcode, + Int16BinOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + byte temp3 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value2))), + WASM_LOCAL_SET(temp3, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_SIMD_I16x8_EXTRACT_LANE(0, WASM_LOCAL_GET(temp3))); + + CHECK_EQ(expected_op(0xffff, static_cast(0x7fffffff)), + r.Call(0xffff, 0x7fffffff)); + CHECK_EQ(expected_op(0xfeff, static_cast(0x7fffffff)), + r.Call(0xfeff, 0x7fffffff)); + CHECK_EQ(expected_op(0xffff, static_cast(0x7ffffeff)), + r.Call(0xffff, 0x7ffffeff)); +} + +void RunI32x4UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int32UnOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + int32_t* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test value, perform unop, and write the result. + byte value = 0; + byte temp1 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), + WASM_ONE); + + FOR_INT32_INPUTS(x) { + r.Call(x); + int32_t expected = expected_op(x); + for (int i = 0; i < 4; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } +} + +void RunI32x4BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int32BinOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + int32_t* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test values, perform binop, and write the result. + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value2))), + WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_ONE); + + FOR_INT32_INPUTS(x) { + FOR_INT32_INPUTS(y) { + r.Call(x, y); + int32_t expected = expected_op(x, y); + for (int i = 0; i < 4; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } + } +} + +void RunI32x4ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int32ShiftOp expected_op) { + // Intentionally shift by 32, should be no-op. + for (int shift = 1; shift <= 32; shift++) { + WasmRunner r(execution_tier, lower_simd); + int32_t* memory = r.builder().AddMemoryElems(1); + int32_t* g_imm = r.builder().AddGlobal(kWasmS128); + int32_t* g_mem = r.builder().AddGlobal(kWasmS128); + byte value = 0; + byte simd = r.AllocateLocal(kWasmS128); + // Shift using an immediate, and shift using a value loaded from memory. + BUILD( + r, WASM_LOCAL_SET(simd, WASM_SIMD_I32x4_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_SHIFT_OP(opcode, WASM_LOCAL_GET(simd), + WASM_I32V(shift))), + WASM_GLOBAL_SET(1, WASM_SIMD_SHIFT_OP( + opcode, WASM_LOCAL_GET(simd), + WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))), + WASM_ONE); + + r.builder().WriteMemory(&memory[0], shift); + FOR_INT32_INPUTS(x) { + r.Call(x); + int32_t expected = expected_op(x, shift); + for (int i = 0; i < 4; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g_imm[i])); + CHECK_EQ(expected, ReadLittleEndianValue(&g_mem[i])); + } + } + } +} + +void RunI64x2UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int64UnOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + int64_t* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test value, perform unop, and write the result. + byte value = 0; + byte temp1 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I64x2_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), + WASM_ONE); + + FOR_INT64_INPUTS(x) { + r.Call(x); + int64_t expected = expected_op(x); + for (int i = 0; i < 2; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } +} + +void RunI64x2BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int64BinOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + int64_t* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test values, perform binop, and write the result. + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_I64x2_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_I64x2_SPLAT(WASM_LOCAL_GET(value2))), + WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_ONE); + + FOR_INT64_INPUTS(x) { + FOR_INT64_INPUTS(y) { + r.Call(x, y); + int64_t expected = expected_op(x, y); + for (int i = 0; i < 2; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } + } +} + +void RunI64x2ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int64ShiftOp expected_op) { + // Intentionally shift by 64, should be no-op. + for (int shift = 1; shift <= 64; shift++) { + WasmRunner r(execution_tier, lower_simd); + int32_t* memory = r.builder().AddMemoryElems(1); + int64_t* g_imm = r.builder().AddGlobal(kWasmS128); + int64_t* g_mem = r.builder().AddGlobal(kWasmS128); + byte value = 0; + byte simd = r.AllocateLocal(kWasmS128); + // Shift using an immediate, and shift using a value loaded from memory. + BUILD( + r, WASM_LOCAL_SET(simd, WASM_SIMD_I64x2_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_SHIFT_OP(opcode, WASM_LOCAL_GET(simd), + WASM_I32V(shift))), + WASM_GLOBAL_SET(1, WASM_SIMD_SHIFT_OP( + opcode, WASM_LOCAL_GET(simd), + WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))), + WASM_ONE); + + r.builder().WriteMemory(&memory[0], shift); + FOR_INT64_INPUTS(x) { + r.Call(x); + int64_t expected = expected_op(x, shift); + for (int i = 0; i < 2; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g_imm[i])); + CHECK_EQ(expected, ReadLittleEndianValue(&g_mem[i])); + } + } + } +} bool IsExtreme(float x) { float abs_x = std::fabs(x); @@ -118,6 +492,83 @@ void RunF32x4UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, } } +void RunF32x4BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, FloatBinOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + float* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test values, perform binop, and write the result. + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(value2))), + WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_ONE); + + FOR_FLOAT32_INPUTS(x) { + if (!PlatformCanRepresent(x)) continue; + FOR_FLOAT32_INPUTS(y) { + if (!PlatformCanRepresent(y)) continue; + float expected = expected_op(x, y); + if (!PlatformCanRepresent(expected)) continue; + r.Call(x, y); + for (int i = 0; i < 4; i++) { + float actual = ReadLittleEndianValue(&g[i]); + CheckFloatResult(x, y, expected, actual, true /* exact */); + } + } + } + + FOR_FLOAT32_NAN_INPUTS(i) { + float x = bit_cast(nan_test_array[i]); + if (!PlatformCanRepresent(x)) continue; + FOR_FLOAT32_NAN_INPUTS(j) { + float y = bit_cast(nan_test_array[j]); + if (!PlatformCanRepresent(y)) continue; + float expected = expected_op(x, y); + if (!PlatformCanRepresent(expected)) continue; + r.Call(x, y); + for (int i = 0; i < 4; i++) { + float actual = ReadLittleEndianValue(&g[i]); + CheckFloatResult(x, y, expected, actual, true /* exact */); + } + } + } +} + +void RunF32x4CompareOpTest(TestExecutionTier execution_tier, + LowerSimd lower_simd, WasmOpcode opcode, + FloatCompareOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Set up global to hold mask output. + int32_t* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test values, perform compare op, and write the result. + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(value2))), + WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_ONE); + + FOR_FLOAT32_INPUTS(x) { + if (!PlatformCanRepresent(x)) continue; + FOR_FLOAT32_INPUTS(y) { + if (!PlatformCanRepresent(y)) continue; + float diff = x - y; // Model comparison as subtraction. + if (!PlatformCanRepresent(diff)) continue; + r.Call(x, y); + int32_t expected = expected_op(x, y); + for (int i = 0; i < 4; i++) { + CHECK_EQ(expected, ReadLittleEndianValue(&g[i])); + } + } + } +} + bool IsExtreme(double x) { double abs_x = std::fabs(x); const double kSmallFloatThreshold = 1.0e-298; @@ -171,6 +622,131 @@ void CheckDoubleResult(double x, double y, double expected, double actual, } } +void RunF64x2UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, DoubleUnOp expected_op, bool exact) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + double* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test value, perform unop, and write the result. + byte value = 0; + byte temp1 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(opcode, WASM_LOCAL_GET(temp1))), + WASM_ONE); + + FOR_FLOAT64_INPUTS(x) { + if (!PlatformCanRepresent(x)) continue; + // Extreme values have larger errors so skip them for approximation tests. + if (!exact && IsExtreme(x)) continue; + double expected = expected_op(x); +#if V8_OS_AIX + if (!MightReverseSign(expected_op)) + expected = FpOpWorkaround(x, expected); +#endif + if (!PlatformCanRepresent(expected)) continue; + r.Call(x); + for (int i = 0; i < 2; i++) { + double actual = ReadLittleEndianValue(&g[i]); + CheckDoubleResult(x, x, expected, actual, exact); + } + } + + FOR_FLOAT64_NAN_INPUTS(i) { + double x = bit_cast(double_nan_test_array[i]); + if (!PlatformCanRepresent(x)) continue; + // Extreme values have larger errors so skip them for approximation tests. + if (!exact && IsExtreme(x)) continue; + double expected = expected_op(x); + if (!PlatformCanRepresent(expected)) continue; + r.Call(x); + for (int i = 0; i < 2; i++) { + double actual = ReadLittleEndianValue(&g[i]); + CheckDoubleResult(x, x, expected, actual, exact); + } + } +} + +void RunF64x2BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, DoubleBinOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Global to hold output. + double* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test value, perform binop, and write the result. + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp2, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value2))), + WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_ONE); + + FOR_FLOAT64_INPUTS(x) { + if (!PlatformCanRepresent(x)) continue; + FOR_FLOAT64_INPUTS(y) { + if (!PlatformCanRepresent(x)) continue; + double expected = expected_op(x, y); + if (!PlatformCanRepresent(expected)) continue; + r.Call(x, y); + for (int i = 0; i < 2; i++) { + double actual = ReadLittleEndianValue(&g[i]); + CheckDoubleResult(x, y, expected, actual, true /* exact */); + } + } + } + + FOR_FLOAT64_NAN_INPUTS(i) { + double x = bit_cast(double_nan_test_array[i]); + if (!PlatformCanRepresent(x)) continue; + FOR_FLOAT64_NAN_INPUTS(j) { + double y = bit_cast(double_nan_test_array[j]); + double expected = expected_op(x, y); + if (!PlatformCanRepresent(expected)) continue; + r.Call(x, y); + for (int i = 0; i < 2; i++) { + double actual = ReadLittleEndianValue(&g[i]); + CheckDoubleResult(x, y, expected, actual, true /* exact */); + } + } + } +} + +void RunF64x2CompareOpTest(TestExecutionTier execution_tier, + LowerSimd lower_simd, WasmOpcode opcode, + DoubleCompareOp expected_op) { + WasmRunner r(execution_tier, lower_simd); + // Set up global to hold mask output. + int64_t* g = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test values, perform compare op, and write the result. + byte value1 = 0, value2 = 1; + byte temp1 = r.AllocateLocal(kWasmS128); + byte temp2 = r.AllocateLocal(kWasmS128); + // Make the lanes of each temp compare differently: + // temp1 = y, x and temp2 = y, y. + BUILD(r, WASM_LOCAL_SET(temp1, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value1))), + WASM_LOCAL_SET(temp1, + WASM_SIMD_F64x2_REPLACE_LANE(1, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(value2))), + WASM_LOCAL_SET(temp2, WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(value2))), + WASM_GLOBAL_SET(0, WASM_SIMD_BINOP(opcode, WASM_LOCAL_GET(temp1), + WASM_LOCAL_GET(temp2))), + WASM_ONE); + + FOR_FLOAT64_INPUTS(x) { + if (!PlatformCanRepresent(x)) continue; + FOR_FLOAT64_INPUTS(y) { + if (!PlatformCanRepresent(y)) continue; + double diff = x - y; // Model comparison as subtraction. + if (!PlatformCanRepresent(diff)) continue; + r.Call(x, y); + int64_t expected0 = expected_op(x, y); + int64_t expected1 = expected_op(y, y); + CHECK_EQ(expected0, ReadLittleEndianValue(&g[0])); + CHECK_EQ(expected1, ReadLittleEndianValue(&g[1])); + } + } +} + } // namespace wasm } // namespace internal } // namespace v8 diff --git a/test/cctest/wasm/wasm-simd-utils.h b/test/cctest/wasm/wasm-simd-utils.h index 6f6c9efbec..157731df27 100644 --- a/test/cctest/wasm/wasm-simd-utils.h +++ b/test/cctest/wasm/wasm-simd-utils.h @@ -9,12 +9,72 @@ #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, LowerSimd lower_simd, + WasmOpcode opcode, Int8UnOp expected_op); + +template +void RunI8x16BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, OpType expected_op); + +void RunI8x16ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int8ShiftOp expected_op); +void RunI8x16MixedRelationalOpTest(TestExecutionTier execution_tier, + LowerSimd lower_simd, WasmOpcode opcode, + Int8BinOp expected_op); + +void RunI16x8UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int16UnOp expected_op); +template +void RunI16x8BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, OpType expected_op); +void RunI16x8ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int16ShiftOp expected_op); +void RunI16x8MixedRelationalOpTest(TestExecutionTier execution_tier, + LowerSimd lower_simd, WasmOpcode opcode, + Int16BinOp expected_op); + +void RunI32x4UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int32UnOp expected_op); +void RunI32x4BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int32BinOp expected_op); +void RunI32x4ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int32ShiftOp expected_op); + +void RunI64x2UnOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int64UnOp expected_op); +void RunI64x2BinOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int64BinOp expected_op); +void RunI64x2ShiftOpTest(TestExecutionTier execution_tier, LowerSimd lower_simd, + WasmOpcode opcode, Int64ShiftOp expected_op); // Generic expected value functions. template