Title: [149041] trunk
Revision
149041
Author
[email protected]
Date
2013-04-24 08:48:55 -0700 (Wed, 24 Apr 2013)

Log Message

Filled out more cases of branch folding in the DFG
https://bugs.webkit.org/show_bug.cgi?id=115088

Reviewed by Oliver Hunt.

Source/_javascript_Core: 

No change on the benchmarks we track, but a 3X speedup on a
microbenchmark that uses these techniques.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock): (!/=)= and (!/=)== can constant
fold all types, not just numbers, because true constants have no
side effects when type-converted at runtime.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateBoolean): Added support for fixing up
boolean uses, like we do for other types like number.

* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleBooleanBranch):
(JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileStrictEq):
(JSC::DFG::SpeculativeJIT::compileBooleanCompare): Peephole fuse
boolean compare and/or compare-branch, now that we have the types for
them.

* dfg/DFGSpeculativeJIT.h: Updated declarations.

LayoutTests: 

* fast/js/regress/script-tests/branch-fold.js:
(g): Added some boolean and constant-folded cases.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (149040 => 149041)


--- trunk/LayoutTests/ChangeLog	2013-04-24 15:44:57 UTC (rev 149040)
+++ trunk/LayoutTests/ChangeLog	2013-04-24 15:48:55 UTC (rev 149041)
@@ -1,3 +1,13 @@
+2013-04-24  Geoffrey Garen  <[email protected]>
+
+        Filled out more cases of branch folding in the DFG
+        https://bugs.webkit.org/show_bug.cgi?id=115088
+
+        Reviewed by Oliver Hunt.
+
+        * fast/js/regress/script-tests/branch-fold.js:
+        (g): Added some boolean and constant-folded cases.
+
 2013-04-24  Christophe Dumez  <[email protected]>
 
         Unreviewed EFL gardening.

Modified: trunk/LayoutTests/fast/js/regress/script-tests/branch-fold.js (149040 => 149041)


--- trunk/LayoutTests/fast/js/regress/script-tests/branch-fold.js	2013-04-24 15:44:57 UTC (rev 149040)
+++ trunk/LayoutTests/fast/js/regress/script-tests/branch-fold.js	2013-04-24 15:48:55 UTC (rev 149041)
@@ -52,4 +52,40 @@
         throw "bad result";
 }
 
+function g(x, y)
+{
+    var i;
+    var limit = 150000;
+
+    for (i = 0; i < limit; ++i) {
+        if (true == false)
+            break;
+        if (true != true)
+            break;
+        if ("start" === "end")
+            break;
+        if (null !== null)
+            break;
+    }
+
+    if (i != limit)
+        throw "bad result";
+
+    for (i = 0; i < limit; ++i) {
+        if (x == false)
+            break;
+        if (x !== true)
+            break;
+        if (x != y)
+            break;
+        if (x !== y)
+            break;
+        x = x == y;
+    }
+
+    if (i != limit)
+        throw "bad result";
+}
+
 f();
+g(true, true);

Modified: trunk/Source/_javascript_Core/ChangeLog (149040 => 149041)


--- trunk/Source/_javascript_Core/ChangeLog	2013-04-24 15:44:57 UTC (rev 149040)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-04-24 15:48:55 UTC (rev 149041)
@@ -1 +1,33 @@
+2013-04-23  Geoffrey Garen  <[email protected]>
+
+        Filled out more cases of branch folding in the DFG
+        https://bugs.webkit.org/show_bug.cgi?id=115088
+
+        Reviewed by Oliver Hunt.
+
+        No change on the benchmarks we track, but a 3X speedup on a
+        microbenchmark that uses these techniques.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock): (!/=)= and (!/=)== can constant
+        fold all types, not just numbers, because true constants have no
+        side effects when type-converted at runtime.
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::shouldSpeculateBoolean): Added support for fixing up
+        boolean uses, like we do for other types like number.
+
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleBooleanBranch):
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
+        (JSC::DFG::SpeculativeJIT::compare):
+        (JSC::DFG::SpeculativeJIT::compileStrictEq):
+        (JSC::DFG::SpeculativeJIT::compileBooleanCompare): Peephole fuse
+        boolean compare and/or compare-branch, now that we have the types for
+        them.
+
+        * dfg/DFGSpeculativeJIT.h: Updated declarations.
+
 == Rolled over to ChangeLog-2013-04-24 ==

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (149040 => 149041)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2013-04-24 15:44:57 UTC (rev 149040)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2013-04-24 15:48:55 UTC (rev 149041)
@@ -679,7 +679,9 @@
     {
         return node->isStronglyProvedConstantIn(inlineCallFrame());
     }
-    
+
+    // Our codegen for constant strict equality performs a bitwise comparison,
+    // so we can only select values that have a consistent bitwise identity.
     bool isConstantForCompareStrictEq(Node* node)
     {
         if (!node->isConstant())
@@ -2432,11 +2434,9 @@
             if (canFold(op1) && canFold(op2)) {
                 JSValue a = valueOfJSConstant(op1);
                 JSValue b = valueOfJSConstant(op2);
-                if (a.isNumber() && b.isNumber()) {
-                    set(currentInstruction[1].u.operand,
-                        getJSConstantForValue(jsBoolean(a.asNumber() == b.asNumber())));
-                    NEXT_OPCODE(op_eq);
-                }
+                set(currentInstruction[1].u.operand,
+                    getJSConstantForValue(jsBoolean(JSValue::equal(m_codeBlock->globalObject()->globalExec(), a, b))));
+                NEXT_OPCODE(op_eq);
             }
             set(currentInstruction[1].u.operand, addToGraph(CompareEq, op1, op2));
             NEXT_OPCODE(op_eq);
@@ -2454,11 +2454,9 @@
             if (canFold(op1) && canFold(op2)) {
                 JSValue a = valueOfJSConstant(op1);
                 JSValue b = valueOfJSConstant(op2);
-                if (a.isNumber() && b.isNumber()) {
-                    set(currentInstruction[1].u.operand,
-                        getJSConstantForValue(jsBoolean(a.asNumber() == b.asNumber())));
-                    NEXT_OPCODE(op_stricteq);
-                }
+                set(currentInstruction[1].u.operand,
+                    getJSConstantForValue(jsBoolean(JSValue::strictEqual(m_codeBlock->globalObject()->globalExec(), a, b))));
+                NEXT_OPCODE(op_stricteq);
             }
             if (isConstantForCompareStrictEq(op1))
                 set(currentInstruction[1].u.operand, addToGraph(CompareStrictEqConstant, op2, op1));
@@ -2475,11 +2473,9 @@
             if (canFold(op1) && canFold(op2)) {
                 JSValue a = valueOfJSConstant(op1);
                 JSValue b = valueOfJSConstant(op2);
-                if (a.isNumber() && b.isNumber()) {
-                    set(currentInstruction[1].u.operand,
-                        getJSConstantForValue(jsBoolean(a.asNumber() != b.asNumber())));
-                    NEXT_OPCODE(op_stricteq);
-                }
+                set(currentInstruction[1].u.operand,
+                    getJSConstantForValue(jsBoolean(!JSValue::equal(m_codeBlock->globalObject()->globalExec(), a, b))));
+                NEXT_OPCODE(op_neq);
             }
             set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, op1, op2)));
             NEXT_OPCODE(op_neq);
@@ -2497,11 +2493,9 @@
             if (canFold(op1) && canFold(op2)) {
                 JSValue a = valueOfJSConstant(op1);
                 JSValue b = valueOfJSConstant(op2);
-                if (a.isNumber() && b.isNumber()) {
-                    set(currentInstruction[1].u.operand,
-                        getJSConstantForValue(jsBoolean(a.asNumber() != b.asNumber())));
-                    NEXT_OPCODE(op_stricteq);
-                }
+                set(currentInstruction[1].u.operand,
+                    getJSConstantForValue(jsBoolean(!JSValue::strictEqual(m_codeBlock->globalObject()->globalExec(), a, b))));
+                NEXT_OPCODE(op_nstricteq);
             }
             Node* invertedResult;
             if (isConstantForCompareStrictEq(op1))

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (149040 => 149041)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2013-04-24 15:44:57 UTC (rev 149040)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2013-04-24 15:48:55 UTC (rev 149041)
@@ -305,6 +305,11 @@
             }
             if (node->op() != CompareEq)
                 break;
+            if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
+                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
+                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child2());
+                break;
+            }
             if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
                 setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
                 setUseKindAndUnboxIfProfitable<StringUse>(node->child2());
@@ -333,6 +338,11 @@
         }
             
         case CompareStrictEq: {
+            if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
+                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
+                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child2());
+                break;
+            }
             if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
                 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
                 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (149040 => 149041)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2013-04-24 15:44:57 UTC (rev 149040)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2013-04-24 15:48:55 UTC (rev 149041)
@@ -1233,6 +1233,11 @@
         return isCellSpeculation(prediction());
     }
     
+    static bool shouldSpeculateBoolean(Node* op1, Node* op2)
+    {
+        return op1->shouldSpeculateBoolean() && op2->shouldSpeculateBoolean();
+    }
+    
     static bool shouldSpeculateInteger(Node* op1, Node* op2)
     {
         return op1->shouldSpeculateInteger() && op2->shouldSpeculateInteger();

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (149040 => 149041)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2013-04-24 15:44:57 UTC (rev 149040)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2013-04-24 15:48:55 UTC (rev 149041)
@@ -1469,6 +1469,37 @@
     jump(notTaken);
 }
 
+void SpeculativeJIT::compilePeepHoleBooleanBranch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
+{
+    BlockIndex taken = branchNode->takenBlockIndex();
+    BlockIndex notTaken = branchNode->notTakenBlockIndex();
+
+    // 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.
+    if (taken == nextBlock()) {
+        condition = JITCompiler::invert(condition);
+        BlockIndex tmp = taken;
+        taken = notTaken;
+        notTaken = tmp;
+    }
+
+    if (isBooleanConstant(node->child1().node())) {
+        bool imm = valueOfBooleanConstant(node->child1().node());
+        SpeculateBooleanOperand op2(this, node->child2());
+        branch32(condition, JITCompiler::Imm32(JSValue::encode(jsBoolean(imm))), op2.gpr(), taken);
+    } else if (isBooleanConstant(node->child2().node())) {
+        SpeculateBooleanOperand op1(this, node->child1());
+        bool imm = valueOfBooleanConstant(node->child2().node());
+        branch32(condition, op1.gpr(), JITCompiler::Imm32(JSValue::encode(jsBoolean(imm))), taken);
+    } else {
+        SpeculateBooleanOperand op1(this, node->child1());
+        SpeculateBooleanOperand op2(this, node->child2());
+        branch32(condition, op1.gpr(), op2.gpr(), taken);
+    }
+
+    jump(notTaken);
+}
+
 void SpeculativeJIT::compilePeepHoleIntegerBranch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
 {
     BlockIndex taken = branchNode->takenBlockIndex();
@@ -1521,7 +1552,9 @@
                 // Use non-peephole comparison, for now.
                 return false;
             }
-            if (node->isBinaryUseKind(ObjectUse))
+            if (node->isBinaryUseKind(BooleanUse))
+                compilePeepHoleBooleanBranch(node, branchNode, condition);
+            else if (node->isBinaryUseKind(ObjectUse))
                 compilePeepHoleObjectEquality(node, branchNode);
             else if (node->child1().useKind() == ObjectUse && node->child2().useKind() == ObjectOrOtherUse)
                 compilePeepHoleObjectToObjectOrOtherEquality(node->child1(), node->child2(), branchNode);
@@ -3499,6 +3532,11 @@
             return false;
         }
         
+        if (node->isBinaryUseKind(BooleanUse)) {
+            compileBooleanCompare(node, condition);
+            return false;
+        }
+
         if (node->isBinaryUseKind(ObjectUse)) {
             compileObjectEquality(node);
             return false;
@@ -3598,6 +3636,21 @@
 bool SpeculativeJIT::compileStrictEq(Node* node)
 {
     switch (node->binaryUseKind()) {
+    case BooleanUse: {
+        unsigned branchIndexInBlock = detectPeepHoleBranch();
+        if (branchIndexInBlock != UINT_MAX) {
+            Node* branchNode = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
+            compilePeepHoleBooleanBranch(node, branchNode, MacroAssembler::Equal);
+            use(node->child1());
+            use(node->child2());
+            m_indexInBlock = branchIndexInBlock;
+            m_currentNode = branchNode;
+            return true;
+        }
+        compileBooleanCompare(node, MacroAssembler::Equal);
+        return false;
+    }
+
     case Int32Use: {
         unsigned branchIndexInBlock = detectPeepHoleBranch();
         if (branchIndexInBlock != UINT_MAX) {
@@ -3658,6 +3711,23 @@
     }
 }
 
+void SpeculativeJIT::compileBooleanCompare(Node* node, MacroAssembler::RelationalCondition condition)
+{
+    SpeculateBooleanOperand op1(this, node->child1());
+    SpeculateBooleanOperand op2(this, node->child2());
+    GPRTemporary result(this);
+    
+    m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
+    
+    // If we add a DataFormatBool, we should use it here.
+#if USE(JSVALUE32_64)
+    booleanResult(result.gpr(), node);
+#else
+    m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+    jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
+#endif
+}
+
 void SpeculativeJIT::compileStringEquality(Node* node)
 {
     SpeculateCellOperand left(this, node->child1());

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (149040 => 149041)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2013-04-24 15:44:57 UTC (rev 149040)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2013-04-24 15:48:55 UTC (rev 149041)
@@ -1908,6 +1908,7 @@
     bool compare(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
     bool compilePeepHoleBranch(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
     void compilePeepHoleIntegerBranch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
+    void compilePeepHoleBooleanBranch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
     void compilePeepHoleDoubleBranch(Node*, Node* branchNode, JITCompiler::DoubleCondition);
     void compilePeepHoleObjectEquality(Node*, Node* branchNode);
     void compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, Node* branchNode);
@@ -1924,6 +1925,7 @@
     void compileNewStringObject(Node*);
     
     void compileIntegerCompare(Node*, MacroAssembler::RelationalCondition);
+    void compileBooleanCompare(Node*, MacroAssembler::RelationalCondition);
     void compileDoubleCompare(Node*, MacroAssembler::DoubleCondition);
     
     bool compileStrictEqForConstant(Node*, Edge value, JSValue constant);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to