1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/runtime/runtime-utils.h" 6 7 #include "src/arguments.h" 8 #include "src/base/macros.h" 9 #include "src/conversions.h" 10 #include "src/factory.h" 11 #include "src/objects-inl.h" 12 13 // Implement Single Instruction Multiple Data (SIMD) operations as defined in 14 // the SIMD.js draft spec: 15 // http://littledan.github.io/simd.html 16 17 namespace v8 { 18 namespace internal { 19 20 namespace { 21 22 // Functions to convert Numbers to SIMD component types. 23 24 template <typename T, typename F> 25 static bool CanCast(F from) { 26 // A float can't represent 2^31 - 1 or 2^32 - 1 exactly, so promote the limits 27 // to double. Otherwise, the limit is truncated and numbers like 2^31 or 2^32 28 // get through, causing any static_cast to be undefined. 29 return from >= static_cast<double>(std::numeric_limits<T>::min()) && 30 from <= static_cast<double>(std::numeric_limits<T>::max()); 31 } 32 33 34 // Explicitly specialize for conversions to float, which always succeed. 35 template <> 36 bool CanCast<float>(int32_t from) { 37 return true; 38 } 39 40 41 template <> 42 bool CanCast<float>(uint32_t from) { 43 return true; 44 } 45 46 47 template <typename T> 48 static T ConvertNumber(double number); 49 50 51 template <> 52 float ConvertNumber<float>(double number) { 53 return DoubleToFloat32(number); 54 } 55 56 57 template <> 58 int32_t ConvertNumber<int32_t>(double number) { 59 return DoubleToInt32(number); 60 } 61 62 63 template <> 64 uint32_t ConvertNumber<uint32_t>(double number) { 65 return DoubleToUint32(number); 66 } 67 68 69 template <> 70 int16_t ConvertNumber<int16_t>(double number) { 71 return static_cast<int16_t>(DoubleToInt32(number)); 72 } 73 74 75 template <> 76 uint16_t ConvertNumber<uint16_t>(double number) { 77 return static_cast<uint16_t>(DoubleToUint32(number)); 78 } 79 80 81 template <> 82 int8_t ConvertNumber<int8_t>(double number) { 83 return static_cast<int8_t>(DoubleToInt32(number)); 84 } 85 86 87 template <> 88 uint8_t ConvertNumber<uint8_t>(double number) { 89 return static_cast<uint8_t>(DoubleToUint32(number)); 90 } 91 92 93 // TODO(bbudge): Make this consistent with SIMD instruction results. 94 inline float RecipApprox(float a) { return 1.0f / a; } 95 96 97 // TODO(bbudge): Make this consistent with SIMD instruction results. 98 inline float RecipSqrtApprox(float a) { return 1.0f / std::sqrt(a); } 99 100 101 // Saturating addition for int16_t and int8_t. 102 template <typename T> 103 inline T AddSaturate(T a, T b) { 104 const T max = std::numeric_limits<T>::max(); 105 const T min = std::numeric_limits<T>::min(); 106 int32_t result = a + b; 107 if (result > max) return max; 108 if (result < min) return min; 109 return result; 110 } 111 112 113 // Saturating subtraction for int16_t and int8_t. 114 template <typename T> 115 inline 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 125 inline 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 133 inline 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 141 inline 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 148 inline 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 160 RUNTIME_FUNCTION(Runtime_IsSimdValue) { 161 HandleScope scope(isolate); 162 DCHECK(args.length() == 1); 163 return isolate->heap()->ToBoolean(args[0]->IsSimd128Value()); 164 } 165 166 167 RUNTIME_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 187 RUNTIME_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 355 SIMD_ALL_TYPES(SIMD_CREATE_FUNCTION) 356 SIMD_ALL_TYPES(SIMD_EXTRACT_FUNCTION) 357 SIMD_ALL_TYPES(SIMD_REPLACE_FUNCTION) 358 SIMD_ALL_TYPES(SIMD_CHECK_FUNCTION) 359 SIMD_ALL_TYPES(SIMD_SWIZZLE_FUNCTION) 360 SIMD_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 416 SIMD_ABS_FUNCTION(Float32x4, float, 4) 417 SIMD_SQRT_FUNCTION(Float32x4, float, 4) 418 SIMD_RECIP_APPROX_FUNCTION(Float32x4, float, 4) 419 SIMD_RECIP_SQRT_APPROX_FUNCTION(Float32x4, float, 4) 420 SIMD_DIV_FUNCTION(Float32x4, float, 4) 421 SIMD_MINNUM_FUNCTION(Float32x4, float, 4) 422 SIMD_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 496 SIMD_INT_TYPES(SIMD_LSL_FUNCTION) 497 SIMD_UINT_TYPES(SIMD_LSL_FUNCTION) 498 SIMD_INT_TYPES(SIMD_ASR_FUNCTION) 499 SIMD_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 540 SIMD_BOOL_TYPES(SIMD_ANY_FUNCTION) 541 SIMD_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 568 SIMD_SMALL_INT_TYPES(SIMD_ADD_SATURATE_FUNCTION) 569 SIMD_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 622 SIMD_NUMERIC_TYPES(SIMD_ADD_FUNCTION) 623 SIMD_NUMERIC_TYPES(SIMD_SUB_FUNCTION) 624 SIMD_NUMERIC_TYPES(SIMD_MUL_FUNCTION) 625 SIMD_NUMERIC_TYPES(SIMD_MIN_FUNCTION) 626 SIMD_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 661 SIMD_EQUALITY_TYPES(SIMD_EQUAL_FUNCTION) 662 SIMD_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 692 SIMD_RELATIONAL_TYPES(SIMD_LESS_THAN_FUNCTION) 693 SIMD_RELATIONAL_TYPES(SIMD_LESS_THAN_OR_EQUAL_FUNCTION) 694 SIMD_RELATIONAL_TYPES(SIMD_GREATER_THAN_FUNCTION) 695 SIMD_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 748 SIMD_LOGICAL_TYPES(SIMD_AND_FUNCTION) 749 SIMD_LOGICAL_TYPES(SIMD_OR_FUNCTION) 750 SIMD_LOGICAL_TYPES(SIMD_XOR_FUNCTION) 751 SIMD_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 782 SIMD_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 801 SIMD_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 836 SIMD_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 894 SIMD_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 1012 SIMD_NUMERIC_TYPES(SIMD_LOAD_FUNCTION) 1013 SIMD_LOADN_STOREN_TYPES(SIMD_LOAD1_FUNCTION) 1014 SIMD_LOADN_STOREN_TYPES(SIMD_LOAD2_FUNCTION) 1015 SIMD_LOADN_STOREN_TYPES(SIMD_LOAD3_FUNCTION) 1016 SIMD_NUMERIC_TYPES(SIMD_STORE_FUNCTION) 1017 SIMD_LOADN_STOREN_TYPES(SIMD_STORE1_FUNCTION) 1018 SIMD_LOADN_STOREN_TYPES(SIMD_STORE2_FUNCTION) 1019 SIMD_LOADN_STOREN_TYPES(SIMD_STORE3_FUNCTION) 1020 1021 //------------------------------------------------------------------- 1022 1023 } // namespace internal 1024 } // namespace v8 1025