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/bit-vector.h"
      6 #include "src/compiler/instruction.h"
      7 #include "src/compiler/register-allocator-verifier.h"
      8 
      9 namespace v8 {
     10 namespace internal {
     11 namespace compiler {
     12 
     13 namespace {
     14 
     15 size_t OperandCount(const Instruction* instr) {
     16   return instr->InputCount() + instr->OutputCount() + instr->TempCount();
     17 }
     18 
     19 
     20 void VerifyEmptyGaps(const Instruction* instr) {
     21   for (int i = Instruction::FIRST_GAP_POSITION;
     22        i <= Instruction::LAST_GAP_POSITION; i++) {
     23     Instruction::GapPosition inner_pos =
     24         static_cast<Instruction::GapPosition>(i);
     25     CHECK(instr->GetParallelMove(inner_pos) == nullptr);
     26   }
     27 }
     28 
     29 
     30 void VerifyAllocatedGaps(const Instruction* instr) {
     31   for (int i = Instruction::FIRST_GAP_POSITION;
     32        i <= Instruction::LAST_GAP_POSITION; i++) {
     33     Instruction::GapPosition inner_pos =
     34         static_cast<Instruction::GapPosition>(i);
     35     auto moves = instr->GetParallelMove(inner_pos);
     36     if (moves == nullptr) continue;
     37     for (auto move : *moves) {
     38       if (move->IsRedundant()) continue;
     39       CHECK(move->source().IsAllocated() || move->source().IsConstant());
     40       CHECK(move->destination().IsAllocated());
     41     }
     42   }
     43 }
     44 
     45 }  // namespace
     46 
     47 
     48 void RegisterAllocatorVerifier::VerifyInput(
     49     const OperandConstraint& constraint) {
     50   CHECK_NE(kSameAsFirst, constraint.type_);
     51   if (constraint.type_ != kImmediate && constraint.type_ != kExplicit) {
     52     CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
     53              constraint.virtual_register_);
     54   }
     55 }
     56 
     57 
     58 void RegisterAllocatorVerifier::VerifyTemp(
     59     const OperandConstraint& constraint) {
     60   CHECK_NE(kSameAsFirst, constraint.type_);
     61   CHECK_NE(kImmediate, constraint.type_);
     62   CHECK_NE(kExplicit, constraint.type_);
     63   CHECK_NE(kConstant, constraint.type_);
     64 }
     65 
     66 
     67 void RegisterAllocatorVerifier::VerifyOutput(
     68     const OperandConstraint& constraint) {
     69   CHECK_NE(kImmediate, constraint.type_);
     70   CHECK_NE(kExplicit, constraint.type_);
     71   CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
     72            constraint.virtual_register_);
     73 }
     74 
     75 
     76 RegisterAllocatorVerifier::RegisterAllocatorVerifier(
     77     Zone* zone, const RegisterConfiguration* config,
     78     const InstructionSequence* sequence)
     79     : zone_(zone), config_(config), sequence_(sequence), constraints_(zone) {
     80   constraints_.reserve(sequence->instructions().size());
     81   // TODO(dcarney): model unique constraints.
     82   // Construct OperandConstraints for all InstructionOperands, eliminating
     83   // kSameAsFirst along the way.
     84   for (const auto* instr : sequence->instructions()) {
     85     // All gaps should be totally unallocated at this point.
     86     VerifyEmptyGaps(instr);
     87     const size_t operand_count = OperandCount(instr);
     88     auto* op_constraints = zone->NewArray<OperandConstraint>(operand_count);
     89     size_t count = 0;
     90     for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
     91       BuildConstraint(instr->InputAt(i), &op_constraints[count]);
     92       VerifyInput(op_constraints[count]);
     93     }
     94     for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
     95       BuildConstraint(instr->TempAt(i), &op_constraints[count]);
     96       VerifyTemp(op_constraints[count]);
     97     }
     98     for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
     99       BuildConstraint(instr->OutputAt(i), &op_constraints[count]);
    100       if (op_constraints[count].type_ == kSameAsFirst) {
    101         CHECK(instr->InputCount() > 0);
    102         op_constraints[count].type_ = op_constraints[0].type_;
    103         op_constraints[count].value_ = op_constraints[0].value_;
    104       }
    105       VerifyOutput(op_constraints[count]);
    106     }
    107     InstructionConstraint instr_constraint = {instr, operand_count,
    108                                               op_constraints};
    109     constraints()->push_back(instr_constraint);
    110   }
    111 }
    112 
    113 
    114 void RegisterAllocatorVerifier::VerifyAssignment() {
    115   CHECK(sequence()->instructions().size() == constraints()->size());
    116   auto instr_it = sequence()->begin();
    117   for (const auto& instr_constraint : *constraints()) {
    118     const auto* instr = instr_constraint.instruction_;
    119     // All gaps should be totally allocated at this point.
    120     VerifyAllocatedGaps(instr);
    121     const size_t operand_count = instr_constraint.operand_constaints_size_;
    122     const auto* op_constraints = instr_constraint.operand_constraints_;
    123     CHECK_EQ(instr, *instr_it);
    124     CHECK(operand_count == OperandCount(instr));
    125     size_t count = 0;
    126     for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
    127       CheckConstraint(instr->InputAt(i), &op_constraints[count]);
    128     }
    129     for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
    130       CheckConstraint(instr->TempAt(i), &op_constraints[count]);
    131     }
    132     for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
    133       CheckConstraint(instr->OutputAt(i), &op_constraints[count]);
    134     }
    135     ++instr_it;
    136   }
    137 }
    138 
    139 
    140 void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
    141                                                 OperandConstraint* constraint) {
    142   constraint->value_ = kMinInt;
    143   constraint->virtual_register_ = InstructionOperand::kInvalidVirtualRegister;
    144   if (op->IsConstant()) {
    145     constraint->type_ = kConstant;
    146     constraint->value_ = ConstantOperand::cast(op)->virtual_register();
    147     constraint->virtual_register_ = constraint->value_;
    148   } else if (op->IsExplicit()) {
    149     constraint->type_ = kExplicit;
    150   } else if (op->IsImmediate()) {
    151     auto imm = ImmediateOperand::cast(op);
    152     int value = imm->type() == ImmediateOperand::INLINE ? imm->inline_value()
    153                                                         : imm->indexed_value();
    154     constraint->type_ = kImmediate;
    155     constraint->value_ = value;
    156   } else {
    157     CHECK(op->IsUnallocated());
    158     const auto* unallocated = UnallocatedOperand::cast(op);
    159     int vreg = unallocated->virtual_register();
    160     constraint->virtual_register_ = vreg;
    161     if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
    162       constraint->type_ = sequence()->IsFloat(vreg) ? kDoubleSlot : kSlot;
    163       constraint->value_ = unallocated->fixed_slot_index();
    164     } else {
    165       switch (unallocated->extended_policy()) {
    166         case UnallocatedOperand::ANY:
    167         case UnallocatedOperand::NONE:
    168           if (sequence()->IsFloat(vreg)) {
    169             constraint->type_ = kNoneDouble;
    170           } else {
    171             constraint->type_ = kNone;
    172           }
    173           break;
    174         case UnallocatedOperand::FIXED_REGISTER:
    175           if (unallocated->HasSecondaryStorage()) {
    176             constraint->type_ = kRegisterAndSlot;
    177             constraint->spilled_slot_ = unallocated->GetSecondaryStorage();
    178           } else {
    179             constraint->type_ = kFixedRegister;
    180           }
    181           constraint->value_ = unallocated->fixed_register_index();
    182           break;
    183         case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
    184           constraint->type_ = kFixedDoubleRegister;
    185           constraint->value_ = unallocated->fixed_register_index();
    186           break;
    187         case UnallocatedOperand::MUST_HAVE_REGISTER:
    188           if (sequence()->IsFloat(vreg)) {
    189             constraint->type_ = kDoubleRegister;
    190           } else {
    191             constraint->type_ = kRegister;
    192           }
    193           break;
    194         case UnallocatedOperand::MUST_HAVE_SLOT:
    195           constraint->type_ = sequence()->IsFloat(vreg) ? kDoubleSlot : kSlot;
    196           break;
    197         case UnallocatedOperand::SAME_AS_FIRST_INPUT:
    198           constraint->type_ = kSameAsFirst;
    199           break;
    200       }
    201     }
    202   }
    203 }
    204 
    205 
    206 void RegisterAllocatorVerifier::CheckConstraint(
    207     const InstructionOperand* op, const OperandConstraint* constraint) {
    208   switch (constraint->type_) {
    209     case kConstant:
    210       CHECK(op->IsConstant());
    211       CHECK_EQ(ConstantOperand::cast(op)->virtual_register(),
    212                constraint->value_);
    213       return;
    214     case kImmediate: {
    215       CHECK(op->IsImmediate());
    216       auto imm = ImmediateOperand::cast(op);
    217       int value = imm->type() == ImmediateOperand::INLINE
    218                       ? imm->inline_value()
    219                       : imm->indexed_value();
    220       CHECK_EQ(value, constraint->value_);
    221       return;
    222     }
    223     case kRegister:
    224       CHECK(op->IsRegister());
    225       return;
    226     case kDoubleRegister:
    227       CHECK(op->IsDoubleRegister());
    228       return;
    229     case kExplicit:
    230       CHECK(op->IsExplicit());
    231       return;
    232     case kFixedRegister:
    233     case kRegisterAndSlot:
    234       CHECK(op->IsRegister());
    235       CHECK_EQ(LocationOperand::cast(op)->GetRegister().code(),
    236                constraint->value_);
    237       return;
    238     case kFixedDoubleRegister:
    239       CHECK(op->IsDoubleRegister());
    240       CHECK_EQ(LocationOperand::cast(op)->GetDoubleRegister().code(),
    241                constraint->value_);
    242       return;
    243     case kFixedSlot:
    244       CHECK(op->IsStackSlot());
    245       CHECK_EQ(LocationOperand::cast(op)->index(), constraint->value_);
    246       return;
    247     case kSlot:
    248       CHECK(op->IsStackSlot());
    249       return;
    250     case kDoubleSlot:
    251       CHECK(op->IsDoubleStackSlot());
    252       return;
    253     case kNone:
    254       CHECK(op->IsRegister() || op->IsStackSlot());
    255       return;
    256     case kNoneDouble:
    257       CHECK(op->IsDoubleRegister() || op->IsDoubleStackSlot());
    258       return;
    259     case kSameAsFirst:
    260       CHECK(false);
    261       return;
    262   }
    263 }
    264 
    265 namespace {
    266 
    267 typedef RpoNumber Rpo;
    268 
    269 static const int kInvalidVreg = InstructionOperand::kInvalidVirtualRegister;
    270 
    271 struct PhiData : public ZoneObject {
    272   PhiData(Rpo definition_rpo, const PhiInstruction* phi, int first_pred_vreg,
    273           const PhiData* first_pred_phi, Zone* zone)
    274       : definition_rpo(definition_rpo),
    275         virtual_register(phi->virtual_register()),
    276         first_pred_vreg(first_pred_vreg),
    277         first_pred_phi(first_pred_phi),
    278         operands(zone) {
    279     operands.reserve(phi->operands().size());
    280     operands.insert(operands.begin(), phi->operands().begin(),
    281                     phi->operands().end());
    282   }
    283   const Rpo definition_rpo;
    284   const int virtual_register;
    285   const int first_pred_vreg;
    286   const PhiData* first_pred_phi;
    287   IntVector operands;
    288 };
    289 
    290 class PhiMap : public ZoneMap<int, PhiData*>, public ZoneObject {
    291  public:
    292   explicit PhiMap(Zone* zone) : ZoneMap<int, PhiData*>(zone) {}
    293 };
    294 
    295 struct OperandLess {
    296   bool operator()(const InstructionOperand* a,
    297                   const InstructionOperand* b) const {
    298     return a->CompareCanonicalized(*b);
    299   }
    300 };
    301 
    302 class OperandMap : public ZoneObject {
    303  public:
    304   struct MapValue : public ZoneObject {
    305     MapValue()
    306         : incoming(nullptr),
    307           define_vreg(kInvalidVreg),
    308           use_vreg(kInvalidVreg),
    309           succ_vreg(kInvalidVreg) {}
    310     MapValue* incoming;  // value from first predecessor block.
    311     int define_vreg;     // valid if this value was defined in this block.
    312     int use_vreg;        // valid if this value was used in this block.
    313     int succ_vreg;       // valid if propagated back from successor block.
    314   };
    315 
    316   class Map
    317       : public ZoneMap<const InstructionOperand*, MapValue*, OperandLess> {
    318    public:
    319     explicit Map(Zone* zone)
    320         : ZoneMap<const InstructionOperand*, MapValue*, OperandLess>(zone) {}
    321 
    322     // Remove all entries with keys not in other.
    323     void Intersect(const Map& other) {
    324       if (this->empty()) return;
    325       auto it = this->begin();
    326       OperandLess less;
    327       for (const auto& o : other) {
    328         while (less(it->first, o.first)) {
    329           this->erase(it++);
    330           if (it == this->end()) return;
    331         }
    332         if (it->first->EqualsCanonicalized(*o.first)) {
    333           ++it;
    334           if (it == this->end()) return;
    335         } else {
    336           CHECK(less(o.first, it->first));
    337         }
    338       }
    339     }
    340   };
    341 
    342   explicit OperandMap(Zone* zone) : map_(zone) {}
    343 
    344   Map& map() { return map_; }
    345 
    346   void RunParallelMoves(Zone* zone, const ParallelMove* moves) {
    347     // Compute outgoing mappings.
    348     Map to_insert(zone);
    349     for (auto move : *moves) {
    350       if (move->IsEliminated()) continue;
    351       auto cur = map().find(&move->source());
    352       CHECK(cur != map().end());
    353       auto res =
    354           to_insert.insert(std::make_pair(&move->destination(), cur->second));
    355       // Ensure injectivity of moves.
    356       CHECK(res.second);
    357     }
    358     // Drop current mappings.
    359     for (auto move : *moves) {
    360       if (move->IsEliminated()) continue;
    361       auto cur = map().find(&move->destination());
    362       if (cur != map().end()) map().erase(cur);
    363     }
    364     // Insert new values.
    365     map().insert(to_insert.begin(), to_insert.end());
    366   }
    367 
    368   void RunGaps(Zone* zone, const Instruction* instr) {
    369     for (int i = Instruction::FIRST_GAP_POSITION;
    370          i <= Instruction::LAST_GAP_POSITION; i++) {
    371       auto inner_pos = static_cast<Instruction::GapPosition>(i);
    372       auto move = instr->GetParallelMove(inner_pos);
    373       if (move == nullptr) continue;
    374       RunParallelMoves(zone, move);
    375     }
    376   }
    377 
    378   void Drop(const InstructionOperand* op) {
    379     auto it = map().find(op);
    380     if (it != map().end()) map().erase(it);
    381   }
    382 
    383   void DropRegisters(const RegisterConfiguration* config) {
    384     // TODO(dcarney): sort map by kind and drop range.
    385     for (auto it = map().begin(); it != map().end();) {
    386       auto op = it->first;
    387       if (op->IsRegister() || op->IsDoubleRegister()) {
    388         map().erase(it++);
    389       } else {
    390         ++it;
    391       }
    392     }
    393   }
    394 
    395   MapValue* Define(Zone* zone, const InstructionOperand* op,
    396                    int virtual_register) {
    397     auto value = new (zone) MapValue();
    398     value->define_vreg = virtual_register;
    399     auto res = map().insert(std::make_pair(op, value));
    400     if (!res.second) res.first->second = value;
    401     return value;
    402   }
    403 
    404   void Use(const InstructionOperand* op, int use_vreg, bool initial_pass) {
    405     auto it = map().find(op);
    406     CHECK(it != map().end());
    407     auto v = it->second;
    408     if (v->define_vreg != kInvalidVreg) {
    409       CHECK_EQ(v->define_vreg, use_vreg);
    410     }
    411     // Already used this vreg in this block.
    412     if (v->use_vreg != kInvalidVreg) {
    413       CHECK_EQ(v->use_vreg, use_vreg);
    414       return;
    415     }
    416     if (!initial_pass) {
    417       // A value may be defined and used in this block or the use must have
    418       // propagated up.
    419       if (v->succ_vreg != kInvalidVreg) {
    420         CHECK_EQ(v->succ_vreg, use_vreg);
    421       } else {
    422         CHECK_EQ(v->define_vreg, use_vreg);
    423       }
    424       // Mark the use.
    425       it->second->use_vreg = use_vreg;
    426       return;
    427     }
    428     // Go up block list and ensure the correct definition is reached.
    429     for (; v != nullptr; v = v->incoming) {
    430       // Value unused in block.
    431       if (v->define_vreg == kInvalidVreg && v->use_vreg == kInvalidVreg) {
    432         continue;
    433       }
    434       // Found correct definition or use.
    435       CHECK(v->define_vreg == use_vreg || v->use_vreg == use_vreg);
    436       // Mark the use.
    437       it->second->use_vreg = use_vreg;
    438       return;
    439     }
    440     // Use of a non-phi value without definition.
    441     CHECK(false);
    442   }
    443 
    444   void UsePhi(const InstructionOperand* op, const PhiData* phi,
    445               bool initial_pass) {
    446     auto it = map().find(op);
    447     CHECK(it != map().end());
    448     auto v = it->second;
    449     int use_vreg = phi->virtual_register;
    450     // Phis are not defined.
    451     CHECK_EQ(kInvalidVreg, v->define_vreg);
    452     // Already used this vreg in this block.
    453     if (v->use_vreg != kInvalidVreg) {
    454       CHECK_EQ(v->use_vreg, use_vreg);
    455       return;
    456     }
    457     if (!initial_pass) {
    458       // A used phi must have propagated its use to a predecessor.
    459       CHECK_EQ(v->succ_vreg, use_vreg);
    460       // Mark the use.
    461       v->use_vreg = use_vreg;
    462       return;
    463     }
    464     // Go up the block list starting at the first predecessor and ensure this
    465     // phi has a correct use or definition.
    466     for (v = v->incoming; v != nullptr; v = v->incoming) {
    467       // Value unused in block.
    468       if (v->define_vreg == kInvalidVreg && v->use_vreg == kInvalidVreg) {
    469         continue;
    470       }
    471       // Found correct definition or use.
    472       if (v->define_vreg != kInvalidVreg) {
    473         CHECK(v->define_vreg == phi->first_pred_vreg);
    474       } else if (v->use_vreg != phi->first_pred_vreg) {
    475         // Walk the phi chain, hunting for a matching phi use.
    476         auto p = phi;
    477         for (; p != nullptr; p = p->first_pred_phi) {
    478           if (p->virtual_register == v->use_vreg) break;
    479         }
    480         CHECK(p);
    481       }
    482       // Mark the use.
    483       it->second->use_vreg = use_vreg;
    484       return;
    485     }
    486     // Use of a phi value without definition.
    487     UNREACHABLE();
    488   }
    489 
    490  private:
    491   Map map_;
    492   DISALLOW_COPY_AND_ASSIGN(OperandMap);
    493 };
    494 
    495 }  // namespace
    496 
    497 
    498 class RegisterAllocatorVerifier::BlockMaps {
    499  public:
    500   BlockMaps(Zone* zone, const InstructionSequence* sequence)
    501       : zone_(zone),
    502         sequence_(sequence),
    503         phi_map_guard_(sequence->VirtualRegisterCount(), zone),
    504         phi_map_(zone),
    505         incoming_maps_(zone),
    506         outgoing_maps_(zone) {
    507     InitializePhis();
    508     InitializeOperandMaps();
    509   }
    510 
    511   bool IsPhi(int virtual_register) {
    512     return phi_map_guard_.Contains(virtual_register);
    513   }
    514 
    515   const PhiData* GetPhi(int virtual_register) {
    516     auto it = phi_map_.find(virtual_register);
    517     CHECK(it != phi_map_.end());
    518     return it->second;
    519   }
    520 
    521   OperandMap* InitializeIncoming(size_t block_index, bool initial_pass) {
    522     return initial_pass ? InitializeFromFirstPredecessor(block_index)
    523                         : InitializeFromIntersection(block_index);
    524   }
    525 
    526   void PropagateUsesBackwards() {
    527     typedef std::set<size_t, std::greater<size_t>, zone_allocator<size_t>>
    528         BlockIds;
    529     BlockIds block_ids((BlockIds::key_compare()),
    530                        zone_allocator<size_t>(zone()));
    531     // First ensure that incoming contains only keys in all predecessors.
    532     for (auto block : sequence()->instruction_blocks()) {
    533       size_t index = block->rpo_number().ToSize();
    534       block_ids.insert(index);
    535       auto& succ_map = incoming_maps_[index]->map();
    536       for (size_t i = 0; i < block->PredecessorCount(); ++i) {
    537         auto pred_rpo = block->predecessors()[i];
    538         succ_map.Intersect(outgoing_maps_[pred_rpo.ToSize()]->map());
    539       }
    540     }
    541     // Back propagation fixpoint.
    542     while (!block_ids.empty()) {
    543       // Pop highest block_id.
    544       auto block_id_it = block_ids.begin();
    545       const size_t succ_index = *block_id_it;
    546       block_ids.erase(block_id_it);
    547       // Propagate uses back to their definition blocks using succ_vreg.
    548       auto block = sequence()->instruction_blocks()[succ_index];
    549       auto& succ_map = incoming_maps_[succ_index]->map();
    550       for (size_t i = 0; i < block->PredecessorCount(); ++i) {
    551         for (auto& succ_val : succ_map) {
    552           // An incoming map contains no defines.
    553           CHECK_EQ(kInvalidVreg, succ_val.second->define_vreg);
    554           // Compute succ_vreg.
    555           int succ_vreg = succ_val.second->succ_vreg;
    556           if (succ_vreg == kInvalidVreg) {
    557             succ_vreg = succ_val.second->use_vreg;
    558             // Initialize succ_vreg in back propagation chain.
    559             succ_val.second->succ_vreg = succ_vreg;
    560           }
    561           if (succ_vreg == kInvalidVreg) continue;
    562           // May need to transition phi.
    563           if (IsPhi(succ_vreg)) {
    564             auto phi = GetPhi(succ_vreg);
    565             if (phi->definition_rpo.ToSize() == succ_index) {
    566               // phi definition block, transition to pred value.
    567               succ_vreg = phi->operands[i];
    568             }
    569           }
    570           // Push succ_vreg up to all predecessors.
    571           auto pred_rpo = block->predecessors()[i];
    572           auto& pred_map = outgoing_maps_[pred_rpo.ToSize()]->map();
    573           auto& pred_val = *pred_map.find(succ_val.first);
    574           if (pred_val.second->use_vreg != kInvalidVreg) {
    575             CHECK_EQ(succ_vreg, pred_val.second->use_vreg);
    576           }
    577           if (pred_val.second->define_vreg != kInvalidVreg) {
    578             CHECK_EQ(succ_vreg, pred_val.second->define_vreg);
    579           }
    580           if (pred_val.second->succ_vreg != kInvalidVreg) {
    581             CHECK_EQ(succ_vreg, pred_val.second->succ_vreg);
    582           } else {
    583             pred_val.second->succ_vreg = succ_vreg;
    584             block_ids.insert(pred_rpo.ToSize());
    585           }
    586         }
    587       }
    588     }
    589     // Clear uses and back links for second pass.
    590     for (auto operand_map : incoming_maps_) {
    591       for (auto& succ_val : operand_map->map()) {
    592         succ_val.second->incoming = nullptr;
    593         succ_val.second->use_vreg = kInvalidVreg;
    594       }
    595     }
    596   }
    597 
    598  private:
    599   OperandMap* InitializeFromFirstPredecessor(size_t block_index) {
    600     auto to_init = outgoing_maps_[block_index];
    601     CHECK(to_init->map().empty());
    602     auto block = sequence()->instruction_blocks()[block_index];
    603     if (block->predecessors().empty()) return to_init;
    604     size_t predecessor_index = block->predecessors()[0].ToSize();
    605     // Ensure not a backedge.
    606     CHECK(predecessor_index < block->rpo_number().ToSize());
    607     auto incoming = outgoing_maps_[predecessor_index];
    608     // Copy map and replace values.
    609     to_init->map() = incoming->map();
    610     for (auto& it : to_init->map()) {
    611       auto incoming = it.second;
    612       it.second = new (zone()) OperandMap::MapValue();
    613       it.second->incoming = incoming;
    614     }
    615     // Copy to incoming map for second pass.
    616     incoming_maps_[block_index]->map() = to_init->map();
    617     return to_init;
    618   }
    619 
    620   OperandMap* InitializeFromIntersection(size_t block_index) {
    621     return incoming_maps_[block_index];
    622   }
    623 
    624   void InitializeOperandMaps() {
    625     size_t block_count = sequence()->instruction_blocks().size();
    626     incoming_maps_.reserve(block_count);
    627     outgoing_maps_.reserve(block_count);
    628     for (size_t i = 0; i < block_count; ++i) {
    629       incoming_maps_.push_back(new (zone()) OperandMap(zone()));
    630       outgoing_maps_.push_back(new (zone()) OperandMap(zone()));
    631     }
    632   }
    633 
    634   void InitializePhis() {
    635     const size_t block_count = sequence()->instruction_blocks().size();
    636     for (size_t block_index = 0; block_index < block_count; ++block_index) {
    637       const auto block = sequence()->instruction_blocks()[block_index];
    638       for (auto phi : block->phis()) {
    639         int first_pred_vreg = phi->operands()[0];
    640         const PhiData* first_pred_phi = nullptr;
    641         if (IsPhi(first_pred_vreg)) {
    642           first_pred_phi = GetPhi(first_pred_vreg);
    643           first_pred_vreg = first_pred_phi->first_pred_vreg;
    644         }
    645         CHECK(!IsPhi(first_pred_vreg));
    646         auto phi_data = new (zone()) PhiData(
    647             block->rpo_number(), phi, first_pred_vreg, first_pred_phi, zone());
    648         auto res =
    649             phi_map_.insert(std::make_pair(phi->virtual_register(), phi_data));
    650         CHECK(res.second);
    651         phi_map_guard_.Add(phi->virtual_register());
    652       }
    653     }
    654   }
    655 
    656   typedef ZoneVector<OperandMap*> OperandMaps;
    657   typedef ZoneVector<PhiData*> PhiVector;
    658 
    659   Zone* zone() const { return zone_; }
    660   const InstructionSequence* sequence() const { return sequence_; }
    661 
    662   Zone* const zone_;
    663   const InstructionSequence* const sequence_;
    664   BitVector phi_map_guard_;
    665   PhiMap phi_map_;
    666   OperandMaps incoming_maps_;
    667   OperandMaps outgoing_maps_;
    668 };
    669 
    670 
    671 void RegisterAllocatorVerifier::VerifyGapMoves() {
    672   BlockMaps block_maps(zone(), sequence());
    673   VerifyGapMoves(&block_maps, true);
    674   block_maps.PropagateUsesBackwards();
    675   VerifyGapMoves(&block_maps, false);
    676 }
    677 
    678 
    679 // Compute and verify outgoing values for every block.
    680 void RegisterAllocatorVerifier::VerifyGapMoves(BlockMaps* block_maps,
    681                                                bool initial_pass) {
    682   const size_t block_count = sequence()->instruction_blocks().size();
    683   for (size_t block_index = 0; block_index < block_count; ++block_index) {
    684     auto current = block_maps->InitializeIncoming(block_index, initial_pass);
    685     const auto block = sequence()->instruction_blocks()[block_index];
    686     for (int instr_index = block->code_start(); instr_index < block->code_end();
    687          ++instr_index) {
    688       const auto& instr_constraint = constraints_[instr_index];
    689       const auto instr = instr_constraint.instruction_;
    690       current->RunGaps(zone(), instr);
    691       const auto op_constraints = instr_constraint.operand_constraints_;
    692       size_t count = 0;
    693       for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
    694         if (op_constraints[count].type_ == kImmediate ||
    695             op_constraints[count].type_ == kExplicit) {
    696           continue;
    697         }
    698         int virtual_register = op_constraints[count].virtual_register_;
    699         auto op = instr->InputAt(i);
    700         if (!block_maps->IsPhi(virtual_register)) {
    701           current->Use(op, virtual_register, initial_pass);
    702         } else {
    703           auto phi = block_maps->GetPhi(virtual_register);
    704           current->UsePhi(op, phi, initial_pass);
    705         }
    706       }
    707       for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
    708         current->Drop(instr->TempAt(i));
    709       }
    710       if (instr->IsCall()) {
    711         current->DropRegisters(config());
    712       }
    713       for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
    714         int virtual_register = op_constraints[count].virtual_register_;
    715         OperandMap::MapValue* value =
    716             current->Define(zone(), instr->OutputAt(i), virtual_register);
    717         if (op_constraints[count].type_ == kRegisterAndSlot) {
    718           const AllocatedOperand* reg_op =
    719               AllocatedOperand::cast(instr->OutputAt(i));
    720           MachineRepresentation rep = reg_op->representation();
    721           const AllocatedOperand* stack_op = AllocatedOperand::New(
    722               zone(), LocationOperand::LocationKind::STACK_SLOT, rep,
    723               op_constraints[i].spilled_slot_);
    724           auto insert_result =
    725               current->map().insert(std::make_pair(stack_op, value));
    726           DCHECK(insert_result.second);
    727           USE(insert_result);
    728         }
    729       }
    730     }
    731   }
    732 }
    733 
    734 }  // namespace compiler
    735 }  // namespace internal
    736 }  // namespace v8
    737