[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/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index b461e7f..6a4eb13 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -334,6 +334,10 @@
case ArithAbs: {
if (m_graph.unaryArithShouldSpeculateInt32(node, FixupPass)) {
fixIntOrBooleanEdge(node->child1());
+ if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
+ node->setArithMode(Arith::Unchecked);
+ else
+ node->setArithMode(Arith::CheckOverflow);
break;
}
fixDoubleOrBooleanEdge(node->child1());
diff --git a/Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp b/Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp
index 7df9004..02aa134 100644
--- a/Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp
@@ -1203,6 +1203,43 @@
// optimize by using the relationships before the operation, but we need to
// call executeNode() before we optimize.
switch (node->op()) {
+ case ArithAbs: {
+ if (node->child1().useKind() != Int32Use)
+ break;
+
+ auto iter = m_relationships.find(node->child1().node());
+ if (iter == m_relationships.end())
+ break;
+
+ int minValue = std::numeric_limits<int>::min();
+ int maxValue = std::numeric_limits<int>::max();
+ for (Relationship relationship : iter->value) {
+ minValue = std::max(minValue, relationship.minValueOfLeft());
+ maxValue = std::min(maxValue, relationship.maxValueOfLeft());
+ }
+
+ executeNode(block->at(nodeIndex));
+
+ if (minValue >= 0) {
+ node->convertToIdentityOn(node->child1().node());
+ changed = true;
+ break;
+ }
+ if (maxValue <= 0) {
+ node->convertToArithNegate();
+ if (minValue > std::numeric_limits<int>::min())
+ node->setArithMode(Arith::Unchecked);
+ changed = true;
+ break;
+ }
+ if (minValue > std::numeric_limits<int>::min()) {
+ node->setArithMode(Arith::Unchecked);
+ changed = true;
+ break;
+ }
+
+ break;
+ }
case ArithAdd: {
if (!node->isBinaryUseKind(Int32Use))
break;
@@ -1309,6 +1346,13 @@
setRelationship(Relationship::safeCreate(node->child1().node(), m_zero, Relationship::GreaterThan, -1));
break;
}
+
+ case ArithAbs: {
+ if (node->child1().useKind() != Int32Use)
+ break;
+ setRelationship(Relationship(node, m_zero, Relationship::GreaterThan, -1));
+ break;
+ }
case ArithAdd: {
// We're only interested in int32 additions and we currently only know how to
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 12870d9..7612896 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -650,6 +650,12 @@
child2() = Edge();
m_op = ArithSqrt;
}
+
+ void convertToArithNegate()
+ {
+ ASSERT(m_op == ArithAbs && child1().useKind() == Int32Use);
+ m_op = ArithNegate;
+ }
JSValue asJSValue()
{
@@ -1678,6 +1684,7 @@
bool hasArithMode()
{
switch (op()) {
+ case ArithAbs:
case ArithAdd:
case ArithSub:
case ArithNegate:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 140311e..e564ccb 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2302,7 +2302,8 @@
m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
m_jit.add32(scratch.gpr(), result.gpr());
m_jit.xor32(scratch.gpr(), result.gpr());
- speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, result.gpr(), MacroAssembler::TrustedImm32(1 << 31)));
+ if (shouldCheckOverflow(node->arithMode()))
+ speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, result.gpr(), MacroAssembler::TrustedImm32(1 << 31)));
int32Result(result.gpr(), node);
break;
}