instruction-sequence-unittest.cc 20.3 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "test/unittests/compiler/backend/instruction-sequence-unittest.h"
6 7 8 9 10 11 12 13 14
#include "src/base/utils/random-number-generator.h"
#include "src/compiler/pipeline.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"

namespace v8 {
namespace internal {
namespace compiler {

15
namespace {
16
constexpr int kMaxNumAllocatable =
17
    std::max(Register::kNumRegisters, DoubleRegister::kNumRegisters);
18 19 20
static std::array<int, kMaxNumAllocatable> kAllocatableCodes =
    base::make_array<kMaxNumAllocatable>(
        [](size_t i) { return static_cast<int>(i); });
21 22 23 24
}

InstructionSequenceTest::InstructionSequenceTest()
    : sequence_(nullptr),
25 26
      num_general_registers_(Register::kNumRegisters),
      num_double_registers_(DoubleRegister::kNumRegisters),
27 28
      instruction_blocks_(zone()),
      current_block_(nullptr),
29
      block_returns_(false) {}
30 31 32

void InstructionSequenceTest::SetNumRegs(int num_general_registers,
                                         int num_double_registers) {
33
  CHECK(!config_);
34 35
  CHECK(instructions_.empty());
  CHECK(instruction_blocks_.empty());
36 37
  CHECK_GE(Register::kNumRegisters, num_general_registers);
  CHECK_GE(DoubleRegister::kNumRegisters, num_double_registers);
38 39 40 41
  num_general_registers_ = num_general_registers;
  num_double_registers_ = num_double_registers;
}

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
int InstructionSequenceTest::GetNumRegs(MachineRepresentation rep) {
  switch (rep) {
    case MachineRepresentation::kFloat32:
      return config()->num_float_registers();
    case MachineRepresentation::kFloat64:
      return config()->num_double_registers();
    case MachineRepresentation::kSimd128:
      return config()->num_simd128_registers();
    default:
      return config()->num_general_registers();
  }
}

int InstructionSequenceTest::GetAllocatableCode(int index,
                                                MachineRepresentation rep) {
  switch (rep) {
    case MachineRepresentation::kFloat32:
      return config()->GetAllocatableFloatCode(index);
    case MachineRepresentation::kFloat64:
      return config()->GetAllocatableDoubleCode(index);
    case MachineRepresentation::kSimd128:
      return config()->GetAllocatableSimd128Code(index);
    default:
      return config()->GetAllocatableGeneralCode(index);
  }
}
68

69
const RegisterConfiguration* InstructionSequenceTest::config() {
70 71 72
  if (!config_) {
    config_.reset(new RegisterConfiguration(
        num_general_registers_, num_double_registers_, num_general_registers_,
73 74
        num_double_registers_, kAllocatableCodes.data(),
        kAllocatableCodes.data(),
75
        kSimpleFPAliasing ? RegisterConfiguration::OVERLAP
76
                          : RegisterConfiguration::COMBINE));
77 78
  }
  return config_.get();
79 80 81 82
}

InstructionSequence* InstructionSequenceTest::sequence() {
  if (sequence_ == nullptr) {
83 84
    sequence_ = zone()->New<InstructionSequence>(isolate(), zone(),
                                                 &instruction_blocks_);
85 86
    sequence_->SetRegisterConfigurationForTesting(
        InstructionSequenceTest::config());
87 88 89 90 91
  }
  return sequence_;
}

void InstructionSequenceTest::StartLoop(int loop_blocks) {
92
  CHECK_NULL(current_block_);
93 94 95 96 97 98 99 100
  if (!loop_blocks_.empty()) {
    CHECK(!loop_blocks_.back().loop_header_.IsValid());
  }
  LoopData loop_data = {Rpo::Invalid(), loop_blocks};
  loop_blocks_.push_back(loop_data);
}

void InstructionSequenceTest::EndLoop() {
101
  CHECK_NULL(current_block_);
102 103 104 105 106
  CHECK(!loop_blocks_.empty());
  CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
  loop_blocks_.pop_back();
}

107
void InstructionSequenceTest::StartBlock(bool deferred) {
108
  block_returns_ = false;
109
  NewBlock(deferred);
110 111
}

dcarney's avatar
dcarney committed
112 113
Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) {
  Instruction* result = nullptr;
114 115 116 117 118 119 120 121
  if (block_returns_) {
    CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
    completion.type_ = kBlockEnd;
  }
  switch (completion.type_) {
    case kBlockEnd:
      break;
    case kFallThrough:
122
      result = EmitJump(completion.op_);
123 124 125
      break;
    case kJump:
      CHECK(!block_returns_);
126
      result = EmitJump(completion.op_);
127 128 129
      break;
    case kBranch:
      CHECK(!block_returns_);
dcarney's avatar
dcarney committed
130
      result = EmitBranch(completion.op_);
131 132 133
      break;
  }
  completions_.push_back(completion);
134
  CHECK_NOT_NULL(current_block_);
135 136 137 138
  int end = static_cast<int>(sequence()->instructions().size());
  if (current_block_->code_start() == end) {  // Empty block.  Insert a nop.
    sequence()->AddInstruction(Instruction::New(zone(), kArchNop));
  }
139 140
  sequence()->EndBlock(current_block_->rpo_number());
  current_block_ = nullptr;
dcarney's avatar
dcarney committed
141
  return result;
142 143 144
}

InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) {
145
  return TestOperand(kImmediate, imm);
146 147 148 149
}

InstructionSequenceTest::VReg InstructionSequenceTest::Define(
    TestOperand output_op) {
150
  VReg vreg = NewReg(output_op);
151
  InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)};
dcarney's avatar
dcarney committed
152
  Emit(kArchNop, 1, outputs);
153 154 155
  return vreg;
}

dcarney's avatar
dcarney committed
156
Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) {
157
  block_returns_ = true;
158
  InstructionOperand inputs[1]{ConvertInputOp(input_op_0)};
dcarney's avatar
dcarney committed
159
  return Emit(kArchRet, 0, nullptr, 1, inputs);
160 161 162 163 164 165 166 167
}

PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
                                             VReg incoming_vreg_1,
                                             VReg incoming_vreg_2,
                                             VReg incoming_vreg_3) {
  VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2,
                   incoming_vreg_3};
168 169 170
  size_t input_count = 0;
  for (; input_count < arraysize(inputs); ++input_count) {
    if (inputs[input_count].value_ == kNoValue) break;
171
  }
172
  CHECK_LT(0, input_count);
173
  auto phi = zone()->New<PhiInstruction>(zone(), NewReg().value_, input_count);
174 175 176 177 178 179 180 181 182
  for (size_t i = 0; i < input_count; ++i) {
    SetInput(phi, i, inputs[i]);
  }
  current_block_->AddPhi(phi);
  return phi;
}

PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
                                             size_t input_count) {
183
  auto phi = zone()->New<PhiInstruction>(zone(), NewReg().value_, input_count);
184
  SetInput(phi, 0, incoming_vreg_0);
185 186 187 188
  current_block_->AddPhi(phi);
  return phi;
}

189 190
void InstructionSequenceTest::SetInput(PhiInstruction* phi, size_t input,
                                       VReg vreg) {
191
  CHECK_NE(kNoValue, vreg.value_);
192
  phi->SetInput(input, vreg.value_);
193 194 195 196 197 198
}

InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
    int32_t imm) {
  VReg vreg = NewReg();
  sequence()->AddConstant(vreg.value_, Constant(imm));
199
  InstructionOperand outputs[1]{ConstantOperand(vreg.value_)};
dcarney's avatar
dcarney committed
200
  Emit(kArchNop, 1, outputs);
201 202 203
  return vreg;
}

dcarney's avatar
dcarney committed
204
Instruction* InstructionSequenceTest::EmitNop() { return Emit(kArchNop); }
205

206 207 208 209 210 211 212 213 214
static size_t CountInputs(size_t size,
                          InstructionSequenceTest::TestOperand* inputs) {
  size_t i = 0;
  for (; i < size; ++i) {
    if (inputs[i].type_ == InstructionSequenceTest::kInvalid) break;
  }
  return i;
}

dcarney's avatar
dcarney committed
215 216
Instruction* InstructionSequenceTest::EmitI(size_t input_size,
                                            TestOperand* inputs) {
217
  InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
dcarney's avatar
dcarney committed
218
  return Emit(kArchNop, 0, nullptr, input_size, mapped_inputs);
219 220
}

dcarney's avatar
dcarney committed
221 222 223 224
Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0,
                                            TestOperand input_op_1,
                                            TestOperand input_op_2,
                                            TestOperand input_op_3) {
225 226
  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
  return EmitI(CountInputs(arraysize(inputs), inputs), inputs);
227 228 229
}

InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
230
    TestOperand output_op, size_t input_size, TestOperand* inputs) {
231
  VReg output_vreg = NewReg(output_op);
232 233
  InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
  InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
dcarney's avatar
dcarney committed
234
  Emit(kArchNop, 1, outputs, input_size, mapped_inputs);
235 236 237
  return output_vreg;
}

238 239 240 241 242
InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
    TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
    TestOperand input_op_2, TestOperand input_op_3) {
  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
  return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs);
243 244
}

dcarney's avatar
dcarney committed
245 246 247
InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
    TestOperand output_op_0, TestOperand output_op_1, size_t input_size,
    TestOperand* inputs) {
248 249
  VRegPair output_vregs =
      std::make_pair(NewReg(output_op_0), NewReg(output_op_1));
dcarney's avatar
dcarney committed
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
  InstructionOperand outputs[2]{
      ConvertOutputOp(output_vregs.first, output_op_0),
      ConvertOutputOp(output_vregs.second, output_op_1)};
  InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
  Emit(kArchNop, 2, outputs, input_size, mapped_inputs);
  return output_vregs;
}

InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
    TestOperand output_op_0, TestOperand output_op_1, TestOperand input_op_0,
    TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) {
  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
  return EmitOOI(output_op_0, output_op_1,
                 CountInputs(arraysize(inputs), inputs), inputs);
}

266 267
InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
    TestOperand output_op, size_t input_size, TestOperand* inputs) {
268
  VReg output_vreg = NewReg(output_op);
269 270 271
  InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
  CHECK(UnallocatedOperand::cast(outputs[0]).HasFixedPolicy());
  InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
dcarney's avatar
dcarney committed
272 273
  Emit(kArchCallCodeObject, 1, outputs, input_size, mapped_inputs, 0, nullptr,
       true);
274 275 276 277 278 279 280
  return output_vreg;
}

InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
    TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
    TestOperand input_op_2, TestOperand input_op_3) {
  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
281
  return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs);
282 283
}

dcarney's avatar
dcarney committed
284
Instruction* InstructionSequenceTest::EmitBranch(TestOperand input_op) {
285 286
  InstructionOperand inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()),
                               ConvertInputOp(Imm()), ConvertInputOp(Imm())};
287 288
  InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
                           FlagsConditionField::encode(kEqual);
289
  auto instruction = NewInstruction(opcode, 0, nullptr, 4, inputs);
dcarney's avatar
dcarney committed
290
  return AddInstruction(instruction);
291 292
}

dcarney's avatar
dcarney committed
293
Instruction* InstructionSequenceTest::EmitFallThrough() {
294
  auto instruction = NewInstruction(kArchNop, 0, nullptr);
dcarney's avatar
dcarney committed
295
  return AddInstruction(instruction);
296 297
}

298 299
Instruction* InstructionSequenceTest::EmitJump(TestOperand input_op) {
  InstructionOperand inputs[1]{ConvertInputOp(input_op)};
300
  auto instruction = NewInstruction(kArchJmp, 0, nullptr, 1, inputs);
dcarney's avatar
dcarney committed
301
  return AddInstruction(instruction);
302 303 304
}

Instruction* InstructionSequenceTest::NewInstruction(
305 306 307
    InstructionCode code, size_t outputs_size, InstructionOperand* outputs,
    size_t inputs_size, InstructionOperand* inputs, size_t temps_size,
    InstructionOperand* temps) {
308
  CHECK(current_block_);
309 310 311 312
  return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
                          inputs, temps_size, temps);
}

313
InstructionOperand InstructionSequenceTest::Unallocated(
314
    TestOperand op, UnallocatedOperand::ExtendedPolicy policy) {
315
  return UnallocatedOperand(policy, op.vreg_.value_);
316 317
}

318
InstructionOperand InstructionSequenceTest::Unallocated(
319 320
    TestOperand op, UnallocatedOperand::ExtendedPolicy policy,
    UnallocatedOperand::Lifetime lifetime) {
321
  return UnallocatedOperand(policy, lifetime, op.vreg_.value_);
322 323
}

324
InstructionOperand InstructionSequenceTest::Unallocated(
325
    TestOperand op, UnallocatedOperand::ExtendedPolicy policy, int index) {
326
  return UnallocatedOperand(policy, index, op.vreg_.value_);
327 328
}

329
InstructionOperand InstructionSequenceTest::Unallocated(
330
    TestOperand op, UnallocatedOperand::BasicPolicy policy, int index) {
331
  return UnallocatedOperand(policy, index, op.vreg_.value_);
332 333
}

334
InstructionOperand* InstructionSequenceTest::ConvertInputs(
335
    size_t input_size, TestOperand* inputs) {
336 337
  InstructionOperand* mapped_inputs =
      zone()->NewArray<InstructionOperand>(static_cast<int>(input_size));
338 339 340 341 342 343
  for (size_t i = 0; i < input_size; ++i) {
    mapped_inputs[i] = ConvertInputOp(inputs[i]);
  }
  return mapped_inputs;
}

344
InstructionOperand InstructionSequenceTest::ConvertInputOp(TestOperand op) {
345 346
  if (op.type_ == kImmediate) {
    CHECK_EQ(op.vreg_.value_, kNoValue);
347
    return ImmediateOperand(ImmediateOperand::INLINE, op.value_);
348 349 350 351 352 353
  }
  CHECK_NE(op.vreg_.value_, kNoValue);
  switch (op.type_) {
    case kNone:
      return Unallocated(op, UnallocatedOperand::NONE,
                         UnallocatedOperand::USED_AT_START);
354 355 356 357
    case kUnique:
      return Unallocated(op, UnallocatedOperand::NONE);
    case kUniqueRegister:
      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
358 359 360
    case kRegister:
      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
                         UnallocatedOperand::USED_AT_START);
361 362 363
    case kSlot:
      return Unallocated(op, UnallocatedOperand::MUST_HAVE_SLOT,
                         UnallocatedOperand::USED_AT_START);
364 365 366
    case kDeoptArg:
      return Unallocated(op, UnallocatedOperand::REGISTER_OR_SLOT,
                         UnallocatedOperand::USED_AT_END);
367 368 369 370 371 372 373 374 375 376 377 378
    case kFixedRegister: {
      MachineRepresentation rep = GetCanonicalRep(op);
      CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
      if (DoesRegisterAllocation()) {
        auto extended_policy = IsFloatingPoint(rep)
                                   ? UnallocatedOperand::FIXED_FP_REGISTER
                                   : UnallocatedOperand::FIXED_REGISTER;
        return Unallocated(op, extended_policy, op.value_);
      } else {
        return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
      }
    }
379
    case kFixedSlot:
380 381 382 383 384 385
      if (DoesRegisterAllocation()) {
        return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
      } else {
        return AllocatedOperand(LocationOperand::STACK_SLOT,
                                GetCanonicalRep(op), op.value_);
      }
386 387 388
    default:
      break;
  }
389
  UNREACHABLE();
390 391
}

392 393
InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg,
                                                            TestOperand op) {
394 395 396 397 398 399 400 401
  CHECK_EQ(op.vreg_.value_, kNoValue);
  op.vreg_ = vreg;
  switch (op.type_) {
    case kSameAsFirst:
      return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
    case kRegister:
      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
    case kFixedSlot:
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
      if (DoesRegisterAllocation()) {
        return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
      } else {
        return AllocatedOperand(LocationOperand::STACK_SLOT,
                                GetCanonicalRep(op), op.value_);
      }
    case kFixedRegister: {
      MachineRepresentation rep = GetCanonicalRep(op);
      CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
      if (DoesRegisterAllocation()) {
        auto extended_policy = IsFloatingPoint(rep)
                                   ? UnallocatedOperand::FIXED_FP_REGISTER
                                   : UnallocatedOperand::FIXED_REGISTER;
        return Unallocated(op, extended_policy, op.value_);
      } else {
        return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
      }
    }
420 421 422
    default:
      break;
  }
423
  UNREACHABLE();
424 425
}

426
InstructionBlock* InstructionSequenceTest::NewBlock(bool deferred) {
427
  CHECK_NULL(current_block_);
428
  Rpo rpo = Rpo::FromInt(static_cast<int>(instruction_blocks_.size()));
429 430 431 432 433 434
  Rpo loop_header = Rpo::Invalid();
  Rpo loop_end = Rpo::Invalid();
  if (!loop_blocks_.empty()) {
    auto& loop_data = loop_blocks_.back();
    // This is a loop header.
    if (!loop_data.loop_header_.IsValid()) {
435
      loop_end = Rpo::FromInt(rpo.ToInt() + loop_data.expected_blocks_);
436 437 438 439 440 441 442 443 444 445 446
      loop_data.expected_blocks_--;
      loop_data.loop_header_ = rpo;
    } else {
      // This is a loop body.
      CHECK_NE(0, loop_data.expected_blocks_);
      // TODO(dcarney): handle nested loops.
      loop_data.expected_blocks_--;
      loop_header = loop_data.loop_header_;
    }
  }
  // Construct instruction block.
447
  auto instruction_block = zone()->New<InstructionBlock>(
448
      zone(), rpo, loop_header, loop_end, Rpo::Invalid(), deferred, false);
449 450 451 452 453 454 455
  instruction_blocks_.push_back(instruction_block);
  current_block_ = instruction_block;
  sequence()->StartBlock(rpo);
  return instruction_block;
}

void InstructionSequenceTest::WireBlocks() {
456
  CHECK(!current_block());
457
  CHECK(instruction_blocks_.size() == completions_.size());
458 459 460
  CHECK(loop_blocks_.empty());
  // Wire in end block to look like a scheduler produced cfg.
  auto end_block = NewBlock();
461
  Emit(kArchNop);
462 463
  current_block_ = nullptr;
  sequence()->EndBlock(end_block->rpo_number());
464 465 466
  size_t offset = 0;
  for (const auto& completion : completions_) {
    switch (completion.type_) {
467 468 469 470
      case kBlockEnd: {
        auto block = instruction_blocks_[offset];
        block->successors().push_back(end_block->rpo_number());
        end_block->predecessors().push_back(block->rpo_number());
471
        break;
472
      }
473 474 475 476 477 478 479 480 481 482 483
      case kFallThrough:  // Fallthrough.
      case kJump:
        WireBlock(offset, completion.offset_0_);
        break;
      case kBranch:
        WireBlock(offset, completion.offset_0_);
        WireBlock(offset, completion.offset_1_);
        break;
    }
    ++offset;
  }
484
  CalculateDominators();
485 486 487 488 489 490 491 492 493 494 495 496
}

void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
  size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset);
  CHECK(block_offset < instruction_blocks_.size());
  CHECK(target_block_offset < instruction_blocks_.size());
  auto block = instruction_blocks_[block_offset];
  auto target = instruction_blocks_[target_block_offset];
  block->successors().push_back(target->rpo_number());
  target->predecessors().push_back(block->rpo_number());
}

497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
void InstructionSequenceTest::CalculateDominators() {
  CHECK_GT(instruction_blocks_.size(), 0);
  ZoneVector<int> dominator_depth(instruction_blocks_.size(), -1, zone());

  CHECK_EQ(instruction_blocks_[0]->rpo_number(), RpoNumber::FromInt(0));
  dominator_depth[0] = 0;
  instruction_blocks_[0]->set_dominator(RpoNumber::FromInt(0));

  for (size_t i = 1; i < instruction_blocks_.size(); i++) {
    InstructionBlock* block = instruction_blocks_[i];
    auto pred = block->predecessors().begin();
    auto end = block->predecessors().end();
    DCHECK(pred != end);  // All blocks except start have predecessors.
    RpoNumber dominator = *pred;
    // For multiple predecessors, walk up the dominator tree until a common
    // dominator is found. Visitation order guarantees that all predecessors
    // except for backwards edges have been visited.
    for (++pred; pred != end; ++pred) {
      // Don't examine backwards edges.
      if (dominator_depth[pred->ToInt()] < 0) continue;

      RpoNumber other = *pred;
      while (dominator != other) {
        if (dominator_depth[dominator.ToInt()] <
            dominator_depth[other.ToInt()]) {
          other = instruction_blocks_[other.ToInt()]->dominator();
        } else {
          dominator = instruction_blocks_[dominator.ToInt()]->dominator();
        }
      }
    }
    block->set_dominator(dominator);
    dominator_depth[i] = dominator_depth[dominator.ToInt()] + 1;
  }
}

dcarney's avatar
dcarney committed
533 534 535 536
Instruction* InstructionSequenceTest::Emit(
    InstructionCode code, size_t outputs_size, InstructionOperand* outputs,
    size_t inputs_size, InstructionOperand* inputs, size_t temps_size,
    InstructionOperand* temps, bool is_call) {
537 538 539
  auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
                                    inputs, temps_size, temps);
  if (is_call) instruction->MarkAsCall();
dcarney's avatar
dcarney committed
540
  return AddInstruction(instruction);
541 542
}

dcarney's avatar
dcarney committed
543
Instruction* InstructionSequenceTest::AddInstruction(Instruction* instruction) {
544
  sequence()->AddInstruction(instruction);
dcarney's avatar
dcarney committed
545
  return instruction;
546 547 548 549 550
}

}  // namespace compiler
}  // namespace internal
}  // namespace v8