Modified: trunk/Source/_javascript_Core/ChangeLog (89083 => 89084)
--- trunk/Source/_javascript_Core/ChangeLog 2011-06-16 23:34:19 UTC (rev 89083)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-06-16 23:40:06 UTC (rev 89084)
@@ -1,3 +1,25 @@
+2011-06-16 Gavin Barraclough <[email protected]>
+
+ 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 <[email protected]>
Try to fix the Windows build.
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (89083 => 89084)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2011-06-16 23:34:19 UTC (rev 89083)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2011-06-16 23:40:06 UTC (rev 89084)
@@ -233,9 +233,9 @@
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 @@
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 @@
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 @@
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 @@
}
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);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (89083 => 89084)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2011-06-16 23:34:19 UTC (rev 89083)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2011-06-16 23:40:06 UTC (rev 89084)
@@ -138,19 +138,37 @@
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;
}
- void compilePeepHoleBranch(Node&, JITCompiler::RelationalCondition);
+ 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 compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
+ void compilePeepHoleEq(Node&, NodeIndex branchNodeIndex);
+
// Add a speculation check without additional recovery.
void speculationCheck(MacroAssembler::Jump jumpToFail)
{