Bug 1155211 - SIMD: Rename lane mutators - with -> replaceLane. r=bbouvier
authorFlorian Merz <flomerz@gmail.com>
Tue, 16 Jun 2015 23:10:12 +0200
changeset 281038 7050f4f4197f2029ec03cf9e7575bcb34042c010
parent 281037 64cb3eddd1a973d09ef4f7f6c7e0b5b2a535151f
child 281039 8b4e4083639ef3563c9ebac4826cfbe8f21ef5ea
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1155211
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1155211 - SIMD: Rename lane mutators - with -> replaceLane. r=bbouvier
js/src/asmjs/AsmJSValidate.cpp
js/src/builtin/SIMD.cpp
js/src/builtin/SIMD.h
js/src/jit-test/tests/SIMD/replacelane.js
js/src/jit-test/tests/SIMD/with.js
js/src/jit-test/tests/asm.js/testSIMD.js
js/src/jit/IonBuilder.h
js/src/jit/MCallOptimize.cpp
js/src/tests/ecma_7/SIMD/replaceLane.js
js/src/tests/ecma_7/SIMD/with.js
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -5624,16 +5624,51 @@ class CheckSimdVectorScalarArgs
             return true;
         }
 
         // Second argument is the scalar
         return CheckSimdScalarArgs(formalSimdType_)(f, arg, argIndex, actualType, def);
     }
 };
 
+class CheckSimdReplaceLaneArgs
+{
+    AsmJSSimdType formalSimdType_;
+
+  public:
+    explicit CheckSimdReplaceLaneArgs(AsmJSSimdType t) : formalSimdType_(t) {}
+
+    bool operator()(FunctionCompiler& f, ParseNode* arg, unsigned argIndex, Type actualType,
+                    MDefinition** def) const
+    {
+        MOZ_ASSERT(argIndex < 3);
+        uint32_t u32;
+        switch (argIndex) {
+          case 0:
+            // First argument is the vector
+            if (!(actualType <= Type(formalSimdType_))) {
+                return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
+                               Type(formalSimdType_).toChars());
+            }
+            return true;
+          case 1:
+            // Second argument is the lane < 4
+            if (!IsLiteralOrConstInt(f, arg, &u32))
+                return f.failf(arg, "lane selector should be a constant integer literal");
+            if (u32 >= SimdTypeToLength(formalSimdType_))
+                return f.failf(arg, "lane selector should be in bounds");
+            return true;
+          case 2:
+            // Third argument is the scalar
+            return CheckSimdScalarArgs(formalSimdType_)(f, arg, argIndex, actualType, def);
+        }
+        return false;
+    }
+};
+
 } // anonymous namespace
 
 static inline bool
 CheckSimdUnary(FunctionCompiler& f, ParseNode* call, AsmJSSimdType opType,
                MSimdUnaryArith::Operation op, MDefinition** def, Type* type)
 {
     DefinitionVector defs;
     if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType), &defs))
@@ -5679,24 +5714,27 @@ CheckSimdBinary<MSimdShift::Operation>(F
     if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType), &argDefs))
         return false;
     *type = Type::Int32x4;
     *def = f.binarySimd<MSimdShift>(argDefs[0], argDefs[1], op);
     return true;
 }
 
 static bool
-CheckSimdWith(FunctionCompiler& f, ParseNode* call, AsmJSSimdType opType, SimdLane lane,
-              MDefinition** def, Type* type)
+CheckSimdReplaceLane(FunctionCompiler& f, ParseNode* call, AsmJSSimdType opType,
+                     MDefinition** def, Type* type)
 {
     DefinitionVector defs;
-    if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType), &defs))
-        return false;
+    if (!CheckSimdCallArgs(f, call, 3, CheckSimdReplaceLaneArgs(opType), &defs))
+        return false;
+    ParseNode* laneArg = NextNode(CallArgList(call));
+    uint32_t lane;
+    JS_ALWAYS_TRUE(IsLiteralInt(f.m(), laneArg, &lane));
     *type = opType;
-    *def = f.insertElementSimd(defs[0], defs[1], lane, type->toMIRType());
+    *def = f.insertElementSimd(defs[0], defs[2], SimdLane(lane), type->toMIRType());
     return true;
 }
 
 namespace {
 // Include CheckSimdCast in unnamed namespace to avoid MSVC name lookup bug (due to the use of Type).
 
 template<class T>
 static bool
@@ -5945,24 +5983,18 @@ CheckSimdOperationCall(FunctionCompiler&
 
       case AsmJSSimdOperation_and:
         return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::and_, def, type);
       case AsmJSSimdOperation_or:
         return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::or_, def, type);
       case AsmJSSimdOperation_xor:
         return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::xor_, def, type);
 
-      case AsmJSSimdOperation_withX:
-        return CheckSimdWith(f, call, opType, SimdLane::LaneX, def, type);
-      case AsmJSSimdOperation_withY:
-        return CheckSimdWith(f, call, opType, SimdLane::LaneY, def, type);
-      case AsmJSSimdOperation_withZ:
-        return CheckSimdWith(f, call, opType, SimdLane::LaneZ, def, type);
-      case AsmJSSimdOperation_withW:
-        return CheckSimdWith(f, call, opType, SimdLane::LaneW, def, type);
+      case AsmJSSimdOperation_replaceLane:
+          return CheckSimdReplaceLane(f, call, opType, def, type);
 
       case AsmJSSimdOperation_fromInt32x4:
         return CheckSimdCast<MSimdConvert>(f, call, AsmJSSimdType_int32x4, opType, def, type);
       case AsmJSSimdOperation_fromFloat32x4:
         return CheckSimdCast<MSimdConvert>(f, call, AsmJSSimdType_float32x4, opType, def, type);
       case AsmJSSimdOperation_fromInt32x4Bits:
         return CheckSimdCast<MSimdReinterpretCast>(f, call, AsmJSSimdType_int32x4, opType, def, type);
       case AsmJSSimdOperation_fromFloat32x4Bits:
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -609,32 +609,16 @@ struct Xor {
 template<typename T>
 struct And {
     static T apply(T l, T r) { return l & r; }
 };
 template<typename T>
 struct Or {
     static T apply(T l, T r) { return l | r; }
 };
-template<typename T>
-struct WithX {
-    static T apply(int32_t lane, T scalar, T x) { return lane == 0 ? scalar : x; }
-};
-template<typename T>
-struct WithY {
-    static T apply(int32_t lane, T scalar, T x) { return lane == 1 ? scalar : x; }
-};
-template<typename T>
-struct WithZ {
-    static T apply(int32_t lane, T scalar, T x) { return lane == 2 ? scalar : x; }
-};
-template<typename T>
-struct WithW {
-    static T apply(int32_t lane, T scalar, T x) { return lane == 3 ? scalar : x; }
-};
 // For the following three operators, if the value v we're trying to shift is
 // such that v << bits can't fit in the int32 range, then we have undefined
 // behavior, according to C++11 [expr.shift]p2.
 struct ShiftLeft {
     static int32_t apply(int32_t v, int32_t bits) {
         return uint32_t(bits) >= 32 ? 0 : v << bits;
     }
 };
@@ -712,36 +696,43 @@ UnaryFunc(JSContext* cx, unsigned argc, 
 
 template<typename In, template<typename C> class Op, typename Out>
 static bool
 BinaryFunc(JSContext* cx, unsigned argc, Value* vp)
 {
     return CoercedBinaryFunc<In, Out, Op, Out>(cx, argc, vp);
 }
 
-template<typename V, template<typename T> class OpWith>
+template<typename V>
 static bool
-FuncWith(JSContext* cx, unsigned argc, Value* vp)
+ReplaceLane(JSContext* cx, unsigned argc, Value* vp)
 {
     typedef typename V::Elem Elem;
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    // Only the first argument is mandatory
-    if (args.length() < 1 || !IsVectorObject<V>(args[0]))
+    // Only the first and second arguments are mandatory
+    if (args.length() < 2 || !IsVectorObject<V>(args[0]))
         return ErrorBadArgs(cx);
 
     Elem* vec = TypedObjectMemory<Elem*>(args[0]);
     Elem result[V::lanes];
 
+    if (!args[1].isInt32())
+        return ErrorBadArgs(cx);
+    int32_t lanearg = args[1].toInt32();
+    if (lanearg < 0 || uint32_t(lanearg) >= V::lanes)
+        return ErrorBadArgs(cx);
+    uint32_t lane = uint32_t(lanearg);
+
     Elem value;
-    if (!V::toType(cx, args.get(1), &value))
+    if (!V::toType(cx, args.get(2), &value))
         return false;
 
     for (unsigned i = 0; i < V::lanes; i++)
-        result[i] = OpWith<Elem>::apply(i, value, vec[i]);
+        result[i] = i == lane ? value : vec[i];
     return StoreResult<V>(cx, args, result);
 }
 
 template<typename V>
 static bool
 Swizzle(JSContext* cx, unsigned argc, Value* vp)
 {
     typedef typename V::Elem Elem;
@@ -1165,9 +1156,8 @@ FLOAT64X2_FUNCTION_LIST(DEFINE_SIMD_FLOA
 #define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands)         \
 bool                                                               \
 js::simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp)   \
 {                                                                  \
     return Func(cx, argc, vp);                                     \
 }
 INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION)
 #undef DEFINE_SIMD_INT32X4_FUNCTION
-
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -54,25 +54,22 @@
   V(mul, (BinaryFunc<Float32x4, Mul, Float32x4>), 2)                                  \
   V(notEqual, (CompareFunc<Float32x4, NotEqual>), 2)                                  \
   V(or, (CoercedBinaryFunc<Float32x4, Int32x4, Or, Float32x4>), 2)                    \
   V(store,  (Store<Float32x4, 4>), 3)                                                 \
   V(store3, (Store<Float32x4, 3>), 3)                                                 \
   V(store2, (Store<Float32x4, 2>), 3)                                                 \
   V(store1, (Store<Float32x4, 1>), 3)                                                 \
   V(sub, (BinaryFunc<Float32x4, Sub, Float32x4>), 2)                                  \
-  V(withX, (FuncWith<Float32x4, WithX>), 2)                                           \
-  V(withY, (FuncWith<Float32x4, WithY>), 2)                                           \
-  V(withZ, (FuncWith<Float32x4, WithZ>), 2)                                           \
-  V(withW, (FuncWith<Float32x4, WithW>), 2)                                           \
   V(xor, (CoercedBinaryFunc<Float32x4, Int32x4, Xor, Float32x4>), 2)
 
 #define FLOAT32X4_TERNARY_FUNCTION_LIST(V)                                            \
   V(bitselect, BitSelect<Float32x4>, 3)                                               \
   V(clamp, Clamp<Float32x4>, 3)                                                       \
+  V(replaceLane, (ReplaceLane<Float32x4>), 3)                                         \
   V(select, Select<Float32x4>, 3)
 
 #define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)                                            \
   V(swizzle, Swizzle<Float32x4>, 2)                                                   \
   V(shuffle, Shuffle<Float32x4>, 3)
 
 #define FLOAT32X4_FUNCTION_LIST(V)                                                    \
   FLOAT32X4_UNARY_FUNCTION_LIST(V)                                                    \
@@ -106,23 +103,22 @@
   V(max, (BinaryFunc<Float64x2, Maximum, Float64x2>), 2)                              \
   V(maxNum, (BinaryFunc<Float64x2, MaxNum, Float64x2>), 2)                            \
   V(min, (BinaryFunc<Float64x2, Minimum, Float64x2>), 2)                              \
   V(minNum, (BinaryFunc<Float64x2, MinNum, Float64x2>), 2)                            \
   V(mul, (BinaryFunc<Float64x2, Mul, Float64x2>), 2)                                  \
   V(notEqual, (CompareFunc<Float64x2, NotEqual>), 2)                                  \
   V(store,  (Store<Float64x2, 2>), 3)                                                 \
   V(store1, (Store<Float64x2, 1>), 3)                                                 \
-  V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2)                                  \
-  V(withX, (FuncWith<Float64x2, WithX>), 2)                                           \
-  V(withY, (FuncWith<Float64x2, WithY>), 2)
+  V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2)
 
 #define FLOAT64X2_TERNARY_FUNCTION_LIST(V)                                            \
   V(bitselect, BitSelect<Float64x2>, 3)                                               \
   V(clamp, Clamp<Float64x2>, 3)                                                       \
+  V(replaceLane, (ReplaceLane<Float64x2>), 3)                                         \
   V(select, Select<Float64x2>, 3)
 
 #define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)                                            \
   V(swizzle, Swizzle<Float64x2>, 2)                                                   \
   V(shuffle, Shuffle<Float64x2>, 3)
 
 #define FLOAT64X2_FUNCTION_LIST(V)                                                    \
   FLOAT64X2_UNARY_FUNCTION_LIST(V)                                                    \
@@ -158,24 +154,21 @@
   V(sub, (BinaryFunc<Int32x4, Sub, Int32x4>), 2)                                      \
   V(shiftLeftByScalar, (Int32x4BinaryScalar<ShiftLeft>), 2)                           \
   V(shiftRightArithmeticByScalar, (Int32x4BinaryScalar<ShiftRightArithmetic>), 2)     \
   V(shiftRightLogicalByScalar, (Int32x4BinaryScalar<ShiftRightLogical>), 2)           \
   V(store,  (Store<Int32x4, 4>), 3)                                                   \
   V(store3, (Store<Int32x4, 3>), 3)                                                   \
   V(store2, (Store<Int32x4, 2>), 3)                                                   \
   V(store1, (Store<Int32x4, 1>), 3)                                                   \
-  V(withX, (FuncWith<Int32x4, WithX>), 2)                                             \
-  V(withY, (FuncWith<Int32x4, WithY>), 2)                                             \
-  V(withZ, (FuncWith<Int32x4, WithZ>), 2)                                             \
-  V(withW, (FuncWith<Int32x4, WithW>), 2)                                             \
   V(xor, (BinaryFunc<Int32x4, Xor, Int32x4>), 2)
 
 #define INT32X4_TERNARY_FUNCTION_LIST(V)                                              \
   V(bitselect, BitSelect<Int32x4>, 3)                                                 \
+  V(replaceLane, (ReplaceLane<Int32x4>), 3)                                           \
   V(select, Select<Int32x4>, 3)
 
 #define INT32X4_QUARTERNARY_FUNCTION_LIST(V)                                          \
   V(bool, Int32x4Bool, 4)
 
 #define INT32X4_SHUFFLE_FUNCTION_LIST(V)                                              \
   V(swizzle, Swizzle<Int32x4>, 2)                                                     \
   V(shuffle, Shuffle<Int32x4>, 3)
@@ -221,26 +214,21 @@
     _(xor)
 #define COMP_COMMONX4_TO_INT32X4_SIMD_OP(_) \
     _(lessThan)                      \
     _(lessThanOrEqual)               \
     _(equal)                         \
     _(notEqual)                      \
     _(greaterThan)                   \
     _(greaterThanOrEqual)
-#define WITH_COMMONX4_SIMD_OP(_)     \
-    _(withX)                         \
-    _(withY)                         \
-    _(withZ)                         \
-    _(withW)
 // TODO: remove when all SIMD calls are inlined (bug 1112155)
 #define ION_COMMONX4_SIMD_OP(_)      \
     ARITH_COMMONX4_SIMD_OP(_)        \
     BITWISE_COMMONX4_SIMD_OP(_)      \
-    WITH_COMMONX4_SIMD_OP(_)         \
+    _(replaceLane)                   \
     _(bitselect)                     \
     _(select)                        \
     _(splat)                         \
     _(not)                           \
     _(neg)                           \
     _(swizzle)                       \
     _(shuffle)                       \
     _(load)                          \
rename from js/src/jit-test/tests/SIMD/with.js
rename to js/src/jit-test/tests/SIMD/replacelane.js
--- a/js/src/jit-test/tests/SIMD/with.js
+++ b/js/src/jit-test/tests/SIMD/replacelane.js
@@ -2,22 +2,101 @@ load(libdir + 'simd.js');
 
 setJitCompilerOption("ion.warmup.trigger", 50);
 
 function f() {
     var f4 = SIMD.float32x4(1, 2, 3, 4);
     var i4 = SIMD.int32x4(1, 2, 3, 4);
 
     for (var i = 0; i < 150; i++) {
-        assertEqX4(SIMD.int32x4.withX(i4, 42), [42, 2, 3, 4]);
-        assertEqX4(SIMD.int32x4.withY(i4, 42), [1, 42, 3, 4]);
-        assertEqX4(SIMD.int32x4.withZ(i4, 42), [1, 2, 42, 4]);
-        assertEqX4(SIMD.int32x4.withW(i4, 42), [1, 2, 3, 42]);
+        assertEqX4(SIMD.int32x4.replaceLane(i4, 0, 42), [42, 2, 3, 4]);
+        assertEqX4(SIMD.int32x4.replaceLane(i4, 1, 42), [1, 42, 3, 4]);
+        assertEqX4(SIMD.int32x4.replaceLane(i4, 2, 42), [1, 2, 42, 4]);
+        assertEqX4(SIMD.int32x4.replaceLane(i4, 3, 42), [1, 2, 3, 42]);
 
-        assertEqX4(SIMD.float32x4.withX(f4, 42), [42, 2, 3, 4]);
-        assertEqX4(SIMD.float32x4.withY(f4, 42), [1, 42, 3, 4]);
-        assertEqX4(SIMD.float32x4.withZ(f4, 42), [1, 2, 42, 4]);
-        assertEqX4(SIMD.float32x4.withW(f4, 42), [1, 2, 3, 42]);
+        assertEqX4(SIMD.float32x4.replaceLane(f4, 0, 42), [42, 2, 3, 4]);
+        assertEqX4(SIMD.float32x4.replaceLane(f4, 1, 42), [1, 42, 3, 4]);
+        assertEqX4(SIMD.float32x4.replaceLane(f4, 2, 42), [1, 2, 42, 4]);
+        assertEqX4(SIMD.float32x4.replaceLane(f4, 3, 42), [1, 2, 3, 42]);
     }
 }
 
 f();
 
+
+function e() {
+    var f4 = SIMD.float32x4(1, 2, 3, 4);
+    var i4 = SIMD.int32x4(1, 2, 3, 4);
+
+    for (let i = 0; i < 150; i++) {
+        let caught = false;
+        try {
+            let x = SIMD.int32x4.replaceLane(i < 149 ? i4 : f4, 0, 42);
+        } catch(e) {
+            assertEq(e instanceof TypeError, true);
+            assertEq(i, 149);
+            caught = true;
+        }
+        assertEq(i < 149 || caught, true);
+    }
+
+    for (let i = 0; i < 150; i++) {
+        let caught = false;
+        try {
+            let x = SIMD.int32x4.replaceLane(i4, i < 149 ? 0 : 4, 42);
+        } catch(e) {
+            assertEq(e instanceof TypeError, true);
+            assertEq(i, 149);
+            caught = true;
+        }
+        assertEq(i < 149 || caught, true);
+    }
+
+    for (let i = 0; i < 150; i++) {
+        let caught = false;
+        try {
+            let x = SIMD.int32x4.replaceLane(i4, i < 149 ? 0 : 1.1, 42);
+        } catch(e) {
+            assertEq(e instanceof TypeError, true);
+            assertEq(i, 149);
+            caught = true;
+        }
+        assertEq(i < 149 || caught, true);
+    }
+
+    for (let i = 0; i < 150; i++) {
+        let caught = false;
+        try {
+            let x = SIMD.float32x4.replaceLane(i < 149 ? f4 : i4, 0, 42);
+        } catch(e) {
+            assertEq(e instanceof TypeError, true);
+            assertEq(i, 149);
+            caught = true;
+        }
+        assertEq(i < 149 || caught, true);
+    }
+
+    for (let i = 0; i < 150; i++) {
+        let caught = false;
+        try {
+            let x = SIMD.float32x4.replaceLane(f4, i < 149 ? 0 : 4, 42);
+        } catch(e) {
+            assertEq(e instanceof TypeError, true);
+            assertEq(i, 149);
+            caught = true;
+        }
+        assertEq(i < 149 || caught, true);
+    }
+
+    for (let i = 0; i < 150; i++) {
+        let caught = false;
+        try {
+            let x = SIMD.float32x4.replaceLane(f4, i < 149 ? 0 : 1.1, 42);
+        } catch(e) {
+            assertEq(e instanceof TypeError, true);
+            assertEq(i, 149);
+            caught = true;
+        }
+        assertEq(i < 149 || caught, true);
+    }
+}
+
+e();
--- a/js/src/jit-test/tests/asm.js/testSIMD.js
+++ b/js/src/jit-test/tests/asm.js/testSIMD.js
@@ -604,47 +604,44 @@ CheckF4(F32MINNUM + FROUND + 'var NaN = 
 CheckF4(F32MAXNUM, 'var x=f4(1,2,3,4); x=max(x,x)', [1,2,3,4]);
 CheckF4(F32MAXNUM, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=max(x,y)', [13.37, 3, 5, 4]);
 CheckF4(F32MAXNUM + FROUND + 'var Infinity = glob.Infinity;', 'var x=f4(0,0,0,0); var y=f4(2310,3,5,0); x=f4(f32(+Infinity),f32(-Infinity),f32(3),f32(-0.)); x=max(x,y)', [+Infinity,3,5,0]);
 
 CheckF4(F32MAXNUM, 'var x=f4(0,0,-0,-0); var y=f4(0,-0,0,-0); x=max(x,y)', [0,0,0,-0]);
 CheckF4(F32MAXNUM + FROUND + 'var NaN = glob.NaN;', 'var x=f4(0,0,0,0); var y=f4(0,0,0,0); var n=f32(0); n=f32(NaN); x=f4(n,0.,n,0.); y=f4(n,n,0.,0.); x=max(x,y)', [NaN, 0, 0, 0]);
 
 // With
-const WXF = 'var w = f4.withX;';
-const WYF = 'var w = f4.withY;';
-const WZF = 'var w = f4.withZ;';
-const WWF = 'var w = f4.withW;';
+const RLF = 'var r = f4.replaceLane;';
 
-assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, 1);} return f");
-assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, x);} return f");
-assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(1, f32(1));} return f");
-assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(1., f32(1));} return f");
-assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(f32(1), f32(1));} return f");
-assertAsmTypeFail('glob', USE_ASM + I32 + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); var y = i4(1,2,3,4); x = w(y, f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + RLF + "function f() {var x = f4(1,2,3,4); x = r(x, 0, 1);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + RLF + "function f() {var x = f4(1,2,3,4); x = r(x, 0, x);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(x, 4, f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(x, f32(0), f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(1, 0, f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(1, 0., f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(f32(1), 0, f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); var l = 0; x = r(x, l, f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); var y = i4(1,2,3,4); x = r(y, 0, f32(1));} return f");
 
-CheckF4(WXF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [Math.fround(13.37), 2, 3, 4]);
-CheckF4(WYF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, Math.fround(13.37), 3, 4]);
-CheckF4(WZF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, 2, Math.fround(13.37), 4]);
-CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, 2, 3, Math.fround(13.37)]);
-CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37) + f32(6.63));', [1, 2, 3, Math.fround(Math.fround(13.37) + Math.fround(6.63))]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 0, f32(13.37));', [Math.fround(13.37), 2, 3, 4]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 1, f32(13.37));', [1, Math.fround(13.37), 3, 4]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 2, f32(13.37));', [1, 2, Math.fround(13.37), 4]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, f32(13.37));', [1, 2, 3, Math.fround(13.37)]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, f32(13.37) + f32(6.63));', [1, 2, 3, Math.fround(Math.fround(13.37) + Math.fround(6.63))]);
 
-CheckF4(WXF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [Math.fround(13.37), 2, 3, 4]);
-CheckF4(WYF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, Math.fround(13.37), 3, 4]);
-CheckF4(WZF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, 2, Math.fround(13.37), 4]);
-CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, 2, 3, Math.fround(13.37)]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 0, 13.37);', [Math.fround(13.37), 2, 3, 4]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 1, 13.37);', [1, Math.fround(13.37), 3, 4]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 2, 13.37);', [1, 2, Math.fround(13.37), 4]);
+CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, 13.37);', [1, 2, 3, Math.fround(13.37)]);
 
-const WXI = 'var w = i4.withX;';
-const WYI = 'var w = i4.withY;';
-const WZI = 'var w = i4.withZ;';
-const WWI = 'var w = i4.withW;';
-CheckI4(WXI, 'var x = i4(1,2,3,4); x = w(x, 42);', [42, 2, 3, 4]);
-CheckI4(WYI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 42, 3, 4]);
-CheckI4(WZI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 2, 42, 4]);
-CheckI4(WWI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 2, 3, 42]);
+const RLI = 'var r = i4.replaceLane;';
+CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 0, 42);', [42, 2, 3, 4]);
+CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 1, 42);', [1, 42, 3, 4]);
+CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 2, 42);', [1, 2, 42, 4]);
+CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 3, 42);', [1, 2, 3, 42]);
 
 // Comparisons
 // True yields all bits set to 1 (i.e as an int32, 0xFFFFFFFF === -1), false
 // yields all bits set to 0 (i.e 0).
 const T = -1;
 const F = 0;
 
 const EQI32 = 'var eq = i4.equal';
@@ -1314,9 +1311,8 @@ asmLink(asmCompile('glob', 'ffi', code),
     assertEq(x4.w, iters);
 })();
 
 } catch(e) {
     print('Stack:', e.stack)
     print('Error:', e)
     throw e;
 }
-
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -812,18 +812,18 @@ class IonBuilder
 
     template <typename T>
     InliningStatus inlineBinarySimd(CallInfo& callInfo, JSNative native,
                                     typename T::Operation op, SimdTypeDescr::Type type);
     InliningStatus inlineCompSimd(CallInfo& callInfo, JSNative native,
                                   MSimdBinaryComp::Operation op, SimdTypeDescr::Type compType);
     InliningStatus inlineUnarySimd(CallInfo& callInfo, JSNative native,
                                    MSimdUnaryArith::Operation op, SimdTypeDescr::Type type);
-    InliningStatus inlineSimdWith(CallInfo& callInfo, JSNative native, SimdLane lane,
-                                  SimdTypeDescr::Type type);
+    InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native,
+                                         SimdTypeDescr::Type type);
     InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type);
     InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
                                      unsigned numVectors, unsigned numLanes);
     InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type);
     InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
                                      SimdTypeDescr::Type from, SimdTypeDescr::Type to);
     InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, bool isElementWise,
                                     SimdTypeDescr::Type type);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -308,27 +308,20 @@ IonBuilder::inlineNativeCall(CallInfo& c
     if (native == js::simd_int32x4_##OP)                                                           \
         return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Int32x4);      \
     if (native == js::simd_float32x4_##OP)                                                         \
         return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Float32x4);
 
     COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
 #undef INLINE_SIMD_COMPARISON_
 
-#define INLINE_SIMD_SETTER_(LANE)                                                                   \
-    if (native == js::simd_int32x4_with##LANE)                                                      \
-        return inlineSimdWith(callInfo, native, SimdLane::Lane##LANE, SimdTypeDescr::Int32x4);      \
-    if (native == js::simd_float32x4_with##LANE)                                                    \
-        return inlineSimdWith(callInfo, native, SimdLane::Lane##LANE, SimdTypeDescr::Float32x4);
-
-    INLINE_SIMD_SETTER_(X)
-    INLINE_SIMD_SETTER_(Y)
-    INLINE_SIMD_SETTER_(Z)
-    INLINE_SIMD_SETTER_(W)
-#undef INLINE_SIMD_SETTER_
+    if (native == js::simd_int32x4_replaceLane)
+        return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Int32x4);
+    if (native == js::simd_float32x4_replaceLane)
+        return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Float32x4);
 
     if (native == js::simd_int32x4_not)
         return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Int32x4);
     if (native == js::simd_int32x4_neg)
         return inlineUnarySimd(callInfo, native, MSimdUnaryArith::neg, SimdTypeDescr::Int32x4);
 
 #define INLINE_SIMD_FLOAT32X4_UNARY_(OP)                                                           \
     if (native == js::simd_float32x4_##OP)                                                         \
@@ -3211,27 +3204,32 @@ IonBuilder::inlineSimdSplat(CallInfo& ca
 
     // See comment in inlineBinarySimd
     MIRType mirType = SimdTypeDescrToMIRType(type);
     MSimdSplatX4* ins = MSimdSplatX4::New(alloc(), callInfo.getArg(0), mirType);
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineSimdWith(CallInfo& callInfo, JSNative native, SimdLane lane,
-                           SimdTypeDescr::Type type)
+IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
 {
     InlineTypedObject* templateObj = nullptr;
-    if (!checkInlineSimd(callInfo, native, type, 2, &templateObj))
+    if (!checkInlineSimd(callInfo, native, type, 3, &templateObj))
         return InliningStatus_NotInlined;
 
+    MDefinition* arg = callInfo.getArg(1);
+    if (!arg->isConstantValue() || arg->type() != MIRType_Int32)
+        return InliningStatus_NotInlined;
+    int32_t lane = arg->constantValue().toInt32();
+    if (lane < 0 || lane >= 4)
+        return InliningStatus_NotInlined;
     // See comment in inlineBinarySimd
     MIRType mirType = SimdTypeDescrToMIRType(type);
     MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), callInfo.getArg(0),
-                                                      callInfo.getArg(1), mirType, lane);
+                                                      callInfo.getArg(2), mirType, SimdLane(lane));
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
                               SimdTypeDescr::Type from, SimdTypeDescr::Type to)
 {
     InlineTypedObject* templateObj = nullptr;
rename from js/src/tests/ecma_7/SIMD/with.js
rename to js/src/tests/ecma_7/SIMD/replaceLane.js
--- a/js/src/tests/ecma_7/SIMD/with.js
+++ b/js/src/tests/ecma_7/SIMD/replaceLane.js
@@ -1,93 +1,94 @@
 // |reftest| skip-if(!this.hasOwnProperty("SIMD"))
-var BUGNUMBER = 946042;
 var float32x4 = SIMD.float32x4;
 var int32x4 = SIMD.int32x4;
 var float64x2 = SIMD.float64x2;
 
-var summary = 'with{X,Y,Z,W}';
 
-function withX(arr, x) {
+function replaceLane0(arr, x) {
     if (arr.length == 2)
         return [x, arr[1]];
     return [x, arr[1], arr[2], arr[3]];
 }
-function withY(arr, x) {
+function replaceLane1(arr, x) {
     if (arr.length == 2)
         return [arr[0], x];
     return [arr[0], x, arr[2], arr[3]];
 }
-function withZ(arr, x) {
+function replaceLane2(arr, x) {
     return [arr[0], arr[1], x, arr[3]];
 }
-function withW(arr, x) {
+function replaceLane3(arr, x) {
     return [arr[0], arr[1], arr[2], x];
 }
 
-function testWith(vec, scalar, simdFunc, func) {
+function testReplaceLane(vec, scalar, simdFunc, func) {
     var varr = simdToArray(vec);
     var observed = simdToArray(simdFunc(vec, scalar));
     var expected = func(varr, scalar);
     for (var i = 0; i < observed.length; i++)
         assertEq(observed[i], expected[i]);
 }
 
 function test() {
-  print(BUGNUMBER + ": " + summary);
-
   function testType(type, inputs) {
       var length = simdToArray(inputs[0][0]).length;
       for (var [vec, s] of inputs) {
-          testWith(vec, s, SIMD[type].withX, withX);
-          testWith(vec, s, SIMD[type].withY, withY);
+          testReplaceLane(vec, s, (x,y) => SIMD[type].replaceLane(x, 0, y), replaceLane0);
+          testReplaceLane(vec, s, (x,y) => SIMD[type].replaceLane(x, 1, y), replaceLane1);
           if (length <= 2)
               continue;
-          testWith(vec, s, SIMD[type].withZ, withZ);
-          testWith(vec, s, SIMD[type].withW, withW);
+          testReplaceLane(vec, s, (x,y) => SIMD[type].replaceLane(x, 2, y), replaceLane2);
+          testReplaceLane(vec, s, (x,y) => SIMD[type].replaceLane(x, 3, y), replaceLane3);
       }
   }
 
   function TestError(){};
   var good = {valueOf: () => 42};
   var bad = {valueOf: () => {throw new TestError(); }};
 
   var float32x4inputs = [
       [float32x4(1, 2, 3, 4), 5],
       [float32x4(1.87, 2.08, 3.84, 4.17), Math.fround(13.37)],
       [float32x4(NaN, -0, Infinity, -Infinity), 0]
   ];
   testType('float32x4', float32x4inputs);
 
   var v = float32x4inputs[1][0];
-  assertEqX4(float32x4.withX(v), withX(simdToArray(v), NaN));
-  assertEqX4(float32x4.withX(v, good), withX(simdToArray(v), good | 0));
-  assertThrowsInstanceOf(() => float32x4.withX(v, bad), TestError);
+  assertEqX4(float32x4.replaceLane(v, 0), replaceLane0(simdToArray(v), NaN));
+  assertEqX4(float32x4.replaceLane(v, 0, good), replaceLane0(simdToArray(v), good | 0));
+  assertThrowsInstanceOf(() => float32x4.replaceLane(v, 0, bad), TestError);
+  assertThrowsInstanceOf(() => float32x4.replaceLane(v, 4, good), TypeError);
+  assertThrowsInstanceOf(() => float32x4.replaceLane(v, 1.1, good), TypeError);
 
   var float64x2inputs = [
       [float64x2(1, 2), 5],
       [float64x2(1.87, 2.08), Math.fround(13.37)],
       [float64x2(NaN, -0), 0]
   ];
   testType('float64x2', float64x2inputs);
 
   var v = float64x2inputs[1][0];
-  assertEqX4(float64x2.withX(v), withX(simdToArray(v), NaN));
-  assertEqX4(float64x2.withX(v, good), withX(simdToArray(v), good | 0));
-  assertThrowsInstanceOf(() => float64x2.withX(v, bad), TestError);
+  assertEqX4(float64x2.replaceLane(v, 0), replaceLane0(simdToArray(v), NaN));
+  assertEqX4(float64x2.replaceLane(v, 0, good), replaceLane0(simdToArray(v), good | 0));
+  assertThrowsInstanceOf(() => float64x2.replaceLane(v, 0, bad), TestError);
+  assertThrowsInstanceOf(() => float64x2.replaceLane(v, 2, good), TypeError);
+  assertThrowsInstanceOf(() => float64x2.replaceLane(v, 1.1, good), TypeError);
 
   var int32x4inputs = [
       [int32x4(1, 2, 3, 4), 5],
       [int32x4(INT32_MIN, INT32_MAX, 3, 4), INT32_MIN],
   ];
   testType('int32x4', int32x4inputs);
 
   var v = int32x4inputs[1][0];
-  assertEqX4(int32x4.withX(v), withX(simdToArray(v), 0));
-  assertEqX4(int32x4.withX(v, good), withX(simdToArray(v), good | 0));
-  assertThrowsInstanceOf(() => int32x4.withX(v, bad), TestError);
+  assertEqX4(int32x4.replaceLane(v, 0), replaceLane0(simdToArray(v), 0));
+  assertEqX4(int32x4.replaceLane(v, 0, good), replaceLane0(simdToArray(v), good | 0));
+  assertThrowsInstanceOf(() => int32x4.replaceLane(v, 0, bad), TestError);
+  assertThrowsInstanceOf(() => int32x4.replaceLane(v, 4, good), TypeError);
+  assertThrowsInstanceOf(() => int32x4.replaceLane(v, 1.1, good), TypeError);
 
   if (typeof reportCompare === "function")
     reportCompare(true, true);
 }
 
 test();
-