[turbofan] make register allocator verifier independent of phi assignment
authordcarney <dcarney@chromium.org>
Mon, 26 Jan 2015 10:40:16 +0000 (02:40 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 26 Jan 2015 10:40:22 +0000 (10:40 +0000)
Review URL: https://codereview.chromium.org/875853002

Cr-Commit-Position: refs/heads/master@{#26265}

src/compiler/register-allocator-verifier.cc
src/compiler/register-allocator-verifier.h

index df97157..d4471ff 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/bit-vector.h"
 #include "src/compiler/instruction.h"
 #include "src/compiler/register-allocator-verifier.h"
 
@@ -214,90 +215,127 @@ void RegisterAllocatorVerifier::CheckConstraint(
   }
 }
 
+namespace {
 
-class RegisterAllocatorVerifier::OutgoingMapping : public ZoneObject {
+typedef BasicBlock::RpoNumber Rpo;
+
+static const int kInvalidVreg = UnallocatedOperand::kInvalidVirtualRegister;
+
+struct PhiData : public ZoneObject {
+  PhiData(Rpo definition_rpo, const PhiInstruction* phi, int first_pred_vreg,
+          const PhiData* first_pred_phi, Zone* zone)
+      : definition_rpo(definition_rpo),
+        virtual_register(phi->virtual_register()),
+        first_pred_vreg(first_pred_vreg),
+        first_pred_phi(first_pred_phi),
+        operands(zone) {
+    operands.reserve(phi->operands().size());
+    operands.insert(operands.begin(), phi->operands().begin(),
+                    phi->operands().end());
+  }
+  const Rpo definition_rpo;
+  const int virtual_register;
+  const int first_pred_vreg;
+  const PhiData* first_pred_phi;
+  IntVector operands;
+};
+
+typedef std::map<int, PhiData*, std::less<int>,
+                 zone_allocator<std::pair<int, PhiData*>>> PhiMapBase;
+
+class PhiMap : public PhiMapBase, public ZoneObject {
  public:
-  struct OperandLess {
-    bool operator()(const InstructionOperand* a,
-                    const InstructionOperand* b) const {
-      if (a->kind() == b->kind()) return a->index() < b->index();
-      return a->kind() < b->kind();
-    }
+  explicit PhiMap(Zone* zone)
+      : PhiMapBase(key_compare(), allocator_type(zone)) {}
+};
+
+struct OperandLess {
+  bool operator()(const InstructionOperand* a,
+                  const InstructionOperand* b) const {
+    if (a->kind() == b->kind()) return a->index() < b->index();
+    return a->kind() < b->kind();
+  }
+};
+
+class OperandMap : public ZoneObject {
+ public:
+  struct MapValue : public ZoneObject {
+    MapValue()
+        : incoming(nullptr),
+          define_vreg(kInvalidVreg),
+          use_vreg(kInvalidVreg),
+          succ_vreg(kInvalidVreg) {}
+    MapValue* incoming;  // value from first predecessor block.
+    int define_vreg;     // valid if this value was defined in this block.
+    int use_vreg;        // valid if this value was used in this block.
+    int succ_vreg;       // valid if propagated back from successor block.
   };
 
   typedef std::map<
-      const InstructionOperand*, int, OperandLess,
-      zone_allocator<std::pair<const InstructionOperand*, const int>>>
-      LocationMap;
-
-  explicit OutgoingMapping(Zone* zone)
-      : locations_(LocationMap::key_compare(),
-                   LocationMap::allocator_type(zone)),
-        predecessor_intersection_(LocationMap::key_compare(),
-                                  LocationMap::allocator_type(zone)) {}
-
-  LocationMap* locations() { return &locations_; }
-
-  void RunPhis(const InstructionSequence* sequence,
-               const InstructionBlock* block, size_t phi_index) {
-    // This operation is only valid in edge split form.
-    size_t predecessor_index = block->predecessors()[phi_index].ToSize();
-    for (const auto* phi : block->phis()) {
-      CHECK(
-          sequence->instruction_blocks()[predecessor_index]->SuccessorCount() ==
-          1);
-      auto input = phi->inputs()[phi_index];
-      CHECK(locations()->find(input) != locations()->end());
-      auto it = locations()->find(phi->output());
-      CHECK(it != locations()->end());
-      if (input->IsConstant()) {
-        CHECK_EQ(it->second, input->index());
-      } else {
-        CHECK_EQ(it->second, phi->operands()[phi_index]);
+      const InstructionOperand*, MapValue*, OperandLess,
+      zone_allocator<std::pair<const InstructionOperand*, MapValue*>>> MapBase;
+
+  class Map : public MapBase {
+   public:
+    explicit Map(Zone* zone) : MapBase(key_compare(), allocator_type(zone)) {}
+
+    // Remove all entries with keys not in other.
+    void Intersect(const Map& other) {
+      if (this->empty()) return;
+      auto it = this->begin();
+      OperandLess less;
+      for (const auto& o : other) {
+        while (less(it->first, o.first)) {
+          this->erase(it++);
+          if (it == this->end()) return;
+        }
+        if (it->first->Equals(o.first)) {
+          ++it;
+          if (it == this->end()) return;
+        } else {
+          CHECK(less(o.first, it->first));
+        }
       }
-      it->second = phi->virtual_register();
     }
-  }
+  };
 
-  void RunGapInstruction(Zone* zone, const GapInstruction* gap) {
-    for (int i = GapInstruction::FIRST_INNER_POSITION;
-         i <= GapInstruction::LAST_INNER_POSITION; i++) {
-      GapInstruction::InnerPosition inner_pos =
-          static_cast<GapInstruction::InnerPosition>(i);
-      const ParallelMove* move = gap->GetParallelMove(inner_pos);
-      if (move == nullptr) continue;
-      RunParallelMoves(zone, move);
-    }
-  }
+  explicit OperandMap(Zone* zone) : map_(zone) {}
+
+  Map& map() { return map_; }
 
   void RunParallelMoves(Zone* zone, const ParallelMove* move) {
     // Compute outgoing mappings.
-    LocationMap to_insert((LocationMap::key_compare()),
-                          LocationMap::allocator_type(zone));
-    auto* moves = move->move_operands();
+    Map to_insert(zone);
+    auto moves = move->move_operands();
     for (auto i = moves->begin(); i != moves->end(); ++i) {
       if (i->IsEliminated()) continue;
-      auto cur = locations()->find(i->source());
-      CHECK(cur != locations()->end());
+      auto cur = map().find(i->source());
+      CHECK(cur != map().end());
       to_insert.insert(std::make_pair(i->destination(), cur->second));
     }
     // Drop current mappings.
     for (auto i = moves->begin(); i != moves->end(); ++i) {
       if (i->IsEliminated()) continue;
-      auto cur = locations()->find(i->destination());
-      if (cur != locations()->end()) locations()->erase(cur);
+      auto cur = map().find(i->destination());
+      if (cur != map().end()) map().erase(cur);
     }
     // Insert new values.
-    locations()->insert(to_insert.begin(), to_insert.end());
+    map().insert(to_insert.begin(), to_insert.end());
   }
 
-  void Map(const InstructionOperand* op, int virtual_register) {
-    locations()->insert(std::make_pair(op, virtual_register));
+  void RunGapInstruction(Zone* zone, const GapInstruction* gap) {
+    for (int i = GapInstruction::FIRST_INNER_POSITION;
+         i <= GapInstruction::LAST_INNER_POSITION; i++) {
+      auto inner_pos = static_cast<GapInstruction::InnerPosition>(i);
+      auto move = gap->GetParallelMove(inner_pos);
+      if (move == nullptr) continue;
+      RunParallelMoves(zone, move);
+    }
   }
 
   void Drop(const InstructionOperand* op) {
-    auto it = locations()->find(op);
-    if (it != locations()->end()) locations()->erase(it);
+    auto it = map().find(op);
+    if (it != map().end()) map().erase(it);
   }
 
   void DropRegisters(const RegisterConfiguration* config) {
@@ -311,131 +349,316 @@ class RegisterAllocatorVerifier::OutgoingMapping : public ZoneObject {
     }
   }
 
-  void InitializeFromFirstPredecessor(const InstructionSequence* sequence,
-                                      const OutgoingMappings* outgoing_mappings,
-                                      const InstructionBlock* block) {
-    if (block->predecessors().empty()) return;
-    size_t predecessor_index = block->predecessors()[0].ToSize();
-    CHECK(predecessor_index < block->rpo_number().ToSize());
-    auto* incoming = outgoing_mappings->at(predecessor_index);
-    if (block->PredecessorCount() >= 1) {
-      // Update incoming map with phis. The remaining phis will be checked later
-      // as their mappings are not guaranteed to exist yet.
-      incoming->RunPhis(sequence, block, 0);
+  void Define(Zone* zone, const InstructionOperand* op, int virtual_register) {
+    auto value = new (zone) MapValue();
+    value->define_vreg = virtual_register;
+    auto res = map().insert(std::make_pair(op, value));
+    if (!res.second) res.first->second = value;
+  }
+
+  void Use(const InstructionOperand* op, int use_vreg, bool initial_pass) {
+    auto it = map().find(op);
+    CHECK(it != map().end());
+    auto v = it->second;
+    if (v->define_vreg != kInvalidVreg) {
+      CHECK_EQ(v->define_vreg, use_vreg);
     }
-    // Now initialize outgoing mapping for this block with incoming mapping.
-    CHECK(locations_.empty());
-    locations_ = incoming->locations_;
+    // Already used this vreg in this block.
+    if (v->use_vreg != kInvalidVreg) {
+      CHECK_EQ(v->use_vreg, use_vreg);
+      return;
+    }
+    if (!initial_pass) {
+      // A value may be defined and used in this block or the use must have
+      // propagated up.
+      if (v->succ_vreg != kInvalidVreg) {
+        CHECK_EQ(v->succ_vreg, use_vreg);
+      } else {
+        CHECK_EQ(v->define_vreg, use_vreg);
+      }
+      // Mark the use.
+      it->second->use_vreg = use_vreg;
+      return;
+    }
+    // Go up block list and ensure the correct definition is reached.
+    for (; v != nullptr; v = v->incoming) {
+      // Value unused in block.
+      if (v->define_vreg == kInvalidVreg && v->use_vreg == kInvalidVreg) {
+        continue;
+      }
+      // Found correct definition or use.
+      CHECK(v->define_vreg == use_vreg || v->use_vreg == use_vreg);
+      // Mark the use.
+      it->second->use_vreg = use_vreg;
+      return;
+    }
+    // Use of a non-phi value without definition.
+    CHECK(false);
   }
 
-  void InitializeFromIntersection() { locations_ = predecessor_intersection_; }
+  void UsePhi(const InstructionOperand* op, const PhiData* phi,
+              bool initial_pass) {
+    auto it = map().find(op);
+    CHECK(it != map().end());
+    auto v = it->second;
+    int use_vreg = phi->virtual_register;
+    // Phis are not defined.
+    CHECK_EQ(kInvalidVreg, v->define_vreg);
+    // Already used this vreg in this block.
+    if (v->use_vreg != kInvalidVreg) {
+      CHECK_EQ(v->use_vreg, use_vreg);
+      return;
+    }
+    if (!initial_pass) {
+      // A used phi must have propagated its use to a predecessor.
+      CHECK_EQ(v->succ_vreg, use_vreg);
+      // Mark the use.
+      v->use_vreg = use_vreg;
+      return;
+    }
+    // Go up the block list starting at the first predecessor and ensure this
+    // phi has a correct use or definition.
+    for (v = v->incoming; v != nullptr; v = v->incoming) {
+      // Value unused in block.
+      if (v->define_vreg == kInvalidVreg && v->use_vreg == kInvalidVreg) {
+        continue;
+      }
+      // Found correct definition or use.
+      if (v->define_vreg != kInvalidVreg) {
+        CHECK(v->define_vreg == phi->first_pred_vreg);
+      } else if (v->use_vreg != phi->first_pred_vreg) {
+        // Walk the phi chain, hunting for a matching phi use.
+        auto p = phi;
+        for (; p != nullptr; p = p->first_pred_phi) {
+          if (p->virtual_register == v->use_vreg) break;
+        }
+        CHECK_NE(nullptr, p);
+      }
+      // Mark the use.
+      it->second->use_vreg = use_vreg;
+      return;
+    }
+    // Use of a phi value without definition.
+    CHECK(false);
+  }
+
+ private:
+  Map map_;
+  DISALLOW_COPY_AND_ASSIGN(OperandMap);
+};
+
+}  // namespace
+
+
+class RegisterAllocatorVerifier::BlockMaps {
+ public:
+  BlockMaps(Zone* zone, const InstructionSequence* sequence)
+      : zone_(zone),
+        sequence_(sequence),
+        phi_map_guard_(sequence->VirtualRegisterCount(), zone),
+        phi_map_(zone),
+        incoming_maps_(zone),
+        outgoing_maps_(zone) {
+    InitializePhis();
+    InitializeOperandMaps();
+  }
+
+  bool IsPhi(int virtual_register) {
+    return phi_map_guard_.Contains(virtual_register);
+  }
 
-  void InitializeIntersection(const OutgoingMapping* incoming) {
-    CHECK(predecessor_intersection_.empty());
-    predecessor_intersection_ = incoming->locations_;
+  const PhiData* GetPhi(int virtual_register) {
+    auto it = phi_map_.find(virtual_register);
+    CHECK(it != phi_map_.end());
+    return it->second;
   }
 
-  void Intersect(const OutgoingMapping* other) {
-    if (predecessor_intersection_.empty()) return;
-    auto it = predecessor_intersection_.begin();
-    OperandLess less;
-    for (const auto& o : other->locations_) {
-      while (less(it->first, o.first)) {
-        ++it;
-        if (it == predecessor_intersection_.end()) return;
+  OperandMap* InitializeIncoming(size_t block_index, bool initial_pass) {
+    return initial_pass ? InitializeFromFirstPredecessor(block_index)
+                        : InitializeFromIntersection(block_index);
+  }
+
+  void PropagateUsesBackwards() {
+    typedef std::set<size_t, std::greater<size_t>, zone_allocator<size_t>>
+        BlockIds;
+    BlockIds block_ids((BlockIds::key_compare()),
+                       zone_allocator<size_t>(zone()));
+    // First ensure that incoming contains only keys in all predecessors.
+    for (auto block : sequence()->instruction_blocks()) {
+      size_t index = block->rpo_number().ToSize();
+      block_ids.insert(index);
+      auto& succ_map = incoming_maps_[index]->map();
+      for (size_t i = 0; i < block->PredecessorCount(); ++i) {
+        auto pred_rpo = block->predecessors()[i];
+        succ_map.Intersect(outgoing_maps_[pred_rpo.ToSize()]->map());
       }
-      if (it->first->Equals(o.first)) {
-        if (o.second != it->second) {
-          predecessor_intersection_.erase(it++);
-        } else {
-          ++it;
+    }
+    // Back propagation fixpoint.
+    while (!block_ids.empty()) {
+      // Pop highest block_id.
+      auto block_id_it = block_ids.begin();
+      const size_t succ_index = *block_id_it;
+      block_ids.erase(block_id_it);
+      // Propagate uses back to their definition blocks using succ_vreg.
+      auto block = sequence()->instruction_blocks()[succ_index];
+      auto& succ_map = incoming_maps_[succ_index]->map();
+      for (size_t i = 0; i < block->PredecessorCount(); ++i) {
+        for (auto& succ_val : succ_map) {
+          // An incoming map contains no defines.
+          CHECK_EQ(kInvalidVreg, succ_val.second->define_vreg);
+          // Compute succ_vreg.
+          int succ_vreg = succ_val.second->succ_vreg;
+          if (succ_vreg == kInvalidVreg) {
+            succ_vreg = succ_val.second->use_vreg;
+            // Initialize succ_vreg in back propagation chain.
+            succ_val.second->succ_vreg = succ_vreg;
+          }
+          if (succ_vreg == kInvalidVreg) continue;
+          // May need to transition phi.
+          if (IsPhi(succ_vreg)) {
+            auto phi = GetPhi(succ_vreg);
+            if (phi->definition_rpo.ToSize() == succ_index) {
+              // phi definition block, transition to pred value.
+              succ_vreg = phi->operands[i];
+            }
+          }
+          // Push succ_vreg up to all predecessors.
+          auto pred_rpo = block->predecessors()[i];
+          auto& pred_map = outgoing_maps_[pred_rpo.ToSize()]->map();
+          auto& pred_val = *pred_map.find(succ_val.first);
+          if (pred_val.second->use_vreg != kInvalidVreg) {
+            CHECK_EQ(succ_vreg, pred_val.second->use_vreg);
+          }
+          if (pred_val.second->define_vreg != kInvalidVreg) {
+            CHECK_EQ(succ_vreg, pred_val.second->define_vreg);
+          }
+          if (pred_val.second->succ_vreg != kInvalidVreg) {
+            CHECK_EQ(succ_vreg, pred_val.second->succ_vreg);
+          } else {
+            pred_val.second->succ_vreg = succ_vreg;
+            block_ids.insert(pred_rpo.ToSize());
+          }
         }
-        if (it == predecessor_intersection_.end()) return;
+      }
+    }
+    // Clear uses and back links for second pass.
+    for (auto operand_map : incoming_maps_) {
+      for (auto& succ_val : operand_map->map()) {
+        succ_val.second->incoming = nullptr;
+        succ_val.second->use_vreg = kInvalidVreg;
       }
     }
   }
 
  private:
-  LocationMap locations_;
-  LocationMap predecessor_intersection_;
+  OperandMap* InitializeFromFirstPredecessor(size_t block_index) {
+    auto to_init = outgoing_maps_[block_index];
+    CHECK(to_init->map().empty());
+    auto block = sequence()->instruction_blocks()[block_index];
+    if (block->predecessors().empty()) return to_init;
+    size_t predecessor_index = block->predecessors()[0].ToSize();
+    // Ensure not a backedge.
+    CHECK(predecessor_index < block->rpo_number().ToSize());
+    auto incoming = outgoing_maps_[predecessor_index];
+    // Copy map and replace values.
+    to_init->map() = incoming->map();
+    for (auto& it : to_init->map()) {
+      auto incoming = it.second;
+      it.second = new (zone()) OperandMap::MapValue();
+      it.second->incoming = incoming;
+    }
+    // Copy to incoming map for second pass.
+    incoming_maps_[block_index]->map() = to_init->map();
+    return to_init;
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(OutgoingMapping);
-};
+  OperandMap* InitializeFromIntersection(size_t block_index) {
+    return incoming_maps_[block_index];
+  }
 
+  void InitializeOperandMaps() {
+    size_t block_count = sequence()->instruction_blocks().size();
+    incoming_maps_.reserve(block_count);
+    outgoing_maps_.reserve(block_count);
+    for (size_t i = 0; i < block_count; ++i) {
+      incoming_maps_.push_back(new (zone()) OperandMap(zone()));
+      outgoing_maps_.push_back(new (zone()) OperandMap(zone()));
+    }
+  }
 
-// Verify that all gap moves move the operands for a virtual register into the
-// correct location for every instruction.
-void RegisterAllocatorVerifier::VerifyGapMoves() {
-  typedef ZoneVector<OutgoingMapping*> OutgoingMappings;
-  OutgoingMappings outgoing_mappings(
-      static_cast<int>(sequence()->instruction_blocks().size()), nullptr,
-      zone());
-  // Construct all mappings, ignoring back edges and multiple entries.
-  ConstructOutgoingMappings(&outgoing_mappings, true);
-  // Run all remaining phis and compute the intersection of all predecessor
-  // mappings.
-  for (const auto* block : sequence()->instruction_blocks()) {
-    if (block->PredecessorCount() == 0) continue;
-    const size_t block_index = block->rpo_number().ToSize();
-    auto* mapping = outgoing_mappings[block_index];
-    bool initialized = false;
-    // Walk predecessors in reverse to ensure Intersect is correctly working.
-    // If it did nothing, the second pass would do exactly what the first pass
-    // did.
-    for (size_t phi_input = block->PredecessorCount() - 1; true; --phi_input) {
-      const size_t pred_block_index = block->predecessors()[phi_input].ToSize();
-      auto* incoming = outgoing_mappings[pred_block_index];
-      if (phi_input != 0) incoming->RunPhis(sequence(), block, phi_input);
-      if (!initialized) {
-        mapping->InitializeIntersection(incoming);
-        initialized = true;
-      } else {
-        mapping->Intersect(incoming);
+  void InitializePhis() {
+    const size_t block_count = sequence()->instruction_blocks().size();
+    for (size_t block_index = 0; block_index < block_count; ++block_index) {
+      const auto block = sequence()->instruction_blocks()[block_index];
+      for (auto phi : block->phis()) {
+        int first_pred_vreg = phi->operands()[0];
+        const PhiData* first_pred_phi = nullptr;
+        if (IsPhi(first_pred_vreg)) {
+          first_pred_phi = GetPhi(first_pred_vreg);
+          first_pred_vreg = first_pred_phi->first_pred_vreg;
+        }
+        CHECK(!IsPhi(first_pred_vreg));
+        auto phi_data = new (zone()) PhiData(
+            block->rpo_number(), phi, first_pred_vreg, first_pred_phi, zone());
+        auto res =
+            phi_map_.insert(std::make_pair(phi->virtual_register(), phi_data));
+        CHECK(res.second);
+        phi_map_guard_.Add(phi->virtual_register());
       }
-      if (phi_input == 0) break;
     }
   }
-  // Construct all mappings again, this time using the instersection mapping
-  // above as the incoming mapping instead of the result from the first
-  // predecessor.
-  ConstructOutgoingMappings(&outgoing_mappings, false);
+
+  typedef ZoneVector<OperandMap*> OperandMaps;
+  typedef ZoneVector<PhiData*> PhiVector;
+
+  Zone* zone() const { return zone_; }
+  const InstructionSequence* sequence() const { return sequence_; }
+
+  Zone* const zone_;
+  const InstructionSequence* const sequence_;
+  BitVector phi_map_guard_;
+  PhiMap phi_map_;
+  OperandMaps incoming_maps_;
+  OperandMaps outgoing_maps_;
+};
+
+
+void RegisterAllocatorVerifier::VerifyGapMoves() {
+  BlockMaps block_maps(zone(), sequence());
+  VerifyGapMoves(&block_maps, true);
+  block_maps.PropagateUsesBackwards();
+  VerifyGapMoves(&block_maps, false);
 }
 
 
-void RegisterAllocatorVerifier::ConstructOutgoingMappings(
-    OutgoingMappings* outgoing_mappings, bool initial_pass) {
-  // Compute the locations of all virtual registers leaving every block, using
-  // only the first predecessor as source for the input mapping.
-  for (const auto* block : sequence()->instruction_blocks()) {
-    const size_t block_index = block->rpo_number().ToSize();
-    auto* current = outgoing_mappings->at(block_index);
-    CHECK(initial_pass == (current == nullptr));
-    // Initialize current.
-    if (!initial_pass) {
-      // Skip check second time around for blocks without multiple predecessors
-      // as we have already executed this in the initial run.
-      if (block->PredecessorCount() <= 1) continue;
-      current->InitializeFromIntersection();
-    } else {
-      current = new (zone()) OutgoingMapping(zone());
-      outgoing_mappings->at(block_index) = current;
-      // Copy outgoing values from predecessor block.
-      current->InitializeFromFirstPredecessor(sequence(), outgoing_mappings,
-                                              block);
-    }
-    // Update current with gaps and operands for all instructions in block.
+// Compute and verify outgoing values for every block.
+void RegisterAllocatorVerifier::VerifyGapMoves(BlockMaps* block_maps,
+                                               bool initial_pass) {
+  const size_t block_count = sequence()->instruction_blocks().size();
+  for (size_t block_index = 0; block_index < block_count; ++block_index) {
+    auto current = block_maps->InitializeIncoming(block_index, initial_pass);
+    const auto block = sequence()->instruction_blocks()[block_index];
     for (int instr_index = block->code_start(); instr_index < block->code_end();
          ++instr_index) {
       const auto& instr_constraint = constraints_[instr_index];
-      const auto* instr = instr_constraint.instruction_;
-      const auto* op_constraints = instr_constraint.operand_constraints_;
+      const auto instr = instr_constraint.instruction_;
+      if (instr->IsSourcePosition()) continue;
+      if (instr->IsGapMoves()) {
+        current->RunGapInstruction(zone(), GapInstruction::cast(instr));
+        continue;
+      }
+      const auto op_constraints = instr_constraint.operand_constraints_;
       size_t count = 0;
       for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
         if (op_constraints[count].type_ == kImmediate) continue;
-        auto it = current->locations()->find(instr->InputAt(i));
         int virtual_register = op_constraints[count].virtual_register_;
-        CHECK(it != current->locations()->end());
-        CHECK_EQ(it->second, virtual_register);
+        auto op = instr->InputAt(i);
+        if (!block_maps->IsPhi(virtual_register)) {
+          current->Use(op, virtual_register, initial_pass);
+        } else {
+          auto phi = block_maps->GetPhi(virtual_register);
+          current->UsePhi(op, phi, initial_pass);
+        }
       }
       for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
         current->Drop(instr->TempAt(i));
@@ -444,13 +667,8 @@ void RegisterAllocatorVerifier::ConstructOutgoingMappings(
         current->DropRegisters(config());
       }
       for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
-        current->Drop(instr->OutputAt(i));
         int virtual_register = op_constraints[count].virtual_register_;
-        current->Map(instr->OutputAt(i), virtual_register);
-      }
-      if (instr->IsGapMoves()) {
-        const auto* gap = GapInstruction::cast(instr);
-        current->RunGapInstruction(zone(), gap);
+        current->Define(zone(), instr->OutputAt(i), virtual_register);
       }
     }
   }
index 4e35dc2..70552fb 100644 (file)
@@ -49,10 +49,9 @@ class RegisterAllocatorVerifier FINAL : public ZoneObject {
     OperandConstraint* operand_constraints_;
   };
 
-  class OutgoingMapping;
+  class BlockMaps;
 
   typedef ZoneVector<InstructionConstraint> Constraints;
-  typedef ZoneVector<OutgoingMapping*> OutgoingMappings;
 
   Zone* zone() const { return zone_; }
   const RegisterConfiguration* config() { return config_; }
@@ -68,8 +67,7 @@ class RegisterAllocatorVerifier FINAL : public ZoneObject {
   void CheckConstraint(const InstructionOperand* op,
                        const OperandConstraint* constraint);
 
-  void ConstructOutgoingMappings(OutgoingMappings* outgoing_mappings,
-                                 bool initial_pass);
+  void VerifyGapMoves(BlockMaps* outgoing_mappings, bool initial_pass);
 
   Zone* const zone_;
   const RegisterConfiguration* config_;