LCOV - code coverage report
Current view: top level - js/src/jit - Sink.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 46 93 49.5 %
Date: 2017-07-14 16:53:18 Functions: 4 4 100.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/Sink.h"
       8             : 
       9             : #include "mozilla/Vector.h"
      10             : 
      11             : #include "jit/IonAnalysis.h"
      12             : #include "jit/JitSpewer.h"
      13             : #include "jit/MIR.h"
      14             : #include "jit/MIRGenerator.h"
      15             : #include "jit/MIRGraph.h"
      16             : 
      17             : namespace js {
      18             : namespace jit {
      19             : 
      20             : // Given the last found common dominator and a new definition to dominate, the
      21             : // CommonDominator function returns the basic block which dominate the last
      22             : // common dominator and the definition. If no such block exists, then this
      23             : // functions return null.
      24             : static MBasicBlock*
      25         109 : CommonDominator(MBasicBlock* commonDominator, MBasicBlock* defBlock)
      26             : {
      27             :     // This is the first instruction visited, record its basic block as being
      28             :     // the only interesting one.
      29         109 :     if (!commonDominator)
      30          56 :         return defBlock;
      31             : 
      32             :     // Iterate on immediate dominators of the known common dominator to find a
      33             :     // block which dominates all previous uses as well as this instruction.
      34         183 :     while (!commonDominator->dominates(defBlock)) {
      35          65 :         MBasicBlock* nextBlock = commonDominator->immediateDominator();
      36             :         // All uses are dominated, so, this cannot happen unless the graph
      37             :         // coherency is not respected.
      38          65 :         MOZ_ASSERT(commonDominator != nextBlock);
      39          65 :         commonDominator = nextBlock;
      40             :     }
      41             : 
      42          53 :     return commonDominator;
      43             : }
      44             : 
      45             : bool
      46           8 : Sink(MIRGenerator* mir, MIRGraph& graph)
      47             : {
      48           8 :     TempAllocator& alloc = graph.alloc();
      49           8 :     bool sinkEnabled = mir->optimizationInfo().sinkEnabled();
      50             : 
      51         411 :     for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
      52         403 :         if (mir->shouldCancel("Sink"))
      53           0 :             return false;
      54             : 
      55        1875 :         for (MInstructionReverseIterator iter = block->rbegin(); iter != block->rend(); ) {
      56        1472 :             MInstruction* ins = *iter++;
      57             : 
      58             :             // Only instructions which can be recovered on bailout can be moved
      59             :             // into the bailout paths.
      60        5334 :             if (ins->isGuard() || ins->isGuardRangeBailouts() ||
      61        3804 :                 ins->isRecoveredOnBailout() || !ins->canRecoverOnBailout())
      62             :             {
      63        2883 :                 continue;
      64             :             }
      65             : 
      66             :             // Compute a common dominator for all uses of the current
      67             :             // instruction.
      68          61 :             bool hasLiveUses = false;
      69          61 :             bool hasUses = false;
      70          61 :             MBasicBlock* usesDominator = nullptr;
      71        1110 :             for (MUseIterator i(ins->usesBegin()), e(ins->usesEnd()); i != e; i++) {
      72        1090 :                 hasUses = true;
      73        1090 :                 MNode* consumerNode = (*i)->consumer();
      74        1090 :                 if (consumerNode->isResumePoint())
      75         921 :                     continue;
      76             : 
      77         169 :                 MDefinition* consumer = consumerNode->toDefinition();
      78         169 :                 if (consumer->isRecoveredOnBailout())
      79          60 :                     continue;
      80             : 
      81         109 :                 hasLiveUses = true;
      82             : 
      83             :                 // If the instruction is a Phi, then we should dominate the
      84             :                 // predecessor from which the value is coming from.
      85         109 :                 MBasicBlock* consumerBlock = consumer->block();
      86         109 :                 if (consumer->isPhi())
      87          20 :                     consumerBlock = consumerBlock->getPredecessor(consumer->indexOf(*i));
      88             : 
      89         109 :                 usesDominator = CommonDominator(usesDominator, consumerBlock);
      90         109 :                 if (usesDominator == *block)
      91          41 :                     break;
      92             :             }
      93             : 
      94             :             // Leave this instruction for DCE.
      95          61 :             if (!hasUses)
      96           0 :                 continue;
      97             : 
      98             :             // We have no uses, so sink this instruction in all the bailout
      99             :             // paths.
     100          61 :             if (!hasLiveUses) {
     101           5 :                 MOZ_ASSERT(!usesDominator);
     102           5 :                 ins->setRecoveredOnBailout();
     103           5 :                 JitSpewDef(JitSpew_Sink, "  No live uses, recover the instruction on bailout\n", ins);
     104           5 :                 continue;
     105             :             }
     106             : 
     107             :             // This guard is temporarly moved here as the above code deals with
     108             :             // Dead Code elimination, which got moved into this Sink phase, as
     109             :             // the Dead Code elimination used to move instructions with no-live
     110             :             // uses to the bailout path.
     111          56 :             if (!sinkEnabled)
     112          56 :                 continue;
     113             : 
     114             :             // To move an effectful instruction, we would have to verify that the
     115             :             // side-effect is not observed. In the mean time, we just inhibit
     116             :             // this optimization on effectful instructions.
     117           0 :             if (ins->isEffectful())
     118           0 :                 continue;
     119             : 
     120             :             // If all the uses are under a loop, we might not want to work
     121             :             // against LICM by moving everything back into the loop, but if the
     122             :             // loop is it-self inside an if, then we still want to move the
     123             :             // computation under this if statement.
     124           0 :             while (block->loopDepth() < usesDominator->loopDepth()) {
     125           0 :                 MOZ_ASSERT(usesDominator != usesDominator->immediateDominator());
     126           0 :                 usesDominator = usesDominator->immediateDominator();
     127             :             }
     128             : 
     129             :             // Only move instructions if there is a branch between the dominator
     130             :             // of the uses and the original instruction. This prevent moving the
     131             :             // computation of the arguments into an inline function if there is
     132             :             // no major win.
     133           0 :             MBasicBlock* lastJoin = usesDominator;
     134           0 :             while (*block != lastJoin && lastJoin->numPredecessors() == 1) {
     135           0 :                 MOZ_ASSERT(lastJoin != lastJoin->immediateDominator());
     136           0 :                 MBasicBlock* next = lastJoin->immediateDominator();
     137           0 :                 if (next->numSuccessors() > 1)
     138           0 :                     break;
     139           0 :                 lastJoin = next;
     140             :             }
     141           0 :             if (*block == lastJoin)
     142           0 :                 continue;
     143             : 
     144             :             // Skip to the next instruction if we cannot find a common dominator
     145             :             // for all the uses of this instruction, or if the common dominator
     146             :             // correspond to the block of the current instruction.
     147           0 :             if (!usesDominator || usesDominator == *block)
     148           0 :                 continue;
     149             : 
     150             :             // Only instruction which can be recovered on bailout and which are
     151             :             // sinkable can be moved into blocks which are below while filling
     152             :             // the resume points with a clone which is recovered on bailout.
     153             : 
     154             :             // If the instruction has live uses and if it is clonable, then we
     155             :             // can clone the instruction for all non-dominated uses and move the
     156             :             // instruction into the block which is dominating all live uses.
     157           0 :             if (!ins->canClone())
     158           0 :                 continue;
     159             : 
     160             :             // If the block is a split-edge block, which is created for folding
     161             :             // test conditions, then the block has no resume point and has
     162             :             // multiple predecessors.  In such case, we cannot safely move
     163             :             // bailing instruction to these blocks as we have no way to bailout.
     164           0 :             if (!usesDominator->entryResumePoint() && usesDominator->numPredecessors() != 1)
     165           0 :                 continue;
     166             : 
     167           0 :             JitSpewDef(JitSpew_Sink, "  Can Clone & Recover, sink instruction\n", ins);
     168           0 :             JitSpew(JitSpew_Sink, "  into Block %u", usesDominator->id());
     169             : 
     170             :             // Copy the arguments and clone the instruction.
     171           0 :             MDefinitionVector operands(alloc);
     172           0 :             for (size_t i = 0, end = ins->numOperands(); i < end; i++) {
     173           0 :                 if (!operands.append(ins->getOperand(i)))
     174           0 :                     return false;
     175             :             }
     176             : 
     177           0 :             MInstruction* clone = ins->clone(alloc, operands);
     178           0 :             ins->block()->insertBefore(ins, clone);
     179           0 :             clone->setRecoveredOnBailout();
     180             : 
     181             :             // We should not update the producer of the entry resume point, as
     182             :             // it cannot refer to any instruction within the basic block excepts
     183             :             // for Phi nodes.
     184           0 :             MResumePoint* entry = usesDominator->entryResumePoint();
     185             : 
     186             :             // Replace the instruction by its clone in all the resume points /
     187             :             // recovered-on-bailout instructions which are not in blocks which
     188             :             // are dominated by the usesDominator block.
     189           0 :             for (MUseIterator i(ins->usesBegin()), e(ins->usesEnd()); i != e; ) {
     190           0 :                 MUse* use = *i++;
     191           0 :                 MNode* consumer = use->consumer();
     192             : 
     193             :                 // If the consumer is a Phi, then we look for the index of the
     194             :                 // use to find the corresponding predecessor block, which is
     195             :                 // then used as the consumer block.
     196           0 :                 MBasicBlock* consumerBlock = consumer->block();
     197           0 :                 if (consumer->isDefinition() && consumer->toDefinition()->isPhi()) {
     198           0 :                     consumerBlock = consumerBlock->getPredecessor(
     199           0 :                         consumer->toDefinition()->toPhi()->indexOf(use));
     200             :                 }
     201             : 
     202             :                 // Keep the current instruction for all dominated uses, except
     203             :                 // for the entry resume point of the block in which the
     204             :                 // instruction would be moved into.
     205           0 :                 if (usesDominator->dominates(consumerBlock) &&
     206           0 :                     (!consumer->isResumePoint() || consumer->toResumePoint() != entry))
     207             :                 {
     208           0 :                     continue;
     209             :                 }
     210             : 
     211           0 :                 use->replaceProducer(clone);
     212             :             }
     213             : 
     214             :             // As we move this instruction in a different block, we should
     215             :             // verify that we do not carry over a resume point which would refer
     216             :             // to an outdated state of the control flow.
     217           0 :             if (ins->resumePoint())
     218           0 :                 ins->clearResumePoint();
     219             : 
     220             :             // Now, that all uses which are not dominated by usesDominator are
     221             :             // using the cloned instruction, we can safely move the instruction
     222             :             // into the usesDominator block.
     223           0 :             MInstruction* at = usesDominator->safeInsertTop(nullptr, MBasicBlock::IgnoreRecover);
     224           0 :             block->moveBefore(at, ins);
     225             :         }
     226             :     }
     227             : 
     228           8 :     return true;
     229             : }
     230             : 
     231             : } // namespace jit
     232           9 : } // namespace js

Generated by: LCOV version 1.13