SIMD.js specification v0.9

Introduction

This proposal adds SIMD types and operations to ECMAScript. The proposal adds new primitive types Float32x4, etc, together with wrappers and a definition of their behavior in the language. The current proposal should form a full first draft with all functions and types included.

One problem that this spec aims to solve is to define equality for SIMD values. Before the spec was written, prior implementations used object identity-based equality. However, maintaining object identity puts a big burden on compilers to maintain this identity through operations, where they would rather be able to duplicate and de-duplicate SIMD values arbitrarily based on algebraic identities. By making SIMD values into primitive types with structural equality, compilers are given more freedom.

Ideally, SIMD values will fit into a larger value types proposal. Such a proposal would be a bit more involved, but good work has already been done in that direction. This document describes SIMD without a larger value type system, but it aims to be consistent with how value types might work, and once value types are described in more detail, it will be great to refactor this text by just explaining SIMD in terms of value types. On the other hand, this proposal gives a vehicle to work out some of the issues in value types and can be used as a guide for future value type designs.

This document is organized in terms of where changes would be made to the ES2015 spec. Although ecmarkup generates numbering at the beginning of headers, these won't correspond to the numbering within the existing ECMAScript spec, so I've included a matching numbering in parentheses afterwards, referring to the ES2015 spec.

In this text, SIMD is used to refer to the various SIMD types: Float32x4, Int32x4, Int16x8 Int8x16, Uint32x4, Uint16x8 Uint8x16, Bool32x4, Bool16x8 and Bool8x16. Similarly to Number, SIMD is used to refer to both the type and the wrapper constructor object. This looks a bit confusing, but it provides the most regularity, as an aim of this specification is to make SIMD types primitives that operate analogously to the existing primitives, rather than a new, exotic sort of thing. To reduce ambiguity, the wrapper constructor is usually referred to as SIMDConstructor, and the type is referred to as SIMDType. SIMD types are associated with a descriptor spec object, called SIMDDescriptor.

Please file any issues here! The authoritative copy of this file is in in the simd.js repo; to propose changes to this spec, please send pull requests against that repository. Daniel Ehrenberg (littledan) is responsible for watching for changes to that file, generating the output with ecmarkup and pushing it to the official rendered location.

Because this document is in spec order, rather than written for direct readability, the logical starting point is actually halfway down.

Related links:

Changelog:

1Terms and definitions (4.3)

1.1primitive value (4.3.2)

member of one of the types Undefined, Null, Boolean, Number, Symbol, String, or one of the SIMD types as defined in clause 6

1.2SIMD

a meta-variable ranging over all SIMD types, namely Float32x4, Int32x4, Int16x8 Int8x16, Uint32x4, Uint16x8, Uint8x16, Bool32x4, Bool16x8 and Bool8x16.

1.3SIMDDescriptor

The type descriptor for the particular SIMD type SIMD.

1.4SIMD types

family of types which each consist of a set of SIMD vector values. Note
For example, the Float32x4 type consists of the set of vectors of 4 32-bit floats.

1.5SIMD value

Member of a particular SIMD type. These values are represented as described in the SIMD section. SIMD values are primitives, and they are represented as records with two fields.

1.6SIMD object

For a particular SIMD type, a member of the Object type which has a [[SIMDData]] internal slot.

1.7SIMD type descriptor

A specification-internal record describing the behavior and properties of a SIMD type, described in the %SIMD% section. The meta-variable SIMDDescriptor ranges over type descriptors.

1.8SIMD boolean type

A SIMD type whose values are booleans, namely Bool32x4, Bool16x8 and Bool8x16.

1.9SIMD integer type

A SIMD type whose values are integers, namely Int32x4, Int16x8, Int8x16, Uint32x4, Uint16x8, and Uint8x16.

1.10SIMD floating-point type

A SIMD type whose values are floating-point numbers, namely Float32x4.

1.11SIMD signed integer type

A SIMD type whose values are signed integers, namely Int32x4, Int16x8 and Int8x16.

1.12SIMD unsigned integer type

A SIMD type whose values are unsigned integers, namely Uint32x4, Uint16x8, and Uint8x16.

2ECMAScript Data Types and Values (6)

2.1ECMAScript language types (6.1)

2.1.1The Object Type (6.1.7)

2.1.1.1Well-Known Intrinsic Objects (6.1.7.4)

Table 1: Well-known Intrinsic Objects
Intrinsic Name Global Name ECMAScript Language Association
%SIMD% SIMD The SIMD object
%SIMD_Float32x4% SIMD.Float32x4 The SIMD.Float32x4 constructor
%SIMD_Float32x4Prototype% SIMD.Float32x4.prototype The initial value of the prototype data property of %SIMD.Float32x4%
%SIMD_Int32x4% SIMD.Int32x4 The SIMD.Int32x4 constructor
%SIMD_Int32x4Prototype% SIMD.Int32x4.prototype The initial value of the prototype data property of %SIMD.Int32x4%
%SIMD_Int16x8% SIMD.Int16x8 The SIMD.Int16x8 constructor
%SIMD_Int16x8Prototype% SIMD.Int16x8.prototype The initial value of the prototype data property of %SIMD.Int16x8%
%SIMD_Int8x16% SIMD.Int8x16 The SIMD.Int8x16 constructor
%SIMD_Int8x16Prototype% SIMD.Int8x16.prototype The initial value of the prototype data property of %SIMD.Int8x16%
%SIMD_Uint32x4% SIMD.Uint32x4 The SIMD.Uint32x4 constructor
%SIMD_Uint32x4Prototype% SIMD.Uint32x4.prototype The initial value of the prototype data property of %SIMD.Uint32x4%
%SIMD_Uint16x8% SIMD.Uint16x8 The SIMD.Uint16x8 constructor
%SIMD_Uint16x8Prototype% SIMD.Uint16x8.prototype The initial value of the prototype data property of %SIMD.Uint16x8%
%SIMD_Uint8x16% SIMD.Uint8x16 The SIMD.Uint8x16 constructor
%SIMD_Uint8x16Prototype% SIMD.Uint8x16.prototype The initial value of the prototype data property of %SIMD.Uint8x16%
%SIMD_Bool32x4% SIMD.Bool32x4 The SIMD.Bool32x4 constructor
%SIMD_Bool32x4Prototype% SIMD.Bool32x4.prototype The initial value of the prototype data property of %SIMD.Bool32x4%
%SIMD_Bool16x8% SIMD.Bool16x8 The SIMD.Bool16x8 constructor
%SIMD_Bool16x8Prototype% SIMD.Bool16x8.prototype The initial value of the prototype data property of %SIMD.Bool16x8%
%SIMD_Bool8x16% SIMD.Bool8x16 The SIMD.Bool8x16 constructor
%SIMD_Bool8x16Prototype% SIMD.Bool8x16.prototype The initial value of the prototype data property of %SIMD.Bool8x16%

2.2SIMD types

A SIMD value is a homogeneous vector of Numbers or Booleans, possibly from a restricted range. Each SIMD value is represented as a record with the following immutable fields:
  • [[SIMDTypeDescriptor]], which refers to the type descriptor for the type.
  • [[SIMDElements]], which is a List of values representing the SIMD contents.
Note 1
The [[SIMDTypeDescriptor]] field effectively determines its type. The SIMD type descriptors are defined in a table.
Note 2
A list which is in the [[SIMDElements]] of a SIMD value field is never modified.
Note 3
[[SIMDElements]] is a list of Number values for integer and floating point SIMD types, and Boolean values for boolean SIMD types.
SIMD type descriptors are records with the following fields:
  • [[VectorLength]]: The number of elements present in a SIMD value of the type
  • [[ElementSize]]: Size in bytes of each element
  • [[Cast]]: An internal algorithm for down-casting a Number to the precision representable in the SIMD type
  • [[SerializeElement]]: An internal algorithm for writing a Number as [[ElementSize]] bytes
  • [[DeserializeElement]]: An internal algorithm for converting [[ElementSize]] bytes into a Number
  • [[ElementMax]]: The maximum value included in the range representable by the element type
  • [[ElementMin]]: The minimum value included in the range representable by the element type

Each SIMD type descriptor is listed in this table. All SIMD types are either integer SIMD types, boolean SIMD types or or floating point SIMD types. Certain operations are defined on either integer, boolean or floating point types, and integer types are be signed or unsigned, and this is noted in the table.

The [[ElementMax]], [[ElementMin]], [[ElementSize]], [[SerializeElement]] and [[DeserializeElement]] fields are optional, and defined only on certain SIMD types. Operations which use these fields have been defined only on the types which have them. Note 4
Many SIMD type descriptors have a [[Cast]] algorithm which outputs a Number. However, this Number is often in a restricted range, and implementations may use a different representation internally.

2.2.1Float32x4

Float32x4 is a SIMD type representing four 32-bit floating point values. Float32x4 values can be created using the [[Call]] operation on the SIMD.Float32x4 object. Its behavior as a SIMD type is defined by the Float32x4 SIMD type descriptor.

2.2.2Int32x4

Int32x4 is a SIMD type representing four 32-bit signed integer values. Int32x4 values can be created using the [[Call]] operation on the SIMD.Int32x4 object. Its behavior as a SIMD type is defined by the Int32x4 SIMD type descriptor.

2.2.3Int16x8

Int16x8 is a SIMD type representing eight 16-bit signed integer values. Int16x8 values can be created using the [[Call]] operation on the SIMD.Int16x8 object. Its behavior as a SIMD type is defined by the Int16x8 SIMD type descriptor.

2.2.4Int8x16

Int8x16 is a SIMD type representing sixteen 8-bit signed integer values. Int8x16 values can be created using the [[Call]] operation on the SIMD.Int8x16 object. Its behavior as a SIMD type is defined by the Int8x16 SIMD type descriptor.

2.2.5Uint32x4

Uint32x4 is a SIMD type representing four 32-bit unsigned integer values. Uint32x4 values can be created using the [[Call]] operation on the SIMD.Uint32x4 object. Its behavior as a SIMD type is defined by the Uint32x4 SIMD type descriptor.

2.2.6Uint16x8

Uint16x8 is a SIMD type representing eight 16-bit unsigned integer values. Uint16x8 values can be created using the [[Call]] operation on the SIMD.Uint16x8 object. Its behavior as a SIMD type is defined by the Uint16x8 SIMD type descriptor.

2.2.7Uint8x16

Uint8x16 is a SIMD type representing sixteen 8-bit unsigned integer values. Uint8x16 values can be created using the [[Call]] operation on the SIMD.Uint8x16 object. Its behavior as a SIMD type is defined by the Uint8x16 SIMD type descriptor.

2.2.8Bool32x4

Bool32x4 is a SIMD type representing four boolean values, as an intermediate value in manipulating 128-bit vectors. Bool32x4 values can be created using the [[Call]] operation on the SIMD.Bool32x4 object. Its behavior as a SIMD type is defined by the Bool32x4 SIMD type descriptor.

2.2.9Bool16x8

Bool16x8 is a SIMD type representing eight boolean values, as an intermediate value in manipulating 128-bit vectors. Bool16x8 values can be created using the [[Call]] operation on the SIMD.Bool16x8 object. Its behavior as a SIMD type is defined by the Bool16x8 SIMD type descriptor.

2.2.10Bool8x16

Bool8x16 is a SIMD type representing sixteen boolean values, as an intermediate value in manipulating 128-bit vectors. Bool8x16 values can be created using the [[Call]] operation on the SIMD.Bool8x16 object. Its behavior as a SIMD type is defined by the Bool8x16 SIMD type descriptor.

3Abstract Operations (7)

3.1Type Conversion (7.1)

3.1.1ToPrimitive ( input [, PreferredType] ) (7.1.1)

Argument type: SIMDType
Result: return input

3.1.2ToBoolean ( argument ) (7.1.2)

Argument type: SIMDType
Result: return true

3.1.3ToNumber ( argument ) (7.1.3)

Argument type: SIMDType
Result: throw a TypeError exception

3.1.4ToString ( argument ) (7.1.12)

Argument type: SIMDType
Result:
  1. Let elements be CreateArrayFromList(argument.[[SIMDElements]]).
  2. Let t be the string "SIMD", e.g., "Float32x4".
  3. Let e be ArrayJoin(elements, ", ").
  4. Return a new String value computed by concatenating the values "SIMD.", t, "(", e, and ")".
Note
On a SIMD vector v, eval(v.toString()) == v in the initial global environment, except that NaNs may be canonicalized.

3.1.5ToObject ( argument ) (7.1.13)

Argument type: SIMDType
Result: Return a new %SIMDConstructor% object whose [[SIMDData]] internal slot is set to argument.

3.2RequireObjectCoercible ( argument ) (7.2.1)

Argument type: SIMDType
Result: return argument

3.3SameValue(x, y) (7.2.9)

  1. ReturnIfAbrupt(x).
  2. ReturnIfAbrupt(y).
  3. If Type(x) is different from Type(y), return false.
  4. If Type(x) is Undefined, return true.
  5. If Type(x) is Null, return true.
  6. If Type(x) is Number, then
    1. If x is NaN and y is NaN, return true.
    2. If x is +0 and y is -0, return false.
    3. If x is -0 and y is +0, return false.
    4. If x is the same Number value as y, return true.
    5. Return false.
  7. If Type(x) is String, then
    1. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices) return true; otherwise, return false.
  8. If Type(x) is Boolean, then
    1. If x and y are both true or both false, return true; otherwise, return false.
  9. If Type(x) is Symbol, then
    1. If x and y are both the same Symbol value, return true; otherwise, return false.
  10. If Type(x) is a SIMD type SIMDType:
    1. For i from 0 to SIMDDescriptor.[[VectorLength]] - 1:
      1. If SameValue(SIMDExtractLane(x, i), SIMDExtractLane(y, i)) is false, return false.
    2. return true
  11. Return true if x and y are the same Object value. Otherwise, return false.

3.4SameValueZero(x, y) (7.2.10)

Add an extra step at the bottom of the definition of SameValueZero for the new case involving the new type:
  1. ReturnIfAbrupt(x).
  2. ReturnIfAbrupt(y).
  3. If Type(x) is different from Type(y), return false.
  4. If Type(x) is Undefined, return true.
  5. If Type(x) is Null, return true.
  6. If Type(x) is Number, then
    1. If x is NaN and y is NaN, return true.
    2. If x is +0 and y is -0, return true.
    3. If x is -0 and y is +0, return true.
    4. If x is the same Number value as y, return true.
    5. Return false.
  7. If Type(x) is String, then
    1. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices) return true; otherwise, return false.
  8. If Type(x) is Boolean, then
    1. If x and y are both true or both false, return true; otherwise, return false.
  9. If Type(x) is Symbol, then
    1. If x and y are both the same Symbol value, return true; otherwise, return false.
  10. If Type(x) is a SIMD type SIMDType:
    1. For i from 0 to SIMDDescriptor.[[VectorLength]] - 1:
      1. If SameValueZero(SIMDExtractLane(x, i), SIMDExtractLane(y, i)) is false, return false.
    2. return true
  11. Return true if x and y are the same Object value. Otherwise, return false.

3.5Abstract Equality Comparison (7.2.12)

Replace step 10 with the following:
  1. ReturnIfAbrupt(x).
  2. ReturnIfAbrupt(y).
  3. If Type(x) is the same as Type(y), then
    1. Return the result of performing Strict Equality Comparison x === y.
  4. If x is null and y is undefined, return true.
  5. If x is undefined and y is null, return true.
  6. If Type(x) is Number and Type(y) is String,
    return the result of the comparison x == ToNumber(y).
  7. If Type(x) is String and Type(y) is Number,
    return the result of the comparison ToNumber(x) == y.
  8. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
  9. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
  10. If Type(x) is either String, Number, any SIMDType, or Symbol and Type(y) is Object, then
    return the result of the comparison x == ToPrimitive(y).
  11. If Type(x) is Object and Type(y) is either String, Number, any SIMDType, or Symbol, then
    return the result of the comparison ToPrimitive(x) == y.
  12. Return false.

3.6Strict Equality Comparison (7.2.13)

Add a new step 9, before the existing step 9:
  1. ReturnIfAbrupt(x).
  2. ReturnIfAbrupt(y).
  3. If Type(x) is different from Type(y), return false.
  4. If Type(x) is Undefined, return true.
  5. If Type(x) is Null, return true.
  6. If Type(x) is Number, then
    1. If x is NaN, return false.
    2. If y is NaN, return false.
    3. If x is the same Number value as y, return true.
    4. If x is +0 and y is −0, return true.
    5. If x is −0 and y is +0, return true.
    6. Return false.
  7. If Type(x) is String, then
    1. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices) return true; otherwise, return false.
  8. If Type(x) is Boolean, then
    1. If x and y are both true or both false, return true; otherwise, return false.
  9. If Type(x) is Symbol, then
    1. If x and y are both the same Symbol value, return true; otherwise, return false.
  10. If Type(x) is SIMD type SIMDType:
    1. For i from 0 to SIMDDescriptor.[[VectorLength]] - 1:
      1. If SIMDExtractLane(x, i) === SIMDExtractLane(y, i) is false, return false.
    2. return true
  11. Return true if x and y are the same Object value. Otherwise, return false.

4The typeof Operator (12.5.6)

4.1Runtime Semantics: Evaluation (12.5.6.1)

Table 2: typeof Operator results
Type of valResult
Float32x4"float32x4"
Int32x4"int32x4"
Int16x8"int16x8"
Int8x16"int8x16"
Uint32x4"uint32x4"
Uint16x8"uint16x8"
Uint8x16"uint8x16"
Bool32x4"bool32x4"
Bool16x8"bool16x8"
Bool8x16"bool8x16"

5SIMD

The SIMD object is the %SIMD% intrinsic object and the initial value of the SIMD property of the global object. The SIMD object is an ordinary object.

The value of the [[Prototype]] internal slot of %SIMD% is the intrinsic object %ObjectPrototype% (19.1.3).

5.1Internal algorithms on SIMD types

5.1.1SIMDCreate( descriptor, vectorElements )

  1. Assert: descriptor is a SIMD type descriptor.
  2. Assert: vectorElements is a List.
  3. Assert: The length of vectorElements = descriptor.[[VectorLength]].
  4. Let list be a new List of length descriptor.[[VectorLength]].
  5. For i from 0 to descriptor.[[VectorLength]],
    1. Let n be descriptor.[[Cast]](vectorElements[i]).
    2. ReturnIfAbrupt(n).
    3. Set list[i] to n.
  6. Return the SIMD value specified by the record { [[SIMDTypeDescriptor]]: descriptor, [[SIMDElements]]: list }.

5.1.2SIMDToLane( max, lane )

  1. Let index be ToNumber(lane).
  2. ReturnIfAbrupt(index).
  3. If SameValueZero(index, ToLength(index)) is false or index < 0 or indexmax, throw a RangeError exception.
  4. Return index

5.1.3SIMDExtractLane( value, lane )

  1. Assert: Type(value) is a SIMDType.
  2. Let index be SIMDToLane(value.[[SIMDTypeDescriptor]].[[VectorLength]], lane).
  3. ReturnIfAbrupt(index).
  4. Return value.[[SIMDElements]][index]

5.1.4SIMDReplaceLane( value, lane, replacement )

  1. Assert: Type(value) is a SIMDType.
  2. Let descriptor be value.[[SIMDTypeDescriptor]].
  3. Let index be SIMDToLane(descriptor.[[VectorLength]], lane).
  4. ReturnIfAbrupt(index).
  5. Let list be a copy of value.[[SIMDElements]].
  6. Set list[index] to replacement.
  7. Return SIMDCreate(descriptor, list).

5.1.5MaybeFlushDenormal( n, descriptor )

Two possible internal algorithms are provided. The choice is implementation dependent and should be the alternative that is most efficient for the implementation. An implementation must use the same choice each time this step is executed.

The first option:
  1. Return n.
The second option:
  1. Let subnormal be false.
  2. If descriptor is Float32x4Descriptor, and if n rounded (ties to even) to a single-precision floating point number, in the IEEE 754-2008 single precision binary representation, is a subnormal value, let subnormal be true.
  3. Otherwise, assert descriptor is not a floating point SIMD type descriptor.
  4. If subnormal is true,
    1. If n > 0, return +0.
    2. Otherwise, return -0.
  5. Otherwise, return n.

5.1.6SIMDBinaryOp( a, b, op, outputDescriptor )

  1. Assert: a.[[SIMDTypeDescriptor]] and b.[[SIMDTypeDescriptor]] are the same SIMD type descriptor.
  2. Let descriptor be a.[[SIMDTypeDescriptor]].
  3. If outputDescriptor is not provided, let outputDescriptor be descriptor.
  4. Let list be a new List of length descriptor.[[VectorLength]].
  5. For i from 0 to descriptor.[[VectorLength]],
    1. Let ax = MaybeFlushDenormal(SIMDExtractLane(a, i), descriptor).
    2. Let bx = MaybeFlushDenormal(SIMDExtractLane(b, i), descriptor).
    3. Let res = op(ax, bx);
    4. ReturnIfAbrupt(res).
    5. Let res = MaybeFlushDenormal(res, outputDescriptor).
    6. Set list[i] to res.
  6. Return SIMDCreate(outputDescriptor, list).

5.1.7SIMDUnaryOp( a, op [ , flushDenormal ] )

  1. Let descriptor be a.[[SIMDTypeDescriptor]].
  2. If flushDenormal is not provided, let flushDenormal be true.
  3. Let list be a new List of length descriptor.[[VectorLength]].
  4. ReturnIfAbrupt(block).
  5. For i from 0 to descriptor.[[VectorLength]],
    1. Let ax = SIMDExtractLane(a, i).
    2. If flushDenormal, let ax be MaybeFlushDenormal(ax, descriptor).
    3. Let res = op(ax).
    4. ReturnIfAbrupt(res).
    5. If flushDenormal, let res be MaybeFlushDenormal(res, descriptor).
    6. Set list[i] to res.
  6. Return SIMDCreate(descriptor, list).

5.1.8SIMDScalarOp( a, scalar, op )

  1. Let descriptor be a.[[SIMDTypeDescriptor]].
  2. Assert: descriptor is not a floating point SIMD type.
  3. Let list be a new List of length descriptor.[[VectorLength]].
  4. ReturnIfAbrupt(block).
  5. For i from 0 to descriptor.[[VectorLength]],
    1. Let ax = SIMDExtractLane(a, i).
    2. Let res = op(ax, scalar).
    3. ReturnIfAbrupt(res).
    4. Set list[i] to res.
  6. Return SIMDCreate(descriptor, list).

5.1.9SIMDLoad( dataBlock, descriptor, byteOffset [, length] )

  1. Assert: dataBlock is a Data Block, descriptor is a SIMD type descriptor
  2. If length is not provided, let length be descriptor.[[VectorLength]]. Otherwise, assert lengthdescriptor.[[VectorLength]].
  3. Assert: byteOffset is an integer greater than or equal to zero, and less than or equal to the size of dataBlock - descriptor.[[ElementSize]] × length.
  4. Let list be a List of length descriptor.[[VectorLength]], initialized to all 0.
  5. For i from 0 to length - 1,
    1. Set list[i] to descriptor.[[DeserializeElement]](dataBlock, byteOffset + i × descriptor.[[ElementSize]]).
  6. Return the record { [[SIMDTypeDescriptor]]: descriptor, [[SIMDElements]]: list }.

5.1.10SIMDLoadFromTypedArray( tarray, index, descriptor [, length] )

  1. If tarray does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
  2. If length is not provided, let length be descriptor.[[VectorLength]]. Otherwise, assert lengthdescriptor.[[VectorLength]].
  3. If IsDetachedBuffer(tarray.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
  4. Let block be tarray.[[ViewedArrayBuffer]].[[ArrayBufferData]]
  5. If indexToLength(index), throw a TypeError exception.
  6. Let elementLength be tarray.[[ByteLength]] ÷ tarray.[[ArrayLength]].
  7. Let byteIndex be index × elementLength.
  8. If byteIndex + descriptor.[[ElementSize]] × length > tarray.[[ByteLength]] or byteIndex < 0, throw a RangeError exception.
  9. Return SIMDLoad(block, descriptor, byteIndex, length).

5.1.11SIMDStore( dataBlock, descriptor, byteOffset, n [, length] )

  1. Assert: dataBlock is a Data Block, descriptor is a SIMD type descriptor
  2. If length is not provided, let length be descriptor.[[VectorLength]]. Otherwise, assert lengthdescriptor.[[VectorLength]].
  3. Assert: byteOffset is an integer greater than or equal to zero, and less than or equal to the size of dataBlock - descriptor.[[ElementSize]] × length.
  4. For i from 0 to length - 1,
    1. descriptor.[[SerializeElement]](dataBlock, byteOffset + i × descriptor.[[ElementSize]], n.[[SIMDElements]][i]).

5.1.12SIMDStoreInTypedArray( tarray, index, descriptor, n [, length] )

  1. If n.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. If length is not provided, let length be descriptor.[[VectorLength]]. Otherwise, assert lengthdescriptor.[[VectorLength]].
  3. If IsDetachedBuffer(tarray.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
  4. If tarray does not have a [[ViewedArrayBuffer]] field, throw a TypeError exception.
  5. Let block be tarray.[[ViewedArrayBuffer]].[[ArrayBufferData]]
  6. If indexToLength(index), throw a TypeError exception.
  7. Let elementLength be tarray.[[ByteLength]] ÷ _tarray.[[ArrayLength]].
  8. Let byteIndex be index × elementLength.
  9. If byteIndex + SIMDDescriptor.[[ElementSize]] × length > tarray.[[ByteLength]] or byteIndex < 0, throw a RangeError exception.
  10. SIMDStore(block, SIMDDescriptor, byteIndex, simd, length).
  11. Return n.

5.1.13SIMDReinterpretCast( value, newDescriptor )

Note
This is used to define operations like SIMD.Float32x4.fromInt8x16Bits.
  1. Assert: value.[[SIMDTypeDescriptor]].[[VectorLength]] × value.[[SIMDTypeDescriptor]].[[ElementSize]] = newDescriptor.[[VectorLength]] × newDescriptor.[[ElementSize]].
  2. Let bytes be newDescriptor.[[VectorLength]] × newDescriptor.[[ElementSize]].
  3. Let block be the result of CreateByteDataBlock(bytes).
  4. ReturnIfAbrupt(block).
  5. SIMDStore(block, value, 0).
  6. Return SIMDLoad(block, newDescriptor, 0).

5.1.14SIMDBoolType( descriptor )

  1. Assert: descriptor.[[VectorLength]] × descriptor.[[ElementSize]] = 128. Otherwise, in a future extension to the spec, different boolean descriptors will be returned.
  2. Let length be descriptor.[[VectorLength]].
  3. If length = 4, return Bool32x4Descriptor.
  4. If length = 8, return Bool16x8Descriptor.
  5. Assert length = 16.
  6. Return Bool8x16Descriptor.

5.1.15SIMDRelationalOp( a, b, op )

  1. Let outputDescriptor be SIMDBoolType(a.[[SIMDTypeDescriptor]]).
  2. Return SIMDBinaryOp(a, b, op, outputDescriptor).

5.1.16MathAbs( x )

Returns the absolute value of x; the result has the same magnitude as x but has positive sign.
  • If x is NaN, the result is NaN.
  • If x is −0, the result is +0.
  • If x is −∞, the result is +∞.

5.1.17ToFloat32( argument )

  1. Let x be ToNumber(argument).
  2. ReturnIfAbrupt(x).
  3. If x is NaN, return NaN.
  4. If x is one of +0, −0, +∞, −∞, return x.
  5. Let x32 be the result of converting x to a value in IEEE 754-2008 binary32 format using roundTiesToEven.
  6. Let x64 be the result of converting x32 to a value in IEEE 754-2008 binary64 format.
  7. Return the ECMAScript Number value corresponding to x64.

5.1.18MathSqrt( x )

Returns an implementation-dependent approximation to the square root of x.
  • If x is NaN, the result is NaN.
  • If x is less than 0, the result is NaN.
  • If x is +0, the result is +0.
  • If x is −0, the result is −0.
  • If x is +∞, the result is +∞.

5.1.19MathImul(n, m)

  1. Let a be ToUint32(n).
  2. Let b be ToUint32(m).
  3. Let product be (a × b) modulo 232.
  4. If product ≥ 231, return product − 232, otherwise return product.

5.1.20MathMin(n, m)

Given two arguments, calls ToNumber on each of the arguments and returns the smaller of the resulting values.
  • If n or m is is NaN, the result is NaN.
  • The comparison of values to determine the smallest value is done using the Abstract Relational Comparison algorithm (7.2.11) except that +0 is considered to be larger than −0.

5.1.21MaxNum(n, m)

  1. Assert Type(n) is Number and Type(m) is Number.
  2. If n is NaN, return m.
  3. If m is NaN, return n.
  4. Let result be MathMax(n, m).
  5. ReturnIfAbrupt(result).
  6. Return result.

5.1.22MinNum(n, m)

  1. Assert Type(n) is Number and Type(m) is Number.
  2. If n is NaN, return m.
  3. If m is NaN, return n.
  4. Let result be MathMin(n, m).
  5. ReturnIfAbrupt(result).
  6. Return result.

5.1.23ReciprocalApproximation(n)

Returns an implementation-dependent approximation to the reciprocal of n.
  • If n is NaN, the result is NaN.
  • If n is +0, the result is +∞.
  • If n is -0, the result is -∞.
  • If n is +∞, the result is +0.
  • If n is -∞, the result is -0.

5.1.24ReciprocalSqrtApproximation(n)

Returns an implementation-dependent approximation to the reciprocal of the square root of n.
  • If n is NaN, the result is NaN.
  • If n is +0, the result is +∞.
  • If n is -0, the result is -∞.
  • If n is +∞, the result is +0.
  • If n is less than 0, the result is NaN.

5.1.25Saturate( descriptor, x )

  1. If x > descriptor.[[ElementMax]], return descriptor.[[ElementMax]].
  2. Otherwise, if x < descriptor.[[ElementMin]], return descriptor.[[ElementMin]]
  3. Return x.

5.1.26AddSaturate( descriptor )( x, y )

  1. Return Saturate(descriptor, x + y).

5.1.27SubSaturate( descriptor )( x, y )

  1. Return Saturate(descriptor, x - y).

5.1.28BitwiseOp( @ )( lval, rval )

  1. Let lnum be ToInt32(lval).
  2. ReturnIfAbrupt(lnum).
  3. Let rnum be ToInt32(rval).
  4. ReturnIfAbrupt(rnum).
  5. Return the result of applying the bitwise operator @ to lnum and rnum. The result is a signed 32 bit integer.

5.1.29ArrayJoin( array, separator )

  1. Let O be ToObject(array).
  2. ReturnIfAbrupt(O).
  3. Let len be ToLength(Get(O, "length")).
  4. ReturnIfAbrupt(len).
  5. If separator is undefined, let separator be the single-element String ",".
  6. Let sep be ToString(separator).
  7. ReturnIfAbrupt(sep).
  8. If len is zero, return the empty String.
  9. Let element0 be Get(O, "0").
  10. If element0 is undefined or null, let R be the empty String; otherwise, let R be ToString(element0).
  11. ReturnIfAbrupt(R).
  12. Let k be 1.
  13. Repeat, while k < len
    1. Let S be the String value produced by concatenating R and sep.
    2. Let element be Get(O, ToString(k)).
    3. If element is undefined or null, let next be the empty String; otherwise, let next be ToString(element).
    4. ReturnIfAbrupt(next).
    5. Let R be a String value produced by concatenating S and next.
    6. Increase k by 1.
  14. Return R.

5.2Constructor properties SIMDConstructor of the SIMD object

Each SIMDConstructor, namely Float32x4, Int32x4, Int16x8, Int8x16, Uint32x4, Uint16x8, Uint8x16, Bool32x4, Bool16x8, and Bool8x16, is associated with a SIMDType and SIMDDescriptor. This section describes the constructors and properties on them. Most properties are identical, existing separately defined on each constructor, with most differences being in the SIMDDescriptor. Certain functions are defined only on a subset of SIMDConstructors, however, and this is noted above their algorithm definition.

Each SIMD constructor is defined as a property of the SIMD object. For example, the constructor for Float32x4 is defined as the property SIMD.Float32x4.

The definitions of the constructor and properties of the constructor to follow constitute different identities of functions and objects for each of the copies; in a real implementation, they may call out to completely different pieces of code, even if their implementation in the spec is the same.

5.2.1SIMDConstructor( ...values )

Note
SIMD wrapped objects cannot be created using new on SIMDConstructor; they can be created explicitly with Object() however.
  1. If NewTarget is not undefined, throw a TypeError exception.
  2. Let fields be a new List.
  3. For integer n from 0 to SIMDDescriptor.[[VectorLength]],
    1. Append values[n] to the end of fields, or undefined if there were not enough arguments.
  4. Return SIMDCreate(SIMDDescriptor, fields).
The length property of _SIMD_Constructor is SIMDDescriptor.[[VectorLength]].

5.3Properties of the SIMDConstructor constructors

The value of the [[Prototype]] internal slot of SIMDConstructor is the intrinsic object %FunctionPrototype% (19.2.3).

The length property of SIMDConstructor is SIMDDescriptor.[[VectorLength]].

Each SIMDConstructor has the following properties:

5.3.1SIMDConstructor.splat(n)

  1. Let list be a new List of length SIMDDescriptor.[[VectorLength]], with all entries filled with n.
  2. Return SIMDCreate(SIMDDescriptor, list).

5.3.2SIMDConstructor.check(a)

  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Return a.

5.3.3SIMDConstructor.add(a, b)

This definition uses + to refer to the abstract operation defined by ES2015 12.7.3 (The Addition operator ( + )).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, +).
  3. ReturnIfAbrupt(result).
  4. Return result.
Note
On Float32x4, in this specification, the math is done on two 64-bit values which have a precise representation as a 32-bit float, and then rounded to a Float32. This is equivalent to doing the math on two 32-bit values and storing the result in a 32-bit float. For more information, see When is Double Rounding Innocuous?.

5.3.4SIMDConstructor.sub(a, b)

This definition uses - to refer to the abstract operation defined by ES2015 12.7.4 (The Subtraction operator ( - )).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, -).
  3. ReturnIfAbrupt(result).
  4. Return result.
Note
On Float32x4, in this specification, the math is done on two 64-bit values which have a precise representation as a 32-bit float, and then rounded to a Float32. This is equivalent to doing the math on two 32-bit values and storing the result in a 32-bit float. For more information, see When is Double Rounding Innocuous?.

5.3.5SIMDConstructor.mul(a, b)

This definition uses * to refer to the abstract operation defined by ES2015 12.6.3.1 (Applying the * Operator).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. If SIMDType is an integer SIMD type, let op be MathImul; otherwise, SIMDType is a floating point SIMD type, and let op be *.
  3. Let result be SIMDBinaryOp(a, b, op).
  4. ReturnIfAbrupt(result).
  5. Return result.
Note
On Float32x4, in this specification, the math is done on two 64-bit values which have a precise representation as a 32-bit float, and then rounded to a Float32. This is equivalent to doing the math on two 32-bit values and storing the result in a 32-bit float. For more information, see When is Double Rounding Innocuous?.

5.3.6SIMDConstructor.div(a, b)

This definition uses / to refer to the abstract operation defined by ES2015 12.6.3.2 (Applying the / Operator).

This operation is only defined on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, /).
  3. ReturnIfAbrupt(result).
  4. Return result.
Note
On Float32x4, in this specification, the math is done on two 64-bit values which have a precise representation as a 32-bit float, and then rounded to a Float32. This is equivalent to doing the math on two 32-bit values and storing the result in a 32-bit float. For more information, see When is Double Rounding Innocuous?.

5.3.7SIMDConstructor.max(a, b)

This operation is only defined on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, MathMax).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.8SIMDConstructor.min(a, b)

This property is defined only on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, MathMin).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.9SIMDConstructor.maxNum(a, b)

This operation is only defined on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, MaxNum).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.10SIMDConstructor.minNum(a, b)

This operation is only defined on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, MinNum).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.11SIMDConstructor.neg(a)

This definition uses unary - to refer to the abstract operation defined by ES2015 12.5.10 (Unary - Operator).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDUnaryOp(a, -, false).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.12SIMDConstructor.sqrt(a)

This operation is only defined on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDUnaryOp(a, MathSqrt).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.13SIMDConstructor.reciprocalApproximation(a)

This operation is only defined on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDUnaryOp(a, ReciprocalApproximation).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.14SIMDConstructor.reciprocalSqrtApproximation(a)

This operation is only defined on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDUnaryOp(a, ReciprocalSqrtApproximation).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.15SIMDConstructor.abs(a)

This operation is only defined on floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDUnaryOp(a, MathAbs, false).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.16SIMDConstructor.and(a, b)

This operation is only defined on integer and boolean SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, BitwiseOp(&)).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.17SIMDConstructor.xor(a, b)

This operation is only defined on integer and boolean SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, BitwiseOp(^)).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.18SIMDConstructor.or(a, b)

This operation is only defined on integer and boolean SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, BitwiseOp(|)).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.19SIMDConstructor.not(a)

This operation is only defined on integer and boolean SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDUnaryOp(a, ~).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.20SIMDConstructor.lessThan(a, b)

This definition uses < to refer to the abstract operation defined by ES2015 7.2.11 (Abstract Relational Comparison).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDRelationalOp(a, b, <).
  3. ReturnIfAbrupt(result).
  4. Return result.
Note
Due to the definition of SIMDRelationalOp, denormals will perform in this function as if they are equal to each other on some platforms, but not others.

5.3.21SIMDConstructor.lessThanOrEqual(a, b)

This definition uses <= to refer to the abstract operation defined by ES2015 7.2.11 (Abstract Relational Comparison).

This operation exists only on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDRelationalOp(a, b, <=).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.22SIMDConstructor.greaterThan(a, b)

This definition uses > to refer to the abstract operation defined by ES2015 7.2.11 (Abstract Relational Comparison).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDRelationalOp(a, b, >).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.23SIMDConstructor.greaterThanOrEqual(a, b)

This definition uses >= to refer to the abstract operation defined by ES2015 7.2.11 (Abstract Relational Comparison).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDRelationalOp(a, b, >=).
  3. ReturnIfAbrupt(result).
  4. Return result.

5.3.24SIMDConstructor.equal(a, b)

This definition uses === to refer to the abstract operation defined by ES2015 7.2.13 (Strict Equality Comparison).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDRelationalOp(a, b, ===).
  3. ReturnIfAbrupt(result).
  4. Return result.
Note
The resulting notion of equality is weaker than === on some platforms because denormals may be flushed to 0.

5.3.25SIMDConstructor.notEqual(a, b)

This definition uses !== to refer to the abstract operation defined by ES2015 7.2.13 (Strict Equality Comparison).

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDRelationalOp(a, b, !==).
  3. ReturnIfAbrupt(result).
  4. Return result.
Note
The resulting notion of equality is weaker than === on some platforms because denormals may be flushed to 0.

5.3.26SIMDConstructor.anyTrue(a)

This operation is only defined on boolean SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. For i from 0 to SIMDDescriptor.[[VectorLength]] - 1,
    1. If a.[[SIMDElements]][i] is true, return true.
  3. Return false.

5.3.27SIMDConstructor.allTrue(a)

This operation is only defined on boolean SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. For i from 0 to SIMDDescriptor.[[VectorLength]] - 1,
    1. If a.[[SIMDElements]][i] is false, return false.
  3. Return true.

5.3.28SIMDConstructor.select( selector, a, b )

This operation is only defined on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let outputDescriptor be SIMDBoolType(SIMDDescriptor).
  3. If selector.[[SIMDTypeDescriptor]] is not outputDescriptor, throw a TypeError exception.
  4. Let list be a new List.
  5. For i from 0 to SIMDDescriptor.[[VectorLength]] - 1,
    1. If sector.[[SIMDElements]][i] is true, let list[i] be a.[[SIMDElements]][i].
    2. Otherwise, let list[i] be b.[[SIMDElements]][i].
  6. Return SIMDCreate(SIMDDescriptor, list).

5.3.29SIMDConstructor.addSaturate( a, b )

This operation is only defined on integer SIMD types whose SIMDDescriptor.[[ElementSize]] ≤ 2.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, AddSaturate(a.[[SIMDTypeDescriptor]])).
  3. ReturnIfAbrupt(result).
  4. Return result.
Note
This operation is not defined on Uint32x4 and Int32x4 because it is not accelerated by current hardware on those types.

5.3.30SIMDConstructor.subSaturate( a, b )

This operation is only defined on integer SIMD types whose SIMDDescriptor.[[ElementSize]] ≤ 2.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor or b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let result be SIMDBinaryOp(a, b, SubSaturate(a.[[SIMDTypeDescriptor]])).
  3. ReturnIfAbrupt(result).
  4. Return result.
Note
This operation is not defined on Uint32x4 and Int32x4 because it is not accelerated by current hardware on those types.

5.3.31SIMDConstructor.shiftLeftByScalar( a, bits )

This operation is only defined on integer SIMD types. This definition uses << to refer to the abstract operation defined by ES2015 12.8.3 (The Left Shift Operator ( << )).
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let scalar be ToUint32(bits).
  3. Let shiftCount be scalar modulo (SIMDDescriptor.[[ElementSize]] × 8)
  4. Let result be SIMDScalarOp(a, shiftCount, <<).
  5. ReturnIfAbrupt(result).
  6. Return result.
Note
The "masked" shift count semantics matches the ECMAScript scalar shift semantics.

5.3.32SIMDConstructor.shiftRightByScalar( a, bits )

This operation is only defined on integer SIMD types. On unsigned SIMD types, the following definition is used. This definition uses >>> to refer to the abstract operation defined by ES2015 12.8.5 (The Unsigned Right Shift Operator ( >>> )).
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let scalar be ToUint32(bits).
  3. Let shiftCount be scalar modulo (SIMDDescriptor.[[ElementSize]] × 8)
  4. Let result be SIMDScalarOp(a, shiftCount, >>>).
  5. ReturnIfAbrupt(result).
  6. Return result.
On signed SIMD types, the following definition is used. This definition uses >> to refer to the abstract operation defined by ES2015 12.8.4 (The Signed Right Shift Operator ( >> )).
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let scalar be ToUint32(bits).
  3. Let shiftCount be scalar modulo (SIMDDescriptor.[[ElementSize]] × 8)
  4. Let result be SIMDScalarOp(a, shiftCount, >>).
  5. ReturnIfAbrupt(result).
  6. Return result.
Note
The "masked" shift count semantics matches the ECMAScript scalar shift semantics.

5.3.33SIMDConstructor.extractLane( simd, lane )

  1. If simd.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Return SIMDExtractLane(simd, lane).

5.3.34SIMDConstructor.replaceLane( simd, lane, value )

  1. If simd.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Return SIMDReplaceLane(simd, lane, value).

5.3.35SIMDConstructor.store( tarray, index, simd )

This is defined when SIMDDescriptor has a [[SerializeElement]] field.

This operation exists only on integer and floating point SIMD types.
  1. Return SIMDStoreInTypedArray(tarray, index, SIMDDescriptor, simd).

5.3.36SIMDConstructor.store1( tarray, index, simd )

This function is defined only on SIMD types where SIMDDescriptor.[[VectorLength]] = 4, and when SIMDDescriptor has a [[SerializeElement]] field.

This operation exists only on integer and floating point SIMD types.
  1. Return SIMDStoreInTypedArray(tarray, index, SIMDDescriptor, simd, 1).

5.3.37SIMDConstructor.store2( tarray, index, simd )

This function is defined only on SIMD types where SIMDDescriptor.[[VectorLength]] = 4, and when SIMDDescriptor has a [[SerializeElement]] field.

This operation exists only on integer and floating point SIMD types.
  1. Return SIMDStoreInTypedArray(tarray, index, SIMDDescriptor, simd, 2).

5.3.38SIMDConstructor.store3( tarray, index, simd )

This function is defined only on SIMD types where SIMDDescriptor.[[VectorLength]] = 4, and when SIMDDescriptor has a [[SerializeElement]] field.

This operation exists only on integer and floating point SIMD types.
  1. Return SIMDStoreInTypedArray(tarray, index, SIMDDescriptor, simd, 3).

5.3.39SIMDConstructor.load( tarray, index )

This function is defined only on SIMD types where SIMDDescriptor has a [[DeserializeElement]] field.

This operation exists only on integer and floating point SIMD types. Note
load takes a TypedArray of any element type as an argument. One way to use it is to pass in a Uint8Array regardless of SIMD type, which is useful because it allows the compiler to eliminate the shift in going from the index to the pointer offset. Other options considered were to use an ArrayBuffer (but this is not idiomatic, to take an ArrayBuffer directly as an argument to read off of) or a DataView (but DataViews don't tend to expose platform-dependent endianness, which is important here, and they tend to use methods on DataView.prototype, which are harder to optimize in an asm.js context).
  1. Return SIMDLoadFromTypedArray(tarray, index, SIMDDescriptor).

5.3.40SIMDConstructor.load1(tarray, index)

This function is defined only on SIMD types where SIMDDescriptor.[[VectorLength]] = 4 and SIMDDescriptor has a [[DeserializeElement]] field.

This operation exists only on integer and floating point SIMD types.
  1. Return SIMDLoadFromTypedArray(tarray, index, SIMDDescriptor, 1).

5.3.41SIMDConstructor.load2(tarray, index)

This function is defined only on SIMD types where SIMDDescriptor.[[VectorLength]] = 4 and SIMDDescriptor has a [[DeserializeElement]] field.

This operation exists only on integer and floating point SIMD types.
  1. Return SIMDLoadFromTypedArray(tarray, index, SIMDDescriptor, 2).

5.3.42SIMDConstructor.load3(tarray, index)

This function is defined only on SIMD types where SIMDDescriptor.[[VectorLength]] = 4 and SIMDDescriptor has a [[DeserializeElement]] field.

This operation exists only on integer and floating point SIMD types.
  1. Return SIMDLoadFromTypedArray(tarray, index, SIMDDescriptor, 3).

5.3.43SIMDConstructor.fromTIMDBits( value )

In this definition, TIMD is not SIMD, and TIMD ranges over all SIMD types for which SIMDDescriptor.[[ElementSize]] × SIMDDescriptor.[[VectorLength]] = TIMDDescriptor.[[ElementSize]] × TIMDDescriptor.[[VectorLength]], unless one descriptor does not have a [[SerializeElement]] field. Note
All of the SIMD types described in this spec are 16 bytes, but Booleans have no serialization, so all pairs of types which do not include Booleans are included.
  1. If value.[[SIMDTypeDescriptor]] is not TIMDDescriptor, throw a TypeError exception.
  2. Return SIMDReinterpretCast(value, SIMDDescriptor).

5.3.44SIMDConstructor.fromTIMD( value )

In this definition, TIMD is not SIMD, TIMD ranges over all SIMD types for which SIMDDescriptor.[[VectorLength]] = TIMDDescriptor.[[VectorLength]], neither of SIMD and TIMD are of boolean type, and SIMD and TIMD are not both integer types.
  1. If value.[[SIMDTypeDescriptor]] is not TIMDDescriptor, throw a TypeError exception.
  2. Let list be a copy of value.[[SIMDElements]].
  3. If SIMD is an integer type and TIMD is a floating point type,
    1. For element in list,
      1. If element is NaN, throw a RangeError exception.
      2. Let intElement be ToInteger(element).
      3. If intElement > SIMDDescriptor.[[ElementMax]] or intElement < SIMDDescriptor.[[ElementMin]], throw a RangeError exception.
  4. Return SIMDCreate(SIMDDescriptor, list).
Note
This definition uses < and > to refer to the abstract operation defined by ES2015 7.2.11 (Abstract Relational Comparison)

5.3.45SIMDConstructor.swizzle( a, ...lanes )

This operation exists only on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let indices be a new List.
  3. For integer n from 0 to SIMDDescriptor.[[VectorLength]],
    1. Let lane be lanes[i], or 0 if lanes is not long enough.
    2. Let index be SIMDToLane(value.[[SIMDTypeDescriptor]].[[VectorLength]], lane).
    3. ReturnIfAbrupt(index).
    4. Append index to the end of indices.
  4. Let fields be a new List of length SIMDDescriptor.[[VectorLength]].
  5. For i in from 0 to SIMDDescriptor.[[VectorLength]] - 1,
    1. Set fields[i] to SIMDExtractLane(a, indices[i])
  6. Return SIMDCreate(SIMDDescriptor, fields).
The length property of _SIMD_.swizzle is 1 + SIMDDescriptor.[[VectorLength]].

5.3.46SIMDConstructor.shuffle( a, b, ...lanes )

This operation exists only on integer and floating point SIMD types.
  1. If a.[[SIMDTypeDescriptor]] is not SIMDDescriptor, or if b.[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  2. Let indices be a new List.
  3. For integer n from 0 to SIMDDescriptor.[[VectorLength]],
    1. Let lane be lanes[i], or 0 if lanes is not long enough.
    2. Let index be SIMDToLane(SIMDDescriptor.[[VectorLength]] * 2, lane).
    3. ReturnIfAbrupt(index).
    4. Append index to the end of indices.
  4. Let fields be a new List of length SIMDDescriptor.[[VectorLength]].
  5. For i in from 0 to SIMDDescriptor.[[VectorLength]] - 1,
    1. Let idx be indices[i].
    2. If idxSIMDDescriptor.[[VectorLength]],
      1. Set fields[i] to SIMDExtractLane(b, idx - SIMDDescriptor.[[VectorLength]])
    3. Otherwise,
      1. Set fields[i] to SIMDExtractLane(a, idx)
  6. Return SIMDCreate(SIMDDescriptor, fields).
The length property of _SIMD_.shuffle is 2 + SIMDDescriptor.[[VectorLength]] * 2.

5.4The SIMDConstructor.prototype

5.4.1SIMDConstructor.prototype.constructor

The initial value of SIMDConstructor.prototype.constructor is the intrinsic object %SIMDConstructor%

5.4.2SIMDConstructor.prototype.valueOf()

  1. If this does not have a [[SIMDWrapperData]] internal slot, throw a TypeError exception.
  2. If this.[[SIMDWrapperData]].[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  3. Return this.[[SIMDWrapperData]].

5.4.3SIMDConstructor.prototype.toLocaleString( [ reserved1 [, reserved2 ] )

An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the TypedArray.prototype.toLocaleString method as specified in the ECMA-402 specification. If an ECMAScript implementation does not include the ECMA-402 API the following specification of the toLocaleString method is used. Note
The first and second editions of ECMA-402 did not include a replacement specification for the TypedArray.prototype.toLocaleString method.
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
  1. If this does not have a [[SIMDWrapperData]] internal slot, throw a TypeError exception.
  2. If this.[[SIMDWrapperData]].[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  3. Let separator be the String value for the list-separator String appropriate for the host environment’s current locale (this is derived in an implementation-defined way).
  4. Let list be an empty List
  5. For each element element in argument.[[SIMDElements]],
    1. Let R be ToString(Invoke(element, "toLocaleString")).
    2. ReturnIfAbrupt(R).
    3. Append R to list.
  6. Let results be CreateArrayFromList(list).
  7. Let t be the string "SIMD", e.g., "Float32x4".
  8. Let e be ArrayJoin(results, separator).
  9. Return a new String value computed by concatenating the previous value of t, "(", e, and ")".

5.4.4SIMDConstructor.prototype.toString()

  1. If this does not have a [[SIMDWrapperData]] internal slot, throw a TypeError exception.
  2. If this.[[SIMDWrapperData]].[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  3. Return ToString(this.[[SIMDWrapperData]]).
Note
This definition depends on the primitive SIMDType's behavior under ToString. Alternatively, SIMDType could have ToString defined by calling ToObject and then reaching this method (or whatever the user overrides it with), in which case the current definition in ToString would be brought down here.

5.4.5SIMDConstructor.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "SIMD.SIMD", e.g., "SIMD.Float32x4".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

5.4.6SIMDConstructor.prototype [ @@toPrimitive ] ( hint )

Note
This function is called by ECMAScript language operators to convert a Symbol object to a primitive value. The allowed values for hint are "default", "number", and "string".
When the @@toPrimitive method is called with argument hint, the following steps are taken:
  1. Let s be the this value.
  2. If Type(s) is a SIMD type, return s.
  3. If Type(s) is not Object, throw a TypeError exception.
  4. If s does not have a [[SIMDWrapperData]] internal slot, throw a TypeError exception.
  5. If s.[[SIMDWrapperData]].[[SIMDTypeDescriptor]] is not SIMDDescriptor, throw a TypeError exception.
  6. Return the value of s’s [[SIMDWrapperData]] internal slot.

The value of the name property of this function is "[Symbol.toPrimitive]".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

5.5SIMD type descriptors

This section describes the SIMD type descriptors, which are organized as described in the %SIMD% section. The following internal algorithms support the definition of the SIMD types.

In the internal algorithms in this section, preceding the first step, if isLittleEndian is not present, set isLittleEndian to either true or false. The choice is implementation dependent and should be the alternative that is most efficient for the implementation. An implementation must use the same value each time one of the following algorithms is executed, and it must be consistent across all algorithms.

5.5.1SerializeFloat32( block, offset, n, isLittleEndian )

Note
Derived from part of SetValueInBuffer. Note that this specification does not require a particular bit pattern for NaN, and that it does not need to be the same across calls.
  1. Assert: block is a Data Block.
  2. Assert: offset is a number.
  3. Assert: n is a number.
  4. Assert: offset + 4 is less than or equal to the size of block.
  5. Set rawBytes to a List containing the 4 bytes that are the result of converting value to IEEE 754-2008 binary32 format using “Round to nearest, ties to even” rounding mode. If isLittleEndian is false, the bytes are arranged in big endian order. Otherwise, the bytes are arranged in little endian order. If value is NaN, rawValue may be set to any implementation chosen NaN encoding. An implementation must always choose the same NaN encoding for a distinct Not-a-Number value.
  6. Store the individual bytes of rawBytes into block, in order, starting at block[offset].

5.5.2DeserializeFloat32( block, offset, isLittleEndian )

Note
Derived from part of GetValueFromBuffer. Note that while this says to return "the NaN value", the binary representation is not observable and canonicalization is not required.
  1. Assert: block is a Data Block.
  2. Assert: offset is a number.
  3. Assert: offset + 4 is less than or equal to the size of block.
  4. Let rawValue be a List of 4 containing, in order, the sequence of 4 bytes starting with block[offset].
  5. If isLittleEndian is false, reverse the order of the elements of rawValue.
  6. Let value be the byte elements of rawValue concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2008 binary32 value.
  7. If value is an IEEE 754-2008 binary32 NaN value, return the NaN Number value.
  8. Return the Number value that corresponds to value.

5.5.3SerializeInt( descriptor )( block, offset, n, isLittleEndian )

Note
Derived from part of SetValueInBuffer.
  1. Assert: block is a Data Block.
  2. Assert: offset is a number.
  3. Assert: n is a number.
  4. Assert: n = descriptor.[[Cast]](n).
  5. Assert: offset + descriptor.[[ElementSize]] is less than or equal to the size of block.
  6. Let rawBytes be a List containing the descriptor.[[ElementSize]]-byte binary 2’s complement encoding of n. If isLittleEndian is false, the bytes are ordered in big endian order. Otherwise, the bytes are ordered in little endian order.
  7. Store the individual bytes of rawBytes into block, in order, starting at block[offset].

5.5.4DeserializeInt( descriptor )( block, offset, isLittleEndian )

Note
Derived from part of GetValueFromBuffer.
  1. Assert: block is a Data Block.
  2. Assert: offset is a number.
  3. Assert: offset + descriptor.[[ElementSize]] is less than or equal to the size of block.
  4. Let rawValue be a List of descriptor.[[ElementSize]] containing, in order, the sequence of descriptor.[[ElementSize]] bytes starting with block[offset].
  5. If isLittleEndian is false, reverse the order of the elements of rawValue.
  6. Let intValue be the byte elements of rawValue concatenated and interpreted as a bit string encoding of an integer of bit length descriptor.[[ElementSize]] × 8. If descriptor is a signed type, interpret as signed 2's complement; if it is unsigned, interpret as an unsigned integer.
  7. Return the Number value that corresponds to intValue.
Table 3: SIMD type descriptors
Name Kind of SIMD value [[VectorLength]] [[ElementSize]] [[Cast]] [[SerializeElement]] [[DeserializeElement]] [[ElementMax]] [[ElementMin]]
Float32x4 floating-point 4 4 ToFloat32 SerializeFloat32 DeserializeFloat32
Int32x4 signed integer 4 4 ToInt32 SerializeInt(Int32x4Descriptor) DeserializeInt(Int32x4Descriptor) 231-1 -231
Int16x8 signed integer 8 2 ToInt16 SerializeInt(Int16x8Descriptor) DeserializeInt(Int16x8Descriptor) 215-1 -215
Int8x16 signed integer 16 1 ToInt8 SerializeInt(Int8x16Descriptor) DeserializeInt(Int8x16Descriptor) 127 -128
Uint32x4 unsigned integer 4 4 ToUint32 SerializeInt(Uint32x4Descriptor) DeserializeInt(Uint32x4Descriptor) 232-1 0
Uint16x8 unsigned integer 8 2 ToUint16 SerializeInt(Uint16x8Descriptor) DeserializeInt(Uint16x8Descriptor) 216-1 0
Uint8x16 unsigned integer 16 1 ToUint8 SerializeInt(Uint8x16Descriptor) DeserializeInt(Uint8x16Descriptor) 255 0
Bool32x4 boolean 4 ToBoolean
Bool16x8 boolean 8 ToBoolean
Bool8x16 boolean 16 ToBoolean