OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/bit-vector.h" | 5 #include "src/bit-vector.h" |
6 #include "src/compiler/instruction.h" | 6 #include "src/compiler/instruction.h" |
7 #include "src/compiler/register-allocator-verifier.h" | 7 #include "src/compiler/register-allocator-verifier.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 14 matching lines...) Expand all Loading... |
25 CHECK(instr->GetParallelMove(inner_pos) == nullptr); | 25 CHECK(instr->GetParallelMove(inner_pos) == nullptr); |
26 } | 26 } |
27 } | 27 } |
28 | 28 |
29 | 29 |
30 void VerifyAllocatedGaps(const Instruction* instr) { | 30 void VerifyAllocatedGaps(const Instruction* instr) { |
31 for (int i = Instruction::FIRST_GAP_POSITION; | 31 for (int i = Instruction::FIRST_GAP_POSITION; |
32 i <= Instruction::LAST_GAP_POSITION; i++) { | 32 i <= Instruction::LAST_GAP_POSITION; i++) { |
33 Instruction::GapPosition inner_pos = | 33 Instruction::GapPosition inner_pos = |
34 static_cast<Instruction::GapPosition>(i); | 34 static_cast<Instruction::GapPosition>(i); |
35 auto moves = instr->GetParallelMove(inner_pos); | 35 const ParallelMove* moves = instr->GetParallelMove(inner_pos); |
36 if (moves == nullptr) continue; | 36 if (moves == nullptr) continue; |
37 for (auto move : *moves) { | 37 for (const MoveOperands* move : *moves) { |
38 if (move->IsRedundant()) continue; | 38 if (move->IsRedundant()) continue; |
39 CHECK(move->source().IsAllocated() || move->source().IsConstant()); | 39 CHECK(move->source().IsAllocated() || move->source().IsConstant()); |
40 CHECK(move->destination().IsAllocated()); | 40 CHECK(move->destination().IsAllocated()); |
41 } | 41 } |
42 } | 42 } |
43 } | 43 } |
44 | 44 |
45 } // namespace | 45 } // namespace |
46 | 46 |
47 | 47 |
(...skipping 26 matching lines...) Expand all Loading... |
74 | 74 |
75 | 75 |
76 RegisterAllocatorVerifier::RegisterAllocatorVerifier( | 76 RegisterAllocatorVerifier::RegisterAllocatorVerifier( |
77 Zone* zone, const RegisterConfiguration* config, | 77 Zone* zone, const RegisterConfiguration* config, |
78 const InstructionSequence* sequence) | 78 const InstructionSequence* sequence) |
79 : zone_(zone), config_(config), sequence_(sequence), constraints_(zone) { | 79 : zone_(zone), config_(config), sequence_(sequence), constraints_(zone) { |
80 constraints_.reserve(sequence->instructions().size()); | 80 constraints_.reserve(sequence->instructions().size()); |
81 // TODO(dcarney): model unique constraints. | 81 // TODO(dcarney): model unique constraints. |
82 // Construct OperandConstraints for all InstructionOperands, eliminating | 82 // Construct OperandConstraints for all InstructionOperands, eliminating |
83 // kSameAsFirst along the way. | 83 // kSameAsFirst along the way. |
84 for (const auto* instr : sequence->instructions()) { | 84 for (const Instruction* instr : sequence->instructions()) { |
85 // All gaps should be totally unallocated at this point. | 85 // All gaps should be totally unallocated at this point. |
86 VerifyEmptyGaps(instr); | 86 VerifyEmptyGaps(instr); |
87 const size_t operand_count = OperandCount(instr); | 87 const size_t operand_count = OperandCount(instr); |
88 auto* op_constraints = zone->NewArray<OperandConstraint>(operand_count); | 88 OperandConstraint* op_constraints = |
| 89 zone->NewArray<OperandConstraint>(operand_count); |
89 size_t count = 0; | 90 size_t count = 0; |
90 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) { | 91 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) { |
91 BuildConstraint(instr->InputAt(i), &op_constraints[count]); | 92 BuildConstraint(instr->InputAt(i), &op_constraints[count]); |
92 VerifyInput(op_constraints[count]); | 93 VerifyInput(op_constraints[count]); |
93 } | 94 } |
94 for (size_t i = 0; i < instr->TempCount(); ++i, ++count) { | 95 for (size_t i = 0; i < instr->TempCount(); ++i, ++count) { |
95 BuildConstraint(instr->TempAt(i), &op_constraints[count]); | 96 BuildConstraint(instr->TempAt(i), &op_constraints[count]); |
96 VerifyTemp(op_constraints[count]); | 97 VerifyTemp(op_constraints[count]); |
97 } | 98 } |
98 for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) { | 99 for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) { |
99 BuildConstraint(instr->OutputAt(i), &op_constraints[count]); | 100 BuildConstraint(instr->OutputAt(i), &op_constraints[count]); |
100 if (op_constraints[count].type_ == kSameAsFirst) { | 101 if (op_constraints[count].type_ == kSameAsFirst) { |
101 CHECK(instr->InputCount() > 0); | 102 CHECK(instr->InputCount() > 0); |
102 op_constraints[count].type_ = op_constraints[0].type_; | 103 op_constraints[count].type_ = op_constraints[0].type_; |
103 op_constraints[count].value_ = op_constraints[0].value_; | 104 op_constraints[count].value_ = op_constraints[0].value_; |
104 } | 105 } |
105 VerifyOutput(op_constraints[count]); | 106 VerifyOutput(op_constraints[count]); |
106 } | 107 } |
107 InstructionConstraint instr_constraint = {instr, operand_count, | 108 InstructionConstraint instr_constraint = {instr, operand_count, |
108 op_constraints}; | 109 op_constraints}; |
109 constraints()->push_back(instr_constraint); | 110 constraints()->push_back(instr_constraint); |
110 } | 111 } |
111 } | 112 } |
112 | 113 |
113 | 114 |
114 void RegisterAllocatorVerifier::VerifyAssignment() { | 115 void RegisterAllocatorVerifier::VerifyAssignment() { |
115 CHECK(sequence()->instructions().size() == constraints()->size()); | 116 CHECK(sequence()->instructions().size() == constraints()->size()); |
116 auto instr_it = sequence()->begin(); | 117 auto instr_it = sequence()->begin(); |
117 for (const auto& instr_constraint : *constraints()) { | 118 for (const auto& instr_constraint : *constraints()) { |
118 const auto* instr = instr_constraint.instruction_; | 119 const Instruction* instr = instr_constraint.instruction_; |
119 // All gaps should be totally allocated at this point. | 120 // All gaps should be totally allocated at this point. |
120 VerifyAllocatedGaps(instr); | 121 VerifyAllocatedGaps(instr); |
121 const size_t operand_count = instr_constraint.operand_constaints_size_; | 122 const size_t operand_count = instr_constraint.operand_constaints_size_; |
122 const auto* op_constraints = instr_constraint.operand_constraints_; | 123 const OperandConstraint* op_constraints = |
| 124 instr_constraint.operand_constraints_; |
123 CHECK_EQ(instr, *instr_it); | 125 CHECK_EQ(instr, *instr_it); |
124 CHECK(operand_count == OperandCount(instr)); | 126 CHECK(operand_count == OperandCount(instr)); |
125 size_t count = 0; | 127 size_t count = 0; |
126 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) { | 128 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) { |
127 CheckConstraint(instr->InputAt(i), &op_constraints[count]); | 129 CheckConstraint(instr->InputAt(i), &op_constraints[count]); |
128 } | 130 } |
129 for (size_t i = 0; i < instr->TempCount(); ++i, ++count) { | 131 for (size_t i = 0; i < instr->TempCount(); ++i, ++count) { |
130 CheckConstraint(instr->TempAt(i), &op_constraints[count]); | 132 CheckConstraint(instr->TempAt(i), &op_constraints[count]); |
131 } | 133 } |
132 for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) { | 134 for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) { |
133 CheckConstraint(instr->OutputAt(i), &op_constraints[count]); | 135 CheckConstraint(instr->OutputAt(i), &op_constraints[count]); |
134 } | 136 } |
135 ++instr_it; | 137 ++instr_it; |
136 } | 138 } |
137 } | 139 } |
138 | 140 |
139 | 141 |
140 void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op, | 142 void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op, |
141 OperandConstraint* constraint) { | 143 OperandConstraint* constraint) { |
142 constraint->value_ = kMinInt; | 144 constraint->value_ = kMinInt; |
143 constraint->virtual_register_ = InstructionOperand::kInvalidVirtualRegister; | 145 constraint->virtual_register_ = InstructionOperand::kInvalidVirtualRegister; |
144 if (op->IsConstant()) { | 146 if (op->IsConstant()) { |
145 constraint->type_ = kConstant; | 147 constraint->type_ = kConstant; |
146 constraint->value_ = ConstantOperand::cast(op)->virtual_register(); | 148 constraint->value_ = ConstantOperand::cast(op)->virtual_register(); |
147 constraint->virtual_register_ = constraint->value_; | 149 constraint->virtual_register_ = constraint->value_; |
148 } else if (op->IsExplicit()) { | 150 } else if (op->IsExplicit()) { |
149 constraint->type_ = kExplicit; | 151 constraint->type_ = kExplicit; |
150 } else if (op->IsImmediate()) { | 152 } else if (op->IsImmediate()) { |
151 auto imm = ImmediateOperand::cast(op); | 153 const ImmediateOperand* imm = ImmediateOperand::cast(op); |
152 int value = imm->type() == ImmediateOperand::INLINE ? imm->inline_value() | 154 int value = imm->type() == ImmediateOperand::INLINE ? imm->inline_value() |
153 : imm->indexed_value(); | 155 : imm->indexed_value(); |
154 constraint->type_ = kImmediate; | 156 constraint->type_ = kImmediate; |
155 constraint->value_ = value; | 157 constraint->value_ = value; |
156 } else { | 158 } else { |
157 CHECK(op->IsUnallocated()); | 159 CHECK(op->IsUnallocated()); |
158 const auto* unallocated = UnallocatedOperand::cast(op); | 160 const UnallocatedOperand* unallocated = UnallocatedOperand::cast(op); |
159 int vreg = unallocated->virtual_register(); | 161 int vreg = unallocated->virtual_register(); |
160 constraint->virtual_register_ = vreg; | 162 constraint->virtual_register_ = vreg; |
161 if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) { | 163 if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) { |
162 constraint->type_ = sequence()->IsFloat(vreg) ? kDoubleSlot : kSlot; | 164 constraint->type_ = sequence()->IsFloat(vreg) ? kDoubleSlot : kSlot; |
163 constraint->value_ = unallocated->fixed_slot_index(); | 165 constraint->value_ = unallocated->fixed_slot_index(); |
164 } else { | 166 } else { |
165 switch (unallocated->extended_policy()) { | 167 switch (unallocated->extended_policy()) { |
166 case UnallocatedOperand::ANY: | 168 case UnallocatedOperand::ANY: |
167 case UnallocatedOperand::NONE: | 169 case UnallocatedOperand::NONE: |
168 if (sequence()->IsFloat(vreg)) { | 170 if (sequence()->IsFloat(vreg)) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 void RegisterAllocatorVerifier::CheckConstraint( | 208 void RegisterAllocatorVerifier::CheckConstraint( |
207 const InstructionOperand* op, const OperandConstraint* constraint) { | 209 const InstructionOperand* op, const OperandConstraint* constraint) { |
208 switch (constraint->type_) { | 210 switch (constraint->type_) { |
209 case kConstant: | 211 case kConstant: |
210 CHECK(op->IsConstant()); | 212 CHECK(op->IsConstant()); |
211 CHECK_EQ(ConstantOperand::cast(op)->virtual_register(), | 213 CHECK_EQ(ConstantOperand::cast(op)->virtual_register(), |
212 constraint->value_); | 214 constraint->value_); |
213 return; | 215 return; |
214 case kImmediate: { | 216 case kImmediate: { |
215 CHECK(op->IsImmediate()); | 217 CHECK(op->IsImmediate()); |
216 auto imm = ImmediateOperand::cast(op); | 218 const ImmediateOperand* imm = ImmediateOperand::cast(op); |
217 int value = imm->type() == ImmediateOperand::INLINE | 219 int value = imm->type() == ImmediateOperand::INLINE |
218 ? imm->inline_value() | 220 ? imm->inline_value() |
219 : imm->indexed_value(); | 221 : imm->indexed_value(); |
220 CHECK_EQ(value, constraint->value_); | 222 CHECK_EQ(value, constraint->value_); |
221 return; | 223 return; |
222 } | 224 } |
223 case kRegister: | 225 case kRegister: |
224 CHECK(op->IsRegister()); | 226 CHECK(op->IsRegister()); |
225 return; | 227 return; |
226 case kDoubleRegister: | 228 case kDoubleRegister: |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 : public ZoneMap<const InstructionOperand*, MapValue*, OperandLess> { | 319 : public ZoneMap<const InstructionOperand*, MapValue*, OperandLess> { |
318 public: | 320 public: |
319 explicit Map(Zone* zone) | 321 explicit Map(Zone* zone) |
320 : ZoneMap<const InstructionOperand*, MapValue*, OperandLess>(zone) {} | 322 : ZoneMap<const InstructionOperand*, MapValue*, OperandLess>(zone) {} |
321 | 323 |
322 // Remove all entries with keys not in other. | 324 // Remove all entries with keys not in other. |
323 void Intersect(const Map& other) { | 325 void Intersect(const Map& other) { |
324 if (this->empty()) return; | 326 if (this->empty()) return; |
325 auto it = this->begin(); | 327 auto it = this->begin(); |
326 OperandLess less; | 328 OperandLess less; |
327 for (const auto& o : other) { | 329 for (const std::pair<const InstructionOperand*, MapValue*>& o : other) { |
328 while (less(it->first, o.first)) { | 330 while (less(it->first, o.first)) { |
329 this->erase(it++); | 331 this->erase(it++); |
330 if (it == this->end()) return; | 332 if (it == this->end()) return; |
331 } | 333 } |
332 if (it->first->EqualsCanonicalized(*o.first)) { | 334 if (it->first->EqualsCanonicalized(*o.first)) { |
333 ++it; | 335 ++it; |
334 if (it == this->end()) return; | 336 if (it == this->end()) return; |
335 } else { | 337 } else { |
336 CHECK(less(o.first, it->first)); | 338 CHECK(less(o.first, it->first)); |
337 } | 339 } |
338 } | 340 } |
339 } | 341 } |
340 }; | 342 }; |
341 | 343 |
342 explicit OperandMap(Zone* zone) : map_(zone) {} | 344 explicit OperandMap(Zone* zone) : map_(zone) {} |
343 | 345 |
344 Map& map() { return map_; } | 346 Map& map() { return map_; } |
345 | 347 |
346 void RunParallelMoves(Zone* zone, const ParallelMove* moves) { | 348 void RunParallelMoves(Zone* zone, const ParallelMove* moves) { |
347 // Compute outgoing mappings. | 349 // Compute outgoing mappings. |
348 Map to_insert(zone); | 350 Map to_insert(zone); |
349 for (auto move : *moves) { | 351 for (const MoveOperands* move : *moves) { |
350 if (move->IsEliminated()) continue; | 352 if (move->IsEliminated()) continue; |
351 auto cur = map().find(&move->source()); | 353 auto cur = map().find(&move->source()); |
352 CHECK(cur != map().end()); | 354 CHECK(cur != map().end()); |
353 auto res = | 355 auto res = |
354 to_insert.insert(std::make_pair(&move->destination(), cur->second)); | 356 to_insert.insert(std::make_pair(&move->destination(), cur->second)); |
355 // Ensure injectivity of moves. | 357 // Ensure injectivity of moves. |
356 CHECK(res.second); | 358 CHECK(res.second); |
357 } | 359 } |
358 // Drop current mappings. | 360 // Drop current mappings. |
359 for (auto move : *moves) { | 361 for (const MoveOperands* move : *moves) { |
360 if (move->IsEliminated()) continue; | 362 if (move->IsEliminated()) continue; |
361 auto cur = map().find(&move->destination()); | 363 auto cur = map().find(&move->destination()); |
362 if (cur != map().end()) map().erase(cur); | 364 if (cur != map().end()) map().erase(cur); |
363 } | 365 } |
364 // Insert new values. | 366 // Insert new values. |
365 map().insert(to_insert.begin(), to_insert.end()); | 367 map().insert(to_insert.begin(), to_insert.end()); |
366 } | 368 } |
367 | 369 |
368 void RunGaps(Zone* zone, const Instruction* instr) { | 370 void RunGaps(Zone* zone, const Instruction* instr) { |
369 for (int i = Instruction::FIRST_GAP_POSITION; | 371 for (int i = Instruction::FIRST_GAP_POSITION; |
370 i <= Instruction::LAST_GAP_POSITION; i++) { | 372 i <= Instruction::LAST_GAP_POSITION; i++) { |
371 auto inner_pos = static_cast<Instruction::GapPosition>(i); | 373 Instruction::GapPosition inner_pos = |
372 auto move = instr->GetParallelMove(inner_pos); | 374 static_cast<Instruction::GapPosition>(i); |
| 375 const ParallelMove* move = instr->GetParallelMove(inner_pos); |
373 if (move == nullptr) continue; | 376 if (move == nullptr) continue; |
374 RunParallelMoves(zone, move); | 377 RunParallelMoves(zone, move); |
375 } | 378 } |
376 } | 379 } |
377 | 380 |
378 void Drop(const InstructionOperand* op) { | 381 void Drop(const InstructionOperand* op) { |
379 auto it = map().find(op); | 382 auto it = map().find(op); |
380 if (it != map().end()) map().erase(it); | 383 if (it != map().end()) map().erase(it); |
381 } | 384 } |
382 | 385 |
383 void DropRegisters(const RegisterConfiguration* config) { | 386 void DropRegisters(const RegisterConfiguration* config) { |
384 // TODO(dcarney): sort map by kind and drop range. | 387 // TODO(dcarney): sort map by kind and drop range. |
385 for (auto it = map().begin(); it != map().end();) { | 388 for (auto it = map().begin(); it != map().end();) { |
386 auto op = it->first; | 389 const InstructionOperand* op = it->first; |
387 if (op->IsRegister() || op->IsDoubleRegister()) { | 390 if (op->IsRegister() || op->IsDoubleRegister()) { |
388 map().erase(it++); | 391 map().erase(it++); |
389 } else { | 392 } else { |
390 ++it; | 393 ++it; |
391 } | 394 } |
392 } | 395 } |
393 } | 396 } |
394 | 397 |
395 MapValue* Define(Zone* zone, const InstructionOperand* op, | 398 MapValue* Define(Zone* zone, const InstructionOperand* op, |
396 int virtual_register) { | 399 int virtual_register) { |
397 auto value = new (zone) MapValue(); | 400 MapValue* value = new (zone) MapValue(); |
398 value->define_vreg = virtual_register; | 401 value->define_vreg = virtual_register; |
399 auto res = map().insert(std::make_pair(op, value)); | 402 auto res = map().insert(std::make_pair(op, value)); |
400 if (!res.second) res.first->second = value; | 403 if (!res.second) res.first->second = value; |
401 return value; | 404 return value; |
402 } | 405 } |
403 | 406 |
404 void Use(const InstructionOperand* op, int use_vreg, bool initial_pass) { | 407 void Use(const InstructionOperand* op, int use_vreg, bool initial_pass) { |
405 auto it = map().find(op); | 408 auto it = map().find(op); |
406 CHECK(it != map().end()); | 409 CHECK(it != map().end()); |
407 auto v = it->second; | 410 MapValue* v = it->second; |
408 if (v->define_vreg != kInvalidVreg) { | 411 if (v->define_vreg != kInvalidVreg) { |
409 CHECK_EQ(v->define_vreg, use_vreg); | 412 CHECK_EQ(v->define_vreg, use_vreg); |
410 } | 413 } |
411 // Already used this vreg in this block. | 414 // Already used this vreg in this block. |
412 if (v->use_vreg != kInvalidVreg) { | 415 if (v->use_vreg != kInvalidVreg) { |
413 CHECK_EQ(v->use_vreg, use_vreg); | 416 CHECK_EQ(v->use_vreg, use_vreg); |
414 return; | 417 return; |
415 } | 418 } |
416 if (!initial_pass) { | 419 if (!initial_pass) { |
417 // A value may be defined and used in this block or the use must have | 420 // A value may be defined and used in this block or the use must have |
(...skipping 20 matching lines...) Expand all Loading... |
438 return; | 441 return; |
439 } | 442 } |
440 // Use of a non-phi value without definition. | 443 // Use of a non-phi value without definition. |
441 CHECK(false); | 444 CHECK(false); |
442 } | 445 } |
443 | 446 |
444 void UsePhi(const InstructionOperand* op, const PhiData* phi, | 447 void UsePhi(const InstructionOperand* op, const PhiData* phi, |
445 bool initial_pass) { | 448 bool initial_pass) { |
446 auto it = map().find(op); | 449 auto it = map().find(op); |
447 CHECK(it != map().end()); | 450 CHECK(it != map().end()); |
448 auto v = it->second; | 451 MapValue* v = it->second; |
449 int use_vreg = phi->virtual_register; | 452 int use_vreg = phi->virtual_register; |
450 // Phis are not defined. | 453 // Phis are not defined. |
451 CHECK_EQ(kInvalidVreg, v->define_vreg); | 454 CHECK_EQ(kInvalidVreg, v->define_vreg); |
452 // Already used this vreg in this block. | 455 // Already used this vreg in this block. |
453 if (v->use_vreg != kInvalidVreg) { | 456 if (v->use_vreg != kInvalidVreg) { |
454 CHECK_EQ(v->use_vreg, use_vreg); | 457 CHECK_EQ(v->use_vreg, use_vreg); |
455 return; | 458 return; |
456 } | 459 } |
457 if (!initial_pass) { | 460 if (!initial_pass) { |
458 // A used phi must have propagated its use to a predecessor. | 461 // A used phi must have propagated its use to a predecessor. |
459 CHECK_EQ(v->succ_vreg, use_vreg); | 462 CHECK_EQ(v->succ_vreg, use_vreg); |
460 // Mark the use. | 463 // Mark the use. |
461 v->use_vreg = use_vreg; | 464 v->use_vreg = use_vreg; |
462 return; | 465 return; |
463 } | 466 } |
464 // Go up the block list starting at the first predecessor and ensure this | 467 // Go up the block list starting at the first predecessor and ensure this |
465 // phi has a correct use or definition. | 468 // phi has a correct use or definition. |
466 for (v = v->incoming; v != nullptr; v = v->incoming) { | 469 for (v = v->incoming; v != nullptr; v = v->incoming) { |
467 // Value unused in block. | 470 // Value unused in block. |
468 if (v->define_vreg == kInvalidVreg && v->use_vreg == kInvalidVreg) { | 471 if (v->define_vreg == kInvalidVreg && v->use_vreg == kInvalidVreg) { |
469 continue; | 472 continue; |
470 } | 473 } |
471 // Found correct definition or use. | 474 // Found correct definition or use. |
472 if (v->define_vreg != kInvalidVreg) { | 475 if (v->define_vreg != kInvalidVreg) { |
473 CHECK(v->define_vreg == phi->first_pred_vreg); | 476 CHECK(v->define_vreg == phi->first_pred_vreg); |
474 } else if (v->use_vreg != phi->first_pred_vreg) { | 477 } else if (v->use_vreg != phi->first_pred_vreg) { |
475 // Walk the phi chain, hunting for a matching phi use. | 478 // Walk the phi chain, hunting for a matching phi use. |
476 auto p = phi; | 479 const PhiData* p = phi; |
477 for (; p != nullptr; p = p->first_pred_phi) { | 480 for (; p != nullptr; p = p->first_pred_phi) { |
478 if (p->virtual_register == v->use_vreg) break; | 481 if (p->virtual_register == v->use_vreg) break; |
479 } | 482 } |
480 CHECK(p); | 483 CHECK(p); |
481 } | 484 } |
482 // Mark the use. | 485 // Mark the use. |
483 it->second->use_vreg = use_vreg; | 486 it->second->use_vreg = use_vreg; |
484 return; | 487 return; |
485 } | 488 } |
486 // Use of a phi value without definition. | 489 // Use of a phi value without definition. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 return initial_pass ? InitializeFromFirstPredecessor(block_index) | 525 return initial_pass ? InitializeFromFirstPredecessor(block_index) |
523 : InitializeFromIntersection(block_index); | 526 : InitializeFromIntersection(block_index); |
524 } | 527 } |
525 | 528 |
526 void PropagateUsesBackwards() { | 529 void PropagateUsesBackwards() { |
527 typedef std::set<size_t, std::greater<size_t>, zone_allocator<size_t>> | 530 typedef std::set<size_t, std::greater<size_t>, zone_allocator<size_t>> |
528 BlockIds; | 531 BlockIds; |
529 BlockIds block_ids((BlockIds::key_compare()), | 532 BlockIds block_ids((BlockIds::key_compare()), |
530 zone_allocator<size_t>(zone())); | 533 zone_allocator<size_t>(zone())); |
531 // First ensure that incoming contains only keys in all predecessors. | 534 // First ensure that incoming contains only keys in all predecessors. |
532 for (auto block : sequence()->instruction_blocks()) { | 535 for (const InstructionBlock* block : sequence()->instruction_blocks()) { |
533 size_t index = block->rpo_number().ToSize(); | 536 size_t index = block->rpo_number().ToSize(); |
534 block_ids.insert(index); | 537 block_ids.insert(index); |
535 auto& succ_map = incoming_maps_[index]->map(); | 538 OperandMap::Map& succ_map = incoming_maps_[index]->map(); |
536 for (size_t i = 0; i < block->PredecessorCount(); ++i) { | 539 for (size_t i = 0; i < block->PredecessorCount(); ++i) { |
537 auto pred_rpo = block->predecessors()[i]; | 540 RpoNumber pred_rpo = block->predecessors()[i]; |
538 succ_map.Intersect(outgoing_maps_[pred_rpo.ToSize()]->map()); | 541 succ_map.Intersect(outgoing_maps_[pred_rpo.ToSize()]->map()); |
539 } | 542 } |
540 } | 543 } |
541 // Back propagation fixpoint. | 544 // Back propagation fixpoint. |
542 while (!block_ids.empty()) { | 545 while (!block_ids.empty()) { |
543 // Pop highest block_id. | 546 // Pop highest block_id. |
544 auto block_id_it = block_ids.begin(); | 547 auto block_id_it = block_ids.begin(); |
545 const size_t succ_index = *block_id_it; | 548 const size_t succ_index = *block_id_it; |
546 block_ids.erase(block_id_it); | 549 block_ids.erase(block_id_it); |
547 // Propagate uses back to their definition blocks using succ_vreg. | 550 // Propagate uses back to their definition blocks using succ_vreg. |
548 auto block = sequence()->instruction_blocks()[succ_index]; | 551 const InstructionBlock* block = |
549 auto& succ_map = incoming_maps_[succ_index]->map(); | 552 sequence()->instruction_blocks()[succ_index]; |
| 553 OperandMap::Map& succ_map = incoming_maps_[succ_index]->map(); |
550 for (size_t i = 0; i < block->PredecessorCount(); ++i) { | 554 for (size_t i = 0; i < block->PredecessorCount(); ++i) { |
551 for (auto& succ_val : succ_map) { | 555 for (auto& succ_val : succ_map) { |
552 // An incoming map contains no defines. | 556 // An incoming map contains no defines. |
553 CHECK_EQ(kInvalidVreg, succ_val.second->define_vreg); | 557 CHECK_EQ(kInvalidVreg, succ_val.second->define_vreg); |
554 // Compute succ_vreg. | 558 // Compute succ_vreg. |
555 int succ_vreg = succ_val.second->succ_vreg; | 559 int succ_vreg = succ_val.second->succ_vreg; |
556 if (succ_vreg == kInvalidVreg) { | 560 if (succ_vreg == kInvalidVreg) { |
557 succ_vreg = succ_val.second->use_vreg; | 561 succ_vreg = succ_val.second->use_vreg; |
558 // Initialize succ_vreg in back propagation chain. | 562 // Initialize succ_vreg in back propagation chain. |
559 succ_val.second->succ_vreg = succ_vreg; | 563 succ_val.second->succ_vreg = succ_vreg; |
560 } | 564 } |
561 if (succ_vreg == kInvalidVreg) continue; | 565 if (succ_vreg == kInvalidVreg) continue; |
562 // May need to transition phi. | 566 // May need to transition phi. |
563 if (IsPhi(succ_vreg)) { | 567 if (IsPhi(succ_vreg)) { |
564 auto phi = GetPhi(succ_vreg); | 568 const PhiData* phi = GetPhi(succ_vreg); |
565 if (phi->definition_rpo.ToSize() == succ_index) { | 569 if (phi->definition_rpo.ToSize() == succ_index) { |
566 // phi definition block, transition to pred value. | 570 // phi definition block, transition to pred value. |
567 succ_vreg = phi->operands[i]; | 571 succ_vreg = phi->operands[i]; |
568 } | 572 } |
569 } | 573 } |
570 // Push succ_vreg up to all predecessors. | 574 // Push succ_vreg up to all predecessors. |
571 auto pred_rpo = block->predecessors()[i]; | 575 RpoNumber pred_rpo = block->predecessors()[i]; |
572 auto& pred_map = outgoing_maps_[pred_rpo.ToSize()]->map(); | 576 OperandMap::Map& pred_map = outgoing_maps_[pred_rpo.ToSize()]->map(); |
573 auto& pred_val = *pred_map.find(succ_val.first); | 577 auto& pred_val = *pred_map.find(succ_val.first); |
574 if (pred_val.second->use_vreg != kInvalidVreg) { | 578 if (pred_val.second->use_vreg != kInvalidVreg) { |
575 CHECK_EQ(succ_vreg, pred_val.second->use_vreg); | 579 CHECK_EQ(succ_vreg, pred_val.second->use_vreg); |
576 } | 580 } |
577 if (pred_val.second->define_vreg != kInvalidVreg) { | 581 if (pred_val.second->define_vreg != kInvalidVreg) { |
578 CHECK_EQ(succ_vreg, pred_val.second->define_vreg); | 582 CHECK_EQ(succ_vreg, pred_val.second->define_vreg); |
579 } | 583 } |
580 if (pred_val.second->succ_vreg != kInvalidVreg) { | 584 if (pred_val.second->succ_vreg != kInvalidVreg) { |
581 if (succ_vreg != pred_val.second->succ_vreg) { | 585 if (succ_vreg != pred_val.second->succ_vreg) { |
582 // When a block introduces 2 identical phis A and B, and both are | 586 // When a block introduces 2 identical phis A and B, and both are |
(...skipping 16 matching lines...) Expand all Loading... |
599 } | 603 } |
600 } | 604 } |
601 } else { | 605 } else { |
602 pred_val.second->succ_vreg = succ_vreg; | 606 pred_val.second->succ_vreg = succ_vreg; |
603 block_ids.insert(pred_rpo.ToSize()); | 607 block_ids.insert(pred_rpo.ToSize()); |
604 } | 608 } |
605 } | 609 } |
606 } | 610 } |
607 } | 611 } |
608 // Clear uses and back links for second pass. | 612 // Clear uses and back links for second pass. |
609 for (auto operand_map : incoming_maps_) { | 613 for (OperandMap* operand_map : incoming_maps_) { |
610 for (auto& succ_val : operand_map->map()) { | 614 for (auto& succ_val : operand_map->map()) { |
611 succ_val.second->incoming = nullptr; | 615 succ_val.second->incoming = nullptr; |
612 succ_val.second->use_vreg = kInvalidVreg; | 616 succ_val.second->use_vreg = kInvalidVreg; |
613 } | 617 } |
614 } | 618 } |
615 } | 619 } |
616 | 620 |
617 private: | 621 private: |
618 OperandMap* InitializeFromFirstPredecessor(size_t block_index) { | 622 OperandMap* InitializeFromFirstPredecessor(size_t block_index) { |
619 auto to_init = outgoing_maps_[block_index]; | 623 OperandMap* to_init = outgoing_maps_[block_index]; |
620 CHECK(to_init->map().empty()); | 624 CHECK(to_init->map().empty()); |
621 auto block = sequence()->instruction_blocks()[block_index]; | 625 const InstructionBlock* block = |
| 626 sequence()->instruction_blocks()[block_index]; |
622 if (block->predecessors().empty()) return to_init; | 627 if (block->predecessors().empty()) return to_init; |
623 size_t predecessor_index = block->predecessors()[0].ToSize(); | 628 size_t predecessor_index = block->predecessors()[0].ToSize(); |
624 // Ensure not a backedge. | 629 // Ensure not a backedge. |
625 CHECK(predecessor_index < block->rpo_number().ToSize()); | 630 CHECK(predecessor_index < block->rpo_number().ToSize()); |
626 auto incoming = outgoing_maps_[predecessor_index]; | 631 OperandMap* incoming = outgoing_maps_[predecessor_index]; |
627 // Copy map and replace values. | 632 // Copy map and replace values. |
628 to_init->map() = incoming->map(); | 633 to_init->map() = incoming->map(); |
629 for (auto& it : to_init->map()) { | 634 for (auto& it : to_init->map()) { |
630 auto incoming = it.second; | 635 OperandMap::MapValue* incoming = it.second; |
631 it.second = new (zone()) OperandMap::MapValue(); | 636 it.second = new (zone()) OperandMap::MapValue(); |
632 it.second->incoming = incoming; | 637 it.second->incoming = incoming; |
633 } | 638 } |
634 // Copy to incoming map for second pass. | 639 // Copy to incoming map for second pass. |
635 incoming_maps_[block_index]->map() = to_init->map(); | 640 incoming_maps_[block_index]->map() = to_init->map(); |
636 return to_init; | 641 return to_init; |
637 } | 642 } |
638 | 643 |
639 OperandMap* InitializeFromIntersection(size_t block_index) { | 644 OperandMap* InitializeFromIntersection(size_t block_index) { |
640 return incoming_maps_[block_index]; | 645 return incoming_maps_[block_index]; |
641 } | 646 } |
642 | 647 |
643 void InitializeOperandMaps() { | 648 void InitializeOperandMaps() { |
644 size_t block_count = sequence()->instruction_blocks().size(); | 649 size_t block_count = sequence()->instruction_blocks().size(); |
645 incoming_maps_.reserve(block_count); | 650 incoming_maps_.reserve(block_count); |
646 outgoing_maps_.reserve(block_count); | 651 outgoing_maps_.reserve(block_count); |
647 for (size_t i = 0; i < block_count; ++i) { | 652 for (size_t i = 0; i < block_count; ++i) { |
648 incoming_maps_.push_back(new (zone()) OperandMap(zone())); | 653 incoming_maps_.push_back(new (zone()) OperandMap(zone())); |
649 outgoing_maps_.push_back(new (zone()) OperandMap(zone())); | 654 outgoing_maps_.push_back(new (zone()) OperandMap(zone())); |
650 } | 655 } |
651 } | 656 } |
652 | 657 |
653 void InitializePhis() { | 658 void InitializePhis() { |
654 const size_t block_count = sequence()->instruction_blocks().size(); | 659 const size_t block_count = sequence()->instruction_blocks().size(); |
655 for (size_t block_index = 0; block_index < block_count; ++block_index) { | 660 for (size_t block_index = 0; block_index < block_count; ++block_index) { |
656 const auto block = sequence()->instruction_blocks()[block_index]; | 661 const InstructionBlock* block = |
657 for (auto phi : block->phis()) { | 662 sequence()->instruction_blocks()[block_index]; |
| 663 for (const PhiInstruction* phi : block->phis()) { |
658 int first_pred_vreg = phi->operands()[0]; | 664 int first_pred_vreg = phi->operands()[0]; |
659 const PhiData* first_pred_phi = nullptr; | 665 const PhiData* first_pred_phi = nullptr; |
660 if (IsPhi(first_pred_vreg)) { | 666 if (IsPhi(first_pred_vreg)) { |
661 first_pred_phi = GetPhi(first_pred_vreg); | 667 first_pred_phi = GetPhi(first_pred_vreg); |
662 first_pred_vreg = first_pred_phi->first_pred_vreg; | 668 first_pred_vreg = first_pred_phi->first_pred_vreg; |
663 } | 669 } |
664 CHECK(!IsPhi(first_pred_vreg)); | 670 CHECK(!IsPhi(first_pred_vreg)); |
665 auto phi_data = new (zone()) PhiData( | 671 PhiData* phi_data = new (zone()) PhiData( |
666 block->rpo_number(), phi, first_pred_vreg, first_pred_phi, zone()); | 672 block->rpo_number(), phi, first_pred_vreg, first_pred_phi, zone()); |
667 auto res = | 673 auto res = |
668 phi_map_.insert(std::make_pair(phi->virtual_register(), phi_data)); | 674 phi_map_.insert(std::make_pair(phi->virtual_register(), phi_data)); |
669 CHECK(res.second); | 675 CHECK(res.second); |
670 phi_map_guard_.Add(phi->virtual_register()); | 676 phi_map_guard_.Add(phi->virtual_register()); |
671 } | 677 } |
672 } | 678 } |
673 } | 679 } |
674 | 680 |
675 typedef ZoneVector<OperandMap*> OperandMaps; | 681 typedef ZoneVector<OperandMap*> OperandMaps; |
(...skipping 17 matching lines...) Expand all Loading... |
693 block_maps.PropagateUsesBackwards(); | 699 block_maps.PropagateUsesBackwards(); |
694 VerifyGapMoves(&block_maps, false); | 700 VerifyGapMoves(&block_maps, false); |
695 } | 701 } |
696 | 702 |
697 | 703 |
698 // Compute and verify outgoing values for every block. | 704 // Compute and verify outgoing values for every block. |
699 void RegisterAllocatorVerifier::VerifyGapMoves(BlockMaps* block_maps, | 705 void RegisterAllocatorVerifier::VerifyGapMoves(BlockMaps* block_maps, |
700 bool initial_pass) { | 706 bool initial_pass) { |
701 const size_t block_count = sequence()->instruction_blocks().size(); | 707 const size_t block_count = sequence()->instruction_blocks().size(); |
702 for (size_t block_index = 0; block_index < block_count; ++block_index) { | 708 for (size_t block_index = 0; block_index < block_count; ++block_index) { |
703 auto current = block_maps->InitializeIncoming(block_index, initial_pass); | 709 OperandMap* current = |
704 const auto block = sequence()->instruction_blocks()[block_index]; | 710 block_maps->InitializeIncoming(block_index, initial_pass); |
| 711 const InstructionBlock* block = |
| 712 sequence()->instruction_blocks()[block_index]; |
705 for (int instr_index = block->code_start(); instr_index < block->code_end(); | 713 for (int instr_index = block->code_start(); instr_index < block->code_end(); |
706 ++instr_index) { | 714 ++instr_index) { |
707 const auto& instr_constraint = constraints_[instr_index]; | 715 const InstructionConstraint& instr_constraint = constraints_[instr_index]; |
708 const auto instr = instr_constraint.instruction_; | 716 const Instruction* instr = instr_constraint.instruction_; |
709 current->RunGaps(zone(), instr); | 717 current->RunGaps(zone(), instr); |
710 const auto op_constraints = instr_constraint.operand_constraints_; | 718 const OperandConstraint* op_constraints = |
| 719 instr_constraint.operand_constraints_; |
711 size_t count = 0; | 720 size_t count = 0; |
712 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) { | 721 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) { |
713 if (op_constraints[count].type_ == kImmediate || | 722 if (op_constraints[count].type_ == kImmediate || |
714 op_constraints[count].type_ == kExplicit) { | 723 op_constraints[count].type_ == kExplicit) { |
715 continue; | 724 continue; |
716 } | 725 } |
717 int virtual_register = op_constraints[count].virtual_register_; | 726 int virtual_register = op_constraints[count].virtual_register_; |
718 auto op = instr->InputAt(i); | 727 const InstructionOperand* op = instr->InputAt(i); |
719 if (!block_maps->IsPhi(virtual_register)) { | 728 if (!block_maps->IsPhi(virtual_register)) { |
720 current->Use(op, virtual_register, initial_pass); | 729 current->Use(op, virtual_register, initial_pass); |
721 } else { | 730 } else { |
722 auto phi = block_maps->GetPhi(virtual_register); | 731 const PhiData* phi = block_maps->GetPhi(virtual_register); |
723 current->UsePhi(op, phi, initial_pass); | 732 current->UsePhi(op, phi, initial_pass); |
724 } | 733 } |
725 } | 734 } |
726 for (size_t i = 0; i < instr->TempCount(); ++i, ++count) { | 735 for (size_t i = 0; i < instr->TempCount(); ++i, ++count) { |
727 current->Drop(instr->TempAt(i)); | 736 current->Drop(instr->TempAt(i)); |
728 } | 737 } |
729 if (instr->IsCall()) { | 738 if (instr->IsCall()) { |
730 current->DropRegisters(config()); | 739 current->DropRegisters(config()); |
731 } | 740 } |
732 for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) { | 741 for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) { |
(...skipping 13 matching lines...) Expand all Loading... |
746 USE(insert_result); | 755 USE(insert_result); |
747 } | 756 } |
748 } | 757 } |
749 } | 758 } |
750 } | 759 } |
751 } | 760 } |
752 | 761 |
753 } // namespace compiler | 762 } // namespace compiler |
754 } // namespace internal | 763 } // namespace internal |
755 } // namespace v8 | 764 } // namespace v8 |
OLD | NEW |