Index: src/compiler/register-allocator-verifier.cc |
diff --git a/src/compiler/register-allocator-verifier.cc b/src/compiler/register-allocator-verifier.cc |
index df97157d329d4a9586834a26bc1ba6f93a29db3f..d4471ff899c10b7c68e0e60af2f06f20957d3f68 100644 |
--- a/src/compiler/register-allocator-verifier.cc |
+++ b/src/compiler/register-allocator-verifier.cc |
@@ -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); |
} |
} |
} |