instruction.cc 32.3 KB
Newer Older
1 2 3 4 5
// 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.

#include "src/compiler/common-operator.h"
6
#include "src/compiler/graph.h"
7
#include "src/compiler/instruction.h"
8
#include "src/compiler/schedule.h"
9
#include "src/compiler/state-values-utils.h"
10 11 12 13 14

namespace v8 {
namespace internal {
namespace compiler {

15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

FlagsCondition CommuteFlagsCondition(FlagsCondition condition) {
  switch (condition) {
    case kSignedLessThan:
      return kSignedGreaterThan;
    case kSignedGreaterThanOrEqual:
      return kSignedLessThanOrEqual;
    case kSignedLessThanOrEqual:
      return kSignedGreaterThanOrEqual;
    case kSignedGreaterThan:
      return kSignedLessThan;
    case kUnsignedLessThan:
      return kUnsignedGreaterThan;
    case kUnsignedGreaterThanOrEqual:
      return kUnsignedLessThanOrEqual;
    case kUnsignedLessThanOrEqual:
      return kUnsignedGreaterThanOrEqual;
    case kUnsignedGreaterThan:
      return kUnsignedLessThan;
    case kFloatLessThanOrUnordered:
      return kFloatGreaterThanOrUnordered;
    case kFloatGreaterThanOrEqual:
      return kFloatLessThanOrEqual;
    case kFloatLessThanOrEqual:
      return kFloatGreaterThanOrEqual;
    case kFloatGreaterThanOrUnordered:
      return kFloatLessThanOrUnordered;
    case kFloatLessThan:
      return kFloatGreaterThan;
    case kFloatGreaterThanOrEqualOrUnordered:
      return kFloatLessThanOrEqualOrUnordered;
    case kFloatLessThanOrEqualOrUnordered:
      return kFloatGreaterThanOrEqualOrUnordered;
    case kFloatGreaterThan:
      return kFloatLessThan;
    case kEqual:
    case kNotEqual:
    case kOverflow:
    case kNotOverflow:
    case kUnorderedEqual:
    case kUnorderedNotEqual:
      return condition;
  }
  UNREACHABLE();
  return condition;
}


63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
void InstructionOperand::Print(const RegisterConfiguration* config) const {
  OFStream os(stdout);
  PrintableInstructionOperand wrapper;
  wrapper.register_configuration_ = config;
  wrapper.op_ = *this;
  os << wrapper << std::endl;
}


void InstructionOperand::Print() const {
  const RegisterConfiguration* config =
      RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
  Print(config);
}


79 80
std::ostream& operator<<(std::ostream& os,
                         const PrintableInstructionOperand& printable) {
81
  const InstructionOperand& op = printable.op_;
82
  const RegisterConfiguration* conf = printable.register_configuration_;
83 84 85 86 87 88 89 90 91 92 93
  switch (op.kind()) {
    case InstructionOperand::UNALLOCATED: {
      const UnallocatedOperand* unalloc = UnallocatedOperand::cast(&op);
      os << "v" << unalloc->virtual_register();
      if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
        return os << "(=" << unalloc->fixed_slot_index() << "S)";
      }
      switch (unalloc->extended_policy()) {
        case UnallocatedOperand::NONE:
          return os;
        case UnallocatedOperand::FIXED_REGISTER:
94 95 96 97
          return os << "(="
                    << conf->GetGeneralRegisterName(
                           unalloc->fixed_register_index())
                    << ")";
98
        case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
99 100 101 102
          return os << "(="
                    << conf->GetDoubleRegisterName(
                           unalloc->fixed_register_index())
                    << ")";
103 104
        case UnallocatedOperand::MUST_HAVE_REGISTER:
          return os << "(R)";
105 106
        case UnallocatedOperand::MUST_HAVE_SLOT:
          return os << "(S)";
107 108 109 110 111 112 113
        case UnallocatedOperand::SAME_AS_FIRST_INPUT:
          return os << "(1)";
        case UnallocatedOperand::ANY:
          return os << "(-)";
      }
    }
    case InstructionOperand::CONSTANT:
114 115
      return os << "[constant:" << ConstantOperand::cast(op).virtual_register()
                << "]";
116
    case InstructionOperand::IMMEDIATE: {
117
      ImmediateOperand imm = ImmediateOperand::cast(op);
118 119 120 121 122 123 124
      switch (imm.type()) {
        case ImmediateOperand::INLINE:
          return os << "#" << imm.inline_value();
        case ImmediateOperand::INDEXED:
          return os << "[immediate:" << imm.indexed_value() << "]";
      }
    }
125
    case InstructionOperand::EXPLICIT:
126
    case InstructionOperand::ALLOCATED: {
127
      LocationOperand allocated = LocationOperand::cast(op);
128 129 130 131 132 133 134 135 136 137 138 139 140
      if (op.IsStackSlot()) {
        os << "[stack:" << LocationOperand::cast(op).index();
      } else if (op.IsDoubleStackSlot()) {
        os << "[double_stack:" << LocationOperand::cast(op).index();
      } else if (op.IsRegister()) {
        os << "[" << LocationOperand::cast(op).GetRegister().ToString() << "|R";
      } else {
        DCHECK(op.IsDoubleRegister());
        os << "[" << LocationOperand::cast(op).GetDoubleRegister().ToString()
           << "|R";
      }
      if (allocated.IsExplicit()) {
        os << "|E";
141
      }
142
      switch (allocated.representation()) {
143 144 145 146 147 148 149 150 151 152 153 154
        case MachineRepresentation::kNone:
          os << "|-";
          break;
        case MachineRepresentation::kBit:
          os << "|b";
          break;
        case MachineRepresentation::kWord8:
          os << "|w8";
          break;
        case MachineRepresentation::kWord16:
          os << "|w16";
          break;
155
        case MachineRepresentation::kWord32:
156 157
          os << "|w32";
          break;
158
        case MachineRepresentation::kWord64:
159 160
          os << "|w64";
          break;
161
        case MachineRepresentation::kFloat32:
162 163
          os << "|f32";
          break;
164
        case MachineRepresentation::kFloat64:
165 166
          os << "|f64";
          break;
167 168 169
        case MachineRepresentation::kSimd128:
          os << "|s128";
          break;
170
        case MachineRepresentation::kTagged:
171 172 173 174 175
          os << "|t";
          break;
      }
      return os << "]";
    }
176 177
    case InstructionOperand::INVALID:
      return os << "(x)";
178 179 180 181 182 183
  }
  UNREACHABLE();
  return os;
}


184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
void MoveOperands::Print(const RegisterConfiguration* config) const {
  OFStream os(stdout);
  PrintableInstructionOperand wrapper;
  wrapper.register_configuration_ = config;
  wrapper.op_ = destination();
  os << wrapper << " = ";
  wrapper.op_ = source();
  os << wrapper << std::endl;
}


void MoveOperands::Print() const {
  const RegisterConfiguration* config =
      RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
  Print(config);
}


202 203 204 205 206 207
std::ostream& operator<<(std::ostream& os,
                         const PrintableMoveOperands& printable) {
  const MoveOperands& mo = *printable.move_operands_;
  PrintableInstructionOperand printable_op = {printable.register_configuration_,
                                              mo.destination()};
  os << printable_op;
208
  if (!mo.source().Equals(mo.destination())) {
209 210 211
    printable_op.op_ = mo.source();
    os << " = " << printable_op;
  }
212 213 214 215 216
  return os << ";";
}


bool ParallelMove::IsRedundant() const {
217
  for (MoveOperands* move : *this) {
218
    if (!move->IsRedundant()) return false;
219 220 221 222 223
  }
  return true;
}


dcarney's avatar
dcarney committed
224 225 226
MoveOperands* ParallelMove::PrepareInsertAfter(MoveOperands* move) const {
  MoveOperands* replacement = nullptr;
  MoveOperands* to_eliminate = nullptr;
227
  for (MoveOperands* curr : *this) {
dcarney's avatar
dcarney committed
228
    if (curr->IsEliminated()) continue;
229
    if (curr->destination().EqualsCanonicalized(move->source())) {
dcarney's avatar
dcarney committed
230 231 232
      DCHECK(!replacement);
      replacement = curr;
      if (to_eliminate != nullptr) break;
233
    } else if (curr->destination().EqualsCanonicalized(move->destination())) {
dcarney's avatar
dcarney committed
234 235 236 237 238 239 240 241 242 243 244
      DCHECK(!to_eliminate);
      to_eliminate = curr;
      if (replacement != nullptr) break;
    }
  }
  DCHECK_IMPLIES(replacement == to_eliminate, replacement == nullptr);
  if (replacement != nullptr) move->set_source(replacement->source());
  return to_eliminate;
}


245
ExplicitOperand::ExplicitOperand(LocationKind kind, MachineRepresentation rep,
246
                                 int index)
247 248
    : LocationOperand(EXPLICIT, kind, rep, index) {
  DCHECK_IMPLIES(kind == REGISTER && !IsFloatingPoint(rep),
249
                 Register::from_code(index).IsAllocatable());
250
  DCHECK_IMPLIES(kind == REGISTER && IsFloatingPoint(rep),
251 252 253
                 DoubleRegister::from_code(index).IsAllocatable());
}

254 255 256
Instruction::Instruction(InstructionCode opcode)
    : opcode_(opcode),
      bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
257
                 TempCountField::encode(0) | IsCallField::encode(false)),
258 259
      reference_map_(nullptr),
      block_(nullptr) {
260 261 262
  parallel_moves_[0] = nullptr;
  parallel_moves_[1] = nullptr;
}
263 264

Instruction::Instruction(InstructionCode opcode, size_t output_count,
265 266 267
                         InstructionOperand* outputs, size_t input_count,
                         InstructionOperand* inputs, size_t temp_count,
                         InstructionOperand* temps)
268 269 270 271
    : opcode_(opcode),
      bit_field_(OutputCountField::encode(output_count) |
                 InputCountField::encode(input_count) |
                 TempCountField::encode(temp_count) |
272
                 IsCallField::encode(false)),
273 274
      reference_map_(nullptr),
      block_(nullptr) {
275 276
  parallel_moves_[0] = nullptr;
  parallel_moves_[1] = nullptr;
277 278
  size_t offset = 0;
  for (size_t i = 0; i < output_count; ++i) {
279 280
    DCHECK(!outputs[i].IsInvalid());
    operands_[offset++] = outputs[i];
281 282
  }
  for (size_t i = 0; i < input_count; ++i) {
283 284
    DCHECK(!inputs[i].IsInvalid());
    operands_[offset++] = inputs[i];
285 286
  }
  for (size_t i = 0; i < temp_count; ++i) {
287 288
    DCHECK(!temps[i].IsInvalid());
    operands_[offset++] = temps[i];
289 290 291 292
  }
}


293 294 295 296
bool Instruction::AreMovesRedundant() const {
  for (int i = Instruction::FIRST_GAP_POSITION;
       i <= Instruction::LAST_GAP_POSITION; i++) {
    if (parallel_moves_[i] != nullptr && !parallel_moves_[i]->IsRedundant()) {
297
      return false;
298
    }
299 300 301 302 303
  }
  return true;
}


304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
void Instruction::Print(const RegisterConfiguration* config) const {
  OFStream os(stdout);
  PrintableInstruction wrapper;
  wrapper.instr_ = this;
  wrapper.register_configuration_ = config;
  os << wrapper << std::endl;
}


void Instruction::Print() const {
  const RegisterConfiguration* config =
      RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
  Print(config);
}


320 321 322
std::ostream& operator<<(std::ostream& os,
                         const PrintableParallelMove& printable) {
  const ParallelMove& pm = *printable.parallel_move_;
323
  bool first = true;
324
  for (MoveOperands* move : pm) {
325 326 327
    if (move->IsEliminated()) continue;
    if (!first) os << " ";
    first = false;
328 329
    PrintableMoveOperands pmo = {printable.register_configuration_, move};
    os << pmo;
330 331 332 333 334
  }
  return os;
}


335
void ReferenceMap::RecordReference(const AllocatedOperand& op) {
336
  // Do not record arguments as pointers.
337
  if (op.IsStackSlot() && LocationOperand::cast(op).index() < 0) return;
338 339
  DCHECK(!op.IsDoubleRegister() && !op.IsDoubleStackSlot());
  reference_operands_.push_back(op);
340 341 342
}


343
std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm) {
344
  os << "{";
345
  bool first = true;
346 347 348
  PrintableInstructionOperand poi = {
      RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN),
      InstructionOperand()};
349
  for (const InstructionOperand& op : pm.reference_operands_) {
350 351 352 353 354
    if (!first) {
      os << ";";
    } else {
      first = false;
    }
355
    poi.op_ = op;
356
    os << poi;
357 358 359 360 361
  }
  return os << "}";
}


362
std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
363 364 365 366 367 368 369 370 371 372 373 374
  switch (ao) {
#define CASE(Name) \
  case k##Name:    \
    return os << #Name;
    ARCH_OPCODE_LIST(CASE)
#undef CASE
  }
  UNREACHABLE();
  return os;
}


375
std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
376 377 378 379 380 381 382 383 384 385 386 387 388 389
  switch (am) {
    case kMode_None:
      return os;
#define CASE(Name)   \
  case kMode_##Name: \
    return os << #Name;
      TARGET_ADDRESSING_MODE_LIST(CASE)
#undef CASE
  }
  UNREACHABLE();
  return os;
}


390
std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
391 392 393 394 395
  switch (fm) {
    case kFlags_none:
      return os;
    case kFlags_branch:
      return os << "branch";
396 397
    case kFlags_deoptimize:
      return os << "deoptimize";
398 399 400 401 402 403 404 405
    case kFlags_set:
      return os << "set";
  }
  UNREACHABLE();
  return os;
}


406
std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
  switch (fc) {
    case kEqual:
      return os << "equal";
    case kNotEqual:
      return os << "not equal";
    case kSignedLessThan:
      return os << "signed less than";
    case kSignedGreaterThanOrEqual:
      return os << "signed greater than or equal";
    case kSignedLessThanOrEqual:
      return os << "signed less than or equal";
    case kSignedGreaterThan:
      return os << "signed greater than";
    case kUnsignedLessThan:
      return os << "unsigned less than";
    case kUnsignedGreaterThanOrEqual:
      return os << "unsigned greater than or equal";
    case kUnsignedLessThanOrEqual:
      return os << "unsigned less than or equal";
    case kUnsignedGreaterThan:
      return os << "unsigned greater than";
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
    case kFloatLessThanOrUnordered:
      return os << "less than or unordered (FP)";
    case kFloatGreaterThanOrEqual:
      return os << "greater than or equal (FP)";
    case kFloatLessThanOrEqual:
      return os << "less than or equal (FP)";
    case kFloatGreaterThanOrUnordered:
      return os << "greater than or unordered (FP)";
    case kFloatLessThan:
      return os << "less than (FP)";
    case kFloatGreaterThanOrEqualOrUnordered:
      return os << "greater than, equal or unordered (FP)";
    case kFloatLessThanOrEqualOrUnordered:
      return os << "less than, equal or unordered (FP)";
    case kFloatGreaterThan:
      return os << "greater than (FP)";
444 445 446 447
    case kUnorderedEqual:
      return os << "unordered equal";
    case kUnorderedNotEqual:
      return os << "unordered not equal";
448 449 450 451
    case kOverflow:
      return os << "overflow";
    case kNotOverflow:
      return os << "not overflow";
452 453 454 455 456 457
  }
  UNREACHABLE();
  return os;
}


458 459 460 461
std::ostream& operator<<(std::ostream& os,
                         const PrintableInstruction& printable) {
  const Instruction& instr = *printable.instr_;
  PrintableInstructionOperand printable_op = {printable.register_configuration_,
462
                                              InstructionOperand()};
463 464 465 466
  os << "gap ";
  for (int i = Instruction::FIRST_GAP_POSITION;
       i <= Instruction::LAST_GAP_POSITION; i++) {
    os << "(";
467
    if (instr.parallel_moves()[i] != nullptr) {
468 469 470 471 472 473 474 475
      PrintableParallelMove ppm = {printable.register_configuration_,
                                   instr.parallel_moves()[i]};
      os << ppm;
    }
    os << ") ";
  }
  os << "\n          ";

476 477 478
  if (instr.OutputCount() > 1) os << "(";
  for (size_t i = 0; i < instr.OutputCount(); i++) {
    if (i > 0) os << ", ";
479
    printable_op.op_ = *instr.OutputAt(i);
480
    os << printable_op;
481 482 483 484 485
  }

  if (instr.OutputCount() > 1) os << ") = ";
  if (instr.OutputCount() == 1) os << " = ";

486 487 488 489 490 491 492 493
  os << ArchOpcodeField::decode(instr.opcode());
  AddressingMode am = AddressingModeField::decode(instr.opcode());
  if (am != kMode_None) {
    os << " : " << AddressingModeField::decode(instr.opcode());
  }
  FlagsMode fm = FlagsModeField::decode(instr.opcode());
  if (fm != kFlags_none) {
    os << " && " << fm << " if " << FlagsConditionField::decode(instr.opcode());
494 495 496
  }
  if (instr.InputCount() > 0) {
    for (size_t i = 0; i < instr.InputCount(); i++) {
497
      printable_op.op_ = *instr.InputAt(i);
498
      os << " " << printable_op;
499 500
    }
  }
501
  return os;
502 503 504
}


505 506
Constant::Constant(int32_t v) : type_(kInt32), value_(v) {}

507 508 509 510 511 512 513 514
Constant::Constant(RelocatablePtrConstantInfo info)
#ifdef V8_HOST_ARCH_32_BIT
    : type_(kInt32), value_(info.value()), rmode_(info.rmode()) {
}
#else
    : type_(kInt64), value_(info.value()), rmode_(info.rmode()) {
}
#endif
515

516
std::ostream& operator<<(std::ostream& os, const Constant& constant) {
517 518 519 520 521
  switch (constant.type()) {
    case Constant::kInt32:
      return os << constant.ToInt32();
    case Constant::kInt64:
      return os << constant.ToInt64() << "l";
522 523
    case Constant::kFloat32:
      return os << constant.ToFloat32() << "f";
524 525 526
    case Constant::kFloat64:
      return os << constant.ToFloat64();
    case Constant::kExternalReference:
527 528
      return os << static_cast<const void*>(
                       constant.ToExternalReference().address());
529 530
    case Constant::kHeapObject:
      return os << Brief(*constant.ToHeapObject());
531 532
    case Constant::kRpoNumber:
      return os << "RPO" << constant.ToRpoNumber().ToInt();
533 534 535 536 537 538
  }
  UNREACHABLE();
  return os;
}


539 540 541 542
PhiInstruction::PhiInstruction(Zone* zone, int virtual_register,
                               size_t input_count)
    : virtual_register_(virtual_register),
      output_(UnallocatedOperand(UnallocatedOperand::NONE, virtual_register)),
543 544
      operands_(input_count, InstructionOperand::kInvalidVirtualRegister,
                zone) {}
545 546 547


void PhiInstruction::SetInput(size_t offset, int virtual_register) {
548
  DCHECK_EQ(InstructionOperand::kInvalidVirtualRegister, operands_[offset]);
549 550 551 552
  operands_[offset] = virtual_register;
}


553 554
InstructionBlock::InstructionBlock(Zone* zone, RpoNumber rpo_number,
                                   RpoNumber loop_header, RpoNumber loop_end,
555
                                   bool deferred, bool handler)
556 557 558
    : successors_(zone),
      predecessors_(zone),
      phis_(zone),
559
      ao_number_(rpo_number),
560 561 562 563 564
      rpo_number_(rpo_number),
      loop_header_(loop_header),
      loop_end_(loop_end),
      code_start_(-1),
      code_end_(-1),
565
      deferred_(deferred),
566
      handler_(handler),
567 568
      needs_frame_(false),
      must_construct_frame_(false),
569 570
      must_deconstruct_frame_(false),
      last_deferred_(RpoNumber::Invalid()) {}
571 572


573
size_t InstructionBlock::PredecessorIndexOf(RpoNumber rpo_number) const {
574 575 576 577 578 579 580 581 582
  size_t j = 0;
  for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
       i != predecessors_.end(); ++i, ++j) {
    if (*i == rpo_number) break;
  }
  return j;
}


583
static RpoNumber GetRpo(const BasicBlock* block) {
584
  if (block == nullptr) return RpoNumber::Invalid();
585
  return RpoNumber::FromInt(block->rpo_number());
586 587 588
}


589 590 591
static RpoNumber GetLoopEndRpo(const BasicBlock* block) {
  if (!block->IsLoopHeader()) return RpoNumber::Invalid();
  return RpoNumber::FromInt(block->loop_end()->rpo_number());
592 593 594
}


595 596
static InstructionBlock* InstructionBlockFor(Zone* zone,
                                             const BasicBlock* block) {
597 598
  bool is_handler =
      !block->empty() && block->front()->opcode() == IrOpcode::kIfException;
599 600
  InstructionBlock* instr_block = new (zone)
      InstructionBlock(zone, GetRpo(block), GetRpo(block->loop_header()),
601
                       GetLoopEndRpo(block), block->deferred(), is_handler);
602
  // Map successors and precessors
603
  instr_block->successors().reserve(block->SuccessorCount());
604
  for (BasicBlock* successor : block->successors()) {
605
    instr_block->successors().push_back(GetRpo(successor));
606
  }
607
  instr_block->predecessors().reserve(block->PredecessorCount());
608
  for (BasicBlock* predecessor : block->predecessors()) {
609
    instr_block->predecessors().push_back(GetRpo(predecessor));
610
  }
611
  return instr_block;
612 613
}

614 615 616 617
InstructionBlocks* InstructionSequence::InstructionBlocksFor(
    Zone* zone, const Schedule* schedule) {
  InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
  new (blocks) InstructionBlocks(
618
      static_cast<int>(schedule->rpo_order()->size()), nullptr, zone);
619 620 621
  size_t rpo_number = 0;
  for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
       it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
622
    DCHECK(!(*blocks)[rpo_number]);
623
    DCHECK(GetRpo(*it).ToSize() == rpo_number);
624
    (*blocks)[rpo_number] = InstructionBlockFor(zone, *it);
625
  }
626
  ComputeAssemblyOrder(blocks);
627
  return blocks;
628 629
}

630
void InstructionSequence::ValidateEdgeSplitForm() const {
631 632 633 634 635 636 637 638 639 640 641 642 643
  // Validate blocks are in edge-split form: no block with multiple successors
  // has an edge to a block (== a successor) with more than one predecessors.
  for (const InstructionBlock* block : instruction_blocks()) {
    if (block->SuccessorCount() > 1) {
      for (const RpoNumber& successor_id : block->successors()) {
        const InstructionBlock* successor = InstructionBlockAt(successor_id);
        // Expect precisely one predecessor: "block".
        CHECK(successor->PredecessorCount() == 1 &&
              successor->predecessors()[0] == block->rpo_number());
      }
    }
  }
}
644

645
void InstructionSequence::ValidateDeferredBlockExitPaths() const {
646 647 648 649 650 651 652 653 654 655
  // A deferred block with more than one successor must have all its successors
  // deferred.
  for (const InstructionBlock* block : instruction_blocks()) {
    if (!block->IsDeferred() || block->SuccessorCount() <= 1) continue;
    for (RpoNumber successor_id : block->successors()) {
      CHECK(InstructionBlockAt(successor_id)->IsDeferred());
    }
  }
}

656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
void InstructionSequence::ValidateDeferredBlockEntryPaths() const {
  // If a deferred block has multiple predecessors, they have to
  // all be deferred. Otherwise, we can run into a situation where a range
  // that spills only in deferred blocks inserts its spill in the block, but
  // other ranges need moves inserted by ResolveControlFlow in the predecessors,
  // which may clobber the register of this range.
  for (const InstructionBlock* block : instruction_blocks()) {
    if (!block->IsDeferred() || block->PredecessorCount() <= 1) continue;
    for (RpoNumber predecessor_id : block->predecessors()) {
      CHECK(InstructionBlockAt(predecessor_id)->IsDeferred());
    }
  }
}

void InstructionSequence::ValidateSSA() const {
671 672 673 674 675 676 677 678 679 680 681 682 683 684
  // TODO(mtrofin): We could use a local zone here instead.
  BitVector definitions(VirtualRegisterCount(), zone());
  for (const Instruction* instruction : *this) {
    for (size_t i = 0; i < instruction->OutputCount(); ++i) {
      const InstructionOperand* output = instruction->OutputAt(i);
      int vreg = (output->IsConstant())
                     ? ConstantOperand::cast(output)->virtual_register()
                     : UnallocatedOperand::cast(output)->virtual_register();
      CHECK(!definitions.Contains(vreg));
      definitions.Add(vreg);
    }
  }
}

685 686
void InstructionSequence::ComputeAssemblyOrder(InstructionBlocks* blocks) {
  int ao = 0;
687
  for (InstructionBlock* const block : *blocks) {
688
    if (!block->IsDeferred()) {
689
      block->set_ao_number(RpoNumber::FromInt(ao++));
690 691
    }
  }
692
  for (InstructionBlock* const block : *blocks) {
693
    if (block->IsDeferred()) {
694
      block->set_ao_number(RpoNumber::FromInt(ao++));
695 696 697 698
    }
  }
}

699 700
InstructionSequence::InstructionSequence(Isolate* isolate,
                                         Zone* instruction_zone,
701
                                         InstructionBlocks* instruction_blocks)
702 703
    : isolate_(isolate),
      zone_(instruction_zone),
704
      instruction_blocks_(instruction_blocks),
705
      source_positions_(zone()),
706 707 708 709 710
      constants_(ConstantMap::key_compare(),
                 ConstantMap::allocator_type(zone())),
      immediates_(zone()),
      instructions_(zone()),
      next_virtual_register_(0),
711
      reference_maps_(zone()),
712
      representations_(zone()),
713 714
      deoptimization_entries_(zone()),
      current_block_(nullptr) {}
715

716 717
int InstructionSequence::NextVirtualRegister() {
  int virtual_register = next_virtual_register_++;
718
  CHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
719 720 721 722
  return virtual_register;
}


723
Instruction* InstructionSequence::GetBlockStart(RpoNumber rpo) const {
724
  const InstructionBlock* block = InstructionBlockAt(rpo);
725
  return InstructionAt(block->code_start());
726 727 728
}


729
void InstructionSequence::StartBlock(RpoNumber rpo) {
730 731
  DCHECK_NULL(current_block_);
  current_block_ = InstructionBlockAt(rpo);
732
  int code_start = static_cast<int>(instructions_.size());
733
  current_block_->set_code_start(code_start);
734 735 736
}


737
void InstructionSequence::EndBlock(RpoNumber rpo) {
738
  int end = static_cast<int>(instructions_.size());
739 740
  DCHECK_EQ(current_block_->rpo_number(), rpo);
  if (current_block_->code_start() == end) {  // Empty block.  Insert a nop.
741 742 743
    AddInstruction(Instruction::New(zone(), kArchNop));
    end = static_cast<int>(instructions_.size());
  }
744 745 746 747
  DCHECK(current_block_->code_start() >= 0 &&
         current_block_->code_start() < end);
  current_block_->set_code_end(end);
  current_block_ = nullptr;
748 749 750
}


751
int InstructionSequence::AddInstruction(Instruction* instr) {
752
  DCHECK_NOT_NULL(current_block_);
753
  int index = static_cast<int>(instructions_.size());
754
  instr->set_block(current_block_);
755
  instructions_.push_back(instr);
756
  if (instr->NeedsReferenceMap()) {
757
    DCHECK(instr->reference_map() == nullptr);
758 759 760 761
    ReferenceMap* reference_map = new (zone()) ReferenceMap(zone());
    reference_map->set_instruction_position(index);
    instr->set_reference_map(reference_map);
    reference_maps_.push_back(reference_map);
762 763 764 765 766
  }
  return index;
}


767
InstructionBlock* InstructionSequence::GetInstructionBlock(
768
    int instruction_index) const {
769
  return instructions()[instruction_index]->block();
770 771 772
}


773
static MachineRepresentation FilterRepresentation(MachineRepresentation rep) {
774
  switch (rep) {
775 776 777
    case MachineRepresentation::kBit:
    case MachineRepresentation::kWord8:
    case MachineRepresentation::kWord16:
778
      return InstructionSequence::DefaultRepresentation();
779 780 781 782
    case MachineRepresentation::kWord32:
    case MachineRepresentation::kWord64:
    case MachineRepresentation::kFloat32:
    case MachineRepresentation::kFloat64:
783
    case MachineRepresentation::kSimd128:
784
    case MachineRepresentation::kTagged:
785
      return rep;
786
    case MachineRepresentation::kNone:
787 788 789
      break;
  }
  UNREACHABLE();
790
  return MachineRepresentation::kNone;
791 792 793
}


794 795
MachineRepresentation InstructionSequence::GetRepresentation(
    int virtual_register) const {
796 797 798 799 800 801
  DCHECK_LE(0, virtual_register);
  DCHECK_LT(virtual_register, VirtualRegisterCount());
  if (virtual_register >= static_cast<int>(representations_.size())) {
    return DefaultRepresentation();
  }
  return representations_[virtual_register];
802 803 804
}


805
void InstructionSequence::MarkAsRepresentation(MachineRepresentation rep,
806 807 808 809 810 811
                                               int virtual_register) {
  DCHECK_LE(0, virtual_register);
  DCHECK_LT(virtual_register, VirtualRegisterCount());
  if (virtual_register >= static_cast<int>(representations_.size())) {
    representations_.resize(VirtualRegisterCount(), DefaultRepresentation());
  }
812 813
  rep = FilterRepresentation(rep);
  DCHECK_IMPLIES(representations_[virtual_register] != rep,
814
                 representations_[virtual_register] == DefaultRepresentation());
815
  representations_[virtual_register] = rep;
816 817 818
}


819
InstructionSequence::StateId InstructionSequence::AddFrameStateDescriptor(
820
    FrameStateDescriptor* descriptor) {
821
  int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
822
  deoptimization_entries_.push_back(descriptor);
823
  return StateId::FromInt(deoptimization_id);
824 825
}

826 827 828
FrameStateDescriptor* InstructionSequence::GetFrameStateDescriptor(
    InstructionSequence::StateId state_id) {
  return deoptimization_entries_[state_id.ToInt()];
829 830 831
}


832
int InstructionSequence::GetFrameStateDescriptorCount() {
833
  return static_cast<int>(deoptimization_entries_.size());
834 835 836
}


837 838 839 840
RpoNumber InstructionSequence::InputRpo(Instruction* instr, size_t index) {
  InstructionOperand* operand = instr->InputAt(index);
  Constant constant =
      operand->IsImmediate()
841
          ? GetImmediate(ImmediateOperand::cast(operand))
842 843 844 845 846
          : GetConstant(ConstantOperand::cast(operand)->virtual_register());
  return constant.ToRpoNumber();
}


847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
bool InstructionSequence::GetSourcePosition(const Instruction* instr,
                                            SourcePosition* result) const {
  auto it = source_positions_.find(instr);
  if (it == source_positions_.end()) return false;
  *result = it->second;
  return true;
}


void InstructionSequence::SetSourcePosition(const Instruction* instr,
                                            SourcePosition value) {
  source_positions_.insert(std::make_pair(instr, value));
}


862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
void InstructionSequence::Print(const RegisterConfiguration* config) const {
  OFStream os(stdout);
  PrintableInstructionSequence wrapper;
  wrapper.register_configuration_ = config;
  wrapper.sequence_ = this;
  os << wrapper << std::endl;
}


void InstructionSequence::Print() const {
  const RegisterConfiguration* config =
      RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
  Print(config);
}

877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
void InstructionSequence::PrintBlock(const RegisterConfiguration* config,
                                     int block_id) const {
  OFStream os(stdout);
  RpoNumber rpo = RpoNumber::FromInt(block_id);
  const InstructionBlock* block = InstructionBlockAt(rpo);
  CHECK(block->rpo_number() == rpo);

  os << "B" << block->rpo_number();
  os << ": AO#" << block->ao_number();
  if (block->IsDeferred()) os << " (deferred)";
  if (!block->needs_frame()) os << " (no frame)";
  if (block->must_construct_frame()) os << " (construct frame)";
  if (block->must_deconstruct_frame()) os << " (deconstruct frame)";
  if (block->IsLoopHeader()) {
    os << " loop blocks: [" << block->rpo_number() << ", " << block->loop_end()
       << ")";
  }
  os << "  instructions: [" << block->code_start() << ", " << block->code_end()
     << ")\n  predecessors:";

897
  for (RpoNumber pred : block->predecessors()) {
898 899 900 901
    os << " B" << pred.ToInt();
  }
  os << "\n";

902
  for (const PhiInstruction* phi : block->phis()) {
903 904
    PrintableInstructionOperand printable_op = {config, phi->output()};
    os << "     phi: " << printable_op << " =";
905
    for (int input : phi->operands()) {
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
      os << " v" << input;
    }
    os << "\n";
  }

  ScopedVector<char> buf(32);
  PrintableInstruction printable_instr;
  printable_instr.register_configuration_ = config;
  for (int j = block->first_instruction_index();
       j <= block->last_instruction_index(); j++) {
    // TODO(svenpanne) Add some basic formatting to our streams.
    SNPrintF(buf, "%5d", j);
    printable_instr.instr_ = InstructionAt(j);
    os << "   " << buf.start() << ": " << printable_instr << "\n";
  }

922
  for (RpoNumber succ : block->successors()) {
923 924 925 926 927 928 929 930 931 932
    os << " B" << succ.ToInt();
  }
  os << "\n";
}

void InstructionSequence::PrintBlock(int block_id) const {
  const RegisterConfiguration* config =
      RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
  PrintBlock(config, block_id);
}
933

934
FrameStateDescriptor::FrameStateDescriptor(
935 936
    Zone* zone, FrameStateType type, BailoutId bailout_id,
    OutputFrameStateCombine state_combine, size_t parameters_count,
937 938 939
    size_t locals_count, size_t stack_count,
    MaybeHandle<SharedFunctionInfo> shared_info,
    FrameStateDescriptor* outer_state)
940 941 942
    : type_(type),
      bailout_id_(bailout_id),
      frame_state_combine_(state_combine),
943 944 945
      parameters_count_(parameters_count),
      locals_count_(locals_count),
      stack_count_(stack_count),
946
      values_(zone),
947
      shared_info_(shared_info),
948
      outer_state_(outer_state) {}
949

950

951
size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
952
  size_t size = 1 + parameters_count() + locals_count() + stack_count() +
953 954 955 956 957 958 959 960 961 962 963 964 965 966
                (HasContext() ? 1 : 0);
  switch (combine.kind()) {
    case OutputFrameStateCombine::kPushOutput:
      size += combine.GetPushCount();
      break;
    case OutputFrameStateCombine::kPokeAt:
      break;
  }
  return size;
}


size_t FrameStateDescriptor::GetTotalSize() const {
  size_t total_size = 0;
967
  for (const FrameStateDescriptor* iter = this; iter != nullptr;
968 969 970 971 972 973 974 975 976
       iter = iter->outer_state_) {
    total_size += iter->GetSize();
  }
  return total_size;
}


size_t FrameStateDescriptor::GetFrameCount() const {
  size_t count = 0;
977
  for (const FrameStateDescriptor* iter = this; iter != nullptr;
978 979 980 981 982 983 984 985 986
       iter = iter->outer_state_) {
    ++count;
  }
  return count;
}


size_t FrameStateDescriptor::GetJSFrameCount() const {
  size_t count = 0;
987
  for (const FrameStateDescriptor* iter = this; iter != nullptr;
988
       iter = iter->outer_state_) {
989
    if (FrameStateFunctionInfo::IsJSFunctionType(iter->type_)) {
990 991 992 993 994 995 996
      ++count;
    }
  }
  return count;
}


997 998 999 1000 1001
std::ostream& operator<<(std::ostream& os, const RpoNumber& rpo) {
  return os << rpo.ToSize();
}


1002 1003 1004
std::ostream& operator<<(std::ostream& os,
                         const PrintableInstructionSequence& printable) {
  const InstructionSequence& code = *printable.sequence_;
1005 1006 1007 1008 1009 1010 1011 1012 1013
  for (size_t i = 0; i < code.immediates_.size(); ++i) {
    Constant constant = code.immediates_[i];
    os << "IMM#" << i << ": " << constant << "\n";
  }
  int i = 0;
  for (ConstantMap::const_iterator it = code.constants_.begin();
       it != code.constants_.end(); ++i, ++it) {
    os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
  }
1014
  for (int i = 0; i < code.InstructionBlockCount(); i++) {
1015
    printable.sequence_->PrintBlock(printable.register_configuration_, i);
1016 1017 1018 1019 1020 1021 1022
  }
  return os;
}

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