Home | History | Annotate | Download | only in compiler
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/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 namespace v8 {
     12 namespace internal {
     13 namespace compiler {
     14 
     15 const auto GetRegConfig = RegisterConfiguration::Turbofan;
     16 
     17 FlagsCondition CommuteFlagsCondition(FlagsCondition condition) {
     18   switch (condition) {
     19     case kSignedLessThan:
     20       return kSignedGreaterThan;
     21     case kSignedGreaterThanOrEqual:
     22       return kSignedLessThanOrEqual;
     23     case kSignedLessThanOrEqual:
     24       return kSignedGreaterThanOrEqual;
     25     case kSignedGreaterThan:
     26       return kSignedLessThan;
     27     case kUnsignedLessThan:
     28       return kUnsignedGreaterThan;
     29     case kUnsignedGreaterThanOrEqual:
     30       return kUnsignedLessThanOrEqual;
     31     case kUnsignedLessThanOrEqual:
     32       return kUnsignedGreaterThanOrEqual;
     33     case kUnsignedGreaterThan:
     34       return kUnsignedLessThan;
     35     case kFloatLessThanOrUnordered:
     36       return kFloatGreaterThanOrUnordered;
     37     case kFloatGreaterThanOrEqual:
     38       return kFloatLessThanOrEqual;
     39     case kFloatLessThanOrEqual:
     40       return kFloatGreaterThanOrEqual;
     41     case kFloatGreaterThanOrUnordered:
     42       return kFloatLessThanOrUnordered;
     43     case kFloatLessThan:
     44       return kFloatGreaterThan;
     45     case kFloatGreaterThanOrEqualOrUnordered:
     46       return kFloatLessThanOrEqualOrUnordered;
     47     case kFloatLessThanOrEqualOrUnordered:
     48       return kFloatGreaterThanOrEqualOrUnordered;
     49     case kFloatGreaterThan:
     50       return kFloatLessThan;
     51     case kEqual:
     52     case kNotEqual:
     53     case kOverflow:
     54     case kNotOverflow:
     55     case kUnorderedEqual:
     56     case kUnorderedNotEqual:
     57       return condition;
     58   }
     59   UNREACHABLE();
     60   return condition;
     61 }
     62 
     63 bool InstructionOperand::InterferesWith(const InstructionOperand& that) const {
     64   if (!IsFPRegister() || !that.IsFPRegister() || kSimpleFPAliasing)
     65     return EqualsCanonicalized(that);
     66   // Both operands are fp registers and aliasing is non-simple.
     67   const LocationOperand& loc1 = *LocationOperand::cast(this);
     68   const LocationOperand& loc2 = LocationOperand::cast(that);
     69   return GetRegConfig()->AreAliases(loc1.representation(), loc1.register_code(),
     70                                     loc2.representation(),
     71                                     loc2.register_code());
     72 }
     73 
     74 void InstructionOperand::Print(const RegisterConfiguration* config) const {
     75   OFStream os(stdout);
     76   PrintableInstructionOperand wrapper;
     77   wrapper.register_configuration_ = config;
     78   wrapper.op_ = *this;
     79   os << wrapper << std::endl;
     80 }
     81 
     82 void InstructionOperand::Print() const { Print(GetRegConfig()); }
     83 
     84 std::ostream& operator<<(std::ostream& os,
     85                          const PrintableInstructionOperand& printable) {
     86   const InstructionOperand& op = printable.op_;
     87   const RegisterConfiguration* conf = printable.register_configuration_;
     88   switch (op.kind()) {
     89     case InstructionOperand::UNALLOCATED: {
     90       const UnallocatedOperand* unalloc = UnallocatedOperand::cast(&op);
     91       os << "v" << unalloc->virtual_register();
     92       if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
     93         return os << "(=" << unalloc->fixed_slot_index() << "S)";
     94       }
     95       switch (unalloc->extended_policy()) {
     96         case UnallocatedOperand::NONE:
     97           return os;
     98         case UnallocatedOperand::FIXED_REGISTER:
     99           return os << "(="
    100                     << conf->GetGeneralRegisterName(
    101                            unalloc->fixed_register_index())
    102                     << ")";
    103         case UnallocatedOperand::FIXED_FP_REGISTER:
    104           return os << "(="
    105                     << conf->GetDoubleRegisterName(
    106                            unalloc->fixed_register_index())
    107                     << ")";
    108         case UnallocatedOperand::MUST_HAVE_REGISTER:
    109           return os << "(R)";
    110         case UnallocatedOperand::MUST_HAVE_SLOT:
    111           return os << "(S)";
    112         case UnallocatedOperand::SAME_AS_FIRST_INPUT:
    113           return os << "(1)";
    114         case UnallocatedOperand::ANY:
    115           return os << "(-)";
    116       }
    117     }
    118     case InstructionOperand::CONSTANT:
    119       return os << "[constant:" << ConstantOperand::cast(op).virtual_register()
    120                 << "]";
    121     case InstructionOperand::IMMEDIATE: {
    122       ImmediateOperand imm = ImmediateOperand::cast(op);
    123       switch (imm.type()) {
    124         case ImmediateOperand::INLINE:
    125           return os << "#" << imm.inline_value();
    126         case ImmediateOperand::INDEXED:
    127           return os << "[immediate:" << imm.indexed_value() << "]";
    128       }
    129     }
    130     case InstructionOperand::EXPLICIT:
    131     case InstructionOperand::ALLOCATED: {
    132       LocationOperand allocated = LocationOperand::cast(op);
    133       if (op.IsStackSlot()) {
    134         os << "[stack:" << allocated.index();
    135       } else if (op.IsFPStackSlot()) {
    136         os << "[fp_stack:" << allocated.index();
    137       } else if (op.IsRegister()) {
    138         os << "["
    139            << GetRegConfig()->GetGeneralRegisterName(allocated.register_code())
    140            << "|R";
    141       } else if (op.IsDoubleRegister()) {
    142         os << "["
    143            << GetRegConfig()->GetDoubleRegisterName(allocated.register_code())
    144            << "|R";
    145       } else {
    146         DCHECK(op.IsFloatRegister());
    147         os << "["
    148            << GetRegConfig()->GetFloatRegisterName(allocated.register_code())
    149            << "|R";
    150       }
    151       if (allocated.IsExplicit()) {
    152         os << "|E";
    153       }
    154       switch (allocated.representation()) {
    155         case MachineRepresentation::kNone:
    156           os << "|-";
    157           break;
    158         case MachineRepresentation::kBit:
    159           os << "|b";
    160           break;
    161         case MachineRepresentation::kWord8:
    162           os << "|w8";
    163           break;
    164         case MachineRepresentation::kWord16:
    165           os << "|w16";
    166           break;
    167         case MachineRepresentation::kWord32:
    168           os << "|w32";
    169           break;
    170         case MachineRepresentation::kWord64:
    171           os << "|w64";
    172           break;
    173         case MachineRepresentation::kFloat32:
    174           os << "|f32";
    175           break;
    176         case MachineRepresentation::kFloat64:
    177           os << "|f64";
    178           break;
    179         case MachineRepresentation::kSimd128:
    180           os << "|s128";
    181           break;
    182         case MachineRepresentation::kTagged:
    183           os << "|t";
    184           break;
    185       }
    186       return os << "]";
    187     }
    188     case InstructionOperand::INVALID:
    189       return os << "(x)";
    190   }
    191   UNREACHABLE();
    192   return os;
    193 }
    194 
    195 void MoveOperands::Print(const RegisterConfiguration* config) const {
    196   OFStream os(stdout);
    197   PrintableInstructionOperand wrapper;
    198   wrapper.register_configuration_ = config;
    199   wrapper.op_ = destination();
    200   os << wrapper << " = ";
    201   wrapper.op_ = source();
    202   os << wrapper << std::endl;
    203 }
    204 
    205 void MoveOperands::Print() const { Print(GetRegConfig()); }
    206 
    207 std::ostream& operator<<(std::ostream& os,
    208                          const PrintableMoveOperands& printable) {
    209   const MoveOperands& mo = *printable.move_operands_;
    210   PrintableInstructionOperand printable_op = {printable.register_configuration_,
    211                                               mo.destination()};
    212   os << printable_op;
    213   if (!mo.source().Equals(mo.destination())) {
    214     printable_op.op_ = mo.source();
    215     os << " = " << printable_op;
    216   }
    217   return os << ";";
    218 }
    219 
    220 
    221 bool ParallelMove::IsRedundant() const {
    222   for (MoveOperands* move : *this) {
    223     if (!move->IsRedundant()) return false;
    224   }
    225   return true;
    226 }
    227 
    228 
    229 MoveOperands* ParallelMove::PrepareInsertAfter(MoveOperands* move) const {
    230   MoveOperands* replacement = nullptr;
    231   MoveOperands* to_eliminate = nullptr;
    232   for (MoveOperands* curr : *this) {
    233     if (curr->IsEliminated()) continue;
    234     if (curr->destination().EqualsCanonicalized(move->source())) {
    235       DCHECK(!replacement);
    236       replacement = curr;
    237       if (to_eliminate != nullptr) break;
    238     } else if (curr->destination().EqualsCanonicalized(move->destination())) {
    239       DCHECK(!to_eliminate);
    240       to_eliminate = curr;
    241       if (replacement != nullptr) break;
    242     }
    243   }
    244   DCHECK_IMPLIES(replacement == to_eliminate, replacement == nullptr);
    245   if (replacement != nullptr) move->set_source(replacement->source());
    246   return to_eliminate;
    247 }
    248 
    249 
    250 ExplicitOperand::ExplicitOperand(LocationKind kind, MachineRepresentation rep,
    251                                  int index)
    252     : LocationOperand(EXPLICIT, kind, rep, index) {
    253   DCHECK_IMPLIES(kind == REGISTER && !IsFloatingPoint(rep),
    254                  GetRegConfig()->IsAllocatableGeneralCode(index));
    255   DCHECK_IMPLIES(kind == REGISTER && rep == MachineRepresentation::kFloat32,
    256                  GetRegConfig()->IsAllocatableFloatCode(index));
    257   DCHECK_IMPLIES(kind == REGISTER && (rep == MachineRepresentation::kFloat64),
    258                  GetRegConfig()->IsAllocatableDoubleCode(index));
    259 }
    260 
    261 Instruction::Instruction(InstructionCode opcode)
    262     : opcode_(opcode),
    263       bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
    264                  TempCountField::encode(0) | IsCallField::encode(false)),
    265       reference_map_(nullptr),
    266       block_(nullptr) {
    267   parallel_moves_[0] = nullptr;
    268   parallel_moves_[1] = nullptr;
    269 }
    270 
    271 Instruction::Instruction(InstructionCode opcode, size_t output_count,
    272                          InstructionOperand* outputs, size_t input_count,
    273                          InstructionOperand* inputs, size_t temp_count,
    274                          InstructionOperand* temps)
    275     : opcode_(opcode),
    276       bit_field_(OutputCountField::encode(output_count) |
    277                  InputCountField::encode(input_count) |
    278                  TempCountField::encode(temp_count) |
    279                  IsCallField::encode(false)),
    280       reference_map_(nullptr),
    281       block_(nullptr) {
    282   parallel_moves_[0] = nullptr;
    283   parallel_moves_[1] = nullptr;
    284   size_t offset = 0;
    285   for (size_t i = 0; i < output_count; ++i) {
    286     DCHECK(!outputs[i].IsInvalid());
    287     operands_[offset++] = outputs[i];
    288   }
    289   for (size_t i = 0; i < input_count; ++i) {
    290     DCHECK(!inputs[i].IsInvalid());
    291     operands_[offset++] = inputs[i];
    292   }
    293   for (size_t i = 0; i < temp_count; ++i) {
    294     DCHECK(!temps[i].IsInvalid());
    295     operands_[offset++] = temps[i];
    296   }
    297 }
    298 
    299 
    300 bool Instruction::AreMovesRedundant() const {
    301   for (int i = Instruction::FIRST_GAP_POSITION;
    302        i <= Instruction::LAST_GAP_POSITION; i++) {
    303     if (parallel_moves_[i] != nullptr && !parallel_moves_[i]->IsRedundant()) {
    304       return false;
    305     }
    306   }
    307   return true;
    308 }
    309 
    310 
    311 void Instruction::Print(const RegisterConfiguration* config) const {
    312   OFStream os(stdout);
    313   PrintableInstruction wrapper;
    314   wrapper.instr_ = this;
    315   wrapper.register_configuration_ = config;
    316   os << wrapper << std::endl;
    317 }
    318 
    319 void Instruction::Print() const { Print(GetRegConfig()); }
    320 
    321 std::ostream& operator<<(std::ostream& os,
    322                          const PrintableParallelMove& printable) {
    323   const ParallelMove& pm = *printable.parallel_move_;
    324   bool first = true;
    325   for (MoveOperands* move : pm) {
    326     if (move->IsEliminated()) continue;
    327     if (!first) os << " ";
    328     first = false;
    329     PrintableMoveOperands pmo = {printable.register_configuration_, move};
    330     os << pmo;
    331   }
    332   return os;
    333 }
    334 
    335 
    336 void ReferenceMap::RecordReference(const AllocatedOperand& op) {
    337   // Do not record arguments as pointers.
    338   if (op.IsStackSlot() && LocationOperand::cast(op).index() < 0) return;
    339   DCHECK(!op.IsFPRegister() && !op.IsFPStackSlot());
    340   reference_operands_.push_back(op);
    341 }
    342 
    343 
    344 std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm) {
    345   os << "{";
    346   bool first = true;
    347   PrintableInstructionOperand poi = {GetRegConfig(), InstructionOperand()};
    348   for (const InstructionOperand& op : pm.reference_operands_) {
    349     if (!first) {
    350       os << ";";
    351     } else {
    352       first = false;
    353     }
    354     poi.op_ = op;
    355     os << poi;
    356   }
    357   return os << "}";
    358 }
    359 
    360 
    361 std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
    362   switch (ao) {
    363 #define CASE(Name) \
    364   case k##Name:    \
    365     return os << #Name;
    366     ARCH_OPCODE_LIST(CASE)
    367 #undef CASE
    368   }
    369   UNREACHABLE();
    370   return os;
    371 }
    372 
    373 
    374 std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
    375   switch (am) {
    376     case kMode_None:
    377       return os;
    378 #define CASE(Name)   \
    379   case kMode_##Name: \
    380     return os << #Name;
    381       TARGET_ADDRESSING_MODE_LIST(CASE)
    382 #undef CASE
    383   }
    384   UNREACHABLE();
    385   return os;
    386 }
    387 
    388 
    389 std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
    390   switch (fm) {
    391     case kFlags_none:
    392       return os;
    393     case kFlags_branch:
    394       return os << "branch";
    395     case kFlags_deoptimize:
    396       return os << "deoptimize";
    397     case kFlags_set:
    398       return os << "set";
    399   }
    400   UNREACHABLE();
    401   return os;
    402 }
    403 
    404 
    405 std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
    406   switch (fc) {
    407     case kEqual:
    408       return os << "equal";
    409     case kNotEqual:
    410       return os << "not equal";
    411     case kSignedLessThan:
    412       return os << "signed less than";
    413     case kSignedGreaterThanOrEqual:
    414       return os << "signed greater than or equal";
    415     case kSignedLessThanOrEqual:
    416       return os << "signed less than or equal";
    417     case kSignedGreaterThan:
    418       return os << "signed greater than";
    419     case kUnsignedLessThan:
    420       return os << "unsigned less than";
    421     case kUnsignedGreaterThanOrEqual:
    422       return os << "unsigned greater than or equal";
    423     case kUnsignedLessThanOrEqual:
    424       return os << "unsigned less than or equal";
    425     case kUnsignedGreaterThan:
    426       return os << "unsigned greater than";
    427     case kFloatLessThanOrUnordered:
    428       return os << "less than or unordered (FP)";
    429     case kFloatGreaterThanOrEqual:
    430       return os << "greater than or equal (FP)";
    431     case kFloatLessThanOrEqual:
    432       return os << "less than or equal (FP)";
    433     case kFloatGreaterThanOrUnordered:
    434       return os << "greater than or unordered (FP)";
    435     case kFloatLessThan:
    436       return os << "less than (FP)";
    437     case kFloatGreaterThanOrEqualOrUnordered:
    438       return os << "greater than, equal or unordered (FP)";
    439     case kFloatLessThanOrEqualOrUnordered:
    440       return os << "less than, equal or unordered (FP)";
    441     case kFloatGreaterThan:
    442       return os << "greater than (FP)";
    443     case kUnorderedEqual:
    444       return os << "unordered equal";
    445     case kUnorderedNotEqual:
    446       return os << "unordered not equal";
    447     case kOverflow:
    448       return os << "overflow";
    449     case kNotOverflow:
    450       return os << "not overflow";
    451   }
    452   UNREACHABLE();
    453   return os;
    454 }
    455 
    456 
    457 std::ostream& operator<<(std::ostream& os,
    458                          const PrintableInstruction& printable) {
    459   const Instruction& instr = *printable.instr_;
    460   PrintableInstructionOperand printable_op = {printable.register_configuration_,
    461                                               InstructionOperand()};
    462   os << "gap ";
    463   for (int i = Instruction::FIRST_GAP_POSITION;
    464        i <= Instruction::LAST_GAP_POSITION; i++) {
    465     os << "(";
    466     if (instr.parallel_moves()[i] != nullptr) {
    467       PrintableParallelMove ppm = {printable.register_configuration_,
    468                                    instr.parallel_moves()[i]};
    469       os << ppm;
    470     }
    471     os << ") ";
    472   }
    473   os << "\n          ";
    474 
    475   if (instr.OutputCount() > 1) os << "(";
    476   for (size_t i = 0; i < instr.OutputCount(); i++) {
    477     if (i > 0) os << ", ";
    478     printable_op.op_ = *instr.OutputAt(i);
    479     os << printable_op;
    480   }
    481 
    482   if (instr.OutputCount() > 1) os << ") = ";
    483   if (instr.OutputCount() == 1) os << " = ";
    484 
    485   os << ArchOpcodeField::decode(instr.opcode());
    486   AddressingMode am = AddressingModeField::decode(instr.opcode());
    487   if (am != kMode_None) {
    488     os << " : " << AddressingModeField::decode(instr.opcode());
    489   }
    490   FlagsMode fm = FlagsModeField::decode(instr.opcode());
    491   if (fm != kFlags_none) {
    492     os << " && " << fm << " if " << FlagsConditionField::decode(instr.opcode());
    493   }
    494   if (instr.InputCount() > 0) {
    495     for (size_t i = 0; i < instr.InputCount(); i++) {
    496       printable_op.op_ = *instr.InputAt(i);
    497       os << " " << printable_op;
    498     }
    499   }
    500   return os;
    501 }
    502 
    503 
    504 Constant::Constant(int32_t v) : type_(kInt32), value_(v) {}
    505 
    506 Constant::Constant(RelocatablePtrConstantInfo info) {
    507   if (info.type() == RelocatablePtrConstantInfo::kInt32) {
    508     type_ = kInt32;
    509   } else if (info.type() == RelocatablePtrConstantInfo::kInt64) {
    510     type_ = kInt64;
    511   } else {
    512     UNREACHABLE();
    513   }
    514   value_ = info.value();
    515   rmode_ = info.rmode();
    516 }
    517 
    518 Handle<HeapObject> Constant::ToHeapObject() const {
    519   DCHECK_EQ(kHeapObject, type());
    520   Handle<HeapObject> value(
    521       bit_cast<HeapObject**>(static_cast<intptr_t>(value_)));
    522   if (value->IsConsString()) {
    523     value = String::Flatten(Handle<String>::cast(value), TENURED);
    524   }
    525   return value;
    526 }
    527 
    528 std::ostream& operator<<(std::ostream& os, const Constant& constant) {
    529   switch (constant.type()) {
    530     case Constant::kInt32:
    531       return os << constant.ToInt32();
    532     case Constant::kInt64:
    533       return os << constant.ToInt64() << "l";
    534     case Constant::kFloat32:
    535       return os << constant.ToFloat32() << "f";
    536     case Constant::kFloat64:
    537       return os << constant.ToFloat64();
    538     case Constant::kExternalReference:
    539       return os << static_cast<const void*>(
    540                        constant.ToExternalReference().address());
    541     case Constant::kHeapObject:
    542       return os << Brief(*constant.ToHeapObject());
    543     case Constant::kRpoNumber:
    544       return os << "RPO" << constant.ToRpoNumber().ToInt();
    545   }
    546   UNREACHABLE();
    547   return os;
    548 }
    549 
    550 
    551 PhiInstruction::PhiInstruction(Zone* zone, int virtual_register,
    552                                size_t input_count)
    553     : virtual_register_(virtual_register),
    554       output_(UnallocatedOperand(UnallocatedOperand::NONE, virtual_register)),
    555       operands_(input_count, InstructionOperand::kInvalidVirtualRegister,
    556                 zone) {}
    557 
    558 
    559 void PhiInstruction::SetInput(size_t offset, int virtual_register) {
    560   DCHECK_EQ(InstructionOperand::kInvalidVirtualRegister, operands_[offset]);
    561   operands_[offset] = virtual_register;
    562 }
    563 
    564 
    565 InstructionBlock::InstructionBlock(Zone* zone, RpoNumber rpo_number,
    566                                    RpoNumber loop_header, RpoNumber loop_end,
    567                                    bool deferred, bool handler)
    568     : successors_(zone),
    569       predecessors_(zone),
    570       phis_(zone),
    571       ao_number_(rpo_number),
    572       rpo_number_(rpo_number),
    573       loop_header_(loop_header),
    574       loop_end_(loop_end),
    575       code_start_(-1),
    576       code_end_(-1),
    577       deferred_(deferred),
    578       handler_(handler),
    579       needs_frame_(false),
    580       must_construct_frame_(false),
    581       must_deconstruct_frame_(false),
    582       last_deferred_(RpoNumber::Invalid()) {}
    583 
    584 
    585 size_t InstructionBlock::PredecessorIndexOf(RpoNumber rpo_number) const {
    586   size_t j = 0;
    587   for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
    588        i != predecessors_.end(); ++i, ++j) {
    589     if (*i == rpo_number) break;
    590   }
    591   return j;
    592 }
    593 
    594 
    595 static RpoNumber GetRpo(const BasicBlock* block) {
    596   if (block == nullptr) return RpoNumber::Invalid();
    597   return RpoNumber::FromInt(block->rpo_number());
    598 }
    599 
    600 
    601 static RpoNumber GetLoopEndRpo(const BasicBlock* block) {
    602   if (!block->IsLoopHeader()) return RpoNumber::Invalid();
    603   return RpoNumber::FromInt(block->loop_end()->rpo_number());
    604 }
    605 
    606 
    607 static InstructionBlock* InstructionBlockFor(Zone* zone,
    608                                              const BasicBlock* block) {
    609   bool is_handler =
    610       !block->empty() && block->front()->opcode() == IrOpcode::kIfException;
    611   InstructionBlock* instr_block = new (zone)
    612       InstructionBlock(zone, GetRpo(block), GetRpo(block->loop_header()),
    613                        GetLoopEndRpo(block), block->deferred(), is_handler);
    614   // Map successors and precessors
    615   instr_block->successors().reserve(block->SuccessorCount());
    616   for (BasicBlock* successor : block->successors()) {
    617     instr_block->successors().push_back(GetRpo(successor));
    618   }
    619   instr_block->predecessors().reserve(block->PredecessorCount());
    620   for (BasicBlock* predecessor : block->predecessors()) {
    621     instr_block->predecessors().push_back(GetRpo(predecessor));
    622   }
    623   return instr_block;
    624 }
    625 
    626 InstructionBlocks* InstructionSequence::InstructionBlocksFor(
    627     Zone* zone, const Schedule* schedule) {
    628   InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
    629   new (blocks) InstructionBlocks(
    630       static_cast<int>(schedule->rpo_order()->size()), nullptr, zone);
    631   size_t rpo_number = 0;
    632   for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
    633        it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
    634     DCHECK(!(*blocks)[rpo_number]);
    635     DCHECK(GetRpo(*it).ToSize() == rpo_number);
    636     (*blocks)[rpo_number] = InstructionBlockFor(zone, *it);
    637   }
    638   ComputeAssemblyOrder(blocks);
    639   return blocks;
    640 }
    641 
    642 void InstructionSequence::ValidateEdgeSplitForm() const {
    643   // Validate blocks are in edge-split form: no block with multiple successors
    644   // has an edge to a block (== a successor) with more than one predecessors.
    645   for (const InstructionBlock* block : instruction_blocks()) {
    646     if (block->SuccessorCount() > 1) {
    647       for (const RpoNumber& successor_id : block->successors()) {
    648         const InstructionBlock* successor = InstructionBlockAt(successor_id);
    649         // Expect precisely one predecessor: "block".
    650         CHECK(successor->PredecessorCount() == 1 &&
    651               successor->predecessors()[0] == block->rpo_number());
    652       }
    653     }
    654   }
    655 }
    656 
    657 void InstructionSequence::ValidateDeferredBlockExitPaths() const {
    658   // A deferred block with more than one successor must have all its successors
    659   // deferred.
    660   for (const InstructionBlock* block : instruction_blocks()) {
    661     if (!block->IsDeferred() || block->SuccessorCount() <= 1) continue;
    662     for (RpoNumber successor_id : block->successors()) {
    663       CHECK(InstructionBlockAt(successor_id)->IsDeferred());
    664     }
    665   }
    666 }
    667 
    668 void InstructionSequence::ValidateDeferredBlockEntryPaths() const {
    669   // If a deferred block has multiple predecessors, they have to
    670   // all be deferred. Otherwise, we can run into a situation where a range
    671   // that spills only in deferred blocks inserts its spill in the block, but
    672   // other ranges need moves inserted by ResolveControlFlow in the predecessors,
    673   // which may clobber the register of this range.
    674   for (const InstructionBlock* block : instruction_blocks()) {
    675     if (!block->IsDeferred() || block->PredecessorCount() <= 1) continue;
    676     for (RpoNumber predecessor_id : block->predecessors()) {
    677       CHECK(InstructionBlockAt(predecessor_id)->IsDeferred());
    678     }
    679   }
    680 }
    681 
    682 void InstructionSequence::ValidateSSA() const {
    683   // TODO(mtrofin): We could use a local zone here instead.
    684   BitVector definitions(VirtualRegisterCount(), zone());
    685   for (const Instruction* instruction : *this) {
    686     for (size_t i = 0; i < instruction->OutputCount(); ++i) {
    687       const InstructionOperand* output = instruction->OutputAt(i);
    688       int vreg = (output->IsConstant())
    689                      ? ConstantOperand::cast(output)->virtual_register()
    690                      : UnallocatedOperand::cast(output)->virtual_register();
    691       CHECK(!definitions.Contains(vreg));
    692       definitions.Add(vreg);
    693     }
    694   }
    695 }
    696 
    697 void InstructionSequence::ComputeAssemblyOrder(InstructionBlocks* blocks) {
    698   int ao = 0;
    699   for (InstructionBlock* const block : *blocks) {
    700     if (!block->IsDeferred()) {
    701       block->set_ao_number(RpoNumber::FromInt(ao++));
    702     }
    703   }
    704   for (InstructionBlock* const block : *blocks) {
    705     if (block->IsDeferred()) {
    706       block->set_ao_number(RpoNumber::FromInt(ao++));
    707     }
    708   }
    709 }
    710 
    711 InstructionSequence::InstructionSequence(Isolate* isolate,
    712                                          Zone* instruction_zone,
    713                                          InstructionBlocks* instruction_blocks)
    714     : isolate_(isolate),
    715       zone_(instruction_zone),
    716       instruction_blocks_(instruction_blocks),
    717       source_positions_(zone()),
    718       constants_(ConstantMap::key_compare(),
    719                  ConstantMap::allocator_type(zone())),
    720       immediates_(zone()),
    721       instructions_(zone()),
    722       next_virtual_register_(0),
    723       reference_maps_(zone()),
    724       representations_(zone()),
    725       deoptimization_entries_(zone()),
    726       current_block_(nullptr) {}
    727 
    728 int InstructionSequence::NextVirtualRegister() {
    729   int virtual_register = next_virtual_register_++;
    730   CHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
    731   return virtual_register;
    732 }
    733 
    734 
    735 Instruction* InstructionSequence::GetBlockStart(RpoNumber rpo) const {
    736   const InstructionBlock* block = InstructionBlockAt(rpo);
    737   return InstructionAt(block->code_start());
    738 }
    739 
    740 
    741 void InstructionSequence::StartBlock(RpoNumber rpo) {
    742   DCHECK_NULL(current_block_);
    743   current_block_ = InstructionBlockAt(rpo);
    744   int code_start = static_cast<int>(instructions_.size());
    745   current_block_->set_code_start(code_start);
    746 }
    747 
    748 
    749 void InstructionSequence::EndBlock(RpoNumber rpo) {
    750   int end = static_cast<int>(instructions_.size());
    751   DCHECK_EQ(current_block_->rpo_number(), rpo);
    752   if (current_block_->code_start() == end) {  // Empty block.  Insert a nop.
    753     AddInstruction(Instruction::New(zone(), kArchNop));
    754     end = static_cast<int>(instructions_.size());
    755   }
    756   DCHECK(current_block_->code_start() >= 0 &&
    757          current_block_->code_start() < end);
    758   current_block_->set_code_end(end);
    759   current_block_ = nullptr;
    760 }
    761 
    762 
    763 int InstructionSequence::AddInstruction(Instruction* instr) {
    764   DCHECK_NOT_NULL(current_block_);
    765   int index = static_cast<int>(instructions_.size());
    766   instr->set_block(current_block_);
    767   instructions_.push_back(instr);
    768   if (instr->NeedsReferenceMap()) {
    769     DCHECK(instr->reference_map() == nullptr);
    770     ReferenceMap* reference_map = new (zone()) ReferenceMap(zone());
    771     reference_map->set_instruction_position(index);
    772     instr->set_reference_map(reference_map);
    773     reference_maps_.push_back(reference_map);
    774   }
    775   return index;
    776 }
    777 
    778 
    779 InstructionBlock* InstructionSequence::GetInstructionBlock(
    780     int instruction_index) const {
    781   return instructions()[instruction_index]->block();
    782 }
    783 
    784 
    785 static MachineRepresentation FilterRepresentation(MachineRepresentation rep) {
    786   switch (rep) {
    787     case MachineRepresentation::kBit:
    788     case MachineRepresentation::kWord8:
    789     case MachineRepresentation::kWord16:
    790       return InstructionSequence::DefaultRepresentation();
    791     case MachineRepresentation::kWord32:
    792     case MachineRepresentation::kWord64:
    793     case MachineRepresentation::kFloat32:
    794     case MachineRepresentation::kFloat64:
    795     case MachineRepresentation::kSimd128:
    796     case MachineRepresentation::kTagged:
    797       return rep;
    798     case MachineRepresentation::kNone:
    799       break;
    800   }
    801   UNREACHABLE();
    802   return MachineRepresentation::kNone;
    803 }
    804 
    805 
    806 MachineRepresentation InstructionSequence::GetRepresentation(
    807     int virtual_register) const {
    808   DCHECK_LE(0, virtual_register);
    809   DCHECK_LT(virtual_register, VirtualRegisterCount());
    810   if (virtual_register >= static_cast<int>(representations_.size())) {
    811     return DefaultRepresentation();
    812   }
    813   return representations_[virtual_register];
    814 }
    815 
    816 
    817 void InstructionSequence::MarkAsRepresentation(MachineRepresentation rep,
    818                                                int virtual_register) {
    819   DCHECK_LE(0, virtual_register);
    820   DCHECK_LT(virtual_register, VirtualRegisterCount());
    821   if (virtual_register >= static_cast<int>(representations_.size())) {
    822     representations_.resize(VirtualRegisterCount(), DefaultRepresentation());
    823   }
    824   rep = FilterRepresentation(rep);
    825   DCHECK_IMPLIES(representations_[virtual_register] != rep,
    826                  representations_[virtual_register] == DefaultRepresentation());
    827   representations_[virtual_register] = rep;
    828 }
    829 
    830 
    831 InstructionSequence::StateId InstructionSequence::AddFrameStateDescriptor(
    832     FrameStateDescriptor* descriptor) {
    833   int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
    834   deoptimization_entries_.push_back(descriptor);
    835   return StateId::FromInt(deoptimization_id);
    836 }
    837 
    838 FrameStateDescriptor* InstructionSequence::GetFrameStateDescriptor(
    839     InstructionSequence::StateId state_id) {
    840   return deoptimization_entries_[state_id.ToInt()];
    841 }
    842 
    843 
    844 int InstructionSequence::GetFrameStateDescriptorCount() {
    845   return static_cast<int>(deoptimization_entries_.size());
    846 }
    847 
    848 
    849 RpoNumber InstructionSequence::InputRpo(Instruction* instr, size_t index) {
    850   InstructionOperand* operand = instr->InputAt(index);
    851   Constant constant =
    852       operand->IsImmediate()
    853           ? GetImmediate(ImmediateOperand::cast(operand))
    854           : GetConstant(ConstantOperand::cast(operand)->virtual_register());
    855   return constant.ToRpoNumber();
    856 }
    857 
    858 
    859 bool InstructionSequence::GetSourcePosition(const Instruction* instr,
    860                                             SourcePosition* result) const {
    861   auto it = source_positions_.find(instr);
    862   if (it == source_positions_.end()) return false;
    863   *result = it->second;
    864   return true;
    865 }
    866 
    867 
    868 void InstructionSequence::SetSourcePosition(const Instruction* instr,
    869                                             SourcePosition value) {
    870   source_positions_.insert(std::make_pair(instr, value));
    871 }
    872 
    873 
    874 void InstructionSequence::Print(const RegisterConfiguration* config) const {
    875   OFStream os(stdout);
    876   PrintableInstructionSequence wrapper;
    877   wrapper.register_configuration_ = config;
    878   wrapper.sequence_ = this;
    879   os << wrapper << std::endl;
    880 }
    881 
    882 void InstructionSequence::Print() const { Print(GetRegConfig()); }
    883 
    884 void InstructionSequence::PrintBlock(const RegisterConfiguration* config,
    885                                      int block_id) const {
    886   OFStream os(stdout);
    887   RpoNumber rpo = RpoNumber::FromInt(block_id);
    888   const InstructionBlock* block = InstructionBlockAt(rpo);
    889   CHECK(block->rpo_number() == rpo);
    890 
    891   os << "B" << block->rpo_number();
    892   os << ": AO#" << block->ao_number();
    893   if (block->IsDeferred()) os << " (deferred)";
    894   if (!block->needs_frame()) os << " (no frame)";
    895   if (block->must_construct_frame()) os << " (construct frame)";
    896   if (block->must_deconstruct_frame()) os << " (deconstruct frame)";
    897   if (block->IsLoopHeader()) {
    898     os << " loop blocks: [" << block->rpo_number() << ", " << block->loop_end()
    899        << ")";
    900   }
    901   os << "  instructions: [" << block->code_start() << ", " << block->code_end()
    902      << ")\n  predecessors:";
    903 
    904   for (RpoNumber pred : block->predecessors()) {
    905     os << " B" << pred.ToInt();
    906   }
    907   os << "\n";
    908 
    909   for (const PhiInstruction* phi : block->phis()) {
    910     PrintableInstructionOperand printable_op = {config, phi->output()};
    911     os << "     phi: " << printable_op << " =";
    912     for (int input : phi->operands()) {
    913       os << " v" << input;
    914     }
    915     os << "\n";
    916   }
    917 
    918   ScopedVector<char> buf(32);
    919   PrintableInstruction printable_instr;
    920   printable_instr.register_configuration_ = config;
    921   for (int j = block->first_instruction_index();
    922        j <= block->last_instruction_index(); j++) {
    923     // TODO(svenpanne) Add some basic formatting to our streams.
    924     SNPrintF(buf, "%5d", j);
    925     printable_instr.instr_ = InstructionAt(j);
    926     os << "   " << buf.start() << ": " << printable_instr << "\n";
    927   }
    928 
    929   for (RpoNumber succ : block->successors()) {
    930     os << " B" << succ.ToInt();
    931   }
    932   os << "\n";
    933 }
    934 
    935 void InstructionSequence::PrintBlock(int block_id) const {
    936   PrintBlock(GetRegConfig(), block_id);
    937 }
    938 
    939 FrameStateDescriptor::FrameStateDescriptor(
    940     Zone* zone, FrameStateType type, BailoutId bailout_id,
    941     OutputFrameStateCombine state_combine, size_t parameters_count,
    942     size_t locals_count, size_t stack_count,
    943     MaybeHandle<SharedFunctionInfo> shared_info,
    944     FrameStateDescriptor* outer_state)
    945     : type_(type),
    946       bailout_id_(bailout_id),
    947       frame_state_combine_(state_combine),
    948       parameters_count_(parameters_count),
    949       locals_count_(locals_count),
    950       stack_count_(stack_count),
    951       values_(zone),
    952       shared_info_(shared_info),
    953       outer_state_(outer_state) {}
    954 
    955 
    956 size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
    957   size_t size = 1 + parameters_count() + locals_count() + stack_count() +
    958                 (HasContext() ? 1 : 0);
    959   switch (combine.kind()) {
    960     case OutputFrameStateCombine::kPushOutput:
    961       size += combine.GetPushCount();
    962       break;
    963     case OutputFrameStateCombine::kPokeAt:
    964       break;
    965   }
    966   return size;
    967 }
    968 
    969 
    970 size_t FrameStateDescriptor::GetTotalSize() const {
    971   size_t total_size = 0;
    972   for (const FrameStateDescriptor* iter = this; iter != nullptr;
    973        iter = iter->outer_state_) {
    974     total_size += iter->GetSize();
    975   }
    976   return total_size;
    977 }
    978 
    979 
    980 size_t FrameStateDescriptor::GetFrameCount() const {
    981   size_t count = 0;
    982   for (const FrameStateDescriptor* iter = this; iter != nullptr;
    983        iter = iter->outer_state_) {
    984     ++count;
    985   }
    986   return count;
    987 }
    988 
    989 
    990 size_t FrameStateDescriptor::GetJSFrameCount() const {
    991   size_t count = 0;
    992   for (const FrameStateDescriptor* iter = this; iter != nullptr;
    993        iter = iter->outer_state_) {
    994     if (FrameStateFunctionInfo::IsJSFunctionType(iter->type_)) {
    995       ++count;
    996     }
    997   }
    998   return count;
    999 }
   1000 
   1001 
   1002 std::ostream& operator<<(std::ostream& os, const RpoNumber& rpo) {
   1003   return os << rpo.ToSize();
   1004 }
   1005 
   1006 
   1007 std::ostream& operator<<(std::ostream& os,
   1008                          const PrintableInstructionSequence& printable) {
   1009   const InstructionSequence& code = *printable.sequence_;
   1010   for (size_t i = 0; i < code.immediates_.size(); ++i) {
   1011     Constant constant = code.immediates_[i];
   1012     os << "IMM#" << i << ": " << constant << "\n";
   1013   }
   1014   int i = 0;
   1015   for (ConstantMap::const_iterator it = code.constants_.begin();
   1016        it != code.constants_.end(); ++i, ++it) {
   1017     os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
   1018   }
   1019   for (int i = 0; i < code.InstructionBlockCount(); i++) {
   1020     printable.sequence_->PrintBlock(printable.register_configuration_, i);
   1021   }
   1022   return os;
   1023 }
   1024 
   1025 }  // namespace compiler
   1026 }  // namespace internal
   1027 }  // namespace v8
   1028