Title: [116264] branches/dfgopt/Source/_javascript_Core
Revision
116264
Author
[email protected]
Date
2012-05-06 20:43:03 -0700 (Sun, 06 May 2012)

Log Message

Truncating multiplication on integers should not OSR exit every time
https://bugs.webkit.org/show_bug.cgi?id=85752

Reviewed by Gavin Barraclough.

* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::mulShouldSpeculateInteger):
(Graph):
(JSC::DFG::Graph::mulImmediateShouldSpeculateInteger):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithMul):

Modified Paths

Diff

Modified: branches/dfgopt/Source/_javascript_Core/ChangeLog (116263 => 116264)


--- branches/dfgopt/Source/_javascript_Core/ChangeLog	2012-05-07 03:13:12 UTC (rev 116263)
+++ branches/dfgopt/Source/_javascript_Core/ChangeLog	2012-05-07 03:43:03 UTC (rev 116264)
@@ -1,3 +1,24 @@
+2012-05-06  Filip Pizlo  <[email protected]>
+
+        Truncating multiplication on integers should not OSR exit every time
+        https://bugs.webkit.org/show_bug.cgi?id=85752
+
+        Reviewed by Gavin Barraclough.
+
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::mulShouldSpeculateInteger):
+        (Graph):
+        (JSC::DFG::Graph::mulImmediateShouldSpeculateInteger):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithMul):
+
 2012-05-01  Filip Pizlo  <[email protected]>
 
         DFG should be able to compute dominators

Modified: branches/dfgopt/Source/_javascript_Core/dfg/DFGAbstractState.cpp (116263 => 116264)


--- branches/dfgopt/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-05-07 03:13:12 UTC (rev 116263)
+++ branches/dfgopt/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-05-07 03:43:03 UTC (rev 116264)
@@ -451,7 +451,26 @@
         break;
     }
         
-    case ArithMul:
+    case ArithMul: {
+        JSValue left = forNode(node.child1()).value();
+        JSValue right = forNode(node.child2()).value();
+        if (left && right && left.isNumber() && right.isNumber()) {
+            forNode(nodeIndex).set(JSValue(left.asNumber() * right.asNumber()));
+            m_foundConstants = true;
+            break;
+        }
+        if (m_graph.mulShouldSpeculateInteger(node)) {
+            forNode(node.child1()).filter(PredictInt32);
+            forNode(node.child2()).filter(PredictInt32);
+            forNode(nodeIndex).set(PredictInt32);
+            break;
+        }
+        forNode(node.child1()).filter(PredictNumber);
+        forNode(node.child2()).filter(PredictNumber);
+        forNode(nodeIndex).set(PredictDouble);
+        break;
+    }
+        
     case ArithDiv:
     case ArithMin:
     case ArithMax:
@@ -462,9 +481,6 @@
             double a = left.asNumber();
             double b = right.asNumber();
             switch (node.op()) {
-            case ArithMul:
-                forNode(nodeIndex).set(JSValue(a * b));
-                break;
             case ArithDiv:
                 forNode(nodeIndex).set(JSValue(a / b));
                 break;

Modified: branches/dfgopt/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (116263 => 116264)


--- branches/dfgopt/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2012-05-07 03:13:12 UTC (rev 116263)
+++ branches/dfgopt/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2012-05-07 03:43:03 UTC (rev 116264)
@@ -251,9 +251,16 @@
             break;
         }
             
+        case ArithMul: {
+            if (m_graph.mulShouldSpeculateInteger(node))
+                break;
+            fixDoubleEdge(0);
+            fixDoubleEdge(1);
+            break;
+        }
+
         case ArithMin:
         case ArithMax:
-        case ArithMul:
         case ArithDiv:
         case ArithMod: {
             if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()])

Modified: branches/dfgopt/Source/_javascript_Core/dfg/DFGGraph.h (116263 => 116264)


--- branches/dfgopt/Source/_javascript_Core/dfg/DFGGraph.h	2012-05-07 03:13:12 UTC (rev 116263)
+++ branches/dfgopt/Source/_javascript_Core/dfg/DFGGraph.h	2012-05-07 03:43:03 UTC (rev 116264)
@@ -198,6 +198,21 @@
         return Node::shouldSpeculateInteger(left, right) && add.canSpeculateInteger();
     }
     
+    bool mulShouldSpeculateInteger(Node& mul)
+    {
+        ASSERT(mul.op() == ArithMul);
+        
+        Node& left = at(mul.child1());
+        Node& right = at(mul.child2());
+        
+        if (left.hasConstant())
+            return mulImmediateShouldSpeculateInteger(mul, right, left);
+        if (right.hasConstant())
+            return mulImmediateShouldSpeculateInteger(mul, left, right);
+        
+        return Node::shouldSpeculateInteger(left, right) && mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags());
+    }
+    
     bool negateShouldSpeculateInteger(Node& negate)
     {
         ASSERT(negate.op() == ArithNegate);
@@ -482,6 +497,30 @@
         return nodeCanTruncateInteger(add.arithNodeFlags());
     }
     
+    bool mulImmediateShouldSpeculateInteger(Node& mul, Node& variable, Node& immediate)
+    {
+        ASSERT(immediate.hasConstant());
+        
+        JSValue immediateValue = immediate.valueOfJSConstant(m_codeBlock);
+        if (!immediateValue.isInt32())
+            return false;
+        
+        if (!variable.shouldSpeculateInteger())
+            return false;
+        
+        int32_t intImmediate = immediateValue.asInt32();
+        // Doubles have a 53 bit mantissa so we expect a multiplication of 2^31 (the highest
+        // magnitude possible int32 value) and any value less than 2^22 to not result in any
+        // rounding in a double multiplication - hence it will be equivalent to an integer
+        // multiplication, if we are doing int32 truncation afterwards (which is what
+        // canSpeculateInteger() implies).
+        const int32_t twoToThe22 = 1 << 22;
+        if (intImmediate <= -twoToThe22 || intImmediate >= twoToThe22)
+            return mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags());
+
+        return mul.canSpeculateInteger();
+    }
+    
     // When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
     void refChildren(NodeIndex);
     void derefChildren(NodeIndex);

Modified: branches/dfgopt/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (116263 => 116264)


--- branches/dfgopt/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2012-05-07 03:13:12 UTC (rev 116263)
+++ branches/dfgopt/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2012-05-07 03:43:03 UTC (rev 116264)
@@ -331,8 +331,29 @@
             changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
         }
+
+        case ArithMul: {
+            PredictedType left = m_graph[node.child1()].prediction();
+            PredictedType right = m_graph[node.child2()].prediction();
             
-        case ArithMul:
+            if (left && right) {
+                if (m_graph.mulShouldSpeculateInteger(node))
+                    changed |= mergePrediction(PredictInt32);
+                else
+                    changed |= mergePrediction(PredictDouble);
+            }
+
+            // As soon as a multiply happens, we can easily end up in the part
+            // of the double domain where the point at which you do truncation
+            // can change the outcome. So, ArithMul always checks for overflow
+            // no matter what, and always forces its inputs to check as well.
+            
+            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+            changed |= m_graph[node.child1()].mergeFlags(flags);
+            changed |= m_graph[node.child2()].mergeFlags(flags);
+            break;
+        }
+            
         case ArithDiv: {
             PredictedType left = m_graph[node.child1()].prediction();
             PredictedType right = m_graph[node.child2()].prediction();
@@ -752,7 +773,23 @@
                 break;
             }
                 
-            case ArithMul:
+            case ArithMul: {
+                PredictedType left = m_graph[node.child1()].prediction();
+                PredictedType right = m_graph[node.child2()].prediction();
+                
+                VariableAccessData::Ballot ballot;
+                
+                if (isNumberPrediction(left) && isNumberPrediction(right)
+                    && !m_graph.mulShouldSpeculateInteger(node))
+                    ballot = VariableAccessData::VoteDouble;
+                else
+                    ballot = VariableAccessData::VoteValue;
+                
+                vote(node.child1(), ballot);
+                vote(node.child2(), ballot);
+                break;
+            }
+
             case ArithMin:
             case ArithMax:
             case ArithMod:

Modified: branches/dfgopt/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (116263 => 116264)


--- branches/dfgopt/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2012-05-07 03:13:12 UTC (rev 116263)
+++ branches/dfgopt/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2012-05-07 03:43:03 UTC (rev 116264)
@@ -2645,7 +2645,7 @@
 
 void SpeculativeJIT::compileArithMul(Node& node)
 {
-    if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
+    if (m_jit.graph().mulShouldSpeculateInteger(node)) {
         SpeculateIntegerOperand op1(this, node.child1());
         SpeculateIntegerOperand op2(this, node.child2());
         GPRTemporary result(this);
@@ -2653,16 +2653,18 @@
         GPRReg reg1 = op1.gpr();
         GPRReg reg2 = op2.gpr();
 
-        // What is unfortunate is that we cannot take advantage of nodeCanTruncateInteger()
-        // here. A multiply on integers performed in the double domain and then truncated to
-        // an integer will give a different result than a multiply performed in the integer
-        // domain and then truncated, if the integer domain result would have resulted in
-        // something bigger than what a 32-bit integer can hold. _javascript_ mandates that
-        // the semantics are always as if the multiply had been performed in the double
-        // domain.
+        // We can perform truncated multiplications if we get to this point, because if the
+        // fixup phase could not prove that it would be safe, it would have turned us into
+        // a double multiplication.
+        if (nodeCanTruncateInteger(node.arithNodeFlags())) {
+            m_jit.move(reg1, result.gpr());
+            m_jit.mul32(reg2, result.gpr());
+        } else {
+            speculationCheck(
+                Overflow, JSValueRegs(), NoNode,
+                m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));
+        }
             
-        speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));
-            
         // Check for negative zero, if the users of this node care about such things.
         if (!nodeCanIgnoreNegativeZero(node.arithNodeFlags())) {
             MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr());
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to