| 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/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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |