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