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