Chromium Code Reviews| 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(InstructionSequence* code) { | |
| 324 DCHECK(!IsChild()); | |
| 325 if (!FLAG_turbo_greedy_regalloc) return false; | |
| 326 if (IsEmpty() || HasNoSpillType()) return false; | |
| 327 | |
| 328 InstructionBlock* the_block = nullptr; | |
| 329 int new_spill_start = -1; | |
| 330 for (const LiveRange* child = this; child != nullptr; child = child->next()) { | |
| 331 // If we have slot uses in a subrange, bail out, because we need the value | |
| 332 // on the stack before that use. | |
| 333 if (!child->spilled()) { | |
| 334 if (child->NextStackPosition(child->Start()) != nullptr) return false; | |
| 335 continue; | |
| 336 } | |
| 337 | |
| 338 // Top range shouldn't be spilled, if it is, it brings no value to not | |
| 339 // spill at definition. | |
| 340 if (child == this) return false; | |
| 341 | |
| 342 int first_instr = child->Start().ToInstructionIndex(); | |
| 343 if (new_spill_start < 0) new_spill_start = first_instr; | |
| 344 | |
| 345 // If the range starts at instruction end, the first instruction index is | |
| 346 // the next one. | |
| 347 if (!child->Start().IsGapPosition() && !child->Start().IsStart()) { | |
| 348 ++first_instr; | |
| 349 } | |
| 350 | |
| 351 // We should have an instruction at least. | |
| 352 if (child->End() <= | |
| 353 LifetimePosition::GapFromInstructionIndex(first_instr).NextStart()) | |
| 354 continue; | |
| 355 | |
| 356 InstructionBlock* start_block = code->GetInstructionBlock(first_instr); | |
| 357 // TODO(mtrofin): we could handle a spilled range that ends in a different | |
| 358 // block, and then that block having another spill. | |
| 359 if (the_block != nullptr && the_block != start_block) return false; | |
| 360 if (!start_block->IsDeferred()) return false; | |
| 361 the_block = start_block; | |
| 362 } | |
| 363 if (the_block != nullptr) { | |
| 364 spill_start_index_ = new_spill_start; | |
| 365 spilled_in_deferred_block_ = true; | |
| 366 return true; | |
| 367 } | |
| 368 | |
| 369 return false; | |
| 370 } | |
| 371 | |
| 372 | |
| 322 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, | 373 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, |
| 323 const InstructionOperand& op, | 374 const InstructionOperand& op, |
| 324 bool might_be_duplicated) { | 375 bool might_be_duplicated) { |
| 325 DCHECK_IMPLIES(op.IsConstant(), spills_at_definition_ == nullptr); | 376 DCHECK_IMPLIES(op.IsConstant(), spills_at_definition_ == nullptr); |
| 326 DCHECK(!IsChild()); | 377 DCHECK(!IsChild()); |
| 327 auto zone = sequence->zone(); | 378 auto zone = sequence->zone(); |
| 379 | |
| 380 // If this top level range has a child spilled in a deferred block, we use | |
| 381 // the range and control flow connection mechanism instead. | |
| 382 if (TryCommitSpillInDeferredBlock(sequence)) return; | |
| 383 | |
| 328 for (auto to_spill = spills_at_definition_; to_spill != nullptr; | 384 for (auto to_spill = spills_at_definition_; to_spill != nullptr; |
| 329 to_spill = to_spill->next) { | 385 to_spill = to_spill->next) { |
| 330 auto instr = sequence->InstructionAt(to_spill->gap_index); | 386 auto instr = sequence->InstructionAt(to_spill->gap_index); |
| 331 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); | 387 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); |
| 332 // Skip insertion if it's possible that the move exists already as a | 388 // Skip insertion if it's possible that the move exists already as a |
| 333 // constraint move from a fixed output register to a slot. | 389 // constraint move from a fixed output register to a slot. |
| 334 if (might_be_duplicated) { | 390 if (might_be_duplicated) { |
| 335 bool found = false; | 391 bool found = false; |
| 336 for (auto move_op : *move) { | 392 for (auto move_op : *move) { |
| 337 if (move_op->IsEliminated()) continue; | 393 if (move_op->IsEliminated()) continue; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 409 | 465 |
| 410 UsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) const { | 466 UsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) const { |
| 411 UsePosition* pos = NextUsePosition(start); | 467 UsePosition* pos = NextUsePosition(start); |
| 412 while (pos != nullptr && pos->type() != UsePositionType::kRequiresRegister) { | 468 while (pos != nullptr && pos->type() != UsePositionType::kRequiresRegister) { |
| 413 pos = pos->next(); | 469 pos = pos->next(); |
| 414 } | 470 } |
| 415 return pos; | 471 return pos; |
| 416 } | 472 } |
| 417 | 473 |
| 418 | 474 |
| 475 UsePosition* LiveRange::NextStackPosition(LifetimePosition start) const { | |
|
Benedikt Meurer
2015/07/28 04:57:17
Nit: I'd use NextSlotPosition as name for consiste
| |
| 476 for (UsePosition* pos = NextUsePosition(start); pos != nullptr; | |
| 477 pos = pos->next()) { | |
| 478 if (pos->type() != UsePositionType::kRequiresSlot) continue; | |
| 479 return pos; | |
| 480 } | |
| 481 return nullptr; | |
| 482 } | |
| 483 | |
| 484 | |
| 419 bool LiveRange::CanBeSpilled(LifetimePosition pos) const { | 485 bool LiveRange::CanBeSpilled(LifetimePosition pos) const { |
| 420 // We cannot spill a live range that has a use requiring a register | 486 // We cannot spill a live range that has a use requiring a register |
| 421 // at the current or the immediate next position. | 487 // at the current or the immediate next position. |
| 422 auto use_pos = NextRegisterPosition(pos); | 488 auto use_pos = NextRegisterPosition(pos); |
| 423 if (use_pos == nullptr) return true; | 489 if (use_pos == nullptr) return true; |
| 424 return use_pos->pos() > pos.NextStart().End(); | 490 return use_pos->pos() > pos.NextStart().End(); |
| 425 } | 491 } |
| 426 | 492 |
| 427 | 493 |
| 428 InstructionOperand LiveRange::GetAssignedOperand() const { | 494 InstructionOperand LiveRange::GetAssignedOperand() const { |
| (...skipping 2344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2773 if (CanEagerlyResolveControlFlow(block)) continue; | 2839 if (CanEagerlyResolveControlFlow(block)) continue; |
| 2774 auto live = live_in_sets[block->rpo_number().ToInt()]; | 2840 auto live = live_in_sets[block->rpo_number().ToInt()]; |
| 2775 BitVector::Iterator iterator(live); | 2841 BitVector::Iterator iterator(live); |
| 2776 while (!iterator.Done()) { | 2842 while (!iterator.Done()) { |
| 2777 auto* array = finder.ArrayFor(iterator.Current()); | 2843 auto* array = finder.ArrayFor(iterator.Current()); |
| 2778 for (auto pred : block->predecessors()) { | 2844 for (auto pred : block->predecessors()) { |
| 2779 FindResult result; | 2845 FindResult result; |
| 2780 const auto* pred_block = code()->InstructionBlockAt(pred); | 2846 const auto* pred_block = code()->InstructionBlockAt(pred); |
| 2781 array->Find(block, pred_block, &result); | 2847 array->Find(block, pred_block, &result); |
| 2782 if (result.cur_cover_ == result.pred_cover_ || | 2848 if (result.cur_cover_ == result.pred_cover_ || |
| 2783 result.cur_cover_->spilled()) | 2849 (!result.cur_cover_->TopLevel()->IsSpilledInSingleDeferredBlock() && |
| 2850 result.cur_cover_->spilled())) | |
| 2784 continue; | 2851 continue; |
| 2785 auto pred_op = result.pred_cover_->GetAssignedOperand(); | 2852 auto pred_op = result.pred_cover_->GetAssignedOperand(); |
| 2786 auto cur_op = result.cur_cover_->GetAssignedOperand(); | 2853 auto cur_op = result.cur_cover_->GetAssignedOperand(); |
| 2787 if (pred_op.Equals(cur_op)) continue; | 2854 if (pred_op.Equals(cur_op)) continue; |
| 2788 ResolveControlFlow(block, cur_op, pred_block, pred_op); | 2855 ResolveControlFlow(block, cur_op, pred_block, pred_op); |
| 2789 } | 2856 } |
| 2790 iterator.Advance(); | 2857 iterator.Advance(); |
| 2791 } | 2858 } |
| 2792 } | 2859 } |
| 2793 } | 2860 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 2812 position = Instruction::END; | 2879 position = Instruction::END; |
| 2813 } | 2880 } |
| 2814 data()->AddGapMove(gap_index, position, pred_op, cur_op); | 2881 data()->AddGapMove(gap_index, position, pred_op, cur_op); |
| 2815 } | 2882 } |
| 2816 | 2883 |
| 2817 | 2884 |
| 2818 void LiveRangeConnector::ConnectRanges(Zone* local_zone) { | 2885 void LiveRangeConnector::ConnectRanges(Zone* local_zone) { |
| 2819 DelayedInsertionMap delayed_insertion_map(local_zone); | 2886 DelayedInsertionMap delayed_insertion_map(local_zone); |
| 2820 for (auto first_range : data()->live_ranges()) { | 2887 for (auto first_range : data()->live_ranges()) { |
| 2821 if (first_range == nullptr || first_range->IsChild()) continue; | 2888 if (first_range == nullptr || first_range->IsChild()) continue; |
| 2889 bool connect_spilled = first_range->IsSpilledInSingleDeferredBlock(); | |
| 2822 for (auto second_range = first_range->next(); second_range != nullptr; | 2890 for (auto second_range = first_range->next(); second_range != nullptr; |
| 2823 first_range = second_range, second_range = second_range->next()) { | 2891 first_range = second_range, second_range = second_range->next()) { |
| 2824 auto pos = second_range->Start(); | 2892 auto pos = second_range->Start(); |
| 2825 // Add gap move if the two live ranges touch and there is no block | 2893 // Add gap move if the two live ranges touch and there is no block |
| 2826 // boundary. | 2894 // boundary. |
| 2827 if (second_range->spilled()) continue; | 2895 if (!connect_spilled && second_range->spilled()) continue; |
| 2828 if (first_range->End() != pos) continue; | 2896 if (first_range->End() != pos) continue; |
| 2829 if (data()->IsBlockBoundary(pos) && | 2897 if (data()->IsBlockBoundary(pos) && |
| 2830 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) { | 2898 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) { |
| 2831 continue; | 2899 continue; |
| 2832 } | 2900 } |
| 2833 auto prev_operand = first_range->GetAssignedOperand(); | 2901 auto prev_operand = first_range->GetAssignedOperand(); |
| 2834 auto cur_operand = second_range->GetAssignedOperand(); | 2902 auto cur_operand = second_range->GetAssignedOperand(); |
| 2835 if (prev_operand.Equals(cur_operand)) continue; | 2903 if (prev_operand.Equals(cur_operand)) continue; |
| 2836 bool delay_insertion = false; | 2904 bool delay_insertion = false; |
| 2837 Instruction::GapPosition gap_pos; | 2905 Instruction::GapPosition gap_pos; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2884 auto eliminate = moves->PrepareInsertAfter(move); | 2952 auto eliminate = moves->PrepareInsertAfter(move); |
| 2885 to_insert.push_back(move); | 2953 to_insert.push_back(move); |
| 2886 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 2954 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
| 2887 } | 2955 } |
| 2888 } | 2956 } |
| 2889 | 2957 |
| 2890 | 2958 |
| 2891 } // namespace compiler | 2959 } // namespace compiler |
| 2892 } // namespace internal | 2960 } // namespace internal |
| 2893 } // namespace v8 | 2961 } // namespace v8 |
| OLD | NEW |