зеркало из https://github.com/mozilla/gecko-dev.git
Bug 943303 - Annotate and modify conditions leading to dead branches. r=sunfish
This commit is contained in:
Родитель
dbef3d8866
Коммит
6e4bc9355f
|
@ -1318,6 +1318,29 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
if (mir->shouldCancel("RA De-Beta"))
|
||||
return false;
|
||||
|
||||
if (js_IonOptions.uce) {
|
||||
bool shouldRunUCE = false;
|
||||
if (!r.prepareForUCE(&shouldRunUCE))
|
||||
return false;
|
||||
IonSpewPass("RA check UCE");
|
||||
AssertExtendedGraphCoherency(graph);
|
||||
|
||||
if (mir->shouldCancel("RA check UCE"))
|
||||
return false;
|
||||
|
||||
if (shouldRunUCE) {
|
||||
UnreachableCodeElimination uce(mir, graph);
|
||||
uce.disableAliasAnalysis();
|
||||
if (!uce.analyze())
|
||||
return false;
|
||||
IonSpewPass("UCE After RA");
|
||||
AssertExtendedGraphCoherency(graph);
|
||||
|
||||
if (mir->shouldCancel("UCE After RA"))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!r.truncate())
|
||||
return false;
|
||||
IonSpewPass("Truncate Doubles");
|
||||
|
|
|
@ -62,23 +62,6 @@ MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op)
|
|||
fprintf(fp, "%c", tolower(name[i]));
|
||||
}
|
||||
|
||||
// If one of the inputs to any non-phi are in a block that will abort, then there is
|
||||
// no point in processing this instruction, since control flow cannot reach here.
|
||||
bool
|
||||
MDefinition::earlyAbortCheck()
|
||||
{
|
||||
if (isPhi())
|
||||
return false;
|
||||
for (size_t i = 0, e = numOperands(); i < e; i++) {
|
||||
if (getOperand(i)->block()->earlyAbort()) {
|
||||
block()->setEarlyAbort();
|
||||
IonSpew(IonSpew_Range, "Ignoring value from block %d because instruction %d is in a block that aborts", block()->id(), getOperand(i)->id());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
EqualValues(bool useGVN, MDefinition *left, MDefinition *right)
|
||||
{
|
||||
|
|
|
@ -386,8 +386,6 @@ class MDefinition : public MNode
|
|||
virtual bool truncate();
|
||||
virtual bool isOperandTruncated(size_t index) const;
|
||||
|
||||
bool earlyAbortCheck();
|
||||
|
||||
// Compute an absolute or symbolic range for the value of this node.
|
||||
virtual void computeRange(TempAllocator &alloc) {
|
||||
}
|
||||
|
|
|
@ -275,7 +275,7 @@ MBasicBlock::NewAsmJS(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred, Kin
|
|||
}
|
||||
|
||||
MBasicBlock::MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind)
|
||||
: earlyAbort_(false),
|
||||
: unreachable_(false),
|
||||
graph_(graph),
|
||||
info_(info),
|
||||
predecessors_(graph.alloc()),
|
||||
|
|
|
@ -50,8 +50,8 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
|||
bool inheritResumePoint(MBasicBlock *pred);
|
||||
void assertUsesAreNotWithin(MUseIterator use, MUseIterator end);
|
||||
|
||||
// Does this block do something that forces it to terminate early?
|
||||
bool earlyAbort_;
|
||||
// This block cannot be reached by any means.
|
||||
bool unreachable_;
|
||||
|
||||
// Pushes a copy of a local variable or argument.
|
||||
void pushVariable(uint32_t slot);
|
||||
|
@ -88,14 +88,14 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
|||
void setId(uint32_t id) {
|
||||
id_ = id;
|
||||
}
|
||||
void setEarlyAbort() {
|
||||
earlyAbort_ = true;
|
||||
void setUnreachable() {
|
||||
unreachable_ = true;
|
||||
}
|
||||
void clearEarlyAbort() {
|
||||
earlyAbort_ = false;
|
||||
void clearUnreachable() {
|
||||
unreachable_ = false;
|
||||
}
|
||||
bool earlyAbort() {
|
||||
return earlyAbort_;
|
||||
bool unreachable() {
|
||||
return unreachable_;
|
||||
}
|
||||
// Move the definition to the top of the stack.
|
||||
void pick(int32_t depth);
|
||||
|
|
|
@ -996,7 +996,7 @@ MPhi::computeRange(TempAllocator &alloc)
|
|||
Range *range = nullptr;
|
||||
JS_ASSERT(getOperand(0)->op() != MDefinition::Op_OsrValue);
|
||||
for (size_t i = 0, e = numOperands(); i < e; i++) {
|
||||
if (getOperand(i)->block()->earlyAbort()) {
|
||||
if (getOperand(i)->block()->unreachable()) {
|
||||
IonSpew(IonSpew_Range, "Ignoring unreachable input %d", getOperand(i)->id());
|
||||
continue;
|
||||
}
|
||||
|
@ -1028,8 +1028,8 @@ MBeta::computeRange(TempAllocator &alloc)
|
|||
Range opRange(getOperand(0));
|
||||
Range *range = Range::intersect(alloc, &opRange, comparison_, &emptyRange);
|
||||
if (emptyRange) {
|
||||
IonSpew(IonSpew_Range, "Marking block for inst %d unexitable", id());
|
||||
block()->setEarlyAbort();
|
||||
IonSpew(IonSpew_Range, "Marking block for inst %d unreachable", id());
|
||||
block()->setUnreachable();
|
||||
} else {
|
||||
setRange(range);
|
||||
}
|
||||
|
@ -2555,3 +2555,40 @@ MUrsh::collectRangeInfoPreTrunc()
|
|||
if (lhsRange.lower() >= 0 || rhsRange.lower() >= 1)
|
||||
bailoutsDisabled_ = true;
|
||||
}
|
||||
|
||||
bool
|
||||
RangeAnalysis::prepareForUCE(bool *shouldRemoveDeadCode)
|
||||
{
|
||||
*shouldRemoveDeadCode = false;
|
||||
|
||||
for (ReversePostorderIterator iter(graph_.rpoBegin()); iter != graph_.rpoEnd(); iter++) {
|
||||
MBasicBlock *block = *iter;
|
||||
|
||||
if (!block->unreachable())
|
||||
continue;
|
||||
|
||||
MControlInstruction *cond = block->getPredecessor(0)->lastIns();
|
||||
if (!cond->isTest())
|
||||
continue;
|
||||
|
||||
// Replace the condition of the test control instruction by a constant
|
||||
// chosen based which of the successors has the unreachable flag which is
|
||||
// added by MBeta::computeRange on its own block.
|
||||
MTest *test = cond->toTest();
|
||||
MConstant *constant = nullptr;
|
||||
if (block == test->ifTrue()) {
|
||||
constant = MConstant::New(alloc(), BooleanValue(false));
|
||||
} else {
|
||||
JS_ASSERT(block == test->ifFalse());
|
||||
constant = MConstant::New(alloc(), BooleanValue(true));
|
||||
}
|
||||
test->block()->insertBefore(test, constant);
|
||||
test->replaceOperand(0, constant);
|
||||
IonSpew(IonSpew_Range, "Update condition of %d to reflect unreachable branches.",
|
||||
test->id());
|
||||
|
||||
*shouldRemoveDeadCode = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ class RangeAnalysis
|
|||
bool analyze();
|
||||
bool addRangeAssertions();
|
||||
bool removeBetaNodes();
|
||||
bool prepareForUCE(bool *shouldRemoveDeadCode);
|
||||
bool truncate();
|
||||
|
||||
private:
|
||||
|
|
|
@ -204,7 +204,7 @@ UnreachableCodeElimination::checkDependencyAndRemoveUsesFromUnmarkedBlocks(MDefi
|
|||
{
|
||||
// When the instruction depends on removed block,
|
||||
// alias analysis needs to get rerun to have the right dependency.
|
||||
if (instr->dependency() && !instr->dependency()->block()->isMarked())
|
||||
if (!disableAliasAnalysis_ && instr->dependency() && !instr->dependency()->block()->isMarked())
|
||||
rerunAliasAnalysis_ = true;
|
||||
|
||||
for (MUseIterator iter(instr->usesBegin()); iter != instr->usesEnd(); ) {
|
||||
|
|
|
@ -23,6 +23,7 @@ class UnreachableCodeElimination
|
|||
uint32_t marked_;
|
||||
bool redundantPhis_;
|
||||
bool rerunAliasAnalysis_;
|
||||
bool disableAliasAnalysis_;
|
||||
|
||||
bool prunePointlessBranchesAndMarkReachableBlocks();
|
||||
void checkDependencyAndRemoveUsesFromUnmarkedBlocks(MDefinition *instr);
|
||||
|
@ -38,7 +39,8 @@ class UnreachableCodeElimination
|
|||
graph_(graph),
|
||||
marked_(0),
|
||||
redundantPhis_(false),
|
||||
rerunAliasAnalysis_(false)
|
||||
rerunAliasAnalysis_(false),
|
||||
disableAliasAnalysis_(false)
|
||||
{}
|
||||
|
||||
// Walks the graph and discovers what is reachable. Removes everything else.
|
||||
|
@ -48,6 +50,12 @@ class UnreachableCodeElimination
|
|||
// reachable. The parameter |marked| should be the number of blocks that
|
||||
// are marked.
|
||||
bool removeUnmarkedBlocks(size_t marked);
|
||||
|
||||
// Call this function to prevent alias analysis to run a second time if we
|
||||
// do not need it.
|
||||
void disableAliasAnalysis() {
|
||||
disableAliasAnalysis_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace jit */
|
||||
|
|
Загрузка…
Ссылка в новой задаче