// 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; }
Loop::LoopReturn Loop::init() { IonSpew(IonSpew_LICM, "Loop identified, headed by block %d", header_->id()); IonSpew(IonSpew_LICM, "footer is block %d", header_->backedge()->id()); // The first predecessor of the loop header must dominate the header. JS_ASSERT(header_->id() > header_->getPredecessor(0)->id()); // Loops from backedge to header and marks all visited blocks // as part of the loop. At the same time add all hoistable instructions // (in RPO order) to the instruction worklist. Vector<MBasicBlock *, 1, IonAllocPolicy> inlooplist; if (!inlooplist.append(header_->backedge())) return LoopReturn_Error; header_->backedge()->mark(); while (!inlooplist.empty()) { MBasicBlock *block = inlooplist.back(); // Hoisting requires more finesse if the loop contains a block that // self-dominates: there exists control flow that may enter the loop // without passing through the loop preheader. // // Rather than perform a complicated analysis of the dominance graph, // just return a soft error to ignore this loop. if (block->immediateDominator() == block) { while (!worklist_.empty()) popFromWorklist(); return LoopReturn_Skip; } // Add not yet visited predecessors to the inlooplist. if (block != header_) { for (size_t i = 0; i < block->numPredecessors(); i++) { MBasicBlock *pred = block->getPredecessor(i); if (pred->isMarked()) continue; if (!inlooplist.append(pred)) return LoopReturn_Error; pred->mark(); } } // If any block was added, process them first. if (block != inlooplist.back()) continue; // Add all instructions in this block (but the control instruction) to the worklist for (MInstructionIterator i = block->begin(); i != block->end(); i++) { MInstruction *ins = *i; // Remember whether this loop contains anything which clobbers most // or all floating-point registers. This is just a rough heuristic. if (ins->possiblyCalls()) containsPossibleCall_ = true; if (isHoistable(ins)) { if (!insertInWorklist(ins)) return LoopReturn_Error; } } // All successors of this block are visited. inlooplist.popBack(); } return LoopReturn_Success; }