Example #1
0
// Remove the CFG edge between |pred| and |block|, and if this makes |block|
// unreachable, mark it so, and remove the rest of its incoming edges too. And
// discard any instructions made dead by the entailed release of any phi
// operands.
bool
ValueNumberer::removePredecessorAndCleanUp(MBasicBlock* block, MBasicBlock* pred)
{
    MOZ_ASSERT(!block->isMarked(), "Removing predecessor on block already marked unreachable");

    // We'll be removing a predecessor, so anything we know about phis in this
    // block will be wrong.
    for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd()); iter != end; ++iter)
        values_.forget(*iter);

    // If this is a loop header, test whether it will become an unreachable
    // loop, or whether it needs special OSR-related fixups.
    bool isUnreachableLoop = false;
    MBasicBlock* origBackedgeForOSRFixup = nullptr;
    if (block->isLoopHeader()) {
        if (block->loopPredecessor() == pred) {
            if (MOZ_UNLIKELY(hasNonDominatingPredecessor(block, pred))) {
                JitSpew(JitSpew_GVN, "      "
                        "Loop with header block%u is now only reachable through an "
                        "OSR entry into the middle of the loop!!", block->id());
                origBackedgeForOSRFixup = block->backedge();
            } else {
                // Deleting the entry into the loop makes the loop unreachable.
                isUnreachableLoop = true;
                JitSpew(JitSpew_GVN, "      "
                        "Loop with header block%u is no longer reachable",
                        block->id());
            }
#ifdef DEBUG
        } else if (block->hasUniqueBackedge() && block->backedge() == pred) {
            JitSpew(JitSpew_GVN, "      Loop with header block%u is no longer a loop",
                    block->id());
#endif
        }
    }

    // Actually remove the CFG edge.
    if (!removePredecessorAndDoDCE(block, pred, block->getPredecessorIndex(pred)))
        return false;

    // We've now edited the CFG; check to see if |block| became unreachable.
    if (block->numPredecessors() == 0 || isUnreachableLoop) {
        JitSpew(JitSpew_GVN, "      Disconnecting block%u", block->id());

        // Remove |block| from its dominator parent's subtree. This is the only
        // immediately-dominated-block information we need to update, because
        // everything dominated by this block is about to be swept away.
        MBasicBlock* parent = block->immediateDominator();
        if (parent != block)
            parent->removeImmediatelyDominatedBlock(block);

        // Completely disconnect it from the CFG. We do this now rather than
        // just doing it later when we arrive there in visitUnreachableBlock
        // so that we don't leave a partially broken loop sitting around. This
        // also lets visitUnreachableBlock assert that numPredecessors() == 0,
        // which is a nice invariant.
        if (block->isLoopHeader())
            block->clearLoopHeader();
        for (size_t i = 0, e = block->numPredecessors(); i < e; ++i) {
            if (!removePredecessorAndDoDCE(block, block->getPredecessor(i), i))
                return false;
        }

        // Clear out the resume point operands, as they can hold things that
        // don't appear to dominate them live.
        if (MResumePoint* resume = block->entryResumePoint()) {
            if (!releaseResumePointOperands(resume) || !processDeadDefs())
                return false;
            if (MResumePoint* outer = block->outerResumePoint()) {
                if (!releaseResumePointOperands(outer) || !processDeadDefs())
                    return false;
            }
            MOZ_ASSERT(nextDef_ == nullptr);
            for (MInstructionIterator iter(block->begin()), end(block->end()); iter != end; ) {
                MInstruction* ins = *iter++;
                nextDef_ = *iter;
                if (MResumePoint* resume = ins->resumePoint()) {
                    if (!releaseResumePointOperands(resume) || !processDeadDefs())
                        return false;
                }
            }
            nextDef_ = nullptr;
        } else {
#ifdef DEBUG
            MOZ_ASSERT(block->outerResumePoint() == nullptr,
                       "Outer resume point in block without an entry resume point");
            for (MInstructionIterator iter(block->begin()), end(block->end());
                 iter != end;
                 ++iter)
            {
                MOZ_ASSERT(iter->resumePoint() == nullptr,
                           "Instruction with resume point in block without entry resume point");
            }
#endif
        }

        // Use the mark to note that we've already removed all its predecessors,
        // and we know it's unreachable.
        block->mark();
    } else if (MOZ_UNLIKELY(origBackedgeForOSRFixup != nullptr)) {
        // The loop is no only reachable through OSR into the middle. Fix it
        // up so that the CFG can remain valid.
        if (!fixupOSROnlyLoop(block, origBackedgeForOSRFixup))
            return false;
    }

    return true;
}