bool
RangeAnalysis::tryHoistBoundsCheck(MBasicBlock *header, MBoundsCheck *ins)
{
    // The bounds check's length must be loop invariant.
    if (ins->length()->block()->isMarked())
        return false;

    // The bounds check's index should not be loop invariant (else we would
    // already have hoisted it during LICM).
    SimpleLinearSum index = ExtractLinearSum(ins->index());
    if (!index.term || !index.term->block()->isMarked())
        return false;

    // Check for a symbolic lower and upper bound on the index. If either
    // condition depends on an iteration bound for the loop, only hoist if
    // the bounds check is dominated by the iteration bound's test.
    if (!index.term->range())
        return false;
    const SymbolicBound *lower = index.term->range()->symbolicLower();
    if (!lower || !SymbolicBoundIsValid(header, ins, lower))
        return false;
    const SymbolicBound *upper = index.term->range()->symbolicUpper();
    if (!upper || !SymbolicBoundIsValid(header, ins, upper))
        return false;

    MBasicBlock *preLoop = header->loopPredecessor();
    JS_ASSERT(!preLoop->isMarked());

    MDefinition *lowerTerm = ConvertLinearSum(preLoop, lower->sum);
    if (!lowerTerm)
        return false;

    MDefinition *upperTerm = ConvertLinearSum(preLoop, upper->sum);
    if (!upperTerm)
        return false;

    // We are checking that index + indexConstant >= 0, and know that
    // index >= lowerTerm + lowerConstant. Thus, check that:
    //
    // lowerTerm + lowerConstant + indexConstant >= 0
    // lowerTerm >= -lowerConstant - indexConstant

    int32_t lowerConstant = 0;
    if (!SafeSub(lowerConstant, index.constant, &lowerConstant))
        return false;
    if (!SafeSub(lowerConstant, lower->sum.constant(), &lowerConstant))
        return false;
    MBoundsCheckLower *lowerCheck = MBoundsCheckLower::New(lowerTerm);
    lowerCheck->setMinimum(lowerConstant);

    // We are checking that index < boundsLength, and know that
    // index <= upperTerm + upperConstant. Thus, check that:
    //
    // upperTerm + upperConstant < boundsLength

    int32_t upperConstant = index.constant;
    if (!SafeAdd(upper->sum.constant(), upperConstant, &upperConstant))
        return false;
    MBoundsCheck *upperCheck = MBoundsCheck::New(upperTerm, ins->length());
    upperCheck->setMinimum(upperConstant);
    upperCheck->setMaximum(upperConstant);

    // Hoist the loop invariant upper and lower bounds checks.
    preLoop->insertBefore(preLoop->lastIns(), lowerCheck);
    preLoop->insertBefore(preLoop->lastIns(), upperCheck);

    return true;
}
// Try to compute hoistable checks for the upper and lower bound on ins,
// according to a test in the loop which dominates ins.
//
// Given a bounds check within a loop which is not loop invariant, we would
// like to compute loop invariant bounds checks which imply that the inner
// check will succeed.  These invariant checks can then be added to the
// preheader, and the inner check eliminated.
//
// Example:
//
// for (i = v; i < n; i++)
//   x[i] = 0;
//
// There are two constraints captured by the bounds check here: i >= 0, and
// i < length(x).  'i' is not loop invariant, but we can still hoist these
// checks:
//
// - At the point of the check, it is known that i < n.  Given this,
//   if n <= length(x) then i < length(x), and since n and length(x) are loop
//   invariant the former condition can be hoisted and the i < length(x) check
//   removed.
//
// - i is only incremented within the loop, so if its initial value is >= 0
//   then all its values within the loop will also be >= 0.  The lower bounds
//   check can be hoisted as v >= 0.
//
// tryHoistBoundsCheck encodes this logic.  Given a bounds check B and a test T
// in the loop dominating that bounds check, where B and T share a non-invariant
// term lhs, a new check C is computed such that T && C imply B.
void
Loop::tryHoistBoundsCheck(MBoundsCheck *ins, MTest *test, BranchDirection direction,
                          MInstruction **pupper, MInstruction **plower)
{
    *pupper = NULL;
    *plower = NULL;

    if (!isLoopInvariant(ins->length()))
        return;

    LinearSum lhs(NULL, 0);
    MDefinition *rhs;
    bool lessEqual;
    if (!ExtractLinearInequality(test, direction, &lhs, &rhs, &lessEqual))
        return;

    // Ensure the rhs is a loop invariant term.
    if (rhs && !isLoopInvariant(rhs)) {
        if (!isLoopInvariant(lhs.term))
            return;
        MDefinition *temp = lhs.term;
        lhs.term = rhs;
        rhs = temp;
        if (!SafeSub(0, lhs.constant, &lhs.constant))
            return;
        lessEqual = !lessEqual;
    }

    // Ensure the lhs is a phi node from the start of the loop body.
    if (!lhs.term || !lhs.term->isPhi() || lhs.term->block() != header_)
        return;

    // Check if the lhs in the conditional matches the bounds check index.
    LinearSum index = ExtractLinearSum(ins->index());
    if (index.term != lhs.term)
        return;

    if (!lessEqual)
        return;

    // At the point of the access, it is known that lhs + lhsN <= rhs, and the
    // bounds check is that lhs + indexN + maximum < length. To ensure the
    // bounds check holds then, we need to ensure that:
    //
    // rhs - lhsN + indexN + maximum < length

    int32 adjustment;
    if (!SafeSub(index.constant, lhs.constant, &adjustment))
        return;
    if (!SafeAdd(adjustment, ins->maximum(), &adjustment))
        return;

    // For the lower bound, check that lhs + indexN + minimum >= 0, e.g.
    //
    // lhs >= -indexN - minimum
    //
    // lhs is not loop invariant, but if this condition holds of the backing
    // variable at loop entry and the variable's value never decreases in the
    // loop body, it will hold throughout the loop.

    uint32 position = preLoop_->positionInPhiSuccessor();
    MDefinition *initialIndex = lhs.term->toPhi()->getOperand(position);
    if (!nonDecreasing(initialIndex, lhs.term))
        return;

    int32 lowerBound;
    if (!SafeSub(0, index.constant, &lowerBound))
        return;
    if (!SafeSub(lowerBound, ins->minimum(), &lowerBound))
        return;

    // XXX limit on how much can be hoisted, to ensure ballast works?

    if (!rhs) {
        rhs = MConstant::New(Int32Value(adjustment));
        adjustment = 0;
        preLoop_->insertBefore(preLoop_->lastIns(), rhs->toInstruction());
    }

    MBoundsCheck *upper = MBoundsCheck::New(rhs, ins->length());
    upper->setMinimum(adjustment);
    upper->setMaximum(adjustment);

    MBoundsCheckLower *lower = MBoundsCheckLower::New(initialIndex);
    lower->setMinimum(lowerBound);

    *pupper = upper;
    *plower = lower;
}