LCOV - code coverage report
Current view: top level - js/src/jit - InstructionReordering.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 75 96 78.1 %
Date: 2017-07-14 16:53:18 Functions: 3 3 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/InstructionReordering.h"
       8             : #include "jit/MIRGraph.h"
       9             : 
      10             : using namespace js;
      11             : using namespace js::jit;
      12             : 
      13             : static void
      14          35 : MoveBefore(MBasicBlock* block, MInstruction* at, MInstruction* ins)
      15             : {
      16          35 :     if (at == ins)
      17           4 :         return;
      18             : 
      19             :     // Update instruction numbers.
      20         189 :     for (MInstructionIterator iter(block->begin(at)); *iter != ins; iter++) {
      21         158 :         MOZ_ASSERT(iter->id() < ins->id());
      22         158 :         iter->setId(iter->id() + 1);
      23             :     }
      24          31 :     ins->setId(at->id() - 1);
      25          31 :     block->moveBefore(at, ins);
      26             : }
      27             : 
      28             : static bool
      29         353 : IsLastUse(MDefinition* ins, MDefinition* input, MBasicBlock* loopHeader)
      30             : {
      31             :     // If we are in a loop, this cannot be the last use of any definitions from
      32             :     // outside the loop, as those definitions can be used in future iterations.
      33         353 :     if (loopHeader && input->block()->id() < loopHeader->id())
      34          39 :         return false;
      35         645 :     for (MUseDefIterator iter(input); iter; iter++) {
      36             :         // Watch for uses defined in blocks which ReorderInstructions hasn't
      37             :         // processed yet. These nodes have not had their ids set yet.
      38         443 :         if (iter.def()->block()->id() > ins->block()->id())
      39         206 :             return false;
      40         349 :         if (iter.def()->id() > ins->id())
      41          18 :             return false;
      42             :     }
      43         202 :     return true;
      44             : }
      45             : 
      46             : bool
      47           8 : jit::ReorderInstructions(MIRGenerator* mir, MIRGraph& graph)
      48             : {
      49             :     // Renumber all instructions in the graph as we go.
      50           8 :     size_t nextId = 0;
      51             : 
      52             :     // List of the headers of any loops we are in.
      53          16 :     Vector<MBasicBlock*, 4, SystemAllocPolicy> loopHeaders;
      54             : 
      55         411 :     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
      56             :         // Renumber all definitions inside the basic blocks.
      57         578 :         for (MPhiIterator iter(block->phisBegin()); iter != block->phisEnd(); iter++)
      58         175 :             iter->setId(nextId++);
      59             : 
      60        1875 :         for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++)
      61        1472 :             iter->setId(nextId++);
      62             : 
      63             :         // Don't reorder instructions within entry blocks, which have special requirements.
      64         403 :         if (*block == graph.entryBlock() || *block == graph.osrBlock())
      65          11 :             continue;
      66             : 
      67         392 :         if (block->isLoopHeader()) {
      68           5 :             if (!loopHeaders.append(*block))
      69           0 :                 return false;
      70             :         }
      71             : 
      72         392 :         MBasicBlock* innerLoop = loopHeaders.empty() ? nullptr : loopHeaders.back();
      73             : 
      74         392 :         MInstruction* top = block->safeInsertTop();
      75         392 :         MInstructionReverseIterator rtop = ++block->rbegin(top);
      76        1428 :         for (MInstructionIterator iter(block->begin(top)); iter != block->end(); ) {
      77        1036 :             MInstruction* ins = *iter;
      78             : 
      79             :             // Filter out some instructions which are never reordered.
      80        2984 :             if (ins->isEffectful() ||
      81        1329 :                 !ins->isMovable() ||
      82        1870 :                 ins->resumePoint() ||
      83         417 :                 ins == block->lastIns())
      84             :             {
      85         619 :                 iter++;
      86         619 :                 continue;
      87             :             }
      88             : 
      89             :             // Move constants with a single use in the current block to the
      90             :             // start of the block. Constants won't be reordered by the logic
      91             :             // below, as they have no inputs. Moving them up as high as
      92             :             // possible can allow their use to be moved up further, though,
      93             :             // and has no cost if the constant is emitted at its use.
      94        1686 :             if (ins->isConstant() &&
      95         111 :                 ins->hasOneUse() &&
      96        1375 :                 ins->usesBegin()->consumer()->block() == *block &&
      97          31 :                 !IsFloatingPointType(ins->type()))
      98             :             {
      99          31 :                 iter++;
     100          31 :                 MInstructionIterator targetIter = block->begin();
     101          87 :                 while (targetIter->isConstant() || targetIter->isInterruptCheck()) {
     102          28 :                     if (*targetIter == ins)
     103           0 :                         break;
     104          28 :                     targetIter++;
     105             :                 }
     106          31 :                 MoveBefore(*block, *targetIter, ins);
     107          31 :                 continue;
     108             :             }
     109             : 
     110             :             // Look for inputs where this instruction is the last use of that
     111             :             // input. If we move this instruction up, the input's lifetime will
     112             :             // be shortened, modulo resume point uses (which don't need to be
     113             :             // stored in a register, and can be handled by the register
     114             :             // allocator by just spilling at some point with no reload).
     115         390 :             Vector<MDefinition*, 4, SystemAllocPolicy> lastUsedInputs;
     116         828 :             for (size_t i = 0; i < ins->numOperands(); i++) {
     117         442 :                 MDefinition* input = ins->getOperand(i);
     118         442 :                 if (!input->isConstant() && IsLastUse(ins, input, innerLoop)) {
     119         202 :                     if (!lastUsedInputs.append(input))
     120           0 :                         return false;
     121             :                 }
     122             :             }
     123             : 
     124             :             // Don't try to move instructions which aren't the last use of any
     125             :             // of their inputs (we really ought to move these down instead).
     126         386 :             if (lastUsedInputs.length() < 2) {
     127         382 :                 iter++;
     128         382 :                 continue;
     129             :             }
     130             : 
     131           4 :             MInstruction* target = ins;
     132           4 :             for (MInstructionReverseIterator riter = ++block->rbegin(ins); riter != rtop; riter++) {
     133           4 :                 MInstruction* prev = *riter;
     134           4 :                 if (prev->isInterruptCheck())
     135           0 :                     break;
     136             : 
     137             :                 // The instruction can't be moved before any of its uses.
     138           4 :                 bool isUse = false;
     139           5 :                 for (size_t i = 0; i < ins->numOperands(); i++) {
     140           5 :                     if (ins->getOperand(i) == prev) {
     141           4 :                         isUse = true;
     142           4 :                         break;
     143             :                     }
     144             :                 }
     145           4 :                 if (isUse)
     146           4 :                     break;
     147             : 
     148             :                 // The instruction can't be moved before an instruction that
     149             :                 // stores to a location read by the instruction.
     150           0 :                 if (prev->isEffectful() &&
     151           0 :                     (ins->getAliasSet().flags() & prev->getAliasSet().flags()) &&
     152           0 :                     ins->mightAlias(prev) != MDefinition::AliasType::NoAlias)
     153             :                 {
     154           0 :                     break;
     155             :                 }
     156             : 
     157             :                 // Make sure the instruction will still be the last use of one
     158             :                 // of its inputs when moved up this far.
     159           0 :                 for (size_t i = 0; i < lastUsedInputs.length(); ) {
     160           0 :                     bool found = false;
     161           0 :                     for (size_t j = 0; j < prev->numOperands(); j++) {
     162           0 :                         if (prev->getOperand(j) == lastUsedInputs[i]) {
     163           0 :                             found = true;
     164           0 :                             break;
     165             :                         }
     166             :                     }
     167           0 :                     if (found) {
     168           0 :                         lastUsedInputs[i] = lastUsedInputs.back();
     169           0 :                         lastUsedInputs.popBack();
     170             :                     } else {
     171           0 :                         i++;
     172             :                     }
     173             :                 }
     174           0 :                 if (lastUsedInputs.length() < 2)
     175           0 :                     break;
     176             : 
     177             :                 // We can move the instruction before this one.
     178           0 :                 target = prev;
     179             :             }
     180             : 
     181           4 :             iter++;
     182           4 :             MoveBefore(*block, target, ins);
     183             :         }
     184             : 
     185         392 :         if (block->isLoopBackedge())
     186           5 :             loopHeaders.popBack();
     187             :     }
     188             : 
     189           8 :     return true;
     190             : }

Generated by: LCOV version 1.13