Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: src/compiler/register-allocator.cc

Issue 1242123006: [turbofan] Deferred block spilling heuristic - first step. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/register-allocator.h ('k') | test/mjsunit/mjsunit.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/base/adapters.h" 5 #include "src/base/adapters.h"
6 #include "src/compiler/linkage.h" 6 #include "src/compiler/linkage.h"
7 #include "src/compiler/register-allocator.h" 7 #include "src/compiler/register-allocator.h"
8 #include "src/string-stream.h" 8 #include "src/string-stream.h"
9 9
10 namespace v8 { 10 namespace v8 {
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 first_interval_(nullptr), 249 first_interval_(nullptr),
250 first_pos_(nullptr), 250 first_pos_(nullptr),
251 parent_(nullptr), 251 parent_(nullptr),
252 next_(nullptr), 252 next_(nullptr),
253 spill_operand_(nullptr), 253 spill_operand_(nullptr),
254 spills_at_definition_(nullptr), 254 spills_at_definition_(nullptr),
255 current_interval_(nullptr), 255 current_interval_(nullptr),
256 last_processed_use_(nullptr), 256 last_processed_use_(nullptr),
257 current_hint_position_(nullptr), 257 current_hint_position_(nullptr),
258 size_(kInvalidSize), 258 size_(kInvalidSize),
259 weight_(kInvalidWeight) { 259 weight_(kInvalidWeight),
260 spilled_in_deferred_block_(false) {
260 DCHECK(AllocatedOperand::IsSupportedMachineType(machine_type)); 261 DCHECK(AllocatedOperand::IsSupportedMachineType(machine_type));
261 bits_ = SpillTypeField::encode(SpillType::kNoSpillType) | 262 bits_ = SpillTypeField::encode(SpillType::kNoSpillType) |
262 AssignedRegisterField::encode(kUnassignedRegister) | 263 AssignedRegisterField::encode(kUnassignedRegister) |
263 MachineTypeField::encode(machine_type); 264 MachineTypeField::encode(machine_type);
264 } 265 }
265 266
266 267
267 void LiveRange::Verify() const { 268 void LiveRange::Verify() const {
268 // Walk the positions, verifying that each is in an interval. 269 // Walk the positions, verifying that each is in an interval.
269 auto interval = first_interval_; 270 auto interval = first_interval_;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 313
313 314
314 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, 315 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index,
315 InstructionOperand* operand) { 316 InstructionOperand* operand) {
316 DCHECK(HasNoSpillType()); 317 DCHECK(HasNoSpillType());
317 spills_at_definition_ = new (zone) 318 spills_at_definition_ = new (zone)
318 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); 319 SpillAtDefinitionList(gap_index, operand, spills_at_definition_);
319 } 320 }
320 321
321 322
323 bool LiveRange::TryCommitSpillInDeferredBlock(
324 InstructionSequence* code, const InstructionOperand& spill_operand) {
325 DCHECK(!IsChild());
326
327 if (!FLAG_turbo_greedy_regalloc || IsEmpty() || HasNoSpillType() ||
328 spill_operand.IsConstant() || spill_operand.IsImmediate())
329 return false;
330
331 int count = 0;
332 for (const LiveRange* child = this; child != nullptr; child = child->next()) {
333 int first_instr = child->Start().ToInstructionIndex();
334
335 // If the range starts at instruction end, the first instruction index is
336 // the next one.
337 if (!child->Start().IsGapPosition() && !child->Start().IsStart()) {
338 ++first_instr;
339 }
340
341 // We only look at where the range starts. It doesn't matter where it ends:
342 // if it ends past this block, then either there is a phi there already,
343 // or ResolveControlFlow will adapt the last instruction gap of this block
344 // as if there were a phi. In either case, data flow will be correct.
345 const InstructionBlock* block = code->GetInstructionBlock(first_instr);
346
347 // If we have slot uses in a subrange, bail out, because we need the value
348 // on the stack before that use.
349 bool has_slot_use = child->NextSlotPosition(child->Start()) != nullptr;
350 if (!block->IsDeferred()) {
351 if (child->spilled() || has_slot_use) {
352 return false;
353 }
354 } else {
355 if (child->spilled() || has_slot_use) ++count;
356 }
357 }
358 if (count == 0) return false;
359
360 spill_start_index_ = -1;
361 spilled_in_deferred_block_ = true;
362
363 TRACE("Live Range %d will be spilled only in deferred blocks.\n", id());
364 // If we have ranges that aren't spilled but require the operand on the stack,
365 // make sure we insert the spill.
366 for (const LiveRange* child = this; child != nullptr; child = child->next()) {
367 if (!child->spilled() &&
368 child->NextSlotPosition(child->Start()) != nullptr) {
369 auto instr = code->InstructionAt(child->Start().ToInstructionIndex());
370 // Insert spill at the end to let live range connections happen at START.
371 auto move =
372 instr->GetOrCreateParallelMove(Instruction::END, code->zone());
373 InstructionOperand assigned = child->GetAssignedOperand();
374 if (TopLevel()->has_slot_use()) {
375 bool found = false;
376 for (auto move_op : *move) {
377 if (move_op->IsEliminated()) continue;
378 if (move_op->source().Equals(assigned) &&
379 move_op->destination().Equals(spill_operand)) {
380 found = true;
381 break;
382 }
383 }
384 if (found) continue;
385 }
386
387 move->AddMove(assigned, spill_operand);
388 }
389 }
390
391 return true;
392 }
393
394
322 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, 395 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence,
323 const InstructionOperand& op, 396 const InstructionOperand& op,
324 bool might_be_duplicated) { 397 bool might_be_duplicated) {
325 DCHECK_IMPLIES(op.IsConstant(), spills_at_definition_ == nullptr); 398 DCHECK_IMPLIES(op.IsConstant(), spills_at_definition_ == nullptr);
326 DCHECK(!IsChild()); 399 DCHECK(!IsChild());
327 auto zone = sequence->zone(); 400 auto zone = sequence->zone();
401
402 // If this top level range has a child spilled in a deferred block, we use
403 // the range and control flow connection mechanism instead.
404 if (TryCommitSpillInDeferredBlock(sequence, op)) return;
405
328 for (auto to_spill = spills_at_definition_; to_spill != nullptr; 406 for (auto to_spill = spills_at_definition_; to_spill != nullptr;
329 to_spill = to_spill->next) { 407 to_spill = to_spill->next) {
330 auto instr = sequence->InstructionAt(to_spill->gap_index); 408 auto instr = sequence->InstructionAt(to_spill->gap_index);
331 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); 409 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone);
332 // Skip insertion if it's possible that the move exists already as a 410 // Skip insertion if it's possible that the move exists already as a
333 // constraint move from a fixed output register to a slot. 411 // constraint move from a fixed output register to a slot.
334 if (might_be_duplicated) { 412 if (might_be_duplicated) {
335 bool found = false; 413 bool found = false;
336 for (auto move_op : *move) { 414 for (auto move_op : *move) {
337 if (move_op->IsEliminated()) continue; 415 if (move_op->IsEliminated()) continue;
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 487
410 UsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) const { 488 UsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) const {
411 UsePosition* pos = NextUsePosition(start); 489 UsePosition* pos = NextUsePosition(start);
412 while (pos != nullptr && pos->type() != UsePositionType::kRequiresRegister) { 490 while (pos != nullptr && pos->type() != UsePositionType::kRequiresRegister) {
413 pos = pos->next(); 491 pos = pos->next();
414 } 492 }
415 return pos; 493 return pos;
416 } 494 }
417 495
418 496
497 UsePosition* LiveRange::NextSlotPosition(LifetimePosition start) const {
498 for (UsePosition* pos = NextUsePosition(start); pos != nullptr;
499 pos = pos->next()) {
500 if (pos->type() != UsePositionType::kRequiresSlot) continue;
501 return pos;
502 }
503 return nullptr;
504 }
505
506
419 bool LiveRange::CanBeSpilled(LifetimePosition pos) const { 507 bool LiveRange::CanBeSpilled(LifetimePosition pos) const {
420 // We cannot spill a live range that has a use requiring a register 508 // We cannot spill a live range that has a use requiring a register
421 // at the current or the immediate next position. 509 // at the current or the immediate next position.
422 auto use_pos = NextRegisterPosition(pos); 510 auto use_pos = NextRegisterPosition(pos);
423 if (use_pos == nullptr) return true; 511 if (use_pos == nullptr) return true;
424 return use_pos->pos() > pos.NextStart().End(); 512 return use_pos->pos() > pos.NextStart().End();
425 } 513 }
426 514
427 515
428 InstructionOperand LiveRange::GetAssignedOperand() const { 516 InstructionOperand LiveRange::GetAssignedOperand() const {
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
752 if (a == nullptr || a->start() > other->End()) break; 840 if (a == nullptr || a->start() > other->End()) break;
753 AdvanceLastProcessedMarker(a, advance_last_processed_up_to); 841 AdvanceLastProcessedMarker(a, advance_last_processed_up_to);
754 } else { 842 } else {
755 b = b->next(); 843 b = b->next();
756 } 844 }
757 } 845 }
758 return LifetimePosition::Invalid(); 846 return LifetimePosition::Invalid();
759 } 847 }
760 848
761 849
762 unsigned LiveRange::GetSize() { 850 void LiveRange::UpdateSize() {
763 if (size_ == kInvalidSize) { 851 size_ = 0;
764 size_ = 0; 852 for (auto interval = first_interval(); interval != nullptr;
765 for (auto interval = first_interval(); interval != nullptr; 853 interval = interval->next()) {
766 interval = interval->next()) { 854 size_ += (interval->end().value() - interval->start().value());
767 size_ += (interval->end().value() - interval->start().value());
768 }
769 } 855 }
770
771 return static_cast<unsigned>(size_);
772 } 856 }
773 857
774 858
775 static bool AreUseIntervalsIntersecting(UseInterval* interval1, 859 static bool AreUseIntervalsIntersecting(UseInterval* interval1,
776 UseInterval* interval2) { 860 UseInterval* interval2) {
777 while (interval1 != nullptr && interval2 != nullptr) { 861 while (interval1 != nullptr && interval2 != nullptr) {
778 if (interval1->start() < interval2->start()) { 862 if (interval1->start() < interval2->start()) {
779 if (interval1->end() > interval2->start()) { 863 if (interval1->end() > interval2->start()) {
780 return true; 864 return true;
781 } 865 }
(...skipping 1791 matching lines...) Expand 10 before | Expand all | Expand 10 after
2573 auto safe_point_pos = 2657 auto safe_point_pos =
2574 LifetimePosition::InstructionFromInstructionIndex(safe_point); 2658 LifetimePosition::InstructionFromInstructionIndex(safe_point);
2575 auto cur = range; 2659 auto cur = range;
2576 while (cur != nullptr && !cur->Covers(safe_point_pos)) { 2660 while (cur != nullptr && !cur->Covers(safe_point_pos)) {
2577 cur = cur->next(); 2661 cur = cur->next();
2578 } 2662 }
2579 if (cur == nullptr) continue; 2663 if (cur == nullptr) continue;
2580 2664
2581 // Check if the live range is spilled and the safe point is after 2665 // Check if the live range is spilled and the safe point is after
2582 // the spill position. 2666 // the spill position.
2583 if (!spill_operand.IsInvalid() && 2667 int spill_index = range->IsSpilledInSingleDeferredBlock()
2584 safe_point >= range->spill_start_index()) { 2668 ? cur->Start().ToInstructionIndex()
2669 : range->spill_start_index();
2670
2671 if (!spill_operand.IsInvalid() && safe_point >= spill_index) {
2585 TRACE("Pointer for range %d (spilled at %d) at safe point %d\n", 2672 TRACE("Pointer for range %d (spilled at %d) at safe point %d\n",
2586 range->id(), range->spill_start_index(), safe_point); 2673 range->id(), spill_index, safe_point);
2587 map->RecordReference(AllocatedOperand::cast(spill_operand)); 2674 map->RecordReference(AllocatedOperand::cast(spill_operand));
2588 } 2675 }
2589 2676
2590 if (!cur->spilled()) { 2677 if (!cur->spilled()) {
2591 TRACE( 2678 TRACE(
2592 "Pointer in register for range %d (start at %d) " 2679 "Pointer in register for range %d (start at %d) "
2593 "at safe point %d\n", 2680 "at safe point %d\n",
2594 cur->id(), cur->Start().value(), safe_point); 2681 cur->id(), cur->Start().value(), safe_point);
2595 auto operand = cur->GetAssignedOperand(); 2682 auto operand = cur->GetAssignedOperand();
2596 DCHECK(!operand.IsStackSlot()); 2683 DCHECK(!operand.IsStackSlot());
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
2773 if (CanEagerlyResolveControlFlow(block)) continue; 2860 if (CanEagerlyResolveControlFlow(block)) continue;
2774 auto live = live_in_sets[block->rpo_number().ToInt()]; 2861 auto live = live_in_sets[block->rpo_number().ToInt()];
2775 BitVector::Iterator iterator(live); 2862 BitVector::Iterator iterator(live);
2776 while (!iterator.Done()) { 2863 while (!iterator.Done()) {
2777 auto* array = finder.ArrayFor(iterator.Current()); 2864 auto* array = finder.ArrayFor(iterator.Current());
2778 for (auto pred : block->predecessors()) { 2865 for (auto pred : block->predecessors()) {
2779 FindResult result; 2866 FindResult result;
2780 const auto* pred_block = code()->InstructionBlockAt(pred); 2867 const auto* pred_block = code()->InstructionBlockAt(pred);
2781 array->Find(block, pred_block, &result); 2868 array->Find(block, pred_block, &result);
2782 if (result.cur_cover_ == result.pred_cover_ || 2869 if (result.cur_cover_ == result.pred_cover_ ||
2783 result.cur_cover_->spilled()) 2870 (!result.cur_cover_->TopLevel()->IsSpilledInSingleDeferredBlock() &&
2871 result.cur_cover_->spilled()))
2784 continue; 2872 continue;
2785 auto pred_op = result.pred_cover_->GetAssignedOperand(); 2873 auto pred_op = result.pred_cover_->GetAssignedOperand();
2786 auto cur_op = result.cur_cover_->GetAssignedOperand(); 2874 auto cur_op = result.cur_cover_->GetAssignedOperand();
2787 if (pred_op.Equals(cur_op)) continue; 2875 if (pred_op.Equals(cur_op)) continue;
2788 ResolveControlFlow(block, cur_op, pred_block, pred_op); 2876 ResolveControlFlow(block, cur_op, pred_block, pred_op);
2789 } 2877 }
2790 iterator.Advance(); 2878 iterator.Advance();
2791 } 2879 }
2792 } 2880 }
2793 } 2881 }
(...skipping 18 matching lines...) Expand all
2812 position = Instruction::END; 2900 position = Instruction::END;
2813 } 2901 }
2814 data()->AddGapMove(gap_index, position, pred_op, cur_op); 2902 data()->AddGapMove(gap_index, position, pred_op, cur_op);
2815 } 2903 }
2816 2904
2817 2905
2818 void LiveRangeConnector::ConnectRanges(Zone* local_zone) { 2906 void LiveRangeConnector::ConnectRanges(Zone* local_zone) {
2819 DelayedInsertionMap delayed_insertion_map(local_zone); 2907 DelayedInsertionMap delayed_insertion_map(local_zone);
2820 for (auto first_range : data()->live_ranges()) { 2908 for (auto first_range : data()->live_ranges()) {
2821 if (first_range == nullptr || first_range->IsChild()) continue; 2909 if (first_range == nullptr || first_range->IsChild()) continue;
2910 bool connect_spilled = first_range->IsSpilledInSingleDeferredBlock();
2822 for (auto second_range = first_range->next(); second_range != nullptr; 2911 for (auto second_range = first_range->next(); second_range != nullptr;
2823 first_range = second_range, second_range = second_range->next()) { 2912 first_range = second_range, second_range = second_range->next()) {
2824 auto pos = second_range->Start(); 2913 auto pos = second_range->Start();
2825 // Add gap move if the two live ranges touch and there is no block 2914 // Add gap move if the two live ranges touch and there is no block
2826 // boundary. 2915 // boundary.
2827 if (second_range->spilled()) continue; 2916 if (!connect_spilled && second_range->spilled()) continue;
2828 if (first_range->End() != pos) continue; 2917 if (first_range->End() != pos) continue;
2829 if (data()->IsBlockBoundary(pos) && 2918 if (data()->IsBlockBoundary(pos) &&
2830 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) { 2919 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) {
2831 continue; 2920 continue;
2832 } 2921 }
2833 auto prev_operand = first_range->GetAssignedOperand(); 2922 auto prev_operand = first_range->GetAssignedOperand();
2834 auto cur_operand = second_range->GetAssignedOperand(); 2923 auto cur_operand = second_range->GetAssignedOperand();
2835 if (prev_operand.Equals(cur_operand)) continue; 2924 if (prev_operand.Equals(cur_operand)) continue;
2836 bool delay_insertion = false; 2925 bool delay_insertion = false;
2837 Instruction::GapPosition gap_pos; 2926 Instruction::GapPosition gap_pos;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
2884 auto eliminate = moves->PrepareInsertAfter(move); 2973 auto eliminate = moves->PrepareInsertAfter(move);
2885 to_insert.push_back(move); 2974 to_insert.push_back(move);
2886 if (eliminate != nullptr) to_eliminate.push_back(eliminate); 2975 if (eliminate != nullptr) to_eliminate.push_back(eliminate);
2887 } 2976 }
2888 } 2977 }
2889 2978
2890 2979
2891 } // namespace compiler 2980 } // namespace compiler
2892 } // namespace internal 2981 } // namespace internal
2893 } // namespace v8 2982 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/register-allocator.h ('k') | test/mjsunit/mjsunit.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698