// Remove the CFG edge between |pred| and |block|, after releasing the phi // operands on that edge and discarding any definitions consequently made dead. bool ValueNumberer::removePredecessorAndDoDCE(MBasicBlock* block, MBasicBlock* pred, size_t predIndex) { MOZ_ASSERT(!block->isMarked(), "Block marked unreachable should have predecessors removed already"); // Before removing the predecessor edge, scan the phi operands for that edge // for dead code before they get removed. MOZ_ASSERT(nextDef_ == nullptr); for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd()); iter != end; ) { MPhi* phi = *iter++; MOZ_ASSERT(!values_.has(phi), "Visited phi in block having predecessor removed"); MOZ_ASSERT(!phi->isGuard()); MDefinition* op = phi->getOperand(predIndex); phi->removeOperand(predIndex); nextDef_ = iter != end ? *iter : nullptr; if (!handleUseReleased(op, DontSetUseRemoved) || !processDeadDefs()) return false; // If |nextDef_| became dead while we had it pinned, advance the // iterator and discard it now. while (nextDef_ && !nextDef_->hasUses() && !nextDef_->isGuardRangeBailouts()) { phi = nextDef_->toPhi(); iter++; nextDef_ = iter != end ? *iter : nullptr; if (!discardDefsRecursively(phi)) return false; } } nextDef_ = nullptr; block->removePredecessorWithoutPhiOperands(pred, predIndex); return true; }