Bug 943303 - Annotate and modify conditions leading to dead branches. r=sunfish

This commit is contained in:
Nicolas B. Pierron 2013-12-09 05:56:19 -08:00
Родитель dbef3d8866
Коммит 6e4bc9355f
9 изменённых файлов: 83 добавлений и 33 удалений

Просмотреть файл

@ -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 */