diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index 91aa10a5878..b7efc67d9f1 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -13,6 +13,7 @@ #include "builtin/SIMD.h" +#include "mozilla/IntegerTypeTraits.h" #include "jsapi.h" #include "jsfriendapi.h" @@ -147,12 +148,17 @@ static bool SignMask(JSContext *cx, unsigned argc, Value *vp) return false; } - Elem *data = reinterpret_cast(typedObj.typedMem()); - int32_t mx = data[0] < 0.0 ? 1 : 0; - int32_t my = data[1] < 0.0 ? 1 : 0; - int32_t mz = data[2] < 0.0 ? 1 : 0; - int32_t mw = data[3] < 0.0 ? 1 : 0; - int32_t result = mx | my << 1 | mz << 2 | mw << 3; + // Load the data as integer so that we treat the sign bit consistently, + // since -0.0 is not less than zero, but it still has the sign bit set. + typedef typename mozilla::SignedStdintTypeForSize::Type Int; + static_assert(SimdType::lanes * sizeof(Int) <= jit::Simd128DataSize, + "signMask access should respect the bounds of the type"); + const Elem *elems = reinterpret_cast(typedObj.typedMem()); + int32_t result = 0; + for (unsigned i = 0; i < SimdType::lanes; ++i) { + Int x = mozilla::BitwiseCast(elems[i]); + result |= (x < 0) << i; + } args.rval().setInt32(result); return true; } diff --git a/js/src/jit-test/tests/asm.js/testSIMD.js b/js/src/jit-test/tests/asm.js/testSIMD.js index bbe56a78910..db8848bb8bd 100644 --- a/js/src/jit-test/tests/asm.js/testSIMD.js +++ b/js/src/jit-test/tests/asm.js/testSIMD.js @@ -188,7 +188,7 @@ assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f() { var x=i4(0,- assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + 'var Infinity = glob.Infinity; function f() { var x=f4(0,0,0,0); x=f4(f32(1), f32(-13.37), f32(42), f32(-Infinity)); return x.signMask | 0 } return f'), this)(), 0b1010); assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + 'var Infinity = glob.Infinity; function f() { var x=f4(0,0,0,0); x=f4(f32(-1), f32(0), f32(-0.000001), f32(Infinity)); return x.signMask | 0 } return f'), this)(), 0b0101); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + 'var NaN = glob.NaN; function f() { var x=f4(0,0,0,0); x=f4(f32(-1), f32(NaN), f32(3.), f32(4.)); return x.signMask | 0 } return f'), this)(), 0b0001); +assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + 'var NaN = glob.NaN; function f() { var x=f4(0,0,0,0); x=f4(f32(-1), f32(NaN), f32(-0), f32(0)); return x.signMask | 0 } return f'), this)(), 0b0101); // 1.3.3. Variable assignments assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4();} return f"); diff --git a/js/src/tests/ecma_7/SIMD/signmask.js b/js/src/tests/ecma_7/SIMD/signmask.js new file mode 100644 index 00000000000..88adbc43dfb --- /dev/null +++ b/js/src/tests/ecma_7/SIMD/signmask.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty("SIMD")) + +var float32x4 = SIMD.float32x4; +var int32x4 = SIMD.int32x4; + +function test_float32x4() { + var v, w; + for ([v, w] of [[float32x4(-1, 20, 30, 4), 0b0001], + [float32x4(9.999, 2.1234, 30.4443, -4), 0b1000], + [float32x4(0, -Infinity, +Infinity, -0), 0b1010]]) + { + assertEq(v.signMask, w); + } + + if (typeof reportCompare === "function") + reportCompare(true, true); +} + +function test_int32x4() { + var v, w; + for ([v, w] of [[int32x4(-1, 20, 30, 4), 0b0001], + [int32x4(10, 2, 30.2, -4), 0b1000], + [int32x4(0, 0x80000000, 0x7fffffff, -0), 0b0010]]) + { + assertEq(v.signMask, w); + } + + if (typeof reportCompare === "function") + reportCompare(true, true); +} + +test_float32x4(); +test_int32x4(); diff --git a/mfbt/IntegerTypeTraits.h b/mfbt/IntegerTypeTraits.h index 9414451f913..6144d2084c4 100644 --- a/mfbt/IntegerTypeTraits.h +++ b/mfbt/IntegerTypeTraits.h @@ -79,6 +79,11 @@ struct UnsignedStdintTypeForSize : detail::StdintTypeForSizeAndSignedness {}; +template +struct SignedStdintTypeForSize + : detail::StdintTypeForSizeAndSignedness +{}; + template struct PositionOfSignBit {