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.
5 #include "src/runtime/runtime-utils.h"
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"
13 // Implement Single Instruction Multiple Data (SIMD) operations as defined in
14 // the SIMD.js draft spec:
15 // http://littledan.github.io/simd.html
22 // Functions to convert Numbers to SIMD component types.
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());
34 // Explicitly specialize for conversions to float, which always succeed.
36 bool CanCast<float>(int32_t from) {
42 bool CanCast<float>(uint32_t from) {
48 static T ConvertNumber(double number);
52 float ConvertNumber<float>(double number) {
53 return DoubleToFloat32(number);
58 int32_t ConvertNumber<int32_t>(double number) {
59 return DoubleToInt32(number);
64 uint32_t ConvertNumber<uint32_t>(double number) {
65 return DoubleToUint32(number);
70 int16_t ConvertNumber<int16_t>(double number) {
71 return static_cast<int16_t>(DoubleToInt32(number));
76 uint16_t ConvertNumber<uint16_t>(double number) {
77 return static_cast<uint16_t>(DoubleToUint32(number));
82 int8_t ConvertNumber<int8_t>(double number) {
83 return static_cast<int8_t>(DoubleToInt32(number));
88 uint8_t ConvertNumber<uint8_t>(double number) {
89 return static_cast<uint8_t>(DoubleToUint32(number));
93 // TODO(bbudge): Make this consistent with SIMD instruction results.
94 inline float RecipApprox(float a) { return 1.0f / a; }
97 // TODO(bbudge): Make this consistent with SIMD instruction results.
98 inline float RecipSqrtApprox(float a) { return 1.0f / std::sqrt(a); }
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;
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);
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;
133 inline float Min(float a, float b) {
136 if (a == b) return std::signbit(a) ? a : b;
137 return std::numeric_limits<float>::quiet_NaN();
141 inline float Max(float a, float b) {
144 if (a == b) return std::signbit(b) ? a : b;
145 return std::numeric_limits<float>::quiet_NaN();
149 inline float MinNumber(float a, float b) {
150 if (std::isnan(a)) return b;
151 if (std::isnan(b)) return a;
156 inline float MaxNumber(float a, float b) {
157 if (std::isnan(a)) return b;
158 if (std::isnan(b)) return a;
164 //-------------------------------------------------------------------
166 // SIMD helper functions.
168 RUNTIME_FUNCTION(Runtime_IsSimdValue) {
169 HandleScope scope(isolate);
170 DCHECK(args.length() == 1);
171 return isolate->heap()->ToBoolean(args[0]->IsSimd128Value());
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();
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);
192 RUNTIME_FUNCTION(Runtime_SimdSameValue) {
193 HandleScope scope(isolate);
194 DCHECK(args.length() == 2);
195 CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0);
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));
204 result = a->BitwiseEquals(b);
208 return isolate->heap()->ToBoolean(result);
212 RUNTIME_FUNCTION(Runtime_SimdSameValueZero) {
213 HandleScope scope(isolate);
214 DCHECK(args.length() == 2);
215 CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0);
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));
224 result = a->BitwiseEquals(b);
228 return isolate->heap()->ToBoolean(result);
232 //-------------------------------------------------------------------
236 #define CONVERT_SIMD_LANE_ARG_CHECKED(name, index, lanes) \
237 CONVERT_INT32_ARG_CHECKED(name, index); \
238 RUNTIME_ASSERT(name >= 0 && name < lanes);
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)); \
248 Handle<type> result = isolate->factory()->New##type(lanes);
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)); \
259 Handle<type> result = isolate->factory()->New##type(lanes);
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); \
270 Handle<bool_type> result = isolate->factory()->New##bool_type(lanes);
272 //-------------------------------------------------------------------
276 #define GET_NUMERIC_ARG(lane_type, name, index) \
277 CONVERT_NUMBER_ARG_HANDLE_CHECKED(a, index); \
278 name = ConvertNumber<lane_type>(a->Number());
280 #define GET_BOOLEAN_ARG(lane_type, name, index) \
281 name = args[index]->BooleanValue();
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)
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) \
304 return *isolate->factory()->New##type(lanes); \
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)); \
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); \
327 replace(lane_type, lanes[lane], 2); \
328 Handle<type> result = isolate->factory()->New##type(lanes); \
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); \
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); \
350 Handle<type> result = isolate->factory()->New##type(lanes); \
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); \
367 Handle<type> result = isolate->factory()->New##type(lanes); \
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)
378 //-------------------------------------------------------------------
380 // Float-only functions.
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); \
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); \
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); \
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); \
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); \
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); \
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); \
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)
440 //-------------------------------------------------------------------
442 // Int-only functions.
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)
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)
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);
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; \
473 Handle<type> result = isolate->factory()->New##type(lanes); \
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); \
491 Handle<type> result = isolate->factory()->New##type(lanes); \
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); \
508 Handle<type> result = isolate->factory()->New##type(lanes); \
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); \
518 for (int i = 0; i < lane_count; i++) { \
519 sum += a->get_lane(i); \
521 return *isolate->factory()->NewNumber(sum); \
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)
530 //-------------------------------------------------------------------
532 // Bool-only functions.
534 #define SIMD_BOOL_TYPES(FUNCTION) \
535 FUNCTION(Bool32x4, 4) \
536 FUNCTION(Bool16x8, 8) \
537 FUNCTION(Bool8x16, 16)
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)) { \
551 return isolate->heap()->ToBoolean(result); \
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)) { \
566 return isolate->heap()->ToBoolean(result); \
569 SIMD_BOOL_TYPES(SIMD_ANY_FUNCTION)
570 SIMD_BOOL_TYPES(SIMD_ALL_FUNCTION)
572 //-------------------------------------------------------------------
574 // Small Int-only functions.
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)
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); \
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); \
597 SIMD_SMALL_INT_TYPES(SIMD_ADD_SATURATE_FUNCTION)
598 SIMD_SMALL_INT_TYPES(SIMD_SUB_SATURATE_FUNCTION)
600 //-------------------------------------------------------------------
602 // Small Unsigned int-only functions.
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)
608 #define SIMD_ABS_DIFF_FUNCTION(type, lane_type, lane_count, wide_type, \
610 RUNTIME_FUNCTION(Runtime_##type##AbsoluteDifference) { \
611 HandleScope scope(isolate); \
612 SIMD_BINARY_OP(type, lane_type, lane_count, AbsoluteDifference, result); \
616 #define SIMD_WIDE_ABS_DIFF_FUNCTION(type, lane_type, lane_count, wide_type, \
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)); \
628 Handle<wide_type> result = isolate->factory()->New##wide_type(lanes); \
632 SIMD_SMALL_UINT_TYPES(SIMD_ABS_DIFF_FUNCTION)
633 SIMD_SMALL_UINT_TYPES(SIMD_WIDE_ABS_DIFF_FUNCTION)
635 //-------------------------------------------------------------------
637 // Numeric functions.
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)
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); \
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); \
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); \
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); \
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); \
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)
692 //-------------------------------------------------------------------
694 // Relational functions.
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)
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)
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); \
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); \
725 SIMD_EQUALITY_TYPES(SIMD_EQUAL_FUNCTION)
726 SIMD_EQUALITY_TYPES(SIMD_NOT_EQUAL_FUNCTION)
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); \
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); \
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); \
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); \
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)
761 //-------------------------------------------------------------------
763 // Logical functions.
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)
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); \
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); \
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); \
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); \
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)
817 //-------------------------------------------------------------------
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)
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); \
842 Handle<type> result = isolate->factory()->New##type(lanes); \
846 SIMD_SELECT_TYPES(SIMD_SELECT_FUNCTION)
848 //-------------------------------------------------------------------
850 // Signed / unsigned functions.
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)
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); \
865 SIMD_SIGNED_TYPES(SIMD_NEG_FUNCTION)
867 //-------------------------------------------------------------------
869 // Casting functions.
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)
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); \
896 Handle<type> result = isolate->factory()->New##type(lanes); \
900 SIMD_FROM_TYPES(SIMD_FROM_FUNCTION)
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)
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); \
958 SIMD_FROM_BITS_TYPES(SIMD_FROM_BITS_FUNCTION)
960 } // namespace internal