void RangeAnalysis::analyzeLoop(MBasicBlock *header) { // Try to compute an upper bound on the number of times the loop backedge // will be taken. Look for tests that dominate the backedge and which have // an edge leaving the loop body. MBasicBlock *backedge = header->backedge(); // Ignore trivial infinite loops. if (backedge == header) return; markBlocksInLoopBody(header, backedge); LoopIterationBound *iterationBound = NULL; MBasicBlock *block = backedge; do { BranchDirection direction; MTest *branch = block->immediateDominatorBranch(&direction); if (block == block->immediateDominator()) break; block = block->immediateDominator(); if (branch) { direction = NegateBranchDirection(direction); MBasicBlock *otherBlock = branch->branchSuccessor(direction); if (!otherBlock->isMarked()) { iterationBound = analyzeLoopIterationCount(header, branch, direction); if (iterationBound) break; } } } while (block != header); if (!iterationBound) { graph_.unmarkBlocks(); return; } #ifdef DEBUG if (IonSpewEnabled(IonSpew_Range)) { Sprinter sp(GetIonContext()->cx); sp.init(); iterationBound->sum.print(sp); IonSpew(IonSpew_Range, "computed symbolic bound on backedges: %s", sp.string()); } #endif // Try to compute symbolic bounds for the phi nodes at the head of this // loop, expressed in terms of the iteration bound just computed. for (MDefinitionIterator iter(header); iter; iter++) { MDefinition *def = *iter; if (def->isPhi()) analyzeLoopPhi(header, iterationBound, def->toPhi()); } // Try to hoist any bounds checks from the loop using symbolic bounds. Vector<MBoundsCheck *, 0, IonAllocPolicy> hoistedChecks; for (ReversePostorderIterator iter(graph_.rpoBegin()); iter != graph_.rpoEnd(); iter++) { MBasicBlock *block = *iter; if (!block->isMarked()) continue; for (MDefinitionIterator iter(block); iter; iter++) { MDefinition *def = *iter; if (def->isBoundsCheck() && def->isMovable()) { if (tryHoistBoundsCheck(header, def->toBoundsCheck())) hoistedChecks.append(def->toBoundsCheck()); } } } // Note: replace all uses of the original bounds check with the // actual index. This is usually done during bounds check elimination, // but in this case it's safe to do it here since the load/store is // definitely not loop-invariant, so we will never move it before // one of the bounds checks we just added. for (size_t i = 0; i < hoistedChecks.length(); i++) { MBoundsCheck *ins = hoistedChecks[i]; ins->replaceAllUsesWith(ins->index()); ins->block()->discard(ins); } graph_.unmarkBlocks(); }