LCOV - code coverage report
Current view: top level - js/src/jit - AliasAnalysis.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 106 135 78.5 %
Date: 2017-07-14 16:53:18 Functions: 10 11 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "jit/AliasAnalysis.h"
       8             : 
       9             : #include <stdio.h>
      10             : 
      11             : #include "jit/AliasAnalysisShared.h"
      12             : #include "jit/Ion.h"
      13             : #include "jit/IonBuilder.h"
      14             : #include "jit/JitSpewer.h"
      15             : #include "jit/MIR.h"
      16             : #include "jit/MIRGraph.h"
      17             : 
      18             : #include "vm/Printer.h"
      19             : 
      20             : using namespace js;
      21             : using namespace js::jit;
      22             : 
      23             : using mozilla::Array;
      24             : 
      25             : namespace js {
      26             : namespace jit {
      27             : 
      28             : class LoopAliasInfo : public TempObject
      29             : {
      30             :   private:
      31             :     LoopAliasInfo* outer_;
      32             :     MBasicBlock* loopHeader_;
      33             :     MInstructionVector invariantLoads_;
      34             : 
      35             :   public:
      36           7 :     LoopAliasInfo(TempAllocator& alloc, LoopAliasInfo* outer, MBasicBlock* loopHeader)
      37           7 :       : outer_(outer), loopHeader_(loopHeader), invariantLoads_(alloc)
      38           7 :     { }
      39             : 
      40          55 :     MBasicBlock* loopHeader() const {
      41          55 :         return loopHeader_;
      42             :     }
      43          14 :     LoopAliasInfo* outer() const {
      44          14 :         return outer_;
      45             :     }
      46          34 :     bool addInvariantLoad(MInstruction* ins) {
      47          34 :         return invariantLoads_.append(ins);
      48             :     }
      49           7 :     const MInstructionVector& invariantLoads() const {
      50           7 :         return invariantLoads_;
      51             :     }
      52         104 :     MInstruction* firstInstruction() const {
      53         104 :         return *loopHeader_->begin();
      54             :     }
      55             : };
      56             : 
      57             : } // namespace jit
      58             : } // namespace js
      59             : 
      60          10 : AliasAnalysis::AliasAnalysis(MIRGenerator* mir, MIRGraph& graph)
      61             :   : AliasAnalysisShared(mir, graph),
      62          10 :     loop_(nullptr)
      63             : {
      64          10 : }
      65             : 
      66             : // Whether there might be a path from src to dest, excluding loop backedges. This is
      67             : // approximate and really ought to depend on precomputed reachability information.
      68             : static inline bool
      69         542 : BlockMightReach(MBasicBlock* src, MBasicBlock* dest)
      70             : {
      71         809 :     while (src->id() <= dest->id()) {
      72         518 :         if (src == dest)
      73          16 :             return true;
      74         502 :         switch (src->numSuccessors()) {
      75             :           case 0:
      76         110 :             return false;
      77             :           case 1: {
      78         267 :             MBasicBlock* successor = src->getSuccessor(0);
      79         267 :             if (successor->id() <= src->id())
      80           0 :                 return true; // Don't iloop.
      81         267 :             src = successor;
      82         267 :             break;
      83             :           }
      84             :           default:
      85         125 :             return true;
      86             :         }
      87             :     }
      88          24 :     return false;
      89             : }
      90             : 
      91             : static void
      92         203 : IonSpewDependency(MInstruction* load, MInstruction* store, const char* verb, const char* reason)
      93             : {
      94         203 :     if (!JitSpewEnabled(JitSpew_Alias))
      95         203 :         return;
      96             : 
      97           0 :     Fprinter& out = JitSpewPrinter();
      98           0 :     out.printf("Load ");
      99           0 :     load->printName(out);
     100           0 :     out.printf(" %s on store ", verb);
     101           0 :     store->printName(out);
     102           0 :     out.printf(" (%s)\n", reason);
     103             : }
     104             : 
     105             : static void
     106           0 : IonSpewAliasInfo(const char* pre, MInstruction* ins, const char* post)
     107             : {
     108           0 :     if (!JitSpewEnabled(JitSpew_Alias))
     109           0 :         return;
     110             : 
     111           0 :     Fprinter& out = JitSpewPrinter();
     112           0 :     out.printf("%s ", pre);
     113           0 :     ins->printName(out);
     114           0 :     out.printf(" %s\n", post);
     115             : }
     116             : 
     117             : // This pass annotates every load instruction with the last store instruction
     118             : // on which it depends. The algorithm is optimistic in that it ignores explicit
     119             : // dependencies and only considers loads and stores.
     120             : //
     121             : // Loads inside loops only have an implicit dependency on a store before the
     122             : // loop header if no instruction inside the loop body aliases it. To calculate
     123             : // this efficiently, we maintain a list of maybe-invariant loads and the combined
     124             : // alias set for all stores inside the loop. When we see the loop's backedge, this
     125             : // information is used to mark every load we wrongly assumed to be loop invariant as
     126             : // having an implicit dependency on the last instruction of the loop header, so that
     127             : // it's never moved before the loop header.
     128             : //
     129             : // The algorithm depends on the invariant that both control instructions and effectful
     130             : // instructions (stores) are never hoisted.
     131             : bool
     132          10 : AliasAnalysis::analyze()
     133             : {
     134          20 :     Vector<MInstructionVector, AliasSet::NumCategories, JitAllocPolicy> stores(alloc());
     135             : 
     136             :     // Initialize to the first instruction.
     137          10 :     MInstruction* firstIns = *graph_.entryBlock()->begin();
     138         120 :     for (unsigned i = 0; i < AliasSet::NumCategories; i++) {
     139         220 :         MInstructionVector defs(alloc());
     140         110 :         if (!defs.append(firstIns))
     141           0 :             return false;
     142         110 :         if (!stores.append(Move(defs)))
     143           0 :             return false;
     144             :     }
     145             : 
     146             :     // Type analysis may have inserted new instructions. Since this pass depends
     147             :     // on the instruction number ordering, all instructions are renumbered.
     148          10 :     uint32_t newId = 0;
     149             : 
     150         736 :     for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
     151         726 :         if (mir->shouldCancel("Alias Analysis (main loop)"))
     152           0 :             return false;
     153             : 
     154         726 :         if (block->isLoopHeader()) {
     155           7 :             JitSpew(JitSpew_Alias, "Processing loop header %d", block->id());
     156           7 :             loop_ = new(alloc()) LoopAliasInfo(alloc(), loop_, *block);
     157             :         }
     158             : 
     159        1069 :         for (MPhiIterator def(block->phisBegin()), end(block->phisEnd()); def != end; ++def)
     160         343 :             def->setId(newId++);
     161             : 
     162        3425 :         for (MInstructionIterator def(block->begin()), end(block->begin(block->lastIns()));
     163             :              def != end;
     164             :              ++def)
     165             :         {
     166        2699 :             def->setId(newId++);
     167             : 
     168        2699 :             AliasSet set = def->getAliasSet();
     169        2699 :             if (set.isNone())
     170        4507 :                 continue;
     171             : 
     172             :             // For the purposes of alias analysis, all recoverable operations
     173             :             // are treated as effect free as the memory represented by these
     174             :             // operations cannot be aliased by others.
     175         493 :             if (def->canRecoverOnBailout())
     176          95 :                 continue;
     177             : 
     178         398 :             if (set.isStore()) {
     179        2358 :                 for (AliasSetIterator iter(set); iter; iter++) {
     180        2095 :                     if (!stores[*iter].append(*def))
     181           0 :                         return false;
     182             :                 }
     183             : 
     184         263 :                 if (JitSpewEnabled(JitSpew_Alias)) {
     185           0 :                     Fprinter& out = JitSpewPrinter();
     186           0 :                     out.printf("Processing store ");
     187           0 :                     def->printName(out);
     188           0 :                     out.printf(" (flags %x)\n", set.flags());
     189             :                 }
     190             :             } else {
     191             :                 // Find the most recent store on which this instruction depends.
     192         135 :                 MInstruction* lastStore = firstIns;
     193             : 
     194         276 :                 for (AliasSetIterator iter(set); iter; iter++) {
     195         141 :                     MInstructionVector& aliasedStores = stores[*iter];
     196         357 :                     for (int i = aliasedStores.length() - 1; i >= 0; i--) {
     197         357 :                         MInstruction* store = aliasedStores[i];
     198        1067 :                         if (genericMightAlias(*def, store) != MDefinition::AliasType::NoAlias &&
     199         632 :                             def->mightAlias(store) != MDefinition::AliasType::NoAlias &&
     200         275 :                             BlockMightReach(store->block(), *block))
     201             :                         {
     202         141 :                             if (lastStore->id() < store->id())
     203         135 :                                 lastStore = store;
     204         141 :                             break;
     205             :                         }
     206             :                     }
     207             :                 }
     208             : 
     209         135 :                 def->setDependency(lastStore);
     210         135 :                 IonSpewDependency(*def, lastStore, "depends", "");
     211             : 
     212             :                 // If the last store was before the current loop, we assume this load
     213             :                 // is loop invariant. If a later instruction writes to the same location,
     214             :                 // we will fix this at the end of the loop.
     215         135 :                 if (loop_ && lastStore->id() < loop_->firstInstruction()->id()) {
     216          34 :                     if (!loop_->addInvariantLoad(*def))
     217           0 :                         return false;
     218             :                 }
     219             :             }
     220             :         }
     221             : 
     222             :         // Renumber the last instruction, as the analysis depends on this and the order.
     223         726 :         block->lastIns()->setId(newId++);
     224             : 
     225         726 :         if (block->isLoopBackedge()) {
     226           7 :             MOZ_ASSERT(loop_->loopHeader() == block->loopHeaderOfBackedge());
     227           7 :             JitSpew(JitSpew_Alias, "Processing loop backedge %d (header %d)", block->id(),
     228          14 :                     loop_->loopHeader()->id());
     229           7 :             LoopAliasInfo* outerLoop = loop_->outer();
     230           7 :             MInstruction* firstLoopIns = *loop_->loopHeader()->begin();
     231             : 
     232           7 :             const MInstructionVector& invariant = loop_->invariantLoads();
     233             : 
     234          41 :             for (unsigned i = 0; i < invariant.length(); i++) {
     235          34 :                 MInstruction* ins = invariant[i];
     236          34 :                 AliasSet set = ins->getAliasSet();
     237          34 :                 MOZ_ASSERT(set.isLoad());
     238             : 
     239          34 :                 bool hasAlias = false;
     240          34 :                 for (AliasSetIterator iter(set); iter; iter++) {
     241          34 :                     MInstructionVector& aliasedStores = stores[*iter];
     242          56 :                     for (int i = aliasedStores.length() - 1;; i--) {
     243          56 :                         MInstruction* store = aliasedStores[i];
     244          56 :                         if (store->id() < firstLoopIns->id())
     245           0 :                             break;
     246         112 :                         if (genericMightAlias(ins, store) != MDefinition::AliasType::NoAlias &&
     247          56 :                             ins->mightAlias(store) != MDefinition::AliasType::NoAlias)
     248             :                         {
     249          34 :                             hasAlias = true;
     250          34 :                             IonSpewDependency(ins, store, "aliases", "store in loop body");
     251          34 :                             break;
     252             :                         }
     253          22 :                     }
     254          34 :                     if (hasAlias)
     255          34 :                         break;
     256             :                 }
     257             : 
     258          34 :                 if (hasAlias) {
     259             :                     // This instruction depends on stores inside the loop body. Mark it as having a
     260             :                     // dependency on the last instruction of the loop header. The last instruction is a
     261             :                     // control instruction and these are never hoisted.
     262          34 :                     MControlInstruction* controlIns = loop_->loopHeader()->lastIns();
     263          34 :                     IonSpewDependency(ins, controlIns, "depends", "due to stores in loop body");
     264          34 :                     ins->setDependency(controlIns);
     265             :                 } else {
     266           0 :                     IonSpewAliasInfo("Load", ins, "does not depend on any stores in this loop");
     267             : 
     268           0 :                     if (outerLoop && ins->dependency()->id() < outerLoop->firstInstruction()->id()) {
     269           0 :                         IonSpewAliasInfo("Load", ins, "may be invariant in outer loop");
     270           0 :                         if (!outerLoop->addInvariantLoad(ins))
     271           0 :                             return false;
     272             :                     }
     273             :                 }
     274             :             }
     275           7 :             loop_ = loop_->outer();
     276             :         }
     277             :     }
     278             : 
     279          10 :     spewDependencyList();
     280             : 
     281          10 :     MOZ_ASSERT(loop_ == nullptr);
     282          10 :     return true;
     283             : }

Generated by: LCOV version 1.13