bool Loop::hoistInstructions(InstructionQueue &toHoist) { // Iterate in post-order (uses before definitions) for (int32_t i = toHoist.length() - 1; i >= 0; i--) { MInstruction *ins = toHoist[i]; // Don't hoist MConstantElements, MConstant and MBox // if it doesn't enable us to hoist one of its uses. // We want those instructions as close as possible to their use. if (ins->isConstantElements() || ins->isConstant() || ins->isBox()) { bool loopInvariantUse = false; for (MUseDefIterator use(ins); use; use++) { if (use.def()->isLoopInvariant()) { loopInvariantUse = true; break; } } if (!loopInvariantUse) ins->setNotLoopInvariant(); } } // Move all instructions to the preLoop_ block just before the control instruction. for (size_t i = 0; i < toHoist.length(); i++) { MInstruction *ins = toHoist[i]; // Loads may have an implicit dependency on either stores (effectful instructions) or // control instructions so we should never move these. JS_ASSERT(!ins->isControlInstruction()); JS_ASSERT(!ins->isEffectful()); JS_ASSERT(ins->isMovable()); if (!ins->isLoopInvariant()) continue; if (checkHotness(ins->block())) { ins->block()->moveBefore(preLoop_->lastIns(), ins); ins->setNotLoopInvariant(); } } return true; }
bool Loop::hoistInstructions(InstructionQueue &toHoist, InstructionQueue &boundsChecks) { // Hoist bounds checks first, so that hoistBoundsCheck can test for // invariant instructions, but delay actual insertion until the end to // handle dependencies on loop invariant instructions. InstructionQueue hoistedChecks; for (size_t i = 0; i < boundsChecks.length(); i++) { MBoundsCheck *ins = boundsChecks[i]->toBoundsCheck(); if (isLoopInvariant(ins) || !isInLoop(ins)) continue; // Try to find a test dominating the bounds check which can be // transformed into a hoistable check. Stop after the first such check // which could be transformed (the one which will be the closest to the // access in the source). MBasicBlock *block = ins->block(); while (true) { BranchDirection direction; MTest *branch = block->immediateDominatorBranch(&direction); if (branch) { MInstruction *upper, *lower; tryHoistBoundsCheck(ins, branch, direction, &upper, &lower); if (upper && !hoistedChecks.append(upper)) return false; if (lower && !hoistedChecks.append(lower)) return false; if (upper || lower) { ins->block()->discard(ins); break; } } MBasicBlock *dom = block->immediateDominator(); if (dom == block) break; block = dom; } } // Move all instructions to the preLoop_ block just before the control instruction. for (size_t i = 0; i < toHoist.length(); i++) { MInstruction *ins = toHoist[i]; // Loads may have an implicit dependency on either stores (effectful instructions) or // control instructions so we should never move these. JS_ASSERT(!ins->isControlInstruction()); JS_ASSERT(!ins->isEffectful()); JS_ASSERT(ins->isMovable()); if (checkHotness(ins->block())) { ins->block()->moveBefore(preLoop_->lastIns(), ins); ins->setNotLoopInvariant(); } } for (size_t i = 0; i < hoistedChecks.length(); i++) { MInstruction *ins = hoistedChecks[i]; preLoop_->insertBefore(preLoop_->lastIns(), ins); } return true; }