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);