mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1138881 - IonMonkey: Improve types at AndOr, r=bhackett
This commit is contained in:
parent
57eca445bd
commit
dde1cfabd7
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user