Bug 1138881 - IonMonkey: Improve types at AndOr, r=bhackett

This commit is contained in:
Hannes Verschore 2015-03-25 16:15:27 +01:00
parent 57eca445bd
commit dde1cfabd7
2 changed files with 38 additions and 116 deletions

View File

@ -305,112 +305,11 @@ MaybeFoldConditionBlock(MIRGraph &graph, MBasicBlock *initialBlock)
graph.removeBlock(testBlock);
}
static void
MaybeFoldAndOrBlock(MIRGraph &graph, MBasicBlock *initialBlock)
{
// Optimize the MIR graph to improve the code generated for && and ||
// operations when they are used in tests. This is very similar to the
// above method for folding condition blocks, though the two are
// separated (with as much common code as possible) for clarity. This
// normally requires three blocks. The final test can always be eliminated,
// though we don't try to constant fold away the branch block as well.
// Look for a triangle pattern:
//
// initialBlock
// / |
// branchBlock |
// \ |
// phiBlock
// |
// testBlock
//
// Where phiBlock contains a single phi combining values pushed onto the
// stack by initialBlock and testBlock, and testBlock contains a test on
// that phi. phiBlock and testBlock may be the same block; generated code
// will use different blocks if the &&/|| is in an inlined function.
MInstruction *ins = initialBlock->lastIns();
if (!ins->isTest())
return;
MTest *initialTest = ins->toTest();
bool branchIsTrue = true;
MBasicBlock *branchBlock = initialTest->ifTrue();
MBasicBlock *phiBlock = initialTest->ifFalse();
if (branchBlock->numSuccessors() != 1 || branchBlock->getSuccessor(0) != phiBlock) {
branchIsTrue = false;
branchBlock = initialTest->ifFalse();
phiBlock = initialTest->ifTrue();
}
if (branchBlock->numSuccessors() != 1 || branchBlock->getSuccessor(0) != phiBlock)
return;
if (branchBlock->numPredecessors() != 1 || phiBlock->numPredecessors() != 2)
return;
if (initialBlock->isLoopBackedge() || branchBlock->isLoopBackedge())
return;
MBasicBlock *testBlock = phiBlock;
if (testBlock->numSuccessors() == 1) {
if (testBlock->isLoopBackedge())
return;
testBlock = testBlock->getSuccessor(0);
if (testBlock->numPredecessors() != 1)
return;
}
// Make sure the test block does not have any outgoing loop backedges.
if (!SplitCriticalEdgesForBlock(graph, testBlock))
CrashAtUnhandlableOOM("MaybeFoldAndOrBlock");
MPhi *phi;
MTest *finalTest;
if (!BlockIsSingleTest(phiBlock, testBlock, &phi, &finalTest))
return;
MDefinition *branchResult = phi->getOperand(phiBlock->indexForPredecessor(branchBlock));
MDefinition *initialResult = phi->getOperand(phiBlock->indexForPredecessor(initialBlock));
if (initialResult != initialTest->input())
return;
// OK, we found the desired pattern, now transform the graph.
// Remove the phi from phiBlock.
phiBlock->discardPhi(*phiBlock->phisBegin());
// Change the end of the initial and branch blocks to a test that jumps
// directly to successors of testBlock, rather than to testBlock itself.
UpdateTestSuccessors(graph.alloc(), initialBlock, initialResult,
branchIsTrue ? branchBlock : finalTest->ifTrue(),
branchIsTrue ? finalTest->ifFalse() : branchBlock,
testBlock);
UpdateTestSuccessors(graph.alloc(), branchBlock, branchResult,
finalTest->ifTrue(), finalTest->ifFalse(), testBlock);
// Remove phiBlock, if different from testBlock.
if (phiBlock != testBlock) {
testBlock->removePredecessor(phiBlock);
graph.removeBlock(phiBlock);
}
// Remove testBlock itself.
finalTest->ifTrue()->removePredecessor(testBlock);
finalTest->ifFalse()->removePredecessor(testBlock);
graph.removeBlock(testBlock);
}
void
jit::FoldTests(MIRGraph &graph)
{
for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++)
MaybeFoldConditionBlock(graph, *block);
MaybeFoldAndOrBlock(graph, *block);
}
}
static void

View File

@ -302,12 +302,12 @@ IonBuilder::CFGState::IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MTest *t
}
IonBuilder::CFGState
IonBuilder::CFGState::AndOr(jsbytecode *join, MBasicBlock *joinStart)
IonBuilder::CFGState::AndOr(jsbytecode *join, MBasicBlock *lhs)
{
CFGState state;
state.state = AND_OR;
state.stopAt = join;
state.branch.ifFalse = joinStart;
state.branch.ifFalse = lhs;
state.branch.test = nullptr;
return state;
}
@ -2695,16 +2695,25 @@ IonBuilder::processNextTableSwitchCase(CFGState &state)
IonBuilder::ControlStatus
IonBuilder::processAndOrEnd(CFGState &state)
{
// We just processed the RHS of an && or || expression.
// Now jump to the join point (the false block).
current->end(MGoto::New(alloc(), state.branch.ifFalse));
MOZ_ASSERT(current);
MBasicBlock *lhs = state.branch.ifFalse;
if (!state.branch.ifFalse->addPredecessor(alloc(), current))
// Create a new block to represent the join.
MBasicBlock *join = newBlock(current, state.stopAt);
if (!join)
return ControlStatus_Error;
if (!setCurrentAndSpecializePhis(state.branch.ifFalse))
// End the rhs.
current->end(MGoto::New(alloc(), join));
// End the lhs.
lhs->end(MGoto::New(alloc(), join));
if (!join->addPredecessor(alloc(), state.branch.ifFalse))
return ControlStatus_Error;
// Set the join path as current path.
if (!setCurrentAndSpecializePhis(join))
return ControlStatus_Error;
graph().moveBlockToEnd(current);
pc = current->pc();
return ControlStatus_Joined;
}
@ -4117,20 +4126,34 @@ IonBuilder::jsop_andor(JSOp op)
// We have to leave the LHS on the stack.
MDefinition *lhs = current->peek(-1);
MBasicBlock *evalLhs = newBlock(current, joinStart);
MBasicBlock *evalRhs = newBlock(current, rhsStart);
MBasicBlock *join = newBlock(current, joinStart);
if (!evalRhs || !join)
if (!evalLhs || !evalRhs)
return false;
MTest *test = (op == JSOP_AND)
? newTest(lhs, evalRhs, join)
: newTest(lhs, join, evalRhs);
? newTest(lhs, evalRhs, evalLhs)
: newTest(lhs, evalLhs, evalRhs);
current->end(test);
if (!cfgStack_.append(CFGState::AndOr(joinStart, join)))
// Create the lhs block and specialize.
if (!setCurrentAndSpecializePhis(evalLhs))
return false;
return setCurrentAndSpecializePhis(evalRhs);
if (!improveTypesAtTest(test->getOperand(0), test->ifTrue() == current, test))
return false;
// Create the rhs block.
if (!cfgStack_.append(CFGState::AndOr(joinStart, evalLhs)))
return false;
if (!setCurrentAndSpecializePhis(evalRhs))
return false;
if (!improveTypesAtTest(test->getOperand(0), test->ifTrue() == current, test))
return false;
return true;
}
bool