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