blob: 79ac7a38340a8c679db40f0097ef0a2c9f1ec6c8 [file] [log] [blame]
<!doctype html>
<meta charset="utf8">
<title>SIMD.js specification v0.7.1</title>
<link rel="stylesheet" href="https://bterlson.github.com/ecmarkup/elements.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/github.min.css">
<emu-biblio href="./biblio.json"></emu-biblio>
<h1>SIMD.js specification v0.7.1</h1>
<emu-intro id="intro">
<h1>Introduction</h1>
<p>
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.
</p>
<p>
One problem that this spec aims to solve is to define equality for SIMD values. Existing implementations use 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.
</p>
<p>
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 someone steps forward to describe value types in more detail, it will be great to simplify 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.
</p>
<p>
This document is organized in terms of where changes would be made to the ES6 spec. Although ecmarkup generates numbering at the beginning of headers, these won't correspond to the numbering within the existing ECMA spec, so I've included a matching numbering in parentheses afterwards, referring to the ES6 spec.
</p>
<p>
In this text, _SIMD_ is used to refer to the various SIMD types: Float32x4, Int32x4, Int16x8 Int8x16, Bool32x4, Bool16x8 and Bool8x16. Similarly to Number, _SIMD_ is used to refer to both the type <em>and</em> 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.</p>
<p><strong>Please file any issues <a href="https://github.com/johnmccutchan/ecmascript_simd/issues">here</a>!</strong> The authoritative copy of this file is in <a href="https://github.com/johnmccutchan/ecmascript_simd/blob/master/tc39/spec.html">in the simd.js repo</a>; 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 <a href="http://littledan.github.io/simd.html">the current location</a>.</p>
<p>Because this document is in spec order, rather than written for direct readability, the logical starting point is actually <a href="#simd">halfway down</a>.</p>
<p>
Related links:
</p>
<ul>
<li><a href="https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md">Value types proposal</a></li>
<li><a href="https://github.com/johnmccutchan/ecmascript_simd/blob/master/src/ecmascript_simd.js">SIMD polyfill</a></li>
<li><a href="https://github.com/johnmccutchan/ecmascript_simd/issues/157">Bug about SIMD.js value semantics</a></li>
</ul>
<p>Changelog:</p>
<ul>
<li>v0.1: Initial proposal based on SIMD values held in Data Blocks</li>
<li>v0.2:
<ul>
<li>SIMD values are explained as Lists of Numbers, and serialized/deserialized only on loads and stores to TypedArrays, and casts.</li>
<li>SIMD values point to a type descriptor, not to the wrapper constructor, which makes cross-realm access more straightforward.</li>
<li>Add all SIMD types, more SIMD operations and all DataView operations.</li>
</ul>
</li>
<li>v0.3: Add more operations, fix some errors and clarify wording.</li>
<li>v0.4: Fix various bugs, mostly reported by rwaldron.</li>
<li>v0.4.1: Refactor definitions for integer types to reduce duplication.</li>
<li>v0.5: Logical and bitwise operations; Int64x2.</li>
<li>v0.5.1: Logical casts between types, like SIMD.float32x4.fromInt32x4; Less exact definition for reciprocalApproximation, reciprocalSqrtApproximation</li>
<li>v0.5.2: Saturating arithmetic; fix mul mis-spec.</li>
<li>v0.5.3: Remove mention of signalling NaN (matches ES6).</li>
<li>v0.5.4: Better formatting for modifications of existing algorithms.</li>
<li>v0.5.5: toLocaleString, shifts, saturating functions only on int16 and smaller, sumOfAbsoluteDifferences. This is the first version to include all functions.</li>
<li>v0.5.6: Fix a few typos, added notes, removed DataView methods, store returns value.</li>
<li>v0.6: Remove Int64x2 and add boolean vectors.</li>
<li>v0.6.1: Relax behavior on subnormals, float to int conversion throws on out of bounds, shift does not mask.</li>
<li>v0.7: Remove Float64x2, Bool64x2, {load,store}[123], selectBits (could be in phase 2); add unsigned operations and sum of absolute differences operations; minor fix in 'shift' definition; clarify what the SIMD object is.</li>
<li>v0.7.1: Add back in {load,store}[123], make ToString() homoiconic.</li>
</ul>
</emu-intro>
<emu-clause id="types">
<h1>ECMAScript Data Types and Values (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-data-types-and-values">6</a>)</h1>
<emu-clause id="all-types">
<h1>ECMAScript language types (<a href="http://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-language-types">6.1</a>)</h1>
<emu-clause id="intrinsics">
<h1>Well-Known Intrinsic Objects (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-well-known-intrinsic-objects">6.1.7.4</a>)</h1>
<p>
<strong>Intrinsic name</strong>: %SIMD%
<br/>
<strong>Global name</strong>: `SIMD`
<br/>
<strong>ECMAScript Language Association</strong>: The <a href="#simd">`SIMD`</a> object
</p>
<p>
<strong>Intrinsic name</strong>: %_SIMD_Constructor%
<br/>
<strong>Global name</strong>: `SIMD.`_SIMD_ (e.g., `SIMD.Float32x4`)
<br/>
<strong>ECMAScript Language Association</strong>: The <a href="#simd-constructor">_SIMD_Constructor</a> constructor
</p>
<p>
<strong>Intrinsic name</strong>: %_SIMD_Prototype%
<br/>
<strong>Global name</strong>: `SIMD.`_SIMD_`.prototype` (e.g., `SIMD.Float32x4.prototype`)
<br/>
<strong>ECMAScript Language Association</strong>: The initial value of the prototype data property of <a href="#simd-constructor">%_SIMD_Constructor%</a>
</p>
<p>
<strong>Intrinsic name</strong>: %ArrayPrototype_join%
<br/>
<strong>Global name</strong>: `Array.prototype.join`
<br/>
<strong>ECMAScript Language Association</strong>: The initial value of the "join" data property of the intrinsic %ArrayPrototype% object (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.join">ES2015 2.1.3.12</a>)
</p>
<p>
<strong>Intrinsic name</strong>: %Math_abs%
<br/>
<strong>Global name</strong>: `Math.abs`
<br/>
<strong>ECMAScript Language Association</strong>: The initial value of the "abs" data property of the intrinsic %Math% object (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.abs">ES2015 20.2.2.1</a>)
</p>
<p>
<strong>Intrinsic name</strong>: %Math_fround%
<br/>
<strong>Global name</strong>: `Math.fround`
<br/>
<strong>ECMAScript Language Association</strong>: The initial value of the "fround" data property of the intrinsic %Math% object (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.fround">ES2015 20.2.2.17</a>)
</p>
<p>
<strong>Intrinsic name</strong>: %Math_max%
<br/>
<strong>Global name</strong>: `Math.max`
<br/>
<strong>ECMAScript Language Association</strong>: The initial value of the "max" data property of the intrinsic %Math% object (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.max">ES2015 20.2.2.24</a>)
</p>
<p>
<strong>Intrinsic name</strong>: %Math_min%
<br/>
<strong>Global name</strong>: `Math.min`
<br/>
<strong>ECMAScript Language Association</strong>: The initial value of the "min" data property of the intrinsic %Math% object (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.min">ES2015 20.2.2.25</a>)
</p>
<p>
<strong>Intrinsic name</strong>: %Math_sqrt%
<br/>
<strong>Global name</strong>: `Math.sqrt`
<br/>
<strong>ECMAScript Language Association</strong>: The initial value of the "max" data property of the intrinsic %Math% object (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.sqrt">ES2015 20.2.2.32</a>)
</p>
<p>
<strong>Intrinsic name</strong>: %Math_imul%
<br/>
<strong>Global name</strong>: `Math.imul`
<br/>
<strong>ECMAScript Language Association</strong>: The initial value of the "imul" data property of the intrinsic %Math% object (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.imul">ES2015 20.2.2.19</a>)
</p>
</emu-clause>
</emu-clause>
<emu-clause id="simd-types">
<h1>SIMD types</h1>
<emu-clause id="float32x4">
<h1>Float32x4</h1>
<p>
`Float32x4` is a SIMD type representing four 32-bit floating point values. Float32x4 values can be created using the [[Call]] operation on the <a href="#simd-wrap">SIMD.Float32x4</a> object. Its behavior as a SIMD type is defined by the <a href="#simd-float32x4">Float32x4 SIMD type descriptor</a>.
</p>
</emu-clause>
<emu-clause id="int32x4">
<h1>Int32x4</h1>
<p>
`Int32x4` is a SIMD type representing four 32-bit integer values. Int32x4 values can be created using the [[Call]] operation on the <a href="#simd-wrap">SIMD.Int32x4</a> object. Its behavior as a SIMD type is defined by the <a href="#simd-int32x4">Int32x4 SIMD type descriptor</a>
</p>
</emu-clause>
<emu-clause id="int16x8">
<h1>Int16x8</h1>
<p>
`Int16x8` is a SIMD type representing eight 16-bit integer values. Int16x8 values can be created using the [[Call]] operation on the <a href="#simd-wrap">SIMD.Int16x8</a> object. Its behavior as a SIMD type is defined by the <a href="#simd-int16x8">Int16x8 SIMD type descriptor</a>
</p>
</emu-clause>
<emu-clause id="int8x16">
<h1>Int8x16</h1>
<p>
`Int8x16` is a SIMD type representing sixteen 8-bit integer values. Int8x16 values can be created using the [[Call]] operation on the <a href="#simd-wrap">SIMD.Int8x16</a> object. Its behavior as a SIMD type is defined by the <a href="#simd-int8x16">Int8x16 SIMD type descriptor</a>
</p>
</emu-clause>
<emu-clause id="bool32x4">
<h1>Bool32x4</h1>
<p>
`Bool32x4` is a SIMD type representing two boolean values, as an intermediate value in manipulating 128-bit vectors. Bool32x4 values can be created using the [[Call]] operation on the <a href="#simd-wrap">SIMD.Bool32x4</a> object. Its behavior as a SIMD type is defined by the <a href="#simd-bool32x4">Bool32x4 SIMD type descriptor</a>
</p>
</emu-clause>
<emu-clause id="bool16x8">
<h1>Bool16x8</h1>
<p>
`Bool16x8` is a SIMD type representing two boolean values, as an intermediate value in manipulating 128-bit vectors. Bool16x8 values can be created using the [[Call]] operation on the <a href="#simd-wrap">SIMD.Bool16x8</a> object. Its behavior as a SIMD type is defined by the <a href="#simd-bool16x8">Bool16x8 SIMD type descriptor</a>
</p>
</emu-clause>
<emu-clause id="bool8x16">
<h1>Bool8x16</h1>
<p>
`Bool8x16` is a SIMD type representing two boolean values, as an intermediate value in manipulating 128-bit vectors. Bool8x16 values can be created using the [[Call]] operation on the <a href="#simd-wrap">SIMD.Bool8x16</a> object. Its behavior as a SIMD type is defined by the <a href="#simd-bool8x16">Bool8x16 SIMD type descriptor</a>
</p>
</emu-clause>
</emu-clause>
</emu-clause>
<emu-clause id="abstract-operations">
<h1>Abstract Operations (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-operations">7</a>)</h1>
<emu-clause id="type-conversion">
<h1>Type Conversion (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-type-conversion">7.1</a>)</h1>
<emu-clause id="to-primitive">
<h1>ToPrimitive ( input [, PreferredType] ) (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-toprimitive">7.1.1</a>)</h1>
<strong>Argument type</strong>: _SIMD_Type
<br/>
<strong>Result</strong>: return _input_
<emu-note>
An additional option considered is to define this as calling ToObject on it, and then ToPrimitive on the resulting wrapper object. This would have the advantage of allowing toString and valueOf be defined on the wrapper prototype, which seems more realistic to me as a path for value types.
</emu-note>
</emu-clause>
<emu-clause id="to-boolean">
<h1>ToBoolean ( argument ) (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-toboolean">7.1.2</a>)</h1>
<strong>Argument type</strong>: _SIMD_Type
<br/>
<strong>Result</strong>: return ~true~
<emu-note>
While it would be possible to make the zero-vector false as a boolean, there are multiple possible interepretations of ToBoolean, and if a programmer is refactoring scalar code, naively keeping in a conditional will lead to a false outcome. Implementation constraints make it expensive to throw on ToBoolean, so returning ~true~ (as Objects do) is a nice, neutral answer.
</emu-note>
</emu-clause>
<emu-clause id="to-number">
<h1>ToNumber ( argument ) (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tonumber">7.1.3</a>)</h1>
<strong>Argument type</strong>: _SIMD_Type
</br>
<strong>Result</strong>: throw a ~TypeError~ exception
</emu-clause>
<emu-clause id="to-string">
<h1>ToString ( argument ) (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tostring">7.1.12</a>)</h1>
<strong>Argument type</strong>: _SIMD_Type
<br/>
<strong>Result</strong>:
<emu-alg>
1. Let _elements_ be an Array containing the contents of _argument_.[[SIMDElements]]
1. Let _t_ be the string `"`<var>SIMD</var>`"`, e.g., `"Float32x4"`.
1. Let e be Call(%ArrayPrototype_join%, _elements_, «","»).
1. Return a new String value computed by concatenating the previous value of "SIMD.", _t_, "(", _e_, and ")".
</emu-alg>
<emu-note>On a SIMD vector, `eval(vector.toString()) == vector` in the initial global environment.</emu-note>
</emu-clause>
<emu-clause id="to-object">
<h1>ToObject ( argument ) (<a href="http://people.mozilla.org/~jorendorff/es6-draft.html#sec-toobject">7.1.13</a>)</h1>
<strong>Argument type</strong>: _SIMD_Type
<br/>
<strong>Result</strong>: Return a new %_SIMD_Constructor% wrapper object whose [[SIMDWrapperData]] internal slot is set to _argument_.
</emu-clause>
</emu-clause>
<emu-clause id="require-object-coercible">
<h1>RequireObjectCoercible ( argument ) (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-requireobjectcoercible">7.2.1</a>)</h1>
<strong>Argument type</strong>: _SIMD_Type
<br/>
<strong>Result</strong>: return _argument_
</emu-clause>
<emu-clause id="same-value">
<h1>SameValue(x, y) (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevalue">7.2.9</a>)</h1>
<emu-alg>
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. <ins>For each SIMD type _SIMD_Type:</ins>
1. <ins>If Type(_x_) is _SIMD_Type:</ins>
1. <ins>Assert Type(_y_) is _SIMD_Type.</ins>
1. <ins>For _i_ from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1:</ins>
1. <ins>If SameValue(SIMDExtractLane(_x_, _i_), SIMDExtractLane(_y_, _i_)) is ~false~, return ~false~.</ins>
1. <ins>return ~true~</ins>
1. Return ~true~ if _x_ and _y_ are the same Object value. Otherwise, return ~false~.
</emu-alg>
</emu-clause>
<emu-clause id="same-value-zero">
<h1>SameValueZero(x, y) (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero">7.2.10</a>)</h1>
Add an extra step at the bottom of the definition of SameValueZero for the new case involving the new type:
<emu-alg>
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. <ins>For each SIMD type _SIMD_Type:</ins>
1. <ins>If Type(_x_) is _SIMD_Type:</ins>
1. <ins>Assert Type(_y_) is _SIMD_Type.</ins>
1. <ins>For _i_ from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1:</ins>
1. <ins>If SameValueZero(SIMDExtractLane(_x_, _i_), SIMDExtractLane(_y_, _i_)) is ~false~, return ~false~.</ins>
1. <ins>return ~true~</ins>
1. Return ~true~ if _x_ and _y_ are the same Object value. Otherwise, return ~false~.
</emu-alg>
</emu-clause>
<emu-clause id="abstract-relational-comparison">
<h1>Abstract Relational Comparison (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">7.2.11</a>)</h1>
<emu-note><p>No changes needed for SIMD; it will throw a TypeError if either operand is a SIMD value because the algorithm will call ToNumber in step 6.a or 6.c, which throws on SIMD values.</p><p>It is important for Abstract Relational Comparison to throw on SIMD types because there is no clear scalar boolean interpretation, and allowing it to throw makes it possible overload the operator in the future.</p></emu-note>
</emu-clause>
<emu-clause id="abstract-equality">
<h1>Abstract Equality Comparison (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-equality-comparison">7.2.12</a>)</h1>
Replace step 10 with the following:
<emu-alg>
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,<br/> return the result of the comparison x == ToNumber(_y_).
1. If Type(_x_) is String and Type(_y_) is Number,<br/> 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, <ins>any _SIMD_Type,</ins> or Symbol and Type(_y_) is Object, then<br/>return the result of the comparison x == ToPrimitive(_y_).
1. If Type(_x_) is Object and Type(_y_) is either String, Number, <ins>any _SIMD_Type,</ins> or Symbol, then<br/>return the result of the comparison ToPrimitive(_x_) == y.
1. Return ~false~.
</emu-alg>
</emu-clause>
<emu-clause id="strict-equality-comparison">
<h1>Strict Equality Comparison (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-strict-equality-comparison">7.2.13</a>)</h1>
Add a new step 9, before the existing step 9:
<emu-alg>
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. <ins>For each SIMD type _SIMD_Type:</ins>
1. <ins>If Type(_x_) is _SIMD_Type:</ins>
1. <ins>Assert Type(_y_) is _SIMD_Type.</ins>
1. <ins>For _i_ from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1:</ins>
1. <ins>If SIMDExtractLane(_x_, _i_) === SIMDExtractLane(_y_, _i_) is ~false~, return ~false~.</ins>
1. <ins>return ~true~</ins>
1. Return ~true~ if _x_ and _y_ are the same Object value. Otherwise, return ~false~.
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="typeof">
<h1>The typeof Operator (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-typeof-operator">12.5.6</a>)</h1>
<emu-clause id="typeof-evaluation">
<h1>Runtime Semantics: Evaluation (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-typeof-operator-runtime-semantics-evaluation">12.5.6.1</a>)</h1>
<strong>Type of val</strong>: Float32x4
<br/>
<strong>Result</strong>: "float32x4"
<br/>
<strong>Type of val</strong>: Int32x4
<br/>
<strong>Result</strong>: "int32x4"
<br/>
<strong>Type of val</strong>: Int16x8
<br/>
<strong>Result</strong>: "int16x8"
<br/>
<strong>Type of val</strong>: Int8x16
<br/>
<strong>Result</strong>: "int8x16"
<br/>
<strong>Type of val</strong>: Bool32x4
<br/>
<strong>Result</strong>: "bool32x4"
<br/>
<strong>Type of val</strong>: Bool16x8
<br/>
<strong>Result</strong>: "bool16x8"
<br/>
<strong>Type of val</strong>: Bool8x16
<br/>
<strong>Result</strong>: "bool8x16"
<emu-note>This follows the pattern for Number ("number"), Boolean ("boolean"), etc.</emu-note>
</emu-clause>
</emu-clause>
<emu-clause id="addition">
<h1>The Addition operator ( + ) (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-addition-operator-plus">12.7.3</a>)</h1>
<emu-clause id="addition-semantics">
<h1>Runtime Semantics: Evaluation (<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-addition-operator-plus">12.7.3.1</a>)</h1>
<emu-note><p>No changes needed for SIMD. With one SIMD argument and one argument which is a String after ToPrimitive is applied, this will coerce the SIMD value to a string, giving a printed representation like `"float32x4(1, 2, 3, 4)"`. Otherwise, if either argument is a SIMD value, then ToNumber will be run on step 12. or 14., which would throw a TypeError.</p><p>It is important for `+` to throw when applied to SIMD types to allow the future definition of operator overloading on `+` . Is the current SIMD+String behavior acceptable, or should that throw too?</p></emu-note>
</emu-clause>
</emu-clause>
<emu-clause id="simd">
<h1>SIMD</h1>
<p>
The SIMD object is the %SIMD% intrinsic object and the initial value of the SIMD property of the global object. The SIMD object is a single ordinary object.
</p>
<p>
The value of the [[Prototype]] internal slot of the SIMD object is the intrinsic object %ObjectPrototype% (19.1.3).
</p>
<p>
The SIMD object is not a function object. It does not have a [[Construct]] internal method; it is not possible to use the SIMD object as a constructor with the new operator. The SIMD object also does not have a [[Call]] internal method; it is not possible to invoke the SIMD object as a function.
</p>
<p>
The SIMD global object has several constructor properties, one for each SIMD type.
</p>
<p>
Each SIMD value is specified as a record with the following internal attributes:
</p>
<ul>
<li>[[SIMDTypeDescriptor]], which refers to the wrapper constructor for the type.</li>
<li>[[SIMDElements]], which is a List of values representing the SIMD contents. The [[SIMDElements]] List is modified in internal algorithms when building a SIMD value, but never modified after that. As a rule, the elements list may be modified before putting it in the record, but may not be modified once it is in a record for a SIMD value.</li>
</ul>
SIMD type descriptors have the following internal slots:
<ul>
<li>[[SIMDLength]]: The number of elements present in a SIMD value of the type</li>
<li>[[SIMDElementSize]]: Size in bytes of each element</li>
<li>[[SIMDCastNumber]]: An internal algorithm for down-casting a Number to the precision representable in the SIMD type</li>
<li>[[SIMDSerializeElement]]: An internal algorithm for writing a Number as [[SIMDElementSize]] bytes</li>
<li>[[SIMDDeserializeElement]]: An internal algorithm for converting [[SIMDElementSize]] bytes into a Number</li>
</ul>
<p>
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. It is noted in the section on each SIMD type whether it is an integer, boolean or floating point type.
</p>
<p>
The [[SIMDElementSize]], [[SIMDSerializeElement]] and [[SIMDDeserializeElement]] slots are optional, and defined only on certain SIMD types. Without these, cast, load and store operations are undefined. They come as a pair.
</p>
<emu-note>Rather than constructors having internal slots, this could be specified by a table analogous to Table 49 in the ES6 description for TypedArrays. However, the author finds it easier to express this purely in terms of records. TypedArrays could be specified like this too, and share some infrastructure with SIMD, but in their current form, it seems difficult to generalize them to SIMD directly.</emu-note>
<emu-note>SIMDCastNumber converts elements to Numbers; however, for most SIMD types, it will convert them to a restricted range of Number. In a real implementation, the numbers would likely be represented in a more compact form. However, the internal representation is not observable.</emu-note>
<emu-clause id="simd-algorithms">
<h1>Internal algorithms on SIMD types</h1>
<emu-clause id="simd-create" aoid="SIMDCreate">
<h1>SIMDCreate( descriptor, fields...)</h1>
This internal algorithm creates a new value of the type corresponding to the specified wrapper with the following procedure:
<emu-note>The following algorithm uses splat arguments in the spec and indexes them as an array, but there isn't proper machinery in the spec to describe this behavior</emu-note>
<emu-alg>
1. If Length(fields) == _descriptor_.[[SIMDLength]], then throw a TypeError.
1. Let _list_ be a new List of length _descriptor_.[[SIMDLength]].
1. For _i_ from 0 to _descriptor_.[[SIMDLength]],
1. Let _n_ be <var>descriptor</var>.[[SIMDCastNumber]](fields[<var>i</var>]).
1. ReturnIfAbrupt(_n_).
1. Set <var>list</var>[<var>i</var>] to _n_.
1. Return the record { [[SIMDTypeDescriptor]]: _descriptor_, [[SIMDElements]]: _list_ }.
</emu-alg>
</emu-clause>
<emu-clause id="simd-abstract-extract-lane" aoid="SIMDExtractLane">
<h1>SIMDExtractLane( value, field )</h1>
<emu-alg>
1. Assert: Type(_value_) is a _SIMD_Type.
1. If Type(_field_) is not Number, throw a TypeError
1. If _field_ != ToInt32(_field_) or _field_ < 0 or _field_ >= _descriptor_.[[SIMDLength]], throw a RangeError.
1. Return <var>value</var>.[[SIMDElements]][<var>field</var>]
</emu-alg>
<emu-note>While this single definition doesn't explicitly refer to the SIMD type in indexing the list, an implementation may use different representations for the Number elements on different types and generate different code for the accesses.</emu-note>
</emu-clause>
<emu-clause id="simd-abstract-replace-lane" aoid="SIMDReplaceLane">
<h1>SIMDReplaceLane( value, field, replacement )</h1>
<emu-alg>
1. Assert: Type(_value_) is a _SIMD_Type.
1. Let _descriptor_ be _a_.[[SIMDTypeDescriptor]].
1. If Type(_field_) is not Number, throw a TypeError
1. If _field_ != ToInt32(_field_) or _field_ < 0 or _field_ >= _descriptor_.[[SIMDLength]], throw a RangeError.
1. Let _list_ be a copy of _value_.[[SIMDElements]].
1. Set <var>list</var>[<var>field</var>] to _replacement_.
1. Return SIMDCreate(_descriptor_, ..._list_).
</emu-alg>
<emu-note>While this single definition doesn't explicitly refer to the SIMD type in indexing the list, an implementation may use different representations for the Number elements on different types and generate different code for the accesses.</emu-note>
</emu-clause>
<emu-clause id="simd-binary" aoid="SIMDBinaryOp">
<h1>SIMDBinaryOp( a, b, op, outputDescriptor )</h1>
<emu-alg>
1. Assert: _a_.[[SIMDTypeDescriptor]] is _b_.[[SIMDTypeDescriptor]]
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_.[[SIMDLength]].
1. For _i_ from 0 to _descriptor_.[[SIMDLength]],
1. Let _ax_ = SIMDExtractLane(_a_, _i_).
1. Let _bx_ = SIMDExtractLane(_b_, _i_).
1. Let _res_ = op(_ax_, _bx_).
1. ReturnIfAbrupt(_res_).
1. Set <var>list</var>[<var>i</var>] to _res_.
1. Return SIMDCreate(_outputDescriptor_, ..._list_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-unary" aoid="SIMDUnaryOp">
<h1>SIMDUnaryOp( a, op )</h1>
<emu-alg>
1. Let _descriptor_ be _a_.[[SIMDTypeDescriptor]].
1. Let _list_ be a new List of length _descriptor_.[[SIMDLength]].
1. ReturnIfAbrupt(_block_).
1. For _i_ from 0 to _descriptor_.[[SIMDLength]],
1. Let _ax_ = SIMDExtractLane(_a_, _i_).
1. Let _res_ = op(_ax_).
1. ReturnIfAbrupt(_res_).
1. Set <var>list</var>[<var>i</var>] to _res_.
1. Return SIMDCreate(_descriptor_, ..._list_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-scalar" aoid="SIMDUnaryOp">
<h1>SIMDScalarOp( a, scalar, op )</h1>
<emu-alg>
1. Let _descriptor_ be _a_.[[SIMDTypeDescriptor]].
1. Let _list_ be a new List of length _descriptor_.[[SIMDLength]].
1. ReturnIfAbrupt(_block_).
1. For _i_ from 0 to _descriptor_.[[SIMDLength]],
1. Let _ax_ = SIMDExtractLane(_a_, _i_).
1. Let _res_ = op(_ax_, _scalar_).
1. ReturnIfAbrupt(_res_).
1. Set <var>list</var>[<var>i</var>] to _res_.
1. Return SIMDCreate(_descriptor_, ..._list_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-load" aoid="SIMDLoad">
<h1>SIMDLoad( dataBlock, descriptor, byteOffset [, length] )</h1>
<emu-alg>
1. Assert: _dataBlock_ is a Data Block, _descriptor_ is a SIMD type descriptor
1. If _length_ is not provided, let _length_ be _descriptor_.[[SIMDLength]]. Otherwise, assert _length_ <= _descriptor_.[[SIMDLength]].
1. Assert: _byteOffset_ is an integer greater than or equal to zero, and less than or equal to the size of _dataBlock_ - _descriptor_.[[SIMDElementSize]] * _length_.
1. Let _list_ be a List of length _descriptor_.[[SIMDLength]], initialized to all 0.
1. For _i_ from 0 to _length_ - 1,
1. Set <var>list</var>[<var>i</var>] to <var>descriptor</var>.[[SIMDDeserializeElement]](<var>dataBlock</var>, _byteOffset_).
1. Return the record { [[SIMDTypeDescriptor]]: _descriptor_, [[SIMDElements]]: _list_ }.
</emu-alg>
</emu-clause>
<emu-clause id="simd-store" aoid="SIMDStore">
<h1>SIMDStore( dataBlock, descriptor, byteOffset, n [, length] )</h1>
<emu-alg>
1. Assert: _dataBlock_ is a Data Block, _descriptor_ is a SIMD type descriptor
1. If _length_ is not provided, let _length_ be _descriptor_.[[SIMDLength]]. Otherwise, assert _length_ <= _descriptor_.[[SIMDLength]].
1. Assert: _byteOffset_ is an integer greater than or equal to zero, and less than or equal to the size of _dataBlock_ - _descriptor_.[[SIMDElementSize]] * _length_.
1. For _i_ from 0 to _length_ - 1,
1. <var>descriptor</var>.[[SIMDSerializeElement]](<var>dataBlock</var>, _byteOffset_ + _i_ * _descriptor_.[[SIMDElementSize]], <var>n</var>.[[SIMDElements]][<var>i</var>]).
</emu-alg>
</emu-clause>
<emu-clause id="simd-reinterpret-cast" aoid="SIMDReinterpretCast">
<h1>SIMDReinterpretCast( value, newDescriptor )</h1>
<emu-note>This is used to define operations like SIMD.Float32x4.fromInt8x16Bits.</emu-note>
<emu-alg>
1. Assert: _value_.[[SIMDTypeDescriptor]].[[SIMDLength]] * _value_.[[SIMDTypeDescriptor]].[[SIMDElementSize]] == _newDescriptor_.[[SIMDLength]] * _newDescriptor_.[[SIMDElementSize]].
1. Let _bytes_ be _newDescriptor_.[[SIMDLength]] * _newDescriptor_.[[SIMDElementSize]].
1. Let _block_ be the result of CreateByteDataBlock(_bytes_).
1. ReturnIfAbrupt(_block_).
1. SIMDStore(_block_, _value_, 0).
1. Return SIMDLoad(_block_, _newDescriptor_, 0).
</emu-alg>
</emu-clause>
<emu-clause id="simd-int-type" aoid="SIMDBoolType">
<h1>SIMDBoolType( descriptor )</h1>
<emu-alg>
1. Assert: _descriptor_.[[SIMDLength]] * _descriptor.[[SIMDElementSize]] = 128. Otherwise, in a future extension to the spec, different boolean descriptors will be returned.
1. Let _length_ be _descriptor_.[[SIMDLength]].
1. If _length_ = 4, return Bool32x4Descriptor.
1. If _length_ = 8, return Bool16x8Descriptor.
1. Assert _length_ = 16.
1. Return Bool8x16Descriptor.
</emu-alg>
</emu-clause>
<emu-clause id="simd-boolean-op" aoid="SIMDBooleanOp">
<h1>SIMDBooleanOp( a, b, op )</h1>
<emu-alg>
1. Let _outputDescriptor_ be SIMDBoolType(_a_.[[SIMDTypeDescriptor]]).
1. Return SIMDBinaryOp(_a_, _b_, _op_, _outputDescriptor_).
</emu-alg>
</emu-clause>
<emu-clause id="UnsignedValue">
<h1>UnsignedValue( value, descriptor )</h1>
<emu-alg>
1. If _value_ < 0, let _value_ be _value_ + 1 << (_descriptor_.[[SIMDElementSize]] * 8).
1. Return _value_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-unsigned-boolean-op" aoid="SIMDUnsignedBooleanOp">
<h1>SIMDUnsignedBooleanOp( a, b, op )</h1>
<emu-alg>
1. Let _outputDescriptor_ be SIMDBoolType(_a_.[[SIMDTypeDescriptor]]).
1. Define the internal algorithm _unsignedOp_( _x_, _y_ ) as performing the following steps:
1. Return _op_(UnsignedValue(_a_.[[SIMDTypeDescriptor]], _x_), UnsignedValue(_a_.[[SIMDTypeDescriptor]], _y_))
1. Return SIMDBinaryOp(_a_, _b_, _unsignedOp_, _outputDescriptor_).
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="simd-constructor">
<h1>_SIMD_Constructor</h1>
<p>
Each _SIMD_Constructor, namely Float32x4, Int32x4, Int16x8, and Int8x16, 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.
</p>
<p>
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.
</p>
<emu-note>
As with Boolean, String, etc, _SIMD_Constructor is a constructor for the wrapper when invoked with new, and returns a primitive when called as a function.
</emu-note>
<emu-clause id="simd-wrap">
<h1>_SIMD_Constructor( value )</h1>
This description applies if the constructor is called with exactly one argument.
<emu-alg>
1. If ~NewTarget~ is undefined, throw a ~ReferenceError~ (NB: ~TypeError~?).
1. If _value_ is not of the type _SIMD_Type, throw a ~TypeError~.
1. Let _O_ be OrdinaryCreateFromConstructor(~NewTarget~, "%_SIMD_Prototype%", «[[SIMDWrapperData]]» ).
1. ReturnIfAbrupt(_O_).
1. Set the value of _O_’s [[SIMDWrapperData]] internal slot to _value_.
1. Return _O_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-wrapper">
<h1>_SIMD_Constructor( fields... )</h1>
This description applies if the constructor is called with more than one argument.
<emu-alg>
1. If _SIMD_Descriptor.[[SIMDElementsLength]] does not equal Length(fields), throw a TypeError.
1. Return SIMDCreate(_SIMD_Descriptor, fields...).
</emu-alg>
</emu-clause>
<emu-clause id="simd-splat">
<h1>_SIMD_Constructor.splat(n)</h1>
<emu-alg>
1. Let _list_ be a new List of length _SIMD_Descriptor.[[SIMDLength]], with all entries filled with _n_.
1. Return SIMDCreate(_SIMD_Descriptor, ..._list_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-check">
<h1>_SIMD_Constructor.check(a)</h1>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Return _a_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-add">
<h1>_SIMD_Constructor.add(a, b)</h1>
This definition uses the refers to + as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-addition-operator-plus">ES2015 12.7.3 (The Addition operator ( + ))</a>, with the following change in behavior: If either argument to + is a sub-normal floating point number, then the result is defined as either gradual underflow or flushing that argument to 0.
<emu-note>The definition is weaker for SIMD than for scalar + to allow for implementation on some SIMD architectures which flush to 0 on subnormals.</emu-note>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, +).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-sub">
<h1>_SIMD_Constructor.sub(a, b)</h1>
This definition uses the refers to - as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-subtraction-operator-minus">ES2015 12.7.4 (The Subtraction operator ( - ))</a>, with the following change in behavior: If either argument to - is a sub-normal floating point number, then the result is defined as either gradual underflow or flushing that argument to 0.
<emu-note>The definition is weaker for SIMD than for scalar - to allow for implementation on some SIMD architectures which flush to 0 on subnormals.</emu-note>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, -).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-mul">
<h1>_SIMD_Constructor.mul(a, b)</h1>
This definition uses the refers to - as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-applying-the-mul-operator">ES2015 12.6.3.1 (Applying the * Operator)</a>, with the following change in behavior: If either argument to * is a sub-normal floating point number, then the result is defined as either gradual underflow or flushing that argument to 0.
<emu-note>The definition is weaker for SIMD than for scalar * to allow for implementation on some SIMD architectures which flush to 0 on subnormals.</emu-note>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If _SIMD_Type is an integer SIMD type, let _op_ be %Math_imul%; otherwise, _SIMD_Type is a floating point SIMD type, and let _op_ be <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-applying-the-mul-operator">*</a>.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, _op_).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-div">
<h1>_SIMD_Constructor.div(a, b)</h1>
<p>
This definition uses the refers to - as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-applying-the-div-operator">ES2015 12.6.3.2 (Applying the / Operator)</a>, with the following change in behavior: If either argument to / is a sub-normal floating point number, then the result is defined as either as either gradual underflow or flushing that argument to 0.
</p>
<emu-note>The definition is weaker for SIMD than for scalar / to allow for implementation on some SIMD architectures which flush to 0 on subnormals.</emu-note>
<p>
This function is defined only on floating point SIMD types.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-applying-the-div-operator">/</a>).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-max">
This property is defined only on floating point SIMD types.
<h1>_SIMD_Constructor.max(a, b)</h1>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, %Math_max%).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-min">
This property is defined only on floating point SIMD types.
<h1>_SIMD_Constructor.min(a, b)</h1>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, %Math_min%).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="max-num" aoid="MaxNum">
<h1>MaxNum(n, m)</h1>
<emu-alg>
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 Call(%Math_max%, %Math%, «_n_, _m_»).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-max-num">
<h1>_SIMD_Constructor.maxNum(a, b)</h1>
This property is defined only on floating point SIMD types.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, MaxNum).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="min-num" aoid="MinNum">
<h1>MinNum(n, m)</h1>
<emu-alg>
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 Call(%Math_min%, %Math%, «_n_, _m_»).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-min-num">
<h1>_SIMD_Constructor.minNum(a, b)</h1>
This property is defined only on floating point SIMD types.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, MinNum).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-neg">
<h1>_SIMD_Constructor.neg(a)</h1>
This definition uses the refers to unary - as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-unary-minus-operator">ES2015 12.5.10 (Unary - Operator)</a>.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnaryOp(_a_, <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-unary-minus-operator">-</a>).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-sqrt">
<h1>_SIMD_Constructor.sqrt(a)</h1>
This property is defined only on floating point SIMD types.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnaryOp(_a_, %Math_sqrt%).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="reciprocal" aoid="ReciprocalApproximation">
<h1>ReciprocalApproximation(n)</h1>
Returns an implementation-dependent approximation to the reciprocal of _n_.
<ul>
<li>If _n_ is ~NaN~, the result is ~NaN~.</li>
<li>If _n_ is +0, the result is +∞.</li>
<li>If _n_ is -0, the result is -∞.</li>
<li>If _n_ is +∞, the result is +0.</li>
<li>If _n_ is -∞, the result is -0.</li>
</ul>
</emu-clause>
<emu-clause id="simd-reciprocal-approximation">
<h1>_SIMD_Constructor.reciprocalApproximation(a, b)</h1>
This property is defined only on floating point SIMD types.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnaryOp(_a_, ReciprocalApproximation).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="reciprocal" aoid="ReciprocalSqrtApproximation">
<h1>ReciprocalSqrtApproximation(n)</h1>
Returns an implementation-dependent approximation to the reciprocal of the square root of _n_.
<ul>
<li>If _n_ is ~NaN~, the result is ~NaN~.</li>
<li>If _n_ is +0, the result is +∞.</li>
<li>If _n_ is -0, the result is -∞.</li>
<li>If _n_ is +∞, the result is +0.</li>
<li>If _n_ is less than 0, the result is ~NaN~.</li>
</ul>
</emu-clause>
<emu-clause id="simd-reciprocal-sqrt-approximation">
<h1>_SIMD_Constructor.reciprocalSqrtApproximation(a)</h1>
This property is defined only on floating point SIMD types.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnaryOp(_a_, ReciprocalSqrtApproximation).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-abs">
<h1>_SIMD_Constructor.abs(a)</h1>
This operation exists only on floating point SIMD types.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnaryOp(_a_, %Math_abs%).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-and">
<h1>_SIMD_Constructor.and(a, b)</h1>
<p>
This definition uses the refers to & as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-binary-bitwise-operators">ES2015 12.11 (Binary Bitwise Operators)</a>.
</p>
<p>
This operation exists only on integer and boolean SIMD types.
</p>
<emu-note>On boolean types, this could have been specified as using && rather than &. However, the behavior is the same, as `ToBoolean(x&y)` is the same as `x && y` for boolean `x` and `y`. The same goes for `or` below.</emu-note>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, &).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-xor">
<h1>_SIMD_Constructor.xor(a, b)</h1>
<p>
This definition uses the refers to ^ as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-binary-bitwise-operators">ES2015 12.11 (Binary Bitwise Operators)</a>.
</p>
<p>
This operation exists only on integer and boolean SIMD types.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, ^).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-or">
<h1>_SIMD_Constructor.or(a, b)</h1>
<p>
This definition uses the refers to | as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-binary-bitwise-operators">ES2015 12.11 (Binary Bitwise Operators)</a>.
</p>
<p>
This operation exists only on integer and boolean SIMD types.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, |).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-not">
<h1>_SIMD_Constructor.not(a)</h1>
<p>
This definition uses the refers to ~ as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-bitwise-not-operator">ES2015 12.5.11</a> (Bitwise NOT Operator ( ~ )).
</p>
<p>
This operation exists only on integer and boolean SIMD types.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnaryOp(_a_, ~).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-less-than">
<h1>_SIMD_Constructor.lessThan(a, b)</h1>
<p>
This definition uses the refers to < as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">ES2015 7.2.11 (Abstract Relational Comparison)</a>.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBooleanOp(_a_, _b_, <).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Does abstract relational comparison correspond to what hardware accelerates?</emu-note>
</emu-clause>
<emu-clause id="simd-less-than-or-equal">
<h1>_SIMD_Constructor.lessThanOrEqual(a, b)</h1>
<p>
This definition uses the refers to <= as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">ES2015 7.2.11 (Abstract Relational Comparison)</a>.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBooleanOp(_a_, _b_, <=).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Does abstract relational comparison correspond to what hardware accelerates?</emu-note>
</emu-clause>
<emu-clause id="simd-greater-than">
<h1>_SIMD_Constructor.greaterThan(a, b)</h1>
<p>
This definition uses the refers to > as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">ES2015 7.2.11 (Abstract Relational Comparison)</a>.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBooleanOp(_a_, _b_, >).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-greater-than-or-equal">
<h1>_SIMD_Constructor.greaterThanOrEqual(a, b)</h1>
<p>
This definition uses the refers to >= as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">ES2015 7.2.11 (Abstract Relational Comparison)</a>.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBooleanOp(_a_, _b_, >=).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Does abstract relational comparison correspond to what hardware accelerates?</emu-note>
</emu-clause>
<emu-clause id="simd-unsigned-less-than">
<h1>_SIMD_Constructor.unsignedLessThan(a, b)</h1>
<p>
This definition uses the refers to < as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">ES2015 7.2.11 (Abstract Relational Comparison)</a>.
</p>
<p>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnsignedBooleanOp(_a_, _b_, <).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Does abstract relational comparison correspond to what hardware accelerates?</emu-note>
</emu-clause>
<emu-clause id="simd-unsigned-less-than-or-equal">
<h1>_SIMD_Constructor.unsignedLessThanOrEqual(a, b)</h1>
<p>
This definition uses the refers to <= as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">ES2015 7.2.11 (Abstract Relational Comparison)</a>.
</p>
<p>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnsignedBooleanOp(_a_, _b_, <=).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Does abstract relational comparison correspond to what hardware accelerates?</emu-note>
</emu-clause>
<emu-clause id="simd-unsigned-greater-than">
<h1>_SIMD_Constructor.unsignedGreaterThan(a, b)</h1>
<p>
This definition uses the refers to > as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">ES2015 7.2.11 (Abstract Relational Comparison)</a>.
</p>
<p>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDUnsignedBooleanOp(_a_, _b_, >).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-unsigned-greater-than-or-equal">
<h1>_SIMD_Constructor.unsignedGreaterThanOrEqual(a, b)</h1>
<p>
This definition uses the refers to >= as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-relational-comparison">ES2015 7.2.11 (Abstract Relational Comparison)</a>.
</p>
<p>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBooleanOp(_a_, _b_, >=).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Does abstract relational comparison correspond to what hardware accelerates?</emu-note>
</emu-clause>
<emu-clause id="simd-equal">
<h1>_SIMD_Constructor.equal(a, b)</h1>
<p>
This definition uses the refers to === as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-strict-equality-comparison">ES2015 7.2.13 (Strict Equality Comparison)</a>.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBooleanOp(_a_, _b_, ===).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>The polyfill uses ==. Does this behavior on NaN, +0, -0 correspond to what hardware accelerates?</emu-note>
</emu-clause>
<emu-clause id="simd-not-equal">
<h1>_SIMD_Constructor.notEqual(a, b)</h1>
<p>
This definition uses the refers to !== as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-strict-equality-comparison">ES2015 7.2.13 (Strict Equality Comparison)</a>.
</p>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBooleanOp(_a_, _b_, !==).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>The polyfill uses ==. Does this behavior on NaN, +0, -0 correspond to what hardware accelerates?</emu-note>
</emu-clause>
<emu-clause id="simd-any-true">
<h1>_SIMD_Constructor.anyTrue(a)</h1>
This is defined on boolean SIMD types.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. For _i_ from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1,
1. If <var>a</var>.[[SIMDElements]][<var>i</var>] is ~true~, return ~true~.
1. Return ~false~.
</emu-alg>
</emu-clause>
<emu-clause id="simd-all-true">
<h1>_SIMD_Constructor.allTrue(a)</h1>
This is defined on boolean SIMD types.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. For _i_ from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1,
1. If <var>a</var>.[[SIMDElements]][<var>i</var>] is ~false~, return ~false~.
1. Return ~true~.
</emu-alg>
</emu-clause>
<emu-clause id="simd-select">
<h1>_SIMD_Constructor.select( selector, a, b )</h1>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _outputDescriptor_ be SIMDBoolType(_SIMD_Descriptor).
1. If _selector_.[[SIMDTypeDescriptor]] is not _outputDescriptor_, throw a TypeError.
1. Let _list_ be a new List.
1. For _i_ from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1,
1. If <var>sector</var>.[[SIMDElements]][<var>i</var>] is ~true~, let <var>list</var>[<var>i</var>] be <var>a</var>.[[SIMDElements]][<var>i</var>].
1. Otherwise, let <var>list</var>[<var>i</var>] be <var>b</var>.[[SIMDElements]][<var>i</var>].
1. Return SIMDCreate(_SIMD_Descriptor, ..._list_).
</emu-alg>
</emu-clause>
<emu-clause id="saturate" aoid="Saturate">
<h1>Saturate( byteWidth, x )</h1>
<emu-alg>
1. Let _max_ be 1 << (_byteWidth_ * 8 - 1).
1. Let _z_ be _x_ + _y_.
1. If _z_ >= _max_, let _z_ be _max_ - 1.
1. Otherwise, if _z_ < -_max_, let _z_ be -_max_.
1. Return _z_.
</emu-alg>
</emu-clause>
<emu-clause id="add-saturate" aoid="AddSaturate">
<h1>AddSaturate( byteWidth )( x, y )</h1>
<emu-alg>
1. Return Saturate(_byteWidth_, _x_ + _y_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-add-saturate">
<h1>_SIMD_Constructor.addSaturate( a, b )</h1>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, AddSaturate(_a_.[[SIMDTypeDescriptor]].[[SIMDElementSize]])).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="sub-saturate" aoid="SubSaturate">
<h1>SubSaturate( byteWidth )( x, y )</h1>
<emu-alg>
1. Return Saturate(_byteWidth_, _x_ - _y_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-sub-saturate">
<h1>_SIMD_Constructor.subSaturate( a, b )</h1>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, SubSaturate(_a_.[[SIMDTypeDescriptor]].[[SIMDElementSize]])).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="unsigned-saturate" aoid="UnsignedSaturate">
<h1>UnsignedSaturate( byteWidth, x )</h1>
<emu-alg>
1. Let _max_ be 1 << _byteWidth_ * 8.
1. Let _z_ be _x_ + _y_.
1. If _z_ >= _max_, let _z_ be _max_ - 1.
1. Otherwise, if _z_ < 0, let _z_ be 0.
1. Return _z_.
</emu-alg>
</emu-clause>
<emu-clause id="unsigned-add-saturate" aoid="UnsignedAddSaturate">
<h1>UnsignedAddSaturate( byteWidth )( x, y )</h1>
<emu-alg>
1. Return UnsignedSaturate(_byteWidth_, _x_ + _y_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-unsigned-add-saturate">
<h1>_SIMD_Constructor.unsignedAddSaturate( a, b )</h1>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, UnsignedAddSaturate(_a_.[[SIMDTypeDescriptor]].[[SIMDElementSize]])).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="unsigned-sub-saturate" aoid="UnsignedSubSaturate">
<h1>UnsignedSubSaturate( byteWidth )( x, y )</h1>
<emu-alg>
1. Return UnsignedSaturate(_byteWidth_, _x_ - _y_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-unsigned-sub-saturate">
<h1>_SIMD_Constructor.unsignedSubSaturate( a, b )</h1>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, UnsignedSubSaturate(_a_.[[SIMDTypeDescriptor]].[[SIMDElementSize]])).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-shift-left-by-scalar">
<h1>_SIMD_Constructor.shiftLeftByScalar( a, scalar )</h1>
This operation is only defined on integer SIMD types. This definition uses the refers to << as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-left-shift-operator">ES2015 12.8.3 (The Left Shift Operator ( << ))</a>.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If ToUint32(_scalar_) does not equal _scalar_, throw a TypeError.
1. If _scalar_ >= _SIMD_Descriptor.[[SIMDElementSize]] * 8, then
1. Let _list_ be a list of length _SIMD_Descriptor.[[SIMDLength]], filled with 0.
1. return SIMDCreate(_SIMD_Descriptor, _list_).
1. Let _result_ be SIMDScalarOp(_a_, _scalar_, <<).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Unlike ECMAScript scalar shift, there is no "wrap-around" behavior.</emu-note>
</emu-clause>
<emu-clause id="simd-shift-right-logical-by-scalar">
<h1>_SIMD_Constructor.shiftRightLogicalByScalar( a, scalar )</h1>
This operation is only defined on integer SIMD types. This definition uses the refers to >>> as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-unsigned-right-shift-operator">ES2015 12.8.5 (The Unsigned Right Shift Operator ( >>> ))</a>.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If ToUint32(_scalar_) does not equal _scalar_, throw a TypeError.
1. If _scalar_ >= _SIMD_Descriptor.[[SIMDElementSize]] * 8, then
1. Let _list_ be a list of length _SIMD_Descriptor.[[SIMDLength]], filled with 0.
1. return SIMDCreate(_SIMD_Descriptor, _list_).
1. Let _result_ be SIMDScalarOp(_a_, _scalar_, >>>).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Unlike ECMAScript scalar shift, there is no "wrap-around" behavior.</emu-note>
</emu-clause>
<emu-clause id="simd-shift-right-arithmetic-by-scalar">
<h1>_SIMD_Constructor.shiftRightArithmeticByScalar( a, scalar )</h1>
This operation is only defined on integer SIMD types. This definition uses the refers to >> as defined by <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-signed-right-shift-operator">ES2015 12.8.4 (The Signed Right Shift Operator ( >> ))</a>.
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If ToUint32(_scalar_) does not equal _scalar_, throw a TypeError.
1. If _scalar_ >= _SIMD_Descriptor.[[SIMDElementSize]] * 8, then
1. Let _list_ be a list of length _SIMD_Descriptor.[[SIMDLength]], filled with 0.
1. return SIMDCreate(_SIMD_Descriptor, _list_).
1. Let _result_ be SIMDScalarOp(_a_, _scalar_, >>).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
<emu-note>Unlike ECMAScript scalar shift, there is no "wrap-around" behavior.</emu-note>
</emu-clause>
<emu-clause id="simd-unsigned-horizontal-sum">
<h1>_SIMD_Constructor.unsignedHorizontalSum( a )</h1>
This operation is only defined on integer SIMD types.
<emu-note>This operation is still under discussion. See <a href="https://github.com/johnmccutchan/ecmascript_simd/issues/135">this bug thread</a>.</emu-note>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _sum_ be 0.
1. For _i_ from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1,
1. Let _sum_ be _sum_ + UnsignedValue(_a_.[[SIMDElements]][<var>i</var>], _SIMD_Descriptor).
1. Return _sum_.
</emu-alg>
</emu-clause>
<emu-clause id="absolute-difference" aoid="AbsoluteDifference">
<h1>AbsoluteDifference( a, b )</h1>
<emu-alg>
1. Return Call(%Math_abs%, %Math%, «_a_ - _b_»).
</emu-alg>
</emu-clause>
<emu-clause id="simd-unsigned-absolte-difference">
<h1>_SIMD_Constructor.unsignedAbsoluteDifference( a, b )</h1>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
<emu-note>This operation is still under discussion. See <a href="https://github.com/johnmccutchan/ecmascript_simd/issues/135">this bug thread</a>.</emu-note>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _result_ be SIMDBinaryOp(_a_, _b_, AbsoluteDifference).
1. ReturnIfAbrupt(_result_).
1. Return _result_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-unsigned-widened-absolute-difference">
<h1>_SIMD_Constructor.widenedUnsignedAbsoluteDifference( a, b )</h1>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
<emu-note>This operation is still under discussion. See <a href="https://github.com/johnmccutchan/ecmascript_simd/issues/135">this bug thread</a>. To use this operation and get at the upper half of a vector, a shuffle is required.</emu-note>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor or _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If _SIMD_Descriptor is `Int8x16`, then let _outputDescriptor_ be `Int16x8`.
1. Else, Assert _SIMD_Descriptor is `Int16x8`; let _outputDescriptor_ be `Int32x4`.
1. Let _list_ be a new List of length _descriptor_.[[SIMDLength]].
1. For _i_ from 0 to _outputDescriptor_.[[SIMDLength]],
1. Let _ax_ = SIMDExtractLane(_a_, _i_).
1. Let _bx_ = SIMDExtractLane(_b_, _i_).
1. Let _res_ = AbsoluteDifference(_ax_, _bx_).
1. ReturnIfAbrupt(_res_).
1. Set <var>list</var>[<var>i</var>] to _res_.
1. Return SIMDCreate(_outputDescriptor_, ..._list_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-extract-lane">
<h1>_SIMD_Constructor.extractLane( simd, field )</h1>
<emu-alg>
1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Return SIMDExtractLane(_simd_, _field_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-unsigned-extract-lane">
<h1>_SIMD_Constructor.unsignedExtractLane( simd, field )</h1>
This operation is only defined on integer SIMD types whose _SIMD_Descriptor.[[SIMDElementSize]] <= 2.
<emu-alg>
1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Let _value_ SIMDExtractLane(_simd_, _field_).
1. Return UnsignedValue(_value_, _descriptor_).
</emu-alg>
<emu-note>No unsignedReplaceLane or unsigned constructor is needed because replaceLane's implicit cast will handle unsigned elements.</emu-note>
</emu-clause>
<emu-clause id="simd-replace-lane">
<h1>_SIMD_Constructor.replaceLane(simd, field, value)</h1>
<emu-alg>
1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. Return SIMDReplaceLane(_simd_, _field_, _value_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-store-function">
<h1>_SIMD_Constructor.store(tarray, index, simd)</h1>
This is defined when _SIMD_Descriptor has a [[SIMDSerializeElement]] internal slot.
<emu-note>The first seven steps of the following `store`/`load` functions are very similar. A refactoring could reduce the spec size.</emu-note>
<emu-alg>
1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError.
1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]]
1. If _index_ != ToInt32(_index_), throw a TypeError.
1. Let _elementLength_ be _tarray_.[[ByteLength]] / _tarray.[[ArrayLength]].
1. Let _byteIndex_ be _index_ * _elementLength_.
1. If _byteIndex_ + _SIMD_Descriptor.[[SIMDElementSize]] * _SIMD_Descriptor.[[SIMDLength]] > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError.
1. SIMDStore(_block_, _SIMD_Descriptor, _byteIndex_, _simd_).
1. Return _simd_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-store1">
<h1>_SIMD_Constructor.store1(tarray, index, simd)</h1>
This function is defined only on SIMD types where _SIMD_Descriptor.[[SIMDLength]] == 4, and when _SIMD_Descriptor has a [[SIMDSerializeElement]] internal slot.
<emu-note>In this specification, that set consists of Float32x4 and Int32x4.</emu-note>
<emu-alg>
1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError.
1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]]
1. If _index_ != ToInt32(_index_), throw a TypeError.
1. Let _elementLength_ be _tarray_.[[ByteLength]] / _tarray.[[ArrayLength]].
1. Let _byteIndex_ be _index_ * _elementLength_.
1. If _byteIndex_ + _SIMD_Descriptor.[[SIMDElementSize]] > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError.
1. SIMDStore(_block_, _SIMD_Descriptor, _byteIndex_, _simd_, 1).
1. Return _simd_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-store2">
<h1>_SIMD_Constructor.store2(tarray, index, simd)</h1>
This function is defined only on SIMD types where _SIMD_Descriptor.[[SIMDLength]] == 4, and when _SIMD_Descriptor has a [[SIMDSerializeElement]] internal slot.
<emu-note>In this specification, that set consists of Float32x4 and Int32x4.</emu-note>
<emu-alg>
1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError.
1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]]
1. If _index_ != ToInt32(_index_), throw a TypeError.
1. Let _elementLength_ be _tarray_.[[ByteLength]] / _tarray.[[ArrayLength]].
1. Let _byteIndex_ be _index_ * _elementLength_.
1. If _byteIndex_ + _SIMD_Descriptor.[[SIMDElementSize]] * 2 > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError.
1. SIMDStore(_block_, _SIMD_Descriptor, _byteIndex_, _simd_, 2).
1. Return _simd_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-store3">
<h1>_SIMD_Constructor.store3(tarray, index)</h1>
This function is defined only on SIMD types where _SIMD_Descriptor.[[SIMDLength]] == 4, and when _SIMD_Descriptor has a [[SIMDSerializeElement]] internal slot.
<emu-note>In this specification, that set consists of Float32x4 and Int32x4.</emu-note>
<emu-alg>
1. If _simd_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a TypeError.
1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError.
1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]]
1. If _index_ != ToInt32(_index_), throw a TypeError.
1. Let _elementLength_ be _tarray_.[[ByteLength]] / _tarray.[[ArrayLength]].
1. Let _byteIndex_ be _index_ * _elementLength_.
1. If _byteIndex_ + _SIMD_Descriptor.[[SIMDElementSize]] * 3 > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError.
1. SIMDStore(_block_, _SIMD_Descriptor, _byteIndex_, 3).
1. Return _simd_.
</emu-alg>
</emu-clause>
<emu-clause id="simd-load-function">
<h1>_SIMD_Constructor.load(tarray, index)</h1>
This function is defined only on SIMD types where _SIMD_Descriptor has a [[SIMDDeserializeElement]] internal slot.
<emu-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).</emu-note>
<emu-alg>
1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError.
1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]]
1. If _index_ != ToInt32(_index_), throw a TypeError.
1. Let _elementLength_ be _tarray_.[[ByteLength]] / _tarray_.[[ArrayLength]].
1. Let _byteIndex_ be _index_ * _elementLength_.
1. If _byteIndex_ + _SIMD_Descriptor.[[SIMDElementSize]] * _SIMD_Descriptor.[[SIMDLength]] > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError.
1. Return SIMDLoad(_block_, _SIMD_Descriptor, _byteIndex_).
</emu-alg>
</emu-clause>
<emu-clause id="simd-load1">
<h1>_SIMD_Constructor.load1(tarray, index)</h1>
This function is defined only on SIMD types where _SIMD_Descriptor.[[SIMDLength]] == 4 and _SIMD_Descriptor has a [[SIMDDeserializeElement]] internal slot.
<emu-note>In this specification, that set consists of Float32x4 and Int32x4.</emu-note>
<emu-alg>
1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError.
1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]]
1. If _index_ != ToInt32(_index_), throw a TypeError.
1. Let _elementLength_ be _tarray_.[[ByteLength]] / _tarray.[[ArrayLength]].
1. Let _byteIndex_ be _index_ * _elementLength_.
1. If _byteIndex_ + _SIMD_Descriptor.[[SIMDElementSize]] > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError.
1. Return SIMDLoad(_block_, _SIMD_Descriptor, _byteIndex_, 1).
</emu-alg>
</emu-clause>
<emu-clause id="simd-load2">
<h1>_SIMD_Constructor.load2(tarray, index)</h1>
This function is defined only on SIMD types where _SIMD_Descriptor.[[SIMDLength]] == 4 and _SIMD_Descriptor has a [[SIMDDeserializeElement]] internal slot.
<emu-note>In this specification, that set consists of Float32x4 and Int32x4.</emu-note>
<emu-alg>
1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError.
1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]]
1. If _index_ != ToInt32(_index_), throw a TypeError.
1. Let _elementLength_ be _tarray_.[[ByteLength]] / _tarray.[[ArrayLength]].
1. Let _byteIndex_ be _index_ * _elementLength_.
1. If _byteIndex_ + _SIMD_Descriptor.[[SIMDElementSize]] * 2 > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError.
1. Return SIMDLoad(_block_, _SIMD_Descriptor, _byteIndex_, 2).
</emu-alg>
</emu-clause>
<emu-clause id="simd-load3">
<h1>_SIMD_Constructor.load3(tarray, index)</h1>
This function is defined only on SIMD types where _SIMD_Descriptor.[[SIMDLength]] == 4 and _SIMD_Descriptor has a [[SIMDDeserializeElement]] internal slot.
<emu-note>In this specification, that set consists of Float32x4 and Int32x4.</emu-note>
<emu-alg>
1. If _tarray_ does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError.
1. Let _block_ be _tarray_.[[ViewedArrayBuffer]].[[ArrayBufferData]]
1. If _index_ != ToInt32(_index_), throw a TypeError.
1. Let _elementLength_ be _tarray_.[[ByteLength]] / _tarray.[[ArrayLength]].
1. Let _byteIndex_ be _index_ * _elementLength_.
1. If _byteIndex_ + _SIMD_Descriptor.[[SIMDElementSize]] * 3 > _tarray_.[[ByteLength]] or _byteIndex_ < 0, throw a RangeError.
1. Return SIMDLoad(_block_, _SIMD_Descriptor, _byteIndex_, 3).
</emu-alg>
</emu-clause>
<emu-clause id="simd-to-timd">
<h1><var>SIMD</var>Constructor.from<var>TIMD</var>Bits( value )</h1>
In this definition, _TIMD_ ranges over all SIMD types for which _SIMD_Descriptor.[[SIMDElementSize]] * _SIMD_Descriptor.[[SIMDLength]] == _TIMD_Descriptor.[[SIMDElementSize]] * _TIMD_Descriptor.[[SIMDLength]].
<emu-note>All of the SIMD types described in this spec are 16 bytes, so all pairs are included.</emu-note>
<emu-alg>
1. If _value_.[[SIMDTypeDescriptor]] is not _TIMD_Descriptor, throw a TypeError.
1. Return SIMDReinterpretCast(_value_, _SIMD_Descriptor).
</emu-alg>
</emu-clause>
<emu-clause id="simd-to-timd-logical">
<h1><var>SIMD</var>Constructor.from<var>TIMD</var>( value )</h1>
In this definition, _TIMD_ ranges over all SIMD types for which _SIMD_Descriptor.[[SIMDLength]] == _TIMD_Descriptor.[[SIMDLength]].
<emu-alg>
1. If _value_.[[SIMDTypeDescriptor]] is not _TIMD_Descriptor, throw a TypeError.
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~.
1. Return SIMDCreate(_SIMD_Descriptor, ..._list_).
</emu-alg>
</emu-clause>
<emu-clause id="swizzle">
<h1>_SIMD_.swizzle( a, lanes... )</h1>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a ~TypeError~.
1. If the length of _lanes_ does not equal _SIMD_Descriptor.[[SIMDLength]], throw a ~TypeError~.
1. For each _lane_ in _lanes_:
1. If _lane_ is not a Number, or _lane_ != ToInt32(_lane_), throw a ~TypeError~.
1. If _lane_ < 0 or _lane_ >= _SIMD_Descriptor.[[SIMDLength]], throw a ~RangeError~.
1. Let _list_ be a new List of length _SIMD_Descriptor.[[SIMDLength]].
1. For _i_ in from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1,
1. Set <var>list</var>[<var>i</var>] to SIMDExtractLane(_a_, <var>lanes</var>[<var>i</var>])
1. Return SIMDCreate(_SIMD_Descriptor, ..._list_).
</emu-alg>
</emu-clause>
<emu-clause id="shuffle">
<h1>_SIMD_.shuffle( a, b, lanes... )</h1>
<emu-alg>
1. If _a_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, or if _b_.[[SIMDTypeDescriptor]] is not _SIMD_Descriptor, throw a ~TypeError~.
1. If the length of _lanes_ does not equal _SIMD_Descriptor.[[SIMDLength]] * 2, throw a ~TypeError~.
1. For each _lane_ in _lanes_:
1. If _lane_ is not a Number, or _lane_ != ToInt32(_lane_), throw a ~TypeError~.
1. If _lane_ < 0 or _lane_ >= _SIMD_Descriptor.[[SIMDLength]] * 2, throw a ~RangeError~.
1. Let _list_ be a new List of length _SIMD_Descriptor.[[SIMDLength]].
1. For _i_ in from 0 to _SIMD_Descriptor.[[SIMDLength]] - 1,
1. Let _idx_ be <var>lanes</var>[<var>i</var>].
1. If _idx_ >= _SIMD_Descriptor.[[SIMDLength]],
1. Set <var>list</var>[<var>i</var>] to SIMDExtractLane(_b_, <var>lanes</var>[<var>i</var>] - _SIMD_Descriptor.[[SIMDLength]])
1. Otherwise,
1. Set <var>list</var>[<var>i</var>] to SIMDExtractLane(_a_, <var>lanes</var>[<var>i</var>])
1. Return SIMDCreate(_SIMD_Descriptor, ..._list_).
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="simd-proto">
<h1>The _SIMD_Constructor.prototype</h1>
<emu-note>
Previously, if accessors like x were included, these would be spec'd as getters (with null setter) on the _SIMD_Constructor.prototype . However, they have been removed in favor of _SIMD_Constructor.extractLane. Are there any non-trivial properties? Users could add methods like .add() here if they want to use SIMD in an object-oriented way. It would also be easy to define properties on the prototype that would make SIMD values and wrapper objects array-like.
</emu-note>
<emu-clause id="simd-proto-constructor">
<h1>_SIMD_Constructor.prototype.constructor</h1>
The initial value of _SIMD_Constructor.prototype.constructor is the intrinsic object %_SIMD_Constructor%
</emu-clause>
<emu-clause id="simd-prototype-valueof">
<h1>_SIMD_Constructor.prototype.valueOf()</h1>
<emu-alg>
1. If ~this~ does not have a [[SIMDWrapperData]] internal slot, throw a ~TypeError~.
1. Return ~this~.[[SIMDWrapperData]].
</emu-alg>
</emu-clause>
<emu-clause id="simd-prototype-tolocalestring">
<h1>_SIMD_Constructor.prototype.toLocaleString()</h1>
<emu-alg>
1. If ~this~ does not have a [[SIMDWrapperData]] internal slot, throw a ~TypeError~.
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 an Array containing the contents of _list_.
1. Let _t_ be the string `"`<var>SIMD</var>`"`, e.g., `"Float32x4"`.
1. Let _e_ be Call(%ArrayPrototype_join%, _results_, «_separator_»).
1. Return a new String value computed by concatenating the previous value of _t_, "(", _e_, and ")".
</emu-alg>
</emu-clause>
<emu-clause id="simd-prototype-tostring">
<h1>_SIMD_Constructor.prototype.toString()</h1>
<emu-alg>
1. If ~this~ does not have a [[SIMDWrapperData]] internal slot, throw a ~TypeError~.
1. Return ToString(~this~.[[SIMDWrapperData]]).
</emu-alg>
<emu-note>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.</emu-note>
</emu-clause>
<emu-clause>
<h1>_SIMD_Constructor.prototype [ @@toStringTag ]</h1>
<p>
The initial value of the @@toStringTag property is the String value `"SIMD.`_SIMD_`"`, e.g., `"SIMD.Float32x4"`.
<p>
</p>
This property has the attributes { [[Writable]]: ~false~, [[Enumerable]]: ~false~, [[Configurable]]: ~true~ }.
</p>
</emu-clause>
</emu-clause>
<emu-clause id="simd-descriptors">
<h1>SIMD type descriptors</h1>
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.
<emu-clause id="simd-float32x4">
<h1>Float32x4Descriptor type descriptor</h1>
<p>
The Float32x4Descriptor floating point SIMD type descriptor has the following internal slots:
</p>
<ul>
<li>[[SIMDLength]]: 4</li>
<li>[[SIMDElementSize]]: 4</li>
<li>[[SIMDCastNumber]]: %Math_fround%</li>
<li>[[SIMDSerializeElement]]: SerializeFloat32</li>
<li>[[SIMDDeserializeElement]]: DeserializeFloat32</li>
</ul>
<emu-clause id="serialize-float32" aoid="SerializeFloat32">
<h1>SerializeFloat32( block, offset, n, isLittleEndian )</h1>
<emu-note>Derived from part of <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-setvalueinbuffer">SetValueInBuffer</a>. 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.</emu-note>
<emu-alg>
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 <var>block</var>[<var>offset</var>].
</emu-alg>
</emu-clause>
<emu-clause id="deserialize-float32" aoid="DeserializeFloat32">
<h1>DeserializeFloat32( block, offset, isLittleEndian )</h1>
<emu-note>Derived from part of <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-getvaluefrombuffer">GetValueFromBuffer</a>. Note that while this says to return "the ~NaN~ value", the binary representation is not observable and canonicalization is not required.</emu-note>
<emu-alg>
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 <var>block</var>[<var>offset</var>].
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_.
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="simd-int32x4">
<h1>Int32x4Descriptor type descriptor</h1>
<p>
The Int32x4Descriptor integer SIMD type descriptor has the following internal slots:
</p>
<ul>
<li>[[SIMDLength]]: 4</li>
<li>[[SIMDElementSize]]: 4</li>
<li>[[SIMDCastNumber]]: ToInt32</li>
<li>[[SIMDSerializeElement]]: SerializeInt32</li>
<li>[[SIMDDeserializeElement]]: DeserializeInt32</li>
</ul>
<emu-clause id="serialize-int" aoid="SerializeInt">
<h1>SerializeInt( block, offset, n, isLittleEndian, descriptor )</h1>
<emu-note>Derived from part of <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-setvalueinbuffer">SetValueInBuffer</a>.</emu-note>
<emu-alg>
1. Assert: _block_ is a Data Block.
1. Assert: _offset_ is a number.
1. Assert: _n_ is a number.
1. Assert: _n_ == _descriptor_.[[SIMDCastNumber]](_n_).
1. Assert: _offset_ + _descriptor_.[[SIMDElementSize]] is less than or equal to the size of _block_.
1. Let _rawBytes_ be a List containing the _descriptor_.[[SIMDElementSize]]-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 <var>block</var>[<var>offset</var>].
</emu-alg>
</emu-clause>
<emu-clause id="deserialize-int32" aoid="DeserializeInt">
<h1>DeserializeInt( block, offset, isLittleEndian, descriptor )</h1>
<emu-note>Derived from part of <a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-getvaluefrombuffer">GetValueFromBuffer</a>.</emu-note>
<emu-alg>
1. Assert: _block_ is a Data Block.
1. Assert: _offset_ is a number.
1. Assert: _offset_ + _descriptor_.[[SIMDElementSize]] is less than or equal to the size of _block_.
1. Let _rawValue_ be a List of _descriptor_.[[SIMDElementSize]] containing, in order, the sequence of _descriptor_.[[SIMDElementSize]] bytes starting with <var>block</var>[<var>offset</var>].
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 a binary little-endian 2’s complement number of bit length _descriptor_.[[SIMDElementSize]] × 8.
1. Return the Number value that corresponds to _intValue_.
</emu-alg>
</emu-clause>
<emu-clause id="serialize-int32" aoid="SerializeInt32">
<h1>SerializeInt32( block, offset, n, isLittleEndian )</h1>
<emu-alg>
1. SerializeInt( block, offset, n, isLittleEndian, Int32x4Descriptor ).
</emu-alg>
</emu-clause>
<emu-clause id="deserialize-int32" aoid="DeserializeInt32">
<h1>DeserializeInt32( block, offset, isLittleEndian )</h1>
<emu-alg>
1. Return DeserializeInt( block, offset, isLittleEndian, Int32x4Descriptor).
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="simd-int16x8">
<h1>Int16x8Descriptor type descriptor</h1>
<p>
The Int16x8Descriptor integer SIMD type descriptor has the following internal slots:
</p>
<ul>
<li>[[SIMDLength]]: 8</li>
<li>[[SIMDElementSize]]: 2</li>
<li>[[SIMDCastNumber]]: ToInt16</li>
<li>[[SIMDSerializeElement]]: SerializeInt16</li>
<li>[[SIMDDeserializeElement]]: DeserializeInt16</li>
</ul>
<emu-clause id="serialize-int16" aoid="SerializeInt16">
<h1>SerializeInt16( block, offset, n, isLittleEndian )</h1>
<emu-alg>
1. SerializeInt( block, offset, n, isLittleEndian, Int16x8Descriptor ).
</emu-alg>
</emu-clause>
<emu-clause id="deserialize-int16" aoid="DeserializeInt16">
<h1>DeserializeInt16( block, offset, isLittleEndian )</h1>
<emu-alg>
1. Return DeserializeInt( block, offset, isLittleEndian, Int16x8Descriptor).
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="simd-int8x16">
<h1>Int8x16Descriptor type descriptor</h1>
<p>
The Int8x16Descriptor integer SIMD type descriptor has the following internal slots:
</p>
<ul>
<li>[[SIMDLength]]: 16</li>
<li>[[SIMDElementSize]]: 1</li>
<li>[[SIMDCastNumber]]: ToInt8</li>
<li>[[SIMDSerializeElement]]: SerializeInt8</li>
<li>[[SIMDDeserializeElement]]: DeserializeInt8</li>
</ul>
<emu-clause id="serialize-int8" aoid="SerializeInt8">
<h1>SerializeInt8( block, offset, n, isLittleEndian )</h1>
<emu-alg>
1. SerializeInt( block, offset, n, isLittleEndian, Int8x16Descriptor ).
</emu-alg>
</emu-clause>
<emu-clause id="deserialize-int8" aoid="DeserializeInt8">
<h1>DeserializeInt8( block, offset, isLittleEndian )</h1>
<emu-alg>
1. Return DeserializeInt( block, offset, isLittleEndian, Int8x16Descriptor).
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="simd-bool32x4">
<h1>Bool32x4 type descriptor</h1>
<p>
The Bool32x4Descriptor boolean SIMD type descriptor has the following internal slots:
</p>
<ul>
<li>[[SIMDLength]]: 4</li>
<li>[[SIMDElementSize]]: undefined</li>
<li>[[SIMDCastNumber]]: ToBoolean</li>
<li>[[SIMDSerializeElement]]: undefined</li>
<li>[[SIMDDeserializeElement]]: undefined</li>
</ul>
</emu-clause>
<emu-clause id="simd-bool16x8">
<h1>Bool16x8 type descriptor</h1>
<p>
The Bool16x8Descriptor boolean SIMD type descriptor has the following internal slots:
</p>
<ul>
<li>[[SIMDLength]]: 8</li>
<li>[[SIMDElementSize]]: undefined</li>
<li>[[SIMDCastNumber]]: ToBoolean</li>
<li>[[SIMDSerializeElement]]: undefined</li>
<li>[[SIMDDeserializeElement]]: undefined</li>
</ul>
</emu-clause>
<emu-clause id="simd-bool8x16">
<h1>Bool8x16 type descriptor</h1>
<p>
The Bool8x16Descriptor boolean SIMD type descriptor has the following internal slots:
</p>
<ul>
<li>[[SIMDLength]]: 16</li>
<li>[[SIMDElementSize]]: undefined</li>
<li>[[SIMDCastNumber]]: ToBoolean</li>
<li>[[SIMDSerializeElement]]: undefined</li>
<li>[[SIMDDeserializeElement]]: undefined</li>
</ul>
</emu-clause>
</emu-clause>
</emu-clause>