[JSC] Remove the overflow check on ArithAbs when possible
https://bugs.webkit.org/show_bug.cgi?id=154325
Patch by Benjamin Poulain <bpoulain@apple.com> on 2016-02-17
Reviewed by Filip Pizlo.
This patch adds support for ArithMode for ArithAbs.
It is useful for kraken tests where Math.abs() is used
on values for which the range is known.
For example, imaging-gaussian-blur has two Math.abs() with
integers that are always in a small range around zero.
The IntegerRangeOptimizationPhase detects the range correctly
so we can just update the ArithMode depending on the input.
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGIntegerRangeOptimizationPhase.cpp:
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToArithNegate):
(JSC::DFG::Node::hasArithMode):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::compileArithAbs):
* tests/stress/arith-abs-integer-range-optimization.js: Added.
(negativeRange):
(negativeRangeIncludingZero):
(negativeRangeWithOverflow):
(positiveRange):
(positiveRangeIncludingZero):
(rangeWithoutOverflow):
* tests/stress/arith-abs-with-bitwise-or-zero.js: Added.
(opaqueAbs):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@196726 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/tests/stress/arith-abs-integer-range-optimization.js b/Source/JavaScriptCore/tests/stress/arith-abs-integer-range-optimization.js
new file mode 100644
index 0000000..5be96f7
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arith-abs-integer-range-optimization.js
@@ -0,0 +1,139 @@
+function negativeRange(results)
+{
+ for (var i = -1; i > -10; --i) {
+ results[Math.abs(i)] = i;
+ }
+}
+noInline(negativeRange);
+
+for (var i = 0; i < 1e4; ++i) {
+ var results = [];
+ negativeRange(results);
+ if (results.length != 10)
+ throw "Wrong result length: " + results.length;
+ for (var j = 0; j < 10; ++j) {
+ if (j < 1) {
+ if (results[j] !== undefined)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ continue;
+ }
+ if (results[j] !== -j)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ }
+}
+
+function negativeRangeIncludingZero(results)
+{
+ for (var i = 0; i > -10; --i) {
+ results[Math.abs(i)] = i;
+ }
+}
+noInline(negativeRangeIncludingZero);
+
+for (var i = 0; i < 1e4; ++i) {
+ var results = [];
+ negativeRangeIncludingZero(results);
+ if (results.length != 10)
+ throw "Wrong result length: " + results.length;
+ for (var j = 0; j < 10; ++j) {
+ if (results[j] !== -j)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ }
+}
+
+function negativeRangeWithOverflow(results, limit)
+{
+ var i = -2147483648 + 10;
+ do {
+ results.push(Math.abs(i));
+ --i;
+ } while (i !== limit);
+}
+noInline(negativeRangeWithOverflow);
+
+// First, we warm up without overflow.
+for (var i = 0; i < 1e4; ++i) {
+ var results = [];
+ negativeRangeWithOverflow(results, -2147483647);
+ if (results.length != 9)
+ throw "Wrong result length: " + results.length;
+ for (var j = 0; j < 9; ++j) {
+ if (results[j] !== 2147483638 + j)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ }
+}
+
+// Then we overflow.
+for (var i = 0; i < 1e4; ++i) {
+ var results = [];
+ negativeRangeWithOverflow(results, -2147483648);
+ if (results.length != 10)
+ throw "Wrong result length: " + results.length;
+ for (var j = 0; j < 10; ++j) {
+ if (results[j] !== 2147483638 + j)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ }
+}
+
+function positiveRange(results)
+{
+ for (var i = 1; i < 10; ++i) {
+ results[Math.abs(i)] = i;
+ }
+}
+noInline(positiveRange);
+
+for (var i = 0; i < 1e4; ++i) {
+ var results = [];
+ positiveRange(results);
+ if (results.length != 10)
+ throw "Wrong result length: " + results.length;
+ for (var j = 0; j < 10; ++j) {
+ if (j < 1) {
+ if (results[j] !== undefined)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ continue;
+ }
+ if (results[j] !== j)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ }
+}
+
+function positiveRangeIncludingZero(results)
+{
+ for (var i = 0; i < 10; ++i) {
+ results[Math.abs(i)] = i;
+ }
+}
+noInline(positiveRangeIncludingZero);
+
+for (var i = 0; i < 1e4; ++i) {
+ var results = [];
+ positiveRangeIncludingZero(results);
+ if (results.length != 10)
+ throw "Wrong result length: " + results.length;
+ for (var j = 0; j < 10; ++j) {
+ if (results[j] !== j)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ }
+}
+
+function rangeWithoutOverflow(results)
+{
+ for (var i = -10; i < 10; ++i) {
+ results[i] = Math.abs(i);
+ }
+}
+noInline(rangeWithoutOverflow);
+
+for (var i = 0; i < 1e4; ++i) {
+ var results = [];
+ rangeWithoutOverflow(results);
+ if (results.length != 10)
+ throw "Wrong result length: " + results.length;
+ for (var j = -10; j < 10; ++j) {
+ var expected = (j < 0) ? -j : j;
+ if (results[j] !== expected)
+ throw "Wrong result, results[j] = " + results[j] + " at j = " + j;
+ }
+}