blob: 9e5614242a656d882f31856c84519eb12d715d8b [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/runtime/runtime-utils.h"
6
7#include "src/arguments.h"
8#include "src/base/macros.h"
9#include "src/conversions.h"
10#include "src/factory.h"
11#include "src/objects-inl.h"
12
13// Implement Single Instruction Multiple Data (SIMD) operations as defined in
14// the SIMD.js draft spec:
15// http://littledan.github.io/simd.html
16
17namespace v8 {
18namespace internal {
19
20namespace {
21
22// Functions to convert Numbers to SIMD component types.
23
24template <typename T, typename F>
25static bool CanCast(F from) {
26 // A float can't represent 2^31 - 1 or 2^32 - 1 exactly, so promote the limits
27 // to double. Otherwise, the limit is truncated and numbers like 2^31 or 2^32
28 // get through, causing any static_cast to be undefined.
29 return from >= static_cast<double>(std::numeric_limits<T>::min()) &&
30 from <= static_cast<double>(std::numeric_limits<T>::max());
31}
32
33
34// Explicitly specialize for conversions to float, which always succeed.
35template <>
36bool CanCast<float>(int32_t from) {
37 return true;
38}
39
40
41template <>
42bool CanCast<float>(uint32_t from) {
43 return true;
44}
45
46
47template <typename T>
48static T ConvertNumber(double number);
49
50
51template <>
52float ConvertNumber<float>(double number) {
53 return DoubleToFloat32(number);
54}
55
56
57template <>
58int32_t ConvertNumber<int32_t>(double number) {
59 return DoubleToInt32(number);
60}
61
62
63template <>
64uint32_t ConvertNumber<uint32_t>(double number) {
65 return DoubleToUint32(number);
66}
67
68
69template <>
70int16_t ConvertNumber<int16_t>(double number) {
71 return static_cast<int16_t>(DoubleToInt32(number));
72}
73
74
75template <>
76uint16_t ConvertNumber<uint16_t>(double number) {
77 return static_cast<uint16_t>(DoubleToUint32(number));
78}
79
80
81template <>
82int8_t ConvertNumber<int8_t>(double number) {
83 return static_cast<int8_t>(DoubleToInt32(number));
84}
85
86
87template <>
88uint8_t ConvertNumber<uint8_t>(double number) {
89 return static_cast<uint8_t>(DoubleToUint32(number));
90}
91
92
93// TODO(bbudge): Make this consistent with SIMD instruction results.
94inline float RecipApprox(float a) { return 1.0f / a; }
95
96
97// TODO(bbudge): Make this consistent with SIMD instruction results.
98inline float RecipSqrtApprox(float a) { return 1.0f / std::sqrt(a); }
99
100
101// Saturating addition for int16_t and int8_t.
102template <typename T>
103inline T AddSaturate(T a, T b) {
104 const T max = std::numeric_limits<T>::max();
105 const T min = std::numeric_limits<T>::min();
106 int32_t result = a + b;
107 if (result > max) return max;
108 if (result < min) return min;
109 return result;
110}
111
112
113// Saturating subtraction for int16_t and int8_t.
114template <typename T>
115inline T SubSaturate(T a, T b) {
116 const T max = std::numeric_limits<T>::max();
117 const T min = std::numeric_limits<T>::min();
118 int32_t result = a - b;
119 if (result > max) return max;
120 if (result < min) return min;
121 return result;
122}
123
124
125inline float Min(float a, float b) {
126 if (a < b) return a;
127 if (a > b) return b;
128 if (a == b) return std::signbit(a) ? a : b;
129 return std::numeric_limits<float>::quiet_NaN();
130}
131
132
133inline float Max(float a, float b) {
134 if (a > b) return a;
135 if (a < b) return b;
136 if (a == b) return std::signbit(b) ? a : b;
137 return std::numeric_limits<float>::quiet_NaN();
138}
139
140
141inline float MinNumber(float a, float b) {
142 if (std::isnan(a)) return b;
143 if (std::isnan(b)) return a;
144 return Min(a, b);
145}
146
147
148inline float MaxNumber(float a, float b) {
149 if (std::isnan(a)) return b;
150 if (std::isnan(b)) return a;
151 return Max(a, b);
152}
153
154} // namespace
155
156//-------------------------------------------------------------------
157
158// SIMD helper functions.
159
160RUNTIME_FUNCTION(Runtime_IsSimdValue) {
161 HandleScope scope(isolate);
162 DCHECK(args.length() == 1);
163 return isolate->heap()->ToBoolean(args[0]->IsSimd128Value());
164}
165
166
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000167//-------------------------------------------------------------------
168
169// Utility macros.
170
171#define CONVERT_SIMD_LANE_ARG_CHECKED(name, index, lanes) \
172 CONVERT_INT32_ARG_CHECKED(name, index); \
173 RUNTIME_ASSERT(name >= 0 && name < lanes);
174
175#define CONVERT_SIMD_ARG_HANDLE_THROW(Type, name, index) \
176 Handle<Type> name; \
177 if (args[index]->Is##Type()) { \
178 name = args.at<Type>(index); \
179 } else { \
180 THROW_NEW_ERROR_RETURN_FAILURE( \
181 isolate, NewTypeError(MessageTemplate::kInvalidSimdOperation)); \
182 }
183
184#define SIMD_UNARY_OP(type, lane_type, lane_count, op, result) \
185 static const int kLaneCount = lane_count; \
186 DCHECK(args.length() == 1); \
187 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
188 lane_type lanes[kLaneCount]; \
189 for (int i = 0; i < kLaneCount; i++) { \
190 lanes[i] = op(a->get_lane(i)); \
191 } \
192 Handle<type> result = isolate->factory()->New##type(lanes);
193
194#define SIMD_BINARY_OP(type, lane_type, lane_count, op, result) \
195 static const int kLaneCount = lane_count; \
196 DCHECK(args.length() == 2); \
197 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
198 CONVERT_SIMD_ARG_HANDLE_THROW(type, b, 1); \
199 lane_type lanes[kLaneCount]; \
200 for (int i = 0; i < kLaneCount; i++) { \
201 lanes[i] = op(a->get_lane(i), b->get_lane(i)); \
202 } \
203 Handle<type> result = isolate->factory()->New##type(lanes);
204
205#define SIMD_RELATIONAL_OP(type, bool_type, lane_count, a, b, op, result) \
206 static const int kLaneCount = lane_count; \
207 DCHECK(args.length() == 2); \
208 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
209 CONVERT_SIMD_ARG_HANDLE_THROW(type, b, 1); \
210 bool lanes[kLaneCount]; \
211 for (int i = 0; i < kLaneCount; i++) { \
212 lanes[i] = a->get_lane(i) op b->get_lane(i); \
213 } \
214 Handle<bool_type> result = isolate->factory()->New##bool_type(lanes);
215
216//-------------------------------------------------------------------
217
218// Common functions.
219
220#define GET_NUMERIC_ARG(lane_type, name, index) \
221 CONVERT_NUMBER_ARG_HANDLE_CHECKED(a, index); \
222 name = ConvertNumber<lane_type>(a->Number());
223
224#define GET_BOOLEAN_ARG(lane_type, name, index) \
225 name = args[index]->BooleanValue();
226
227#define SIMD_ALL_TYPES(FUNCTION) \
228 FUNCTION(Float32x4, float, 4, NewNumber, GET_NUMERIC_ARG) \
229 FUNCTION(Int32x4, int32_t, 4, NewNumber, GET_NUMERIC_ARG) \
230 FUNCTION(Uint32x4, uint32_t, 4, NewNumber, GET_NUMERIC_ARG) \
231 FUNCTION(Bool32x4, bool, 4, ToBoolean, GET_BOOLEAN_ARG) \
232 FUNCTION(Int16x8, int16_t, 8, NewNumber, GET_NUMERIC_ARG) \
233 FUNCTION(Uint16x8, uint16_t, 8, NewNumber, GET_NUMERIC_ARG) \
234 FUNCTION(Bool16x8, bool, 8, ToBoolean, GET_BOOLEAN_ARG) \
235 FUNCTION(Int8x16, int8_t, 16, NewNumber, GET_NUMERIC_ARG) \
236 FUNCTION(Uint8x16, uint8_t, 16, NewNumber, GET_NUMERIC_ARG) \
237 FUNCTION(Bool8x16, bool, 16, ToBoolean, GET_BOOLEAN_ARG)
238
239#define SIMD_CREATE_FUNCTION(type, lane_type, lane_count, extract, replace) \
240 RUNTIME_FUNCTION(Runtime_Create##type) { \
241 static const int kLaneCount = lane_count; \
242 HandleScope scope(isolate); \
243 DCHECK(args.length() == kLaneCount); \
244 lane_type lanes[kLaneCount]; \
245 for (int i = 0; i < kLaneCount; i++) { \
246 replace(lane_type, lanes[i], i) \
247 } \
248 return *isolate->factory()->New##type(lanes); \
249 }
250
251#define SIMD_EXTRACT_FUNCTION(type, lane_type, lane_count, extract, replace) \
252 RUNTIME_FUNCTION(Runtime_##type##ExtractLane) { \
253 HandleScope scope(isolate); \
254 DCHECK(args.length() == 2); \
255 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
256 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lane_count); \
257 return *isolate->factory()->extract(a->get_lane(lane)); \
258 }
259
260#define SIMD_REPLACE_FUNCTION(type, lane_type, lane_count, extract, replace) \
261 RUNTIME_FUNCTION(Runtime_##type##ReplaceLane) { \
262 static const int kLaneCount = lane_count; \
263 HandleScope scope(isolate); \
264 DCHECK(args.length() == 3); \
265 CONVERT_SIMD_ARG_HANDLE_THROW(type, simd, 0); \
266 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, kLaneCount); \
267 lane_type lanes[kLaneCount]; \
268 for (int i = 0; i < kLaneCount; i++) { \
269 lanes[i] = simd->get_lane(i); \
270 } \
271 replace(lane_type, lanes[lane], 2); \
272 Handle<type> result = isolate->factory()->New##type(lanes); \
273 return *result; \
274 }
275
276#define SIMD_CHECK_FUNCTION(type, lane_type, lane_count, extract, replace) \
277 RUNTIME_FUNCTION(Runtime_##type##Check) { \
278 HandleScope scope(isolate); \
279 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
280 return *a; \
281 }
282
283#define SIMD_SWIZZLE_FUNCTION(type, lane_type, lane_count, extract, replace) \
284 RUNTIME_FUNCTION(Runtime_##type##Swizzle) { \
285 static const int kLaneCount = lane_count; \
286 HandleScope scope(isolate); \
287 DCHECK(args.length() == 1 + kLaneCount); \
288 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
289 lane_type lanes[kLaneCount]; \
290 for (int i = 0; i < kLaneCount; i++) { \
291 CONVERT_SIMD_LANE_ARG_CHECKED(index, i + 1, kLaneCount); \
292 lanes[i] = a->get_lane(index); \
293 } \
294 Handle<type> result = isolate->factory()->New##type(lanes); \
295 return *result; \
296 }
297
298#define SIMD_SHUFFLE_FUNCTION(type, lane_type, lane_count, extract, replace) \
299 RUNTIME_FUNCTION(Runtime_##type##Shuffle) { \
300 static const int kLaneCount = lane_count; \
301 HandleScope scope(isolate); \
302 DCHECK(args.length() == 2 + kLaneCount); \
303 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
304 CONVERT_SIMD_ARG_HANDLE_THROW(type, b, 1); \
305 lane_type lanes[kLaneCount]; \
306 for (int i = 0; i < kLaneCount; i++) { \
307 CONVERT_SIMD_LANE_ARG_CHECKED(index, i + 2, kLaneCount * 2); \
308 lanes[i] = index < kLaneCount ? a->get_lane(index) \
309 : b->get_lane(index - kLaneCount); \
310 } \
311 Handle<type> result = isolate->factory()->New##type(lanes); \
312 return *result; \
313 }
314
315SIMD_ALL_TYPES(SIMD_CREATE_FUNCTION)
316SIMD_ALL_TYPES(SIMD_EXTRACT_FUNCTION)
317SIMD_ALL_TYPES(SIMD_REPLACE_FUNCTION)
318SIMD_ALL_TYPES(SIMD_CHECK_FUNCTION)
319SIMD_ALL_TYPES(SIMD_SWIZZLE_FUNCTION)
320SIMD_ALL_TYPES(SIMD_SHUFFLE_FUNCTION)
321
322//-------------------------------------------------------------------
323
324// Float-only functions.
325
326#define SIMD_ABS_FUNCTION(type, lane_type, lane_count) \
327 RUNTIME_FUNCTION(Runtime_##type##Abs) { \
328 HandleScope scope(isolate); \
329 SIMD_UNARY_OP(type, lane_type, lane_count, std::abs, result); \
330 return *result; \
331 }
332
333#define SIMD_SQRT_FUNCTION(type, lane_type, lane_count) \
334 RUNTIME_FUNCTION(Runtime_##type##Sqrt) { \
335 HandleScope scope(isolate); \
336 SIMD_UNARY_OP(type, lane_type, lane_count, std::sqrt, result); \
337 return *result; \
338 }
339
340#define SIMD_RECIP_APPROX_FUNCTION(type, lane_type, lane_count) \
341 RUNTIME_FUNCTION(Runtime_##type##RecipApprox) { \
342 HandleScope scope(isolate); \
343 SIMD_UNARY_OP(type, lane_type, lane_count, RecipApprox, result); \
344 return *result; \
345 }
346
347#define SIMD_RECIP_SQRT_APPROX_FUNCTION(type, lane_type, lane_count) \
348 RUNTIME_FUNCTION(Runtime_##type##RecipSqrtApprox) { \
349 HandleScope scope(isolate); \
350 SIMD_UNARY_OP(type, lane_type, lane_count, RecipSqrtApprox, result); \
351 return *result; \
352 }
353
354#define BINARY_DIV(a, b) (a) / (b)
355#define SIMD_DIV_FUNCTION(type, lane_type, lane_count) \
356 RUNTIME_FUNCTION(Runtime_##type##Div) { \
357 HandleScope scope(isolate); \
358 SIMD_BINARY_OP(type, lane_type, lane_count, BINARY_DIV, result); \
359 return *result; \
360 }
361
362#define SIMD_MINNUM_FUNCTION(type, lane_type, lane_count) \
363 RUNTIME_FUNCTION(Runtime_##type##MinNum) { \
364 HandleScope scope(isolate); \
365 SIMD_BINARY_OP(type, lane_type, lane_count, MinNumber, result); \
366 return *result; \
367 }
368
369#define SIMD_MAXNUM_FUNCTION(type, lane_type, lane_count) \
370 RUNTIME_FUNCTION(Runtime_##type##MaxNum) { \
371 HandleScope scope(isolate); \
372 SIMD_BINARY_OP(type, lane_type, lane_count, MaxNumber, result); \
373 return *result; \
374 }
375
376SIMD_ABS_FUNCTION(Float32x4, float, 4)
377SIMD_SQRT_FUNCTION(Float32x4, float, 4)
378SIMD_RECIP_APPROX_FUNCTION(Float32x4, float, 4)
379SIMD_RECIP_SQRT_APPROX_FUNCTION(Float32x4, float, 4)
380SIMD_DIV_FUNCTION(Float32x4, float, 4)
381SIMD_MINNUM_FUNCTION(Float32x4, float, 4)
382SIMD_MAXNUM_FUNCTION(Float32x4, float, 4)
383
384//-------------------------------------------------------------------
385
386// Int-only functions.
387
388#define SIMD_INT_TYPES(FUNCTION) \
389 FUNCTION(Int32x4, int32_t, 32, 4) \
390 FUNCTION(Int16x8, int16_t, 16, 8) \
391 FUNCTION(Int8x16, int8_t, 8, 16)
392
393#define SIMD_UINT_TYPES(FUNCTION) \
394 FUNCTION(Uint32x4, uint32_t, 32, 4) \
395 FUNCTION(Uint16x8, uint16_t, 16, 8) \
396 FUNCTION(Uint8x16, uint8_t, 8, 16)
397
398#define CONVERT_SHIFT_ARG_CHECKED(name, index) \
399 RUNTIME_ASSERT(args[index]->IsNumber()); \
400 int32_t signed_shift = 0; \
401 RUNTIME_ASSERT(args[index]->ToInt32(&signed_shift)); \
402 uint32_t name = bit_cast<uint32_t>(signed_shift);
403
404#define SIMD_LSL_FUNCTION(type, lane_type, lane_bits, lane_count) \
405 RUNTIME_FUNCTION(Runtime_##type##ShiftLeftByScalar) { \
406 static const int kLaneCount = lane_count; \
407 HandleScope scope(isolate); \
408 DCHECK(args.length() == 2); \
409 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
410 CONVERT_SHIFT_ARG_CHECKED(shift, 1); \
411 lane_type lanes[kLaneCount] = {0}; \
412 if (shift < lane_bits) { \
413 for (int i = 0; i < kLaneCount; i++) { \
414 lanes[i] = a->get_lane(i) << shift; \
415 } \
416 } \
417 Handle<type> result = isolate->factory()->New##type(lanes); \
418 return *result; \
419 }
420
421#define SIMD_LSR_FUNCTION(type, lane_type, lane_bits, lane_count) \
422 RUNTIME_FUNCTION(Runtime_##type##ShiftRightByScalar) { \
423 static const int kLaneCount = lane_count; \
424 HandleScope scope(isolate); \
425 DCHECK(args.length() == 2); \
426 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
427 CONVERT_SHIFT_ARG_CHECKED(shift, 1); \
428 lane_type lanes[kLaneCount] = {0}; \
429 if (shift < lane_bits) { \
430 for (int i = 0; i < kLaneCount; i++) { \
431 lanes[i] = static_cast<lane_type>( \
432 bit_cast<lane_type>(a->get_lane(i)) >> shift); \
433 } \
434 } \
435 Handle<type> result = isolate->factory()->New##type(lanes); \
436 return *result; \
437 }
438
439#define SIMD_ASR_FUNCTION(type, lane_type, lane_bits, lane_count) \
440 RUNTIME_FUNCTION(Runtime_##type##ShiftRightByScalar) { \
441 static const int kLaneCount = lane_count; \
442 HandleScope scope(isolate); \
443 DCHECK(args.length() == 2); \
444 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
445 CONVERT_SHIFT_ARG_CHECKED(shift, 1); \
446 if (shift >= lane_bits) shift = lane_bits - 1; \
447 lane_type lanes[kLaneCount]; \
448 for (int i = 0; i < kLaneCount; i++) { \
449 int64_t shifted = static_cast<int64_t>(a->get_lane(i)) >> shift; \
450 lanes[i] = static_cast<lane_type>(shifted); \
451 } \
452 Handle<type> result = isolate->factory()->New##type(lanes); \
453 return *result; \
454 }
455
456SIMD_INT_TYPES(SIMD_LSL_FUNCTION)
457SIMD_UINT_TYPES(SIMD_LSL_FUNCTION)
458SIMD_INT_TYPES(SIMD_ASR_FUNCTION)
459SIMD_UINT_TYPES(SIMD_LSR_FUNCTION)
460
461//-------------------------------------------------------------------
462
463// Bool-only functions.
464
465#define SIMD_BOOL_TYPES(FUNCTION) \
466 FUNCTION(Bool32x4, 4) \
467 FUNCTION(Bool16x8, 8) \
468 FUNCTION(Bool8x16, 16)
469
470#define SIMD_ANY_FUNCTION(type, lane_count) \
471 RUNTIME_FUNCTION(Runtime_##type##AnyTrue) { \
472 HandleScope scope(isolate); \
473 DCHECK(args.length() == 1); \
474 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
475 bool result = false; \
476 for (int i = 0; i < lane_count; i++) { \
477 if (a->get_lane(i)) { \
478 result = true; \
479 break; \
480 } \
481 } \
482 return isolate->heap()->ToBoolean(result); \
483 }
484
485#define SIMD_ALL_FUNCTION(type, lane_count) \
486 RUNTIME_FUNCTION(Runtime_##type##AllTrue) { \
487 HandleScope scope(isolate); \
488 DCHECK(args.length() == 1); \
489 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 0); \
490 bool result = true; \
491 for (int i = 0; i < lane_count; i++) { \
492 if (!a->get_lane(i)) { \
493 result = false; \
494 break; \
495 } \
496 } \
497 return isolate->heap()->ToBoolean(result); \
498 }
499
500SIMD_BOOL_TYPES(SIMD_ANY_FUNCTION)
501SIMD_BOOL_TYPES(SIMD_ALL_FUNCTION)
502
503//-------------------------------------------------------------------
504
505// Small Int-only functions.
506
507#define SIMD_SMALL_INT_TYPES(FUNCTION) \
508 FUNCTION(Int16x8, int16_t, 8) \
509 FUNCTION(Uint16x8, uint16_t, 8) \
510 FUNCTION(Int8x16, int8_t, 16) \
511 FUNCTION(Uint8x16, uint8_t, 16)
512
513#define SIMD_ADD_SATURATE_FUNCTION(type, lane_type, lane_count) \
514 RUNTIME_FUNCTION(Runtime_##type##AddSaturate) { \
515 HandleScope scope(isolate); \
516 SIMD_BINARY_OP(type, lane_type, lane_count, AddSaturate, result); \
517 return *result; \
518 }
519
520#define BINARY_SUB(a, b) (a) - (b)
521#define SIMD_SUB_SATURATE_FUNCTION(type, lane_type, lane_count) \
522 RUNTIME_FUNCTION(Runtime_##type##SubSaturate) { \
523 HandleScope scope(isolate); \
524 SIMD_BINARY_OP(type, lane_type, lane_count, SubSaturate, result); \
525 return *result; \
526 }
527
528SIMD_SMALL_INT_TYPES(SIMD_ADD_SATURATE_FUNCTION)
529SIMD_SMALL_INT_TYPES(SIMD_SUB_SATURATE_FUNCTION)
530
531//-------------------------------------------------------------------
532
533// Numeric functions.
534
535#define SIMD_NUMERIC_TYPES(FUNCTION) \
536 FUNCTION(Float32x4, float, 4) \
537 FUNCTION(Int32x4, int32_t, 4) \
538 FUNCTION(Uint32x4, uint32_t, 4) \
539 FUNCTION(Int16x8, int16_t, 8) \
540 FUNCTION(Uint16x8, uint16_t, 8) \
541 FUNCTION(Int8x16, int8_t, 16) \
542 FUNCTION(Uint8x16, uint8_t, 16)
543
544#define BINARY_ADD(a, b) (a) + (b)
545#define SIMD_ADD_FUNCTION(type, lane_type, lane_count) \
546 RUNTIME_FUNCTION(Runtime_##type##Add) { \
547 HandleScope scope(isolate); \
548 SIMD_BINARY_OP(type, lane_type, lane_count, BINARY_ADD, result); \
549 return *result; \
550 }
551
552#define BINARY_SUB(a, b) (a) - (b)
553#define SIMD_SUB_FUNCTION(type, lane_type, lane_count) \
554 RUNTIME_FUNCTION(Runtime_##type##Sub) { \
555 HandleScope scope(isolate); \
556 SIMD_BINARY_OP(type, lane_type, lane_count, BINARY_SUB, result); \
557 return *result; \
558 }
559
560#define BINARY_MUL(a, b) (a) * (b)
561#define SIMD_MUL_FUNCTION(type, lane_type, lane_count) \
562 RUNTIME_FUNCTION(Runtime_##type##Mul) { \
563 HandleScope scope(isolate); \
564 SIMD_BINARY_OP(type, lane_type, lane_count, BINARY_MUL, result); \
565 return *result; \
566 }
567
568#define SIMD_MIN_FUNCTION(type, lane_type, lane_count) \
569 RUNTIME_FUNCTION(Runtime_##type##Min) { \
570 HandleScope scope(isolate); \
571 SIMD_BINARY_OP(type, lane_type, lane_count, Min, result); \
572 return *result; \
573 }
574
575#define SIMD_MAX_FUNCTION(type, lane_type, lane_count) \
576 RUNTIME_FUNCTION(Runtime_##type##Max) { \
577 HandleScope scope(isolate); \
578 SIMD_BINARY_OP(type, lane_type, lane_count, Max, result); \
579 return *result; \
580 }
581
582SIMD_NUMERIC_TYPES(SIMD_ADD_FUNCTION)
583SIMD_NUMERIC_TYPES(SIMD_SUB_FUNCTION)
584SIMD_NUMERIC_TYPES(SIMD_MUL_FUNCTION)
585SIMD_NUMERIC_TYPES(SIMD_MIN_FUNCTION)
586SIMD_NUMERIC_TYPES(SIMD_MAX_FUNCTION)
587
588//-------------------------------------------------------------------
589
590// Relational functions.
591
592#define SIMD_RELATIONAL_TYPES(FUNCTION) \
593 FUNCTION(Float32x4, Bool32x4, 4) \
594 FUNCTION(Int32x4, Bool32x4, 4) \
595 FUNCTION(Uint32x4, Bool32x4, 4) \
596 FUNCTION(Int16x8, Bool16x8, 8) \
597 FUNCTION(Uint16x8, Bool16x8, 8) \
598 FUNCTION(Int8x16, Bool8x16, 16) \
599 FUNCTION(Uint8x16, Bool8x16, 16)
600
601#define SIMD_EQUALITY_TYPES(FUNCTION) \
602 SIMD_RELATIONAL_TYPES(FUNCTION) \
603 FUNCTION(Bool32x4, Bool32x4, 4) \
604 FUNCTION(Bool16x8, Bool16x8, 8) \
605 FUNCTION(Bool8x16, Bool8x16, 16)
606
607#define SIMD_EQUAL_FUNCTION(type, bool_type, lane_count) \
608 RUNTIME_FUNCTION(Runtime_##type##Equal) { \
609 HandleScope scope(isolate); \
610 SIMD_RELATIONAL_OP(type, bool_type, lane_count, a, b, ==, result); \
611 return *result; \
612 }
613
614#define SIMD_NOT_EQUAL_FUNCTION(type, bool_type, lane_count) \
615 RUNTIME_FUNCTION(Runtime_##type##NotEqual) { \
616 HandleScope scope(isolate); \
617 SIMD_RELATIONAL_OP(type, bool_type, lane_count, a, b, !=, result); \
618 return *result; \
619 }
620
621SIMD_EQUALITY_TYPES(SIMD_EQUAL_FUNCTION)
622SIMD_EQUALITY_TYPES(SIMD_NOT_EQUAL_FUNCTION)
623
624#define SIMD_LESS_THAN_FUNCTION(type, bool_type, lane_count) \
625 RUNTIME_FUNCTION(Runtime_##type##LessThan) { \
626 HandleScope scope(isolate); \
627 SIMD_RELATIONAL_OP(type, bool_type, lane_count, a, b, <, result); \
628 return *result; \
629 }
630
631#define SIMD_LESS_THAN_OR_EQUAL_FUNCTION(type, bool_type, lane_count) \
632 RUNTIME_FUNCTION(Runtime_##type##LessThanOrEqual) { \
633 HandleScope scope(isolate); \
634 SIMD_RELATIONAL_OP(type, bool_type, lane_count, a, b, <=, result); \
635 return *result; \
636 }
637
638#define SIMD_GREATER_THAN_FUNCTION(type, bool_type, lane_count) \
639 RUNTIME_FUNCTION(Runtime_##type##GreaterThan) { \
640 HandleScope scope(isolate); \
641 SIMD_RELATIONAL_OP(type, bool_type, lane_count, a, b, >, result); \
642 return *result; \
643 }
644
645#define SIMD_GREATER_THAN_OR_EQUAL_FUNCTION(type, bool_type, lane_count) \
646 RUNTIME_FUNCTION(Runtime_##type##GreaterThanOrEqual) { \
647 HandleScope scope(isolate); \
648 SIMD_RELATIONAL_OP(type, bool_type, lane_count, a, b, >=, result); \
649 return *result; \
650 }
651
652SIMD_RELATIONAL_TYPES(SIMD_LESS_THAN_FUNCTION)
653SIMD_RELATIONAL_TYPES(SIMD_LESS_THAN_OR_EQUAL_FUNCTION)
654SIMD_RELATIONAL_TYPES(SIMD_GREATER_THAN_FUNCTION)
655SIMD_RELATIONAL_TYPES(SIMD_GREATER_THAN_OR_EQUAL_FUNCTION)
656
657//-------------------------------------------------------------------
658
659// Logical functions.
660
661#define SIMD_LOGICAL_TYPES(FUNCTION) \
662 FUNCTION(Int32x4, int32_t, 4, _INT) \
663 FUNCTION(Uint32x4, uint32_t, 4, _INT) \
664 FUNCTION(Int16x8, int16_t, 8, _INT) \
665 FUNCTION(Uint16x8, uint16_t, 8, _INT) \
666 FUNCTION(Int8x16, int8_t, 16, _INT) \
667 FUNCTION(Uint8x16, uint8_t, 16, _INT) \
668 FUNCTION(Bool32x4, bool, 4, _BOOL) \
669 FUNCTION(Bool16x8, bool, 8, _BOOL) \
670 FUNCTION(Bool8x16, bool, 16, _BOOL)
671
672#define BINARY_AND_INT(a, b) (a) & (b)
673#define BINARY_AND_BOOL(a, b) (a) && (b)
674#define SIMD_AND_FUNCTION(type, lane_type, lane_count, op) \
675 RUNTIME_FUNCTION(Runtime_##type##And) { \
676 HandleScope scope(isolate); \
677 SIMD_BINARY_OP(type, lane_type, lane_count, BINARY_AND##op, result); \
678 return *result; \
679 }
680
681#define BINARY_OR_INT(a, b) (a) | (b)
682#define BINARY_OR_BOOL(a, b) (a) || (b)
683#define SIMD_OR_FUNCTION(type, lane_type, lane_count, op) \
684 RUNTIME_FUNCTION(Runtime_##type##Or) { \
685 HandleScope scope(isolate); \
686 SIMD_BINARY_OP(type, lane_type, lane_count, BINARY_OR##op, result); \
687 return *result; \
688 }
689
690#define BINARY_XOR_INT(a, b) (a) ^ (b)
691#define BINARY_XOR_BOOL(a, b) (a) != (b)
692#define SIMD_XOR_FUNCTION(type, lane_type, lane_count, op) \
693 RUNTIME_FUNCTION(Runtime_##type##Xor) { \
694 HandleScope scope(isolate); \
695 SIMD_BINARY_OP(type, lane_type, lane_count, BINARY_XOR##op, result); \
696 return *result; \
697 }
698
699#define UNARY_NOT_INT ~
700#define UNARY_NOT_BOOL !
701#define SIMD_NOT_FUNCTION(type, lane_type, lane_count, op) \
702 RUNTIME_FUNCTION(Runtime_##type##Not) { \
703 HandleScope scope(isolate); \
704 SIMD_UNARY_OP(type, lane_type, lane_count, UNARY_NOT##op, result); \
705 return *result; \
706 }
707
708SIMD_LOGICAL_TYPES(SIMD_AND_FUNCTION)
709SIMD_LOGICAL_TYPES(SIMD_OR_FUNCTION)
710SIMD_LOGICAL_TYPES(SIMD_XOR_FUNCTION)
711SIMD_LOGICAL_TYPES(SIMD_NOT_FUNCTION)
712
713//-------------------------------------------------------------------
714
715// Select functions.
716
717#define SIMD_SELECT_TYPES(FUNCTION) \
718 FUNCTION(Float32x4, float, Bool32x4, 4) \
719 FUNCTION(Int32x4, int32_t, Bool32x4, 4) \
720 FUNCTION(Uint32x4, uint32_t, Bool32x4, 4) \
721 FUNCTION(Int16x8, int16_t, Bool16x8, 8) \
722 FUNCTION(Uint16x8, uint16_t, Bool16x8, 8) \
723 FUNCTION(Int8x16, int8_t, Bool8x16, 16) \
724 FUNCTION(Uint8x16, uint8_t, Bool8x16, 16)
725
726#define SIMD_SELECT_FUNCTION(type, lane_type, bool_type, lane_count) \
727 RUNTIME_FUNCTION(Runtime_##type##Select) { \
728 static const int kLaneCount = lane_count; \
729 HandleScope scope(isolate); \
730 DCHECK(args.length() == 3); \
731 CONVERT_SIMD_ARG_HANDLE_THROW(bool_type, mask, 0); \
732 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 1); \
733 CONVERT_SIMD_ARG_HANDLE_THROW(type, b, 2); \
734 lane_type lanes[kLaneCount]; \
735 for (int i = 0; i < kLaneCount; i++) { \
736 lanes[i] = mask->get_lane(i) ? a->get_lane(i) : b->get_lane(i); \
737 } \
738 Handle<type> result = isolate->factory()->New##type(lanes); \
739 return *result; \
740 }
741
742SIMD_SELECT_TYPES(SIMD_SELECT_FUNCTION)
743
744//-------------------------------------------------------------------
745
746// Signed / unsigned functions.
747
748#define SIMD_SIGNED_TYPES(FUNCTION) \
749 FUNCTION(Float32x4, float, 4) \
750 FUNCTION(Int32x4, int32_t, 4) \
751 FUNCTION(Int16x8, int16_t, 8) \
752 FUNCTION(Int8x16, int8_t, 16)
753
754#define SIMD_NEG_FUNCTION(type, lane_type, lane_count) \
755 RUNTIME_FUNCTION(Runtime_##type##Neg) { \
756 HandleScope scope(isolate); \
757 SIMD_UNARY_OP(type, lane_type, lane_count, -, result); \
758 return *result; \
759 }
760
761SIMD_SIGNED_TYPES(SIMD_NEG_FUNCTION)
762
763//-------------------------------------------------------------------
764
765// Casting functions.
766
767#define SIMD_FROM_TYPES(FUNCTION) \
768 FUNCTION(Float32x4, float, 4, Int32x4, int32_t) \
769 FUNCTION(Float32x4, float, 4, Uint32x4, uint32_t) \
770 FUNCTION(Int32x4, int32_t, 4, Float32x4, float) \
771 FUNCTION(Int32x4, int32_t, 4, Uint32x4, uint32_t) \
772 FUNCTION(Uint32x4, uint32_t, 4, Float32x4, float) \
773 FUNCTION(Uint32x4, uint32_t, 4, Int32x4, int32_t) \
774 FUNCTION(Int16x8, int16_t, 8, Uint16x8, uint16_t) \
775 FUNCTION(Uint16x8, uint16_t, 8, Int16x8, int16_t) \
776 FUNCTION(Int8x16, int8_t, 16, Uint8x16, uint8_t) \
777 FUNCTION(Uint8x16, uint8_t, 16, Int8x16, int8_t)
778
779#define SIMD_FROM_FUNCTION(type, lane_type, lane_count, from_type, from_ctype) \
780 RUNTIME_FUNCTION(Runtime_##type##From##from_type) { \
781 static const int kLaneCount = lane_count; \
782 HandleScope scope(isolate); \
783 DCHECK(args.length() == 1); \
784 CONVERT_SIMD_ARG_HANDLE_THROW(from_type, a, 0); \
785 lane_type lanes[kLaneCount]; \
786 for (int i = 0; i < kLaneCount; i++) { \
787 from_ctype a_value = a->get_lane(i); \
788 if (a_value != a_value) a_value = 0; \
789 RUNTIME_ASSERT(CanCast<lane_type>(a_value)); \
790 lanes[i] = static_cast<lane_type>(a_value); \
791 } \
792 Handle<type> result = isolate->factory()->New##type(lanes); \
793 return *result; \
794 }
795
796SIMD_FROM_TYPES(SIMD_FROM_FUNCTION)
797
798#define SIMD_FROM_BITS_TYPES(FUNCTION) \
799 FUNCTION(Float32x4, float, 4, Int32x4) \
800 FUNCTION(Float32x4, float, 4, Uint32x4) \
801 FUNCTION(Float32x4, float, 4, Int16x8) \
802 FUNCTION(Float32x4, float, 4, Uint16x8) \
803 FUNCTION(Float32x4, float, 4, Int8x16) \
804 FUNCTION(Float32x4, float, 4, Uint8x16) \
805 FUNCTION(Int32x4, int32_t, 4, Float32x4) \
806 FUNCTION(Int32x4, int32_t, 4, Uint32x4) \
807 FUNCTION(Int32x4, int32_t, 4, Int16x8) \
808 FUNCTION(Int32x4, int32_t, 4, Uint16x8) \
809 FUNCTION(Int32x4, int32_t, 4, Int8x16) \
810 FUNCTION(Int32x4, int32_t, 4, Uint8x16) \
811 FUNCTION(Uint32x4, uint32_t, 4, Float32x4) \
812 FUNCTION(Uint32x4, uint32_t, 4, Int32x4) \
813 FUNCTION(Uint32x4, uint32_t, 4, Int16x8) \
814 FUNCTION(Uint32x4, uint32_t, 4, Uint16x8) \
815 FUNCTION(Uint32x4, uint32_t, 4, Int8x16) \
816 FUNCTION(Uint32x4, uint32_t, 4, Uint8x16) \
817 FUNCTION(Int16x8, int16_t, 8, Float32x4) \
818 FUNCTION(Int16x8, int16_t, 8, Int32x4) \
819 FUNCTION(Int16x8, int16_t, 8, Uint32x4) \
820 FUNCTION(Int16x8, int16_t, 8, Uint16x8) \
821 FUNCTION(Int16x8, int16_t, 8, Int8x16) \
822 FUNCTION(Int16x8, int16_t, 8, Uint8x16) \
823 FUNCTION(Uint16x8, uint16_t, 8, Float32x4) \
824 FUNCTION(Uint16x8, uint16_t, 8, Int32x4) \
825 FUNCTION(Uint16x8, uint16_t, 8, Uint32x4) \
826 FUNCTION(Uint16x8, uint16_t, 8, Int16x8) \
827 FUNCTION(Uint16x8, uint16_t, 8, Int8x16) \
828 FUNCTION(Uint16x8, uint16_t, 8, Uint8x16) \
829 FUNCTION(Int8x16, int8_t, 16, Float32x4) \
830 FUNCTION(Int8x16, int8_t, 16, Int32x4) \
831 FUNCTION(Int8x16, int8_t, 16, Uint32x4) \
832 FUNCTION(Int8x16, int8_t, 16, Int16x8) \
833 FUNCTION(Int8x16, int8_t, 16, Uint16x8) \
834 FUNCTION(Int8x16, int8_t, 16, Uint8x16) \
835 FUNCTION(Uint8x16, uint8_t, 16, Float32x4) \
836 FUNCTION(Uint8x16, uint8_t, 16, Int32x4) \
837 FUNCTION(Uint8x16, uint8_t, 16, Uint32x4) \
838 FUNCTION(Uint8x16, uint8_t, 16, Int16x8) \
839 FUNCTION(Uint8x16, uint8_t, 16, Uint16x8) \
840 FUNCTION(Uint8x16, uint8_t, 16, Int8x16)
841
842#define SIMD_FROM_BITS_FUNCTION(type, lane_type, lane_count, from_type) \
843 RUNTIME_FUNCTION(Runtime_##type##From##from_type##Bits) { \
844 static const int kLaneCount = lane_count; \
845 HandleScope scope(isolate); \
846 DCHECK(args.length() == 1); \
847 CONVERT_SIMD_ARG_HANDLE_THROW(from_type, a, 0); \
848 lane_type lanes[kLaneCount]; \
849 a->CopyBits(lanes); \
850 Handle<type> result = isolate->factory()->New##type(lanes); \
851 return *result; \
852 }
853
854SIMD_FROM_BITS_TYPES(SIMD_FROM_BITS_FUNCTION)
855
856
857//-------------------------------------------------------------------
858
859// Load and Store functions.
860
861#define SIMD_LOADN_STOREN_TYPES(FUNCTION) \
862 FUNCTION(Float32x4, float, 4) \
863 FUNCTION(Int32x4, int32_t, 4) \
864 FUNCTION(Uint32x4, uint32_t, 4)
865
866
867// Common Load and Store Functions
868
869#define SIMD_LOAD(type, lane_type, lane_count, count, result) \
870 static const int kLaneCount = lane_count; \
871 DCHECK(args.length() == 2); \
872 CONVERT_SIMD_ARG_HANDLE_THROW(JSTypedArray, tarray, 0); \
873 CONVERT_INT32_ARG_CHECKED(index, 1) \
874 size_t bpe = tarray->element_size(); \
875 uint32_t bytes = count * sizeof(lane_type); \
876 size_t byte_length = NumberToSize(isolate, tarray->byte_length()); \
877 RUNTIME_ASSERT(index >= 0 && index * bpe + bytes <= byte_length); \
878 size_t tarray_offset = NumberToSize(isolate, tarray->byte_offset()); \
879 uint8_t* tarray_base = \
880 static_cast<uint8_t*>(tarray->GetBuffer()->backing_store()) + \
881 tarray_offset; \
882 lane_type lanes[kLaneCount] = {0}; \
883 memcpy(lanes, tarray_base + index * bpe, bytes); \
884 Handle<type> result = isolate->factory()->New##type(lanes);
885
886
887#define SIMD_STORE(type, lane_type, lane_count, count, a) \
888 static const int kLaneCount = lane_count; \
889 DCHECK(args.length() == 3); \
890 CONVERT_SIMD_ARG_HANDLE_THROW(JSTypedArray, tarray, 0); \
891 CONVERT_SIMD_ARG_HANDLE_THROW(type, a, 2); \
892 CONVERT_INT32_ARG_CHECKED(index, 1) \
893 size_t bpe = tarray->element_size(); \
894 uint32_t bytes = count * sizeof(lane_type); \
895 size_t byte_length = NumberToSize(isolate, tarray->byte_length()); \
896 RUNTIME_ASSERT(index >= 0 && index * bpe + bytes <= byte_length); \
897 size_t tarray_offset = NumberToSize(isolate, tarray->byte_offset()); \
898 uint8_t* tarray_base = \
899 static_cast<uint8_t*>(tarray->GetBuffer()->backing_store()) + \
900 tarray_offset; \
901 lane_type lanes[kLaneCount]; \
902 for (int i = 0; i < kLaneCount; i++) { \
903 lanes[i] = a->get_lane(i); \
904 } \
905 memcpy(tarray_base + index * bpe, lanes, bytes);
906
907
908#define SIMD_LOAD_FUNCTION(type, lane_type, lane_count) \
909 RUNTIME_FUNCTION(Runtime_##type##Load) { \
910 HandleScope scope(isolate); \
911 SIMD_LOAD(type, lane_type, lane_count, lane_count, result); \
912 return *result; \
913 }
914
915
916#define SIMD_LOAD1_FUNCTION(type, lane_type, lane_count) \
917 RUNTIME_FUNCTION(Runtime_##type##Load1) { \
918 HandleScope scope(isolate); \
919 SIMD_LOAD(type, lane_type, lane_count, 1, result); \
920 return *result; \
921 }
922
923
924#define SIMD_LOAD2_FUNCTION(type, lane_type, lane_count) \
925 RUNTIME_FUNCTION(Runtime_##type##Load2) { \
926 HandleScope scope(isolate); \
927 SIMD_LOAD(type, lane_type, lane_count, 2, result); \
928 return *result; \
929 }
930
931
932#define SIMD_LOAD3_FUNCTION(type, lane_type, lane_count) \
933 RUNTIME_FUNCTION(Runtime_##type##Load3) { \
934 HandleScope scope(isolate); \
935 SIMD_LOAD(type, lane_type, lane_count, 3, result); \
936 return *result; \
937 }
938
939
940#define SIMD_STORE_FUNCTION(type, lane_type, lane_count) \
941 RUNTIME_FUNCTION(Runtime_##type##Store) { \
942 HandleScope scope(isolate); \
943 SIMD_STORE(type, lane_type, lane_count, lane_count, a); \
944 return *a; \
945 }
946
947
948#define SIMD_STORE1_FUNCTION(type, lane_type, lane_count) \
949 RUNTIME_FUNCTION(Runtime_##type##Store1) { \
950 HandleScope scope(isolate); \
951 SIMD_STORE(type, lane_type, lane_count, 1, a); \
952 return *a; \
953 }
954
955
956#define SIMD_STORE2_FUNCTION(type, lane_type, lane_count) \
957 RUNTIME_FUNCTION(Runtime_##type##Store2) { \
958 HandleScope scope(isolate); \
959 SIMD_STORE(type, lane_type, lane_count, 2, a); \
960 return *a; \
961 }
962
963
964#define SIMD_STORE3_FUNCTION(type, lane_type, lane_count) \
965 RUNTIME_FUNCTION(Runtime_##type##Store3) { \
966 HandleScope scope(isolate); \
967 SIMD_STORE(type, lane_type, lane_count, 3, a); \
968 return *a; \
969 }
970
971
972SIMD_NUMERIC_TYPES(SIMD_LOAD_FUNCTION)
973SIMD_LOADN_STOREN_TYPES(SIMD_LOAD1_FUNCTION)
974SIMD_LOADN_STOREN_TYPES(SIMD_LOAD2_FUNCTION)
975SIMD_LOADN_STOREN_TYPES(SIMD_LOAD3_FUNCTION)
976SIMD_NUMERIC_TYPES(SIMD_STORE_FUNCTION)
977SIMD_LOADN_STOREN_TYPES(SIMD_STORE1_FUNCTION)
978SIMD_LOADN_STOREN_TYPES(SIMD_STORE2_FUNCTION)
979SIMD_LOADN_STOREN_TYPES(SIMD_STORE3_FUNCTION)
980
981//-------------------------------------------------------------------
982
983} // namespace internal
984} // namespace v8