LCOV - code coverage report
Current view: top level - test/unittests/interpreter - bytecode-register-optimizer-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 104 104 100.0 %
Date: 2019-04-18 Functions: 23 32 71.9 %

          Line data    Source code
       1             : // Copyright 2016 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/v8.h"
       6             : 
       7             : #include "src/interpreter/bytecode-label.h"
       8             : #include "src/interpreter/bytecode-register-optimizer.h"
       9             : #include "test/unittests/interpreter/bytecode-utils.h"
      10             : #include "test/unittests/test-utils.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : namespace interpreter {
      15             : 
      16             : class BytecodeRegisterOptimizerTest
      17             :     : public BytecodeRegisterOptimizer::BytecodeWriter,
      18             :       public TestWithIsolateAndZone {
      19             :  public:
      20             :   struct RegisterTransfer {
      21             :     Bytecode bytecode;
      22             :     Register input;
      23             :     Register output;
      24             :   };
      25             : 
      26           8 :   BytecodeRegisterOptimizerTest() = default;
      27           8 :   ~BytecodeRegisterOptimizerTest() override { delete register_allocator_; }
      28             : 
      29           8 :   void Initialize(int number_of_parameters, int number_of_locals) {
      30          16 :     register_allocator_ = new BytecodeRegisterAllocator(number_of_locals);
      31             :     register_optimizer_ = new (zone())
      32             :         BytecodeRegisterOptimizer(zone(), register_allocator_, number_of_locals,
      33           8 :                                   number_of_parameters, this);
      34           8 :   }
      35             : 
      36           3 :   void EmitLdar(Register input) override {
      37           9 :     output_.push_back({Bytecode::kLdar, input, Register()});
      38           3 :   }
      39           5 :   void EmitStar(Register output) override {
      40          15 :     output_.push_back({Bytecode::kStar, Register(), output});
      41           5 :   }
      42           2 :   void EmitMov(Register input, Register output) override {
      43           4 :     output_.push_back({Bytecode::kMov, input, output});
      44           2 :   }
      45             : 
      46             :   BytecodeRegisterAllocator* allocator() { return register_allocator_; }
      47             :   BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; }
      48             : 
      49           7 :   Register NewTemporary() { return allocator()->NewRegister(); }
      50             : 
      51             :   void ReleaseTemporaries(Register reg) {
      52             :     allocator()->ReleaseRegisters(reg.index());
      53             :   }
      54             : 
      55             :   size_t write_count() const { return output_.size(); }
      56             :   const RegisterTransfer& last_written() const { return output_.back(); }
      57             :   const std::vector<RegisterTransfer>* output() { return &output_; }
      58             : 
      59             :  private:
      60             :   BytecodeRegisterAllocator* register_allocator_;
      61             :   BytecodeRegisterOptimizer* register_optimizer_;
      62             : 
      63             :   std::vector<RegisterTransfer> output_;
      64             : };
      65             : 
      66             : // Sanity tests.
      67             : 
      68       15418 : TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForFlush) {
      69           1 :   Initialize(1, 1);
      70             :   Register temp = NewTemporary();
      71             :   optimizer()->DoStar(temp);
      72           1 :   CHECK_EQ(write_count(), 0u);
      73           1 :   optimizer()->Flush();
      74           1 :   CHECK_EQ(write_count(), 1u);
      75           1 :   CHECK_EQ(output()->at(0).bytecode, Bytecode::kStar);
      76           1 :   CHECK_EQ(output()->at(0).output.index(), temp.index());
      77           1 : }
      78             : 
      79       15418 : TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForJump) {
      80           1 :   Initialize(1, 1);
      81             :   Register temp = NewTemporary();
      82             :   optimizer()->DoStar(temp);
      83           1 :   CHECK_EQ(write_count(), 0u);
      84             :   optimizer()->PrepareForBytecode<Bytecode::kJump, AccumulatorUse::kNone>();
      85           1 :   CHECK_EQ(write_count(), 1u);
      86           1 :   CHECK_EQ(output()->at(0).bytecode, Bytecode::kStar);
      87           1 :   CHECK_EQ(output()->at(0).output.index(), temp.index());
      88           1 : }
      89             : 
      90             : // Basic Register Optimizations
      91             : 
      92       15418 : TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) {
      93           1 :   Initialize(3, 1);
      94           1 :   Register parameter = Register::FromParameterIndex(1, 3);
      95             :   optimizer()->DoLdar(parameter);
      96           1 :   CHECK_EQ(write_count(), 0u);
      97             :   Register temp = NewTemporary();
      98             :   optimizer()->DoStar(temp);
      99             :   ReleaseTemporaries(temp);
     100           1 :   CHECK_EQ(write_count(), 0u);
     101             :   optimizer()->PrepareForBytecode<Bytecode::kReturn, AccumulatorUse::kRead>();
     102           1 :   CHECK_EQ(output()->at(0).bytecode, Bytecode::kLdar);
     103           1 :   CHECK_EQ(output()->at(0).input.index(), parameter.index());
     104           1 : }
     105             : 
     106       15418 : TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterUsed) {
     107           1 :   Initialize(3, 1);
     108             :   optimizer()->PrepareForBytecode<Bytecode::kLdaSmi, AccumulatorUse::kWrite>();
     109             :   Register temp0 = NewTemporary();
     110             :   Register temp1 = NewTemporary();
     111             :   optimizer()->DoStar(temp1);
     112           1 :   CHECK_EQ(write_count(), 0u);
     113             :   optimizer()->PrepareForBytecode<Bytecode::kLdaSmi, AccumulatorUse::kWrite>();
     114           1 :   CHECK_EQ(write_count(), 1u);
     115           1 :   CHECK_EQ(output()->at(0).bytecode, Bytecode::kStar);
     116           1 :   CHECK_EQ(output()->at(0).output.index(), temp1.index());
     117           1 :   optimizer()->DoMov(temp1, temp0);
     118           1 :   CHECK_EQ(write_count(), 1u);
     119             :   ReleaseTemporaries(temp1);
     120           1 :   CHECK_EQ(write_count(), 1u);
     121             :   optimizer()->DoLdar(temp0);
     122           1 :   CHECK_EQ(write_count(), 1u);
     123             :   optimizer()->PrepareForBytecode<Bytecode::kReturn, AccumulatorUse::kRead>();
     124           1 :   CHECK_EQ(write_count(), 2u);
     125           1 :   CHECK_EQ(output()->at(1).bytecode, Bytecode::kLdar);
     126           1 :   CHECK_EQ(output()->at(1).input.index(), temp1.index());
     127           1 : }
     128             : 
     129       15418 : TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterNotFlushed) {
     130           1 :   Initialize(3, 1);
     131             :   optimizer()->PrepareForBytecode<Bytecode::kLdaSmi, AccumulatorUse::kWrite>();
     132             :   Register temp0 = NewTemporary();
     133             :   Register temp1 = NewTemporary();
     134             :   optimizer()->DoStar(temp0);
     135           1 :   CHECK_EQ(write_count(), 0u);
     136             :   optimizer()->DoStar(temp1);
     137           1 :   CHECK_EQ(write_count(), 0u);
     138             :   ReleaseTemporaries(temp1);
     139           1 :   optimizer()->Flush();
     140           1 :   CHECK_EQ(write_count(), 1u);
     141           1 :   CHECK_EQ(output()->at(0).bytecode, Bytecode::kStar);
     142           1 :   CHECK_EQ(output()->at(0).output.index(), temp0.index());
     143           1 : }
     144             : 
     145       15418 : TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) {
     146           1 :   Initialize(3, 1);
     147           1 :   Register parameter = Register::FromParameterIndex(1, 3);
     148             :   optimizer()->DoLdar(parameter);
     149           1 :   CHECK_EQ(write_count(), 0u);
     150             :   Register local = Register(0);
     151             :   optimizer()->DoStar(local);
     152           1 :   CHECK_EQ(write_count(), 1u);
     153           1 :   CHECK_EQ(output()->at(0).bytecode, Bytecode::kMov);
     154           1 :   CHECK_EQ(output()->at(0).input.index(), parameter.index());
     155           1 :   CHECK_EQ(output()->at(0).output.index(), local.index());
     156             : 
     157             :   optimizer()->PrepareForBytecode<Bytecode::kReturn, AccumulatorUse::kRead>();
     158           1 :   CHECK_EQ(write_count(), 2u);
     159           1 :   CHECK_EQ(output()->at(1).bytecode, Bytecode::kLdar);
     160           1 :   CHECK_EQ(output()->at(1).input.index(), local.index());
     161           1 : }
     162             : 
     163       15418 : TEST_F(BytecodeRegisterOptimizerTest, SingleTemporaryNotMaterializedForInput) {
     164           1 :   Initialize(3, 1);
     165           1 :   Register parameter = Register::FromParameterIndex(1, 3);
     166             :   Register temp0 = NewTemporary();
     167           1 :   Register temp1 = NewTemporary();
     168           1 :   optimizer()->DoMov(parameter, temp0);
     169           1 :   optimizer()->DoMov(parameter, temp1);
     170           1 :   CHECK_EQ(write_count(), 0u);
     171             : 
     172           1 :   Register reg = optimizer()->GetInputRegister(temp0);
     173             :   RegisterList reg_list = optimizer()->GetInputRegisterList(
     174           1 :       BytecodeUtils::NewRegisterList(temp0.index(), 1));
     175           1 :   CHECK_EQ(write_count(), 0u);
     176           1 :   CHECK_EQ(parameter.index(), reg.index());
     177           1 :   CHECK_EQ(parameter.index(), reg_list.first_register().index());
     178           1 :   CHECK_EQ(1, reg_list.register_count());
     179           1 : }
     180             : 
     181       15418 : TEST_F(BytecodeRegisterOptimizerTest, RangeOfTemporariesMaterializedForInput) {
     182           1 :   Initialize(3, 1);
     183           1 :   Register parameter = Register::FromParameterIndex(1, 3);
     184             :   Register temp0 = NewTemporary();
     185             :   Register temp1 = NewTemporary();
     186             :   optimizer()->PrepareForBytecode<Bytecode::kLdaSmi, AccumulatorUse::kWrite>();
     187             :   optimizer()->DoStar(temp0);
     188           1 :   optimizer()->DoMov(parameter, temp1);
     189           1 :   CHECK_EQ(write_count(), 0u);
     190             : 
     191             :   optimizer()
     192             :       ->PrepareForBytecode<Bytecode::kCallJSRuntime, AccumulatorUse::kWrite>();
     193             :   RegisterList reg_list = optimizer()->GetInputRegisterList(
     194           1 :       BytecodeUtils::NewRegisterList(temp0.index(), 2));
     195           1 :   CHECK_EQ(temp0.index(), reg_list.first_register().index());
     196           1 :   CHECK_EQ(2, reg_list.register_count());
     197           1 :   CHECK_EQ(write_count(), 2u);
     198           1 :   CHECK_EQ(output()->at(0).bytecode, Bytecode::kStar);
     199           1 :   CHECK_EQ(output()->at(0).output.index(), temp0.index());
     200           1 :   CHECK_EQ(output()->at(1).bytecode, Bytecode::kMov);
     201           1 :   CHECK_EQ(output()->at(1).input.index(), parameter.index());
     202           1 :   CHECK_EQ(output()->at(1).output.index(), temp1.index());
     203           1 : }
     204             : 
     205             : }  // namespace interpreter
     206             : }  // namespace internal
     207        9249 : }  // namespace v8

Generated by: LCOV version 1.10