LCOV - code coverage report
Current view: top level - js/src/jit - FlowAliasAnalysis.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 482 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 43 0.0 %
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/FlowAliasAnalysis.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 LoopInfo : public TempObject
      29             : {
      30             :   private:
      31             :     LoopInfo* outer_;
      32             :     MBasicBlock* loopHeader_;
      33             :     MDefinitionVector loopinvariant_;
      34             : 
      35             :   public:
      36           0 :     LoopInfo(TempAllocator& alloc, LoopInfo* outer, MBasicBlock* loopHeader)
      37           0 :       : outer_(outer), loopHeader_(loopHeader), loopinvariant_(alloc)
      38           0 :     { }
      39             : 
      40           0 :     MBasicBlock* loopHeader() const {
      41           0 :         return loopHeader_;
      42             :     }
      43           0 :     LoopInfo* outer() const {
      44           0 :         return outer_;
      45             :     }
      46           0 :     MDefinitionVector& loopinvariant() {
      47           0 :         return loopinvariant_;
      48             :     }
      49             : };
      50             : 
      51             : static bool
      52           0 : KeepBlock(MBasicBlock *block)
      53             : {
      54             :     // Any block that is predecessor to a loopheader need to be kept.
      55             :     // We need it to process possible loop invariant loads.
      56           0 :     if (block->numSuccessors() == 1 && block->getSuccessor(0)->isLoopHeader())
      57           0 :         return true;
      58             : 
      59             : #ifdef DEBUG
      60             :     // We assume a predecessor to a loopheader has one successor.
      61           0 :     for (size_t i = 0; i < block->numSuccessors(); i++)
      62           0 :         MOZ_ASSERT(!block->getSuccessor(i)->isLoopHeader());
      63             : #endif
      64             : 
      65           0 :     return false;
      66             : }
      67             : 
      68             : class GraphStoreInfo : public TempObject
      69             : {
      70             :     // The current BlockStoreInfo while iterating the block untill,
      71             :     // it contains the store info at the end of the block.
      72             :     BlockStoreInfo* current_;
      73             : 
      74             :     // Vector with pointer to BlockStoreInfo at the end of the block for every block.
      75             :     // Only keeping the info during iteration if needed, else contains nullptr.
      76             :     GraphStoreVector stores_;
      77             : 
      78             :     // All BlockStoreInfo's that aren't needed anymore and can be reused.
      79             :     GraphStoreVector empty_;
      80             : 
      81             :   public:
      82           0 :     explicit GraphStoreInfo(TempAllocator& alloc)
      83           0 :       : current_(nullptr),
      84             :         stores_(alloc),
      85           0 :         empty_(alloc)
      86           0 :     { }
      87             : 
      88           0 :     bool reserve(size_t num) {
      89           0 :         return stores_.appendN(nullptr, num);
      90             :     }
      91             : 
      92           0 :     BlockStoreInfo& current() {
      93           0 :         return *current_;
      94             :     }
      95             : 
      96           0 :     void unsetCurrent() {
      97           0 :         current_ = nullptr;
      98           0 :     }
      99             : 
     100           0 :     BlockStoreInfo* newCurrent(TempAllocator& alloc, MBasicBlock* block) {
     101           0 :         BlockStoreInfo *info = nullptr;
     102           0 :         if (empty_.length() != 0) {
     103           0 :             info = empty_.popCopy();
     104             :         } else {
     105           0 :             info = (BlockStoreInfo*) alloc.allocate(sizeof(BlockStoreInfo));
     106           0 :             if (!info)
     107           0 :                 return nullptr;
     108           0 :             new(info) BlockStoreInfo(alloc);
     109             :         }
     110             : 
     111           0 :         stores_[block->id()] = info;
     112           0 :         current_ = info;
     113           0 :         return current_;
     114             :     }
     115             : 
     116           0 :     void swap(MBasicBlock* block1, MBasicBlock* block2) {
     117           0 :         BlockStoreInfo* info = stores_[block1->id()];
     118           0 :         stores_[block1->id()] = stores_[block2->id()];
     119           0 :         stores_[block2->id()] = info;
     120           0 :         if (stores_[block1->id()] == current_)
     121           0 :             current_ = stores_[block2->id()];
     122           0 :         else if (stores_[block2->id()] == current_)
     123           0 :             current_ = stores_[block1->id()];
     124           0 :     }
     125             : 
     126           0 :     bool maybeFreePredecessorBlocks(MBasicBlock* block) {
     127           0 :         for (size_t i=0; i < block->numPredecessors(); i++) {
     128             : 
     129             :             // For some blocks we cannot free the store info.
     130           0 :             if (KeepBlock(block->getPredecessor(i)))
     131           0 :                 continue;
     132             : 
     133             :             // Check the given block is the last successor.
     134           0 :             bool release = true;
     135           0 :             for (size_t j = 0; j < block->getPredecessor(i)->numSuccessors(); j++) {
     136           0 :                 if (block->getPredecessor(i)->getSuccessor(j)->id() > block->id()) {
     137           0 :                     release = false;
     138           0 :                     break;
     139             :                 }
     140             :             }
     141           0 :             if (release) {
     142           0 :                 BlockStoreInfo *info = stores_[block->getPredecessor(i)->id()];
     143           0 :                 if (!empty_.append(info))
     144           0 :                     return false;
     145           0 :                 info->clear();
     146             : 
     147           0 :                 stores_[block->getPredecessor(i)->id()] = nullptr;
     148             :             }
     149             :         }
     150           0 :         return true;
     151             :     }
     152             : 
     153           0 :     BlockStoreInfo& get(MBasicBlock* block) {
     154           0 :         MOZ_ASSERT(stores_[block->id()] != current_);
     155           0 :         return *stores_[block->id()];
     156             :     }
     157             : };
     158             : 
     159             : } // namespace jit
     160             : } // namespace js
     161             : 
     162             : 
     163           0 : FlowAliasAnalysis::FlowAliasAnalysis(MIRGenerator* mir, MIRGraph& graph)
     164             :   : AliasAnalysisShared(mir, graph),
     165             :     loop_(nullptr),
     166           0 :     output_(graph_.alloc()),
     167           0 :     worklist_(graph_.alloc())
     168             : {
     169           0 :     stores_ = new(graph_.alloc()) GraphStoreInfo(graph_.alloc());
     170           0 : }
     171             : 
     172             : template <typename T>
     173             : static bool
     174           0 : AppendToWorklist(MDefinitionVector& worklist, T& stores)
     175             : {
     176           0 :     if (!worklist.reserve(worklist.length() + stores.length()))
     177           0 :         return false;
     178             : 
     179           0 :     for (size_t j = 0; j < stores.length(); j++) {
     180           0 :         MOZ_ASSERT(stores[j]);
     181           0 :         if (stores[j]->isInWorklist())
     182           0 :             continue;
     183             : 
     184           0 :         worklist.infallibleAppend(stores[j]);
     185           0 :         stores[j]->setInWorklist();
     186             :     }
     187           0 :     return true;
     188             : }
     189             : 
     190             : static void
     191           0 : SetNotInWorkList(MDefinitionVector& worklist)
     192             : {
     193           0 :     for (size_t item = 0; item < worklist.length(); item++)
     194           0 :         worklist[item]->setNotInWorklistUnchecked();
     195           0 : }
     196             : 
     197             : static bool
     198           0 : LoadAliasesStore(MDefinition* load, MDefinition* store)
     199             : {
     200             :     // Always alias first instruction of graph.
     201           0 :     if (store->id() == 0)
     202           0 :         return true;
     203             : 
     204             :     // Default to alias control instructions which indicates loops.
     205             :     // Control instructions are special, since we need to determine
     206             :     // if it aliases anything in the full loop. Which we do lateron.
     207           0 :     if (store->isControlInstruction())
     208           0 :         return true;
     209             : 
     210             :     // Check if the alias categories alias eachother.
     211           0 :     if ((load->getAliasSet() & store->getAliasSet()).isNone())
     212           0 :         return false;
     213             : 
     214             :     // On any operation that has a specific alias category we can use TI to know
     215             :     // the objects operating on don't intersect.
     216           0 :     MDefinition::AliasType mightAlias = AliasAnalysisShared::genericMightAlias(load, store);
     217           0 :     if (mightAlias == MDefinition::AliasType::NoAlias)
     218           0 :         return false;
     219             : 
     220             :     // Check if the instruction might alias eachother.
     221           0 :     mightAlias = load->mightAlias(store);
     222           0 :     if (mightAlias == MDefinition::AliasType::NoAlias)
     223           0 :         return false;
     224             : 
     225           0 :     return true;
     226             : }
     227             : 
     228             : #ifdef JS_JITSPEW
     229             : static void
     230           0 : DumpAliasSet(AliasSet set)
     231             : {
     232           0 :     Fprinter &print = JitSpewPrinter();
     233             : 
     234           0 :     if (set.flags() == AliasSet::Any) {
     235           0 :         print.printf("Any");
     236           0 :         return;
     237             :     }
     238             : 
     239           0 :     bool first = true;
     240           0 :     for (AliasSetIterator iter(set); iter; iter++) {
     241           0 :         if (!first)
     242           0 :             print.printf(", ");
     243           0 :         print.printf("%s", AliasSet::Name(*iter));
     244           0 :         first = false;
     245             :     }
     246             : }
     247             : #endif
     248             : 
     249             : #ifdef JS_JITSPEW
     250             : static void
     251           0 : DumpStoreList(BlockStoreInfo& stores)
     252             : {
     253           0 :     Fprinter &print = JitSpewPrinter();
     254           0 :     if (stores.length() == 0) {
     255           0 :         print.printf("empty");
     256           0 :         return;
     257             :     }
     258           0 :     bool first = true;
     259           0 :     for (size_t i = 0; i < stores.length(); i++) {
     260           0 :         if (!first)
     261           0 :             print.printf(", ");
     262           0 :         if (!stores[i]) {
     263           0 :             print.printf("nullptr");
     264           0 :             continue;
     265             :         }
     266           0 :         MOZ_ASSERT(stores[i]->isControlInstruction() ||
     267             :                    stores[i]->getAliasSet().isStore() ||
     268             :                    stores[i]->id() == 0);
     269           0 :         MDefinition::PrintOpcodeName(print, stores[i]->op());
     270           0 :         print.printf("%d", stores[i]->id());
     271           0 :         first = false;
     272             :     }
     273             : }
     274             : #endif
     275             : 
     276             : static void
     277           0 : DumpAnalyzeStart()
     278             : {
     279             : #ifdef JS_JITSPEW
     280           0 :     if (JitSpewEnabled(JitSpew_Alias) || JitSpewEnabled(JitSpew_AliasSummaries)) {
     281           0 :         Fprinter &print = JitSpewPrinter();
     282           0 :         JitSpewHeader(JitSpewEnabled(JitSpew_Alias) ? JitSpew_Alias : JitSpew_AliasSummaries);
     283           0 :         print.printf("Running Alias Analysis on graph\n");
     284             :     }
     285             : #endif
     286           0 : }
     287             : 
     288             : static void
     289           0 : DumpBlockStart(MBasicBlock* block)
     290             : {
     291             : #ifdef JS_JITSPEW
     292           0 :     if (JitSpewEnabled(JitSpew_Alias) || JitSpewEnabled(JitSpew_AliasSummaries)) {
     293           0 :         Fprinter &print = JitSpewPrinter();
     294           0 :         JitSpewHeader(JitSpewEnabled(JitSpew_Alias)?JitSpew_Alias:JitSpew_AliasSummaries);
     295           0 :         if (block->isLoopHeader())
     296           0 :             print.printf(" Visiting block %d (loopheader)\n", block->id());
     297             :         else
     298           0 :             print.printf(" Visiting block %d\n", block->id());
     299             :     }
     300             : #endif
     301           0 : }
     302             : 
     303             : static void
     304           0 : DumpProcessingDeferredLoads(MBasicBlock* loopHeader)
     305             : {
     306             : #ifdef JS_JITSPEW
     307           0 :     if (JitSpewEnabled(JitSpew_Alias)) {
     308           0 :         Fprinter &print = JitSpewPrinter();
     309           0 :         JitSpewHeader(JitSpew_Alias);
     310           0 :         print.printf(" Process deferred loads of loop %d\n", loopHeader->id());
     311             :     }
     312             : #endif
     313           0 : }
     314             : 
     315             : static void
     316           0 : DumpBlockSummary(MBasicBlock* block, BlockStoreInfo& blockInfo)
     317             : {
     318             : #ifdef JS_JITSPEW
     319           0 :     if (JitSpewEnabled(JitSpew_AliasSummaries)) {
     320           0 :         Fprinter &print = JitSpewPrinter();
     321           0 :         JitSpewHeader(JitSpew_AliasSummaries);
     322           0 :         print.printf("  Store at end of block: ");
     323           0 :         DumpStoreList(blockInfo);
     324           0 :         print.printf("\n");
     325             :     }
     326             : #endif
     327           0 : }
     328             : 
     329             : static void
     330           0 : DumpStore(MDefinition* store)
     331             : {
     332             : #ifdef JS_JITSPEW
     333           0 :     if (JitSpewEnabled(JitSpew_Alias)) {
     334           0 :         Fprinter &print = JitSpewPrinter();
     335           0 :         JitSpewHeader(JitSpew_Alias);
     336           0 :         print.printf("  Store ");
     337           0 :         store->PrintOpcodeName(print, store->op());
     338           0 :         print.printf("%d with flags (", store->id());
     339           0 :         DumpAliasSet(store->getAliasSet());
     340           0 :         print.printf(")\n");
     341             :     }
     342             : #endif
     343           0 : }
     344             : 
     345             : static void
     346           0 : DumpLoad(MDefinition* load)
     347             : {
     348             : #ifdef JS_JITSPEW
     349           0 :     if (JitSpewEnabled(JitSpew_Alias)) {
     350           0 :         Fprinter &print = JitSpewPrinter();
     351           0 :         JitSpewHeader(JitSpew_Alias);
     352           0 :         print.printf("  Load ");
     353           0 :         load->PrintOpcodeName(print, load->op());
     354           0 :         print.printf("%d", load->id());
     355           0 :         print.printf(" with flag (");
     356           0 :         DumpAliasSet(load->getAliasSet());
     357           0 :         print.printf(")\n");
     358             :     }
     359             : #endif
     360           0 : }
     361             : 
     362             : static void
     363           0 : DumpLoadOutcome(MDefinition* load, MDefinitionVector& stores, bool defer)
     364             : {
     365             : #ifdef JS_JITSPEW
     366             :     // Spew what we did.
     367           0 :     if (JitSpewEnabled(JitSpew_Alias)) {
     368           0 :         Fprinter &print = JitSpewPrinter();
     369           0 :         JitSpewHeader(JitSpew_Alias);
     370           0 :         print.printf("   Marked depending on ");
     371           0 :         DumpStoreList(stores);
     372           0 :         if (defer)
     373           0 :             print.printf(" deferred");
     374           0 :         print.printf("\n");
     375             :     }
     376             : #endif
     377           0 : }
     378             : 
     379             : static void
     380           0 : DumpLoopInvariant(MDefinition* load, MBasicBlock* loopheader, bool loopinvariant,
     381             :                   MDefinitionVector& loopInvariantDependency)
     382             : {
     383             : #ifdef JS_JITSPEW
     384           0 :     if (JitSpewEnabled(JitSpew_Alias)) {
     385           0 :         Fprinter &print = JitSpewPrinter();
     386           0 :         JitSpewHeader(JitSpew_Alias);
     387           0 :         if (!loopinvariant) {
     388           0 :             print.printf("   Determine not loop invariant to loop %d.\n", loopheader->id());
     389             :         } else {
     390           0 :             print.printf("   Determine loop invariant to loop %d. Dependendy is now: ", loopheader->id());
     391           0 :             DumpStoreList(loopInvariantDependency);
     392           0 :             print.printf("\n");
     393             :         }
     394             :     }
     395             : #endif
     396           0 : }
     397             : 
     398             : static void
     399           0 : DumpImprovement(MDefinition *load, MDefinitionVector& input, MDefinitionVector& output)
     400             : {
     401             : #ifdef JS_JITSPEW
     402           0 :     if (JitSpewEnabled(JitSpew_Alias)) {
     403           0 :         Fprinter &print = JitSpewPrinter();
     404           0 :         JitSpewHeader(JitSpew_Alias);
     405           0 :         print.printf("   Improve dependency from %d", load->id());
     406           0 :         DumpStoreList(input);
     407           0 :         print.printf(" to ");
     408           0 :         DumpStoreList(output);
     409           0 :         print.printf("\n");
     410             :     }
     411             : #endif
     412           0 : }
     413             : 
     414             : // Flow Sensitive Alias Analysis.
     415             : //
     416             : // This pass annotates every load instructions with the last store instruction
     417             : // on which it depends in their dependency_ field. For loop variant instructions
     418             : // this will depend on the control instruction in the specific loop it cannot
     419             : // get hoisted out (if there is no store between start loopheader and
     420             : // instruction).
     421             : //
     422             : // We visit the graph in RPO and keep track of the last stores in that block.
     423             : // Upon entering a block we merge the stores information of the predecessors.
     424             : // Only loopheaders are different, since we eagerly make it depend on the
     425             : // control instruction of the loopheader.
     426             : //
     427             : // During the iteration of a block we keep a running store dependeny list.
     428             : // At the end of the iteration, this will contain the last stores
     429             : // (which we keep for successors).
     430             : //
     431             : // When encountering a store or load we do:
     432             : // - Store: we update the current block store info and put a StoreDependency
     433             : //          to create a store-chain.
     434             : //
     435             : // - Load: we take the current block store dependency info and improve that by
     436             : //         following the store-chain when encountering not aliasing store. Upon
     437             : //         encountering a control instruction (indicates loop) it solely depends on
     438             : //         we defer until the loop has been examined.
     439             : //
     440             : // The algorithm depends on the invariant that both control instructions and effectful
     441             : // instructions (stores) are never hoisted.
     442             : 
     443             : bool
     444           0 : FlowAliasAnalysis::analyze()
     445             : {
     446           0 :     DumpAnalyzeStart();
     447             : 
     448             :     // Type analysis may have inserted new instructions. Since this pass depends
     449             :     // on the instruction number ordering, all instructions are renumbered.
     450           0 :     uint32_t newId = 0;
     451             : 
     452           0 :     if (!stores_->reserve(graph_.numBlocks()))
     453           0 :         return false;
     454             : 
     455           0 :     for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
     456           0 :         if (mir->shouldCancel("Alias Analysis (main loop)"))
     457           0 :             return false;
     458             : 
     459           0 :         DumpBlockStart(*block);
     460             : 
     461           0 :         if (!computeBlockStores(*block))
     462           0 :             return false;
     463           0 :         if (!stores_->maybeFreePredecessorBlocks(*block))
     464           0 :             return false;
     465             : 
     466           0 :         for (MPhiIterator def(block->phisBegin()), end(block->phisEnd()); def != end; ++def)
     467           0 :             def->setId(newId++);
     468             : 
     469           0 :         BlockStoreInfo& blockInfo = stores_->current();
     470             : 
     471             :         // When the store dependencies is empty it means we have a disconnected
     472             :         // graph. Those blocks will never get reached but it is only fixed up
     473             :         // after GVN. Don't run AA on those blocks.
     474           0 :         if (blockInfo.length() == 0)
     475           0 :             continue;
     476             : 
     477           0 :         if (block->isLoopHeader())
     478           0 :             loop_ = new(alloc()) LoopInfo(alloc(), loop_, *block);
     479             : 
     480           0 :         for (MInstructionIterator def(block->begin()), end(block->begin(block->lastIns()));
     481             :                 def != end;
     482             :                 ++def)
     483             :         {
     484           0 :             def->setId(newId++);
     485             : 
     486             :             // For the purposes of alias analysis, all recoverable operations
     487             :             // are treated as effect free as the memory represented by these
     488             :             // operations cannot be aliased by others.
     489           0 :             if (def->canRecoverOnBailout())
     490           0 :                 continue;
     491             : 
     492           0 :             AliasSet set = def->getAliasSet();
     493           0 :             if (set.isStore()) {
     494           0 :                 if (!processStore(blockInfo, *def))
     495           0 :                     return false;
     496           0 :             } else if (set.isLoad()) {
     497           0 :                 if (!processLoad(blockInfo, *def))
     498           0 :                     return false;
     499             :             }
     500             :         }
     501             : 
     502           0 :         block->lastIns()->setId(newId++);
     503             : 
     504           0 :         if (block->isLoopBackedge()) {
     505           0 :             stores_->unsetCurrent();
     506             : 
     507           0 :             LoopInfo* info = loop_;
     508           0 :             loop_ = loop_->outer();
     509             : 
     510           0 :             if (!processDeferredLoads(info))
     511           0 :                 return false;
     512             :         }
     513             : 
     514           0 :         DumpBlockSummary(*block, blockInfo);
     515             :     }
     516             : 
     517           0 :     spewDependencyList();
     518           0 :     return true;
     519             : }
     520             : 
     521             : bool
     522           0 : FlowAliasAnalysis::processStore(BlockStoreInfo& blockInfo, MDefinition* store)
     523             : {
     524             :     // Compute and set dependency information.
     525           0 :     if (!saveStoreDependency(store, blockInfo))
     526           0 :         return false;
     527             : 
     528             :     // Update the block store dependency vector.
     529           0 :     blockInfo.clear();
     530           0 :     if (!blockInfo.append(store))
     531           0 :         return false;
     532             : 
     533             :     // Spew what we did.
     534           0 :     DumpStore(store);
     535           0 :     return true;
     536             : }
     537             : 
     538             : bool
     539           0 : FlowAliasAnalysis::processLoad(BlockStoreInfo& blockInfo, MDefinition* load)
     540             : {
     541           0 :     DumpLoad(load);
     542             : 
     543             :     // Compute dependency information.
     544           0 :     MDefinitionVector& dependencies = blockInfo;
     545           0 :     if (!improveDependency(load, dependencies, output_))
     546           0 :         return false;
     547           0 :     saveLoadDependency(load, output_);
     548             : 
     549             :     // If possible defer when better loop information is present.
     550           0 :     if (deferImproveDependency(output_)) {
     551           0 :         if (!loop_->loopinvariant().append(load))
     552           0 :             return false;
     553             : 
     554           0 :         DumpLoadOutcome(load, output_, /* defer = */ true);
     555           0 :         return true;
     556             :     }
     557             : 
     558           0 :     DumpLoadOutcome(load, output_, /* defer = */ false);
     559           0 :     return true;
     560             : }
     561             : 
     562             : bool
     563           0 : FlowAliasAnalysis::processDeferredLoads(LoopInfo* info)
     564             : {
     565           0 :     DumpProcessingDeferredLoads(info->loopHeader());
     566           0 :     MOZ_ASSERT(loopIsFinished(info->loopHeader()));
     567             : 
     568           0 :     for (size_t i = 0; i < info->loopinvariant().length(); i++) {
     569           0 :         MDefinition* load = info->loopinvariant()[i];
     570             : 
     571           0 :         DumpLoad(load);
     572             : 
     573             :         // Defer load again when this loop still isn't finished yet.
     574           0 :         if (!loopIsFinished(load->dependency()->block())) {
     575           0 :             MOZ_ASSERT(loop_);
     576           0 :             if (!loop_->loopinvariant().append(load))
     577           0 :                 return false;
     578             : 
     579           0 :             DumpLoadOutcome(load, output_, /* defer = */ true);
     580           0 :             continue;
     581             :         }
     582             : 
     583           0 :         MOZ_ASSERT(load->dependency()->block() == info->loopHeader());
     584           0 :         MDefinition* store = load->dependency();
     585           0 :         load->setDependency(nullptr);
     586             : 
     587             :         // Test if this load is loop invariant and if it is,
     588             :         // take the dependencies of non-backedge predecessors of the loop header.
     589             :         bool loopinvariant;
     590           0 :         if (!isLoopInvariant(load, store, &loopinvariant))
     591           0 :             return false;
     592             :         MDefinitionVector &loopInvariantDependency =
     593           0 :             stores_->get(store->block()->loopPredecessor());
     594             : 
     595           0 :         DumpLoopInvariant(load, info->loopHeader(), /* loopinvariant = */ loopinvariant,
     596           0 :                           loopInvariantDependency);
     597             : 
     598             :         // When the store dependencies is empty it means we have a disconnected
     599             :         // graph. Those blocks will never get reached but it is only fixed up
     600             :         // after GVN. Don't improve dependency for those loads.
     601           0 :         if (loopInvariantDependency.length() == 0) {
     602           0 :             load->setDependency(store);
     603           0 :             continue;
     604             :         }
     605             : 
     606           0 :         if (loopinvariant) {
     607           0 :             if (!improveDependency(load, loopInvariantDependency, output_))
     608           0 :                 return false;
     609           0 :             saveLoadDependency(load, output_);
     610             : 
     611             :             // If possible defer when better loop information is present.
     612           0 :             if (deferImproveDependency(output_)) {
     613           0 :                 if (!loop_->loopinvariant().append(load))
     614           0 :                     return false;
     615             : 
     616           0 :                 DumpLoadOutcome(load, output_, /* defer = */ true);
     617             :             } else {
     618           0 :                 DumpLoadOutcome(load, output_, /* defer = */ false);
     619             :             }
     620             : 
     621             :         } else {
     622           0 :             load->setDependency(store);
     623             : 
     624             : #ifdef JS_JITSPEW
     625           0 :             output_.clear();
     626           0 :             if (!output_.append(store))
     627           0 :                 return false;
     628           0 :             DumpLoadOutcome(load, output_, /* defer = */ false);
     629             : #endif
     630             :         }
     631             : 
     632             :     }
     633           0 :     return true;
     634             : }
     635             : 
     636             : // Given a load instruction and an initial store dependency list,
     637             : // find the most accurate store dependency list.
     638             : bool
     639           0 : FlowAliasAnalysis::improveDependency(MDefinition* load, MDefinitionVector& inputStores,
     640             :                                      MDefinitionVector& outputStores)
     641             : {
     642           0 :     MOZ_ASSERT(inputStores.length() > 0);
     643           0 :     outputStores.clear();
     644           0 :     if (!outputStores.appendAll(inputStores))
     645           0 :         return false;
     646             : 
     647           0 :     bool improved = false;
     648           0 :     bool adjusted = true;
     649           0 :     while (adjusted) {
     650           0 :         adjusted = false;
     651           0 :         if (!improveNonAliasedStores(load, outputStores, outputStores, &improved))
     652           0 :             return false;
     653           0 :         MOZ_ASSERT(outputStores.length() != 0);
     654           0 :         if (!improveStoresInFinishedLoops(load, outputStores, &adjusted))
     655           0 :             return false;
     656           0 :         if (adjusted)
     657           0 :             improved = true;
     658             :     }
     659             : 
     660           0 :     if (improved)
     661           0 :         DumpImprovement(load, inputStores, outputStores);
     662             : 
     663           0 :     return true;
     664             : }
     665             : 
     666             : // For every real store dependencies, follow the chain of stores to find the
     667             : // unique set of 'might alias' store dependencies.
     668             : bool
     669           0 : FlowAliasAnalysis::improveNonAliasedStores(MDefinition* load, MDefinitionVector& inputStores,
     670             :                                            MDefinitionVector& outputStores, bool* improved,
     671             :                                            bool onlyControlInstructions)
     672             : {
     673           0 :     MOZ_ASSERT(worklist_.length() == 0);
     674           0 :     if (!AppendToWorklist(worklist_, inputStores))
     675           0 :         return false;
     676           0 :     outputStores.clear();
     677             : 
     678           0 :     for (size_t i = 0; i < worklist_.length(); i++) {
     679           0 :         MOZ_ASSERT(worklist_[i]);
     680             : 
     681           0 :         if (!LoadAliasesStore(load, worklist_[i])) {
     682           0 :             StoreDependency* dep = worklist_[i]->storeDependency();
     683           0 :             MOZ_ASSERT(dep);
     684           0 :             MOZ_ASSERT(dep->get().length() > 0);
     685             : 
     686           0 :             if (!AppendToWorklist(worklist_, dep->get()))
     687           0 :                 return false;
     688             : 
     689           0 :             *improved = true;
     690           0 :             continue;
     691             :         }
     692             : 
     693           0 :         if (onlyControlInstructions && !worklist_[i]->isControlInstruction()) {
     694           0 :             outputStores.clear();
     695           0 :             break;
     696             :         }
     697           0 :         if (!outputStores.append(worklist_[i]))
     698           0 :             return false;
     699             :     }
     700             : 
     701           0 :     SetNotInWorkList(worklist_);
     702           0 :     worklist_.clear();
     703           0 :     return true;
     704             : }
     705             : 
     706             : // Given a load instruction and an initial store dependency list,
     707             : // find the most accurate store dependency list with only control instructions.
     708             : // Returns an empty output list, when there was a non control instructions
     709             : // that couldn't get improved to a control instruction.
     710             : bool
     711           0 : FlowAliasAnalysis::improveLoopDependency(MDefinition* load, MDefinitionVector& inputStores,
     712             :                                          MDefinitionVector& outputStores)
     713             : {
     714           0 :     outputStores.clear();
     715           0 :     if (!outputStores.appendAll(inputStores))
     716           0 :         return false;
     717             : 
     718           0 :     bool improved = false;
     719           0 :     bool adjusted = true;
     720           0 :     while (adjusted) {
     721           0 :         adjusted = false;
     722           0 :         if (!improveNonAliasedStores(load, outputStores, outputStores, &improved,
     723             :                                       /* onlyControlInstructions = */ true))
     724             :         {
     725           0 :             return false;
     726             :         }
     727           0 :         if (outputStores.length() == 0)
     728           0 :             return true;
     729           0 :         if (!improveStoresInFinishedLoops(load, outputStores, &adjusted))
     730           0 :             return false;
     731           0 :         if (adjusted)
     732           0 :             improved = true;
     733             :     }
     734             : 
     735           0 :     if (improved)
     736           0 :         DumpImprovement(load, inputStores, outputStores);
     737             : 
     738           0 :     return true;
     739             : }
     740             : 
     741             : // For every control instruction in the output we find out if the load is loop
     742             : // invariant to that loop. When it is, improve the output dependency store,
     743             : // by pointing to the stores before the loop.
     744             : bool
     745           0 : FlowAliasAnalysis::improveStoresInFinishedLoops(MDefinition* load, MDefinitionVector& stores,
     746             :                                                 bool* improved)
     747             : {
     748           0 :     for (size_t i = 0; i < stores.length(); i++) {
     749           0 :         if (!stores[i]->isControlInstruction())
     750           0 :             continue;
     751           0 :         if (!stores[i]->block()->isLoopHeader())
     752           0 :             continue;
     753             : 
     754           0 :         MOZ_ASSERT(!stores[i]->storeDependency());
     755             : 
     756           0 :         if (!loopIsFinished(stores[i]->block()))
     757           0 :             continue;
     758             : 
     759           0 :         if (load->dependency() == stores[i])
     760           0 :             continue;
     761             : 
     762             :         bool loopinvariant;
     763           0 :         if (!isLoopInvariant(load, stores[i], &loopinvariant))
     764           0 :             return false;
     765           0 :         if (!loopinvariant)
     766           0 :             continue;
     767             : 
     768           0 :         MBasicBlock* pred = stores[i]->block()->loopPredecessor();
     769           0 :         BlockStoreInfo& predInfo = stores_->get(pred);
     770             : 
     771           0 :         MOZ_ASSERT(predInfo.length() > 0);
     772           0 :         stores[i] = predInfo[0];
     773           0 :         for (size_t j = 1; j < predInfo.length(); j++) {
     774           0 :             if (!stores.append(predInfo[j]))
     775           0 :                 return false;
     776             :         }
     777             : 
     778           0 :         *improved = true;
     779             :     }
     780             : 
     781           0 :     return true;
     782             : }
     783             : 
     784             : bool
     785           0 : FlowAliasAnalysis::deferImproveDependency(MDefinitionVector& stores)
     786             : {
     787             :     // Look if the store depends only on 1 non finished loop.
     788             :     // In that case we will defer until that loop has finished.
     789           0 :     return loop_ && stores.length() == 1 &&
     790           0 :            stores[0]->isControlInstruction() &&
     791           0 :            stores[0]->block()->isLoopHeader() &&
     792           0 :            !loopIsFinished(stores[0]->block());
     793             : }
     794             : 
     795             : void
     796           0 : FlowAliasAnalysis::saveLoadDependency(MDefinition* load, MDefinitionVector& dependencies)
     797             : {
     798           0 :     MOZ_ASSERT(dependencies.length() > 0);
     799             : 
     800             :     // For now we only save the last store before the load for other passes.
     801             :     // That means the store with the maximum id.
     802           0 :     MDefinition* max = dependencies[0];
     803           0 :     MDefinition* maxNonControl = nullptr;
     804           0 :     for (size_t i = 0; i < dependencies.length(); i++) {
     805           0 :         MDefinition* ins = dependencies[i];
     806           0 :         if (max->id() < ins->id())
     807           0 :             max = ins;
     808           0 :         if (!ins->isControlInstruction()) {
     809           0 :             if (!maxNonControl || maxNonControl->id() < ins->id())
     810           0 :                 maxNonControl = ins;
     811             :         }
     812             :     }
     813             : 
     814             :     // For loop variant loads with no stores between loopheader and the load,
     815             :     // the control instruction of the loop header is returned.
     816             :     // That id is higher than any store inside the loopheader itself.
     817             :     // Fix for dependency on item in loopheader, but before the "test".
     818             :     // Which would assume it depends on the loop itself.
     819           0 :     if (maxNonControl != max && maxNonControl) {
     820           0 :         if (maxNonControl->block() == max->block())
     821           0 :             max = maxNonControl;
     822             :     }
     823             : 
     824           0 :     load->setDependency(max);
     825           0 : }
     826             : 
     827             : bool
     828           0 : FlowAliasAnalysis::saveStoreDependency(MDefinition* ins, BlockStoreInfo& prevStores)
     829             : {
     830             :     // To form a store dependency chain, we store the previous last dependencies
     831             :     // in the current store.
     832             : 
     833           0 :     StoreDependency* dependency = new(alloc().fallible()) StoreDependency(alloc());
     834           0 :     if (!dependency)
     835           0 :         return false;
     836           0 :     if (!dependency->init(prevStores))
     837           0 :         return false;
     838             : 
     839           0 :     ins->setStoreDependency(dependency);
     840           0 :     return true;
     841             : }
     842             : 
     843             : // Returns if loop has been processed
     844             : // and has complete backedge stores information.
     845             : bool
     846           0 : FlowAliasAnalysis::loopIsFinished(MBasicBlock* loopheader)
     847             : {
     848           0 :     MOZ_ASSERT(loopheader->isLoopHeader());
     849             : 
     850           0 :     if (!loop_)
     851           0 :         return true;
     852             : 
     853           0 :     return loopheader->backedge()->id() <
     854           0 :            loop_->loopHeader()->backedge()->id();
     855             : }
     856             : 
     857             : 
     858             : // Determines if a load is loop invariant.
     859             : //
     860             : // Get the last store dependencies of the backedge of the loop and follow
     861             : // the store chain until finding the aliased stores. Make sure the computed
     862             : // aliased stores is only the loop control instruction or control instructions
     863             : // of loops it is also loop invariant. Only in that case the load is
     864             : // definitely loop invariant.
     865             : bool
     866           0 : FlowAliasAnalysis::isLoopInvariant(MDefinition* load, MDefinition* store, bool* loopinvariant)
     867             : {
     868           0 :     MOZ_ASSERT(store->isControlInstruction());
     869           0 :     MOZ_ASSERT(!store->storeDependency());
     870           0 :     MOZ_ASSERT(store->block()->isLoopHeader());
     871           0 :     MOZ_ASSERT(loopIsFinished(store->block()));
     872             : 
     873           0 :     *loopinvariant = false;
     874           0 :     MBasicBlock* backedge = store->block()->backedge();
     875           0 :     MDefinitionVector output(alloc());
     876             : 
     877             :     // To make sure the improve dependency stops at this loop,
     878             :     // set the loop control instruction as dependency.
     879           0 :     MDefinition* olddep = load->dependency();
     880           0 :     load->setDependency(store);
     881           0 :     if (!improveLoopDependency(load, stores_->get(backedge), output))
     882           0 :         return false;
     883           0 :     load->setDependency(olddep);
     884             : 
     885           0 :     if (output.length() == 0)
     886           0 :         return true;
     887             : 
     888           0 :     for (size_t i = 0; i < output.length(); i++) {
     889           0 :         if (output[i]->storeDependency())
     890           0 :             return true;
     891             : 
     892           0 :         if (!output[i]->isControlInstruction())
     893           0 :             return true;
     894           0 :         if (!output[i]->block()->isLoopHeader())
     895           0 :             return true;
     896             : 
     897           0 :         if (output[i] == store)
     898           0 :             continue;
     899             : 
     900           0 :         return true;
     901             :     }
     902             : 
     903           0 :     *loopinvariant = true;
     904           0 :     return true;
     905             : }
     906             : 
     907             : // Compute the store dependencies at the start of this MBasicBlock.
     908             : bool
     909           0 : FlowAliasAnalysis::computeBlockStores(MBasicBlock* block)
     910             : {
     911           0 :     BlockStoreInfo* blockInfo = stores_->newCurrent(alloc(), block);
     912           0 :     if (!blockInfo)
     913           0 :         return false;
     914             : 
     915             :     // First and osr block depends on the first instruction.
     916           0 :     if (block == graph_.entryBlock() || block == graph_.osrBlock()) {
     917           0 :         MDefinition* firstIns = *block->begin();
     918           0 :         if (!blockInfo->append(firstIns))
     919           0 :             return false;
     920           0 :         return true;
     921             :     }
     922             : 
     923             :     // For loopheaders we take the loopheaders control instruction.
     924             :     // That is not moveable and easy is to detect.
     925           0 :     if (block->isLoopHeader()) {
     926           0 :         if (!blockInfo->append(block->lastIns()))
     927           0 :             return false;
     928           0 :         return true;
     929             :     }
     930             : 
     931             : 
     932             :     // Optimization for consecutive blocks.
     933           0 :     if (block->numPredecessors() == 1) {
     934           0 :         MBasicBlock* pred = block->getPredecessor(0);
     935           0 :         if (pred->numSuccessors() == 1) {
     936           0 :             stores_->swap(block, pred);
     937           0 :             return true;
     938             :         }
     939           0 :         MOZ_ASSERT (pred->numSuccessors() > 1);
     940           0 :         BlockStoreInfo& predInfo = stores_->get(pred);
     941           0 :         return blockInfo->appendAll(predInfo);
     942             :     }
     943             : 
     944             :     // Heuristic: in most cases having more than 5 predecessors,
     945             :     // increases the number of dependencies too much to still be able
     946             :     // to do an optimization. Therefore don't do the merge work.
     947             :     // For simplicity we take an non-dominant always existing instruction.
     948             :     // That way we cannot accidentally move instructions depending on it.
     949           0 :     if (block->numPredecessors() > 5) {
     950           0 :         if (!blockInfo->append(block->getPredecessor(0)->lastIns()))
     951           0 :             return false;
     952           0 :         return true;
     953             :     }
     954             : 
     955             :     // Merging of multiple predecessors.
     956           0 :     for (size_t pred = 0; pred < block->numPredecessors(); pred++) {
     957           0 :         BlockStoreInfo& predInfo = stores_->get(block->getPredecessor(pred));
     958           0 :         if (!AppendToWorklist(*blockInfo, predInfo))
     959           0 :             return false;
     960             :     }
     961           0 :     SetNotInWorkList(*blockInfo);
     962             : 
     963           0 :     return true;
     964             : }

Generated by: LCOV version 1.13