LCOV - code coverage report
Current view: top level - test/unittests/compiler - instruction-sequence-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 238 256 93.0 %
Date: 2017-10-20 Functions: 39 46 84.8 %

          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/base/utils/random-number-generator.h"
       6             : #include "src/compiler/pipeline.h"
       7             : #include "test/unittests/compiler/instruction-sequence-unittest.h"
       8             : #include "test/unittests/test-utils.h"
       9             : #include "testing/gmock/include/gmock/gmock.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : namespace compiler {
      14             : 
      15             : static const char*
      16             :     general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
      17             : static const char*
      18             :     double_register_names_[RegisterConfiguration::kMaxFPRegisters];
      19             : static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
      20             :                                   RegisterConfiguration::kMaxFPRegisters)];
      21             : 
      22             : namespace {
      23             : static int allocatable_codes[InstructionSequenceTest::kDefaultNRegs] = {
      24             :     0, 1, 2, 3, 4, 5, 6, 7};
      25             : }
      26             : 
      27          52 : static void InitializeRegisterNames() {
      28             :   char* loc = register_names_;
      29        1716 :   for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
      30        1664 :     general_register_names_[i] = loc;
      31        1664 :     loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
      32        1664 :     *loc++ = 0;
      33             :   }
      34        1664 :   for (int i = 0; i < RegisterConfiguration::kMaxFPRegisters; ++i) {
      35        1664 :     double_register_names_[i] = loc;
      36        1664 :     loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
      37        1664 :     *loc++ = 0;
      38             :   }
      39          52 : }
      40             : 
      41          52 : InstructionSequenceTest::InstructionSequenceTest()
      42             :     : sequence_(nullptr),
      43             :       num_general_registers_(kDefaultNRegs),
      44             :       num_double_registers_(kDefaultNRegs),
      45             :       instruction_blocks_(zone()),
      46             :       current_block_(nullptr),
      47         104 :       block_returns_(false) {
      48          52 :   InitializeRegisterNames();
      49          52 : }
      50             : 
      51             : 
      52           3 : void InstructionSequenceTest::SetNumRegs(int num_general_registers,
      53             :                                          int num_double_registers) {
      54           3 :   CHECK(!config_);
      55           3 :   CHECK(instructions_.empty());
      56           3 :   CHECK(instruction_blocks_.empty());
      57           3 :   num_general_registers_ = num_general_registers;
      58           3 :   num_double_registers_ = num_double_registers;
      59           3 : }
      60             : 
      61         258 : int InstructionSequenceTest::GetNumRegs(MachineRepresentation rep) {
      62         258 :   switch (rep) {
      63             :     case MachineRepresentation::kFloat32:
      64          30 :       return config()->num_float_registers();
      65             :     case MachineRepresentation::kFloat64:
      66          34 :       return config()->num_double_registers();
      67             :     case MachineRepresentation::kSimd128:
      68          31 :       return config()->num_simd128_registers();
      69             :     default:
      70         163 :       return config()->num_general_registers();
      71             :   }
      72             : }
      73             : 
      74           8 : int InstructionSequenceTest::GetAllocatableCode(int index,
      75             :                                                 MachineRepresentation rep) {
      76           8 :   switch (rep) {
      77             :     case MachineRepresentation::kFloat32:
      78           4 :       return config()->GetAllocatableFloatCode(index);
      79             :     case MachineRepresentation::kFloat64:
      80           4 :       return config()->GetAllocatableDoubleCode(index);
      81             :     case MachineRepresentation::kSimd128:
      82           4 :       return config()->GetAllocatableSimd128Code(index);
      83             :     default:
      84           4 :       return config()->GetAllocatableGeneralCode(index);
      85             :   }
      86             : }
      87             : 
      88         360 : const RegisterConfiguration* InstructionSequenceTest::config() {
      89         360 :   if (!config_) {
      90             :     config_.reset(new RegisterConfiguration(
      91             :         num_general_registers_, num_double_registers_, num_general_registers_,
      92             :         num_double_registers_, allocatable_codes, allocatable_codes,
      93             :         kSimpleFPAliasing ? RegisterConfiguration::OVERLAP
      94             :                           : RegisterConfiguration::COMBINE,
      95             :         general_register_names_,
      96             :         double_register_names_,  // float register names
      97             :         double_register_names_,
      98          52 :         double_register_names_));  // SIMD 128 register names
      99             :   }
     100         360 :   return config_.get();
     101             : }
     102             : 
     103             : 
     104        1217 : InstructionSequence* InstructionSequenceTest::sequence() {
     105        1217 :   if (sequence_ == nullptr) {
     106             :     sequence_ = new (zone())
     107         104 :         InstructionSequence(isolate(), zone(), &instruction_blocks_);
     108             :     sequence_->SetRegisterConfigurationForTesting(
     109          52 :         InstructionSequenceTest::config());
     110             :   }
     111        1217 :   return sequence_;
     112             : }
     113             : 
     114             : 
     115           3 : void InstructionSequenceTest::StartLoop(int loop_blocks) {
     116           3 :   CHECK_NULL(current_block_);
     117           3 :   if (!loop_blocks_.empty()) {
     118           0 :     CHECK(!loop_blocks_.back().loop_header_.IsValid());
     119             :   }
     120           3 :   LoopData loop_data = {Rpo::Invalid(), loop_blocks};
     121           3 :   loop_blocks_.push_back(loop_data);
     122           3 : }
     123             : 
     124             : 
     125           3 : void InstructionSequenceTest::EndLoop() {
     126           3 :   CHECK_NULL(current_block_);
     127           3 :   CHECK(!loop_blocks_.empty());
     128           3 :   CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
     129             :   loop_blocks_.pop_back();
     130           3 : }
     131             : 
     132             : 
     133         122 : void InstructionSequenceTest::StartBlock(bool deferred) {
     134         122 :   block_returns_ = false;
     135         122 :   NewBlock(deferred);
     136         122 : }
     137             : 
     138             : 
     139         122 : Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) {
     140             :   Instruction* result = nullptr;
     141         122 :   if (block_returns_) {
     142          16 :     CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
     143          16 :     completion.type_ = kBlockEnd;
     144             :   }
     145         122 :   switch (completion.type_) {
     146             :     case kBlockEnd:
     147             :       break;
     148             :     case kFallThrough:
     149          17 :       result = EmitJump();
     150          17 :       break;
     151             :     case kJump:
     152          33 :       CHECK(!block_returns_);
     153          33 :       result = EmitJump();
     154          33 :       break;
     155             :     case kBranch:
     156          22 :       CHECK(!block_returns_);
     157          22 :       result = EmitBranch(completion.op_);
     158          22 :       break;
     159             :   }
     160         122 :   completions_.push_back(completion);
     161         122 :   CHECK_NOT_NULL(current_block_);
     162         122 :   sequence()->EndBlock(current_block_->rpo_number());
     163         122 :   current_block_ = nullptr;
     164         122 :   return result;
     165             : }
     166             : 
     167             : 
     168          11 : InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) {
     169          11 :   return TestOperand(kImmediate, imm);
     170             : }
     171             : 
     172             : 
     173          87 : InstructionSequenceTest::VReg InstructionSequenceTest::Define(
     174          87 :     TestOperand output_op) {
     175          87 :   VReg vreg = NewReg(output_op);
     176          87 :   InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)};
     177          87 :   Emit(kArchNop, 1, outputs);
     178          87 :   return vreg;
     179             : }
     180             : 
     181          16 : Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) {
     182          16 :   block_returns_ = true;
     183          16 :   InstructionOperand inputs[1]{ConvertInputOp(input_op_0)};
     184          16 :   return Emit(kArchRet, 0, nullptr, 1, inputs);
     185             : }
     186             : 
     187             : 
     188          49 : PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
     189             :                                              VReg incoming_vreg_1,
     190             :                                              VReg incoming_vreg_2,
     191             :                                              VReg incoming_vreg_3) {
     192             :   VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2,
     193          49 :                    incoming_vreg_3};
     194             :   size_t input_count = 0;
     195         138 :   for (; input_count < arraysize(inputs); ++input_count) {
     196         138 :     if (inputs[input_count].value_ == kNoValue) break;
     197             :   }
     198          49 :   CHECK_LT(0, input_count);
     199          98 :   auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, input_count);
     200         138 :   for (size_t i = 0; i < input_count; ++i) {
     201          89 :     SetInput(phi, i, inputs[i]);
     202             :   }
     203          49 :   current_block_->AddPhi(phi);
     204          49 :   return phi;
     205             : }
     206             : 
     207             : 
     208           5 : PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
     209             :                                              size_t input_count) {
     210          10 :   auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, input_count);
     211           5 :   SetInput(phi, 0, incoming_vreg_0);
     212           5 :   current_block_->AddPhi(phi);
     213           5 :   return phi;
     214             : }
     215             : 
     216             : 
     217          99 : void InstructionSequenceTest::SetInput(PhiInstruction* phi, size_t input,
     218             :                                        VReg vreg) {
     219          99 :   CHECK_NE(kNoValue, vreg.value_);
     220          99 :   phi->SetInput(input, vreg.value_);
     221          99 : }
     222             : 
     223             : 
     224          62 : InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
     225             :     int32_t imm) {
     226          62 :   VReg vreg = NewReg();
     227         124 :   sequence()->AddConstant(vreg.value_, Constant(imm));
     228          62 :   InstructionOperand outputs[1]{ConstantOperand(vreg.value_)};
     229          62 :   Emit(kArchNop, 1, outputs);
     230          62 :   return vreg;
     231             : }
     232             : 
     233             : 
     234           9 : Instruction* InstructionSequenceTest::EmitNop() { return Emit(kArchNop); }
     235             : 
     236             : 
     237             : static size_t CountInputs(size_t size,
     238             :                           InstructionSequenceTest::TestOperand* inputs) {
     239             :   size_t i = 0;
     240          78 :   for (; i < size; ++i) {
     241         136 :     if (inputs[i].type_ == InstructionSequenceTest::kInvalid) break;
     242             :   }
     243             :   return i;
     244             : }
     245             : 
     246             : 
     247          38 : Instruction* InstructionSequenceTest::EmitI(size_t input_size,
     248             :                                             TestOperand* inputs) {
     249          38 :   InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
     250          38 :   return Emit(kArchNop, 0, nullptr, input_size, mapped_inputs);
     251             : }
     252             : 
     253             : 
     254          38 : Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0,
     255             :                                             TestOperand input_op_1,
     256             :                                             TestOperand input_op_2,
     257             :                                             TestOperand input_op_3) {
     258          38 :   TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
     259          38 :   return EmitI(CountInputs(arraysize(inputs), inputs), inputs);
     260             : }
     261             : 
     262             : 
     263          19 : InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
     264          19 :     TestOperand output_op, size_t input_size, TestOperand* inputs) {
     265          19 :   VReg output_vreg = NewReg(output_op);
     266          19 :   InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
     267          19 :   InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
     268          19 :   Emit(kArchNop, 1, outputs, input_size, mapped_inputs);
     269          19 :   return output_vreg;
     270             : }
     271             : 
     272             : 
     273          16 : InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
     274             :     TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
     275             :     TestOperand input_op_2, TestOperand input_op_3) {
     276          16 :   TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
     277          16 :   return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs);
     278             : }
     279             : 
     280             : 
     281           1 : InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
     282           2 :     TestOperand output_op_0, TestOperand output_op_1, size_t input_size,
     283             :     TestOperand* inputs) {
     284             :   VRegPair output_vregs =
     285           3 :       std::make_pair(NewReg(output_op_0), NewReg(output_op_1));
     286             :   InstructionOperand outputs[2]{
     287             :       ConvertOutputOp(output_vregs.first, output_op_0),
     288           1 :       ConvertOutputOp(output_vregs.second, output_op_1)};
     289           1 :   InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
     290           1 :   Emit(kArchNop, 2, outputs, input_size, mapped_inputs);
     291           1 :   return output_vregs;
     292             : }
     293             : 
     294             : 
     295           1 : InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
     296             :     TestOperand output_op_0, TestOperand output_op_1, TestOperand input_op_0,
     297             :     TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) {
     298           1 :   TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
     299             :   return EmitOOI(output_op_0, output_op_1,
     300           1 :                  CountInputs(arraysize(inputs), inputs), inputs);
     301             : }
     302             : 
     303             : 
     304          10 : InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
     305          10 :     TestOperand output_op, size_t input_size, TestOperand* inputs) {
     306          10 :   VReg output_vreg = NewReg(output_op);
     307          10 :   InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
     308          10 :   CHECK(UnallocatedOperand::cast(outputs[0]).HasFixedPolicy());
     309          10 :   InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
     310             :   Emit(kArchCallCodeObject, 1, outputs, input_size, mapped_inputs, 0, nullptr,
     311          10 :        true);
     312          10 :   return output_vreg;
     313             : }
     314             : 
     315             : 
     316           7 : InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
     317             :     TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
     318             :     TestOperand input_op_2, TestOperand input_op_3) {
     319           7 :   TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
     320           7 :   return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs);
     321             : }
     322             : 
     323             : 
     324          22 : Instruction* InstructionSequenceTest::EmitBranch(TestOperand input_op) {
     325             :   InstructionOperand inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()),
     326          88 :                                ConvertInputOp(Imm()), ConvertInputOp(Imm())};
     327             :   InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
     328             :                            FlagsConditionField::encode(kEqual);
     329          22 :   auto instruction = NewInstruction(opcode, 0, nullptr, 4, inputs);
     330          22 :   return AddInstruction(instruction);
     331             : }
     332             : 
     333             : 
     334           0 : Instruction* InstructionSequenceTest::EmitFallThrough() {
     335           0 :   auto instruction = NewInstruction(kArchNop, 0, nullptr);
     336           0 :   return AddInstruction(instruction);
     337             : }
     338             : 
     339             : 
     340          50 : Instruction* InstructionSequenceTest::EmitJump() {
     341          50 :   InstructionOperand inputs[1]{ConvertInputOp(Imm())};
     342          50 :   auto instruction = NewInstruction(kArchJmp, 0, nullptr, 1, inputs);
     343          50 :   return AddInstruction(instruction);
     344             : }
     345             : 
     346             : 
     347         314 : Instruction* InstructionSequenceTest::NewInstruction(
     348             :     InstructionCode code, size_t outputs_size, InstructionOperand* outputs,
     349             :     size_t inputs_size, InstructionOperand* inputs, size_t temps_size,
     350             :     InstructionOperand* temps) {
     351         314 :   CHECK(current_block_);
     352             :   return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
     353         314 :                           inputs, temps_size, temps);
     354             : }
     355             : 
     356             : 
     357           0 : InstructionOperand InstructionSequenceTest::Unallocated(
     358             :     TestOperand op, UnallocatedOperand::ExtendedPolicy policy) {
     359           0 :   return UnallocatedOperand(policy, op.vreg_.value_);
     360             : }
     361             : 
     362             : 
     363           0 : InstructionOperand InstructionSequenceTest::Unallocated(
     364             :     TestOperand op, UnallocatedOperand::ExtendedPolicy policy,
     365             :     UnallocatedOperand::Lifetime lifetime) {
     366           0 :   return UnallocatedOperand(policy, lifetime, op.vreg_.value_);
     367             : }
     368             : 
     369             : 
     370           0 : InstructionOperand InstructionSequenceTest::Unallocated(
     371             :     TestOperand op, UnallocatedOperand::ExtendedPolicy policy, int index) {
     372           0 :   return UnallocatedOperand(policy, index, op.vreg_.value_);
     373             : }
     374             : 
     375             : 
     376           0 : InstructionOperand InstructionSequenceTest::Unallocated(
     377             :     TestOperand op, UnallocatedOperand::BasicPolicy policy, int index) {
     378           0 :   return UnallocatedOperand(policy, index, op.vreg_.value_);
     379             : }
     380             : 
     381             : 
     382          68 : InstructionOperand* InstructionSequenceTest::ConvertInputs(
     383             :     size_t input_size, TestOperand* inputs) {
     384             :   InstructionOperand* mapped_inputs =
     385          68 :       zone()->NewArray<InstructionOperand>(static_cast<int>(input_size));
     386         200 :   for (size_t i = 0; i < input_size; ++i) {
     387         132 :     mapped_inputs[i] = ConvertInputOp(inputs[i]);
     388             :   }
     389          68 :   return mapped_inputs;
     390             : }
     391             : 
     392             : 
     393         286 : InstructionOperand InstructionSequenceTest::ConvertInputOp(TestOperand op) {
     394         286 :   if (op.type_ == kImmediate) {
     395         127 :     CHECK_EQ(op.vreg_.value_, kNoValue);
     396         127 :     return ImmediateOperand(ImmediateOperand::INLINE, op.value_);
     397             :   }
     398         159 :   CHECK_NE(op.vreg_.value_, kNoValue);
     399         159 :   switch (op.type_) {
     400             :     case kNone:
     401             :       return Unallocated(op, UnallocatedOperand::NONE,
     402             :                          UnallocatedOperand::USED_AT_START);
     403             :     case kUnique:
     404             :       return Unallocated(op, UnallocatedOperand::NONE);
     405             :     case kUniqueRegister:
     406             :       return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
     407             :     case kRegister:
     408             :       return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
     409             :                          UnallocatedOperand::USED_AT_START);
     410             :     case kSlot:
     411             :       return Unallocated(op, UnallocatedOperand::MUST_HAVE_SLOT,
     412             :                          UnallocatedOperand::USED_AT_START);
     413             :     case kFixedRegister: {
     414             :       MachineRepresentation rep = GetCanonicalRep(op);
     415          37 :       CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
     416          37 :       if (DoesRegisterAllocation()) {
     417             :         auto extended_policy = IsFloatingPoint(rep)
     418             :                                    ? UnallocatedOperand::FIXED_FP_REGISTER
     419          37 :                                    : UnallocatedOperand::FIXED_REGISTER;
     420             :         return Unallocated(op, extended_policy, op.value_);
     421             :       } else {
     422           0 :         return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
     423             :       }
     424             :     }
     425             :     case kFixedSlot:
     426          12 :       if (DoesRegisterAllocation()) {
     427             :         return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
     428             :       } else {
     429             :         return AllocatedOperand(LocationOperand::STACK_SLOT,
     430             :                                 GetCanonicalRep(op), op.value_);
     431             :       }
     432             :     default:
     433             :       break;
     434             :   }
     435           0 :   CHECK(false);
     436             :   return InstructionOperand();
     437             : }
     438             : 
     439             : 
     440         118 : InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg,
     441             :                                                             TestOperand op) {
     442         118 :   CHECK_EQ(op.vreg_.value_, kNoValue);
     443         118 :   op.vreg_ = vreg;
     444         118 :   switch (op.type_) {
     445             :     case kSameAsFirst:
     446             :       return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
     447             :     case kRegister:
     448             :       return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
     449             :     case kFixedSlot:
     450          39 :       if (DoesRegisterAllocation()) {
     451             :         return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
     452             :       } else {
     453             :         return AllocatedOperand(LocationOperand::STACK_SLOT,
     454           0 :                                 GetCanonicalRep(op), op.value_);
     455             :       }
     456             :     case kFixedRegister: {
     457             :       MachineRepresentation rep = GetCanonicalRep(op);
     458          55 :       CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
     459          55 :       if (DoesRegisterAllocation()) {
     460             :         auto extended_policy = IsFloatingPoint(rep)
     461             :                                    ? UnallocatedOperand::FIXED_FP_REGISTER
     462          53 :                                    : UnallocatedOperand::FIXED_REGISTER;
     463             :         return Unallocated(op, extended_policy, op.value_);
     464             :       } else {
     465           2 :         return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
     466             :       }
     467             :     }
     468             :     default:
     469             :       break;
     470             :   }
     471           0 :   CHECK(false);
     472             :   return InstructionOperand();
     473             : }
     474             : 
     475             : 
     476         174 : InstructionBlock* InstructionSequenceTest::NewBlock(bool deferred) {
     477         174 :   CHECK_NULL(current_block_);
     478         348 :   Rpo rpo = Rpo::FromInt(static_cast<int>(instruction_blocks_.size()));
     479             :   Rpo loop_header = Rpo::Invalid();
     480             :   Rpo loop_end = Rpo::Invalid();
     481         174 :   if (!loop_blocks_.empty()) {
     482             :     auto& loop_data = loop_blocks_.back();
     483             :     // This is a loop header.
     484           4 :     if (!loop_data.loop_header_.IsValid()) {
     485           3 :       loop_end = Rpo::FromInt(rpo.ToInt() + loop_data.expected_blocks_);
     486           3 :       loop_data.expected_blocks_--;
     487           3 :       loop_data.loop_header_ = rpo;
     488             :     } else {
     489             :       // This is a loop body.
     490           1 :       CHECK_NE(0, loop_data.expected_blocks_);
     491             :       // TODO(dcarney): handle nested loops.
     492           1 :       loop_data.expected_blocks_--;
     493           1 :       loop_header = loop_data.loop_header_;
     494             :     }
     495             :   }
     496             :   // Construct instruction block.
     497             :   auto instruction_block = new (zone())
     498         348 :       InstructionBlock(zone(), rpo, loop_header, loop_end, deferred, false);
     499         174 :   instruction_blocks_.push_back(instruction_block);
     500         174 :   current_block_ = instruction_block;
     501         174 :   sequence()->StartBlock(rpo);
     502         174 :   return instruction_block;
     503             : }
     504             : 
     505             : 
     506          52 : void InstructionSequenceTest::WireBlocks() {
     507          52 :   CHECK(!current_block());
     508         206 :   CHECK(instruction_blocks_.size() == completions_.size());
     509          52 :   CHECK(loop_blocks_.empty());
     510             :   // Wire in end block to look like a scheduler produced cfg.
     511          52 :   auto end_block = NewBlock();
     512          52 :   current_block_ = nullptr;
     513          52 :   sequence()->EndBlock(end_block->rpo_number());
     514             :   size_t offset = 0;
     515         226 :   for (const auto& completion : completions_) {
     516         122 :     switch (completion.type_) {
     517             :       case kBlockEnd: {
     518          50 :         auto block = instruction_blocks_[offset];
     519         100 :         block->successors().push_back(end_block->rpo_number());
     520         100 :         end_block->predecessors().push_back(block->rpo_number());
     521          50 :         break;
     522             :       }
     523             :       case kFallThrough:  // Fallthrough.
     524             :       case kJump:
     525          50 :         WireBlock(offset, completion.offset_0_);
     526          50 :         break;
     527             :       case kBranch:
     528          22 :         WireBlock(offset, completion.offset_0_);
     529          22 :         WireBlock(offset, completion.offset_1_);
     530          22 :         break;
     531             :     }
     532         122 :     ++offset;
     533             :   }
     534          52 : }
     535             : 
     536             : 
     537          94 : void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
     538          94 :   size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset);
     539         188 :   CHECK(block_offset < instruction_blocks_.size());
     540          94 :   CHECK(target_block_offset < instruction_blocks_.size());
     541          94 :   auto block = instruction_blocks_[block_offset];
     542          94 :   auto target = instruction_blocks_[target_block_offset];
     543         188 :   block->successors().push_back(target->rpo_number());
     544         188 :   target->predecessors().push_back(block->rpo_number());
     545          94 : }
     546             : 
     547             : 
     548         242 : Instruction* InstructionSequenceTest::Emit(
     549             :     InstructionCode code, size_t outputs_size, InstructionOperand* outputs,
     550             :     size_t inputs_size, InstructionOperand* inputs, size_t temps_size,
     551             :     InstructionOperand* temps, bool is_call) {
     552             :   auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
     553         242 :                                     inputs, temps_size, temps);
     554         242 :   if (is_call) instruction->MarkAsCall();
     555         242 :   return AddInstruction(instruction);
     556             : }
     557             : 
     558             : 
     559           0 : Instruction* InstructionSequenceTest::AddInstruction(Instruction* instruction) {
     560         314 :   sequence()->AddInstruction(instruction);
     561           0 :   return instruction;
     562             : }
     563             : 
     564             : }  // namespace compiler
     565             : }  // namespace internal
     566        7893 : }  // namespace v8

Generated by: LCOV version 1.10