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