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/compiler/linkage.h" | 5 #include "src/compiler/linkage.h" |
6 #include "src/compiler/register-allocator.h" | 6 #include "src/compiler/register-allocator.h" |
7 #include "src/string-stream.h" | 7 #include "src/string-stream.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 | 527 |
528 RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, | 528 RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, |
529 Zone* zone, Frame* frame, | 529 Zone* zone, Frame* frame, |
530 InstructionSequence* code, | 530 InstructionSequence* code, |
531 const char* debug_name) | 531 const char* debug_name) |
532 : local_zone_(zone), | 532 : local_zone_(zone), |
533 frame_(frame), | 533 frame_(frame), |
534 code_(code), | 534 code_(code), |
535 debug_name_(debug_name), | 535 debug_name_(debug_name), |
536 config_(config), | 536 config_(config), |
| 537 phi_map_(PhiMap::key_compare(), PhiMap::allocator_type(local_zone())), |
537 live_in_sets_(code->InstructionBlockCount(), local_zone()), | 538 live_in_sets_(code->InstructionBlockCount(), local_zone()), |
538 live_ranges_(code->VirtualRegisterCount() * 2, local_zone()), | 539 live_ranges_(code->VirtualRegisterCount() * 2, local_zone()), |
539 fixed_live_ranges_(this->config()->num_general_registers(), NULL, | 540 fixed_live_ranges_(this->config()->num_general_registers(), NULL, |
540 local_zone()), | 541 local_zone()), |
541 fixed_double_live_ranges_(this->config()->num_double_registers(), NULL, | 542 fixed_double_live_ranges_(this->config()->num_double_registers(), NULL, |
542 local_zone()), | 543 local_zone()), |
543 unhandled_live_ranges_(code->VirtualRegisterCount() * 2, local_zone()), | 544 unhandled_live_ranges_(code->VirtualRegisterCount() * 2, local_zone()), |
544 active_live_ranges_(8, local_zone()), | 545 active_live_ranges_(8, local_zone()), |
545 inactive_live_ranges_(8, local_zone()), | 546 inactive_live_ranges_(8, local_zone()), |
546 reusable_slots_(8, local_zone()), | 547 reusable_slots_(8, local_zone()), |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
918 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | 919 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { |
919 DCHECK(FLAG_turbo_reuse_spill_slots); | 920 DCHECK(FLAG_turbo_reuse_spill_slots); |
920 int spill_id = spill_ranges_.length(); | 921 int spill_id = spill_ranges_.length(); |
921 SpillRange* spill_range = | 922 SpillRange* spill_range = |
922 new (local_zone()) SpillRange(range, spill_id, local_zone()); | 923 new (local_zone()) SpillRange(range, spill_id, local_zone()); |
923 spill_ranges_.Add(spill_range, local_zone()); | 924 spill_ranges_.Add(spill_range, local_zone()); |
924 return spill_range; | 925 return spill_range; |
925 } | 926 } |
926 | 927 |
927 | 928 |
| 929 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
| 930 DCHECK(FLAG_turbo_reuse_spill_slots); |
| 931 DCHECK(!range->HasAllocatedSpillOperand()); |
| 932 if (range->IsChild() || !range->is_phi()) return false; |
| 933 |
| 934 auto lookup = phi_map_.find(range->id()); |
| 935 DCHECK(lookup != phi_map_.end()); |
| 936 auto phi = lookup->second.phi; |
| 937 auto block = lookup->second.block; |
| 938 // Count the number of spilled operands. |
| 939 size_t spilled_count = 0; |
| 940 LiveRange* first_op = nullptr; |
| 941 for (size_t i = 0; i < phi->operands().size(); i++) { |
| 942 int op = phi->operands()[i]; |
| 943 LiveRange* op_range = LiveRangeFor(op); |
| 944 if (op_range->GetSpillRange() == nullptr) continue; |
| 945 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); |
| 946 LifetimePosition pred_end = |
| 947 LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); |
| 948 while (op_range != nullptr && !op_range->CanCover(pred_end)) { |
| 949 op_range = op_range->next(); |
| 950 } |
| 951 if (op_range != nullptr && op_range->IsSpilled()) { |
| 952 spilled_count++; |
| 953 if (first_op == nullptr) { |
| 954 first_op = op_range->TopLevel(); |
| 955 } |
| 956 } |
| 957 } |
| 958 |
| 959 // Only continue if more than half of the operands are spilled. |
| 960 if (spilled_count * 2 <= phi->operands().size()) { |
| 961 return false; |
| 962 } |
| 963 |
| 964 // Try to merge the spilled operands and count the number of merged spilled |
| 965 // operands. |
| 966 DCHECK(first_op != NULL); |
| 967 SpillRange* first_op_spill = first_op->GetSpillRange(); |
| 968 size_t num_merged = 1; |
| 969 for (size_t i = 1; i < phi->operands().size(); i++) { |
| 970 int op = phi->operands()[i]; |
| 971 LiveRange* op_range = LiveRangeFor(op); |
| 972 SpillRange* op_spill = op_range->GetSpillRange(); |
| 973 if (op_spill != NULL) { |
| 974 if (op_spill->id() == first_op_spill->id() || |
| 975 first_op_spill->TryMerge(op_spill, local_zone())) { |
| 976 num_merged++; |
| 977 } |
| 978 } |
| 979 } |
| 980 |
| 981 // Only continue if enough operands could be merged to the |
| 982 // same spill slot. |
| 983 if (num_merged * 2 <= phi->operands().size() || |
| 984 AreUseIntervalsIntersecting(first_op_spill->interval(), |
| 985 range->first_interval())) { |
| 986 return false; |
| 987 } |
| 988 |
| 989 // If the range does not need register soon, spill it to the merged |
| 990 // spill range. |
| 991 LifetimePosition next_pos = range->Start(); |
| 992 if (code()->IsGapAt(next_pos.InstructionIndex())) { |
| 993 next_pos = next_pos.NextInstruction(); |
| 994 } |
| 995 UsePosition* pos = range->NextUsePositionRegisterIsBeneficial(next_pos); |
| 996 if (pos == NULL) { |
| 997 SpillRange* spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); |
| 998 CHECK(first_op_spill->TryMerge(spill_range, local_zone())); |
| 999 Spill(range); |
| 1000 return true; |
| 1001 } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) { |
| 1002 SpillRange* spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); |
| 1003 CHECK(first_op_spill->TryMerge(spill_range, local_zone())); |
| 1004 SpillBetween(range, range->Start(), pos->pos()); |
| 1005 if (!AllocationOk()) return false; |
| 1006 DCHECK(UnhandledIsSorted()); |
| 1007 return true; |
| 1008 } |
| 1009 return false; |
| 1010 } |
| 1011 |
| 1012 |
928 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { | 1013 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { |
929 int start = block->first_instruction_index(); | 1014 int start = block->first_instruction_index(); |
930 int end = block->last_instruction_index(); | 1015 int end = block->last_instruction_index(); |
931 DCHECK_NE(-1, start); | 1016 DCHECK_NE(-1, start); |
932 for (int i = start; i <= end; ++i) { | 1017 for (int i = start; i <= end; ++i) { |
933 if (code()->IsGapAt(i)) { | 1018 if (code()->IsGapAt(i)) { |
934 Instruction* instr = NULL; | 1019 Instruction* instr = NULL; |
935 Instruction* prev_instr = NULL; | 1020 Instruction* prev_instr = NULL; |
936 if (i < end) instr = InstructionAt(i + 1); | 1021 if (i < end) instr = InstructionAt(i + 1); |
937 if (i > start) prev_instr = InstructionAt(i - 1); | 1022 if (i > start) prev_instr = InstructionAt(i - 1); |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1250 Use(block_start_position, curr_position.InstructionEnd(), temp, NULL); | 1335 Use(block_start_position, curr_position.InstructionEnd(), temp, NULL); |
1251 Define(curr_position, temp, NULL); | 1336 Define(curr_position, temp, NULL); |
1252 } | 1337 } |
1253 } | 1338 } |
1254 } | 1339 } |
1255 } | 1340 } |
1256 | 1341 |
1257 | 1342 |
1258 void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { | 1343 void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { |
1259 for (auto phi : block->phis()) { | 1344 for (auto phi : block->phis()) { |
| 1345 if (FLAG_turbo_reuse_spill_slots) { |
| 1346 auto res = phi_map_.insert( |
| 1347 std::make_pair(phi->virtual_register(), PhiMapValue(phi, block))); |
| 1348 DCHECK(res.second); |
| 1349 USE(res); |
| 1350 } |
1260 auto output = phi->output(); | 1351 auto output = phi->output(); |
1261 int phi_vreg = phi->virtual_register(); | 1352 int phi_vreg = phi->virtual_register(); |
1262 if (!FLAG_turbo_delay_ssa_decon) { | 1353 if (!FLAG_turbo_delay_ssa_decon) { |
1263 for (size_t i = 0; i < phi->operands().size(); ++i) { | 1354 for (size_t i = 0; i < phi->operands().size(); ++i) { |
1264 InstructionBlock* cur_block = | 1355 InstructionBlock* cur_block = |
1265 code()->InstructionBlockAt(block->predecessors()[i]); | 1356 code()->InstructionBlockAt(block->predecessors()[i]); |
1266 // The gap move must be added without any special processing as in | 1357 // The gap move must be added without any special processing as in |
1267 // the AddConstraintsGapMove. | 1358 // the AddConstraintsGapMove. |
1268 code()->AddGapMove(cur_block->last_instruction_index() - 1, | 1359 code()->AddGapMove(cur_block->last_instruction_index() - 1, |
1269 phi->inputs()[i], output); | 1360 phi->inputs()[i], output); |
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1860 current->Start().NextInstruction().Value()) { | 1951 current->Start().NextInstruction().Value()) { |
1861 // Do not spill live range eagerly if use position that can benefit from | 1952 // Do not spill live range eagerly if use position that can benefit from |
1862 // the register is too close to the start of live range. | 1953 // the register is too close to the start of live range. |
1863 SpillBetween(current, current->Start(), pos->pos()); | 1954 SpillBetween(current, current->Start(), pos->pos()); |
1864 if (!AllocationOk()) return; | 1955 if (!AllocationOk()) return; |
1865 DCHECK(UnhandledIsSorted()); | 1956 DCHECK(UnhandledIsSorted()); |
1866 continue; | 1957 continue; |
1867 } | 1958 } |
1868 } | 1959 } |
1869 | 1960 |
| 1961 if (FLAG_turbo_reuse_spill_slots) { |
| 1962 if (TryReuseSpillForPhi(current)) { |
| 1963 continue; |
| 1964 } |
| 1965 if (!AllocationOk()) return; |
| 1966 } |
| 1967 |
1870 for (int i = 0; i < active_live_ranges_.length(); ++i) { | 1968 for (int i = 0; i < active_live_ranges_.length(); ++i) { |
1871 LiveRange* cur_active = active_live_ranges_.at(i); | 1969 LiveRange* cur_active = active_live_ranges_.at(i); |
1872 if (cur_active->End().Value() <= position.Value()) { | 1970 if (cur_active->End().Value() <= position.Value()) { |
1873 ActiveToHandled(cur_active); | 1971 ActiveToHandled(cur_active); |
1874 --i; // The live range was removed from the list of active live ranges. | 1972 --i; // The live range was removed from the list of active live ranges. |
1875 } else if (!cur_active->Covers(position)) { | 1973 } else if (!cur_active->Covers(position)) { |
1876 ActiveToInactive(cur_active); | 1974 ActiveToInactive(cur_active); |
1877 --i; // The live range was removed from the list of active live ranges. | 1975 --i; // The live range was removed from the list of active live ranges. |
1878 } | 1976 } |
1879 } | 1977 } |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2476 } else { | 2574 } else { |
2477 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2575 DCHECK(range->Kind() == GENERAL_REGISTERS); |
2478 assigned_registers_->Add(reg); | 2576 assigned_registers_->Add(reg); |
2479 } | 2577 } |
2480 range->set_assigned_register(reg, code_zone()); | 2578 range->set_assigned_register(reg, code_zone()); |
2481 } | 2579 } |
2482 | 2580 |
2483 } // namespace compiler | 2581 } // namespace compiler |
2484 } // namespace internal | 2582 } // namespace internal |
2485 } // namespace v8 | 2583 } // namespace v8 |
OLD | NEW |