OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/assembler-inl.h" | 5 #include "test/cctest/wasm/test-wasm-simd-common.h" |
6 #include "src/wasm/wasm-macro-gen.h" | |
7 #include "test/cctest/cctest.h" | |
8 #include "test/cctest/compiler/value-helper.h" | |
9 #include "test/cctest/wasm/wasm-run-utils.h" | |
10 | 6 |
11 using namespace v8::base; | 7 using namespace v8::base; |
12 using namespace v8::internal; | 8 using namespace v8::internal; |
13 using namespace v8::internal::compiler; | 9 using namespace v8::internal::compiler; |
14 using namespace v8::internal::wasm; | 10 using namespace v8::internal::wasm; |
15 | 11 |
16 namespace { | 12 namespace test_wasm_simd_common { |
17 | |
18 typedef float (*FloatUnOp)(float); | |
19 typedef float (*FloatBinOp)(float, float); | |
20 typedef int32_t (*FloatCompareOp)(float, float); | |
21 typedef int32_t (*Int32UnOp)(int32_t); | |
22 typedef int32_t (*Int32BinOp)(int32_t, int32_t); | |
23 typedef int32_t (*Int32ShiftOp)(int32_t, int); | |
24 typedef int16_t (*Int16UnOp)(int16_t); | |
25 typedef int16_t (*Int16BinOp)(int16_t, int16_t); | |
26 typedef int16_t (*Int16ShiftOp)(int16_t, int); | |
27 typedef int8_t (*Int8UnOp)(int8_t); | |
28 typedef int8_t (*Int8BinOp)(int8_t, int8_t); | |
29 typedef int8_t (*Int8ShiftOp)(int8_t, int); | |
30 | 13 |
31 #if V8_TARGET_ARCH_ARM | 14 #if V8_TARGET_ARCH_ARM |
| 15 namespace { |
32 // Floating point specific value functions, only used by ARM so far. | 16 // Floating point specific value functions, only used by ARM so far. |
33 int32_t Equal(float a, float b) { return a == b ? 1 : 0; } | 17 int32_t Equal(float a, float b) { return a == b ? 1 : 0; } |
34 | 18 |
35 int32_t NotEqual(float a, float b) { return a != b ? 1 : 0; } | 19 int32_t NotEqual(float a, float b) { return a != b ? 1 : 0; } |
36 #endif // V8_TARGET_ARCH_ARM | |
37 | |
38 // Generic expected value functions. | |
39 template <typename T> | |
40 T Negate(T a) { | |
41 return -a; | |
42 } | 20 } |
43 | 21 |
44 template <typename T> | 22 WASM_EXEC_TEST(F32x4Splat) { RunF32x4SplatTest(); } |
45 T Add(T a, T b) { | |
46 return a + b; | |
47 } | |
48 | 23 |
49 template <typename T> | 24 WASM_EXEC_TEST(F32x4ReplaceLane) { RunF32x4ReplaceLaneTest(); } |
50 T Sub(T a, T b) { | |
51 return a - b; | |
52 } | |
53 | |
54 template <typename T> | |
55 T Mul(T a, T b) { | |
56 return a * b; | |
57 } | |
58 | |
59 template <typename T> | |
60 T Minimum(T a, T b) { | |
61 return a <= b ? a : b; | |
62 } | |
63 | |
64 template <typename T> | |
65 T Maximum(T a, T b) { | |
66 return a >= b ? a : b; | |
67 } | |
68 | |
69 template <typename T> | |
70 T UnsignedMinimum(T a, T b) { | |
71 using UnsignedT = typename std::make_unsigned<T>::type; | |
72 return static_cast<UnsignedT>(a) <= static_cast<UnsignedT>(b) ? a : b; | |
73 } | |
74 | |
75 template <typename T> | |
76 T UnsignedMaximum(T a, T b) { | |
77 using UnsignedT = typename std::make_unsigned<T>::type; | |
78 return static_cast<UnsignedT>(a) >= static_cast<UnsignedT>(b) ? a : b; | |
79 } | |
80 | |
81 template <typename T> | |
82 T Equal(T a, T b) { | |
83 return a == b ? 1 : 0; | |
84 } | |
85 | |
86 template <typename T> | |
87 T NotEqual(T a, T b) { | |
88 return a != b ? 1 : 0; | |
89 } | |
90 | |
91 template <typename T> | |
92 T Greater(T a, T b) { | |
93 return a > b ? 1 : 0; | |
94 } | |
95 | |
96 template <typename T> | |
97 T GreaterEqual(T a, T b) { | |
98 return a >= b ? 1 : 0; | |
99 } | |
100 | |
101 template <typename T> | |
102 T Less(T a, T b) { | |
103 return a < b ? 1 : 0; | |
104 } | |
105 | |
106 template <typename T> | |
107 T LessEqual(T a, T b) { | |
108 return a <= b ? 1 : 0; | |
109 } | |
110 | |
111 template <typename T> | |
112 T UnsignedGreater(T a, T b) { | |
113 using UnsignedT = typename std::make_unsigned<T>::type; | |
114 return static_cast<UnsignedT>(a) > static_cast<UnsignedT>(b) ? 1 : 0; | |
115 } | |
116 | |
117 template <typename T> | |
118 T UnsignedGreaterEqual(T a, T b) { | |
119 using UnsignedT = typename std::make_unsigned<T>::type; | |
120 return static_cast<UnsignedT>(a) >= static_cast<UnsignedT>(b) ? 1 : 0; | |
121 } | |
122 | |
123 template <typename T> | |
124 T UnsignedLess(T a, T b) { | |
125 using UnsignedT = typename std::make_unsigned<T>::type; | |
126 return static_cast<UnsignedT>(a) < static_cast<UnsignedT>(b) ? 1 : 0; | |
127 } | |
128 | |
129 template <typename T> | |
130 T UnsignedLessEqual(T a, T b) { | |
131 using UnsignedT = typename std::make_unsigned<T>::type; | |
132 return static_cast<UnsignedT>(a) <= static_cast<UnsignedT>(b) ? 1 : 0; | |
133 } | |
134 | |
135 template <typename T> | |
136 T LogicalShiftLeft(T a, int shift) { | |
137 return a << shift; | |
138 } | |
139 | |
140 template <typename T> | |
141 T LogicalShiftRight(T a, int shift) { | |
142 using UnsignedT = typename std::make_unsigned<T>::type; | |
143 return static_cast<UnsignedT>(a) >> shift; | |
144 } | |
145 | |
146 template <typename T> | |
147 int64_t Widen(T value) { | |
148 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller"); | |
149 return static_cast<int64_t>(value); | |
150 } | |
151 | |
152 template <typename T> | |
153 int64_t UnsignedWiden(T value) { | |
154 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller"); | |
155 using UnsignedT = typename std::make_unsigned<T>::type; | |
156 return static_cast<int64_t>(static_cast<UnsignedT>(value)); | |
157 } | |
158 | |
159 template <typename T> | |
160 T Clamp(int64_t value) { | |
161 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller"); | |
162 int64_t min = static_cast<int64_t>(std::numeric_limits<T>::min()); | |
163 int64_t max = static_cast<int64_t>(std::numeric_limits<T>::max()); | |
164 int64_t clamped = std::max(min, std::min(max, value)); | |
165 return static_cast<T>(clamped); | |
166 } | |
167 | |
168 template <typename T> | |
169 T AddSaturate(T a, T b) { | |
170 return Clamp<T>(Widen(a) + Widen(b)); | |
171 } | |
172 | |
173 template <typename T> | |
174 T SubSaturate(T a, T b) { | |
175 return Clamp<T>(Widen(a) - Widen(b)); | |
176 } | |
177 | |
178 template <typename T> | |
179 T UnsignedAddSaturate(T a, T b) { | |
180 using UnsignedT = typename std::make_unsigned<T>::type; | |
181 return Clamp<UnsignedT>(UnsignedWiden(a) + UnsignedWiden(b)); | |
182 } | |
183 | |
184 template <typename T> | |
185 T UnsignedSubSaturate(T a, T b) { | |
186 using UnsignedT = typename std::make_unsigned<T>::type; | |
187 return Clamp<UnsignedT>(UnsignedWiden(a) - UnsignedWiden(b)); | |
188 } | |
189 | |
190 template <typename T> | |
191 T And(T a, T b) { | |
192 return a & b; | |
193 } | |
194 | |
195 template <typename T> | |
196 T Or(T a, T b) { | |
197 return a | b; | |
198 } | |
199 | |
200 template <typename T> | |
201 T Xor(T a, T b) { | |
202 return a ^ b; | |
203 } | |
204 | |
205 template <typename T> | |
206 T Not(T a) { | |
207 return ~a; | |
208 } | |
209 | |
210 } // namespace | |
211 | |
212 // TODO(gdeepti): These are tests using sample values to verify functional | |
213 // correctness of opcodes, add more tests for a range of values and macroize | |
214 // tests. | |
215 | |
216 // TODO(bbudge) Figure out how to compare floats in Wasm code that can handle | |
217 // NaNs. For now, our tests avoid using NaNs. | |
218 #define WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lane_value, lane_index) \ | |
219 WASM_IF(WASM_##LANE_TYPE##_NE(WASM_GET_LOCAL(lane_value), \ | |
220 WASM_SIMD_##TYPE##_EXTRACT_LANE( \ | |
221 lane_index, WASM_GET_LOCAL(value))), \ | |
222 WASM_RETURN1(WASM_ZERO)) | |
223 | |
224 #define WASM_SIMD_CHECK4(TYPE, value, LANE_TYPE, lv0, lv1, lv2, lv3) \ | |
225 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv0, 0) \ | |
226 , WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv1, 1), \ | |
227 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv2, 2), \ | |
228 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv3, 3) | |
229 | |
230 #define WASM_SIMD_CHECK_SPLAT4(TYPE, value, LANE_TYPE, lv) \ | |
231 WASM_SIMD_CHECK4(TYPE, value, LANE_TYPE, lv, lv, lv, lv) | |
232 | |
233 #define WASM_SIMD_CHECK8(TYPE, value, LANE_TYPE, lv0, lv1, lv2, lv3, lv4, lv5, \ | |
234 lv6, lv7) \ | |
235 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv0, 0) \ | |
236 , WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv1, 1), \ | |
237 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv2, 2), \ | |
238 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv3, 3), \ | |
239 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv4, 4), \ | |
240 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv5, 5), \ | |
241 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv6, 6), \ | |
242 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv7, 7) | |
243 | |
244 #define WASM_SIMD_CHECK_SPLAT8(TYPE, value, LANE_TYPE, lv) \ | |
245 WASM_SIMD_CHECK8(TYPE, value, LANE_TYPE, lv, lv, lv, lv, lv, lv, lv, lv) | |
246 | |
247 #define WASM_SIMD_CHECK16(TYPE, value, LANE_TYPE, lv0, lv1, lv2, lv3, lv4, \ | |
248 lv5, lv6, lv7, lv8, lv9, lv10, lv11, lv12, lv13, \ | |
249 lv14, lv15) \ | |
250 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv0, 0) \ | |
251 , WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv1, 1), \ | |
252 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv2, 2), \ | |
253 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv3, 3), \ | |
254 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv4, 4), \ | |
255 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv5, 5), \ | |
256 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv6, 6), \ | |
257 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv7, 7), \ | |
258 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv8, 8), \ | |
259 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv9, 9), \ | |
260 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv10, 10), \ | |
261 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv11, 11), \ | |
262 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv12, 12), \ | |
263 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv13, 13), \ | |
264 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv14, 14), \ | |
265 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv15, 15) | |
266 | |
267 #define WASM_SIMD_CHECK_SPLAT16(TYPE, value, LANE_TYPE, lv) \ | |
268 WASM_SIMD_CHECK16(TYPE, value, LANE_TYPE, lv, lv, lv, lv, lv, lv, lv, lv, \ | |
269 lv, lv, lv, lv, lv, lv, lv, lv) | |
270 | |
271 #define WASM_SIMD_CHECK_F32_LANE(TYPE, value, lane_value, lane_index) \ | |
272 WASM_IF( \ | |
273 WASM_I32_NE(WASM_I32_REINTERPRET_F32(WASM_GET_LOCAL(lane_value)), \ | |
274 WASM_I32_REINTERPRET_F32(WASM_SIMD_##TYPE##_EXTRACT_LANE( \ | |
275 lane_index, WASM_GET_LOCAL(value)))), \ | |
276 WASM_RETURN1(WASM_ZERO)) | |
277 | |
278 #define WASM_SIMD_CHECK4_F32(TYPE, value, lv0, lv1, lv2, lv3) \ | |
279 WASM_SIMD_CHECK_F32_LANE(TYPE, value, lv0, 0) \ | |
280 , WASM_SIMD_CHECK_F32_LANE(TYPE, value, lv1, 1), \ | |
281 WASM_SIMD_CHECK_F32_LANE(TYPE, value, lv2, 2), \ | |
282 WASM_SIMD_CHECK_F32_LANE(TYPE, value, lv3, 3) | |
283 | |
284 #define WASM_SIMD_CHECK_SPLAT4_F32(TYPE, value, lv) \ | |
285 WASM_SIMD_CHECK4_F32(TYPE, value, lv, lv, lv, lv) | |
286 | |
287 #define TO_BYTE(val) static_cast<byte>(val) | |
288 #define WASM_SIMD_OP(op) kSimdPrefix, TO_BYTE(op) | |
289 #define WASM_SIMD_SPLAT(Type, x) x, WASM_SIMD_OP(kExpr##Type##Splat) | |
290 #define WASM_SIMD_UNOP(op, x) x, WASM_SIMD_OP(op) | |
291 #define WASM_SIMD_BINOP(op, x, y) x, y, WASM_SIMD_OP(op) | |
292 #define WASM_SIMD_SHIFT_OP(op, shift, x) x, WASM_SIMD_OP(op), TO_BYTE(shift) | |
293 #define WASM_SIMD_SELECT(format, x, y, z) \ | |
294 x, y, z, WASM_SIMD_OP(kExprS##format##Select) | |
295 // Since boolean vectors can't be checked directly, materialize them into | |
296 // integer vectors using a Select operation. | |
297 #define WASM_SIMD_MATERIALIZE_BOOLS(format, x) \ | |
298 x, WASM_SIMD_I##format##_SPLAT(WASM_ONE), \ | |
299 WASM_SIMD_I##format##_SPLAT(WASM_ZERO), \ | |
300 WASM_SIMD_OP(kExprS##format##Select) | |
301 | |
302 #define WASM_SIMD_I16x8_SPLAT(x) x, WASM_SIMD_OP(kExprI16x8Splat) | |
303 #define WASM_SIMD_I16x8_EXTRACT_LANE(lane, x) \ | |
304 x, WASM_SIMD_OP(kExprI16x8ExtractLane), TO_BYTE(lane) | |
305 #define WASM_SIMD_I16x8_REPLACE_LANE(lane, x, y) \ | |
306 x, y, WASM_SIMD_OP(kExprI16x8ReplaceLane), TO_BYTE(lane) | |
307 #define WASM_SIMD_I8x16_SPLAT(x) x, WASM_SIMD_OP(kExprI8x16Splat) | |
308 #define WASM_SIMD_I8x16_EXTRACT_LANE(lane, x) \ | |
309 x, WASM_SIMD_OP(kExprI8x16ExtractLane), TO_BYTE(lane) | |
310 #define WASM_SIMD_I8x16_REPLACE_LANE(lane, x, y) \ | |
311 x, y, WASM_SIMD_OP(kExprI8x16ReplaceLane), TO_BYTE(lane) | |
312 | |
313 #define WASM_SIMD_F32x4_FROM_I32x4(x) x, WASM_SIMD_OP(kExprF32x4SConvertI32x4) | |
314 #define WASM_SIMD_F32x4_FROM_U32x4(x) x, WASM_SIMD_OP(kExprF32x4UConvertI32x4) | |
315 #define WASM_SIMD_I32x4_FROM_F32x4(x) x, WASM_SIMD_OP(kExprI32x4SConvertF32x4) | |
316 #define WASM_SIMD_U32x4_FROM_F32x4(x) x, WASM_SIMD_OP(kExprI32x4UConvertF32x4) | |
317 | |
318 #if V8_TARGET_ARCH_ARM | |
319 WASM_EXEC_TEST(F32x4Splat) { | |
320 FLAG_wasm_simd_prototype = true; | |
321 | |
322 WasmRunner<int32_t, float> r(kExecuteCompiled); | |
323 byte lane_val = 0; | |
324 byte simd = r.AllocateLocal(kWasmS128); | |
325 BUILD(r, | |
326 WASM_SET_LOCAL(simd, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(lane_val))), | |
327 WASM_SIMD_CHECK_SPLAT4_F32(F32x4, simd, lane_val), WASM_ONE); | |
328 | |
329 FOR_FLOAT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i)); } | |
330 } | |
331 | |
332 WASM_EXEC_TEST(F32x4ReplaceLane) { | |
333 FLAG_wasm_simd_prototype = true; | |
334 WasmRunner<int32_t, float, float> r(kExecuteCompiled); | |
335 byte old_val = 0; | |
336 byte new_val = 1; | |
337 byte simd = r.AllocateLocal(kWasmS128); | |
338 BUILD(r, WASM_SET_LOCAL(simd, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(old_val))), | |
339 WASM_SET_LOCAL(simd, | |
340 WASM_SIMD_F32x4_REPLACE_LANE(0, WASM_GET_LOCAL(simd), | |
341 WASM_GET_LOCAL(new_val))), | |
342 WASM_SIMD_CHECK4(F32x4, simd, F32, new_val, old_val, old_val, old_val), | |
343 WASM_SET_LOCAL(simd, | |
344 WASM_SIMD_F32x4_REPLACE_LANE(1, WASM_GET_LOCAL(simd), | |
345 WASM_GET_LOCAL(new_val))), | |
346 WASM_SIMD_CHECK4(F32x4, simd, F32, new_val, new_val, old_val, old_val), | |
347 WASM_SET_LOCAL(simd, | |
348 WASM_SIMD_F32x4_REPLACE_LANE(2, WASM_GET_LOCAL(simd), | |
349 WASM_GET_LOCAL(new_val))), | |
350 WASM_SIMD_CHECK4(F32x4, simd, F32, new_val, new_val, new_val, old_val), | |
351 WASM_SET_LOCAL(simd, | |
352 WASM_SIMD_F32x4_REPLACE_LANE(3, WASM_GET_LOCAL(simd), | |
353 WASM_GET_LOCAL(new_val))), | |
354 WASM_SIMD_CHECK_SPLAT4(F32x4, simd, F32, new_val), WASM_ONE); | |
355 | |
356 CHECK_EQ(1, r.Call(3.14159, -1.5)); | |
357 } | |
358 | 25 |
359 // Tests both signed and unsigned conversion. | 26 // Tests both signed and unsigned conversion. |
360 WASM_EXEC_TEST(F32x4FromInt32x4) { | 27 WASM_EXEC_TEST(F32x4FromInt32x4) { |
361 FLAG_wasm_simd_prototype = true; | 28 FLAG_wasm_simd_prototype = true; |
362 WasmRunner<int32_t, int32_t, float, float> r(kExecuteCompiled); | 29 WasmRunner<int32_t, int32_t, float, float> r(kExecuteCompiled); |
363 byte a = 0; | 30 byte a = 0; |
364 byte expected_signed = 1; | 31 byte expected_signed = 1; |
365 byte expected_unsigned = 2; | 32 byte expected_unsigned = 2; |
366 byte simd0 = r.AllocateLocal(kWasmS128); | 33 byte simd0 = r.AllocateLocal(kWasmS128); |
367 byte simd1 = r.AllocateLocal(kWasmS128); | 34 byte simd1 = r.AllocateLocal(kWasmS128); |
(...skipping 23 matching lines...) Expand all Loading... |
391 | 58 |
392 FOR_FLOAT32_INPUTS(i) { | 59 FOR_FLOAT32_INPUTS(i) { |
393 if (std::isnan(*i)) continue; | 60 if (std::isnan(*i)) continue; |
394 CHECK_EQ(1, r.Call(*i, expected_op(*i))); | 61 CHECK_EQ(1, r.Call(*i, expected_op(*i))); |
395 } | 62 } |
396 } | 63 } |
397 | 64 |
398 WASM_EXEC_TEST(F32x4Abs) { RunF32x4UnOpTest(kExprF32x4Abs, std::abs); } | 65 WASM_EXEC_TEST(F32x4Abs) { RunF32x4UnOpTest(kExprF32x4Abs, std::abs); } |
399 WASM_EXEC_TEST(F32x4Neg) { RunF32x4UnOpTest(kExprF32x4Neg, Negate); } | 66 WASM_EXEC_TEST(F32x4Neg) { RunF32x4UnOpTest(kExprF32x4Neg, Negate); } |
400 | 67 |
401 void RunF32x4BinOpTest(WasmOpcode simd_op, FloatBinOp expected_op) { | |
402 FLAG_wasm_simd_prototype = true; | |
403 WasmRunner<int32_t, float, float, float> r(kExecuteCompiled); | |
404 byte a = 0; | |
405 byte b = 1; | |
406 byte expected = 2; | |
407 byte simd0 = r.AllocateLocal(kWasmS128); | |
408 byte simd1 = r.AllocateLocal(kWasmS128); | |
409 BUILD(r, WASM_SET_LOCAL(simd0, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(a))), | |
410 WASM_SET_LOCAL(simd1, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(b))), | |
411 WASM_SET_LOCAL(simd1, WASM_SIMD_BINOP(simd_op, WASM_GET_LOCAL(simd0), | |
412 WASM_GET_LOCAL(simd1))), | |
413 WASM_SIMD_CHECK_SPLAT4_F32(F32x4, simd1, expected), WASM_ONE); | |
414 | |
415 FOR_FLOAT32_INPUTS(i) { | |
416 if (std::isnan(*i)) continue; | |
417 FOR_FLOAT32_INPUTS(j) { | |
418 if (std::isnan(*j)) continue; | |
419 float expected = expected_op(*i, *j); | |
420 // SIMD on some platforms may handle denormalized numbers differently. | |
421 // TODO(bbudge) On platforms that flush denorms to zero, test with | |
422 // expected == 0. | |
423 if (std::fpclassify(expected) == FP_SUBNORMAL) continue; | |
424 CHECK_EQ(1, r.Call(*i, *j, expected)); | |
425 } | |
426 } | |
427 } | |
428 | |
429 WASM_EXEC_TEST(F32x4Add) { RunF32x4BinOpTest(kExprF32x4Add, Add); } | 68 WASM_EXEC_TEST(F32x4Add) { RunF32x4BinOpTest(kExprF32x4Add, Add); } |
430 WASM_EXEC_TEST(F32x4Sub) { RunF32x4BinOpTest(kExprF32x4Sub, Sub); } | 69 WASM_EXEC_TEST(F32x4Sub) { RunF32x4BinOpTest(kExprF32x4Sub, Sub); } |
431 | 70 |
432 void RunF32x4CompareOpTest(WasmOpcode simd_op, FloatCompareOp expected_op) { | 71 void RunF32x4CompareOpTest(WasmOpcode simd_op, FloatCompareOp expected_op) { |
433 FLAG_wasm_simd_prototype = true; | 72 FLAG_wasm_simd_prototype = true; |
434 WasmRunner<int32_t, float, float, int32_t> r(kExecuteCompiled); | 73 WasmRunner<int32_t, float, float, int32_t> r(kExecuteCompiled); |
435 byte a = 0; | 74 byte a = 0; |
436 byte b = 1; | 75 byte b = 1; |
437 byte expected = 2; | 76 byte expected = 2; |
438 byte simd0 = r.AllocateLocal(kWasmS128); | 77 byte simd0 = r.AllocateLocal(kWasmS128); |
(...skipping 15 matching lines...) Expand all Loading... |
454 if (std::fpclassify(*i - *j) == FP_SUBNORMAL) continue; | 93 if (std::fpclassify(*i - *j) == FP_SUBNORMAL) continue; |
455 CHECK_EQ(1, r.Call(*i, *j, expected_op(*i, *j))); | 94 CHECK_EQ(1, r.Call(*i, *j, expected_op(*i, *j))); |
456 } | 95 } |
457 } | 96 } |
458 } | 97 } |
459 | 98 |
460 WASM_EXEC_TEST(F32x4Equal) { RunF32x4CompareOpTest(kExprF32x4Eq, Equal); } | 99 WASM_EXEC_TEST(F32x4Equal) { RunF32x4CompareOpTest(kExprF32x4Eq, Equal); } |
461 WASM_EXEC_TEST(F32x4NotEqual) { RunF32x4CompareOpTest(kExprF32x4Ne, NotEqual); } | 100 WASM_EXEC_TEST(F32x4NotEqual) { RunF32x4CompareOpTest(kExprF32x4Ne, NotEqual); } |
462 #endif // V8_TARGET_ARCH_ARM | 101 #endif // V8_TARGET_ARCH_ARM |
463 | 102 |
464 WASM_EXEC_TEST(I32x4Splat) { | 103 WASM_EXEC_TEST(I32x4Splat) { RunI32x4SplatTest(); } |
465 FLAG_wasm_simd_prototype = true; | |
466 | 104 |
467 // Store SIMD value in a local variable, use extract lane to check lane values | 105 WASM_EXEC_TEST(I32x4ReplaceLane) { RunI32x4ReplaceLaneTest(); } |
468 // This test is not a test for ExtractLane as Splat does not create | |
469 // interesting SIMD values. | |
470 // | |
471 // SetLocal(1, I32x4Splat(Local(0))); | |
472 // For each lane index | |
473 // if(Local(0) != I32x4ExtractLane(Local(1), index) | |
474 // return 0 | |
475 // | |
476 // return 1 | |
477 WasmRunner<int32_t, int32_t> r(kExecuteCompiled); | |
478 byte lane_val = 0; | |
479 byte simd = r.AllocateLocal(kWasmS128); | |
480 BUILD(r, | |
481 WASM_SET_LOCAL(simd, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(lane_val))), | |
482 WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, lane_val), WASM_ONE); | |
483 | |
484 FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i)); } | |
485 } | |
486 | |
487 WASM_EXEC_TEST(I32x4ReplaceLane) { | |
488 FLAG_wasm_simd_prototype = true; | |
489 WasmRunner<int32_t, int32_t, int32_t> r(kExecuteCompiled); | |
490 byte old_val = 0; | |
491 byte new_val = 1; | |
492 byte simd = r.AllocateLocal(kWasmS128); | |
493 BUILD(r, WASM_SET_LOCAL(simd, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(old_val))), | |
494 WASM_SET_LOCAL(simd, | |
495 WASM_SIMD_I32x4_REPLACE_LANE(0, WASM_GET_LOCAL(simd), | |
496 WASM_GET_LOCAL(new_val))), | |
497 WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, old_val, old_val, old_val), | |
498 WASM_SET_LOCAL(simd, | |
499 WASM_SIMD_I32x4_REPLACE_LANE(1, WASM_GET_LOCAL(simd), | |
500 WASM_GET_LOCAL(new_val))), | |
501 WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, new_val, old_val, old_val), | |
502 WASM_SET_LOCAL(simd, | |
503 WASM_SIMD_I32x4_REPLACE_LANE(2, WASM_GET_LOCAL(simd), | |
504 WASM_GET_LOCAL(new_val))), | |
505 WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, new_val, new_val, old_val), | |
506 WASM_SET_LOCAL(simd, | |
507 WASM_SIMD_I32x4_REPLACE_LANE(3, WASM_GET_LOCAL(simd), | |
508 WASM_GET_LOCAL(new_val))), | |
509 WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, new_val), WASM_ONE); | |
510 | |
511 CHECK_EQ(1, r.Call(1, 2)); | |
512 } | |
513 | 106 |
514 #if V8_TARGET_ARCH_ARM | 107 #if V8_TARGET_ARCH_ARM |
515 | 108 |
516 WASM_EXEC_TEST(I16x8Splat) { | 109 WASM_EXEC_TEST(I16x8Splat) { |
517 FLAG_wasm_simd_prototype = true; | 110 FLAG_wasm_simd_prototype = true; |
518 | 111 |
519 WasmRunner<int32_t, int32_t> r(kExecuteCompiled); | 112 WasmRunner<int32_t, int32_t> r(kExecuteCompiled); |
520 byte lane_val = 0; | 113 byte lane_val = 0; |
521 byte simd = r.AllocateLocal(kWasmS128); | 114 byte simd = r.AllocateLocal(kWasmS128); |
522 BUILD(r, | 115 BUILD(r, |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, expected), WASM_ONE); | 362 WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, expected), WASM_ONE); |
770 | 363 |
771 FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i, expected_op(*i))); } | 364 FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i, expected_op(*i))); } |
772 } | 365 } |
773 | 366 |
774 WASM_EXEC_TEST(I32x4Neg) { RunI32x4UnOpTest(kExprI32x4Neg, Negate); } | 367 WASM_EXEC_TEST(I32x4Neg) { RunI32x4UnOpTest(kExprI32x4Neg, Negate); } |
775 | 368 |
776 WASM_EXEC_TEST(S128Not) { RunI32x4UnOpTest(kExprS128Not, Not); } | 369 WASM_EXEC_TEST(S128Not) { RunI32x4UnOpTest(kExprS128Not, Not); } |
777 #endif // V8_TARGET_ARCH_ARM | 370 #endif // V8_TARGET_ARCH_ARM |
778 | 371 |
779 void RunI32x4BinOpTest(WasmOpcode simd_op, Int32BinOp expected_op) { | |
780 FLAG_wasm_simd_prototype = true; | |
781 WasmRunner<int32_t, int32_t, int32_t, int32_t> r(kExecuteCompiled); | |
782 byte a = 0; | |
783 byte b = 1; | |
784 byte expected = 2; | |
785 byte simd0 = r.AllocateLocal(kWasmS128); | |
786 byte simd1 = r.AllocateLocal(kWasmS128); | |
787 BUILD(r, WASM_SET_LOCAL(simd0, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(a))), | |
788 WASM_SET_LOCAL(simd1, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(b))), | |
789 WASM_SET_LOCAL(simd1, WASM_SIMD_BINOP(simd_op, WASM_GET_LOCAL(simd0), | |
790 WASM_GET_LOCAL(simd1))), | |
791 WASM_SIMD_CHECK_SPLAT4(I32x4, simd1, I32, expected), WASM_ONE); | |
792 | |
793 FOR_INT32_INPUTS(i) { | |
794 FOR_INT32_INPUTS(j) { CHECK_EQ(1, r.Call(*i, *j, expected_op(*i, *j))); } | |
795 } | |
796 } | |
797 | |
798 WASM_EXEC_TEST(I32x4Add) { RunI32x4BinOpTest(kExprI32x4Add, Add); } | 372 WASM_EXEC_TEST(I32x4Add) { RunI32x4BinOpTest(kExprI32x4Add, Add); } |
799 | 373 |
800 WASM_EXEC_TEST(I32x4Sub) { RunI32x4BinOpTest(kExprI32x4Sub, Sub); } | 374 WASM_EXEC_TEST(I32x4Sub) { RunI32x4BinOpTest(kExprI32x4Sub, Sub); } |
801 | 375 |
802 #if V8_TARGET_ARCH_ARM | 376 #if V8_TARGET_ARCH_ARM |
803 WASM_EXEC_TEST(I32x4Mul) { RunI32x4BinOpTest(kExprI32x4Mul, Mul); } | 377 WASM_EXEC_TEST(I32x4Mul) { RunI32x4BinOpTest(kExprI32x4Mul, Mul); } |
804 | 378 |
805 WASM_EXEC_TEST(I32x4Min) { RunI32x4BinOpTest(kExprI32x4MinS, Minimum); } | 379 WASM_EXEC_TEST(I32x4Min) { RunI32x4BinOpTest(kExprI32x4MinS, Minimum); } |
806 | 380 |
807 WASM_EXEC_TEST(I32x4Max) { RunI32x4BinOpTest(kExprI32x4MaxS, Maximum); } | 381 WASM_EXEC_TEST(I32x4Max) { RunI32x4BinOpTest(kExprI32x4MaxS, Maximum); } |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1228 WASM_SIMD_CHECK_LANE(I##format, mask, I32, val1, 2), \ | 802 WASM_SIMD_CHECK_LANE(I##format, mask, I32, val1, 2), \ |
1229 WASM_SIMD_CHECK_LANE(I##format, mask, I32, val2, 3), WASM_ONE); \ | 803 WASM_SIMD_CHECK_LANE(I##format, mask, I32, val2, 3), WASM_ONE); \ |
1230 \ | 804 \ |
1231 CHECK_EQ(1, r.Call(0x12, 0x34)); \ | 805 CHECK_EQ(1, r.Call(0x12, 0x34)); \ |
1232 } | 806 } |
1233 | 807 |
1234 WASM_SIMD_SELECT_TEST(32x4) | 808 WASM_SIMD_SELECT_TEST(32x4) |
1235 WASM_SIMD_SELECT_TEST(16x8) | 809 WASM_SIMD_SELECT_TEST(16x8) |
1236 WASM_SIMD_SELECT_TEST(8x16) | 810 WASM_SIMD_SELECT_TEST(8x16) |
1237 #endif // V8_TARGET_ARCH_ARM | 811 #endif // V8_TARGET_ARCH_ARM |
| 812 } // namespace test_wasm_simd_common |
OLD | NEW |