From e0fb4b123e8cd1ffe32a07dfd13cdf44179d0f31 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Tue, 31 May 2016 09:00:20 -0700 Subject: [PATCH] Bug 1136226 - Inline saturating arithmetic operations. r=sunfish Add support for inlining addSaturate and subSaturate SIMD operations when compiling SIMD.js. --- js/src/jit-test/lib/simd.js | 4 +- js/src/jit-test/tests/SIMD/binary-arith.js | 12 +++--- .../tests/SIMD/float32x4-binary-arith.js | 10 ++--- js/src/jit-test/tests/SIMD/saturate.js | 37 +++++++++++++++++++ js/src/jit/IonBuilder.h | 2 + js/src/jit/MCallOptimize.cpp | 22 ++++++++++- 6 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 js/src/jit-test/tests/SIMD/saturate.js diff --git a/js/src/jit-test/lib/simd.js b/js/src/jit-test/lib/simd.js index 7490a1ebba12..f275c6f08107 100644 --- a/js/src/jit-test/lib/simd.js +++ b/js/src/jit-test/lib/simd.js @@ -9,11 +9,11 @@ function booleanBinaryX4(op, v, w) { return arr; } -function binaryX4(op, v, w) { +function binaryX(op, v, w) { var arr = []; var [varr, warr] = [simdToArray(v), simdToArray(w)]; [varr, warr] = [varr.map(Math.fround), warr.map(Math.fround)]; - for (var i = 0; i < 4; i++) + for (var i = 0; i < varr.length; i++) arr[i] = op(varr[i], warr[i]); return arr.map(Math.fround); } diff --git a/js/src/jit-test/tests/SIMD/binary-arith.js b/js/src/jit-test/tests/SIMD/binary-arith.js index 3fe70f1b0c9e..a85d069edd8a 100644 --- a/js/src/jit-test/tests/SIMD/binary-arith.js +++ b/js/src/jit-test/tests/SIMD/binary-arith.js @@ -10,13 +10,13 @@ function f() { var f2 = SIMD.Float32x4(4, 3, 2, 1); for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Float32x4.add(f1, f2), binaryX4((x, y) => x + y, f1, f2)); - assertEqX4(SIMD.Float32x4.sub(f1, f2), binaryX4((x, y) => x - y, f1, f2)); - assertEqX4(SIMD.Float32x4.mul(f1, f2), binaryX4((x, y) => x * y, f1, f2)); + assertEqX4(SIMD.Float32x4.add(f1, f2), binaryX((x, y) => x + y, f1, f2)); + assertEqX4(SIMD.Float32x4.sub(f1, f2), binaryX((x, y) => x - y, f1, f2)); + assertEqX4(SIMD.Float32x4.mul(f1, f2), binaryX((x, y) => x * y, f1, f2)); - assertEqX4(SIMD.Int32x4.add(i1, i2), binaryX4((x, y) => x + y, i1, i2)); - assertEqX4(SIMD.Int32x4.sub(i1, i2), binaryX4((x, y) => x - y, i1, i2)); - assertEqX4(SIMD.Int32x4.mul(i1, i2), binaryX4((x, y) => x * y, i1, i2)); + assertEqX4(SIMD.Int32x4.add(i1, i2), binaryX((x, y) => x + y, i1, i2)); + assertEqX4(SIMD.Int32x4.sub(i1, i2), binaryX((x, y) => x - y, i1, i2)); + assertEqX4(SIMD.Int32x4.mul(i1, i2), binaryX((x, y) => x * y, i1, i2)); } } diff --git a/js/src/jit-test/tests/SIMD/float32x4-binary-arith.js b/js/src/jit-test/tests/SIMD/float32x4-binary-arith.js index e2febd314b52..63e9215d9fef 100644 --- a/js/src/jit-test/tests/SIMD/float32x4-binary-arith.js +++ b/js/src/jit-test/tests/SIMD/float32x4-binary-arith.js @@ -22,11 +22,11 @@ function f() { var f1 = SIMD.Float32x4(1, 2, 3, 4); var f2 = SIMD.Float32x4(4, 3, 2, 1); for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Float32x4.div(f1, f2), binaryX4((x, y) => x / y, f1, f2)); - assertEqX4(SIMD.Float32x4.min(f1, f2), binaryX4(Math.min, f1, f2)); - assertEqX4(SIMD.Float32x4.max(f1, f2), binaryX4(Math.max, f1, f2)); - assertEqX4(SIMD.Float32x4.minNum(f1, f2), binaryX4(minNum, f1, f2)); - assertEqX4(SIMD.Float32x4.maxNum(f1, f2), binaryX4(maxNum, f1, f2)); + assertEqX4(SIMD.Float32x4.div(f1, f2), binaryX((x, y) => x / y, f1, f2)); + assertEqX4(SIMD.Float32x4.min(f1, f2), binaryX(Math.min, f1, f2)); + assertEqX4(SIMD.Float32x4.max(f1, f2), binaryX(Math.max, f1, f2)); + assertEqX4(SIMD.Float32x4.minNum(f1, f2), binaryX(minNum, f1, f2)); + assertEqX4(SIMD.Float32x4.maxNum(f1, f2), binaryX(maxNum, f1, f2)); } } diff --git a/js/src/jit-test/tests/SIMD/saturate.js b/js/src/jit-test/tests/SIMD/saturate.js new file mode 100644 index 000000000000..a98cf7ad799f --- /dev/null +++ b/js/src/jit-test/tests/SIMD/saturate.js @@ -0,0 +1,37 @@ +load(libdir + 'simd.js'); + +setJitCompilerOption("ion.warmup.trigger", 50); + +const INT8_MIN = -128; +const INT8_MAX = 127; +const UINT8_MAX = 255; + +function sat8(x) { + if (x < INT8_MIN) return INT8_MIN; + if (x > INT8_MAX) return INT8_MAX; + return x; +} + +function usat8(x) { + if (x < 0) return 0; + if (x > UINT8_MAX) return UINT8_MAX; + return x; +} + +function f() { + var i1 = SIMD.Int8x16(1, 100, 3, 4); + var i2 = SIMD.Int8x16(4, 30, 2, 1); + + var u1 = SIMD.Uint8x16(1, 2, 3, 4); + var u2 = SIMD.Uint8x16(4, 3, 2, 1); + + for (var i = 0; i < 150; i++) { + assertEqX4(SIMD.Int8x16.addSaturate(i1, i2), binaryX((x, y) => sat8(x + y), i1, i2)); + assertEqX4(SIMD.Int8x16.subSaturate(i1, i2), binaryX((x, y) => sat8(x - y), i1, i2)); + + assertEqX4(SIMD.Uint8x16.addSaturate(u1, u2), binaryX((x, y) => usat8(x + y), u1, u2)); + assertEqX4(SIMD.Uint8x16.subSaturate(u1, u2), binaryX((x, y) => usat8(x - y), u1, u2)); + } +} + +f(); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index acb6ef43a391..da09ec8047ad 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -918,6 +918,8 @@ class IonBuilder template InliningStatus inlineSimdBinary(CallInfo& callInfo, JSNative native, typename T::Operation op, SimdType type); + InliningStatus inlineSimdBinarySaturating(CallInfo& callInfo, JSNative native, + MSimdBinarySaturating::Operation op, SimdType type); InliningStatus inlineSimdShift(CallInfo& callInfo, JSNative native, MSimdShift::Operation op, SimdType type); InliningStatus inlineSimdComp(CallInfo& callInfo, JSNative native, diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 276af8825da4..821dc6368284 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -3268,9 +3268,12 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, SimdType type) case SimdOperation::Fn_minNum: return inlineSimdBinary(callInfo, native, MSimdBinaryArith::Op_minNum, type); + + // Binary saturating. case SimdOperation::Fn_addSaturate: + return inlineSimdBinarySaturating(callInfo, native, MSimdBinarySaturating::add, type); case SimdOperation::Fn_subSaturate: - MOZ_CRASH("NYI"); + return inlineSimdBinarySaturating(callInfo, native, MSimdBinarySaturating::sub, type); // Binary bitwise. case SimdOperation::Fn_and: @@ -3563,6 +3566,23 @@ IonBuilder::inlineSimdBinary(CallInfo& callInfo, JSNative native, typename T::Op return boxSimd(callInfo, ins, templateObj); } +// Inline a binary SIMD operation where both arguments are SIMD types. +IonBuilder::InliningStatus +IonBuilder::inlineSimdBinarySaturating(CallInfo& callInfo, JSNative native, + MSimdBinarySaturating::Operation op, SimdType type) +{ + InlineTypedObject* templateObj = nullptr; + if (!canInlineSimd(callInfo, native, 2, &templateObj)) + return InliningStatus_NotInlined; + + MDefinition* lhs = unboxSimd(callInfo.getArg(0), type); + MDefinition* rhs = unboxSimd(callInfo.getArg(1), type); + + MSimdBinarySaturating* ins = + MSimdBinarySaturating::New(alloc(), lhs, rhs, op, GetSimdSign(type)); + return boxSimd(callInfo, ins, templateObj); +} + // Inline a SIMD shiftByScalar operation. IonBuilder::InliningStatus IonBuilder::inlineSimdShift(CallInfo& callInfo, JSNative native, MSimdShift::Operation op,