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