tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ValueNumbering.cpp (47990B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "jit/ValueNumbering.h"
      8 
      9 #include "jit/IonAnalysis.h"
     10 #include "jit/JitSpewer.h"
     11 #include "jit/MIRGenerator.h"
     12 #include "jit/MIRGraph.h"
     13 
     14 using namespace js;
     15 using namespace js::jit;
     16 
     17 /*
     18 * [SMDOC] IonMonkey Value Numbering
     19 *
     20 * Some notes on the main algorithm here:
     21 *  - The SSA identifier id() is the value number. We do replaceAllUsesWith as
     22 *    we go, so there's always at most one visible value with a given number.
     23 *
     24 *  - Consequently, the GVN algorithm is effectively pessimistic. This means it
     25 *    is not as powerful as an optimistic GVN would be, but it is simpler and
     26 *    faster.
     27 *
     28 *  - We iterate in RPO, so that when visiting a block, we've already optimized
     29 *    and hashed all values in dominating blocks. With occasional exceptions,
     30 *    this allows us to do everything in a single pass.
     31 *
     32 *  - When we do use multiple passes, we just re-run the algorithm on the whole
     33 *    graph instead of doing sparse propagation. This is a tradeoff to keep the
     34 *    algorithm simpler and lighter on inputs that don't have a lot of
     35 *    interesting unreachable blocks or degenerate loop induction variables, at
     36 *    the expense of being slower on inputs that do. The loop for this always
     37 *    terminates, because it only iterates when code is or will be removed, so
     38 *    eventually it must stop iterating.
     39 *
     40 *  - Values are not immediately removed from the hash set when they go out of
     41 *    scope. Instead, we check for dominance after a lookup. If the dominance
     42 *    check fails, the value is removed.
     43 */
     44 
     45 HashNumber ValueNumberer::VisibleValues::ValueHasher::hash(Lookup ins) {
     46  return ins->valueHash();
     47 }
     48 
     49 // Test whether two MDefinitions are congruent.
     50 bool ValueNumberer::VisibleValues::ValueHasher::match(Key k, Lookup l) {
     51  // If one of the instructions depends on a store, and the other instruction
     52  // does not depend on the same store, the instructions are not congruent.
     53  if (k->dependency() != l->dependency()) {
     54    return false;
     55  }
     56 
     57  bool congruent =
     58      k->congruentTo(l);  // Ask the values themselves what they think.
     59 #ifdef JS_JITSPEW
     60  if (congruent != l->congruentTo(k)) {
     61    JitSpew(
     62        JitSpew_GVN,
     63        "      congruentTo relation is not symmetric between %s%u and %s%u!!",
     64        k->opName(), k->id(), l->opName(), l->id());
     65  }
     66 #endif
     67  return congruent;
     68 }
     69 
     70 void ValueNumberer::VisibleValues::ValueHasher::rekey(Key& k, Key newKey) {
     71  k = newKey;
     72 }
     73 
     74 ValueNumberer::VisibleValues::VisibleValues(TempAllocator& alloc)
     75    : set_(alloc) {}
     76 
     77 // Look up the first entry for |def|.
     78 ValueNumberer::VisibleValues::Ptr ValueNumberer::VisibleValues::findLeader(
     79    const MDefinition* def) const {
     80  return set_.lookup(def);
     81 }
     82 
     83 // Look up the first entry for |def|.
     84 ValueNumberer::VisibleValues::AddPtr
     85 ValueNumberer::VisibleValues::findLeaderForAdd(MDefinition* def) {
     86  return set_.lookupForAdd(def);
     87 }
     88 
     89 // Insert a value into the set.
     90 bool ValueNumberer::VisibleValues::add(AddPtr p, MDefinition* def) {
     91  return set_.add(p, def);
     92 }
     93 
     94 // Insert a value onto the set overwriting any existing entry.
     95 void ValueNumberer::VisibleValues::overwrite(AddPtr p, MDefinition* def) {
     96  set_.replaceKey(p, def);
     97 }
     98 
     99 // |def| will be discarded, so remove it from any sets.
    100 void ValueNumberer::VisibleValues::forget(const MDefinition* def) {
    101  Ptr p = set_.lookup(def);
    102  if (p && *p == def) {
    103    set_.remove(p);
    104  }
    105 }
    106 
    107 // Clear all state.
    108 void ValueNumberer::VisibleValues::clear() { set_.clear(); }
    109 
    110 #ifdef DEBUG
    111 // Test whether |def| is in the set.
    112 bool ValueNumberer::VisibleValues::has(const MDefinition* def) const {
    113  Ptr p = set_.lookup(def);
    114  return p && *p == def;
    115 }
    116 #endif
    117 
    118 // Call MDefinition::justReplaceAllUsesWith, and add some GVN-specific asserts.
    119 static void ReplaceAllUsesWith(MDefinition* from, MDefinition* to) {
    120  MOZ_ASSERT(from != to, "GVN shouldn't try to replace a value with itself");
    121  MOZ_ASSERT(from->type() == to->type(),
    122             "Def replacement has different MIR type");
    123  MOZ_ASSERT(!to->isDiscarded(),
    124             "GVN replaces an instruction by a removed instruction");
    125 
    126  // Update the node's wasm ref type to the LUB of the two nodes being combined.
    127  // This ensures that any type-based optimizations downstream remain correct.
    128  to->setWasmRefType(wasm::MaybeRefType::leastUpperBound(from->wasmRefType(),
    129                                                         to->wasmRefType()));
    130 
    131  // We don't need the extra setting of ImplicitlyUsed flags that the regular
    132  // replaceAllUsesWith does because we do it ourselves.
    133  from->justReplaceAllUsesWith(to);
    134 }
    135 
    136 // Test whether |succ| is a successor of |block|.
    137 static bool HasSuccessor(const MControlInstruction* block,
    138                         const MBasicBlock* succ) {
    139  for (size_t i = 0, e = block->numSuccessors(); i != e; ++i) {
    140    if (block->getSuccessor(i) == succ) {
    141      return true;
    142    }
    143  }
    144  return false;
    145 }
    146 
    147 // Given a block which has had predecessors removed but is still reachable, test
    148 // whether the block's new dominator will be closer than its old one and whether
    149 // it will expose potential optimization opportunities.
    150 static MBasicBlock* ComputeNewDominator(MBasicBlock* block, MBasicBlock* old) {
    151  MBasicBlock* now = block->getPredecessor(0);
    152  for (size_t i = 1, e = block->numPredecessors(); i < e; ++i) {
    153    MBasicBlock* pred = block->getPredecessor(i);
    154    // Note that dominators haven't been recomputed yet, so we have to check
    155    // whether now dominates pred, not block.
    156    while (!now->dominates(pred)) {
    157      MBasicBlock* next = now->immediateDominator();
    158      if (next == old) {
    159        return old;
    160      }
    161      if (next == now) {
    162        MOZ_ASSERT(block == old,
    163                   "Non-self-dominating block became self-dominating");
    164        return block;
    165      }
    166      now = next;
    167    }
    168  }
    169  MOZ_ASSERT(old != block || old != now,
    170             "Missed self-dominating block staying self-dominating");
    171  return now;
    172 }
    173 
    174 // Test for any defs which look potentially interesting to GVN.
    175 static bool BlockHasInterestingDefs(MBasicBlock* block) {
    176  return !block->phisEmpty() || *block->begin() != block->lastIns();
    177 }
    178 
    179 // Walk up the dominator tree from |block| to the root and test for any defs
    180 // which look potentially interesting to GVN.
    181 static bool ScanDominatorsForDefs(MBasicBlock* block) {
    182  for (MBasicBlock* i = block;;) {
    183    if (BlockHasInterestingDefs(block)) {
    184      return true;
    185    }
    186 
    187    MBasicBlock* immediateDominator = i->immediateDominator();
    188    if (immediateDominator == i) {
    189      break;
    190    }
    191    i = immediateDominator;
    192  }
    193  return false;
    194 }
    195 
    196 // Walk up the dominator tree from |now| to |old| and test for any defs which
    197 // look potentially interesting to GVN.
    198 static bool ScanDominatorsForDefs(MBasicBlock* now, MBasicBlock* old) {
    199  MOZ_ASSERT(old->dominates(now),
    200             "Refined dominator not dominated by old dominator");
    201 
    202  for (MBasicBlock* i = now; i != old; i = i->immediateDominator()) {
    203    if (BlockHasInterestingDefs(i)) {
    204      return true;
    205    }
    206  }
    207  return false;
    208 }
    209 
    210 // Given a block which has had predecessors removed but is still reachable, test
    211 // whether the block's new dominator will be closer than its old one and whether
    212 // it will expose potential optimization opportunities.
    213 static bool IsDominatorRefined(MBasicBlock* block) {
    214  MBasicBlock* old = block->immediateDominator();
    215  MBasicBlock* now = ComputeNewDominator(block, old);
    216 
    217  // If this block is just a goto and it doesn't dominate its destination,
    218  // removing its predecessors won't refine the dominators of anything
    219  // interesting.
    220  MControlInstruction* control = block->lastIns();
    221  if (*block->begin() == control && block->phisEmpty() && control->isGoto() &&
    222      !block->dominates(control->toGoto()->target())) {
    223    return false;
    224  }
    225 
    226  // We've computed block's new dominator. Test whether there are any
    227  // newly-dominating definitions which look interesting.
    228  if (block == old) {
    229    return block != now && ScanDominatorsForDefs(now);
    230  }
    231  MOZ_ASSERT(block != now, "Non-self-dominating block became self-dominating");
    232  return ScanDominatorsForDefs(now, old);
    233 }
    234 
    235 // |def| has just had one of its users release it. If it's now dead, enqueue it
    236 // for discarding, otherwise just make note of it.
    237 bool ValueNumberer::handleUseReleased(MDefinition* def,
    238                                      ImplicitUseOption implicitUseOption) {
    239  if (IsDiscardable(def)) {
    240    values_.forget(def);
    241    if (!deadDefs_.append(def)) {
    242      return false;
    243    }
    244  } else {
    245    if (implicitUseOption == SetImplicitUse) {
    246      def->setImplicitlyUsedUnchecked();
    247    }
    248  }
    249  return true;
    250 }
    251 
    252 // Discard |def| and anything in its use-def subtree which is no longer needed.
    253 bool ValueNumberer::discardDefsRecursively(MDefinition* def,
    254                                           AllowEffectful allowEffectful) {
    255  MOZ_ASSERT(deadDefs_.empty(), "deadDefs_ not cleared");
    256 
    257  return discardDef(def, allowEffectful) && processDeadDefs();
    258 }
    259 
    260 // Assuming |resume| is unreachable, release its operands.
    261 // It might be nice to integrate this code with prepareForDiscard, however GVN
    262 // needs it to call handleUseReleased so that it can observe when a definition
    263 // becomes unused, so it isn't trivial to do.
    264 bool ValueNumberer::releaseResumePointOperands(MResumePoint* resume) {
    265  for (size_t i = 0, e = resume->numOperands(); i < e; ++i) {
    266    if (!resume->hasOperand(i)) {
    267      continue;
    268    }
    269    MDefinition* op = resume->getOperand(i);
    270    resume->releaseOperand(i);
    271 
    272    // We set the ImplicitlyUsed flag when removing resume point operands,
    273    // because even though we may think we're certain that a particular
    274    // branch might not be taken, the type information might be incomplete.
    275    if (!handleUseReleased(op, SetImplicitUse)) {
    276      return false;
    277    }
    278  }
    279  return true;
    280 }
    281 
    282 // Assuming |phi| is dead, release and remove its operands. If an operand
    283 // becomes dead, push it to the discard worklist.
    284 bool ValueNumberer::releaseAndRemovePhiOperands(MPhi* phi) {
    285  // MPhi saves operands in a vector so we iterate in reverse.
    286  for (int o = phi->numOperands() - 1; o >= 0; --o) {
    287    MDefinition* op = phi->getOperand(o);
    288    phi->removeOperand(o);
    289    if (!handleUseReleased(op, DontSetImplicitUse)) {
    290      return false;
    291    }
    292  }
    293  return true;
    294 }
    295 
    296 // Assuming |def| is dead, release its operands. If an operand becomes dead,
    297 // push it to the discard worklist.
    298 bool ValueNumberer::releaseOperands(MDefinition* def) {
    299  for (size_t o = 0, e = def->numOperands(); o < e; ++o) {
    300    MDefinition* op = def->getOperand(o);
    301    def->releaseOperand(o);
    302    if (!handleUseReleased(op, DontSetImplicitUse)) {
    303      return false;
    304    }
    305  }
    306  return true;
    307 }
    308 
    309 // Discard |def| and mine its operands for any subsequently dead defs.
    310 bool ValueNumberer::discardDef(MDefinition* def,
    311                               AllowEffectful allowEffectful) {
    312 #ifdef JS_JITSPEW
    313  JitSpew(JitSpew_GVN, "      Discarding %s %s%u",
    314          def->block()->isMarked() ? "unreachable" : "dead", def->opName(),
    315          def->id());
    316 #endif
    317 #ifdef DEBUG
    318  MOZ_ASSERT(def != nextDef_, "Invalidating the MDefinition iterator");
    319  if (def->block()->isMarked()) {
    320    MOZ_ASSERT(!def->hasUses(), "Discarding def that still has uses");
    321  } else {
    322    MOZ_ASSERT(allowEffectful == AllowEffectful::Yes
    323                   ? IsDiscardableAllowEffectful(def)
    324                   : IsDiscardable(def),
    325               "Discarding non-discardable definition");
    326    MOZ_ASSERT(!values_.has(def), "Discarding a definition still in the set");
    327  }
    328 #endif
    329 
    330  MBasicBlock* block = def->block();
    331  if (def->isPhi()) {
    332    MPhi* phi = def->toPhi();
    333    if (!releaseAndRemovePhiOperands(phi)) {
    334      return false;
    335    }
    336    block->discardPhi(phi);
    337  } else {
    338    MInstruction* ins = def->toInstruction();
    339    if (MResumePoint* resume = ins->resumePoint()) {
    340      if (!releaseResumePointOperands(resume)) {
    341        return false;
    342      }
    343    }
    344    if (!releaseOperands(ins)) {
    345      return false;
    346    }
    347    block->discardIgnoreOperands(ins);
    348  }
    349 
    350  // If that was the last definition in the block, it can be safely removed
    351  // from the graph.
    352  if (block->phisEmpty() && block->begin() == block->end()) {
    353    MOZ_ASSERT(block->isMarked(),
    354               "Reachable block lacks at least a control instruction");
    355 
    356    // As a special case, don't remove a block which is a dominator tree
    357    // root so that we don't invalidate the iterator in visitGraph. We'll
    358    // check for this and remove it later.
    359    if (block->immediateDominator() != block) {
    360      JitSpew(JitSpew_GVN, "      Block block%u is now empty; discarding",
    361              block->id());
    362      graph_.removeBlock(block);
    363      blocksRemoved_ = true;
    364    } else {
    365      JitSpew(JitSpew_GVN,
    366              "      Dominator root block%u is now empty; will discard later",
    367              block->id());
    368    }
    369  }
    370 
    371  return true;
    372 }
    373 
    374 // Recursively discard all the defs on the deadDefs_ worklist.
    375 bool ValueNumberer::processDeadDefs() {
    376  MDefinition* nextDef = nextDef_;
    377  while (!deadDefs_.empty()) {
    378    MDefinition* def = deadDefs_.popCopy();
    379 
    380    // Don't invalidate the MDefinition iterator. This is what we're going
    381    // to visit next, so we won't miss anything.
    382    if (def == nextDef) {
    383      continue;
    384    }
    385 
    386    if (!discardDef(def)) {
    387      return false;
    388    }
    389  }
    390  return true;
    391 }
    392 
    393 // Test whether |block|, which is a loop header, has any predecessors other than
    394 // |loopPred|, the loop predecessor, which it doesn't dominate.
    395 static bool hasNonDominatingPredecessor(MBasicBlock* block,
    396                                        MBasicBlock* loopPred) {
    397  MOZ_ASSERT(block->isLoopHeader());
    398  MOZ_ASSERT(block->loopPredecessor() == loopPred);
    399 
    400  for (uint32_t i = 0, e = block->numPredecessors(); i < e; ++i) {
    401    MBasicBlock* pred = block->getPredecessor(i);
    402    if (pred != loopPred && !block->dominates(pred)) {
    403      return true;
    404    }
    405  }
    406  return false;
    407 }
    408 
    409 // A loop is about to be made reachable only through an OSR entry into one of
    410 // its nested loops. Fix everything up.
    411 bool ValueNumberer::fixupOSROnlyLoop(MBasicBlock* block) {
    412  // Create an empty and unreachable(!) block which jumps to |block|. This
    413  // allows |block| to remain marked as a loop header, so we don't have to
    414  // worry about moving a different block into place as the new loop header,
    415  // which is hard, especially if the OSR is into a nested loop. Doing all
    416  // that would produce slightly more optimal code, but this is so
    417  // extraordinarily rare that it isn't worth the complexity.
    418  MBasicBlock* fake = MBasicBlock::NewFakeLoopPredecessor(graph_, block);
    419  if (!fake) {
    420    return false;
    421  }
    422  fake->setImmediateDominator(fake);
    423  fake->addNumDominated(1);
    424  fake->setDomIndex(fake->id());
    425 
    426  JitSpew(JitSpew_GVN, "        Created fake block%u", fake->id());
    427  hasOSRFixups_ = true;
    428  return true;
    429 }
    430 
    431 // Remove the CFG edge between |pred| and |block|, after releasing the phi
    432 // operands on that edge and discarding any definitions consequently made dead.
    433 bool ValueNumberer::removePredecessorAndDoDCE(MBasicBlock* block,
    434                                              MBasicBlock* pred,
    435                                              size_t predIndex) {
    436  MOZ_ASSERT(
    437      !block->isMarked(),
    438      "Block marked unreachable should have predecessors removed already");
    439 
    440  // Before removing the predecessor edge, scan the phi operands for that edge
    441  // for dead code before they get removed.
    442  MOZ_ASSERT(nextDef_ == nullptr);
    443  for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd());
    444       iter != end;) {
    445    MPhi* phi = *iter++;
    446    MOZ_ASSERT(!values_.has(phi),
    447               "Visited phi in block having predecessor removed");
    448    MOZ_ASSERT(!phi->isGuard());
    449 
    450    MDefinition* op = phi->getOperand(predIndex);
    451    phi->removeOperand(predIndex);
    452 
    453    nextDef_ = iter != end ? *iter : nullptr;
    454    if (!handleUseReleased(op, DontSetImplicitUse) || !processDeadDefs()) {
    455      return false;
    456    }
    457 
    458    // If |nextDef_| became dead while we had it pinned, advance the
    459    // iterator and discard it now.
    460    while (nextDef_ && !nextDef_->hasUses() &&
    461           !nextDef_->isGuardRangeBailouts()) {
    462      phi = nextDef_->toPhi();
    463      iter++;
    464      nextDef_ = iter != end ? *iter : nullptr;
    465      if (!discardDefsRecursively(phi)) {
    466        return false;
    467      }
    468    }
    469  }
    470  nextDef_ = nullptr;
    471 
    472  block->removePredecessorWithoutPhiOperands(pred, predIndex);
    473  return true;
    474 }
    475 
    476 // Remove the CFG edge between |pred| and |block|, and if this makes |block|
    477 // unreachable, mark it so, and remove the rest of its incoming edges too. And
    478 // discard any instructions made dead by the entailed release of any phi
    479 // operands.
    480 bool ValueNumberer::removePredecessorAndCleanUp(MBasicBlock* block,
    481                                                MBasicBlock* pred) {
    482  MOZ_ASSERT(!block->isMarked(),
    483             "Removing predecessor on block already marked unreachable");
    484 
    485  // We'll be removing a predecessor, so anything we know about phis in this
    486  // block will be wrong.
    487  for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd());
    488       iter != end; ++iter) {
    489    values_.forget(*iter);
    490  }
    491 
    492  // If this is a loop header, test whether it will become an unreachable
    493  // loop, or whether it needs special OSR-related fixups.
    494  bool isUnreachableLoop = false;
    495  if (block->isLoopHeader()) {
    496    if (block->loopPredecessor() == pred) {
    497      if (MOZ_UNLIKELY(hasNonDominatingPredecessor(block, pred))) {
    498        JitSpew(JitSpew_GVN,
    499                "      "
    500                "Loop with header block%u is now only reachable through an "
    501                "OSR entry into the middle of the loop!!",
    502                block->id());
    503      } else {
    504        // Deleting the entry into the loop makes the loop unreachable.
    505        isUnreachableLoop = true;
    506        JitSpew(JitSpew_GVN,
    507                "      "
    508                "Loop with header block%u is no longer reachable",
    509                block->id());
    510      }
    511 #ifdef JS_JITSPEW
    512    } else if (block->hasUniqueBackedge() && block->backedge() == pred) {
    513      JitSpew(JitSpew_GVN, "      Loop with header block%u is no longer a loop",
    514              block->id());
    515 #endif
    516    }
    517  }
    518 
    519  // Actually remove the CFG edge.
    520  if (!removePredecessorAndDoDCE(block, pred,
    521                                 block->getPredecessorIndex(pred))) {
    522    return false;
    523  }
    524 
    525  // We've now edited the CFG; check to see if |block| became unreachable.
    526  if (block->numPredecessors() == 0 || isUnreachableLoop) {
    527    JitSpew(JitSpew_GVN, "      Disconnecting block%u", block->id());
    528 
    529    // Remove |block| from its dominator parent's subtree. This is the only
    530    // immediately-dominated-block information we need to update, because
    531    // everything dominated by this block is about to be swept away.
    532    MBasicBlock* parent = block->immediateDominator();
    533    if (parent != block) {
    534      parent->removeImmediatelyDominatedBlock(block);
    535    }
    536 
    537    // Completely disconnect it from the CFG. We do this now rather than
    538    // just doing it later when we arrive there in visitUnreachableBlock
    539    // so that we don't leave a partially broken loop sitting around. This
    540    // also lets visitUnreachableBlock assert that numPredecessors() == 0,
    541    // which is a nice invariant.
    542    if (block->isLoopHeader()) {
    543      block->clearLoopHeader();
    544    }
    545    for (size_t i = 0, e = block->numPredecessors(); i < e; ++i) {
    546      if (!removePredecessorAndDoDCE(block, block->getPredecessor(i), i)) {
    547        return false;
    548      }
    549    }
    550 
    551    // Clear out the resume point operands, as they can hold things that
    552    // don't appear to dominate them live.
    553    if (MResumePoint* resume = block->entryResumePoint()) {
    554      if (!releaseResumePointOperands(resume) || !processDeadDefs()) {
    555        return false;
    556      }
    557      if (MResumePoint* outer = block->outerResumePoint()) {
    558        if (!releaseResumePointOperands(outer) || !processDeadDefs()) {
    559          return false;
    560        }
    561      }
    562      MOZ_ASSERT(nextDef_ == nullptr);
    563      for (MInstructionIterator iter(block->begin()), end(block->end());
    564           iter != end;) {
    565        MInstruction* ins = *iter++;
    566        nextDef_ = iter != end ? *iter : nullptr;
    567        if (MResumePoint* resume = ins->resumePoint()) {
    568          if (!releaseResumePointOperands(resume) || !processDeadDefs()) {
    569            return false;
    570          }
    571        }
    572      }
    573      nextDef_ = nullptr;
    574    } else {
    575 #ifdef DEBUG
    576      MOZ_ASSERT(block->outerResumePoint() == nullptr,
    577                 "Outer resume point in block without an entry resume point");
    578      for (MInstructionIterator iter(block->begin()), end(block->end());
    579           iter != end; ++iter) {
    580        MOZ_ASSERT(iter->resumePoint() == nullptr,
    581                   "Instruction with resume point in block without entry "
    582                   "resume point");
    583      }
    584 #endif
    585    }
    586 
    587    // Use the mark to note that we've already removed all its predecessors,
    588    // and we know it's unreachable.
    589    block->mark();
    590  }
    591 
    592  return true;
    593 }
    594 
    595 // Return a simplified form of |def|, if we can.
    596 MDefinition* ValueNumberer::simplified(MDefinition* def) const {
    597  return def->foldsTo(graph_.alloc());
    598 }
    599 
    600 // If an equivalent and dominating value already exists in the set, return it.
    601 // Otherwise insert |def| into the set and return it.
    602 MDefinition* ValueNumberer::leader(MDefinition* def) {
    603  // If the value isn't suitable for eliminating, don't bother hashing it. The
    604  // convention is that congruentTo returns false for node kinds that wish to
    605  // opt out of redundance elimination.
    606  // TODO: It'd be nice to clean up that convention (bug 1031406).
    607  if (!def->isEffectful() && def->congruentTo(def)) {
    608    // Look for a match.
    609    VisibleValues::AddPtr p = values_.findLeaderForAdd(def);
    610    if (p) {
    611      MDefinition* rep = *p;
    612      if (!rep->isDiscarded() && rep->block()->dominates(def->block())) {
    613        // We found a dominating congruent value.
    614        return rep;
    615      }
    616 
    617      // The congruent value doesn't dominate. It never will again in this
    618      // dominator tree, so overwrite it.
    619      values_.overwrite(p, def);
    620    } else {
    621      // No match. Add a new entry.
    622      if (!values_.add(p, def)) {
    623        return nullptr;
    624      }
    625    }
    626 
    627 #ifdef JS_JITSPEW
    628    JitSpew(JitSpew_GVN, "      Recording %s%u", def->opName(), def->id());
    629 #endif
    630  }
    631 
    632  return def;
    633 }
    634 
    635 // Test whether |phi| is dominated by a congruent phi.
    636 bool ValueNumberer::hasLeader(const MPhi* phi,
    637                              const MBasicBlock* phiBlock) const {
    638  if (VisibleValues::Ptr p = values_.findLeader(phi)) {
    639    const MDefinition* rep = *p;
    640    return rep != phi && rep->block()->dominates(phiBlock);
    641  }
    642  return false;
    643 }
    644 
    645 // Test whether there are any phis in |header| which are newly optimizable, as a
    646 // result of optimizations done inside the loop. This is not a sparse approach,
    647 // but restarting is rare enough in practice. Termination is ensured by
    648 // discarding the phi triggering the iteration.
    649 bool ValueNumberer::loopHasOptimizablePhi(MBasicBlock* header) const {
    650  // If the header is unreachable, don't bother re-optimizing it.
    651  if (header->isMarked()) {
    652    return false;
    653  }
    654 
    655  // Rescan the phis for any that can be simplified, since they may be reading
    656  // values from backedges.
    657  for (MPhiIterator iter(header->phisBegin()), end(header->phisEnd());
    658       iter != end; ++iter) {
    659    MPhi* phi = *iter;
    660    MOZ_ASSERT_IF(!phi->hasUses(), !DeadIfUnused(phi));
    661 
    662    if (phi->operandIfRedundant() || hasLeader(phi, header)) {
    663      return true;  // Phi can be simplified.
    664    }
    665  }
    666  return false;
    667 }
    668 
    669 // Visit |def|.
    670 bool ValueNumberer::visitDefinition(MDefinition* def) {
    671  // Nop does not fit in any of the previous optimization, as its only purpose
    672  // is to reduce the register pressure by keeping additional resume
    673  // point. Still, there is no need consecutive list of MNop instructions, and
    674  // this will slow down every other iteration on the Graph.
    675  if (def->isNop()) {
    676    MNop* nop = def->toNop();
    677    MBasicBlock* block = nop->block();
    678 
    679    // We look backward to know if we can remove the previous Nop, we do not
    680    // look forward as we would not benefit from the folding made by GVN.
    681    MInstructionReverseIterator iter = ++block->rbegin(nop);
    682 
    683    // This nop is at the beginning of the basic block, just replace the
    684    // resume point of the basic block by the one from the resume point.
    685    if (iter == block->rend()) {
    686      JitSpew(JitSpew_GVN, "      Removing Nop%u", nop->id());
    687      nop->moveResumePointAsEntry();
    688      block->discard(nop);
    689      return true;
    690    }
    691 
    692    // The previous instruction is also a Nop, no need to keep it anymore.
    693    MInstruction* prev = *iter;
    694    if (prev->isNop()) {
    695      JitSpew(JitSpew_GVN, "      Removing Nop%u", prev->id());
    696      block->discard(prev);
    697      return true;
    698    }
    699 
    700    // The Nop is introduced to capture the result and make sure the operands
    701    // are not live anymore when there are no further uses. Though when
    702    // all operands are still needed the Nop doesn't decrease the liveness
    703    // and can get removed.
    704    MResumePoint* rp = nop->resumePoint();
    705    if (rp && rp->numOperands() > 0 &&
    706        rp->getOperand(rp->numOperands() - 1) == prev &&
    707        !nop->block()->lastIns()->isThrow() &&
    708        !prev->isAssertRecoveredOnBailout()) {
    709      size_t numOperandsLive = 0;
    710      for (size_t j = 0; j < prev->numOperands(); j++) {
    711        for (size_t i = 0; i < rp->numOperands(); i++) {
    712          if (prev->getOperand(j) == rp->getOperand(i)) {
    713            numOperandsLive++;
    714            break;
    715          }
    716        }
    717      }
    718 
    719      if (numOperandsLive == prev->numOperands()) {
    720        JitSpew(JitSpew_GVN, "      Removing Nop%u", nop->id());
    721        block->discard(nop);
    722      }
    723    }
    724 
    725    return true;
    726  }
    727 
    728  // Skip optimizations on instructions which are recovered on bailout, to
    729  // avoid mixing instructions which are recovered on bailouts with
    730  // instructions which are not.
    731  if (def->isRecoveredOnBailout()) {
    732    return true;
    733  }
    734 
    735  // If this instruction has a dependency() into an unreachable block, we'll
    736  // need to update AliasAnalysis.
    737  MDefinition* dep = def->dependency();
    738  if (dep != nullptr && (dep->isDiscarded() || dep->block()->isDead())) {
    739    JitSpew(JitSpew_GVN, "      AliasAnalysis invalidated");
    740    if (updateAliasAnalysis_ && !dependenciesBroken_) {
    741      // TODO: Recomputing alias-analysis could theoretically expose more
    742      // GVN opportunities.
    743      JitSpew(JitSpew_GVN, "        Will recompute!");
    744      dependenciesBroken_ = true;
    745    }
    746    // Temporarily clear its dependency, to protect foldsTo, which may
    747    // wish to use the dependency to do store-to-load forwarding.
    748    def->setDependency(def->toInstruction());
    749  } else {
    750    dep = nullptr;
    751  }
    752 
    753  // Look for a simplified form of |def|.
    754  MDefinition* sim = simplified(def);
    755  if (sim != def) {
    756    if (sim == nullptr) {
    757      return false;
    758    }
    759 
    760    bool isNewInstruction = sim->block() == nullptr;
    761 
    762    // If |sim| doesn't belong to a block, insert it next to |def|.
    763    if (isNewInstruction) {
    764 #ifdef DEBUG
    765      if (sim->isObjectKeysLength() && def->isArrayLength()) {
    766        // /!\ Exception: MArrayLength::foldsTo replaces a sequence of
    767        // instructions containing an effectful instruction by an effectful
    768        // instruction.
    769      } else {
    770        // Otherwise, a new |sim| node mustn't be effectful when |def| wasn't
    771        // effectful.
    772        MOZ_ASSERT_IF(sim->isEffectful(), def->isEffectful());
    773      }
    774 #endif
    775 
    776      // If both instructions are effectful, |sim| must have stolen the resume
    777      // point of |def| when it's a new instruction.
    778      MOZ_ASSERT_IF(def->isEffectful() && sim->isEffectful(),
    779                    !def->toInstruction()->resumePoint() &&
    780                        sim->toInstruction()->resumePoint());
    781 
    782      def->block()->insertAfter(def->toInstruction(), sim->toInstruction());
    783    }
    784 
    785    // Get rid of flags that are meaningless for wasm and that hinder dead code
    786    // removal below.  Do this separately for |def| and |sim| to guard against
    787    // future scenarios where they come from different (JS-vs-wasm) worlds.
    788    // See bug 1969987.  This is an interim fix to a larger problem, as
    789    // described in bug 1973635.
    790    if (def->isGuardRangeBailouts() && def->block()->info().compilingWasm()) {
    791      def->setNotGuardRangeBailoutsUnchecked();
    792    }
    793    if (sim->isGuardRangeBailouts() && sim->block()->info().compilingWasm()) {
    794      sim->setNotGuardRangeBailoutsUnchecked();
    795    }
    796 
    797 #ifdef JS_JITSPEW
    798    JitSpew(JitSpew_GVN, "      Folded %s%u to %s%u", def->opName(), def->id(),
    799            sim->opName(), sim->id());
    800 #endif
    801    MOZ_ASSERT(!sim->isDiscarded());
    802    ReplaceAllUsesWith(def, sim);
    803 
    804    // The node's foldsTo said |def| can be replaced by |sim|. If |def| is a
    805    // guard, then either |sim| is also a guard, or a guard isn't actually
    806    // needed, so we can clear |def|'s guard flag and let it be discarded.
    807    def->setNotGuardUnchecked();
    808 
    809    if (def->isGuardRangeBailouts()) {
    810      sim->setGuardRangeBailoutsUnchecked();
    811    }
    812 
    813    if (sim->bailoutKind() == BailoutKind::Unknown) {
    814      sim->setBailoutKind(def->bailoutKind());
    815    }
    816 
    817    // Discard |def| if it's now unused. Similar to guards, we allow to replace
    818    // effectful instructions when the node's foldsTo method said |def| can be
    819    // replaced.
    820    if (DeadIfUnusedAllowEffectful(def)) {
    821      if (!discardDefsRecursively(def, AllowEffectful::Yes)) {
    822        return false;
    823      }
    824 
    825      // If that ended up discarding |sim|, then we're done here.
    826      if (sim->isDiscarded()) {
    827        return true;
    828      }
    829    }
    830 
    831    if (!rerun_ && def->isPhi() && !sim->isPhi()) {
    832      rerun_ = true;
    833      JitSpew(JitSpew_GVN,
    834              "      Replacing phi%u may have enabled cascading optimisations; "
    835              "will re-run",
    836              def->id());
    837    }
    838 
    839    // Otherwise, procede to optimize with |sim| in place of |def|.
    840    def = sim;
    841 
    842    // If the simplified instruction was already part of the graph, then we
    843    // probably already visited and optimized this instruction.
    844    if (!isNewInstruction) {
    845      return true;
    846    }
    847  }
    848 
    849  // Now that foldsTo is done, re-enable the original dependency. Even though
    850  // it may be pointing into a discarded block, it's still valid for the
    851  // purposes of detecting congruent loads.
    852  if (dep != nullptr) {
    853    def->setDependency(dep);
    854  }
    855 
    856  // Look for a dominating def which makes |def| redundant.
    857  MDefinition* rep = leader(def);
    858  if (rep != def) {
    859    if (rep == nullptr) {
    860      return false;
    861    }
    862 
    863    if (rep->isPhi()) {
    864      MOZ_ASSERT(def->isPhi());
    865      rep->toPhi()->updateForReplacement(def->toPhi());
    866    }
    867 
    868 #ifdef JS_JITSPEW
    869    JitSpew(JitSpew_GVN, "      Replacing %s%u with %s%u", def->opName(),
    870            def->id(), rep->opName(), rep->id());
    871 #endif
    872    ReplaceAllUsesWith(def, rep);
    873 
    874    // The node's congruentTo said |def| is congruent to |rep|, and it's
    875    // dominated by |rep|. If |def| is a guard, it's covered by |rep|,
    876    // so we can clear |def|'s guard flag and let it be discarded.
    877    def->setNotGuardUnchecked();
    878 
    879    if (DeadIfUnused(def)) {
    880      // discardDef should not add anything to the deadDefs, as the
    881      // redundant operation should have the same input operands.
    882      mozilla::DebugOnly<bool> r = discardDef(def);
    883      MOZ_ASSERT(
    884          r,
    885          "discardDef shouldn't have tried to add anything to the worklist, "
    886          "so it shouldn't have failed");
    887      MOZ_ASSERT(deadDefs_.empty(),
    888                 "discardDef shouldn't have added anything to the worklist");
    889    }
    890  }
    891 
    892  return true;
    893 }
    894 
    895 // Visit the control instruction at the end of |block|.
    896 bool ValueNumberer::visitControlInstruction(MBasicBlock* block) {
    897  // Look for a simplified form of the control instruction.
    898  MControlInstruction* control = block->lastIns();
    899  MDefinition* rep = simplified(control);
    900  if (rep == control) {
    901    return true;
    902  }
    903 
    904  if (rep == nullptr) {
    905    return false;
    906  }
    907 
    908  MControlInstruction* newControl = rep->toControlInstruction();
    909  MOZ_ASSERT(!newControl->block(),
    910             "Control instruction replacement shouldn't already be in a block");
    911 #ifdef JS_JITSPEW
    912  JitSpew(JitSpew_GVN, "      Folded control instruction %s%u to %s%u",
    913          control->opName(), control->id(), newControl->opName(),
    914          graph_.getNumInstructionIds());
    915 #endif
    916 
    917  // If the simplification removes any CFG edges, update the CFG and remove
    918  // any blocks that become dead.
    919  size_t oldNumSuccs = control->numSuccessors();
    920  size_t newNumSuccs = newControl->numSuccessors();
    921  if (newNumSuccs != oldNumSuccs) {
    922    MOZ_ASSERT(newNumSuccs < oldNumSuccs,
    923               "New control instruction has too many successors");
    924    for (size_t i = 0; i != oldNumSuccs; ++i) {
    925      MBasicBlock* succ = control->getSuccessor(i);
    926      if (HasSuccessor(newControl, succ)) {
    927        continue;
    928      }
    929      if (succ->isMarked()) {
    930        continue;
    931      }
    932      if (!removePredecessorAndCleanUp(succ, block)) {
    933        return false;
    934      }
    935      if (succ->isMarked()) {
    936        continue;
    937      }
    938      if (!rerun_) {
    939        if (!remainingBlocks_.append(succ)) {
    940          return false;
    941        }
    942      }
    943    }
    944  }
    945 
    946  if (!releaseOperands(control)) {
    947    return false;
    948  }
    949  block->discardIgnoreOperands(control);
    950  block->end(newControl);
    951  if (block->entryResumePoint() && newNumSuccs != oldNumSuccs) {
    952    block->flagOperandsOfPrunedBranches(newControl);
    953  }
    954  return processDeadDefs();
    955 }
    956 
    957 // |block| is unreachable. Mine it for opportunities to delete more dead
    958 // code, and then discard it.
    959 bool ValueNumberer::visitUnreachableBlock(MBasicBlock* block) {
    960  JitSpew(JitSpew_GVN, "    Visiting unreachable block%u%s%s%s", block->id(),
    961          block->isLoopHeader() ? " (loop header)" : "",
    962          block->isSplitEdge() ? " (split edge)" : "",
    963          block->immediateDominator() == block ? " (dominator root)" : "");
    964 
    965  MOZ_ASSERT(block->isMarked(),
    966             "Visiting unmarked (and therefore reachable?) block");
    967  MOZ_ASSERT(block->numPredecessors() == 0,
    968             "Block marked unreachable still has predecessors");
    969  MOZ_ASSERT(block != graph_.entryBlock(), "Removing normal entry block");
    970  MOZ_ASSERT(block != graph_.osrBlock(), "Removing OSR entry block");
    971  MOZ_ASSERT(deadDefs_.empty(), "deadDefs_ not cleared");
    972 
    973  // Disconnect all outgoing CFG edges.
    974  for (size_t i = 0, e = block->numSuccessors(); i < e; ++i) {
    975    MBasicBlock* succ = block->getSuccessor(i);
    976    if (succ->isDead() || succ->isMarked()) {
    977      continue;
    978    }
    979    if (!removePredecessorAndCleanUp(succ, block)) {
    980      return false;
    981    }
    982    if (succ->isMarked()) {
    983      continue;
    984    }
    985    // |succ| is still reachable. Make a note of it so that we can scan
    986    // it for interesting dominator tree changes later.
    987    if (!rerun_) {
    988      if (!remainingBlocks_.append(succ)) {
    989        return false;
    990      }
    991    }
    992  }
    993 
    994  // Discard any instructions with no uses. The remaining instructions will be
    995  // discarded when their last use is discarded.
    996  MOZ_ASSERT(nextDef_ == nullptr);
    997  for (MDefinitionIterator iter(block); iter;) {
    998    MDefinition* def = *iter++;
    999    if (def->hasUses()) {
   1000      continue;
   1001    }
   1002    nextDef_ = iter ? *iter : nullptr;
   1003    if (!discardDefsRecursively(def)) {
   1004      return false;
   1005    }
   1006  }
   1007 
   1008  nextDef_ = nullptr;
   1009  MControlInstruction* control = block->lastIns();
   1010  return discardDefsRecursively(control);
   1011 }
   1012 
   1013 // Visit all the phis and instructions |block|.
   1014 bool ValueNumberer::visitBlock(MBasicBlock* block) {
   1015  MOZ_ASSERT(!block->isMarked(), "Blocks marked unreachable during GVN");
   1016  MOZ_ASSERT(!block->isDead(), "Block to visit is already dead");
   1017 
   1018  JitSpew(JitSpew_GVN, "    Visiting block%u", block->id());
   1019 
   1020  // Visit the definitions in the block top-down.
   1021  MOZ_ASSERT(nextDef_ == nullptr);
   1022  for (MDefinitionIterator iter(block); iter;) {
   1023    if (!graph_.alloc().ensureBallast()) {
   1024      return false;
   1025    }
   1026    MDefinition* def = *iter++;
   1027 
   1028    // Remember where our iterator is so that we don't invalidate it.
   1029    nextDef_ = iter ? *iter : nullptr;
   1030 
   1031    // If the definition is dead, discard it.
   1032    if (IsDiscardable(def)) {
   1033      if (!discardDefsRecursively(def)) {
   1034        return false;
   1035      }
   1036      continue;
   1037    }
   1038 
   1039    if (!visitDefinition(def)) {
   1040      return false;
   1041    }
   1042  }
   1043  nextDef_ = nullptr;
   1044 
   1045  if (!graph_.alloc().ensureBallast()) {
   1046    return false;
   1047  }
   1048 
   1049  return visitControlInstruction(block);
   1050 }
   1051 
   1052 // Visit all the blocks dominated by dominatorRoot.
   1053 bool ValueNumberer::visitDominatorTree(MBasicBlock* dominatorRoot) {
   1054  JitSpew(JitSpew_GVN,
   1055          "  Visiting dominator tree (with %" PRIu64
   1056          " blocks) rooted at block%u%s",
   1057          uint64_t(dominatorRoot->numDominated()), dominatorRoot->id(),
   1058          dominatorRoot == graph_.entryBlock() ? " (normal entry block)"
   1059          : dominatorRoot == graph_.osrBlock() ? " (OSR entry block)"
   1060          : dominatorRoot->numPredecessors() == 0
   1061              ? " (odd unreachable block)"
   1062              : " (merge point from normal entry and OSR entry)");
   1063  MOZ_ASSERT(dominatorRoot->immediateDominator() == dominatorRoot,
   1064             "root is not a dominator tree root");
   1065 
   1066  // Visit all blocks dominated by dominatorRoot, in RPO. This has the nice
   1067  // property that we'll always visit a block before any block it dominates,
   1068  // so we can make a single pass through the list and see every full
   1069  // redundance.
   1070  size_t numVisited = 0;
   1071  size_t numDiscarded = 0;
   1072  for (ReversePostorderIterator iter(graph_.rpoBegin(dominatorRoot));;) {
   1073    MOZ_ASSERT(iter != graph_.rpoEnd(), "Inconsistent dominator information");
   1074    MBasicBlock* block = *iter++;
   1075    // We're only visiting blocks in dominatorRoot's tree right now.
   1076    if (!dominatorRoot->dominates(block)) {
   1077      continue;
   1078    }
   1079 
   1080    // If this is a loop backedge, remember the header, as we may not be able
   1081    // to find it after we simplify the block.
   1082    MBasicBlock* header =
   1083        block->isLoopBackedge() ? block->loopHeaderOfBackedge() : nullptr;
   1084 
   1085    if (block->isMarked()) {
   1086      // This block has become unreachable; handle it specially.
   1087      if (!visitUnreachableBlock(block)) {
   1088        return false;
   1089      }
   1090      ++numDiscarded;
   1091    } else {
   1092      // Visit the block!
   1093      if (!visitBlock(block)) {
   1094        return false;
   1095      }
   1096      ++numVisited;
   1097    }
   1098 
   1099    // If the block is/was a loop backedge, check to see if the block that
   1100    // is/was its header has optimizable phis, which would want a re-run.
   1101    if (!rerun_ && header && loopHasOptimizablePhi(header)) {
   1102      JitSpew(JitSpew_GVN,
   1103              "    Loop phi in block%u can now be optimized; will re-run GVN!",
   1104              header->id());
   1105      rerun_ = true;
   1106      remainingBlocks_.clear();
   1107    }
   1108 
   1109    MOZ_ASSERT(numVisited <= dominatorRoot->numDominated() - numDiscarded,
   1110               "Visited blocks too many times");
   1111    if (numVisited >= dominatorRoot->numDominated() - numDiscarded) {
   1112      break;
   1113    }
   1114  }
   1115 
   1116  totalNumVisited_ += numVisited;
   1117  values_.clear();
   1118  return true;
   1119 }
   1120 
   1121 // Visit all the blocks in the graph.
   1122 bool ValueNumberer::visitGraph() {
   1123  // Due to OSR blocks, the set of blocks dominated by a blocks may not be
   1124  // contiguous in the RPO. Do a separate traversal for each dominator tree
   1125  // root. There's always the main entry, and sometimes there's an OSR entry,
   1126  // and then there are the roots formed where the OSR paths merge with the
   1127  // main entry paths.
   1128  for (ReversePostorderIterator iter(graph_.rpoBegin());;) {
   1129    MOZ_ASSERT(iter != graph_.rpoEnd(), "Inconsistent dominator information");
   1130    MBasicBlock* block = *iter;
   1131    if (block->immediateDominator() == block) {
   1132      if (!visitDominatorTree(block)) {
   1133        return false;
   1134      }
   1135 
   1136      // Normally unreachable blocks would be removed by now, but if this
   1137      // block is a dominator tree root, it has been special-cased and left
   1138      // in place in order to avoid invalidating our iterator. Now that
   1139      // we've finished the tree, increment the iterator, and then if it's
   1140      // marked for removal, remove it.
   1141      ++iter;
   1142      if (block->isMarked()) {
   1143        JitSpew(JitSpew_GVN, "      Discarding dominator root block%u",
   1144                block->id());
   1145        MOZ_ASSERT(
   1146            block->begin() == block->end(),
   1147            "Unreachable dominator tree root has instructions after tree walk");
   1148        MOZ_ASSERT(block->phisEmpty(),
   1149                   "Unreachable dominator tree root has phis after tree walk");
   1150        graph_.removeBlock(block);
   1151        blocksRemoved_ = true;
   1152      }
   1153 
   1154      MOZ_ASSERT(totalNumVisited_ <= graph_.numBlocks(),
   1155                 "Visited blocks too many times");
   1156      if (totalNumVisited_ >= graph_.numBlocks()) {
   1157        break;
   1158      }
   1159    } else {
   1160      // This block a dominator tree root. Proceed to the next one.
   1161      ++iter;
   1162    }
   1163  }
   1164  totalNumVisited_ = 0;
   1165  return true;
   1166 }
   1167 
   1168 bool ValueNumberer::insertOSRFixups() {
   1169  ReversePostorderIterator end(graph_.end());
   1170  for (ReversePostorderIterator iter(graph_.begin()); iter != end;) {
   1171    MBasicBlock* block = *iter++;
   1172 
   1173    // Only add fixup block above for loops which can be reached from OSR.
   1174    if (!block->isLoopHeader()) {
   1175      continue;
   1176    }
   1177 
   1178    // If the loop header is not self-dominated, then this loop does not
   1179    // have to deal with a second entry point, so there is no need to add a
   1180    // second entry point with a fixup block.
   1181    if (block->immediateDominator() != block) {
   1182      continue;
   1183    }
   1184 
   1185    if (!fixupOSROnlyLoop(block)) {
   1186      return false;
   1187    }
   1188  }
   1189 
   1190  return true;
   1191 }
   1192 
   1193 // OSR fixups serve the purpose of representing the non-OSR entry into a loop
   1194 // when the only real entry is an OSR entry into the middle. However, if the
   1195 // entry into the middle is subsequently folded away, the loop may actually
   1196 // have become unreachable. Mark-and-sweep all blocks to remove all such code.
   1197 bool ValueNumberer::cleanupOSRFixups() {
   1198  // Mark.
   1199  Vector<MBasicBlock*, 0, JitAllocPolicy> worklist(graph_.alloc());
   1200  unsigned numMarked = 2;
   1201  graph_.entryBlock()->mark();
   1202  graph_.osrBlock()->mark();
   1203  if (!worklist.append(graph_.entryBlock()) ||
   1204      !worklist.append(graph_.osrBlock())) {
   1205    return false;
   1206  }
   1207  while (!worklist.empty()) {
   1208    MBasicBlock* block = worklist.popCopy();
   1209    for (size_t i = 0, e = block->numSuccessors(); i != e; ++i) {
   1210      MBasicBlock* succ = block->getSuccessor(i);
   1211      if (!succ->isMarked()) {
   1212        ++numMarked;
   1213        succ->mark();
   1214        if (!worklist.append(succ)) {
   1215          return false;
   1216        }
   1217      } else if (succ->isLoopHeader() && succ->loopPredecessor() == block &&
   1218                 succ->numPredecessors() == 3) {
   1219        // Unmark fixup blocks if the loop predecessor is marked after
   1220        // the loop header.
   1221        succ->getPredecessor(1)->unmarkUnchecked();
   1222      }
   1223    }
   1224 
   1225    // OSR fixup blocks are needed if and only if the loop header is
   1226    // reachable from its backedge (via the OSR block) and not from its
   1227    // original loop predecessor.
   1228    //
   1229    // Thus OSR fixup blocks are removed if the loop header is not
   1230    // reachable, or if the loop header is reachable from both its backedge
   1231    // and its original loop predecessor.
   1232    if (block->isLoopHeader()) {
   1233      MBasicBlock* maybeFixupBlock = nullptr;
   1234      if (block->numPredecessors() == 2) {
   1235        maybeFixupBlock = block->getPredecessor(0);
   1236      } else {
   1237        MOZ_ASSERT(block->numPredecessors() == 3);
   1238        if (!block->loopPredecessor()->isMarked()) {
   1239          maybeFixupBlock = block->getPredecessor(1);
   1240        }
   1241      }
   1242 
   1243      if (maybeFixupBlock && !maybeFixupBlock->isMarked() &&
   1244          maybeFixupBlock->numPredecessors() == 0) {
   1245        MOZ_ASSERT(maybeFixupBlock->numSuccessors() == 1,
   1246                   "OSR fixup block should have exactly one successor");
   1247        MOZ_ASSERT(maybeFixupBlock != graph_.entryBlock(),
   1248                   "OSR fixup block shouldn't be the entry block");
   1249        MOZ_ASSERT(maybeFixupBlock != graph_.osrBlock(),
   1250                   "OSR fixup block shouldn't be the OSR entry block");
   1251        maybeFixupBlock->mark();
   1252      }
   1253    }
   1254  }
   1255 
   1256  // And sweep.
   1257  return RemoveUnmarkedBlocks(mir_, graph_, numMarked);
   1258 }
   1259 
   1260 ValueNumberer::ValueNumberer(const MIRGenerator* mir, MIRGraph& graph)
   1261    : mir_(mir),
   1262      graph_(graph),
   1263      // Initialize the value set. It's tempting to pass in a length that is a
   1264      // function of graph_.getNumInstructionIds(). But if we start out with a
   1265      // large capacity, it will be far larger than the actual element count for
   1266      // most of the pass, so when we remove elements, it would often think it
   1267      // needs to compact itself. Empirically, just letting the HashTable grow
   1268      // as needed on its own seems to work pretty well.
   1269      values_(graph.alloc()),
   1270      deadDefs_(graph.alloc()),
   1271      remainingBlocks_(graph.alloc()),
   1272      nextDef_(nullptr),
   1273      totalNumVisited_(0),
   1274      rerun_(false),
   1275      blocksRemoved_(false),
   1276      updateAliasAnalysis_(false),
   1277      dependenciesBroken_(false),
   1278      hasOSRFixups_(false) {}
   1279 
   1280 bool ValueNumberer::run(UpdateAliasAnalysisFlag updateAliasAnalysis) {
   1281  updateAliasAnalysis_ = updateAliasAnalysis == UpdateAliasAnalysis;
   1282 
   1283  JitSpew(JitSpew_GVN, "Running GVN on graph (with %" PRIu64 " blocks)",
   1284          uint64_t(graph_.numBlocks()));
   1285 
   1286  // Adding fixup blocks only make sense iff we have a second entry point into
   1287  // the graph which cannot be reached any more from the entry point.
   1288  if (graph_.osrBlock()) {
   1289    if (!insertOSRFixups()) {
   1290      return false;
   1291    }
   1292  }
   1293 
   1294  // Top level non-sparse iteration loop. If an iteration performs a
   1295  // significant change, such as discarding a block which changes the
   1296  // dominator tree and may enable more optimization, this loop takes another
   1297  // iteration.
   1298  int runs = 0;
   1299  for (;;) {
   1300    if (!visitGraph()) {
   1301      return false;
   1302    }
   1303 
   1304    // Test whether any block which was not removed but which had at least
   1305    // one predecessor removed will have a new dominator parent.
   1306    while (!remainingBlocks_.empty()) {
   1307      MBasicBlock* block = remainingBlocks_.popCopy();
   1308      if (!block->isDead() && IsDominatorRefined(block)) {
   1309        JitSpew(JitSpew_GVN,
   1310                "  Dominator for block%u can now be refined; will re-run GVN!",
   1311                block->id());
   1312        rerun_ = true;
   1313        remainingBlocks_.clear();
   1314        break;
   1315      }
   1316    }
   1317 
   1318    if (blocksRemoved_) {
   1319      if (!AccountForCFGChanges(mir_, graph_, dependenciesBroken_,
   1320                                /* underValueNumberer = */ true)) {
   1321        return false;
   1322      }
   1323 
   1324      blocksRemoved_ = false;
   1325      dependenciesBroken_ = false;
   1326    }
   1327 
   1328    if (mir_->shouldCancel("GVN (outer loop)")) {
   1329      return false;
   1330    }
   1331 
   1332    // If no further opportunities have been discovered, we're done.
   1333    if (!rerun_) {
   1334      break;
   1335    }
   1336 
   1337    rerun_ = false;
   1338 
   1339    // Enforce an arbitrary iteration limit. This is rarely reached, and
   1340    // isn't even strictly necessary, as the algorithm is guaranteed to
   1341    // terminate on its own in a finite amount of time (since every time we
   1342    // re-run we discard the construct which triggered the re-run), but it
   1343    // does help avoid slow compile times on pathological code.
   1344    ++runs;
   1345    if (runs == 6) {
   1346      JitSpew(JitSpew_GVN, "Re-run cutoff of %d reached. Terminating GVN!",
   1347              runs);
   1348      break;
   1349    }
   1350 
   1351    JitSpew(JitSpew_GVN,
   1352            "Re-running GVN on graph (run %d, now with %" PRIu64 " blocks)",
   1353            runs, uint64_t(graph_.numBlocks()));
   1354  }
   1355 
   1356  if (MOZ_UNLIKELY(hasOSRFixups_)) {
   1357    if (!cleanupOSRFixups()) {
   1358      return false;
   1359    }
   1360    hasOSRFixups_ = false;
   1361  }
   1362 
   1363  return true;
   1364 }