https://bugs.webkit.org/show_bug.cgi?id=62824
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Jun 2011 23:40:06 +0000 (23:40 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Jun 2011 23:40:06 +0000 (23:40 +0000)
DFG JIT - add support for branch-fusion of compareEq, JSValue comparisons in SpeculativeJIT

Reviewed by Sam Weinig.

CompareEq of non-integer values is the most common cause of speculation failure.

* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleIntegerBranch):
    - Support Equals.
(JSC::DFG::SpeculativeJIT::compilePeepHoleEq):
    - new! - peephole optimized Eq of JSValues.
(JSC::DFG::SpeculativeJIT::compile):
    - Add peephole optimization for CompareEq.
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::detectPeepHoleBranch):
    - Add support for dead nodes between compare & branch.
(JSC::DFG::SpeculativeJIT::isInteger):
    - Added to determine which form of peephole to do in CompareEq.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@89084 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

index 2c990c1..eaa6a76 100644 (file)
@@ -1,3 +1,25 @@
+2011-06-16  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        https://bugs.webkit.org/show_bug.cgi?id=62824
+        DFG JIT - add support for branch-fusion of compareEq, JSValue comparisons in SpeculativeJIT
+
+        CompareEq of non-integer values is the most common cause of speculation failure.
+
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleIntegerBranch):
+            - Support Equals.
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleEq):
+            - new! - peephole optimized Eq of JSValues.
+        (JSC::DFG::SpeculativeJIT::compile):
+            - Add peephole optimization for CompareEq.
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::detectPeepHoleBranch):
+            - Add support for dead nodes between compare & branch.
+        (JSC::DFG::SpeculativeJIT::isInteger):
+            - Added to determine which form of peephole to do in CompareEq.
+
 2011-06-16  Geoffrey Garen  <ggaren@apple.com>
 
         Try to fix the Windows build.
index d1ebef4..4d9e36f 100644 (file)
@@ -233,9 +233,9 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
     return InvalidGPRReg;
 }
 
-void SpeculativeJIT::compilePeepHoleBranch(Node& node, JITCompiler::RelationalCondition condition)
+void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition condition)
 {
-    Node& branchNode = m_jit.graph()[m_compileIndex + 1];
+    Node& branchNode = m_jit.graph()[branchNodeIndex];
     BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());
     BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());
 
@@ -266,6 +266,37 @@ void SpeculativeJIT::compilePeepHoleBranch(Node& node, JITCompiler::RelationalCo
         addBranch(m_jit.jump(), notTaken);
 }
 
+void SpeculativeJIT::compilePeepHoleEq(Node& node, NodeIndex branchNodeIndex)
+{
+    Node& branchNode = m_jit.graph()[branchNodeIndex];
+    BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());
+    BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());
+
+    // The branch instruction will branch to the taken block.
+    // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
+    JITCompiler::ResultCondition condition = JITCompiler::NonZero;
+    if (taken == (m_block + 1)) {
+        condition = JITCompiler::Zero;
+        BlockIndex tmp = taken;
+        taken = notTaken;
+        notTaken = tmp;
+    }
+
+    JSValueOperand op1(this, node.child1);
+    JSValueOperand op2(this, node.child2);
+    GPRReg op1GPR = op1.gpr();
+    GPRReg op2GPR = op2.gpr();
+    flushRegisters();
+
+    GPRResult result(this);
+    callOperation(operationCompareEq, result.gpr(), op1GPR, op2GPR);
+    addBranch(m_jit.branchTest8(condition, result.gpr()), taken);
+
+    // Check for fall through, otherwise we need to jump.
+    if (notTaken != (m_block + 1))
+        addBranch(m_jit.jump(), notTaken);
+}
+
 void SpeculativeJIT::compile(Node& node)
 {
     NodeType op = node.op;
@@ -549,16 +580,17 @@ void SpeculativeJIT::compile(Node& node)
 
     case CompareLess: {
         // Fused compare & branch.
-        if (detectPeepHoleBranch()) {
+        NodeIndex branchNodeIndex = detectPeepHoleBranch();
+        if (branchNodeIndex != NoNode) {
             // detectPeepHoleBranch currently only permits the branch to be the very next node,
             // so can be no intervening nodes to also reference the compare. 
             ASSERT(node.adjustedRefCount() == 1);
 
-            compilePeepHoleBranch(node, JITCompiler::LessThan);
+            compilePeepHoleIntegerBranch(node, branchNodeIndex, JITCompiler::LessThan);
 
             use(node.child1);
             use(node.child2);
-            ++m_compileIndex;
+            m_compileIndex = branchNodeIndex;
             return;
         }
 
@@ -577,16 +609,17 @@ void SpeculativeJIT::compile(Node& node)
 
     case CompareLessEq: {
         // Fused compare & branch.
-        if (detectPeepHoleBranch()) {
+        NodeIndex branchNodeIndex = detectPeepHoleBranch();
+        if (branchNodeIndex != NoNode) {
             // detectPeepHoleBranch currently only permits the branch to be the very next node,
             // so can be no intervening nodes to also reference the compare. 
             ASSERT(node.adjustedRefCount() == 1);
 
-            compilePeepHoleBranch(node, JITCompiler::LessThanOrEqual);
+            compilePeepHoleIntegerBranch(node, branchNodeIndex, JITCompiler::LessThanOrEqual);
 
             use(node.child1);
             use(node.child2);
-            ++m_compileIndex;
+            m_compileIndex = branchNodeIndex;
             return;
         }
 
@@ -604,6 +637,24 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case CompareEq: {
+        // Fused compare & branch.
+        NodeIndex branchNodeIndex = detectPeepHoleBranch();
+        if (branchNodeIndex != NoNode) {
+            // detectPeepHoleBranch currently only permits the branch to be the very next node,
+            // so can be no intervening nodes to also reference the compare. 
+            ASSERT(node.adjustedRefCount() == 1);
+
+            if (isInteger(node.child1) || isInteger(node.child2))
+                compilePeepHoleIntegerBranch(node, branchNodeIndex, JITCompiler::Equal);
+            else
+                compilePeepHoleEq(node, branchNodeIndex);
+
+            use(node.child1);
+            use(node.child2);
+            m_compileIndex = branchNodeIndex;
+            return;
+        }
+
         SpeculateIntegerOperand op1(this, node.child1);
         SpeculateIntegerOperand op2(this, node.child2);
         GPRTemporary result(this, op1, op2);
index 04769bf..ad9a9f1 100644 (file)
@@ -138,18 +138,36 @@ private:
     void checkArgumentTypes();
     void initializeVariableTypes();
 
-    bool detectPeepHoleBranch()
+    // Returns the node index of the branch node if peephole is okay, NoNode otherwise.
+    NodeIndex detectPeepHoleBranch()
     {
-        // Check if the block contains precisely one more node.
-        if (m_compileIndex + 2 != m_jit.graph().m_blocks[m_block]->end)
-            return false;
+        NodeIndex lastNodeIndex = m_jit.graph().m_blocks[m_block]->end - 1;
+
+        // Check that no intervening nodes will be generated.
+        for (NodeIndex index = m_compileIndex + 1; index < lastNodeIndex; ++index) {
+            if (m_jit.graph()[index].shouldGenerate())
+                return NoNode;
+        }
 
         // Check if the lastNode is a branch on this node.
-        Node& lastNode = m_jit.graph()[m_compileIndex + 1];
-        return lastNode.op == Branch && lastNode.child1 == m_compileIndex;
+        Node& lastNode = m_jit.graph()[lastNodeIndex];
+        return lastNode.op == Branch && lastNode.child1 == m_compileIndex ? lastNodeIndex : NoNode;
+    }
+
+    bool isInteger(NodeIndex nodeIndex)
+    {
+        Node& node = m_jit.graph()[nodeIndex];
+        if (node.hasInt32Result())
+            return true;
+
+        VirtualRegister virtualRegister = node.virtualRegister();
+        GenerationInfo& info = m_generationInfo[virtualRegister];
+
+        return (info.registerFormat() | DataFormatJS) == DataFormatJSInteger;
     }
 
-    void compilePeepHoleBranch(Node&, JITCompiler::RelationalCondition);
+    void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
+    void compilePeepHoleEq(Node&, NodeIndex branchNodeIndex);
 
     // Add a speculation check without additional recovery.
     void speculationCheck(MacroAssembler::Jump jumpToFail)