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 _SIMD_Constructor, and the type is referred to as _SIMD_Type. SIMD types are associated with a descriptor spec object, called _SIMD_Descriptor.

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:

Terms and definitions (4.3)

primitive 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

_SIMD_

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

_SIMD_Descriptor

The type descriptor for the particular SIMD type _SIMD_.

SIMD types

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

SIMD 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.

SIMD object

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

SIMD type descriptor

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

SIMD boolean type

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

SIMD integer type

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

SIMD floating-point type

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

SIMD signed integer type

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

SIMD unsigned integer type

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

ECMAScript Data Types and Values (6)

ECMAScript language types (6.1)

The Object Type (6.1.7)

Well-Known Intrinsic Objects (6.1.7.4)

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%

SIMD types

A SIMD value is a homogeneous vector of a Numbers or Booleans, possibly from a restricted range. Each SIMD value is represented as a record with the following immutable fields: The [[SIMDTypeDescriptor]] field effectively determines its type. The SIMD type descriptors are defined in a table. A list which is in the [[SIMDElements]] of a SIMD value field is never modified. SIMD type descriptors are records with the following fields:

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. 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.

Float32x4

`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.

Int32x4

`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.

Int16x8

`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.

Int8x16

`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.

Uint32x4

`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.

Uint16x8

`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.

Uint8x16

`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.

Bool32x4

`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.

Bool16x8

`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.

Bool8x16

`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.

Abstract Operations (7)

Type Conversion (7.1)

ToPrimitive ( input [, PreferredType] ) (7.1.1)

Argument type: _SIMD_Type
Result: return _input_

ToBoolean ( argument ) (7.1.2)

Argument type: _SIMD_Type
Result: return *true*

ToNumber ( argument ) (7.1.3)

Argument type: _SIMD_Type
Result: throw a *TypeError* exception

ToString ( argument ) (7.1.12)

Argument type: _SIMD_Type
Result: 1. Let _elements_ be CreateArrayFromList(_argument_.[[SIMDElements]]). 1. Let _t_ be the string `"`SIMD`"`, e.g., `"Float32x4"`. 1. Let e be ArrayJoin(_elements_, ", "). 1. Return a new String value computed by concatenating the values "SIMD.", _t_, "(", _e_, and ")". On a SIMD vector v, `eval(v.toString()) == v` in the initial global environment, except that NaNs may be canonicalized.

ToObject ( argument ) (7.1.13)

Argument type: _SIMD_Type
Result: Return a new %_SIMD_Constructor% object whose [[SIMDData]] internal slot is set to _argument_.

RequireObjectCoercible ( argument ) (7.2.1)

Argument type: _SIMD_Type
Result: return _argument_

SameValue(x, y) (7.2.9)

1. ReturnIfAbrupt(_x_). 1. ReturnIfAbrupt(_y_). 1. If Type(_x_) is different from Type(_y_), return *false*. 1. If Type(_x_) is Undefined, return *true*. 1. If Type(_x_) is Null, return *true*. 1. If Type(_x_) is Number, then 1. If _x_ is *NaN* and _y_ is *NaN*, return *true*. 1. If _x_ is +0 and _y_ is -0, return *false*. 1. If _x_ is -0 and _y_ is +0, return *false*. 1. If _x_ is the same Number value as _y_, return *true*. 1. Return *false*. 1. 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. 1. If Type(_x_) is Boolean, then 1. If _x_ and _y_ are both true or both false, return true; otherwise, return false. 1. If Type(_x_) is Symbol, then 1. If _x_ and _y_ are both the same Symbol value, return true; otherwise, return false. 1. If Type(_x_) is a SIMD type _SIMD_Type: 1. For _i_ from 0 to _SIMD_Descriptor.[[VectorLength]] - 1: 1. If SameValue(SIMDExtractLane(_x_, _i_), SIMDExtractLane(_y_, _i_)) is *false*, return *false*. 1. return *true* 1. Return *true* if _x_ and _y_ are the same Object value. Otherwise, return *false*.

SameValueZero(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_). 1. ReturnIfAbrupt(_y_). 1. If Type(_x_) is different from Type(_y_), return *false*. 1. If Type(_x_) is Undefined, return *true*. 1. If Type(_x_) is Null, return *true*. 1. If Type(_x_) is Number, then 1. If _x_ is *NaN* and _y_ is *NaN*, return *true*. 1. If _x_ is +0 and _y_ is -0, return *true*. 1. If _x_ is -0 and _y_ is +0, return *true*. 1. If _x_ is the same Number value as _y_, return *true*. 1. Return *false*. 1. 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. 1. If Type(_x_) is Boolean, then 1. If _x_ and _y_ are both true or both false, return true; otherwise, return false. 1. If Type(_x_) is Symbol, then 1. If _x_ and _y_ are both the same Symbol value, return true; otherwise, return false. 1. If Type(_x_) is a SIMD type _SIMD_Type: 1. For _i_ from 0 to _SIMD_Descriptor.[[VectorLength]] - 1: 1. If SameValueZero(SIMDExtractLane(_x_, _i_), SIMDExtractLane(_y_, _i_)) is *false*, return *false*. 1. return *true* 1. Return *true* if _x_ and _y_ are the same Object value. Otherwise, return *false*.

Abstract Equality Comparison (7.2.12)

Replace step 10 with the following: 1. ReturnIfAbrupt(_x_). 1. ReturnIfAbrupt(_y_). 1. If Type(_x_) is the same as Type(_y_), then 1. Return the result of performing Strict Equality Comparison x === y. 1. If x is null and y is undefined, return *true*. 1. If x is undefined and y is null, return *true*. 1. If Type(_x_) is Number and Type(_y_) is String,
return the result of the comparison x == ToNumber(_y_). 1. If Type(_x_) is String and Type(_y_) is Number,
return the result of the comparison ToNumber(_x_) == y. 1. If Type(_x_) is Boolean, return the result of the comparison ToNumber(_x_) == y. 1. If Type(_y_) is Boolean, return the result of the comparison x == ToNumber(_y_). 1. If Type(_x_) is either String, Number, any _SIMD_Type, or Symbol and Type(_y_) is Object, then
return the result of the comparison x == ToPrimitive(_y_). 1. If Type(_x_) is Object and Type(_y_) is either String, Number, any _SIMD_Type, or Symbol, then
return the result of the comparison ToPrimitive(_x_) == y. 1. Return *false*.

Strict Equality Comparison (7.2.13)

Add a new step 9, before the existing step 9: 1. ReturnIfAbrupt(_x_). 1. ReturnIfAbrupt(_y_). 1. If Type(_x_) is different from Type(_y_), return *false*. 1. If Type(_x_) is Undefined, return *true*. 1. If Type(_x_) is Null, return *true*. 1. If Type(_x_) is Number, then 1. If _x_ is *NaN*, return *false*. 1. If _y_ is *NaN*, return *false*. 1. If _x_ is the same Number value as y, return *true*. 1. If _x_ is +0 and y is −0, return *true*. 1. If _x_ is −0 and y is +0, return *true*. 1. Return *false*. 1. 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. 1. If Type(_x_) is Boolean, then 1. If _x_ and _y_ are both true or both false, return true; otherwise, return false. 1. If Type(_x_) is Symbol, then 1. If _x_ and _y_ are both the same Symbol value, return true; otherwise, return false. 1. If Type(_x_) is SIMD type _SIMD_Type: 1. For _i_ from 0 to _SIMD_Descriptor.[[VectorLength]] - 1: 1. If SIMDExtractLane(_x_, _i_) === SIMDExtractLane(_y_, _i_) is *false*, return *false*. 1. return *true* 1. Return *true* if _x_ and _y_ are the same Object value. Otherwise, return *false*.

The typeof Operator (12.5.6)

Runtime Semantics: Evaluation (12.5.6.1)

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"

SIMD

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).

Internal algorithms on SIMD types

SIMDCreate( descriptor, vectorElements )

1. Assert: _descriptor_ is a SIMD type descriptor. 1. Assert: _vectorElements_ is a List. 1. Assert: The length of _vectorElements_ = _descriptor_.[[VectorLength]]. 1. Let _list_ be a new List of length _descriptor_.[[VectorLength]]. 1. For _i_ from 0 to _descriptor_.[[VectorLength]], 1. Let _n_ be descriptor.[[Cast]](vectorElements[i]). 1. ReturnIfAbrupt(_n_). 1. Set list[i] to _n_. 1. Return the SIMD value specified by the record { [[SIMDTypeDescriptor]]: _descriptor_, [[SIMDElements]]: _list_ }.

SIMDToLane( max, lane )

1. Let _index_ be ToNumber(_lane_). 1. ReturnIfAbrupt(_index_). 1. If SameValueZero(_index_, ToLength(_index_)) is *false* or _index_ < 0 or _index_ ≥ _max_, throw a RangeError exception. 1. Return _index_

SIMDExtractLane( value, lane )

1. Assert: Type(_value_) is a _SIMD_Type. 1. Let _index_ be SIMDToLane(_value_.[[SIMDTypeDescriptor]].[[VectorLength]], _lane_). 1. ReturnIfAbrupt(_index_). 1. Return value.[[SIMDElements]][index]

SIMDReplaceLane( value, lane, replacement )

1. Assert: Type(_value_) is a _SIMD_Type. 1. Let _descriptor_ be _value_.[[SIMDTypeDescriptor]]. 1. Let _index_ be SIMDToLane(_descriptor_.[[VectorLength]], _lane_). 1. ReturnIfAbrupt(_index_). 1. Let _list_ be a copy of _value_.[[SIMDElements]]. 1. Set list[index] to _replacement_. 1. Return SIMDCreate(_descriptor_, _list_).

MaybeFlushDenormal( 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. 1. 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. 1. Otherwise, assert _descriptor_ is not a floating point SIMD type descriptor. 1. If _subnormal_ is true, 1. If _n_ > 0, return +0. 1. Otherwise, return -0. 1. Otherwise, return _n_.

SIMDBinaryOp( a, b, op, outputDescriptor )

1. Assert: _a_.[[SIMDTypeDescriptor]] and _b_.[[SIMDTypeDescriptor]] are the same SIMD type descriptor. 1. Let _descriptor_ be _a_.[[SIMDTypeDescriptor]]. 1. If _outputDescriptor_ is not provided, let _outputDescriptor_ be _descriptor_. 1. Let _list_ be a new List of length _descriptor_.[[VectorLength]]. 1. For _i_ from 0 to _descriptor_.[[VectorLength]], 1. Let _ax_ = MaybeFlushDenormal(SIMDExtractLane(_a_, _i_), _descriptor_). 1. Let _bx_ = MaybeFlushDenormal(SIMDExtractLane(_b_, _i_), _descriptor_). 1. Let _res_ = op(_ax_, _bx_); 1. ReturnIfAbrupt(_res_). 1. Let _res_ = MaybeFlushDenormal(_res_, _outputDescriptor_). 1. Set list[i] to _res_. 1. Return SIMDCreate(_outputDescriptor_, _list_).

SIMDUnaryOp( a, op [ , flushDenormal ] )

1. Let _descriptor_ be _a_.[[SIMDTypeDescriptor]]. 1. If _flushDenormal_ is not provided, let _flushDenormal_ be *true*. 1. Let _list_ be a new List of length _descriptor_.[[VectorLength]]. 1. ReturnIfAbrupt(_block_). 1. For _i_ from 0 to _descriptor_.[[VectorLength]], 1. Let _ax_ = SIMDExtractLane(_a_, _i_). 1. If _flushDenormal_, let _ax_ be MaybeFlushDenormal(_ax_, _descriptor_). 1. Let _res_ = op(_ax_). 1. ReturnIfAbrupt(_res_). 1. If _flushDenormal_, let _res_ be MaybeFlushDenormal(_res_, _descriptor_). 1. Set list[i] to _res_. 1. Return SIMDCreate(_descriptor_, _list_).

SIMDScalarOp( a, scalar, op )

1. Let _descriptor_ be _a_.[[SIMDTypeDescriptor]]. 1. Assert: _descriptor_ is not a floating point SIMD type. 1. Let _list_ be a new List of length _descriptor_.[[VectorLength]]. 1. ReturnIfAbrupt(_block_). 1. For _i_ from 0 to _descriptor_.[[VectorLength]], 1. Let _ax_ = SIMDExtractLane(_a_, _i_). 1. Let _res_ = op(_ax_, _scalar_). 1. ReturnIfAbrupt(_res_). 1. Set list[i] to _res_. 1. Return SIMDCreate(_descriptor_, _list_).

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

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

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

1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception. 1. If _length_ is not provided, let _length_ be _descriptor_.[[VectorLength]]. Otherwise, assert _length_ ≤ _descriptor_.[[VectorLength]]. 1. If IsDetachedBuffer(_tarray_.[[ViewedArrayBuffer]]) is *true*, throw a TypeError exception. 1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]] 1. If _index_ ≠ ToLength(_index_), throw a TypeError exception. 1. Let _elementLength_ be _tarray_.[[ByteLength]] ÷ _tarray_.[[ArrayLength]]. 1. Let _byteIndex_ be _index_ × _elementLength_. 1. If _byteIndex_ + _descriptor_.[[ElementSize]] × length > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError exception. 1. Return SIMDLoad(_block_, _descriptor_, _byteIndex_, length).

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

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

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

1. If _n_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. If _length_ is not provided, let _length_ be _descriptor_.[[VectorLength]]. Otherwise, assert _length_ ≤ _descriptor_.[[VectorLength]]. 1. If IsDetachedBuffer(_tarray_.[[ViewedArrayBuffer]]) is *true*, throw a TypeError exception. 1. If _tarray_ does not have a [[ViewedArrayBuffer]] field, throw a TypeError exception. 1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]] 1. If _index_ ≠ ToLength(_index_), throw a TypeError exception. 1. Let _elementLength_ be _tarray_.[[ByteLength]] ÷ _tarray.[[ArrayLength]]. 1. Let _byteIndex_ be _index_ × _elementLength_. 1. If _byteIndex_ + _SIMD_Descriptor.[[ElementSize]] × _length_ > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError exception. 1. SIMDStore(_block_, _SIMD_Descriptor, _byteIndex_, _simd_, _length_). 1. Return _n_.

SIMDReinterpretCast( value, newDescriptor )

This is used to define operations like SIMD.Float32x4.fromInt8x16Bits. 1. Assert: _value_.[[SIMDTypeDescriptor]].[[VectorLength]] × _value_.[[SIMDTypeDescriptor]].[[ElementSize]] = _newDescriptor_.[[VectorLength]] × _newDescriptor_.[[ElementSize]]. 1. Let _bytes_ be _newDescriptor_.[[VectorLength]] × _newDescriptor_.[[ElementSize]]. 1. Let _block_ be the result of CreateByteDataBlock(_bytes_). 1. ReturnIfAbrupt(_block_). 1. SIMDStore(_block_, _value_, 0). 1. Return SIMDLoad(_block_, _newDescriptor_, 0).

SIMDBoolType( descriptor )

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

SIMDRelationalOp( a, b, op )

1. Let _outputDescriptor_ be SIMDBoolType(_a_.[[SIMDTypeDescriptor]]). 1. Return SIMDBinaryOp(_a_, _b_, _op_, _outputDescriptor_).

MathAbs( 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 +∞.

ToFloat32( x )

1. If x is NaN, return NaN. 1. If x is one of +0, −0, +∞, −∞, return x. 1. Let x32 be the result of converting x to a value in IEEE 754-2008 binary32 format using roundTiesToEven. 1. Let x64 be the result of converting x32 to a value in IEEE 754-2008 binary64 format. 1. Return the ECMAScript Number value corresponding to x64.

MathSqrt( 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 +∞.

MathImul(n, m)

1. Let _a_ be ToUint32(_x_). 1. Let _b_ be ToUint32(_y_). 1. Let _product_ be (_a_ × b) modulo 232. 1. If _product_ ≥ 231, return _product_ − 232, otherwise return _product_.

MathMin(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.

MaxNum(n, m)

1. Assert Type(_n_) is Number and Type(_m_) is Number. 1. If _n_ is *NaN*, return _m_. 1. If _m_ is *NaN*, return _n_. 1. Let _result_ be MathMax(_n_, _m_). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

MinNum(n, m)

1. Assert Type(_n_) is Number and Type(_m_) is Number. 1. If _n_ is *NaN*, return _m_. 1. If _m_ is *NaN*, return _n_. 1. Let _result_ be MathMin(_n_, _m_). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

ReciprocalApproximation(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.

ReciprocalSqrtApproximation(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*.

Saturate( descriptor, x )

1. If _x_ > _descriptor_.[[ElementMax]], return _descriptor_.[[ElementMax]]. 1. Otherwise, if _x_ < _descriptor_.[[ElementMin]], return _descriptor_.[[ElementMin]] 1. Return _x_.

AddSaturate( descriptor )( x, y )

1. Return Saturate(_descriptor_, _x_ + _y_).

SubSaturate( descriptor )( x, y )

1. Return Saturate(_descriptor_, _x_ - _y_).

BitwiseOp( @ )( lval, rval )

1. Let _lnum_ be ToInt32(_lval_). 1. ReturnIfAbrupt(_lnum_). 1. Let rnum be ToInt32(_rval_). 1. ReturnIfAbrupt(_rnum_). 1. Return the result of applying the bitwise operator @ to _lnum_ and _rnum_. The result is a signed 32 bit integer.

ArrayJoin( array, separator )

1. Let _O_ be ToObject(_array_). 1. ReturnIfAbrupt(_O_). 1. Let len be ToLength(Get(_O_, "length")). 1. ReturnIfAbrupt(_len_). 1. If _separator_ is undefined, let _separator_ be the single-element String ",". 1. Let _sep_ be ToString(_separator_). 1. ReturnIfAbrupt(_sep_). 1. If _len_ is zero, return the empty String. 1. Let _element0_ be Get(_O_, "0"). 1. If _element0_ is undefined or null, let _R_ be the empty String; otherwise, let R be ToString(_element0_). 1. ReturnIfAbrupt(_R_). 1. Let _k_ be 1. 1. Repeat, while _k_ < _len_ 1. Let _S_ be the String value produced by concatenating _R_ and _sep_. 1. Let _element_ be Get(_O_, ToString(_k_)). 1. If _element_ is undefined or null, let _next_ be the empty String; otherwise, let _next_ be ToString(_element_). 1. ReturnIfAbrupt(_next_). 1. Let _R_ be a String value produced by concatenating _S_ and _next_. 1. Increase _k_ by 1. 1. Return _R_.

Constructor properties _SIMD_Constructor of the SIMD object

Each _SIMD_Constructor, namely Float32x4, Int32x4, Int16x8, Int8x16, Uint32x4, Uint16x8, Uint8x16, Bool32x4, Bool16x8, and Bool8x16, is associated with a _SIMD_Type and _SIMD_Descriptor. 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 _SIMD_Descriptor. Certain functions are defined only on a subset of _SIMD_Constructors, 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.

_SIMD_Constructor( ...values )

SIMD wrapped objects cannot be created using `new` on _SIMD_Constructor; they can be created explicitly with `Object()` however. 1. If *NewTarget* is not undefined, throw a *TypeError* exception. 1. Let _fields_ be a new List. 1. For integer _n_ from *0* to _SIMD_Descriptor.[[VectorLength]], 1. Append _values_[_n_] to the end of _fields_, or *undefined* if there were not enough arguments. 1. Return SIMDCreate(_SIMD_Descriptor, _fields_). The `length` property of `_SIMD_Constructor` is _SIMD_Descriptor.[[VectorLength]].

Properties of the _SIMD_Constructor constructors

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

The `length` property of _SIMD_Constructor is _SIMD_Descriptor.[[VectorLength]].

Each _SIMD_Constructor has the following properties:

_SIMD_Constructor.splat(n)

1. Let _list_ be a new List of length _SIMD_Descriptor.[[VectorLength]], with all entries filled with _n_. 1. Return SIMDCreate(_SIMD_Descriptor, _list_).

_SIMD_Constructor.check(a)

1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a *TypeError* exception. 1. Return _a_.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, `+`). 1. ReturnIfAbrupt(_result_). 1. Return _result_. 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?.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, `-`). 1. ReturnIfAbrupt(_result_). 1. Return _result_. 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?.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. If _SIMD_Type is an integer SIMD type, let _op_ be MathImul; otherwise, _SIMD_Type is a floating point SIMD type, and let _op_ be `*`. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, _op_). 1. ReturnIfAbrupt(_result_). 1. Return _result_. 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?.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, `/`). 1. ReturnIfAbrupt(_result_). 1. Return _result_. 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?.

_SIMD_Constructor.max(a, b)

This operation is only defined on floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, MathMax). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.min(a, b)

This property is defined only on floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, MathMin). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.maxNum(a, b)

This operation is only defined on floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, MaxNum). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.minNum(a, b)

This operation is only defined on floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, MinNum). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.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 _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDUnaryOp(_a_, `-`, *false*). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.sqrt(a)

This operation is only defined on floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDUnaryOp(_a_, MathSqrt). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.reciprocalApproximation(a, b)

This operation is only defined on floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDUnaryOp(_a_, ReciprocalApproximation). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.reciprocalSqrtApproximation(a)

This operation is only defined on floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDUnaryOp(_a_, ReciprocalSqrtApproximation). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.abs(a)

This operation is only defined on floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDUnaryOp(_a_, MathAbs, *false*). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.and(a, b)

This operation is only defined on integer and boolean SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, BitwiseOp(&)). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.xor(a, b)

This operation is only defined on integer and boolean SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, BitwiseOp(^)). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.or(a, b)

This operation is only defined on integer and boolean SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDBinaryOp(_a_, _b_, BitwiseOp(|)). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.not(a)

This operation is only defined on integer and boolean SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDUnaryOp(_a_, `~`). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDRelationalOp(_a_, _b_, `<`). 1. ReturnIfAbrupt(_result_). 1. Return _result_. 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.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDRelationalOp(_a_, _b_, `<=`). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDRelationalOp(_a_, _b_, `>`). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDRelationalOp(_a_, _b_, `>=`). 1. ReturnIfAbrupt(_result_). 1. Return _result_.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDRelationalOp(_a_, _b_, `===`). 1. ReturnIfAbrupt(_result_). 1. Return _result_. The resulting notion of equality is weaker than `===` on some platforms because denormals may be flushed to 0.

_SIMD_Constructor.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 _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _result_ be SIMDRelationalOp(_a_, _b_, `!==`). 1. ReturnIfAbrupt(_result_). 1. Return _result_. The resulting notion of equality is weaker than === on some platforms because denormals may be flushed to 0.

_SIMD_Constructor.anyTrue(a)

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

_SIMD_Constructor.allTrue(a)

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

_SIMD_Constructor.select( selector, a, b )

This operation is only defined on integer and floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Let _outputDescriptor_ be SIMDBoolType(_SIMD_Descriptor). 1. If _selector_.[[SIMDTypeDescriptor]] is not _outputDescriptor_, throw a TypeError exception. 1. Let _list_ be a new List. 1. For _i_ from 0 to _SIMD_Descriptor.[[VectorLength]] - 1, 1. If sector.[[SIMDElements]][i] is *true*, let list[i] be a.[[SIMDElements]][i]. 1. Otherwise, let list[i] be b.[[SIMDElements]][i]. 1. Return SIMDCreate(_SIMD_Descriptor, _list_).

_SIMD_Constructor.addSaturate( a, b )

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

_SIMD_Constructor.subSaturate( a, b )

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

_SIMD_Constructor.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 _SIMD_Descriptor, throw a TypeError exception. 1. Let _scalar_ be ToUint32(_bits_). 1. If _scalar_ ≥ _SIMD_Descriptor.[[ElementSize]] × 8, then 1. Let _list_ be a list of length _SIMD_Descriptor.[[VectorLength]], filled with 0. 1. return SIMDCreate(_SIMD_Descriptor, _list_). 1. Let _result_ be SIMDScalarOp(_a_, _scalar_, `<<`). 1. ReturnIfAbrupt(_result_). 1. Return _result_. Unlike ECMAScript scalar shift, there is no "wrap-around" behavior.

_SIMD_Constructor.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 _SIMD_Descriptor, throw a TypeError exception. 1. Let _scalar_ be ToUint32(_bits_). 1. If _scalar_ ≥ _SIMD_Descriptor.[[ElementSize]] × 8, then 1. Let _list_ be a list of length _SIMD_Descriptor.[[VectorLength]], filled with 0. 1. return SIMDCreate(_SIMD_Descriptor, _list_). 1. Let _result_ be SIMDScalarOp(_a_, _scalar_, `>>>`). 1. ReturnIfAbrupt(_result_). 1. 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 _SIMD_Descriptor, throw a TypeError exception. 1. Let _scalar_ be ToUint32(_bits_). 1. If _scalar_ ≥ _SIMD_Descriptor.[[ElementSize]] × 8, then 1. Let _scalar_ be _SIMD_Descriptor.[[ElementSize]] × 8 - 1. 1. Let _result_ be SIMDScalarOp(_a_, _scalar_, `>>`). 1. ReturnIfAbrupt(_result_). 1. Return _result_. In both definitions, unlike ECMAScript scalar shift, there is no "wrap-around" behavior.

_SIMD_Constructor.extractLane( simd, lane )

1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Return SIMDExtractLane(_simd_, _lane_).

_SIMD_Constructor.replaceLane( simd, lane, value )

1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError exception. 1. Return SIMDReplaceLane(_simd_, _lane_, _value_).

_SIMD_Constructor.store( tarray, index, simd )

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

This operation exists only on integer and floating point SIMD types. 1. Return SIMDStoreInTypedArray(_tarray_, _index_, _SIMD_Descriptor, _simd_).

_SIMD_Constructor.store1( tarray, index, simd )

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

This operation exists only on integer and floating point SIMD types. 1. Return SIMDStoreInTypedArray(_tarray_, _index_, _SIMD_Descriptor, _simd_, 1).

_SIMD_Constructor.store2( tarray, index, simd )

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

This operation exists only on integer and floating point SIMD types. 1. Return SIMDStoreInTypedArray(_tarray_, _index_, _SIMD_Descriptor, _simd_, 2).

_SIMD_Constructor.store3( tarray, index, simd )

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

This operation exists only on integer and floating point SIMD types. 1. Return SIMDStoreInTypedArray(_tarray_, _index_, _SIMD_Descriptor, _simd_, 3).

_SIMD_Constructor.load( tarray, index )

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

This operation exists only on integer and floating point SIMD types. `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_, _SIMD_Descriptor).

_SIMD_Constructor.load1(tarray, index)

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

This operation exists only on integer and floating point SIMD types. 1. Return SIMDLoadFromTypedArray(_tarray_, _index_, _SIMD_Descriptor, 1).

_SIMD_Constructor.load2(tarray, index)

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

This operation exists only on integer and floating point SIMD types. 1. Return SIMDLoadFromTypedArray(_tarray_, _index_, _SIMD_Descriptor, 2).

_SIMD_Constructor.load3(tarray, index)

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

This operation exists only on integer and floating point SIMD types. 1. Return SIMDLoadFromTypedArray(_tarray_, _index_, _SIMD_Descriptor, 3).

SIMDConstructor.fromTIMDBits( value )

In this definition, _TIMD_ ranges over all SIMD types for which _SIMD_Descriptor.[[ElementSize]] × _SIMD_Descriptor.[[VectorLength]] = _TIMD_Descriptor.[[ElementSize]] × _TIMD_Descriptor.[[VectorLength]], unless one descriptor does not have a [[SerializeElement]] field. 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 _TIMD_Descriptor, throw a TypeError exception. 1. Return SIMDReinterpretCast(_value_, _SIMD_Descriptor).

SIMDConstructor.fromTIMD( value )

In this definition, _TIMD_ ranges over all SIMD types for which _SIMD_Descriptor.[[VectorLength]] = _TIMD_Descriptor.[[VectorLength]], and where _SIMD_ and _TIMD_ are not boolean types. 1. If _value_.[[SIMDTypeDescriptor]] is not _TIMD_Descriptor, throw a TypeError exception. 1. Let _list_ be a copy of _value_.[[SIMDElements]]. 1. For _element_ in _list_, 1. If _SIMD_ is an integer type and _TIMD_ is a floating point type, and _element_ is greater than the maximum value or less than the minimum value of _SIMD_, throw a *RangeError* exception. 1. Return SIMDCreate(_SIMD_Descriptor, _list_).

_SIMD_Constructor.swizzle( a, ...lanes )

This operation exists only on integer and floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a *TypeError* exception. 1. Let _indices_ be a new List. 1. For integer _n_ from *0* to _SIMD_Descriptor.[[VectorLength]], 1. Let _lane_ be lanes[i], or 0 if _lanes_ is not long enough. 1. Let _index_ be SIMDToLane(_value_.[[SIMDTypeDescriptor]].[[VectorLength]], _lane_). 1. ReturnIfAbrupt(_index_). 1. Append _index_ to the end of _indices_. 1. Let _fields_ be a new List of length _SIMD_Descriptor.[[VectorLength]]. 1. For _i_ in from 0 to _SIMD_Descriptor.[[VectorLength]] - 1, 1. Set fields[i] to SIMDExtractLane(_a_, indices[i]) 1. Return SIMDCreate(_SIMD_Descriptor, _fields_). The `length` property of `_SIMD_.swizzle` is 1 + _SIMD_Descriptor.[[VectorLength]].

_SIMD_Constructor.shuffle( a, b, ...lanes )

This operation exists only on integer and floating point SIMD types. 1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, or if _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a *TypeError* exception. 1. Let _indices_ be a new List. 1. For integer _n_ from *0* to _SIMD_Descriptor.[[VectorLength]], 1. Let _lane_ be lanes[i], or 0 if _lanes_ is not long enough. 1. Let _index_ be SIMDToLane(_SIMD_Descriptor.[[VectorLength]] * 2, _lane_). 1. ReturnIfAbrupt(_index_). 1. Append _index_ to the end of _indices_. 1. Let _fields_ be a new List of length _SIMD_Descriptor.[[VectorLength]]. 1. For _i_ in from 0 to _SIMD_Descriptor.[[VectorLength]] - 1, 1. Let _idx_ be indices[i]. 1. If _idx_ ≥ _SIMD_Descriptor.[[VectorLength]], 1. Set fields[i] to SIMDExtractLane(_b_, _idx_ - _SIMD_Descriptor.[[VectorLength]]) 1. Otherwise, 1. Set fields[i] to SIMDExtractLane(_a_, _idx_) 1. Return SIMDCreate(_SIMD_Descriptor, _fields_). The `length` property of `_SIMD_.shuffle` is 2 + _SIMD_Descriptor.[[VectorLength]] * 2.

The _SIMD_Constructor.prototype

_SIMD_Constructor.prototype.constructor

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

_SIMD_Constructor.prototype.valueOf()

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

_SIMD_Constructor.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. 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. 1. If *this*.[[SIMDWrapperData]].[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a *TypeError* exception. 1. 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). 1. Let _list_ be an empty List 1. For each element _element_ in _argument_.[[SIMDElements]], 1. Let _R_ be ToString(Invoke(_element_, "toLocaleString")). 1. ReturnIfAbrupt(_R_). 1. Append _R_ to _list_. 1. Let _results_ be CreateArrayFromList(_list_). 1. Let _t_ be the string `"`SIMD`"`, e.g., `"Float32x4"`. 1. Let _e_ be ArrayJoin(_results_, _separator_). 1. Return a new String value computed by concatenating the previous value of _t_, "(", _e_, and ")".

_SIMD_Constructor.prototype.toString()

1. If *this* does not have a [[SIMDWrapperData]] internal slot, throw a *TypeError* exception. 1. If *this*.[[SIMDWrapperData]].[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a *TypeError* exception. 1. Return ToString(*this*.[[SIMDWrapperData]]). This definition depends on the primitive _SIMD_Type's behavior under ToString. Alternatively, _SIMD_Type 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.

_SIMD_Constructor.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* }.

_SIMD_Constructor.prototype [ @@toPrimitive ] ( hint )

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. 1. If Type(_s_) is a SIMD type, return _s_. 1. If Type(_s_) is not `Object`, throw a *TypeError* exception. 1. If _s_ does not have a [[SIMDWrapperData]] internal slot, throw a *TypeError* exception. 1. If _s_.[[SIMDWrapperData]].[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a *TypeError* exception. 1. 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* }.

SIMD 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.

SerializeFloat32( block, offset, n, isLittleEndian )

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. 1. Assert: _offset_ is a number. 1. Assert: _n_ is a number. 1. Assert: _offset_ + 4 is less than or equal to the size of _block_. 1. 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. 1. Store the individual bytes of _rawBytes_ into _block_, in order, starting at block[offset].

DeserializeFloat32( block, offset, isLittleEndian )

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. 1. Assert: _offset_ is a number. 1. Assert: _offset_ + 4 is less than or equal to the size of _block_. 1. Let _rawValue_ be a List of 4 containing, in order, the sequence of 4 bytes starting with block[offset]. 1. If _isLittleEndian_ is *false*, reverse the order of the elements of _rawValue_. 1. 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. 1. If _value_ is an IEEE 754-2008 binary32 *NaN* value, return the *NaN* Number value. 1. Return the Number value that corresponds to _value_.

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

Derived from part of SetValueInBuffer. 1. Assert: _block_ is a Data Block. 1. Assert: _offset_ is a number. 1. Assert: _n_ is a number. 1. Assert: _n_ = _descriptor_.[[Cast]](_n_). 1. Assert: _offset_ + _descriptor_.[[ElementSize]] is less than or equal to the size of _block_. 1. 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. 1. Store the individual bytes of _rawBytes_ into _block_, in order, starting at block[offset].

DeserializeInt( descriptor )( block, offset, isLittleEndian )

Derived from part of GetValueFromBuffer. 1. Assert: _block_ is a Data Block. 1. Assert: _offset_ is a number. 1. Assert: _offset_ + _descriptor_.[[ElementSize]] is less than or equal to the size of _block_. 1. Let _rawValue_ be a List of _descriptor_.[[ElementSize]] containing, in order, the sequence of _descriptor_.[[ElementSize]] bytes starting with block[offset]. 1. If _isLittleEndian_ is *false*, reverse the order of the elements of _rawValue_. 1. 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. 1. Return the Number value that corresponds to _intValue_.
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