instruction.cc 37 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 6
#include "src/compiler/instruction.h"

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

namespace v8 {
namespace internal {
namespace compiler {

17
const RegisterConfiguration* (*GetRegConfig)() = RegisterConfiguration::Default;
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

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;
53 54 55 56
    case kPositiveOrZero:
    case kNegative:
      UNREACHABLE();
      break;
57 58 59 60 61 62 63 64 65 66 67
    case kEqual:
    case kNotEqual:
    case kOverflow:
    case kNotOverflow:
    case kUnorderedEqual:
    case kUnorderedNotEqual:
      return condition;
  }
  UNREACHABLE();
}

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
bool InstructionOperand::InterferesWith(const InstructionOperand& other) const {
  if (kSimpleFPAliasing || !this->IsFPLocationOperand() ||
      !other.IsFPLocationOperand())
    return EqualsCanonicalized(other);
  // Aliasing is complex and both operands are fp locations.
  const LocationOperand& loc = *LocationOperand::cast(this);
  const LocationOperand& other_loc = LocationOperand::cast(other);
  LocationOperand::LocationKind kind = loc.location_kind();
  LocationOperand::LocationKind other_kind = other_loc.location_kind();
  if (kind != other_kind) return false;
  MachineRepresentation rep = loc.representation();
  MachineRepresentation other_rep = other_loc.representation();
  if (rep == other_rep) return EqualsCanonicalized(other);
  if (kind == LocationOperand::REGISTER) {
    // FP register-register interference.
    return GetRegConfig()->AreAliases(rep, loc.register_code(), other_rep,
                                      other_loc.register_code());
  } else {
    // FP slot-slot interference. Slots of different FP reps can alias because
    // the gap resolver may break a move into 2 or 4 equivalent smaller moves.
    DCHECK_EQ(LocationOperand::STACK_SLOT, kind);
    int index_hi = loc.index();
    int index_lo = index_hi - (1 << ElementSizeLog2Of(rep)) / kPointerSize + 1;
    int other_index_hi = other_loc.index();
    int other_index_lo =
        other_index_hi - (1 << ElementSizeLog2Of(other_rep)) / kPointerSize + 1;
    return other_index_hi >= index_lo && index_hi >= other_index_lo;
  }
  return false;
97
}
98

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
bool LocationOperand::IsCompatible(LocationOperand* op) {
  if (IsRegister() || IsStackSlot()) {
    return op->IsRegister() || op->IsStackSlot();
  } else if (kSimpleFPAliasing) {
    // A backend may choose to generate the same instruction sequence regardless
    // of the FP representation. As a result, we can relax the compatibility and
    // allow a Double to be moved in a Float for example. However, this is only
    // allowed if registers do not overlap.
    return (IsFPRegister() || IsFPStackSlot()) &&
           (op->IsFPRegister() || op->IsFPStackSlot());
  } else if (IsFloatRegister() || IsFloatStackSlot()) {
    return op->IsFloatRegister() || op->IsFloatStackSlot();
  } else if (IsDoubleRegister() || IsDoubleStackSlot()) {
    return op->IsDoubleRegister() || op->IsDoubleStackSlot();
  } else {
    return (IsSimd128Register() || IsSimd128StackSlot()) &&
           (op->IsSimd128Register() || op->IsSimd128StackSlot());
  }
}

119 120
void InstructionOperand::Print(const RegisterConfiguration* config) const {
  OFStream os(stdout);
121 122 123 124 125 126
  PrintableInstructionOperand wrapper;
  wrapper.register_configuration_ = config;
  wrapper.op_ = *this;
  os << wrapper << std::endl;
}

127
void InstructionOperand::Print() const { Print(GetRegConfig()); }
128

129 130
std::ostream& operator<<(std::ostream& os,
                         const PrintableInstructionOperand& printable) {
131
  const InstructionOperand& op = printable.op_;
132
  const RegisterConfiguration* conf = printable.register_configuration_;
133 134 135 136 137 138 139 140 141 142 143
  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:
144 145 146 147
          return os << "(="
                    << conf->GetGeneralRegisterName(
                           unalloc->fixed_register_index())
                    << ")";
148
        case UnallocatedOperand::FIXED_FP_REGISTER:
149 150 151 152
          return os << "(="
                    << conf->GetDoubleRegisterName(
                           unalloc->fixed_register_index())
                    << ")";
153 154
        case UnallocatedOperand::MUST_HAVE_REGISTER:
          return os << "(R)";
155 156
        case UnallocatedOperand::MUST_HAVE_SLOT:
          return os << "(S)";
157 158 159 160 161 162 163
        case UnallocatedOperand::SAME_AS_FIRST_INPUT:
          return os << "(1)";
        case UnallocatedOperand::ANY:
          return os << "(-)";
      }
    }
    case InstructionOperand::CONSTANT:
164 165
      return os << "[constant:" << ConstantOperand::cast(op).virtual_register()
                << "]";
166
    case InstructionOperand::IMMEDIATE: {
167
      ImmediateOperand imm = ImmediateOperand::cast(op);
168 169 170 171 172 173 174
      switch (imm.type()) {
        case ImmediateOperand::INLINE:
          return os << "#" << imm.inline_value();
        case ImmediateOperand::INDEXED:
          return os << "[immediate:" << imm.indexed_value() << "]";
      }
    }
175
    case InstructionOperand::EXPLICIT:
176
    case InstructionOperand::ALLOCATED: {
177
      LocationOperand allocated = LocationOperand::cast(op);
178
      if (op.IsStackSlot()) {
179
        os << "[stack:" << allocated.index();
180
      } else if (op.IsFPStackSlot()) {
181
        os << "[fp_stack:" << allocated.index();
182
      } else if (op.IsRegister()) {
183 184 185
        os << "["
           << GetRegConfig()->GetGeneralRegisterName(allocated.register_code())
           << "|R";
186
      } else if (op.IsDoubleRegister()) {
187 188 189
        os << "["
           << GetRegConfig()->GetDoubleRegisterName(allocated.register_code())
           << "|R";
190
      } else if (op.IsFloatRegister()) {
191 192 193
        os << "["
           << GetRegConfig()->GetFloatRegisterName(allocated.register_code())
           << "|R";
194 195 196 197 198
      } else {
        DCHECK(op.IsSimd128Register());
        os << "["
           << GetRegConfig()->GetSimd128RegisterName(allocated.register_code())
           << "|R";
199 200 201
      }
      if (allocated.IsExplicit()) {
        os << "|E";
202
      }
203
      switch (allocated.representation()) {
204 205 206 207 208 209 210 211 212 213 214 215
        case MachineRepresentation::kNone:
          os << "|-";
          break;
        case MachineRepresentation::kBit:
          os << "|b";
          break;
        case MachineRepresentation::kWord8:
          os << "|w8";
          break;
        case MachineRepresentation::kWord16:
          os << "|w16";
          break;
216
        case MachineRepresentation::kWord32:
217 218
          os << "|w32";
          break;
219
        case MachineRepresentation::kWord64:
220 221
          os << "|w64";
          break;
222
        case MachineRepresentation::kFloat32:
223 224
          os << "|f32";
          break;
225
        case MachineRepresentation::kFloat64:
226 227
          os << "|f64";
          break;
228 229 230
        case MachineRepresentation::kSimd128:
          os << "|s128";
          break;
231 232 233 234 235 236
        case MachineRepresentation::kTaggedSigned:
          os << "|ts";
          break;
        case MachineRepresentation::kTaggedPointer:
          os << "|tp";
          break;
237
        case MachineRepresentation::kTagged:
238 239 240 241 242
          os << "|t";
          break;
      }
      return os << "]";
    }
243 244
    case InstructionOperand::INVALID:
      return os << "(x)";
245 246 247 248
  }
  UNREACHABLE();
}

249 250
void MoveOperands::Print(const RegisterConfiguration* config) const {
  OFStream os(stdout);
251 252 253 254 255 256 257 258
  PrintableInstructionOperand wrapper;
  wrapper.register_configuration_ = config;
  wrapper.op_ = destination();
  os << wrapper << " = ";
  wrapper.op_ = source();
  os << wrapper << std::endl;
}

259
void MoveOperands::Print() const { Print(GetRegConfig()); }
260

261 262 263 264 265 266
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;
267
  if (!mo.source().Equals(mo.destination())) {
268 269 270
    printable_op.op_ = mo.source();
    os << " = " << printable_op;
  }
271 272 273 274 275
  return os << ";";
}


bool ParallelMove::IsRedundant() const {
276
  for (MoveOperands* move : *this) {
277
    if (!move->IsRedundant()) return false;
278 279 280 281
  }
  return true;
}

282 283 284 285
void ParallelMove::PrepareInsertAfter(
    MoveOperands* move, ZoneVector<MoveOperands*>* to_eliminate) const {
  bool no_aliasing =
      kSimpleFPAliasing || !move->destination().IsFPLocationOperand();
dcarney's avatar
dcarney committed
286
  MoveOperands* replacement = nullptr;
287
  MoveOperands* eliminated = nullptr;
288
  for (MoveOperands* curr : *this) {
dcarney's avatar
dcarney committed
289
    if (curr->IsEliminated()) continue;
290
    if (curr->destination().EqualsCanonicalized(move->source())) {
291 292
      // We must replace move's source with curr's destination in order to
      // insert it into this ParallelMove.
dcarney's avatar
dcarney committed
293 294
      DCHECK(!replacement);
      replacement = curr;
295 296 297 298 299 300 301
      if (no_aliasing && eliminated != nullptr) break;
    } else if (curr->destination().InterferesWith(move->destination())) {
      // We can eliminate curr, since move overwrites at least a part of its
      // destination, implying its value is no longer live.
      eliminated = curr;
      to_eliminate->push_back(curr);
      if (no_aliasing && replacement != nullptr) break;
dcarney's avatar
dcarney committed
302 303 304 305 306
    }
  }
  if (replacement != nullptr) move->set_source(replacement->source());
}

307
ExplicitOperand::ExplicitOperand(LocationKind kind, MachineRepresentation rep,
308
                                 int index)
309 310
    : LocationOperand(EXPLICIT, kind, rep, index) {
  DCHECK_IMPLIES(kind == REGISTER && !IsFloatingPoint(rep),
311
                 GetRegConfig()->IsAllocatableGeneralCode(index));
312
  DCHECK_IMPLIES(kind == REGISTER && rep == MachineRepresentation::kFloat32,
313
                 GetRegConfig()->IsAllocatableFloatCode(index));
314
  DCHECK_IMPLIES(kind == REGISTER && (rep == MachineRepresentation::kFloat64),
315
                 GetRegConfig()->IsAllocatableDoubleCode(index));
316 317
}

318 319 320
Instruction::Instruction(InstructionCode opcode)
    : opcode_(opcode),
      bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
321
                 TempCountField::encode(0) | IsCallField::encode(false)),
322 323
      reference_map_(nullptr),
      block_(nullptr) {
324 325 326
  parallel_moves_[0] = nullptr;
  parallel_moves_[1] = nullptr;
}
327 328

Instruction::Instruction(InstructionCode opcode, size_t output_count,
329 330 331
                         InstructionOperand* outputs, size_t input_count,
                         InstructionOperand* inputs, size_t temp_count,
                         InstructionOperand* temps)
332 333 334 335
    : opcode_(opcode),
      bit_field_(OutputCountField::encode(output_count) |
                 InputCountField::encode(input_count) |
                 TempCountField::encode(temp_count) |
336
                 IsCallField::encode(false)),
337 338
      reference_map_(nullptr),
      block_(nullptr) {
339 340
  parallel_moves_[0] = nullptr;
  parallel_moves_[1] = nullptr;
341 342
  size_t offset = 0;
  for (size_t i = 0; i < output_count; ++i) {
343 344
    DCHECK(!outputs[i].IsInvalid());
    operands_[offset++] = outputs[i];
345 346
  }
  for (size_t i = 0; i < input_count; ++i) {
347 348
    DCHECK(!inputs[i].IsInvalid());
    operands_[offset++] = inputs[i];
349 350
  }
  for (size_t i = 0; i < temp_count; ++i) {
351 352
    DCHECK(!temps[i].IsInvalid());
    operands_[offset++] = temps[i];
353 354 355 356
  }
}


357 358 359 360
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()) {
361
      return false;
362
    }
363 364 365 366
  }
  return true;
}

367 368
void Instruction::Print(const RegisterConfiguration* config) const {
  OFStream os(stdout);
369 370 371 372 373 374
  PrintableInstruction wrapper;
  wrapper.instr_ = this;
  wrapper.register_configuration_ = config;
  os << wrapper << std::endl;
}

375
void Instruction::Print() const { Print(GetRegConfig()); }
376

377 378 379
std::ostream& operator<<(std::ostream& os,
                         const PrintableParallelMove& printable) {
  const ParallelMove& pm = *printable.parallel_move_;
380
  bool first = true;
381
  for (MoveOperands* move : pm) {
382 383 384
    if (move->IsEliminated()) continue;
    if (!first) os << " ";
    first = false;
385 386
    PrintableMoveOperands pmo = {printable.register_configuration_, move};
    os << pmo;
387 388 389 390 391
  }
  return os;
}


392
void ReferenceMap::RecordReference(const AllocatedOperand& op) {
393
  // Do not record arguments as pointers.
394
  if (op.IsStackSlot() && LocationOperand::cast(op).index() < 0) return;
395
  DCHECK(!op.IsFPRegister() && !op.IsFPStackSlot());
396
  reference_operands_.push_back(op);
397 398 399
}


400
std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm) {
401
  os << "{";
402
  bool first = true;
403
  PrintableInstructionOperand poi = {GetRegConfig(), InstructionOperand()};
404
  for (const InstructionOperand& op : pm.reference_operands_) {
405 406 407 408 409
    if (!first) {
      os << ";";
    } else {
      first = false;
    }
410
    poi.op_ = op;
411
    os << poi;
412 413 414 415 416
  }
  return os << "}";
}


417
std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
418 419 420 421 422 423 424 425 426 427 428
  switch (ao) {
#define CASE(Name) \
  case k##Name:    \
    return os << #Name;
    ARCH_OPCODE_LIST(CASE)
#undef CASE
  }
  UNREACHABLE();
}


429
std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
430 431 432 433 434 435 436 437 438 439 440 441 442
  switch (am) {
    case kMode_None:
      return os;
#define CASE(Name)   \
  case kMode_##Name: \
    return os << #Name;
      TARGET_ADDRESSING_MODE_LIST(CASE)
#undef CASE
  }
  UNREACHABLE();
}


443
std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
444 445 446 447 448
  switch (fm) {
    case kFlags_none:
      return os;
    case kFlags_branch:
      return os << "branch";
449 450
    case kFlags_branch_and_poison:
      return os << "branch_and_poison";
451 452
    case kFlags_deoptimize:
      return os << "deoptimize";
453 454
    case kFlags_deoptimize_and_poison:
      return os << "deoptimize_and_poison";
455 456
    case kFlags_set:
      return os << "set";
457 458
    case kFlags_trap:
      return os << "trap";
459 460 461 462 463
  }
  UNREACHABLE();
}


464
std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
  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";
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
    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)";
502 503 504 505
    case kUnorderedEqual:
      return os << "unordered equal";
    case kUnorderedNotEqual:
      return os << "unordered not equal";
506 507 508 509
    case kOverflow:
      return os << "overflow";
    case kNotOverflow:
      return os << "not overflow";
510 511 512 513
    case kPositiveOrZero:
      return os << "positive or zero";
    case kNegative:
      return os << "negative";
514 515 516 517 518
  }
  UNREACHABLE();
}


519 520 521 522
std::ostream& operator<<(std::ostream& os,
                         const PrintableInstruction& printable) {
  const Instruction& instr = *printable.instr_;
  PrintableInstructionOperand printable_op = {printable.register_configuration_,
523
                                              InstructionOperand()};
524 525 526 527
  os << "gap ";
  for (int i = Instruction::FIRST_GAP_POSITION;
       i <= Instruction::LAST_GAP_POSITION; i++) {
    os << "(";
528
    if (instr.parallel_moves()[i] != nullptr) {
529 530 531 532 533 534 535 536
      PrintableParallelMove ppm = {printable.register_configuration_,
                                   instr.parallel_moves()[i]};
      os << ppm;
    }
    os << ") ";
  }
  os << "\n          ";

537 538 539
  if (instr.OutputCount() > 1) os << "(";
  for (size_t i = 0; i < instr.OutputCount(); i++) {
    if (i > 0) os << ", ";
540
    printable_op.op_ = *instr.OutputAt(i);
541
    os << printable_op;
542 543 544 545 546
  }

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

547 548 549 550 551 552 553 554
  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());
555 556 557
  }
  if (instr.InputCount() > 0) {
    for (size_t i = 0; i < instr.InputCount(); i++) {
558
      printable_op.op_ = *instr.InputAt(i);
559
      os << " " << printable_op;
560 561
    }
  }
562
  return os;
563 564 565
}


566 567
Constant::Constant(int32_t v) : type_(kInt32), value_(v) {}

568 569 570 571 572 573 574 575 576 577
Constant::Constant(RelocatablePtrConstantInfo info) {
  if (info.type() == RelocatablePtrConstantInfo::kInt32) {
    type_ = kInt32;
  } else if (info.type() == RelocatablePtrConstantInfo::kInt64) {
    type_ = kInt64;
  } else {
    UNREACHABLE();
  }
  value_ = info.value();
  rmode_ = info.rmode();
578
}
579

580 581 582 583 584 585 586
Handle<HeapObject> Constant::ToHeapObject() const {
  DCHECK_EQ(kHeapObject, type());
  Handle<HeapObject> value(
      bit_cast<HeapObject**>(static_cast<intptr_t>(value_)));
  return value;
}

587 588 589 590 591 592
Handle<Code> Constant::ToCode() const {
  DCHECK_EQ(kHeapObject, type());
  Handle<Code> value(bit_cast<Code**>(static_cast<intptr_t>(value_)));
  return value;
}

593
std::ostream& operator<<(std::ostream& os, const Constant& constant) {
594 595 596 597 598
  switch (constant.type()) {
    case Constant::kInt32:
      return os << constant.ToInt32();
    case Constant::kInt64:
      return os << constant.ToInt64() << "l";
599 600
    case Constant::kFloat32:
      return os << constant.ToFloat32() << "f";
601
    case Constant::kFloat64:
602
      return os << constant.ToFloat64().value();
603
    case Constant::kExternalReference:
604 605
      return os << static_cast<const void*>(
                       constant.ToExternalReference().address());
606 607
    case Constant::kHeapObject:
      return os << Brief(*constant.ToHeapObject());
608 609
    case Constant::kRpoNumber:
      return os << "RPO" << constant.ToRpoNumber().ToInt();
610 611 612 613 614
  }
  UNREACHABLE();
}


615 616 617 618
PhiInstruction::PhiInstruction(Zone* zone, int virtual_register,
                               size_t input_count)
    : virtual_register_(virtual_register),
      output_(UnallocatedOperand(UnallocatedOperand::NONE, virtual_register)),
619 620
      operands_(input_count, InstructionOperand::kInvalidVirtualRegister,
                zone) {}
621 622 623


void PhiInstruction::SetInput(size_t offset, int virtual_register) {
624
  DCHECK_EQ(InstructionOperand::kInvalidVirtualRegister, operands_[offset]);
625 626 627
  operands_[offset] = virtual_register;
}

628 629 630 631
void PhiInstruction::RenameInput(size_t offset, int virtual_register) {
  DCHECK_NE(InstructionOperand::kInvalidVirtualRegister, operands_[offset]);
  operands_[offset] = virtual_register;
}
632

633 634
InstructionBlock::InstructionBlock(Zone* zone, RpoNumber rpo_number,
                                   RpoNumber loop_header, RpoNumber loop_end,
635
                                   bool deferred, bool handler)
636 637 638
    : successors_(zone),
      predecessors_(zone),
      phis_(zone),
639
      ao_number_(rpo_number),
640 641 642 643 644
      rpo_number_(rpo_number),
      loop_header_(loop_header),
      loop_end_(loop_end),
      code_start_(-1),
      code_end_(-1),
645
      deferred_(deferred),
646
      handler_(handler),
647 648
      needs_frame_(false),
      must_construct_frame_(false),
649
      must_deconstruct_frame_(false) {}
650

651
size_t InstructionBlock::PredecessorIndexOf(RpoNumber rpo_number) const {
652 653 654 655 656 657 658 659 660
  size_t j = 0;
  for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
       i != predecessors_.end(); ++i, ++j) {
    if (*i == rpo_number) break;
  }
  return j;
}


661
static RpoNumber GetRpo(const BasicBlock* block) {
662
  if (block == nullptr) return RpoNumber::Invalid();
663
  return RpoNumber::FromInt(block->rpo_number());
664 665 666
}


667 668 669
static RpoNumber GetLoopEndRpo(const BasicBlock* block) {
  if (!block->IsLoopHeader()) return RpoNumber::Invalid();
  return RpoNumber::FromInt(block->loop_end()->rpo_number());
670 671 672
}


673 674
static InstructionBlock* InstructionBlockFor(Zone* zone,
                                             const BasicBlock* block) {
675 676
  bool is_handler =
      !block->empty() && block->front()->opcode() == IrOpcode::kIfException;
677 678
  InstructionBlock* instr_block = new (zone)
      InstructionBlock(zone, GetRpo(block), GetRpo(block->loop_header()),
679
                       GetLoopEndRpo(block), block->deferred(), is_handler);
680
  // Map successors and precessors
681
  instr_block->successors().reserve(block->SuccessorCount());
682
  for (BasicBlock* successor : block->successors()) {
683
    instr_block->successors().push_back(GetRpo(successor));
684
  }
685
  instr_block->predecessors().reserve(block->PredecessorCount());
686
  for (BasicBlock* predecessor : block->predecessors()) {
687
    instr_block->predecessors().push_back(GetRpo(predecessor));
688
  }
689
  return instr_block;
690 691
}

692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
std::ostream& operator<<(std::ostream& os,
                         PrintableInstructionBlock& printable_block) {
  const InstructionBlock* block = printable_block.block_;
  const RegisterConfiguration* config = printable_block.register_configuration_;
  const InstructionSequence* code = printable_block.code_;

  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()
     << ")" << std::endl
     << " predecessors:";

  for (RpoNumber pred : block->predecessors()) {
    os << " B" << pred.ToInt();
  }
  os << std::endl;

  for (const PhiInstruction* phi : block->phis()) {
    PrintableInstructionOperand printable_op = {config, phi->output()};
    os << "     phi: " << printable_op << " =";
    for (int input : phi->operands()) {
      os << " v" << input;
    }
    os << std::endl;
  }

  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_ = code->InstructionAt(j);
    os << "   " << buf.start() << ": " << printable_instr << std::endl;
  }

  for (RpoNumber succ : block->successors()) {
    os << " B" << succ.ToInt();
  }
  os << std::endl;
  return os;
}

744 745 746 747
InstructionBlocks* InstructionSequence::InstructionBlocksFor(
    Zone* zone, const Schedule* schedule) {
  InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
  new (blocks) InstructionBlocks(
748
      static_cast<int>(schedule->rpo_order()->size()), nullptr, zone);
749 750 751
  size_t rpo_number = 0;
  for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
       it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
752
    DCHECK(!(*blocks)[rpo_number]);
753
    DCHECK(GetRpo(*it).ToSize() == rpo_number);
754
    (*blocks)[rpo_number] = InstructionBlockFor(zone, *it);
755
  }
756
  ComputeAssemblyOrder(blocks);
757
  return blocks;
758 759
}

760
void InstructionSequence::ValidateEdgeSplitForm() const {
761 762 763 764 765 766 767 768 769 770 771 772 773
  // 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());
      }
    }
  }
}
774

775
void InstructionSequence::ValidateDeferredBlockExitPaths() const {
776 777 778 779 780 781 782 783 784 785
  // 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());
    }
  }
}

786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
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 {
801 802 803 804 805 806 807 808 809 810 811 812 813 814
  // 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);
    }
  }
}

815 816
void InstructionSequence::ComputeAssemblyOrder(InstructionBlocks* blocks) {
  int ao = 0;
817
  for (InstructionBlock* const block : *blocks) {
818
    if (!block->IsDeferred()) {
819
      block->set_ao_number(RpoNumber::FromInt(ao++));
820 821
    }
  }
822
  for (InstructionBlock* const block : *blocks) {
823
    if (block->IsDeferred()) {
824
      block->set_ao_number(RpoNumber::FromInt(ao++));
825 826 827 828
    }
  }
}

829 830
InstructionSequence::InstructionSequence(Isolate* isolate,
                                         Zone* instruction_zone,
831
                                         InstructionBlocks* instruction_blocks)
832 833
    : isolate_(isolate),
      zone_(instruction_zone),
834
      instruction_blocks_(instruction_blocks),
835
      source_positions_(zone()),
836 837 838 839 840
      constants_(ConstantMap::key_compare(),
                 ConstantMap::allocator_type(zone())),
      immediates_(zone()),
      instructions_(zone()),
      next_virtual_register_(0),
841
      reference_maps_(zone()),
842
      representations_(zone()),
843
      representation_mask_(0),
844 845
      deoptimization_entries_(zone()),
      current_block_(nullptr) {}
846

847 848
int InstructionSequence::NextVirtualRegister() {
  int virtual_register = next_virtual_register_++;
849
  CHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
850 851 852 853
  return virtual_register;
}


854
Instruction* InstructionSequence::GetBlockStart(RpoNumber rpo) const {
855
  const InstructionBlock* block = InstructionBlockAt(rpo);
856
  return InstructionAt(block->code_start());
857 858 859
}


860
void InstructionSequence::StartBlock(RpoNumber rpo) {
861 862
  DCHECK_NULL(current_block_);
  current_block_ = InstructionBlockAt(rpo);
863
  int code_start = static_cast<int>(instructions_.size());
864
  current_block_->set_code_start(code_start);
865 866 867
}


868
void InstructionSequence::EndBlock(RpoNumber rpo) {
869
  int end = static_cast<int>(instructions_.size());
870 871
  DCHECK_EQ(current_block_->rpo_number(), rpo);
  if (current_block_->code_start() == end) {  // Empty block.  Insert a nop.
872 873 874
    AddInstruction(Instruction::New(zone(), kArchNop));
    end = static_cast<int>(instructions_.size());
  }
875 876 877 878
  DCHECK(current_block_->code_start() >= 0 &&
         current_block_->code_start() < end);
  current_block_->set_code_end(end);
  current_block_ = nullptr;
879 880 881
}


882
int InstructionSequence::AddInstruction(Instruction* instr) {
883
  DCHECK_NOT_NULL(current_block_);
884
  int index = static_cast<int>(instructions_.size());
885
  instr->set_block(current_block_);
886
  instructions_.push_back(instr);
887
  if (instr->NeedsReferenceMap()) {
888
    DCHECK_NULL(instr->reference_map());
889 890 891 892
    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);
893 894 895 896 897
  }
  return index;
}


898
InstructionBlock* InstructionSequence::GetInstructionBlock(
899
    int instruction_index) const {
900
  return instructions()[instruction_index]->block();
901 902 903
}


904
static MachineRepresentation FilterRepresentation(MachineRepresentation rep) {
905
  switch (rep) {
906 907 908
    case MachineRepresentation::kBit:
    case MachineRepresentation::kWord8:
    case MachineRepresentation::kWord16:
909
      return InstructionSequence::DefaultRepresentation();
910 911
    case MachineRepresentation::kWord32:
    case MachineRepresentation::kWord64:
912 913
    case MachineRepresentation::kTaggedSigned:
    case MachineRepresentation::kTaggedPointer:
914
    case MachineRepresentation::kTagged:
915 916 917
    case MachineRepresentation::kFloat32:
    case MachineRepresentation::kFloat64:
    case MachineRepresentation::kSimd128:
918
      return rep;
919
    case MachineRepresentation::kNone:
920 921
      break;
  }
922

923
  UNREACHABLE();
924 925 926
}


927 928
MachineRepresentation InstructionSequence::GetRepresentation(
    int virtual_register) const {
929 930 931 932 933 934
  DCHECK_LE(0, virtual_register);
  DCHECK_LT(virtual_register, VirtualRegisterCount());
  if (virtual_register >= static_cast<int>(representations_.size())) {
    return DefaultRepresentation();
  }
  return representations_[virtual_register];
935 936 937
}


938
void InstructionSequence::MarkAsRepresentation(MachineRepresentation rep,
939 940 941 942 943 944
                                               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());
  }
945 946
  rep = FilterRepresentation(rep);
  DCHECK_IMPLIES(representations_[virtual_register] != rep,
947
                 representations_[virtual_register] == DefaultRepresentation());
948
  representations_[virtual_register] = rep;
949
  representation_mask_ |= 1 << static_cast<int>(rep);
950 951
}

952
int InstructionSequence::AddDeoptimizationEntry(
953
    FrameStateDescriptor* descriptor, DeoptimizeKind kind,
954
    DeoptimizeReason reason, VectorSlotPair const& feedback) {
955
  int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
956
  deoptimization_entries_.push_back(
957
      DeoptimizationEntry(descriptor, kind, reason, feedback));
958
  return deoptimization_id;
959 960
}

961 962 963
DeoptimizationEntry const& InstructionSequence::GetDeoptimizationEntry(
    int state_id) {
  return deoptimization_entries_[state_id];
964 965 966
}


967 968 969 970
RpoNumber InstructionSequence::InputRpo(Instruction* instr, size_t index) {
  InstructionOperand* operand = instr->InputAt(index);
  Constant constant =
      operand->IsImmediate()
971
          ? GetImmediate(ImmediateOperand::cast(operand))
972 973 974 975 976
          : GetConstant(ConstantOperand::cast(operand)->virtual_register());
  return constant.ToRpoNumber();
}


977 978 979 980 981 982 983 984 985 986 987 988 989 990
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));
}

991 992
void InstructionSequence::Print(const RegisterConfiguration* config) const {
  OFStream os(stdout);
993 994 995 996 997 998
  PrintableInstructionSequence wrapper;
  wrapper.register_configuration_ = config;
  wrapper.sequence_ = this;
  os << wrapper << std::endl;
}

999
void InstructionSequence::Print() const { Print(GetRegConfig()); }
1000

1001
void InstructionSequence::PrintBlock(const RegisterConfiguration* config,
1002
                                     int block_id) const {
1003
  OFStream os(stdout);
1004 1005 1006
  RpoNumber rpo = RpoNumber::FromInt(block_id);
  const InstructionBlock* block = InstructionBlockAt(rpo);
  CHECK(block->rpo_number() == rpo);
1007 1008
  PrintableInstructionBlock printable_block = {config, block, this};
  os << printable_block << std::endl;
1009 1010
}

1011 1012
void InstructionSequence::PrintBlock(int block_id) const {
  PrintBlock(GetRegConfig(), block_id);
1013
}
1014

1015 1016 1017 1018 1019
const RegisterConfiguration*
    InstructionSequence::registerConfigurationForTesting_ = nullptr;

const RegisterConfiguration*
InstructionSequence::RegisterConfigurationForTesting() {
1020
  DCHECK_NOT_NULL(registerConfigurationForTesting_);
1021 1022 1023 1024 1025 1026 1027 1028 1029
  return registerConfigurationForTesting_;
}

void InstructionSequence::SetRegisterConfigurationForTesting(
    const RegisterConfiguration* regConfig) {
  registerConfigurationForTesting_ = regConfig;
  GetRegConfig = InstructionSequence::RegisterConfigurationForTesting;
}

1030
FrameStateDescriptor::FrameStateDescriptor(
1031 1032
    Zone* zone, FrameStateType type, BailoutId bailout_id,
    OutputFrameStateCombine state_combine, size_t parameters_count,
1033 1034 1035
    size_t locals_count, size_t stack_count,
    MaybeHandle<SharedFunctionInfo> shared_info,
    FrameStateDescriptor* outer_state)
1036 1037 1038
    : type_(type),
      bailout_id_(bailout_id),
      frame_state_combine_(state_combine),
1039 1040 1041
      parameters_count_(parameters_count),
      locals_count_(locals_count),
      stack_count_(stack_count),
1042
      values_(zone),
1043
      shared_info_(shared_info),
1044
      outer_state_(outer_state) {}
1045

1046 1047 1048
size_t FrameStateDescriptor::GetSize() const {
  return 1 + parameters_count() + locals_count() + stack_count() +
         (HasContext() ? 1 : 0);
1049 1050 1051 1052 1053
}


size_t FrameStateDescriptor::GetTotalSize() const {
  size_t total_size = 0;
1054
  for (const FrameStateDescriptor* iter = this; iter != nullptr;
1055 1056 1057 1058 1059 1060 1061 1062 1063
       iter = iter->outer_state_) {
    total_size += iter->GetSize();
  }
  return total_size;
}


size_t FrameStateDescriptor::GetFrameCount() const {
  size_t count = 0;
1064
  for (const FrameStateDescriptor* iter = this; iter != nullptr;
1065 1066 1067 1068 1069 1070 1071 1072 1073
       iter = iter->outer_state_) {
    ++count;
  }
  return count;
}


size_t FrameStateDescriptor::GetJSFrameCount() const {
  size_t count = 0;
1074
  for (const FrameStateDescriptor* iter = this; iter != nullptr;
1075
       iter = iter->outer_state_) {
1076
    if (FrameStateFunctionInfo::IsJSFunctionType(iter->type_)) {
1077 1078 1079 1080 1081 1082 1083
      ++count;
    }
  }
  return count;
}


1084 1085 1086 1087 1088
std::ostream& operator<<(std::ostream& os, const RpoNumber& rpo) {
  return os << rpo.ToSize();
}


1089 1090 1091
std::ostream& operator<<(std::ostream& os,
                         const PrintableInstructionSequence& printable) {
  const InstructionSequence& code = *printable.sequence_;
1092 1093 1094 1095 1096 1097 1098 1099 1100
  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";
  }
1101 1102
  PrintableInstructionBlock printable_block = {
      printable.register_configuration_, nullptr, printable.sequence_};
1103
  for (int i = 0; i < code.InstructionBlockCount(); i++) {
1104 1105
    printable_block.block_ = code.InstructionBlockAt(RpoNumber::FromInt(i));
    os << printable_block;
1106 1107 1108 1109 1110 1111 1112
  }
  return os;
}

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