| 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 695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 706 | 706 |
| 707 | 707 |
| 708 void TopLevelLiveRange::RecordSpillLocation(Zone* zone, int gap_index, | 708 void TopLevelLiveRange::RecordSpillLocation(Zone* zone, int gap_index, |
| 709 InstructionOperand* operand) { | 709 InstructionOperand* operand) { |
| 710 DCHECK(HasNoSpillType()); | 710 DCHECK(HasNoSpillType()); |
| 711 spill_move_insertion_locations_ = new (zone) SpillMoveInsertionList( | 711 spill_move_insertion_locations_ = new (zone) SpillMoveInsertionList( |
| 712 gap_index, operand, spill_move_insertion_locations_); | 712 gap_index, operand, spill_move_insertion_locations_); |
| 713 } | 713 } |
| 714 | 714 |
| 715 | 715 |
| 716 void TopLevelLiveRange::MarkSpilledInDeferredBlock( | |
| 717 const InstructionSequence* code) { | |
| 718 if (!FLAG_turbo_preprocess_ranges || IsEmpty() || HasNoSpillType() || | |
| 719 !HasSpillRange()) { | |
| 720 return; | |
| 721 } | |
| 722 | |
| 723 int count = 0; | |
| 724 for (const LiveRange* child = this; child != nullptr; child = child->next()) { | |
| 725 int first_instr = child->Start().ToInstructionIndex(); | |
| 726 | |
| 727 // If the range starts at instruction end, the first instruction index is | |
| 728 // the next one. | |
| 729 if (!child->Start().IsGapPosition() && !child->Start().IsStart()) { | |
| 730 ++first_instr; | |
| 731 } | |
| 732 | |
| 733 // We only look at where the range starts. It doesn't matter where it ends: | |
| 734 // if it ends past this block, then either there is a phi there already, | |
| 735 // or ResolveControlFlow will adapt the last instruction gap of this block | |
| 736 // as if there were a phi. In either case, data flow will be correct. | |
| 737 const InstructionBlock* block = code->GetInstructionBlock(first_instr); | |
| 738 | |
| 739 // If we have slot uses in a subrange, bail out, because we need the value | |
| 740 // on the stack before that use. | |
| 741 bool has_slot_use = child->NextSlotPosition(child->Start()) != nullptr; | |
| 742 if (!block->IsDeferred()) { | |
| 743 if (child->spilled() || has_slot_use) { | |
| 744 TRACE( | |
| 745 "Live Range %d must be spilled at definition: found a " | |
| 746 "slot-requiring non-deferred child range %d.\n", | |
| 747 TopLevel()->vreg(), child->relative_id()); | |
| 748 return; | |
| 749 } | |
| 750 } else { | |
| 751 if (child->spilled() || has_slot_use) ++count; | |
| 752 } | |
| 753 } | |
| 754 if (count == 0) return; | |
| 755 | |
| 756 spill_start_index_ = -1; | |
| 757 spilled_in_deferred_blocks_ = true; | |
| 758 spill_move_insertion_locations_ = nullptr; | |
| 759 } | |
| 760 | |
| 761 | |
| 762 bool TopLevelLiveRange::TryCommitSpillInDeferredBlock( | 716 bool TopLevelLiveRange::TryCommitSpillInDeferredBlock( |
| 763 InstructionSequence* code, const InstructionOperand& spill_operand) { | 717 InstructionSequence* code, const InstructionOperand& spill_operand) { |
| 764 if (!IsSpilledOnlyInDeferredBlocks()) return false; | 718 if (!IsSpilledOnlyInDeferredBlocks()) return false; |
| 765 | 719 |
| 766 TRACE("Live Range %d will be spilled only in deferred blocks.\n", vreg()); | 720 TRACE("Live Range %d will be spilled only in deferred blocks.\n", vreg()); |
| 767 // If we have ranges that aren't spilled but require the operand on the stack, | 721 // If we have ranges that aren't spilled but require the operand on the stack, |
| 768 // make sure we insert the spill. | 722 // make sure we insert the spill. |
| 769 for (const LiveRange* child = this; child != nullptr; child = child->next()) { | 723 for (const LiveRange* child = this; child != nullptr; child = child->next()) { |
| 770 if (!child->spilled() && | 724 if (!child->spilled() && |
| 771 child->NextSlotPosition(child->Start()) != nullptr) { | 725 child->NextSlotPosition(child->Start()) != nullptr) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 } | 801 } |
| 848 | 802 |
| 849 | 803 |
| 850 void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end, | 804 void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end, |
| 851 Zone* zone) { | 805 Zone* zone) { |
| 852 DCHECK(start != Start() || end != End()); | 806 DCHECK(start != Start() || end != End()); |
| 853 DCHECK(start < end); | 807 DCHECK(start < end); |
| 854 | 808 |
| 855 TopLevelLiveRange splinter_temp(-1, machine_type()); | 809 TopLevelLiveRange splinter_temp(-1, machine_type()); |
| 856 UsePosition* last_in_splinter = nullptr; | 810 UsePosition* last_in_splinter = nullptr; |
| 857 if (start <= Start()) { | 811 // Live ranges defined in deferred blocks stay in deferred blocks, so we |
| 858 // TODO(mtrofin): here, the TopLevel part is in the deferred range, so we | 812 // don't need to splinter them. That means that start should always be |
| 859 // may want to continue processing the splinter. However, if the value is | 813 // after the beginning of the range. |
| 860 // defined in a cold block, and then used in a hot block, it follows that | 814 DCHECK(start > Start()); |
| 861 // it should terminate on the RHS of a phi, defined on the hot path. We | 815 |
| 862 // should check this, however, this may not be the place, because we don't | 816 if (end >= End()) { |
| 863 // have access to the instruction sequence. | |
| 864 DCHECK(end < End()); | |
| 865 DetachAt(end, &splinter_temp, zone); | |
| 866 next_ = nullptr; | |
| 867 } else if (end >= End()) { | |
| 868 DCHECK(start > Start()); | 817 DCHECK(start > Start()); |
| 869 DetachAt(start, &splinter_temp, zone); | 818 DetachAt(start, &splinter_temp, zone); |
| 870 next_ = nullptr; | 819 next_ = nullptr; |
| 871 } else { | 820 } else { |
| 872 DCHECK(start < End() && Start() < end); | 821 DCHECK(start < End() && Start() < end); |
| 873 | 822 |
| 874 const int kInvalidId = std::numeric_limits<int>::max(); | 823 const int kInvalidId = std::numeric_limits<int>::max(); |
| 875 | 824 |
| 876 UsePosition* last = DetachAt(start, &splinter_temp, zone); | 825 UsePosition* last = DetachAt(start, &splinter_temp, zone); |
| 877 | 826 |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1390 PrintF("\n"); | 1339 PrintF("\n"); |
| 1391 } else { | 1340 } else { |
| 1392 PrintF(" (function: %s)\n", debug_name()); | 1341 PrintF(" (function: %s)\n", debug_name()); |
| 1393 } | 1342 } |
| 1394 iterator.Advance(); | 1343 iterator.Advance(); |
| 1395 } | 1344 } |
| 1396 return found; | 1345 return found; |
| 1397 } | 1346 } |
| 1398 | 1347 |
| 1399 | 1348 |
| 1349 // If a range is defined in a deferred block, we can expect all the range |
| 1350 // to only cover positions in deferred blocks. Otherwise, a block on the |
| 1351 // hot path would be dominated by a deferred block, meaning it is unreachable |
| 1352 // without passing through the deferred block, which is contradictory. |
| 1353 // In particular, when such a range contributes a result back on the hot |
| 1354 // path, it will be as one of the inputs of a phi. In that case, the value |
| 1355 // will be transferred via a move in the Gap::END's of the last instruction |
| 1356 // of a deferred block. |
| 1357 bool RegisterAllocationData::RangesDefinedInDeferredStayInDeferred() { |
| 1358 for (const TopLevelLiveRange* range : live_ranges()) { |
| 1359 if (range == nullptr || range->IsEmpty() || |
| 1360 !code() |
| 1361 ->GetInstructionBlock(range->Start().ToInstructionIndex()) |
| 1362 ->IsDeferred()) { |
| 1363 continue; |
| 1364 } |
| 1365 for (const UseInterval* i = range->first_interval(); i != nullptr; |
| 1366 i = i->next()) { |
| 1367 int first = i->FirstInstructionIndex(); |
| 1368 int last = i->LastInstructionIndex(); |
| 1369 for (int instr = first; instr <= last;) { |
| 1370 const InstructionBlock* block = code()->GetInstructionBlock(instr); |
| 1371 if (!block->IsDeferred()) return false; |
| 1372 instr = block->last_instruction_index() + 1; |
| 1373 } |
| 1374 } |
| 1375 } |
| 1376 return true; |
| 1377 } |
| 1378 |
| 1379 |
| 1400 SpillRange* RegisterAllocationData::AssignSpillRangeToLiveRange( | 1380 SpillRange* RegisterAllocationData::AssignSpillRangeToLiveRange( |
| 1401 TopLevelLiveRange* range) { | 1381 TopLevelLiveRange* range) { |
| 1402 DCHECK(!range->HasSpillOperand()); | 1382 DCHECK(!range->HasSpillOperand()); |
| 1403 | 1383 |
| 1404 SpillRange* spill_range = range->GetAllocatedSpillRange(); | 1384 SpillRange* spill_range = range->GetAllocatedSpillRange(); |
| 1405 if (spill_range == nullptr) { | 1385 if (spill_range == nullptr) { |
| 1406 DCHECK(!range->IsSplinter()); | 1386 DCHECK(!range->IsSplinter()); |
| 1407 spill_range = new (allocation_zone()) SpillRange(range, allocation_zone()); | 1387 spill_range = new (allocation_zone()) SpillRange(range, allocation_zone()); |
| 1408 } | 1388 } |
| 1409 range->set_spill_type(TopLevelLiveRange::SpillType::kSpillRange); | 1389 range->set_spill_type(TopLevelLiveRange::SpillType::kSpillRange); |
| (...skipping 1547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2957 SpillSlotLocator::SpillSlotLocator(RegisterAllocationData* data) | 2937 SpillSlotLocator::SpillSlotLocator(RegisterAllocationData* data) |
| 2958 : data_(data) {} | 2938 : data_(data) {} |
| 2959 | 2939 |
| 2960 | 2940 |
| 2961 void SpillSlotLocator::LocateSpillSlots() { | 2941 void SpillSlotLocator::LocateSpillSlots() { |
| 2962 auto code = data()->code(); | 2942 auto code = data()->code(); |
| 2963 for (TopLevelLiveRange* range : data()->live_ranges()) { | 2943 for (TopLevelLiveRange* range : data()->live_ranges()) { |
| 2964 if (range == nullptr || range->IsEmpty()) continue; | 2944 if (range == nullptr || range->IsEmpty()) continue; |
| 2965 // We care only about ranges which spill in the frame. | 2945 // We care only about ranges which spill in the frame. |
| 2966 if (!range->HasSpillRange()) continue; | 2946 if (!range->HasSpillRange()) continue; |
| 2967 range->MarkSpilledInDeferredBlock(data()->code()); | |
| 2968 if (range->IsSpilledOnlyInDeferredBlocks()) { | 2947 if (range->IsSpilledOnlyInDeferredBlocks()) { |
| 2969 for (LiveRange* child = range; child != nullptr; child = child->next()) { | 2948 for (LiveRange* child = range; child != nullptr; child = child->next()) { |
| 2970 if (child->spilled()) { | 2949 if (child->spilled()) { |
| 2971 code->GetInstructionBlock(child->Start().ToInstructionIndex()) | 2950 code->GetInstructionBlock(child->Start().ToInstructionIndex()) |
| 2972 ->mark_needs_frame(); | 2951 ->mark_needs_frame(); |
| 2973 } | 2952 } |
| 2974 } | 2953 } |
| 2975 } else { | 2954 } else { |
| 2976 auto spills = range->spill_move_insertion_locations(); | 2955 auto spills = range->spill_move_insertion_locations(); |
| 2977 DCHECK_NOT_NULL(spills); | 2956 DCHECK_NOT_NULL(spills); |
| (...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3466 auto eliminate = moves->PrepareInsertAfter(move); | 3445 auto eliminate = moves->PrepareInsertAfter(move); |
| 3467 to_insert.push_back(move); | 3446 to_insert.push_back(move); |
| 3468 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 3447 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
| 3469 } | 3448 } |
| 3470 } | 3449 } |
| 3471 | 3450 |
| 3472 | 3451 |
| 3473 } // namespace compiler | 3452 } // namespace compiler |
| 3474 } // namespace internal | 3453 } // namespace internal |
| 3475 } // namespace v8 | 3454 } // namespace v8 |
| OLD | NEW |