LCOV - code coverage report
Current view: top level - src/compiler - jump-threading.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 82 88 93.2 %
Date: 2017-04-26 Functions: 4 4 100.0 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/jump-threading.h"
       6             : #include "src/compiler/code-generator-impl.h"
       7             : #include "src/objects-inl.h"
       8             : 
       9             : namespace v8 {
      10             : namespace internal {
      11             : namespace compiler {
      12             : 
      13             : #define TRACE(...)                                \
      14             :   do {                                            \
      15             :     if (FLAG_trace_turbo_jt) PrintF(__VA_ARGS__); \
      16             :   } while (false)
      17             : 
      18             : struct JumpThreadingState {
      19             :   bool forwarded;
      20             :   ZoneVector<RpoNumber>& result;
      21             :   ZoneStack<RpoNumber>& stack;
      22             : 
      23     1833343 :   void Clear(size_t count) { result.assign(count, unvisited()); }
      24    11467664 :   void PushIfUnvisited(RpoNumber num) {
      25    32768715 :     if (result[num.ToInt()] == unvisited()) {
      26     9833367 :       stack.push(num);
      27    19666774 :       result[num.ToInt()] = onstack();
      28             :     }
      29    11467684 :   }
      30    13101964 :   void Forward(RpoNumber to) {
      31    26203928 :     RpoNumber from = stack.top();
      32    39305946 :     RpoNumber to_to = result[to.ToInt()];
      33             :     bool pop = true;
      34    13101964 :     if (to == from) {
      35     8691804 :       TRACE("  xx %d\n", from.ToInt());
      36    17383702 :       result[from.ToInt()] = from;
      37     4410160 :     } else if (to_to == unvisited()) {
      38     1634320 :       TRACE("  fw %d -> %d (recurse)\n", from.ToInt(), to.ToInt());
      39     1634320 :       stack.push(to);
      40     3268656 :       result[to.ToInt()] = onstack();
      41             :       pop = false;  // recurse.
      42     2775840 :     } else if (to_to == onstack()) {
      43          63 :       TRACE("  fw %d -> %d (cycle)\n", from.ToInt(), to.ToInt());
      44         126 :       result[from.ToInt()] = to;  // break the cycle.
      45          63 :       forwarded = true;
      46             :     } else {
      47     2775777 :       TRACE("  fw %d -> %d (forward)\n", from.ToInt(), to.ToInt());
      48     5551552 :       result[from.ToInt()] = to_to;  // forward the block.
      49     2775776 :       forwarded = true;
      50             :     }
      51    13102018 :     if (pop) stack.pop();
      52    13102018 :   }
      53             :   RpoNumber unvisited() { return RpoNumber::FromInt(-1); }
      54             :   RpoNumber onstack() { return RpoNumber::FromInt(-2); }
      55             : };
      56             : 
      57      916567 : bool JumpThreading::ComputeForwarding(Zone* local_zone,
      58             :                                       ZoneVector<RpoNumber>& result,
      59    15850185 :                                       InstructionSequence* code,
      60             :                                       bool frame_at_start) {
      61      916567 :   ZoneStack<RpoNumber> stack(local_zone);
      62      916655 :   JumpThreadingState state = {false, result, stack};
      63      916655 :   state.Clear(code->InstructionBlockCount());
      64             : 
      65             :   // Iterate over the blocks forward, pushing the blocks onto the stack.
      66    13300995 :   for (auto const block : code->instruction_blocks()) {
      67    11467655 :     RpoNumber current = block->rpo_number();
      68    11467655 :     state.PushIfUnvisited(current);
      69             : 
      70             :     // Process the stack, which implements DFS through empty blocks.
      71    60606675 :     while (!state.stack.empty()) {
      72    62653710 :       InstructionBlock* block = code->InstructionBlockAt(state.stack.top());
      73             :       // Process the instructions in a block up to a non-empty instruction.
      74    13101900 :       TRACE("jt [%d] B%d\n", static_cast<int>(stack.size()),
      75             :             block->rpo_number().ToInt());
      76             :       bool fallthru = true;
      77    13101902 :       RpoNumber fw = block->rpo_number();
      78    43754300 :       for (int i = block->code_start(); i < block->code_end(); ++i) {
      79    16841734 :         Instruction* instr = code->InstructionAt(i);
      80    20962053 :         if (!instr->AreMovesRedundant()) {
      81             :           // can't skip instructions with non redundant moves.
      82     4120633 :           TRACE("  parallel move\n");
      83             :           fallthru = false;
      84    33683468 :         } else if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
      85             :           // can't skip instructions with flags continuations.
      86     1360262 :           TRACE("  flags\n");
      87             :           fallthru = false;
      88    15481472 :         } else if (instr->IsNop()) {
      89             :           // skip nops.
      90     8775236 :           TRACE("  nop\n");
      91             :           continue;
      92     6706236 :         } else if (instr->arch_opcode() == kArchJmp) {
      93             :           // try to forward the jump instruction.
      94     4416367 :           TRACE("  jmp\n");
      95             :           // if this block deconstructs the frame, we can't forward it.
      96             :           // TODO(mtrofin): we can still forward if we end up building
      97             :           // the frame at start. So we should move the decision of whether
      98             :           // to build a frame or not in the register allocator, and trickle it
      99             :           // here and to the code generator.
     100     9568251 :           if (frame_at_start ||
     101             :               !(block->must_deconstruct_frame() ||
     102      735355 :                 block->must_construct_frame())) {
     103     4409832 :             fw = code->InputRpo(instr, 0);
     104             :           }
     105             :           fallthru = false;
     106             :         } else {
     107             :           // can't skip other instructions.
     108     2289869 :           TRACE("  other\n");
     109             :           fallthru = false;
     110             :         }
     111             :         break;
     112             :       }
     113    13101875 :       if (fallthru) {
     114      914960 :         int next = 1 + block->rpo_number().ToInt();
     115      914960 :         if (next < code->InstructionBlockCount()) fw = RpoNumber::FromInt(next);
     116             :       }
     117    13101875 :       state.Forward(fw);
     118             :     }
     119             :   }
     120             : 
     121             : #ifdef DEBUG
     122             :   for (RpoNumber num : result) {
     123             :     CHECK(num.IsValid());
     124             :   }
     125             : #endif
     126             : 
     127      916652 :   if (FLAG_trace_turbo_jt) {
     128           0 :     for (int i = 0; i < static_cast<int>(result.size()); i++) {
     129           0 :       TRACE("B%d ", i);
     130           0 :       int to = result[i].ToInt();
     131           0 :       if (i != to) {
     132           0 :         TRACE("-> B%d\n", to);
     133             :       } else {
     134           0 :         TRACE("\n");
     135             :       }
     136             :     }
     137             :   }
     138             : 
     139     1833265 :   return state.forwarded;
     140             : }
     141             : 
     142             : 
     143      556548 : void JumpThreading::ApplyForwarding(ZoneVector<RpoNumber>& result,
     144     1669740 :                                     InstructionSequence* code) {
     145      556548 :   if (!FLAG_turbo_jt) return;
     146             : 
     147      556548 :   Zone local_zone(code->isolate()->allocator(), ZONE_NAME);
     148    23102783 :   ZoneVector<bool> skip(static_cast<int>(result.size()), false, &local_zone);
     149             : 
     150             :   // Skip empty blocks when the previous block doesn't fall through.
     151             :   bool prev_fallthru = true;
     152    68681436 :   for (auto const block : code->instruction_blocks()) {
     153             :     int block_num = block->rpo_number().ToInt();
     154    19814446 :     skip[block_num] = !prev_fallthru && result[block_num].ToInt() != block_num;
     155             : 
     156             :     bool fallthru = true;
     157    92513604 :     for (int i = block->code_start(); i < block->code_end(); ++i) {
     158    35601079 :       Instruction* instr = code->InstructionAt(i);
     159    71202158 :       if (FlagsModeField::decode(instr->opcode()) == kFlags_branch) {
     160             :         fallthru = false;  // branches don't fall through to the next block.
     161    32329671 :       } else if (instr->arch_opcode() == kArchJmp) {
     162    11778120 :         if (skip[block_num]) {
     163             :           // Overwrite a redundant jump with a nop.
     164     2629936 :           TRACE("jt-fw nop @%d\n", i);
     165             :           instr->OverwriteWithNop();
     166             :         }
     167             :         fallthru = false;  // jumps don't fall through to the next block.
     168             :       }
     169             :     }
     170             :     prev_fallthru = fallthru;
     171             :   }
     172             : 
     173             :   // Patch RPO immediates.
     174             :   InstructionSequence::Immediates& immediates = code->immediates();
     175    56886484 :   for (size_t i = 0; i < immediates.size(); i++) {
     176    56886484 :     Constant constant = immediates[i];
     177    28164944 :     if (constant.type() == Constant::kRpoNumber) {
     178             :       RpoNumber rpo = constant.ToRpoNumber();
     179    25661828 :       RpoNumber fw = result[rpo.ToInt()];
     180    15898041 :       if (!(fw == rpo)) immediates[i] = Constant(fw);
     181             :     }
     182             :   }
     183             : 
     184             :   // Recompute assembly order numbers.
     185             :   int ao = 0;
     186    11768964 :   for (auto const block : code->instruction_blocks()) {
     187    10655772 :     if (!block->IsDeferred()) {
     188             :       block->set_ao_number(RpoNumber::FromInt(ao));
     189    15901288 :       if (!skip[block->rpo_number().ToInt()]) ao++;
     190             :     }
     191             :   }
     192    21868090 :   for (auto const block : code->instruction_blocks()) {
     193    10655747 :     if (block->IsDeferred()) {
     194             :       block->set_ao_number(RpoNumber::FromInt(ao));
     195     5410578 :       if (!skip[block->rpo_number().ToInt()]) ao++;
     196             :     }
     197      556596 :   }
     198             : }
     199             : 
     200             : }  // namespace compiler
     201             : }  // namespace internal
     202             : }  // namespace v8

Generated by: LCOV version 1.10