Exemplo n.º 1
0
static void
VisitLoop(MIRGraph &graph, MBasicBlock *header)
{
    MInstruction *hoistPoint = header->loopPredecessor()->lastIns();

    JitSpew(JitSpew_LICM, "  Visiting loop with header block%u, hoisting to %s%u",
            header->id(), hoistPoint->opName(), hoistPoint->id());

    MBasicBlock *backedge = header->backedge();

    // This indicates whether the loop contains calls or other things which
    // clobber most or all floating-point registers. In such loops,
    // floating-point constants should not be hoisted unless it enables further
    // hoisting.
    bool hasCalls = LoopContainsPossibleCall(graph, header, backedge);

    for (auto i(graph.rpoBegin(header)); ; ++i) {
        MOZ_ASSERT(i != graph.rpoEnd(), "Reached end of graph searching for blocks in loop");
        MBasicBlock *block = *i;
        if (!block->isMarked())
            continue;

        VisitLoopBlock(block, header, hoistPoint, hasCalls);

        if (block == backedge)
            break;
    }
}
Exemplo n.º 2
0
bool
jit::LICM(MIRGenerator *mir, MIRGraph &graph)
{
    JitSpew(JitSpew_LICM, "Beginning LICM pass");

    // Iterate in RPO to visit outer loops before inner loops. We'd hoist the
    // same things either way, but outer first means we do a little less work.
    for (auto i(graph.rpoBegin()), e(graph.rpoEnd()); i != e; ++i) {
        MBasicBlock *header = *i;
        if (!header->isLoopHeader())
            continue;

        bool canOsr;
        MarkLoopBlocks(graph, header, &canOsr);

        // Hoisting out of a loop that has an entry from the OSR block in
        // addition to its normal entry is tricky. In theory we could clone
        // the instruction and insert phis.
        if (!canOsr)
            VisitLoop(graph, header);
        else
            JitSpew(JitSpew_LICM, "  Skipping loop with header block%u due to OSR", header->id());

        UnmarkLoopBlocks(graph, header);

        if (mir->shouldCancel("LICM (main loop)"))
            return false;
    }

    return true;
}
Exemplo n.º 3
0
bool
ion::RenumberBlocks(MIRGraph &graph)
{
    size_t id = 0;
    for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++)
        block->setId(id++);

    return true;
}
Exemplo n.º 4
0
static void
ComputeImmediateDominators(MIRGraph &graph)
{
    // The default start block is a root and therefore only self-dominates.
    MBasicBlock *startBlock = *graph.begin();
    startBlock->setImmediateDominator(startBlock);

    // Any OSR block is a root and therefore only self-dominates.
    MBasicBlock *osrBlock = graph.osrBlock();
    if (osrBlock)
        osrBlock->setImmediateDominator(osrBlock);

    bool changed = true;

    while (changed) {
        changed = false;

        ReversePostorderIterator block = graph.rpoBegin();

        // For each block in RPO, intersect all dominators.
        for (; block != graph.rpoEnd(); block++) {
            // If a node has once been found to have no exclusive dominator,
            // it will never have an exclusive dominator, so it may be skipped.
            if (block->immediateDominator() == *block)
                continue;

            MBasicBlock *newIdom = block->getPredecessor(0);

            // Find the first common dominator.
            for (size_t i = 1; i < block->numPredecessors(); i++) {
                MBasicBlock *pred = block->getPredecessor(i);
                if (pred->immediateDominator() != NULL)
                    newIdom = IntersectDominators(pred, newIdom);

                // If there is no common dominator, the block self-dominates.
                if (newIdom == NULL) {
                    block->setImmediateDominator(*block);
                    changed = true;
                    break;
                }
            }

            if (newIdom && block->immediateDominator() != newIdom) {
                block->setImmediateDominator(newIdom);
                changed = true;
            }
        }
    }

#ifdef DEBUG
    // Assert that all blocks have dominator information.
    for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
        JS_ASSERT(block->immediateDominator() != NULL);
    }
#endif
}
Exemplo n.º 5
0
static void
AssertReversePostOrder(MIRGraph &graph)
{
    // Check that every block is visited after all its predecessors (except backedges).
    for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
        JS_ASSERT(!block->isMarked());

        for (size_t i = 0; i < block->numPredecessors(); i++) {
            MBasicBlock *pred = block->getPredecessor(i);
            JS_ASSERT_IF(!pred->isLoopBackedge(), pred->isMarked());
        }

        block->mark();
    }

    graph.unmarkBlocks();
}
Exemplo n.º 6
0
// Test whether any instruction in the loop possiblyCalls().
static bool
LoopContainsPossibleCall(MIRGraph &graph, MBasicBlock *header, MBasicBlock *backedge)
{
    for (auto i(graph.rpoBegin(header)); ; ++i) {
        MOZ_ASSERT(i != graph.rpoEnd(), "Reached end of graph searching for blocks in loop");
        MBasicBlock *block = *i;
        if (!block->isMarked())
            continue;

        for (auto insIter(block->begin()), insEnd(block->end()); insIter != insEnd; ++insIter) {
            MInstruction *ins = *insIter;
            if (ins->possiblyCalls()) {
                JitSpew(JitSpew_LICM, "    Possile call found at %s%u", ins->opName(), ins->id());
                return true;
            }
        }

        if (block == backedge)
            break;
    }
    return false;
}
Exemplo n.º 7
0
bool
jit::ReorderInstructions(MIRGraph& graph)
{
    // Renumber all instructions in the graph as we go.
    size_t nextId = 0;

    // List of the headers of any loops we are in.
    Vector<MBasicBlock*, 4, SystemAllocPolicy> loopHeaders;

    for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
        // Renumber all definitions inside the basic blocks.
        for (MPhiIterator iter(block->phisBegin()); iter != block->phisEnd(); iter++)
            iter->setId(nextId++);

        for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++)
            iter->setId(nextId++);

        // Don't reorder instructions within entry blocks, which have special requirements.
        if (*block == graph.entryBlock() || *block == graph.osrBlock())
            continue;

        if (block->isLoopHeader()) {
            if (!loopHeaders.append(*block))
                return false;
        }

        MBasicBlock* innerLoop = loopHeaders.empty() ? nullptr : loopHeaders.back();

        MInstruction* top = block->safeInsertTop();
        MInstructionReverseIterator rtop = ++block->rbegin(top);
        for (MInstructionIterator iter(block->begin(top)); iter != block->end(); ) {
            MInstruction* ins = *iter;

            // Filter out some instructions which are never reordered.
            if (ins->isEffectful() ||
                !ins->isMovable() ||
                ins->resumePoint() ||
                ins == block->lastIns())
            {
                iter++;
                continue;
            }

            // Move constants with a single use in the current block to the
            // start of the block. Constants won't be reordered by the logic
            // below, as they have no inputs. Moving them up as high as
            // possible can allow their use to be moved up further, though,
            // and has no cost if the constant is emitted at its use.
            if (ins->isConstant() &&
                ins->hasOneUse() &&
                ins->usesBegin()->consumer()->block() == *block &&
                !IsFloatingPointType(ins->type()))
            {
                iter++;
                MInstructionIterator targetIter = block->begin();
                while (targetIter->isConstant() || targetIter->isInterruptCheck()) {
                    if (*targetIter == ins)
                        break;
                    targetIter++;
                }
                MoveBefore(*block, *targetIter, ins);
                continue;
            }

            // Look for inputs where this instruction is the last use of that
            // input. If we move this instruction up, the input's lifetime will
            // be shortened, modulo resume point uses (which don't need to be
            // stored in a register, and can be handled by the register
            // allocator by just spilling at some point with no reload).
            Vector<MDefinition*, 4, SystemAllocPolicy> lastUsedInputs;
            for (size_t i = 0; i < ins->numOperands(); i++) {
                MDefinition* input = ins->getOperand(i);
                if (!input->isConstant() && IsLastUse(ins, input, innerLoop)) {
                    if (!lastUsedInputs.append(input))
                        return false;
                }
            }

            // Don't try to move instructions which aren't the last use of any
            // of their inputs (we really ought to move these down instead).
            if (lastUsedInputs.length() < 2) {
                iter++;
                continue;
            }

            MInstruction* target = ins;
            for (MInstructionReverseIterator riter = ++block->rbegin(ins); riter != rtop; riter++) {
                MInstruction* prev = *riter;
                if (prev->isInterruptCheck())
                    break;

                // The instruction can't be moved before any of its uses.
                bool isUse = false;
                for (size_t i = 0; i < ins->numOperands(); i++) {
                    if (ins->getOperand(i) == prev) {
                        isUse = true;
                        break;
                    }
                }
                if (isUse)
                    break;

                // The instruction can't be moved before an instruction that
                // stores to a location read by the instruction.
                if (prev->isEffectful() &&
                    (ins->getAliasSet().flags() & prev->getAliasSet().flags()) &&
                    ins->mightAlias(prev) != MDefinition::AliasType::NoAlias)
                {
                    break;
                }

                // Make sure the instruction will still be the last use of one
                // of its inputs when moved up this far.
                for (size_t i = 0; i < lastUsedInputs.length(); ) {
                    bool found = false;
                    for (size_t j = 0; j < prev->numOperands(); j++) {
                        if (prev->getOperand(j) == lastUsedInputs[i]) {
                            found = true;
                            break;
                        }
                    }
                    if (found) {
                        lastUsedInputs[i] = lastUsedInputs.back();
                        lastUsedInputs.popBack();
                    } else {
                        i++;
                    }
                }
                if (lastUsedInputs.length() < 2)
                    break;

                // We can move the instruction before this one.
                target = prev;
            }

            iter++;
            MoveBefore(*block, target, ins);
        }

        if (block->isLoopBackedge())
            loopHeaders.popBack();
    }

    return true;
}