// A bounds check is considered redundant if it's dominated by another bounds // check with the same length and the indexes differ by only a constant amount. // In this case we eliminate the redundant bounds check and update the other one // to cover the ranges of both checks. // // Bounds checks are added to a hash map and since the hash function ignores // differences in constant offset, this offers a fast way to find redundant // checks. bool ion::EliminateRedundantBoundsChecks(MIRGraph &graph) { BoundsCheckMap checks; if (!checks.init()) return false; // Stack for pre-order CFG traversal. Vector<MBasicBlock *, 1, IonAllocPolicy> worklist; // The index of the current block in the CFG traversal. size_t index = 0; // Add all self-dominating blocks to the worklist. // This includes all roots. Order does not matter. for (MBasicBlockIterator i(graph.begin()); i != graph.end(); i++) { MBasicBlock *block = *i; if (block->immediateDominator() == block) { if (!worklist.append(block)) return false; } } // Starting from each self-dominating block, traverse the CFG in pre-order. while (!worklist.empty()) { MBasicBlock *block = worklist.popCopy(); // Add all immediate dominators to the front of the worklist. for (size_t i = 0; i < block->numImmediatelyDominatedBlocks(); i++) { if (!worklist.append(block->getImmediatelyDominatedBlock(i))) return false; } for (MDefinitionIterator iter(block); iter; ) { if (!iter->isBoundsCheck()) { iter++; continue; } MBoundsCheck *check = iter->toBoundsCheck(); // Replace all uses of the bounds check with the actual index. // This is (a) necessary, because we can coalesce two different // bounds checks and would otherwise use the wrong index and // (b) helps register allocation. Note that this is safe since // no other pass after bounds check elimination moves instructions. check->replaceAllUsesWith(check->index()); if (!check->isMovable()) { iter++; continue; } MBoundsCheck *dominating = FindDominatingBoundsCheck(checks, check, index); if (!dominating) return false; if (dominating == check) { // We didn't find a dominating bounds check. iter++; continue; } bool eliminated = false; if (!TryEliminateBoundsCheck(dominating, check, &eliminated)) return false; if (eliminated) iter = check->block()->discardDefAt(iter); else iter++; } index++; } JS_ASSERT(index == graph.numBlocks()); return true; }
// Eliminate checks which are redundant given each other or other instructions. // // A type barrier is considered redundant if all missing types have been tested // for by earlier control instructions. // // A bounds check is considered redundant if it's dominated by another bounds // check with the same length and the indexes differ by only a constant amount. // In this case we eliminate the redundant bounds check and update the other one // to cover the ranges of both checks. // // Bounds checks are added to a hash map and since the hash function ignores // differences in constant offset, this offers a fast way to find redundant // checks. bool ion::EliminateRedundantChecks(MIRGraph &graph) { BoundsCheckMap checks; if (!checks.init()) return false; // Stack for pre-order CFG traversal. Vector<MBasicBlock *, 1, IonAllocPolicy> worklist; // The index of the current block in the CFG traversal. size_t index = 0; // Add all self-dominating blocks to the worklist. // This includes all roots. Order does not matter. for (MBasicBlockIterator i(graph.begin()); i != graph.end(); i++) { MBasicBlock *block = *i; if (block->immediateDominator() == block) { if (!worklist.append(block)) return false; } } // Starting from each self-dominating block, traverse the CFG in pre-order. while (!worklist.empty()) { MBasicBlock *block = worklist.popCopy(); // Add all immediate dominators to the front of the worklist. for (size_t i = 0; i < block->numImmediatelyDominatedBlocks(); i++) { if (!worklist.append(block->getImmediatelyDominatedBlock(i))) return false; } for (MDefinitionIterator iter(block); iter; ) { bool eliminated = false; if (iter->isBoundsCheck()) { if (!TryEliminateBoundsCheck(checks, index, iter->toBoundsCheck(), &eliminated)) return false; } else if (iter->isTypeBarrier()) { if (!TryEliminateTypeBarrier(iter->toTypeBarrier(), &eliminated)) return false; } else if (iter->isConvertElementsToDoubles()) { // Now that code motion passes have finished, replace any // ConvertElementsToDoubles with the actual elements. MConvertElementsToDoubles *ins = iter->toConvertElementsToDoubles(); ins->replaceAllUsesWith(ins->elements()); } if (eliminated) iter = block->discardDefAt(iter); else iter++; } index++; } JS_ASSERT(index == graph.numBlocks()); return true; }