blob: 70bc950150ae5b3c2719f480cfc438ab27350396 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/runtime/runtime-utils.h"
6
7#include "src/arguments.h"
8#include "src/base/macros.h"
9#include "src/conversions.h"
10#include "src/factory.h"
11#include "src/objects-inl.h"
12
13// Implement Single Instruction Multiple Data (SIMD) operations as defined in
14// the SIMD.js draft spec:
15// http://littledan.github.io/simd.html
16
17namespace v8 {
18namespace internal {
19
20namespace {
21
22// Functions to convert Numbers to SIMD component types.
23
24template <typename T, typename F>
25static bool CanCast(F from) {
26 // A float can't represent 2^31 - 1 or 2^32 - 1 exactly, so promote the limits
27 // to double. Otherwise, the limit is truncated and numbers like 2^31 or 2^32
28 // get through, causing any static_cast to be undefined.
Ben Murdoch61f157c2016-09-16 13:49:30 +010029 from = trunc(from);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 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.
36template <>
37bool CanCast<float>(int32_t from) {
38 return true;
39}
40
41
42template <>
43bool CanCast<float>(uint32_t from) {
44 return true;
45}
46
47
48template <typename T>
49static T ConvertNumber(double number);
50
51
52template <>
53float ConvertNumber<float>(double number) {
54 return DoubleToFloat32(number);
55}
56
57
58template <>
59int32_t ConvertNumber<int32_t>(double number) {
60 return DoubleToInt32(number);
61}
62
63
64template <>
65uint32_t ConvertNumber<uint32_t>(double number) {
66 return DoubleToUint32(number);
67}
68
69
70template <>
71int16_t ConvertNumber<int16_t>(double number) {
72 return static_cast<int16_t>(DoubleToInt32(number));
73}
74
75
76template <>
77uint16_t ConvertNumber<uint16_t>(double number) {
78 return static_cast<uint16_t>(DoubleToUint32(number));
79}
80
81
82template <>
83int8_t ConvertNumber<int8_t>(double number) {
84 return static_cast<int8_t>(DoubleToInt32(number));
85}
86
87
88template <>
89uint8_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.
95inline float RecipApprox(float a) { return 1.0f / a; }
96
97
98// TODO(bbudge): Make this consistent with SIMD instruction results.
99inline float RecipSqrtApprox(float a) { return 1.0f / std::sqrt(a); }
100
101
102// Saturating addition for int16_t and int8_t.
103template <typename T>
104inline 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.
115template <typename T>
116inline 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
126inline 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
134inline 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
142inline 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
149inline 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
161RUNTIME_FUNCTION(Runtime_IsSimdValue) {
162 HandleScope scope(isolate);
163 DCHECK(args.length() == 1);
164 return isolate->heap()->ToBoolean(args[0]->IsSimd128Value());
165}
166
167
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168//-------------------------------------------------------------------
169
170// Utility macros.
171
Ben Murdoch61f157c2016-09-16 13:49:30 +0100172// 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);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000185
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
Ben Murdoch61f157c2016-09-16 13:49:30 +0100231#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))); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235 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
328SIMD_ALL_TYPES(SIMD_CREATE_FUNCTION)
329SIMD_ALL_TYPES(SIMD_EXTRACT_FUNCTION)
330SIMD_ALL_TYPES(SIMD_REPLACE_FUNCTION)
331SIMD_ALL_TYPES(SIMD_CHECK_FUNCTION)
332SIMD_ALL_TYPES(SIMD_SWIZZLE_FUNCTION)
333SIMD_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
389SIMD_ABS_FUNCTION(Float32x4, float, 4)
390SIMD_SQRT_FUNCTION(Float32x4, float, 4)
391SIMD_RECIP_APPROX_FUNCTION(Float32x4, float, 4)
392SIMD_RECIP_SQRT_APPROX_FUNCTION(Float32x4, float, 4)
393SIMD_DIV_FUNCTION(Float32x4, float, 4)
394SIMD_MINNUM_FUNCTION(Float32x4, float, 4)
395SIMD_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
Ben Murdoch61f157c2016-09-16 13:49:30 +0100411#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); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 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}; \
Ben Murdoch61f157c2016-09-16 13:49:30 +0100429 shift &= lane_bits - 1; \
430 for (int i = 0; i < kLaneCount; i++) { \
431 lanes[i] = a->get_lane(i) << shift; \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 } \
433 Handle<type> result = isolate->factory()->New##type(lanes); \
434 return *result; \
435 }
436
Ben Murdoch61f157c2016-09-16 13:49:30 +0100437#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; \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 }
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); \
Ben Murdoch61f157c2016-09-16 13:49:30 +0100461 shift &= lane_bits - 1; \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 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
471SIMD_INT_TYPES(SIMD_LSL_FUNCTION)
472SIMD_UINT_TYPES(SIMD_LSL_FUNCTION)
473SIMD_INT_TYPES(SIMD_ASR_FUNCTION)
474SIMD_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
515SIMD_BOOL_TYPES(SIMD_ANY_FUNCTION)
516SIMD_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
543SIMD_SMALL_INT_TYPES(SIMD_ADD_SATURATE_FUNCTION)
544SIMD_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
597SIMD_NUMERIC_TYPES(SIMD_ADD_FUNCTION)
598SIMD_NUMERIC_TYPES(SIMD_SUB_FUNCTION)
599SIMD_NUMERIC_TYPES(SIMD_MUL_FUNCTION)
600SIMD_NUMERIC_TYPES(SIMD_MIN_FUNCTION)
601SIMD_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
636SIMD_EQUALITY_TYPES(SIMD_EQUAL_FUNCTION)
637SIMD_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
667SIMD_RELATIONAL_TYPES(SIMD_LESS_THAN_FUNCTION)
668SIMD_RELATIONAL_TYPES(SIMD_LESS_THAN_OR_EQUAL_FUNCTION)
669SIMD_RELATIONAL_TYPES(SIMD_GREATER_THAN_FUNCTION)
670SIMD_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
723SIMD_LOGICAL_TYPES(SIMD_AND_FUNCTION)
724SIMD_LOGICAL_TYPES(SIMD_OR_FUNCTION)
725SIMD_LOGICAL_TYPES(SIMD_XOR_FUNCTION)
726SIMD_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
757SIMD_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
776SIMD_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); \
Ben Murdoch61f157c2016-09-16 13:49:30 +0100803 if (a_value != a_value || !CanCast<lane_type>(a_value)) { \
804 THROW_NEW_ERROR_RETURN_FAILURE( \
805 isolate, NewRangeError(MessageTemplate::kInvalidSimdLaneValue)); \
806 } \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000807 lanes[i] = static_cast<lane_type>(a_value); \
808 } \
809 Handle<type> result = isolate->factory()->New##type(lanes); \
810 return *result; \
811 }
812
813SIMD_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
871SIMD_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
Ben Murdoch61f157c2016-09-16 13:49:30 +0100883#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();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000894
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); \
Ben Murdoch61f157c2016-09-16 13:49:30 +0100901 SIMD_COERCE_INDEX(index, 1); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000902 size_t bpe = tarray->element_size(); \
903 uint32_t bytes = count * sizeof(lane_type); \
904 size_t byte_length = NumberToSize(isolate, tarray->byte_length()); \
Ben Murdoch61f157c2016-09-16 13:49:30 +0100905 if (index < 0 || index * bpe + bytes > byte_length) { \
906 THROW_NEW_ERROR_RETURN_FAILURE( \
907 isolate, NewRangeError(MessageTemplate::kInvalidSimdIndex)); \
908 } \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000917#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); \
Ben Murdoch61f157c2016-09-16 13:49:30 +0100922 SIMD_COERCE_INDEX(index, 1); \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000923 size_t bpe = tarray->element_size(); \
924 uint32_t bytes = count * sizeof(lane_type); \
925 size_t byte_length = NumberToSize(isolate, tarray->byte_length()); \
Ben Murdoch61f157c2016-09-16 13:49:30 +0100926 if (index < 0 || byte_length < index * bpe + bytes) { \
927 THROW_NEW_ERROR_RETURN_FAILURE( \
928 isolate, NewRangeError(MessageTemplate::kInvalidSimdIndex)); \
929 } \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000930 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000940#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
1004SIMD_NUMERIC_TYPES(SIMD_LOAD_FUNCTION)
1005SIMD_LOADN_STOREN_TYPES(SIMD_LOAD1_FUNCTION)
1006SIMD_LOADN_STOREN_TYPES(SIMD_LOAD2_FUNCTION)
1007SIMD_LOADN_STOREN_TYPES(SIMD_LOAD3_FUNCTION)
1008SIMD_NUMERIC_TYPES(SIMD_STORE_FUNCTION)
1009SIMD_LOADN_STOREN_TYPES(SIMD_STORE1_FUNCTION)
1010SIMD_LOADN_STOREN_TYPES(SIMD_STORE2_FUNCTION)
1011SIMD_LOADN_STOREN_TYPES(SIMD_STORE3_FUNCTION)
1012
1013//-------------------------------------------------------------------
1014
1015} // namespace internal
1016} // namespace v8