js/src/jit/LICM.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jit/LICM.h"
     9 #include <stdio.h>
    11 #include "jit/IonSpewer.h"
    12 #include "jit/MIR.h"
    13 #include "jit/MIRGenerator.h"
    14 #include "jit/MIRGraph.h"
    16 using namespace js;
    17 using namespace js::jit;
    19 namespace {
    21 typedef Vector<MInstruction*, 1, IonAllocPolicy> InstructionQueue;
    23 class Loop
    24 {
    25     MIRGenerator *mir;
    27   public:
    28     // Loop code may return three values:
    29     enum LoopReturn {
    30         LoopReturn_Success,
    31         LoopReturn_Error, // Compilation failure.
    32         LoopReturn_Skip   // The loop is not suitable for LICM, but there is no error.
    33     };
    35   public:
    36     // A loop is constructed on a backedge found in the control flow graph.
    37     Loop(MIRGenerator *mir, MBasicBlock *footer);
    39     // Initializes the loop, finds all blocks and instructions contained in the loop.
    40     LoopReturn init();
    42     // Identifies hoistable loop invariant instructions and moves them out of the loop.
    43     bool optimize();
    45   private:
    46     // These blocks define the loop.  header_ points to the loop header
    47     MBasicBlock *header_;
    49     // The pre-loop block is the first predecessor of the loop header.  It is where
    50     // the loop is first entered and where hoisted instructions will be placed.
    51     MBasicBlock* preLoop_;
    53     // This indicates whether the loop contains calls or other things which
    54     // clobber most or all floating-point registers. In such loops,
    55     // floating-point constants should not be hoisted unless it enables further
    56     // hoisting.
    57     bool containsPossibleCall_;
    59     TempAllocator &alloc() const {
    60         return mir->alloc();
    61     }
    63     bool hoistInstructions(InstructionQueue &toHoist);
    65     // Utility methods for invariance testing and instruction hoisting.
    66     bool isInLoop(MDefinition *ins);
    67     bool isBeforeLoop(MDefinition *ins);
    68     bool isLoopInvariant(MInstruction *ins);
    70     // This method determines if this block hot within a loop.  That is, if it's
    71     // always or usually run when the loop executes
    72     bool checkHotness(MBasicBlock *block);
    74     // Worklist and worklist usage methods
    75     InstructionQueue worklist_;
    76     bool insertInWorklist(MInstruction *ins);
    77     MInstruction* popFromWorklist();
    79     inline bool isHoistable(const MDefinition *ins) const {
    80         return ins->isMovable() && !ins->isEffectful() && !ins->neverHoist();
    81     }
    83     bool requiresHoistedUse(const MDefinition *ins) const;
    84 };
    86 } /* namespace anonymous */
    88 LICM::LICM(MIRGenerator *mir, MIRGraph &graph)
    89   : mir(mir), graph(graph)
    90 {
    91 }
    93 bool
    94 LICM::analyze()
    95 {
    96     IonSpew(IonSpew_LICM, "Beginning LICM pass.");
    98     // Iterate in RPO to visit outer loops before inner loops.
    99     for (ReversePostorderIterator i(graph.rpoBegin()); i != graph.rpoEnd(); i++) {
   100         MBasicBlock *header = *i;
   102         // Skip non-headers and self-loops.
   103         if (!header->isLoopHeader() || header->numPredecessors() < 2)
   104             continue;
   106         // Attempt to optimize loop.
   107         Loop loop(mir, header);
   109         Loop::LoopReturn lr = loop.init();
   110         if (lr == Loop::LoopReturn_Error)
   111             return false;
   112         if (lr == Loop::LoopReturn_Skip) {
   113             graph.unmarkBlocks();
   114             continue;
   115         }
   117         if (!loop.optimize())
   118             return false;
   120         graph.unmarkBlocks();
   121     }
   123     return true;
   124 }
   126 Loop::Loop(MIRGenerator *mir, MBasicBlock *header)
   127   : mir(mir),
   128     header_(header),
   129     containsPossibleCall_(false),
   130     worklist_(mir->alloc())
   131 {
   132     preLoop_ = header_->getPredecessor(0);
   133 }
   135 Loop::LoopReturn
   136 Loop::init()
   137 {
   138     IonSpew(IonSpew_LICM, "Loop identified, headed by block %d", header_->id());
   139     IonSpew(IonSpew_LICM, "footer is block %d", header_->backedge()->id());
   141     // The first predecessor of the loop header must dominate the header.
   142     JS_ASSERT(header_->id() > header_->getPredecessor(0)->id());
   144     // Loops from backedge to header and marks all visited blocks
   145     // as part of the loop. At the same time add all hoistable instructions
   146     // (in RPO order) to the instruction worklist.
   147     Vector<MBasicBlock *, 1, IonAllocPolicy> inlooplist(alloc());
   148     if (!inlooplist.append(header_->backedge()))
   149         return LoopReturn_Error;
   150     header_->backedge()->mark();
   152     while (!inlooplist.empty()) {
   153         MBasicBlock *block = inlooplist.back();
   155         // Hoisting requires more finesse if the loop contains a block that
   156         // self-dominates: there exists control flow that may enter the loop
   157         // without passing through the loop preheader.
   158         //
   159         // Rather than perform a complicated analysis of the dominance graph,
   160         // just return a soft error to ignore this loop.
   161         if (block->immediateDominator() == block) {
   162             while (!worklist_.empty())
   163                 popFromWorklist();
   164             return LoopReturn_Skip;
   165         }
   167         // Add not yet visited predecessors to the inlooplist.
   168         if (block != header_) {
   169             for (size_t i = 0; i < block->numPredecessors(); i++) {
   170                 MBasicBlock *pred = block->getPredecessor(i);
   171                 if (pred->isMarked())
   172                     continue;
   174                 if (!inlooplist.append(pred))
   175                     return LoopReturn_Error;
   176                 pred->mark();
   177             }
   178         }
   180         // If any block was added, process them first.
   181         if (block != inlooplist.back())
   182             continue;
   184         // Add all instructions in this block (but the control instruction) to the worklist
   185         for (MInstructionIterator i = block->begin(); i != block->end(); i++) {
   186             MInstruction *ins = *i;
   188             // Remember whether this loop contains anything which clobbers most
   189             // or all floating-point registers. This is just a rough heuristic.
   190             if (ins->possiblyCalls())
   191                 containsPossibleCall_ = true;
   193             if (isHoistable(ins)) {
   194                 if (!insertInWorklist(ins))
   195                     return LoopReturn_Error;
   196             }
   197         }
   199         // All successors of this block are visited.
   200         inlooplist.popBack();
   201     }
   203     return LoopReturn_Success;
   204 }
   206 bool
   207 Loop::optimize()
   208 {
   209     InstructionQueue invariantInstructions(alloc());
   211     IonSpew(IonSpew_LICM, "These instructions are in the loop: ");
   213     while (!worklist_.empty()) {
   214         if (mir->shouldCancel("LICM (worklist)"))
   215             return false;
   217         MInstruction *ins = popFromWorklist();
   219         IonSpewHeader(IonSpew_LICM);
   221         if (IonSpewEnabled(IonSpew_LICM)) {
   222             ins->printName(IonSpewFile);
   223             fprintf(IonSpewFile, " <- ");
   224             ins->printOpcode(IonSpewFile);
   225             fprintf(IonSpewFile, ":  ");
   226         }
   228         if (isLoopInvariant(ins)) {
   229             // Flag this instruction as loop invariant.
   230             ins->setLoopInvariant();
   231             if (!invariantInstructions.append(ins))
   232                 return false;
   234             if (IonSpewEnabled(IonSpew_LICM))
   235                 fprintf(IonSpewFile, " Loop Invariant!\n");
   236         }
   237     }
   239     if (!hoistInstructions(invariantInstructions))
   240         return false;
   241     return true;
   242 }
   244 bool
   245 Loop::requiresHoistedUse(const MDefinition *ins) const
   246 {
   247     if (ins->isConstantElements() || ins->isBox())
   248         return true;
   250     // Integer constants can often be folded as immediates and aren't worth
   251     // hoisting on their own, in general. Floating-point constants typically
   252     // are worth hoisting, unless they'll end up being spilled (eg. due to a
   253     // call).
   254     if (ins->isConstant() && (IsFloatingPointType(ins->type()) || containsPossibleCall_))
   255         return true;
   257     return false;
   258 }
   260 bool
   261 Loop::hoistInstructions(InstructionQueue &toHoist)
   262 {
   263     // Iterate in post-order (uses before definitions)
   264     for (int32_t i = toHoist.length() - 1; i >= 0; i--) {
   265         MInstruction *ins = toHoist[i];
   267         // Don't hoist a cheap constant if it doesn't enable us to hoist one of
   268         // its uses. We want those instructions as close as possible to their
   269         // use, to facilitate folding and minimize register pressure.
   270         if (requiresHoistedUse(ins)) {
   271             bool loopInvariantUse = false;
   272             for (MUseDefIterator use(ins); use; use++) {
   273                 if (use.def()->isLoopInvariant()) {
   274                     loopInvariantUse = true;
   275                     break;
   276                 }
   277             }
   279             if (!loopInvariantUse)
   280                 ins->setNotLoopInvariant();
   281         }
   282     }
   284     // Move all instructions to the preLoop_ block just before the control instruction.
   285     for (size_t i = 0; i < toHoist.length(); i++) {
   286         MInstruction *ins = toHoist[i];
   288         // Loads may have an implicit dependency on either stores (effectful instructions) or
   289         // control instructions so we should never move these.
   290         JS_ASSERT(!ins->isControlInstruction());
   291         JS_ASSERT(!ins->isEffectful());
   292         JS_ASSERT(ins->isMovable());
   294         if (!ins->isLoopInvariant())
   295             continue;
   297         if (checkHotness(ins->block())) {
   298             ins->block()->moveBefore(preLoop_->lastIns(), ins);
   299             ins->setNotLoopInvariant();
   300         }
   301     }
   303     return true;
   304 }
   306 bool
   307 Loop::isInLoop(MDefinition *ins)
   308 {
   309     return ins->block()->isMarked();
   310 }
   312 bool
   313 Loop::isBeforeLoop(MDefinition *ins)
   314 {
   315     return ins->block()->id() < header_->id();
   316 }
   318 bool
   319 Loop::isLoopInvariant(MInstruction *ins)
   320 {
   321     if (!isHoistable(ins)) {
   322         if (IonSpewEnabled(IonSpew_LICM))
   323             fprintf(IonSpewFile, "not hoistable\n");
   324         return false;
   325     }
   327     // Don't hoist if this instruction depends on a store inside or after the loop.
   328     // Note: "after the loop" can sound strange, but Alias Analysis doesn't look
   329     // at the control flow. Therefore it doesn't match the definition here, that a block
   330     // is in the loop when there is a (directed) path from the block to the loop header.
   331     if (ins->dependency() && !isBeforeLoop(ins->dependency())) {
   332         if (IonSpewEnabled(IonSpew_LICM)) {
   333             fprintf(IonSpewFile, "depends on store inside or after loop: ");
   334             ins->dependency()->printName(IonSpewFile);
   335             fprintf(IonSpewFile, "\n");
   336         }
   337         return false;
   338     }
   340     // An instruction is only loop invariant if it and all of its operands can
   341     // be safely hoisted into the loop preheader.
   342     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
   343         if (isInLoop(ins->getOperand(i)) &&
   344             !ins->getOperand(i)->isLoopInvariant()) {
   346             if (IonSpewEnabled(IonSpew_LICM)) {
   347                 ins->getOperand(i)->printName(IonSpewFile);
   348                 fprintf(IonSpewFile, " is in the loop.\n");
   349             }
   351             return false;
   352         }
   353     }
   355     return true;
   356 }
   358 bool
   359 Loop::checkHotness(MBasicBlock *block)
   360 {
   361     // TODO: determine if instructions within this block are worth hoisting.
   362     // They might not be if the block is cold enough within the loop.
   363     // BUG 669517
   364     return true;
   365 }
   367 bool
   368 Loop::insertInWorklist(MInstruction *ins)
   369 {
   370     if (!worklist_.insert(worklist_.begin(), ins))
   371         return false;
   372     ins->setInWorklist();
   373     return true;
   374 }
   376 MInstruction*
   377 Loop::popFromWorklist()
   378 {
   379     MInstruction* toReturn = worklist_.popCopy();
   380     toReturn->setNotInWorklist();
   381     return toReturn;
   382 }

mercurial