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 |