diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index d86f4ca41fa..a531ec42143 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -5629,6 +5629,41 @@ class CheckSimdVectorScalarArgs } }; +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 @@ -5684,14 +5719,17 @@ CheckSimdBinary(FunctionCompiler& f, ParseNode* call, Asm } 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)) + 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; } @@ -5950,14 +5988,8 @@ CheckSimdOperationCall(FunctionCompiler& f, ParseNode* call, const ModuleCompile 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(f, call, AsmJSSimdType_int32x4, opType, def, type); diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index a7508d6e52e..acb7e07ba3a 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -614,22 +614,6 @@ template struct Or { static T apply(T l, T r) { return l | r; } }; -template -struct WithX { - static T apply(int32_t lane, T scalar, T x) { return lane == 0 ? scalar : x; } -}; -template -struct WithY { - static T apply(int32_t lane, T scalar, T x) { return lane == 1 ? scalar : x; } -}; -template -struct WithZ { - static T apply(int32_t lane, T scalar, T x) { return lane == 2 ? scalar : x; } -}; -template -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. @@ -717,26 +701,33 @@ BinaryFunc(JSContext* cx, unsigned argc, Value* vp) return CoercedBinaryFunc(cx, argc, vp); } -template class OpWith> +template 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(args[0])) + // Only the first and second arguments are mandatory + if (args.length() < 2 || !IsVectorObject(args[0])) return ErrorBadArgs(cx); Elem* vec = TypedObjectMemory(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::apply(i, value, vec[i]); + result[i] = i == lane ? value : vec[i]; return StoreResult(cx, args, result); } @@ -1170,4 +1161,3 @@ js::simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \ } INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION) #undef DEFINE_SIMD_INT32X4_FUNCTION - diff --git a/js/src/builtin/SIMD.h b/js/src/builtin/SIMD.h index 1baf3d8b950..fd1722f4d4e 100644 --- a/js/src/builtin/SIMD.h +++ b/js/src/builtin/SIMD.h @@ -59,15 +59,12 @@ V(store2, (Store), 3) \ V(store1, (Store), 3) \ V(sub, (BinaryFunc), 2) \ - V(withX, (FuncWith), 2) \ - V(withY, (FuncWith), 2) \ - V(withZ, (FuncWith), 2) \ - V(withW, (FuncWith), 2) \ V(xor, (CoercedBinaryFunc), 2) #define FLOAT32X4_TERNARY_FUNCTION_LIST(V) \ V(bitselect, BitSelect, 3) \ V(clamp, Clamp, 3) \ + V(replaceLane, (ReplaceLane), 3) \ V(select, Select, 3) #define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V) \ @@ -111,13 +108,12 @@ V(notEqual, (CompareFunc), 2) \ V(store, (Store), 3) \ V(store1, (Store), 3) \ - V(sub, (BinaryFunc), 2) \ - V(withX, (FuncWith), 2) \ - V(withY, (FuncWith), 2) + V(sub, (BinaryFunc), 2) #define FLOAT64X2_TERNARY_FUNCTION_LIST(V) \ V(bitselect, BitSelect, 3) \ V(clamp, Clamp, 3) \ + V(replaceLane, (ReplaceLane), 3) \ V(select, Select, 3) #define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V) \ @@ -163,14 +159,11 @@ V(store3, (Store), 3) \ V(store2, (Store), 3) \ V(store1, (Store), 3) \ - V(withX, (FuncWith), 2) \ - V(withY, (FuncWith), 2) \ - V(withZ, (FuncWith), 2) \ - V(withW, (FuncWith), 2) \ V(xor, (BinaryFunc), 2) #define INT32X4_TERNARY_FUNCTION_LIST(V) \ V(bitselect, BitSelect, 3) \ + V(replaceLane, (ReplaceLane), 3) \ V(select, Select, 3) #define INT32X4_QUARTERNARY_FUNCTION_LIST(V) \ @@ -226,16 +219,11 @@ _(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) \ diff --git a/js/src/jit-test/tests/SIMD/replacelane.js b/js/src/jit-test/tests/SIMD/replacelane.js new file mode 100644 index 00000000000..178508eddeb --- /dev/null +++ b/js/src/jit-test/tests/SIMD/replacelane.js @@ -0,0 +1,102 @@ +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.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.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(); diff --git a/js/src/jit-test/tests/SIMD/with.js b/js/src/jit-test/tests/SIMD/with.js deleted file mode 100644 index 30c53e23ed4..00000000000 --- a/js/src/jit-test/tests/SIMD/with.js +++ /dev/null @@ -1,23 +0,0 @@ -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.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]); - } -} - -f(); - diff --git a/js/src/jit-test/tests/asm.js/testSIMD.js b/js/src/jit-test/tests/asm.js/testSIMD.js index 294fa14aeed..301ca294a83 100644 --- a/js/src/jit-test/tests/asm.js/testSIMD.js +++ b/js/src/jit-test/tests/asm.js/testSIMD.js @@ -609,37 +609,34 @@ CheckF4(F32MAXNUM, 'var x=f4(0,0,-0,-0); var y=f4(0,-0,0,-0); x=max(x,y)', [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 @@ -1319,4 +1316,3 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)(); print('Error:', e) throw e; } - diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index a8d4c01dd8a..a6c5ea6fdae 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -817,8 +817,8 @@ class IonBuilder 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); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 2117bd4f8d1..bf647952df6 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -313,17 +313,10 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) 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); @@ -3216,17 +3209,22 @@ IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr:: } 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); } diff --git a/js/src/tests/ecma_7/SIMD/replaceLane.js b/js/src/tests/ecma_7/SIMD/replaceLane.js new file mode 100644 index 00000000000..4ef5d22b8b0 --- /dev/null +++ b/js/src/tests/ecma_7/SIMD/replaceLane.js @@ -0,0 +1,94 @@ +// |reftest| skip-if(!this.hasOwnProperty("SIMD")) +var float32x4 = SIMD.float32x4; +var int32x4 = SIMD.int32x4; +var float64x2 = SIMD.float64x2; + + +function replaceLane0(arr, x) { + if (arr.length == 2) + return [x, arr[1]]; + return [x, arr[1], arr[2], arr[3]]; +} +function replaceLane1(arr, x) { + if (arr.length == 2) + return [arr[0], x]; + return [arr[0], x, arr[2], arr[3]]; +} +function replaceLane2(arr, x) { + return [arr[0], arr[1], x, arr[3]]; +} +function replaceLane3(arr, x) { + return [arr[0], arr[1], arr[2], x]; +} + +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() { + function testType(type, inputs) { + var length = simdToArray(inputs[0][0]).length; + for (var [vec, s] of inputs) { + 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; + 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.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.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.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(); diff --git a/js/src/tests/ecma_7/SIMD/with.js b/js/src/tests/ecma_7/SIMD/with.js deleted file mode 100644 index b9f53adc30e..00000000000 --- a/js/src/tests/ecma_7/SIMD/with.js +++ /dev/null @@ -1,93 +0,0 @@ -// |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) { - if (arr.length == 2) - return [x, arr[1]]; - return [x, arr[1], arr[2], arr[3]]; -} -function withY(arr, x) { - if (arr.length == 2) - return [arr[0], x]; - return [arr[0], x, arr[2], arr[3]]; -} -function withZ(arr, x) { - return [arr[0], arr[1], x, arr[3]]; -} -function withW(arr, x) { - return [arr[0], arr[1], arr[2], x]; -} - -function testWith(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); - if (length <= 2) - continue; - testWith(vec, s, SIMD[type].withZ, withZ); - testWith(vec, s, SIMD[type].withW, withW); - } - } - - 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); - - 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); - - 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); - - if (typeof reportCompare === "function") - reportCompare(true, true); -} - -test(); -