11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/compiler/backend/register-allocator.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <iomanip> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include "src/base/iterator.h" 101cb0ef41Sopenharmony_ci#include "src/base/small-vector.h" 111cb0ef41Sopenharmony_ci#include "src/base/vector.h" 121cb0ef41Sopenharmony_ci#include "src/codegen/assembler-inl.h" 131cb0ef41Sopenharmony_ci#include "src/codegen/tick-counter.h" 141cb0ef41Sopenharmony_ci#include "src/compiler/backend/spill-placer.h" 151cb0ef41Sopenharmony_ci#include "src/compiler/linkage.h" 161cb0ef41Sopenharmony_ci#include "src/strings/string-stream.h" 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_cinamespace v8 { 191cb0ef41Sopenharmony_cinamespace internal { 201cb0ef41Sopenharmony_cinamespace compiler { 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci#define TRACE_COND(cond, ...) \ 231cb0ef41Sopenharmony_ci do { \ 241cb0ef41Sopenharmony_ci if (cond) PrintF(__VA_ARGS__); \ 251cb0ef41Sopenharmony_ci } while (false) 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci#define TRACE(...) TRACE_COND(data()->is_trace_alloc(), __VA_ARGS__) 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_cinamespace { 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_cistatic constexpr int kFloat32Bit = 321cb0ef41Sopenharmony_ci RepresentationBit(MachineRepresentation::kFloat32); 331cb0ef41Sopenharmony_cistatic constexpr int kSimd128Bit = 341cb0ef41Sopenharmony_ci RepresentationBit(MachineRepresentation::kSimd128); 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciconst InstructionBlock* GetContainingLoop(const InstructionSequence* sequence, 381cb0ef41Sopenharmony_ci const InstructionBlock* block) { 391cb0ef41Sopenharmony_ci RpoNumber index = block->loop_header(); 401cb0ef41Sopenharmony_ci if (!index.IsValid()) return nullptr; 411cb0ef41Sopenharmony_ci return sequence->InstructionBlockAt(index); 421cb0ef41Sopenharmony_ci} 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ciconst InstructionBlock* GetInstructionBlock(const InstructionSequence* code, 451cb0ef41Sopenharmony_ci LifetimePosition pos) { 461cb0ef41Sopenharmony_ci return code->GetInstructionBlock(pos.ToInstructionIndex()); 471cb0ef41Sopenharmony_ci} 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ciInstruction* GetLastInstruction(InstructionSequence* code, 501cb0ef41Sopenharmony_ci const InstructionBlock* block) { 511cb0ef41Sopenharmony_ci return code->InstructionAt(block->last_instruction_index()); 521cb0ef41Sopenharmony_ci} 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci} // namespace 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_civoid LiveRangeBoundArray::Initialize(Zone* zone, TopLevelLiveRange* range) { 571cb0ef41Sopenharmony_ci size_t max_child_count = range->GetMaxChildCount(); 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci start_ = zone->NewArray<LiveRangeBound>(max_child_count); 601cb0ef41Sopenharmony_ci length_ = 0; 611cb0ef41Sopenharmony_ci LiveRangeBound* curr = start_; 621cb0ef41Sopenharmony_ci // The primary loop in ResolveControlFlow is not responsible for inserting 631cb0ef41Sopenharmony_ci // connecting moves for spilled ranges. 641cb0ef41Sopenharmony_ci for (LiveRange* i = range; i != nullptr; i = i->next(), ++curr, ++length_) { 651cb0ef41Sopenharmony_ci new (curr) LiveRangeBound(i, i->spilled()); 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci} 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ciLiveRangeBound* LiveRangeBoundArray::Find( 701cb0ef41Sopenharmony_ci const LifetimePosition position) const { 711cb0ef41Sopenharmony_ci size_t left_index = 0; 721cb0ef41Sopenharmony_ci size_t right_index = length_; 731cb0ef41Sopenharmony_ci while (true) { 741cb0ef41Sopenharmony_ci size_t current_index = left_index + (right_index - left_index) / 2; 751cb0ef41Sopenharmony_ci DCHECK(right_index > current_index); 761cb0ef41Sopenharmony_ci LiveRangeBound* bound = &start_[current_index]; 771cb0ef41Sopenharmony_ci if (bound->start_ <= position) { 781cb0ef41Sopenharmony_ci if (position < bound->end_) return bound; 791cb0ef41Sopenharmony_ci DCHECK(left_index < current_index); 801cb0ef41Sopenharmony_ci left_index = current_index; 811cb0ef41Sopenharmony_ci } else { 821cb0ef41Sopenharmony_ci right_index = current_index; 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci} 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ciLiveRangeBound* LiveRangeBoundArray::FindPred(const InstructionBlock* pred) { 881cb0ef41Sopenharmony_ci LifetimePosition pred_end = LifetimePosition::InstructionFromInstructionIndex( 891cb0ef41Sopenharmony_ci pred->last_instruction_index()); 901cb0ef41Sopenharmony_ci return Find(pred_end); 911cb0ef41Sopenharmony_ci} 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ciLiveRangeBound* LiveRangeBoundArray::FindSucc(const InstructionBlock* succ) { 941cb0ef41Sopenharmony_ci LifetimePosition succ_start = LifetimePosition::GapFromInstructionIndex( 951cb0ef41Sopenharmony_ci succ->first_instruction_index()); 961cb0ef41Sopenharmony_ci return Find(succ_start); 971cb0ef41Sopenharmony_ci} 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_cibool LiveRangeBoundArray::FindConnectableSubranges( 1001cb0ef41Sopenharmony_ci const InstructionBlock* block, const InstructionBlock* pred, 1011cb0ef41Sopenharmony_ci FindResult* result) const { 1021cb0ef41Sopenharmony_ci LifetimePosition pred_end = LifetimePosition::InstructionFromInstructionIndex( 1031cb0ef41Sopenharmony_ci pred->last_instruction_index()); 1041cb0ef41Sopenharmony_ci LiveRangeBound* bound = Find(pred_end); 1051cb0ef41Sopenharmony_ci result->pred_cover_ = bound->range_; 1061cb0ef41Sopenharmony_ci LifetimePosition cur_start = LifetimePosition::GapFromInstructionIndex( 1071cb0ef41Sopenharmony_ci block->first_instruction_index()); 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ci if (bound->CanCover(cur_start)) { 1101cb0ef41Sopenharmony_ci // Both blocks are covered by the same range, so there is nothing to 1111cb0ef41Sopenharmony_ci // connect. 1121cb0ef41Sopenharmony_ci return false; 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci bound = Find(cur_start); 1151cb0ef41Sopenharmony_ci if (bound->skip_) { 1161cb0ef41Sopenharmony_ci return false; 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci result->cur_cover_ = bound->range_; 1191cb0ef41Sopenharmony_ci DCHECK(result->pred_cover_ != nullptr && result->cur_cover_ != nullptr); 1201cb0ef41Sopenharmony_ci return (result->cur_cover_ != result->pred_cover_); 1211cb0ef41Sopenharmony_ci} 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ciLiveRangeFinder::LiveRangeFinder(const TopTierRegisterAllocationData* data, 1241cb0ef41Sopenharmony_ci Zone* zone) 1251cb0ef41Sopenharmony_ci : data_(data), 1261cb0ef41Sopenharmony_ci bounds_length_(static_cast<int>(data_->live_ranges().size())), 1271cb0ef41Sopenharmony_ci bounds_(zone->NewArray<LiveRangeBoundArray>(bounds_length_)), 1281cb0ef41Sopenharmony_ci zone_(zone) { 1291cb0ef41Sopenharmony_ci for (int i = 0; i < bounds_length_; ++i) { 1301cb0ef41Sopenharmony_ci new (&bounds_[i]) LiveRangeBoundArray(); 1311cb0ef41Sopenharmony_ci } 1321cb0ef41Sopenharmony_ci} 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ciLiveRangeBoundArray* LiveRangeFinder::ArrayFor(int operand_index) { 1351cb0ef41Sopenharmony_ci DCHECK(operand_index < bounds_length_); 1361cb0ef41Sopenharmony_ci TopLevelLiveRange* range = data_->live_ranges()[operand_index]; 1371cb0ef41Sopenharmony_ci DCHECK(range != nullptr && !range->IsEmpty()); 1381cb0ef41Sopenharmony_ci DCHECK_EQ(range->vreg(), operand_index); 1391cb0ef41Sopenharmony_ci LiveRangeBoundArray* array = &bounds_[operand_index]; 1401cb0ef41Sopenharmony_ci if (array->ShouldInitialize()) { 1411cb0ef41Sopenharmony_ci array->Initialize(zone_, range); 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci return array; 1441cb0ef41Sopenharmony_ci} 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ciusing DelayedInsertionMapKey = std::pair<ParallelMove*, InstructionOperand>; 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_cistruct DelayedInsertionMapCompare { 1491cb0ef41Sopenharmony_ci bool operator()(const DelayedInsertionMapKey& a, 1501cb0ef41Sopenharmony_ci const DelayedInsertionMapKey& b) const { 1511cb0ef41Sopenharmony_ci if (a.first == b.first) { 1521cb0ef41Sopenharmony_ci return a.second.Compare(b.second); 1531cb0ef41Sopenharmony_ci } 1541cb0ef41Sopenharmony_ci return a.first < b.first; 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci}; 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ciusing DelayedInsertionMap = ZoneMap<DelayedInsertionMapKey, InstructionOperand, 1591cb0ef41Sopenharmony_ci DelayedInsertionMapCompare>; 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ciUsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, 1621cb0ef41Sopenharmony_ci void* hint, UsePositionHintType hint_type) 1631cb0ef41Sopenharmony_ci : operand_(operand), hint_(hint), next_(nullptr), pos_(pos), flags_(0) { 1641cb0ef41Sopenharmony_ci DCHECK_IMPLIES(hint == nullptr, hint_type == UsePositionHintType::kNone); 1651cb0ef41Sopenharmony_ci bool register_beneficial = true; 1661cb0ef41Sopenharmony_ci UsePositionType type = UsePositionType::kRegisterOrSlot; 1671cb0ef41Sopenharmony_ci if (operand_ != nullptr && operand_->IsUnallocated()) { 1681cb0ef41Sopenharmony_ci const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); 1691cb0ef41Sopenharmony_ci if (unalloc->HasRegisterPolicy()) { 1701cb0ef41Sopenharmony_ci type = UsePositionType::kRequiresRegister; 1711cb0ef41Sopenharmony_ci } else if (unalloc->HasSlotPolicy()) { 1721cb0ef41Sopenharmony_ci type = UsePositionType::kRequiresSlot; 1731cb0ef41Sopenharmony_ci register_beneficial = false; 1741cb0ef41Sopenharmony_ci } else if (unalloc->HasRegisterOrSlotOrConstantPolicy()) { 1751cb0ef41Sopenharmony_ci type = UsePositionType::kRegisterOrSlotOrConstant; 1761cb0ef41Sopenharmony_ci register_beneficial = false; 1771cb0ef41Sopenharmony_ci } else { 1781cb0ef41Sopenharmony_ci register_beneficial = !unalloc->HasRegisterOrSlotPolicy(); 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci flags_ = TypeField::encode(type) | HintTypeField::encode(hint_type) | 1821cb0ef41Sopenharmony_ci RegisterBeneficialField::encode(register_beneficial) | 1831cb0ef41Sopenharmony_ci AssignedRegisterField::encode(kUnassignedRegister); 1841cb0ef41Sopenharmony_ci DCHECK(pos_.IsValid()); 1851cb0ef41Sopenharmony_ci} 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_cibool UsePosition::HasHint() const { 1881cb0ef41Sopenharmony_ci int hint_register; 1891cb0ef41Sopenharmony_ci return HintRegister(&hint_register); 1901cb0ef41Sopenharmony_ci} 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_cibool UsePosition::HintRegister(int* register_code) const { 1931cb0ef41Sopenharmony_ci if (hint_ == nullptr) return false; 1941cb0ef41Sopenharmony_ci switch (HintTypeField::decode(flags_)) { 1951cb0ef41Sopenharmony_ci case UsePositionHintType::kNone: 1961cb0ef41Sopenharmony_ci case UsePositionHintType::kUnresolved: 1971cb0ef41Sopenharmony_ci return false; 1981cb0ef41Sopenharmony_ci case UsePositionHintType::kUsePos: { 1991cb0ef41Sopenharmony_ci UsePosition* use_pos = reinterpret_cast<UsePosition*>(hint_); 2001cb0ef41Sopenharmony_ci int assigned_register = AssignedRegisterField::decode(use_pos->flags_); 2011cb0ef41Sopenharmony_ci if (assigned_register == kUnassignedRegister) return false; 2021cb0ef41Sopenharmony_ci *register_code = assigned_register; 2031cb0ef41Sopenharmony_ci return true; 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci case UsePositionHintType::kOperand: { 2061cb0ef41Sopenharmony_ci InstructionOperand* operand = 2071cb0ef41Sopenharmony_ci reinterpret_cast<InstructionOperand*>(hint_); 2081cb0ef41Sopenharmony_ci *register_code = LocationOperand::cast(operand)->register_code(); 2091cb0ef41Sopenharmony_ci return true; 2101cb0ef41Sopenharmony_ci } 2111cb0ef41Sopenharmony_ci case UsePositionHintType::kPhi: { 2121cb0ef41Sopenharmony_ci TopTierRegisterAllocationData::PhiMapValue* phi = 2131cb0ef41Sopenharmony_ci reinterpret_cast<TopTierRegisterAllocationData::PhiMapValue*>(hint_); 2141cb0ef41Sopenharmony_ci int assigned_register = phi->assigned_register(); 2151cb0ef41Sopenharmony_ci if (assigned_register == kUnassignedRegister) return false; 2161cb0ef41Sopenharmony_ci *register_code = assigned_register; 2171cb0ef41Sopenharmony_ci return true; 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci UNREACHABLE(); 2211cb0ef41Sopenharmony_ci} 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ciUsePositionHintType UsePosition::HintTypeForOperand( 2241cb0ef41Sopenharmony_ci const InstructionOperand& op) { 2251cb0ef41Sopenharmony_ci switch (op.kind()) { 2261cb0ef41Sopenharmony_ci case InstructionOperand::CONSTANT: 2271cb0ef41Sopenharmony_ci case InstructionOperand::IMMEDIATE: 2281cb0ef41Sopenharmony_ci return UsePositionHintType::kNone; 2291cb0ef41Sopenharmony_ci case InstructionOperand::UNALLOCATED: 2301cb0ef41Sopenharmony_ci return UsePositionHintType::kUnresolved; 2311cb0ef41Sopenharmony_ci case InstructionOperand::ALLOCATED: 2321cb0ef41Sopenharmony_ci if (op.IsRegister() || op.IsFPRegister()) { 2331cb0ef41Sopenharmony_ci return UsePositionHintType::kOperand; 2341cb0ef41Sopenharmony_ci } else { 2351cb0ef41Sopenharmony_ci DCHECK(op.IsStackSlot() || op.IsFPStackSlot()); 2361cb0ef41Sopenharmony_ci return UsePositionHintType::kNone; 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci case InstructionOperand::PENDING: 2391cb0ef41Sopenharmony_ci case InstructionOperand::INVALID: 2401cb0ef41Sopenharmony_ci break; 2411cb0ef41Sopenharmony_ci } 2421cb0ef41Sopenharmony_ci UNREACHABLE(); 2431cb0ef41Sopenharmony_ci} 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_civoid UsePosition::SetHint(UsePosition* use_pos) { 2461cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(use_pos); 2471cb0ef41Sopenharmony_ci hint_ = use_pos; 2481cb0ef41Sopenharmony_ci flags_ = HintTypeField::update(flags_, UsePositionHintType::kUsePos); 2491cb0ef41Sopenharmony_ci} 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_civoid UsePosition::ResolveHint(UsePosition* use_pos) { 2521cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(use_pos); 2531cb0ef41Sopenharmony_ci if (HintTypeField::decode(flags_) != UsePositionHintType::kUnresolved) return; 2541cb0ef41Sopenharmony_ci hint_ = use_pos; 2551cb0ef41Sopenharmony_ci flags_ = HintTypeField::update(flags_, UsePositionHintType::kUsePos); 2561cb0ef41Sopenharmony_ci} 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_civoid UsePosition::set_type(UsePositionType type, bool register_beneficial) { 2591cb0ef41Sopenharmony_ci DCHECK_IMPLIES(type == UsePositionType::kRequiresSlot, !register_beneficial); 2601cb0ef41Sopenharmony_ci DCHECK_EQ(kUnassignedRegister, AssignedRegisterField::decode(flags_)); 2611cb0ef41Sopenharmony_ci flags_ = TypeField::encode(type) | 2621cb0ef41Sopenharmony_ci RegisterBeneficialField::encode(register_beneficial) | 2631cb0ef41Sopenharmony_ci HintTypeField::encode(HintTypeField::decode(flags_)) | 2641cb0ef41Sopenharmony_ci AssignedRegisterField::encode(kUnassignedRegister); 2651cb0ef41Sopenharmony_ci} 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ciUseInterval* UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { 2681cb0ef41Sopenharmony_ci DCHECK(Contains(pos) && pos != start()); 2691cb0ef41Sopenharmony_ci UseInterval* after = zone->New<UseInterval>(pos, end_); 2701cb0ef41Sopenharmony_ci after->next_ = next_; 2711cb0ef41Sopenharmony_ci next_ = nullptr; 2721cb0ef41Sopenharmony_ci end_ = pos; 2731cb0ef41Sopenharmony_ci return after; 2741cb0ef41Sopenharmony_ci} 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_civoid LifetimePosition::Print() const { StdoutStream{} << *this << std::endl; } 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os, const LifetimePosition pos) { 2791cb0ef41Sopenharmony_ci os << '@' << pos.ToInstructionIndex(); 2801cb0ef41Sopenharmony_ci if (pos.IsGapPosition()) { 2811cb0ef41Sopenharmony_ci os << 'g'; 2821cb0ef41Sopenharmony_ci } else { 2831cb0ef41Sopenharmony_ci os << 'i'; 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci if (pos.IsStart()) { 2861cb0ef41Sopenharmony_ci os << 's'; 2871cb0ef41Sopenharmony_ci } else { 2881cb0ef41Sopenharmony_ci os << 'e'; 2891cb0ef41Sopenharmony_ci } 2901cb0ef41Sopenharmony_ci return os; 2911cb0ef41Sopenharmony_ci} 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ciLiveRange::LiveRange(int relative_id, MachineRepresentation rep, 2941cb0ef41Sopenharmony_ci TopLevelLiveRange* top_level) 2951cb0ef41Sopenharmony_ci : relative_id_(relative_id), 2961cb0ef41Sopenharmony_ci bits_(0), 2971cb0ef41Sopenharmony_ci last_interval_(nullptr), 2981cb0ef41Sopenharmony_ci first_interval_(nullptr), 2991cb0ef41Sopenharmony_ci first_pos_(nullptr), 3001cb0ef41Sopenharmony_ci top_level_(top_level), 3011cb0ef41Sopenharmony_ci next_(nullptr), 3021cb0ef41Sopenharmony_ci current_interval_(nullptr), 3031cb0ef41Sopenharmony_ci last_processed_use_(nullptr), 3041cb0ef41Sopenharmony_ci current_hint_position_(nullptr) { 3051cb0ef41Sopenharmony_ci DCHECK(AllocatedOperand::IsSupportedRepresentation(rep)); 3061cb0ef41Sopenharmony_ci bits_ = AssignedRegisterField::encode(kUnassignedRegister) | 3071cb0ef41Sopenharmony_ci RepresentationField::encode(rep) | 3081cb0ef41Sopenharmony_ci ControlFlowRegisterHint::encode(kUnassignedRegister); 3091cb0ef41Sopenharmony_ci} 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_civoid LiveRange::VerifyPositions() const { 3121cb0ef41Sopenharmony_ci // Walk the positions, verifying that each is in an interval. 3131cb0ef41Sopenharmony_ci UseInterval* interval = first_interval_; 3141cb0ef41Sopenharmony_ci for (UsePosition* pos = first_pos_; pos != nullptr; pos = pos->next()) { 3151cb0ef41Sopenharmony_ci CHECK(Start() <= pos->pos()); 3161cb0ef41Sopenharmony_ci CHECK(pos->pos() <= End()); 3171cb0ef41Sopenharmony_ci CHECK_NOT_NULL(interval); 3181cb0ef41Sopenharmony_ci while (!interval->Contains(pos->pos()) && interval->end() != pos->pos()) { 3191cb0ef41Sopenharmony_ci interval = interval->next(); 3201cb0ef41Sopenharmony_ci CHECK_NOT_NULL(interval); 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci } 3231cb0ef41Sopenharmony_ci} 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_civoid LiveRange::VerifyIntervals() const { 3261cb0ef41Sopenharmony_ci DCHECK(first_interval()->start() == Start()); 3271cb0ef41Sopenharmony_ci LifetimePosition last_end = first_interval()->end(); 3281cb0ef41Sopenharmony_ci for (UseInterval* interval = first_interval()->next(); interval != nullptr; 3291cb0ef41Sopenharmony_ci interval = interval->next()) { 3301cb0ef41Sopenharmony_ci DCHECK(last_end <= interval->start()); 3311cb0ef41Sopenharmony_ci last_end = interval->end(); 3321cb0ef41Sopenharmony_ci } 3331cb0ef41Sopenharmony_ci DCHECK(last_end == End()); 3341cb0ef41Sopenharmony_ci} 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_civoid LiveRange::set_assigned_register(int reg) { 3371cb0ef41Sopenharmony_ci DCHECK(!HasRegisterAssigned() && !spilled()); 3381cb0ef41Sopenharmony_ci bits_ = AssignedRegisterField::update(bits_, reg); 3391cb0ef41Sopenharmony_ci} 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_civoid LiveRange::UnsetAssignedRegister() { 3421cb0ef41Sopenharmony_ci DCHECK(HasRegisterAssigned() && !spilled()); 3431cb0ef41Sopenharmony_ci bits_ = AssignedRegisterField::update(bits_, kUnassignedRegister); 3441cb0ef41Sopenharmony_ci} 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_civoid LiveRange::AttachToNext() { 3471cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(next_); 3481cb0ef41Sopenharmony_ci DCHECK_NE(TopLevel()->last_child_covers_, next_); 3491cb0ef41Sopenharmony_ci last_interval_->set_next(next_->first_interval()); 3501cb0ef41Sopenharmony_ci next_->first_interval_ = nullptr; 3511cb0ef41Sopenharmony_ci last_interval_ = next_->last_interval_; 3521cb0ef41Sopenharmony_ci next_->last_interval_ = nullptr; 3531cb0ef41Sopenharmony_ci if (first_pos() == nullptr) { 3541cb0ef41Sopenharmony_ci first_pos_ = next_->first_pos(); 3551cb0ef41Sopenharmony_ci } else { 3561cb0ef41Sopenharmony_ci UsePosition* ptr = first_pos_; 3571cb0ef41Sopenharmony_ci while (ptr->next() != nullptr) { 3581cb0ef41Sopenharmony_ci ptr = ptr->next(); 3591cb0ef41Sopenharmony_ci } 3601cb0ef41Sopenharmony_ci ptr->set_next(next_->first_pos()); 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci next_->first_pos_ = nullptr; 3631cb0ef41Sopenharmony_ci LiveRange* old_next = next_; 3641cb0ef41Sopenharmony_ci next_ = next_->next_; 3651cb0ef41Sopenharmony_ci old_next->next_ = nullptr; 3661cb0ef41Sopenharmony_ci} 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_civoid LiveRange::Unspill() { 3691cb0ef41Sopenharmony_ci DCHECK(spilled()); 3701cb0ef41Sopenharmony_ci set_spilled(false); 3711cb0ef41Sopenharmony_ci bits_ = AssignedRegisterField::update(bits_, kUnassignedRegister); 3721cb0ef41Sopenharmony_ci} 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_civoid LiveRange::Spill() { 3751cb0ef41Sopenharmony_ci DCHECK(!spilled()); 3761cb0ef41Sopenharmony_ci DCHECK(!TopLevel()->HasNoSpillType()); 3771cb0ef41Sopenharmony_ci set_spilled(true); 3781cb0ef41Sopenharmony_ci bits_ = AssignedRegisterField::update(bits_, kUnassignedRegister); 3791cb0ef41Sopenharmony_ci} 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ciRegisterKind LiveRange::kind() const { 3821cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kIndependent && 3831cb0ef41Sopenharmony_ci IsSimd128(representation())) { 3841cb0ef41Sopenharmony_ci return RegisterKind::kSimd128; 3851cb0ef41Sopenharmony_ci } else { 3861cb0ef41Sopenharmony_ci return IsFloatingPoint(representation()) ? RegisterKind::kDouble 3871cb0ef41Sopenharmony_ci : RegisterKind::kGeneral; 3881cb0ef41Sopenharmony_ci } 3891cb0ef41Sopenharmony_ci} 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_ciUsePosition* LiveRange::FirstHintPosition(int* register_index) { 3921cb0ef41Sopenharmony_ci if (!first_pos_) return nullptr; 3931cb0ef41Sopenharmony_ci if (current_hint_position_) { 3941cb0ef41Sopenharmony_ci if (current_hint_position_->pos() < first_pos_->pos()) { 3951cb0ef41Sopenharmony_ci current_hint_position_ = first_pos_; 3961cb0ef41Sopenharmony_ci } 3971cb0ef41Sopenharmony_ci if (current_hint_position_->pos() > End()) { 3981cb0ef41Sopenharmony_ci current_hint_position_ = nullptr; 3991cb0ef41Sopenharmony_ci } 4001cb0ef41Sopenharmony_ci } 4011cb0ef41Sopenharmony_ci bool needs_revisit = false; 4021cb0ef41Sopenharmony_ci UsePosition* pos = current_hint_position_; 4031cb0ef41Sopenharmony_ci for (; pos != nullptr; pos = pos->next()) { 4041cb0ef41Sopenharmony_ci if (pos->HintRegister(register_index)) { 4051cb0ef41Sopenharmony_ci break; 4061cb0ef41Sopenharmony_ci } 4071cb0ef41Sopenharmony_ci // Phi and use position hints can be assigned during allocation which 4081cb0ef41Sopenharmony_ci // would invalidate the cached hint position. Make sure we revisit them. 4091cb0ef41Sopenharmony_ci needs_revisit = needs_revisit || 4101cb0ef41Sopenharmony_ci pos->hint_type() == UsePositionHintType::kPhi || 4111cb0ef41Sopenharmony_ci pos->hint_type() == UsePositionHintType::kUsePos; 4121cb0ef41Sopenharmony_ci } 4131cb0ef41Sopenharmony_ci if (!needs_revisit) { 4141cb0ef41Sopenharmony_ci current_hint_position_ = pos; 4151cb0ef41Sopenharmony_ci } 4161cb0ef41Sopenharmony_ci#ifdef DEBUG 4171cb0ef41Sopenharmony_ci UsePosition* pos_check = first_pos_; 4181cb0ef41Sopenharmony_ci for (; pos_check != nullptr; pos_check = pos_check->next()) { 4191cb0ef41Sopenharmony_ci if (pos_check->HasHint()) { 4201cb0ef41Sopenharmony_ci break; 4211cb0ef41Sopenharmony_ci } 4221cb0ef41Sopenharmony_ci } 4231cb0ef41Sopenharmony_ci CHECK_EQ(pos, pos_check); 4241cb0ef41Sopenharmony_ci#endif 4251cb0ef41Sopenharmony_ci return pos; 4261cb0ef41Sopenharmony_ci} 4271cb0ef41Sopenharmony_ci 4281cb0ef41Sopenharmony_ciUsePosition* LiveRange::NextUsePosition(LifetimePosition start) const { 4291cb0ef41Sopenharmony_ci UsePosition* use_pos = last_processed_use_; 4301cb0ef41Sopenharmony_ci if (use_pos == nullptr || use_pos->pos() > start) { 4311cb0ef41Sopenharmony_ci use_pos = first_pos(); 4321cb0ef41Sopenharmony_ci } 4331cb0ef41Sopenharmony_ci while (use_pos != nullptr && use_pos->pos() < start) { 4341cb0ef41Sopenharmony_ci use_pos = use_pos->next(); 4351cb0ef41Sopenharmony_ci } 4361cb0ef41Sopenharmony_ci last_processed_use_ = use_pos; 4371cb0ef41Sopenharmony_ci return use_pos; 4381cb0ef41Sopenharmony_ci} 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ciUsePosition* LiveRange::NextUsePositionRegisterIsBeneficial( 4411cb0ef41Sopenharmony_ci LifetimePosition start) const { 4421cb0ef41Sopenharmony_ci UsePosition* pos = NextUsePosition(start); 4431cb0ef41Sopenharmony_ci while (pos != nullptr && !pos->RegisterIsBeneficial()) { 4441cb0ef41Sopenharmony_ci pos = pos->next(); 4451cb0ef41Sopenharmony_ci } 4461cb0ef41Sopenharmony_ci return pos; 4471cb0ef41Sopenharmony_ci} 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ciLifetimePosition LiveRange::NextLifetimePositionRegisterIsBeneficial( 4501cb0ef41Sopenharmony_ci const LifetimePosition& start) const { 4511cb0ef41Sopenharmony_ci UsePosition* next_use = NextUsePositionRegisterIsBeneficial(start); 4521cb0ef41Sopenharmony_ci if (next_use == nullptr) return End(); 4531cb0ef41Sopenharmony_ci return next_use->pos(); 4541cb0ef41Sopenharmony_ci} 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ciUsePosition* LiveRange::PreviousUsePositionRegisterIsBeneficial( 4571cb0ef41Sopenharmony_ci LifetimePosition start) const { 4581cb0ef41Sopenharmony_ci UsePosition* pos = first_pos(); 4591cb0ef41Sopenharmony_ci UsePosition* prev = nullptr; 4601cb0ef41Sopenharmony_ci while (pos != nullptr && pos->pos() < start) { 4611cb0ef41Sopenharmony_ci if (pos->RegisterIsBeneficial()) prev = pos; 4621cb0ef41Sopenharmony_ci pos = pos->next(); 4631cb0ef41Sopenharmony_ci } 4641cb0ef41Sopenharmony_ci return prev; 4651cb0ef41Sopenharmony_ci} 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_ciUsePosition* LiveRange::NextUsePositionSpillDetrimental( 4681cb0ef41Sopenharmony_ci LifetimePosition start) const { 4691cb0ef41Sopenharmony_ci UsePosition* pos = NextUsePosition(start); 4701cb0ef41Sopenharmony_ci while (pos != nullptr && pos->type() != UsePositionType::kRequiresRegister && 4711cb0ef41Sopenharmony_ci !pos->SpillDetrimental()) { 4721cb0ef41Sopenharmony_ci pos = pos->next(); 4731cb0ef41Sopenharmony_ci } 4741cb0ef41Sopenharmony_ci return pos; 4751cb0ef41Sopenharmony_ci} 4761cb0ef41Sopenharmony_ci 4771cb0ef41Sopenharmony_ciUsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) const { 4781cb0ef41Sopenharmony_ci UsePosition* pos = NextUsePosition(start); 4791cb0ef41Sopenharmony_ci while (pos != nullptr && pos->type() != UsePositionType::kRequiresRegister) { 4801cb0ef41Sopenharmony_ci pos = pos->next(); 4811cb0ef41Sopenharmony_ci } 4821cb0ef41Sopenharmony_ci return pos; 4831cb0ef41Sopenharmony_ci} 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_cibool LiveRange::CanBeSpilled(LifetimePosition pos) const { 4861cb0ef41Sopenharmony_ci // We cannot spill a live range that has a use requiring a register 4871cb0ef41Sopenharmony_ci // at the current or the immediate next position. 4881cb0ef41Sopenharmony_ci UsePosition* use_pos = NextRegisterPosition(pos); 4891cb0ef41Sopenharmony_ci if (use_pos == nullptr) return true; 4901cb0ef41Sopenharmony_ci return use_pos->pos() > pos.NextStart().End(); 4911cb0ef41Sopenharmony_ci} 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_cibool LiveRange::IsTopLevel() const { return top_level_ == this; } 4941cb0ef41Sopenharmony_ci 4951cb0ef41Sopenharmony_ciInstructionOperand LiveRange::GetAssignedOperand() const { 4961cb0ef41Sopenharmony_ci DCHECK(!IsEmpty()); 4971cb0ef41Sopenharmony_ci if (HasRegisterAssigned()) { 4981cb0ef41Sopenharmony_ci DCHECK(!spilled()); 4991cb0ef41Sopenharmony_ci return AllocatedOperand(LocationOperand::REGISTER, representation(), 5001cb0ef41Sopenharmony_ci assigned_register()); 5011cb0ef41Sopenharmony_ci } 5021cb0ef41Sopenharmony_ci DCHECK(spilled()); 5031cb0ef41Sopenharmony_ci DCHECK(!HasRegisterAssigned()); 5041cb0ef41Sopenharmony_ci if (TopLevel()->HasSpillOperand()) { 5051cb0ef41Sopenharmony_ci InstructionOperand* op = TopLevel()->GetSpillOperand(); 5061cb0ef41Sopenharmony_ci DCHECK(!op->IsUnallocated()); 5071cb0ef41Sopenharmony_ci return *op; 5081cb0ef41Sopenharmony_ci } 5091cb0ef41Sopenharmony_ci return TopLevel()->GetSpillRangeOperand(); 5101cb0ef41Sopenharmony_ci} 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ciUseInterval* LiveRange::FirstSearchIntervalForPosition( 5131cb0ef41Sopenharmony_ci LifetimePosition position) const { 5141cb0ef41Sopenharmony_ci if (current_interval_ == nullptr) return first_interval_; 5151cb0ef41Sopenharmony_ci if (current_interval_->start() > position) { 5161cb0ef41Sopenharmony_ci current_interval_ = nullptr; 5171cb0ef41Sopenharmony_ci return first_interval_; 5181cb0ef41Sopenharmony_ci } 5191cb0ef41Sopenharmony_ci return current_interval_; 5201cb0ef41Sopenharmony_ci} 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_civoid LiveRange::AdvanceLastProcessedMarker( 5231cb0ef41Sopenharmony_ci UseInterval* to_start_of, LifetimePosition but_not_past) const { 5241cb0ef41Sopenharmony_ci if (to_start_of == nullptr) return; 5251cb0ef41Sopenharmony_ci if (to_start_of->start() > but_not_past) return; 5261cb0ef41Sopenharmony_ci LifetimePosition start = current_interval_ == nullptr 5271cb0ef41Sopenharmony_ci ? LifetimePosition::Invalid() 5281cb0ef41Sopenharmony_ci : current_interval_->start(); 5291cb0ef41Sopenharmony_ci if (to_start_of->start() > start) { 5301cb0ef41Sopenharmony_ci current_interval_ = to_start_of; 5311cb0ef41Sopenharmony_ci } 5321cb0ef41Sopenharmony_ci} 5331cb0ef41Sopenharmony_ci 5341cb0ef41Sopenharmony_ciLiveRange* LiveRange::SplitAt(LifetimePosition position, Zone* zone) { 5351cb0ef41Sopenharmony_ci int new_id = TopLevel()->GetNextChildId(); 5361cb0ef41Sopenharmony_ci LiveRange* child = zone->New<LiveRange>(new_id, representation(), TopLevel()); 5371cb0ef41Sopenharmony_ci child->set_bundle(bundle_); 5381cb0ef41Sopenharmony_ci // If we split, we do so because we're about to switch registers or move 5391cb0ef41Sopenharmony_ci // to/from a slot, so there's no value in connecting hints. 5401cb0ef41Sopenharmony_ci DetachAt(position, child, zone, DoNotConnectHints); 5411cb0ef41Sopenharmony_ci 5421cb0ef41Sopenharmony_ci child->top_level_ = TopLevel(); 5431cb0ef41Sopenharmony_ci child->next_ = next_; 5441cb0ef41Sopenharmony_ci next_ = child; 5451cb0ef41Sopenharmony_ci return child; 5461cb0ef41Sopenharmony_ci} 5471cb0ef41Sopenharmony_ci 5481cb0ef41Sopenharmony_ciUsePosition* LiveRange::DetachAt(LifetimePosition position, LiveRange* result, 5491cb0ef41Sopenharmony_ci Zone* zone, 5501cb0ef41Sopenharmony_ci HintConnectionOption connect_hints) { 5511cb0ef41Sopenharmony_ci DCHECK(Start() < position); 5521cb0ef41Sopenharmony_ci DCHECK(End() > position); 5531cb0ef41Sopenharmony_ci DCHECK(result->IsEmpty()); 5541cb0ef41Sopenharmony_ci // Find the last interval that ends before the position. If the 5551cb0ef41Sopenharmony_ci // position is contained in one of the intervals in the chain, we 5561cb0ef41Sopenharmony_ci // split that interval and use the first part. 5571cb0ef41Sopenharmony_ci UseInterval* current = FirstSearchIntervalForPosition(position); 5581cb0ef41Sopenharmony_ci 5591cb0ef41Sopenharmony_ci // If the split position coincides with the beginning of a use interval 5601cb0ef41Sopenharmony_ci // we need to split use positons in a special way. 5611cb0ef41Sopenharmony_ci bool split_at_start = false; 5621cb0ef41Sopenharmony_ci 5631cb0ef41Sopenharmony_ci if (current->start() == position) { 5641cb0ef41Sopenharmony_ci // When splitting at start we need to locate the previous use interval. 5651cb0ef41Sopenharmony_ci current = first_interval_; 5661cb0ef41Sopenharmony_ci } 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ci UseInterval* after = nullptr; 5691cb0ef41Sopenharmony_ci while (current != nullptr) { 5701cb0ef41Sopenharmony_ci if (current->Contains(position)) { 5711cb0ef41Sopenharmony_ci after = current->SplitAt(position, zone); 5721cb0ef41Sopenharmony_ci break; 5731cb0ef41Sopenharmony_ci } 5741cb0ef41Sopenharmony_ci UseInterval* next = current->next(); 5751cb0ef41Sopenharmony_ci if (next->start() >= position) { 5761cb0ef41Sopenharmony_ci split_at_start = (next->start() == position); 5771cb0ef41Sopenharmony_ci after = next; 5781cb0ef41Sopenharmony_ci current->set_next(nullptr); 5791cb0ef41Sopenharmony_ci break; 5801cb0ef41Sopenharmony_ci } 5811cb0ef41Sopenharmony_ci current = next; 5821cb0ef41Sopenharmony_ci } 5831cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(after); 5841cb0ef41Sopenharmony_ci 5851cb0ef41Sopenharmony_ci // Partition original use intervals to the two live ranges. 5861cb0ef41Sopenharmony_ci UseInterval* before = current; 5871cb0ef41Sopenharmony_ci result->last_interval_ = 5881cb0ef41Sopenharmony_ci (last_interval_ == before) 5891cb0ef41Sopenharmony_ci ? after // Only interval in the range after split. 5901cb0ef41Sopenharmony_ci : last_interval_; // Last interval of the original range. 5911cb0ef41Sopenharmony_ci result->first_interval_ = after; 5921cb0ef41Sopenharmony_ci last_interval_ = before; 5931cb0ef41Sopenharmony_ci 5941cb0ef41Sopenharmony_ci // Find the last use position before the split and the first use 5951cb0ef41Sopenharmony_ci // position after it. 5961cb0ef41Sopenharmony_ci UsePosition* use_after = first_pos(); 5971cb0ef41Sopenharmony_ci UsePosition* use_before = nullptr; 5981cb0ef41Sopenharmony_ci if (split_at_start) { 5991cb0ef41Sopenharmony_ci // The split position coincides with the beginning of a use interval (the 6001cb0ef41Sopenharmony_ci // end of a lifetime hole). Use at this position should be attributed to 6011cb0ef41Sopenharmony_ci // the split child because split child owns use interval covering it. 6021cb0ef41Sopenharmony_ci while (use_after != nullptr && use_after->pos() < position) { 6031cb0ef41Sopenharmony_ci use_before = use_after; 6041cb0ef41Sopenharmony_ci use_after = use_after->next(); 6051cb0ef41Sopenharmony_ci } 6061cb0ef41Sopenharmony_ci } else { 6071cb0ef41Sopenharmony_ci while (use_after != nullptr && use_after->pos() <= position) { 6081cb0ef41Sopenharmony_ci use_before = use_after; 6091cb0ef41Sopenharmony_ci use_after = use_after->next(); 6101cb0ef41Sopenharmony_ci } 6111cb0ef41Sopenharmony_ci } 6121cb0ef41Sopenharmony_ci 6131cb0ef41Sopenharmony_ci // Partition original use positions to the two live ranges. 6141cb0ef41Sopenharmony_ci if (use_before != nullptr) { 6151cb0ef41Sopenharmony_ci use_before->set_next(nullptr); 6161cb0ef41Sopenharmony_ci } else { 6171cb0ef41Sopenharmony_ci first_pos_ = nullptr; 6181cb0ef41Sopenharmony_ci } 6191cb0ef41Sopenharmony_ci result->first_pos_ = use_after; 6201cb0ef41Sopenharmony_ci result->current_hint_position_ = current_hint_position_; 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ci // Discard cached iteration state. It might be pointing 6231cb0ef41Sopenharmony_ci // to the use that no longer belongs to this live range. 6241cb0ef41Sopenharmony_ci last_processed_use_ = nullptr; 6251cb0ef41Sopenharmony_ci current_interval_ = nullptr; 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_ci if (connect_hints == ConnectHints && use_before != nullptr && 6281cb0ef41Sopenharmony_ci use_after != nullptr) { 6291cb0ef41Sopenharmony_ci use_after->SetHint(use_before); 6301cb0ef41Sopenharmony_ci result->current_hint_position_ = use_after; 6311cb0ef41Sopenharmony_ci } 6321cb0ef41Sopenharmony_ci#ifdef DEBUG 6331cb0ef41Sopenharmony_ci VerifyChildStructure(); 6341cb0ef41Sopenharmony_ci result->VerifyChildStructure(); 6351cb0ef41Sopenharmony_ci#endif 6361cb0ef41Sopenharmony_ci return use_before; 6371cb0ef41Sopenharmony_ci} 6381cb0ef41Sopenharmony_ci 6391cb0ef41Sopenharmony_civoid LiveRange::UpdateParentForAllChildren(TopLevelLiveRange* new_top_level) { 6401cb0ef41Sopenharmony_ci LiveRange* child = this; 6411cb0ef41Sopenharmony_ci for (; child != nullptr; child = child->next()) { 6421cb0ef41Sopenharmony_ci child->top_level_ = new_top_level; 6431cb0ef41Sopenharmony_ci } 6441cb0ef41Sopenharmony_ci} 6451cb0ef41Sopenharmony_ci 6461cb0ef41Sopenharmony_civoid LiveRange::ConvertUsesToOperand(const InstructionOperand& op, 6471cb0ef41Sopenharmony_ci const InstructionOperand& spill_op) { 6481cb0ef41Sopenharmony_ci for (UsePosition* pos = first_pos(); pos != nullptr; pos = pos->next()) { 6491cb0ef41Sopenharmony_ci DCHECK(Start() <= pos->pos() && pos->pos() <= End()); 6501cb0ef41Sopenharmony_ci if (!pos->HasOperand()) continue; 6511cb0ef41Sopenharmony_ci switch (pos->type()) { 6521cb0ef41Sopenharmony_ci case UsePositionType::kRequiresSlot: 6531cb0ef41Sopenharmony_ci DCHECK(spill_op.IsStackSlot() || spill_op.IsFPStackSlot()); 6541cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(pos->operand(), &spill_op); 6551cb0ef41Sopenharmony_ci break; 6561cb0ef41Sopenharmony_ci case UsePositionType::kRequiresRegister: 6571cb0ef41Sopenharmony_ci DCHECK(op.IsRegister() || op.IsFPRegister()); 6581cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 6591cb0ef41Sopenharmony_ci case UsePositionType::kRegisterOrSlot: 6601cb0ef41Sopenharmony_ci case UsePositionType::kRegisterOrSlotOrConstant: 6611cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(pos->operand(), &op); 6621cb0ef41Sopenharmony_ci break; 6631cb0ef41Sopenharmony_ci } 6641cb0ef41Sopenharmony_ci } 6651cb0ef41Sopenharmony_ci} 6661cb0ef41Sopenharmony_ci 6671cb0ef41Sopenharmony_ci// This implements an ordering on live ranges so that they are ordered by their 6681cb0ef41Sopenharmony_ci// start positions. This is needed for the correctness of the register 6691cb0ef41Sopenharmony_ci// allocation algorithm. If two live ranges start at the same offset then there 6701cb0ef41Sopenharmony_ci// is a tie breaker based on where the value is first used. This part of the 6711cb0ef41Sopenharmony_ci// ordering is merely a heuristic. 6721cb0ef41Sopenharmony_cibool LiveRange::ShouldBeAllocatedBefore(const LiveRange* other) const { 6731cb0ef41Sopenharmony_ci LifetimePosition start = Start(); 6741cb0ef41Sopenharmony_ci LifetimePosition other_start = other->Start(); 6751cb0ef41Sopenharmony_ci if (start == other_start) { 6761cb0ef41Sopenharmony_ci // Prefer register that has a controlflow hint to make sure it gets 6771cb0ef41Sopenharmony_ci // allocated first. This allows the control flow aware alloction to 6781cb0ef41Sopenharmony_ci // just put ranges back into the queue without other ranges interfering. 6791cb0ef41Sopenharmony_ci if (controlflow_hint() < other->controlflow_hint()) { 6801cb0ef41Sopenharmony_ci return true; 6811cb0ef41Sopenharmony_ci } 6821cb0ef41Sopenharmony_ci // The other has a smaller hint. 6831cb0ef41Sopenharmony_ci if (controlflow_hint() > other->controlflow_hint()) { 6841cb0ef41Sopenharmony_ci return false; 6851cb0ef41Sopenharmony_ci } 6861cb0ef41Sopenharmony_ci // Both have the same hint or no hint at all. Use first use position. 6871cb0ef41Sopenharmony_ci UsePosition* pos = first_pos(); 6881cb0ef41Sopenharmony_ci UsePosition* other_pos = other->first_pos(); 6891cb0ef41Sopenharmony_ci // To make the order total, handle the case where both positions are null. 6901cb0ef41Sopenharmony_ci if (pos == other_pos) return TopLevel()->vreg() < other->TopLevel()->vreg(); 6911cb0ef41Sopenharmony_ci if (pos == nullptr) return false; 6921cb0ef41Sopenharmony_ci if (other_pos == nullptr) return true; 6931cb0ef41Sopenharmony_ci // To make the order total, handle the case where both positions are equal. 6941cb0ef41Sopenharmony_ci if (pos->pos() == other_pos->pos()) 6951cb0ef41Sopenharmony_ci return TopLevel()->vreg() < other->TopLevel()->vreg(); 6961cb0ef41Sopenharmony_ci return pos->pos() < other_pos->pos(); 6971cb0ef41Sopenharmony_ci } 6981cb0ef41Sopenharmony_ci return start < other_start; 6991cb0ef41Sopenharmony_ci} 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_civoid LiveRange::SetUseHints(int register_index) { 7021cb0ef41Sopenharmony_ci for (UsePosition* pos = first_pos(); pos != nullptr; pos = pos->next()) { 7031cb0ef41Sopenharmony_ci if (!pos->HasOperand()) continue; 7041cb0ef41Sopenharmony_ci switch (pos->type()) { 7051cb0ef41Sopenharmony_ci case UsePositionType::kRequiresSlot: 7061cb0ef41Sopenharmony_ci break; 7071cb0ef41Sopenharmony_ci case UsePositionType::kRequiresRegister: 7081cb0ef41Sopenharmony_ci case UsePositionType::kRegisterOrSlot: 7091cb0ef41Sopenharmony_ci case UsePositionType::kRegisterOrSlotOrConstant: 7101cb0ef41Sopenharmony_ci pos->set_assigned_register(register_index); 7111cb0ef41Sopenharmony_ci break; 7121cb0ef41Sopenharmony_ci } 7131cb0ef41Sopenharmony_ci } 7141cb0ef41Sopenharmony_ci} 7151cb0ef41Sopenharmony_ci 7161cb0ef41Sopenharmony_cibool LiveRange::CanCover(LifetimePosition position) const { 7171cb0ef41Sopenharmony_ci if (IsEmpty()) return false; 7181cb0ef41Sopenharmony_ci return Start() <= position && position < End(); 7191cb0ef41Sopenharmony_ci} 7201cb0ef41Sopenharmony_ci 7211cb0ef41Sopenharmony_cibool LiveRange::Covers(LifetimePosition position) const { 7221cb0ef41Sopenharmony_ci if (!CanCover(position)) return false; 7231cb0ef41Sopenharmony_ci UseInterval* start_search = FirstSearchIntervalForPosition(position); 7241cb0ef41Sopenharmony_ci for (UseInterval* interval = start_search; interval != nullptr; 7251cb0ef41Sopenharmony_ci interval = interval->next()) { 7261cb0ef41Sopenharmony_ci DCHECK(interval->next() == nullptr || 7271cb0ef41Sopenharmony_ci interval->next()->start() >= interval->start()); 7281cb0ef41Sopenharmony_ci AdvanceLastProcessedMarker(interval, position); 7291cb0ef41Sopenharmony_ci if (interval->Contains(position)) return true; 7301cb0ef41Sopenharmony_ci if (interval->start() > position) return false; 7311cb0ef41Sopenharmony_ci } 7321cb0ef41Sopenharmony_ci return false; 7331cb0ef41Sopenharmony_ci} 7341cb0ef41Sopenharmony_ci 7351cb0ef41Sopenharmony_ciLifetimePosition LiveRange::NextEndAfter(LifetimePosition position) const { 7361cb0ef41Sopenharmony_ci UseInterval* start_search = FirstSearchIntervalForPosition(position); 7371cb0ef41Sopenharmony_ci while (start_search->end() < position) { 7381cb0ef41Sopenharmony_ci start_search = start_search->next(); 7391cb0ef41Sopenharmony_ci } 7401cb0ef41Sopenharmony_ci return start_search->end(); 7411cb0ef41Sopenharmony_ci} 7421cb0ef41Sopenharmony_ci 7431cb0ef41Sopenharmony_ciLifetimePosition LiveRange::NextStartAfter(LifetimePosition position) { 7441cb0ef41Sopenharmony_ci UseInterval* start_search = FirstSearchIntervalForPosition(position); 7451cb0ef41Sopenharmony_ci while (start_search->start() < position) { 7461cb0ef41Sopenharmony_ci start_search = start_search->next(); 7471cb0ef41Sopenharmony_ci } 7481cb0ef41Sopenharmony_ci next_start_ = start_search->start(); 7491cb0ef41Sopenharmony_ci return next_start_; 7501cb0ef41Sopenharmony_ci} 7511cb0ef41Sopenharmony_ci 7521cb0ef41Sopenharmony_ciLifetimePosition LiveRange::FirstIntersection(LiveRange* other) const { 7531cb0ef41Sopenharmony_ci UseInterval* b = other->first_interval(); 7541cb0ef41Sopenharmony_ci if (b == nullptr) return LifetimePosition::Invalid(); 7551cb0ef41Sopenharmony_ci LifetimePosition advance_last_processed_up_to = b->start(); 7561cb0ef41Sopenharmony_ci UseInterval* a = FirstSearchIntervalForPosition(b->start()); 7571cb0ef41Sopenharmony_ci while (a != nullptr && b != nullptr) { 7581cb0ef41Sopenharmony_ci if (a->start() > other->End()) break; 7591cb0ef41Sopenharmony_ci if (b->start() > End()) break; 7601cb0ef41Sopenharmony_ci LifetimePosition cur_intersection = a->Intersect(b); 7611cb0ef41Sopenharmony_ci if (cur_intersection.IsValid()) { 7621cb0ef41Sopenharmony_ci return cur_intersection; 7631cb0ef41Sopenharmony_ci } 7641cb0ef41Sopenharmony_ci if (a->start() < b->start()) { 7651cb0ef41Sopenharmony_ci a = a->next(); 7661cb0ef41Sopenharmony_ci if (a == nullptr || a->start() > other->End()) break; 7671cb0ef41Sopenharmony_ci AdvanceLastProcessedMarker(a, advance_last_processed_up_to); 7681cb0ef41Sopenharmony_ci } else { 7691cb0ef41Sopenharmony_ci b = b->next(); 7701cb0ef41Sopenharmony_ci } 7711cb0ef41Sopenharmony_ci } 7721cb0ef41Sopenharmony_ci return LifetimePosition::Invalid(); 7731cb0ef41Sopenharmony_ci} 7741cb0ef41Sopenharmony_ci 7751cb0ef41Sopenharmony_civoid LiveRange::Print(const RegisterConfiguration* config, 7761cb0ef41Sopenharmony_ci bool with_children) const { 7771cb0ef41Sopenharmony_ci StdoutStream os; 7781cb0ef41Sopenharmony_ci PrintableLiveRange wrapper; 7791cb0ef41Sopenharmony_ci wrapper.register_configuration_ = config; 7801cb0ef41Sopenharmony_ci for (const LiveRange* i = this; i != nullptr; i = i->next()) { 7811cb0ef41Sopenharmony_ci wrapper.range_ = i; 7821cb0ef41Sopenharmony_ci os << wrapper << std::endl; 7831cb0ef41Sopenharmony_ci if (!with_children) break; 7841cb0ef41Sopenharmony_ci } 7851cb0ef41Sopenharmony_ci} 7861cb0ef41Sopenharmony_ci 7871cb0ef41Sopenharmony_civoid LiveRange::Print(bool with_children) const { 7881cb0ef41Sopenharmony_ci Print(RegisterConfiguration::Default(), with_children); 7891cb0ef41Sopenharmony_ci} 7901cb0ef41Sopenharmony_ci 7911cb0ef41Sopenharmony_cibool LiveRange::RegisterFromBundle(int* hint) const { 7921cb0ef41Sopenharmony_ci if (bundle_ == nullptr || bundle_->reg() == kUnassignedRegister) return false; 7931cb0ef41Sopenharmony_ci *hint = bundle_->reg(); 7941cb0ef41Sopenharmony_ci return true; 7951cb0ef41Sopenharmony_ci} 7961cb0ef41Sopenharmony_ci 7971cb0ef41Sopenharmony_civoid LiveRange::UpdateBundleRegister(int reg) const { 7981cb0ef41Sopenharmony_ci if (bundle_ == nullptr || bundle_->reg() != kUnassignedRegister) return; 7991cb0ef41Sopenharmony_ci bundle_->set_reg(reg); 8001cb0ef41Sopenharmony_ci} 8011cb0ef41Sopenharmony_ci 8021cb0ef41Sopenharmony_cistruct TopLevelLiveRange::SpillMoveInsertionList : ZoneObject { 8031cb0ef41Sopenharmony_ci SpillMoveInsertionList(int gap_index, InstructionOperand* operand, 8041cb0ef41Sopenharmony_ci SpillMoveInsertionList* next) 8051cb0ef41Sopenharmony_ci : gap_index(gap_index), operand(operand), next(next) {} 8061cb0ef41Sopenharmony_ci const int gap_index; 8071cb0ef41Sopenharmony_ci InstructionOperand* const operand; 8081cb0ef41Sopenharmony_ci SpillMoveInsertionList* next; 8091cb0ef41Sopenharmony_ci}; 8101cb0ef41Sopenharmony_ci 8111cb0ef41Sopenharmony_ciTopLevelLiveRange::TopLevelLiveRange(int vreg, MachineRepresentation rep) 8121cb0ef41Sopenharmony_ci : LiveRange(0, rep, this), 8131cb0ef41Sopenharmony_ci vreg_(vreg), 8141cb0ef41Sopenharmony_ci last_child_id_(0), 8151cb0ef41Sopenharmony_ci spill_operand_(nullptr), 8161cb0ef41Sopenharmony_ci spill_move_insertion_locations_(nullptr), 8171cb0ef41Sopenharmony_ci spilled_in_deferred_blocks_(false), 8181cb0ef41Sopenharmony_ci has_preassigned_slot_(false), 8191cb0ef41Sopenharmony_ci spill_start_index_(kMaxInt), 8201cb0ef41Sopenharmony_ci last_pos_(nullptr), 8211cb0ef41Sopenharmony_ci last_child_covers_(this) { 8221cb0ef41Sopenharmony_ci bits_ |= SpillTypeField::encode(SpillType::kNoSpillType); 8231cb0ef41Sopenharmony_ci} 8241cb0ef41Sopenharmony_ci 8251cb0ef41Sopenharmony_civoid TopLevelLiveRange::RecordSpillLocation(Zone* zone, int gap_index, 8261cb0ef41Sopenharmony_ci InstructionOperand* operand) { 8271cb0ef41Sopenharmony_ci DCHECK(HasNoSpillType()); 8281cb0ef41Sopenharmony_ci spill_move_insertion_locations_ = zone->New<SpillMoveInsertionList>( 8291cb0ef41Sopenharmony_ci gap_index, operand, spill_move_insertion_locations_); 8301cb0ef41Sopenharmony_ci} 8311cb0ef41Sopenharmony_ci 8321cb0ef41Sopenharmony_civoid TopLevelLiveRange::CommitSpillMoves(TopTierRegisterAllocationData* data, 8331cb0ef41Sopenharmony_ci const InstructionOperand& op) { 8341cb0ef41Sopenharmony_ci DCHECK_IMPLIES(op.IsConstant(), 8351cb0ef41Sopenharmony_ci GetSpillMoveInsertionLocations(data) == nullptr); 8361cb0ef41Sopenharmony_ci 8371cb0ef41Sopenharmony_ci if (HasGeneralSpillRange()) { 8381cb0ef41Sopenharmony_ci SetLateSpillingSelected(false); 8391cb0ef41Sopenharmony_ci } 8401cb0ef41Sopenharmony_ci 8411cb0ef41Sopenharmony_ci InstructionSequence* sequence = data->code(); 8421cb0ef41Sopenharmony_ci Zone* zone = sequence->zone(); 8431cb0ef41Sopenharmony_ci 8441cb0ef41Sopenharmony_ci for (SpillMoveInsertionList* to_spill = GetSpillMoveInsertionLocations(data); 8451cb0ef41Sopenharmony_ci to_spill != nullptr; to_spill = to_spill->next) { 8461cb0ef41Sopenharmony_ci Instruction* instr = sequence->InstructionAt(to_spill->gap_index); 8471cb0ef41Sopenharmony_ci ParallelMove* move = 8481cb0ef41Sopenharmony_ci instr->GetOrCreateParallelMove(Instruction::START, zone); 8491cb0ef41Sopenharmony_ci move->AddMove(*to_spill->operand, op); 8501cb0ef41Sopenharmony_ci instr->block()->mark_needs_frame(); 8511cb0ef41Sopenharmony_ci } 8521cb0ef41Sopenharmony_ci} 8531cb0ef41Sopenharmony_ci 8541cb0ef41Sopenharmony_civoid TopLevelLiveRange::FilterSpillMoves(TopTierRegisterAllocationData* data, 8551cb0ef41Sopenharmony_ci const InstructionOperand& op) { 8561cb0ef41Sopenharmony_ci DCHECK_IMPLIES(op.IsConstant(), 8571cb0ef41Sopenharmony_ci GetSpillMoveInsertionLocations(data) == nullptr); 8581cb0ef41Sopenharmony_ci bool might_be_duplicated = has_slot_use() || spilled(); 8591cb0ef41Sopenharmony_ci InstructionSequence* sequence = data->code(); 8601cb0ef41Sopenharmony_ci 8611cb0ef41Sopenharmony_ci SpillMoveInsertionList* previous = nullptr; 8621cb0ef41Sopenharmony_ci for (SpillMoveInsertionList* to_spill = GetSpillMoveInsertionLocations(data); 8631cb0ef41Sopenharmony_ci to_spill != nullptr; previous = to_spill, to_spill = to_spill->next) { 8641cb0ef41Sopenharmony_ci Instruction* instr = sequence->InstructionAt(to_spill->gap_index); 8651cb0ef41Sopenharmony_ci ParallelMove* move = instr->GetParallelMove(Instruction::START); 8661cb0ef41Sopenharmony_ci // Skip insertion if it's possible that the move exists already as a 8671cb0ef41Sopenharmony_ci // constraint move from a fixed output register to a slot. 8681cb0ef41Sopenharmony_ci bool found = false; 8691cb0ef41Sopenharmony_ci if (move != nullptr && (might_be_duplicated || has_preassigned_slot())) { 8701cb0ef41Sopenharmony_ci for (MoveOperands* move_op : *move) { 8711cb0ef41Sopenharmony_ci if (move_op->IsEliminated()) continue; 8721cb0ef41Sopenharmony_ci if (move_op->source().Equals(*to_spill->operand) && 8731cb0ef41Sopenharmony_ci move_op->destination().Equals(op)) { 8741cb0ef41Sopenharmony_ci found = true; 8751cb0ef41Sopenharmony_ci if (has_preassigned_slot()) move_op->Eliminate(); 8761cb0ef41Sopenharmony_ci break; 8771cb0ef41Sopenharmony_ci } 8781cb0ef41Sopenharmony_ci } 8791cb0ef41Sopenharmony_ci } 8801cb0ef41Sopenharmony_ci if (found || has_preassigned_slot()) { 8811cb0ef41Sopenharmony_ci // Remove the item from the list. 8821cb0ef41Sopenharmony_ci if (previous == nullptr) { 8831cb0ef41Sopenharmony_ci spill_move_insertion_locations_ = to_spill->next; 8841cb0ef41Sopenharmony_ci } else { 8851cb0ef41Sopenharmony_ci previous->next = to_spill->next; 8861cb0ef41Sopenharmony_ci } 8871cb0ef41Sopenharmony_ci // Even though this location doesn't need a spill instruction, the 8881cb0ef41Sopenharmony_ci // block does require a frame. 8891cb0ef41Sopenharmony_ci instr->block()->mark_needs_frame(); 8901cb0ef41Sopenharmony_ci } 8911cb0ef41Sopenharmony_ci } 8921cb0ef41Sopenharmony_ci} 8931cb0ef41Sopenharmony_ci 8941cb0ef41Sopenharmony_civoid TopLevelLiveRange::SetSpillOperand(InstructionOperand* operand) { 8951cb0ef41Sopenharmony_ci DCHECK(HasNoSpillType()); 8961cb0ef41Sopenharmony_ci DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); 8971cb0ef41Sopenharmony_ci set_spill_type(SpillType::kSpillOperand); 8981cb0ef41Sopenharmony_ci spill_operand_ = operand; 8991cb0ef41Sopenharmony_ci} 9001cb0ef41Sopenharmony_ci 9011cb0ef41Sopenharmony_civoid TopLevelLiveRange::SetSpillRange(SpillRange* spill_range) { 9021cb0ef41Sopenharmony_ci DCHECK(!HasSpillOperand()); 9031cb0ef41Sopenharmony_ci DCHECK(spill_range); 9041cb0ef41Sopenharmony_ci spill_range_ = spill_range; 9051cb0ef41Sopenharmony_ci} 9061cb0ef41Sopenharmony_ci 9071cb0ef41Sopenharmony_ciAllocatedOperand TopLevelLiveRange::GetSpillRangeOperand() const { 9081cb0ef41Sopenharmony_ci SpillRange* spill_range = GetSpillRange(); 9091cb0ef41Sopenharmony_ci int index = spill_range->assigned_slot(); 9101cb0ef41Sopenharmony_ci return AllocatedOperand(LocationOperand::STACK_SLOT, representation(), index); 9111cb0ef41Sopenharmony_ci} 9121cb0ef41Sopenharmony_ci 9131cb0ef41Sopenharmony_civoid TopLevelLiveRange::VerifyChildrenInOrder() const { 9141cb0ef41Sopenharmony_ci LifetimePosition last_end = End(); 9151cb0ef41Sopenharmony_ci for (const LiveRange* child = this->next(); child != nullptr; 9161cb0ef41Sopenharmony_ci child = child->next()) { 9171cb0ef41Sopenharmony_ci DCHECK(last_end <= child->Start()); 9181cb0ef41Sopenharmony_ci last_end = child->End(); 9191cb0ef41Sopenharmony_ci } 9201cb0ef41Sopenharmony_ci} 9211cb0ef41Sopenharmony_ci 9221cb0ef41Sopenharmony_ciLiveRange* TopLevelLiveRange::GetChildCovers(LifetimePosition pos) { 9231cb0ef41Sopenharmony_ci LiveRange* child = last_child_covers_; 9241cb0ef41Sopenharmony_ci DCHECK_NE(child, nullptr); 9251cb0ef41Sopenharmony_ci if (pos < child->Start()) { 9261cb0ef41Sopenharmony_ci // Cached value has advanced too far; start from the top. 9271cb0ef41Sopenharmony_ci child = this; 9281cb0ef41Sopenharmony_ci } 9291cb0ef41Sopenharmony_ci LiveRange* previous_child = nullptr; 9301cb0ef41Sopenharmony_ci while (child != nullptr && child->End() <= pos) { 9311cb0ef41Sopenharmony_ci previous_child = child; 9321cb0ef41Sopenharmony_ci child = child->next(); 9331cb0ef41Sopenharmony_ci } 9341cb0ef41Sopenharmony_ci 9351cb0ef41Sopenharmony_ci // If we've walked past the end, cache the last child instead. This allows 9361cb0ef41Sopenharmony_ci // future calls that are also past the end to be fast, since they will know 9371cb0ef41Sopenharmony_ci // that there is no need to reset the search to the beginning. 9381cb0ef41Sopenharmony_ci last_child_covers_ = child == nullptr ? previous_child : child; 9391cb0ef41Sopenharmony_ci 9401cb0ef41Sopenharmony_ci return !child || !child->Covers(pos) ? nullptr : child; 9411cb0ef41Sopenharmony_ci} 9421cb0ef41Sopenharmony_ci 9431cb0ef41Sopenharmony_civoid TopLevelLiveRange::Verify() const { 9441cb0ef41Sopenharmony_ci VerifyChildrenInOrder(); 9451cb0ef41Sopenharmony_ci for (const LiveRange* child = this; child != nullptr; child = child->next()) { 9461cb0ef41Sopenharmony_ci VerifyChildStructure(); 9471cb0ef41Sopenharmony_ci } 9481cb0ef41Sopenharmony_ci} 9491cb0ef41Sopenharmony_ci 9501cb0ef41Sopenharmony_civoid TopLevelLiveRange::ShortenTo(LifetimePosition start, bool trace_alloc) { 9511cb0ef41Sopenharmony_ci TRACE_COND(trace_alloc, "Shorten live range %d to [%d\n", vreg(), 9521cb0ef41Sopenharmony_ci start.value()); 9531cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(first_interval_); 9541cb0ef41Sopenharmony_ci DCHECK(first_interval_->start() <= start); 9551cb0ef41Sopenharmony_ci DCHECK(start < first_interval_->end()); 9561cb0ef41Sopenharmony_ci first_interval_->set_start(start); 9571cb0ef41Sopenharmony_ci} 9581cb0ef41Sopenharmony_ci 9591cb0ef41Sopenharmony_civoid TopLevelLiveRange::EnsureInterval(LifetimePosition start, 9601cb0ef41Sopenharmony_ci LifetimePosition end, Zone* zone, 9611cb0ef41Sopenharmony_ci bool trace_alloc) { 9621cb0ef41Sopenharmony_ci TRACE_COND(trace_alloc, "Ensure live range %d in interval [%d %d[\n", vreg(), 9631cb0ef41Sopenharmony_ci start.value(), end.value()); 9641cb0ef41Sopenharmony_ci LifetimePosition new_end = end; 9651cb0ef41Sopenharmony_ci while (first_interval_ != nullptr && first_interval_->start() <= end) { 9661cb0ef41Sopenharmony_ci if (first_interval_->end() > end) { 9671cb0ef41Sopenharmony_ci new_end = first_interval_->end(); 9681cb0ef41Sopenharmony_ci } 9691cb0ef41Sopenharmony_ci first_interval_ = first_interval_->next(); 9701cb0ef41Sopenharmony_ci } 9711cb0ef41Sopenharmony_ci 9721cb0ef41Sopenharmony_ci UseInterval* new_interval = zone->New<UseInterval>(start, new_end); 9731cb0ef41Sopenharmony_ci new_interval->set_next(first_interval_); 9741cb0ef41Sopenharmony_ci first_interval_ = new_interval; 9751cb0ef41Sopenharmony_ci if (new_interval->next() == nullptr) { 9761cb0ef41Sopenharmony_ci last_interval_ = new_interval; 9771cb0ef41Sopenharmony_ci } 9781cb0ef41Sopenharmony_ci} 9791cb0ef41Sopenharmony_ci 9801cb0ef41Sopenharmony_civoid TopLevelLiveRange::AddUseInterval(LifetimePosition start, 9811cb0ef41Sopenharmony_ci LifetimePosition end, Zone* zone, 9821cb0ef41Sopenharmony_ci bool trace_alloc) { 9831cb0ef41Sopenharmony_ci TRACE_COND(trace_alloc, "Add to live range %d interval [%d %d[\n", vreg(), 9841cb0ef41Sopenharmony_ci start.value(), end.value()); 9851cb0ef41Sopenharmony_ci if (first_interval_ == nullptr) { 9861cb0ef41Sopenharmony_ci UseInterval* interval = zone->New<UseInterval>(start, end); 9871cb0ef41Sopenharmony_ci first_interval_ = interval; 9881cb0ef41Sopenharmony_ci last_interval_ = interval; 9891cb0ef41Sopenharmony_ci } else { 9901cb0ef41Sopenharmony_ci if (end == first_interval_->start()) { 9911cb0ef41Sopenharmony_ci first_interval_->set_start(start); 9921cb0ef41Sopenharmony_ci } else if (end < first_interval_->start()) { 9931cb0ef41Sopenharmony_ci UseInterval* interval = zone->New<UseInterval>(start, end); 9941cb0ef41Sopenharmony_ci interval->set_next(first_interval_); 9951cb0ef41Sopenharmony_ci first_interval_ = interval; 9961cb0ef41Sopenharmony_ci } else { 9971cb0ef41Sopenharmony_ci // Order of instruction's processing (see ProcessInstructions) guarantees 9981cb0ef41Sopenharmony_ci // that each new use interval either precedes, intersects with or touches 9991cb0ef41Sopenharmony_ci // the last added interval. 10001cb0ef41Sopenharmony_ci DCHECK(start <= first_interval_->end()); 10011cb0ef41Sopenharmony_ci first_interval_->set_start(std::min(start, first_interval_->start())); 10021cb0ef41Sopenharmony_ci first_interval_->set_end(std::max(end, first_interval_->end())); 10031cb0ef41Sopenharmony_ci } 10041cb0ef41Sopenharmony_ci } 10051cb0ef41Sopenharmony_ci} 10061cb0ef41Sopenharmony_ci 10071cb0ef41Sopenharmony_civoid TopLevelLiveRange::AddUsePosition(UsePosition* use_pos, bool trace_alloc) { 10081cb0ef41Sopenharmony_ci LifetimePosition pos = use_pos->pos(); 10091cb0ef41Sopenharmony_ci TRACE_COND(trace_alloc, "Add to live range %d use position %d\n", vreg(), 10101cb0ef41Sopenharmony_ci pos.value()); 10111cb0ef41Sopenharmony_ci UsePosition* prev_hint = nullptr; 10121cb0ef41Sopenharmony_ci UsePosition* prev = nullptr; 10131cb0ef41Sopenharmony_ci UsePosition* current = first_pos_; 10141cb0ef41Sopenharmony_ci while (current != nullptr && current->pos() < pos) { 10151cb0ef41Sopenharmony_ci prev_hint = current->HasHint() ? current : prev_hint; 10161cb0ef41Sopenharmony_ci prev = current; 10171cb0ef41Sopenharmony_ci current = current->next(); 10181cb0ef41Sopenharmony_ci } 10191cb0ef41Sopenharmony_ci 10201cb0ef41Sopenharmony_ci if (prev == nullptr) { 10211cb0ef41Sopenharmony_ci use_pos->set_next(first_pos_); 10221cb0ef41Sopenharmony_ci first_pos_ = use_pos; 10231cb0ef41Sopenharmony_ci } else { 10241cb0ef41Sopenharmony_ci use_pos->set_next(prev->next()); 10251cb0ef41Sopenharmony_ci prev->set_next(use_pos); 10261cb0ef41Sopenharmony_ci } 10271cb0ef41Sopenharmony_ci 10281cb0ef41Sopenharmony_ci if (prev_hint == nullptr && use_pos->HasHint()) { 10291cb0ef41Sopenharmony_ci current_hint_position_ = use_pos; 10301cb0ef41Sopenharmony_ci } 10311cb0ef41Sopenharmony_ci} 10321cb0ef41Sopenharmony_ci 10331cb0ef41Sopenharmony_cistatic bool AreUseIntervalsIntersecting(UseInterval* interval1, 10341cb0ef41Sopenharmony_ci UseInterval* interval2) { 10351cb0ef41Sopenharmony_ci while (interval1 != nullptr && interval2 != nullptr) { 10361cb0ef41Sopenharmony_ci if (interval1->start() < interval2->start()) { 10371cb0ef41Sopenharmony_ci if (interval1->end() > interval2->start()) { 10381cb0ef41Sopenharmony_ci return true; 10391cb0ef41Sopenharmony_ci } 10401cb0ef41Sopenharmony_ci interval1 = interval1->next(); 10411cb0ef41Sopenharmony_ci } else { 10421cb0ef41Sopenharmony_ci if (interval2->end() > interval1->start()) { 10431cb0ef41Sopenharmony_ci return true; 10441cb0ef41Sopenharmony_ci } 10451cb0ef41Sopenharmony_ci interval2 = interval2->next(); 10461cb0ef41Sopenharmony_ci } 10471cb0ef41Sopenharmony_ci } 10481cb0ef41Sopenharmony_ci return false; 10491cb0ef41Sopenharmony_ci} 10501cb0ef41Sopenharmony_ci 10511cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os, 10521cb0ef41Sopenharmony_ci const PrintableLiveRange& printable_range) { 10531cb0ef41Sopenharmony_ci const LiveRange* range = printable_range.range_; 10541cb0ef41Sopenharmony_ci os << "Range: " << range->TopLevel()->vreg() << ":" << range->relative_id() 10551cb0ef41Sopenharmony_ci << " "; 10561cb0ef41Sopenharmony_ci if (range->TopLevel()->is_phi()) os << "phi "; 10571cb0ef41Sopenharmony_ci if (range->TopLevel()->is_non_loop_phi()) os << "nlphi "; 10581cb0ef41Sopenharmony_ci 10591cb0ef41Sopenharmony_ci os << "{" << std::endl; 10601cb0ef41Sopenharmony_ci UseInterval* interval = range->first_interval(); 10611cb0ef41Sopenharmony_ci UsePosition* use_pos = range->first_pos(); 10621cb0ef41Sopenharmony_ci while (use_pos != nullptr) { 10631cb0ef41Sopenharmony_ci if (use_pos->HasOperand()) { 10641cb0ef41Sopenharmony_ci os << *use_pos->operand() << use_pos->pos() << " "; 10651cb0ef41Sopenharmony_ci } 10661cb0ef41Sopenharmony_ci use_pos = use_pos->next(); 10671cb0ef41Sopenharmony_ci } 10681cb0ef41Sopenharmony_ci os << std::endl; 10691cb0ef41Sopenharmony_ci 10701cb0ef41Sopenharmony_ci while (interval != nullptr) { 10711cb0ef41Sopenharmony_ci os << '[' << interval->start() << ", " << interval->end() << ')' 10721cb0ef41Sopenharmony_ci << std::endl; 10731cb0ef41Sopenharmony_ci interval = interval->next(); 10741cb0ef41Sopenharmony_ci } 10751cb0ef41Sopenharmony_ci os << "}"; 10761cb0ef41Sopenharmony_ci return os; 10771cb0ef41Sopenharmony_ci} 10781cb0ef41Sopenharmony_ci 10791cb0ef41Sopenharmony_cinamespace { 10801cb0ef41Sopenharmony_civoid PrintBlockRow(std::ostream& os, const InstructionBlocks& blocks) { 10811cb0ef41Sopenharmony_ci os << " "; 10821cb0ef41Sopenharmony_ci for (auto block : blocks) { 10831cb0ef41Sopenharmony_ci LifetimePosition start_pos = LifetimePosition::GapFromInstructionIndex( 10841cb0ef41Sopenharmony_ci block->first_instruction_index()); 10851cb0ef41Sopenharmony_ci LifetimePosition end_pos = LifetimePosition::GapFromInstructionIndex( 10861cb0ef41Sopenharmony_ci block->last_instruction_index()) 10871cb0ef41Sopenharmony_ci .NextFullStart(); 10881cb0ef41Sopenharmony_ci int length = end_pos.value() - start_pos.value(); 10891cb0ef41Sopenharmony_ci constexpr int kMaxPrefixLength = 32; 10901cb0ef41Sopenharmony_ci char buffer[kMaxPrefixLength]; 10911cb0ef41Sopenharmony_ci int rpo_number = block->rpo_number().ToInt(); 10921cb0ef41Sopenharmony_ci const char* deferred_marker = block->IsDeferred() ? "(deferred)" : ""; 10931cb0ef41Sopenharmony_ci int max_prefix_length = std::min(length, kMaxPrefixLength); 10941cb0ef41Sopenharmony_ci int prefix = snprintf(buffer, max_prefix_length, "[-B%d-%s", rpo_number, 10951cb0ef41Sopenharmony_ci deferred_marker); 10961cb0ef41Sopenharmony_ci os << buffer; 10971cb0ef41Sopenharmony_ci int remaining = length - std::min(prefix, max_prefix_length) - 1; 10981cb0ef41Sopenharmony_ci for (int i = 0; i < remaining; ++i) os << '-'; 10991cb0ef41Sopenharmony_ci os << ']'; 11001cb0ef41Sopenharmony_ci } 11011cb0ef41Sopenharmony_ci os << '\n'; 11021cb0ef41Sopenharmony_ci} 11031cb0ef41Sopenharmony_ci} // namespace 11041cb0ef41Sopenharmony_ci 11051cb0ef41Sopenharmony_civoid LinearScanAllocator::PrintRangeRow(std::ostream& os, 11061cb0ef41Sopenharmony_ci const TopLevelLiveRange* toplevel) { 11071cb0ef41Sopenharmony_ci int position = 0; 11081cb0ef41Sopenharmony_ci os << std::setw(3) << toplevel->vreg() << ": "; 11091cb0ef41Sopenharmony_ci 11101cb0ef41Sopenharmony_ci const char* kind_string; 11111cb0ef41Sopenharmony_ci switch (toplevel->spill_type()) { 11121cb0ef41Sopenharmony_ci case TopLevelLiveRange::SpillType::kSpillRange: 11131cb0ef41Sopenharmony_ci kind_string = "ss"; 11141cb0ef41Sopenharmony_ci break; 11151cb0ef41Sopenharmony_ci case TopLevelLiveRange::SpillType::kDeferredSpillRange: 11161cb0ef41Sopenharmony_ci kind_string = "sd"; 11171cb0ef41Sopenharmony_ci break; 11181cb0ef41Sopenharmony_ci case TopLevelLiveRange::SpillType::kSpillOperand: 11191cb0ef41Sopenharmony_ci kind_string = "so"; 11201cb0ef41Sopenharmony_ci break; 11211cb0ef41Sopenharmony_ci default: 11221cb0ef41Sopenharmony_ci kind_string = "s?"; 11231cb0ef41Sopenharmony_ci } 11241cb0ef41Sopenharmony_ci 11251cb0ef41Sopenharmony_ci for (const LiveRange* range = toplevel; range != nullptr; 11261cb0ef41Sopenharmony_ci range = range->next()) { 11271cb0ef41Sopenharmony_ci for (UseInterval* interval = range->first_interval(); interval != nullptr; 11281cb0ef41Sopenharmony_ci interval = interval->next()) { 11291cb0ef41Sopenharmony_ci LifetimePosition start = interval->start(); 11301cb0ef41Sopenharmony_ci LifetimePosition end = interval->end(); 11311cb0ef41Sopenharmony_ci CHECK_GE(start.value(), position); 11321cb0ef41Sopenharmony_ci for (; start.value() > position; position++) { 11331cb0ef41Sopenharmony_ci os << ' '; 11341cb0ef41Sopenharmony_ci } 11351cb0ef41Sopenharmony_ci int length = end.value() - start.value(); 11361cb0ef41Sopenharmony_ci constexpr int kMaxPrefixLength = 32; 11371cb0ef41Sopenharmony_ci char buffer[kMaxPrefixLength]; 11381cb0ef41Sopenharmony_ci int max_prefix_length = std::min(length + 1, kMaxPrefixLength); 11391cb0ef41Sopenharmony_ci int prefix; 11401cb0ef41Sopenharmony_ci if (range->spilled()) { 11411cb0ef41Sopenharmony_ci prefix = snprintf(buffer, max_prefix_length, "|%s", kind_string); 11421cb0ef41Sopenharmony_ci } else { 11431cb0ef41Sopenharmony_ci prefix = snprintf(buffer, max_prefix_length, "|%s", 11441cb0ef41Sopenharmony_ci RegisterName(range->assigned_register())); 11451cb0ef41Sopenharmony_ci } 11461cb0ef41Sopenharmony_ci os << buffer; 11471cb0ef41Sopenharmony_ci position += std::min(prefix, max_prefix_length - 1); 11481cb0ef41Sopenharmony_ci CHECK_GE(end.value(), position); 11491cb0ef41Sopenharmony_ci const char line_style = range->spilled() ? '-' : '='; 11501cb0ef41Sopenharmony_ci for (; end.value() > position; position++) { 11511cb0ef41Sopenharmony_ci os << line_style; 11521cb0ef41Sopenharmony_ci } 11531cb0ef41Sopenharmony_ci } 11541cb0ef41Sopenharmony_ci } 11551cb0ef41Sopenharmony_ci os << '\n'; 11561cb0ef41Sopenharmony_ci} 11571cb0ef41Sopenharmony_ci 11581cb0ef41Sopenharmony_civoid LinearScanAllocator::PrintRangeOverview() { 11591cb0ef41Sopenharmony_ci std::ostringstream os; 11601cb0ef41Sopenharmony_ci PrintBlockRow(os, code()->instruction_blocks()); 11611cb0ef41Sopenharmony_ci for (auto const toplevel : data()->fixed_live_ranges()) { 11621cb0ef41Sopenharmony_ci if (toplevel == nullptr) continue; 11631cb0ef41Sopenharmony_ci PrintRangeRow(os, toplevel); 11641cb0ef41Sopenharmony_ci } 11651cb0ef41Sopenharmony_ci int rowcount = 0; 11661cb0ef41Sopenharmony_ci for (auto toplevel : data()->live_ranges()) { 11671cb0ef41Sopenharmony_ci if (!CanProcessRange(toplevel)) continue; 11681cb0ef41Sopenharmony_ci if (rowcount++ % 10 == 0) PrintBlockRow(os, code()->instruction_blocks()); 11691cb0ef41Sopenharmony_ci PrintRangeRow(os, toplevel); 11701cb0ef41Sopenharmony_ci } 11711cb0ef41Sopenharmony_ci PrintF("%s\n", os.str().c_str()); 11721cb0ef41Sopenharmony_ci} 11731cb0ef41Sopenharmony_ci 11741cb0ef41Sopenharmony_ciSpillRange::SpillRange(TopLevelLiveRange* parent, Zone* zone) 11751cb0ef41Sopenharmony_ci : live_ranges_(zone), 11761cb0ef41Sopenharmony_ci assigned_slot_(kUnassignedSlot), 11771cb0ef41Sopenharmony_ci byte_width_(ByteWidthForStackSlot(parent->representation())) { 11781cb0ef41Sopenharmony_ci // Spill ranges are created for top level. This is so that, when merging 11791cb0ef41Sopenharmony_ci // decisions are made, we consider the full extent of the virtual register, 11801cb0ef41Sopenharmony_ci // and avoid clobbering it. 11811cb0ef41Sopenharmony_ci UseInterval* result = nullptr; 11821cb0ef41Sopenharmony_ci UseInterval* node = nullptr; 11831cb0ef41Sopenharmony_ci // Copy the intervals for all ranges. 11841cb0ef41Sopenharmony_ci for (LiveRange* range = parent; range != nullptr; range = range->next()) { 11851cb0ef41Sopenharmony_ci UseInterval* src = range->first_interval(); 11861cb0ef41Sopenharmony_ci while (src != nullptr) { 11871cb0ef41Sopenharmony_ci UseInterval* new_node = zone->New<UseInterval>(src->start(), src->end()); 11881cb0ef41Sopenharmony_ci if (result == nullptr) { 11891cb0ef41Sopenharmony_ci result = new_node; 11901cb0ef41Sopenharmony_ci } else { 11911cb0ef41Sopenharmony_ci node->set_next(new_node); 11921cb0ef41Sopenharmony_ci } 11931cb0ef41Sopenharmony_ci node = new_node; 11941cb0ef41Sopenharmony_ci src = src->next(); 11951cb0ef41Sopenharmony_ci } 11961cb0ef41Sopenharmony_ci } 11971cb0ef41Sopenharmony_ci use_interval_ = result; 11981cb0ef41Sopenharmony_ci live_ranges().push_back(parent); 11991cb0ef41Sopenharmony_ci end_position_ = node->end(); 12001cb0ef41Sopenharmony_ci parent->SetSpillRange(this); 12011cb0ef41Sopenharmony_ci} 12021cb0ef41Sopenharmony_ci 12031cb0ef41Sopenharmony_cibool SpillRange::IsIntersectingWith(SpillRange* other) const { 12041cb0ef41Sopenharmony_ci if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || 12051cb0ef41Sopenharmony_ci this->End() <= other->use_interval_->start() || 12061cb0ef41Sopenharmony_ci other->End() <= this->use_interval_->start()) { 12071cb0ef41Sopenharmony_ci return false; 12081cb0ef41Sopenharmony_ci } 12091cb0ef41Sopenharmony_ci return AreUseIntervalsIntersecting(use_interval_, other->use_interval_); 12101cb0ef41Sopenharmony_ci} 12111cb0ef41Sopenharmony_ci 12121cb0ef41Sopenharmony_cibool SpillRange::TryMerge(SpillRange* other) { 12131cb0ef41Sopenharmony_ci if (HasSlot() || other->HasSlot()) return false; 12141cb0ef41Sopenharmony_ci if (byte_width() != other->byte_width() || IsIntersectingWith(other)) 12151cb0ef41Sopenharmony_ci return false; 12161cb0ef41Sopenharmony_ci 12171cb0ef41Sopenharmony_ci LifetimePosition max = LifetimePosition::MaxPosition(); 12181cb0ef41Sopenharmony_ci if (End() < other->End() && other->End() != max) { 12191cb0ef41Sopenharmony_ci end_position_ = other->End(); 12201cb0ef41Sopenharmony_ci } 12211cb0ef41Sopenharmony_ci other->end_position_ = max; 12221cb0ef41Sopenharmony_ci 12231cb0ef41Sopenharmony_ci MergeDisjointIntervals(other->use_interval_); 12241cb0ef41Sopenharmony_ci other->use_interval_ = nullptr; 12251cb0ef41Sopenharmony_ci 12261cb0ef41Sopenharmony_ci for (TopLevelLiveRange* range : other->live_ranges()) { 12271cb0ef41Sopenharmony_ci DCHECK(range->GetSpillRange() == other); 12281cb0ef41Sopenharmony_ci range->SetSpillRange(this); 12291cb0ef41Sopenharmony_ci } 12301cb0ef41Sopenharmony_ci 12311cb0ef41Sopenharmony_ci live_ranges().insert(live_ranges().end(), other->live_ranges().begin(), 12321cb0ef41Sopenharmony_ci other->live_ranges().end()); 12331cb0ef41Sopenharmony_ci other->live_ranges().clear(); 12341cb0ef41Sopenharmony_ci 12351cb0ef41Sopenharmony_ci return true; 12361cb0ef41Sopenharmony_ci} 12371cb0ef41Sopenharmony_ci 12381cb0ef41Sopenharmony_civoid SpillRange::MergeDisjointIntervals(UseInterval* other) { 12391cb0ef41Sopenharmony_ci UseInterval* tail = nullptr; 12401cb0ef41Sopenharmony_ci UseInterval* current = use_interval_; 12411cb0ef41Sopenharmony_ci while (other != nullptr) { 12421cb0ef41Sopenharmony_ci // Make sure the 'current' list starts first 12431cb0ef41Sopenharmony_ci if (current == nullptr || current->start() > other->start()) { 12441cb0ef41Sopenharmony_ci std::swap(current, other); 12451cb0ef41Sopenharmony_ci } 12461cb0ef41Sopenharmony_ci // Check disjointness 12471cb0ef41Sopenharmony_ci DCHECK(other == nullptr || current->end() <= other->start()); 12481cb0ef41Sopenharmony_ci // Append the 'current' node to the result accumulator and move forward 12491cb0ef41Sopenharmony_ci if (tail == nullptr) { 12501cb0ef41Sopenharmony_ci use_interval_ = current; 12511cb0ef41Sopenharmony_ci } else { 12521cb0ef41Sopenharmony_ci tail->set_next(current); 12531cb0ef41Sopenharmony_ci } 12541cb0ef41Sopenharmony_ci tail = current; 12551cb0ef41Sopenharmony_ci current = current->next(); 12561cb0ef41Sopenharmony_ci } 12571cb0ef41Sopenharmony_ci // Other list is empty => we are done 12581cb0ef41Sopenharmony_ci} 12591cb0ef41Sopenharmony_ci 12601cb0ef41Sopenharmony_civoid SpillRange::Print() const { 12611cb0ef41Sopenharmony_ci StdoutStream os; 12621cb0ef41Sopenharmony_ci os << "{" << std::endl; 12631cb0ef41Sopenharmony_ci for (TopLevelLiveRange* range : live_ranges()) { 12641cb0ef41Sopenharmony_ci os << range->vreg() << " "; 12651cb0ef41Sopenharmony_ci } 12661cb0ef41Sopenharmony_ci os << std::endl; 12671cb0ef41Sopenharmony_ci 12681cb0ef41Sopenharmony_ci for (UseInterval* i = interval(); i != nullptr; i = i->next()) { 12691cb0ef41Sopenharmony_ci os << '[' << i->start() << ", " << i->end() << ')' << std::endl; 12701cb0ef41Sopenharmony_ci } 12711cb0ef41Sopenharmony_ci os << "}" << std::endl; 12721cb0ef41Sopenharmony_ci} 12731cb0ef41Sopenharmony_ci 12741cb0ef41Sopenharmony_ciTopTierRegisterAllocationData::PhiMapValue::PhiMapValue( 12751cb0ef41Sopenharmony_ci PhiInstruction* phi, const InstructionBlock* block, Zone* zone) 12761cb0ef41Sopenharmony_ci : phi_(phi), 12771cb0ef41Sopenharmony_ci block_(block), 12781cb0ef41Sopenharmony_ci incoming_operands_(zone), 12791cb0ef41Sopenharmony_ci assigned_register_(kUnassignedRegister) { 12801cb0ef41Sopenharmony_ci incoming_operands_.reserve(phi->operands().size()); 12811cb0ef41Sopenharmony_ci} 12821cb0ef41Sopenharmony_ci 12831cb0ef41Sopenharmony_civoid TopTierRegisterAllocationData::PhiMapValue::AddOperand( 12841cb0ef41Sopenharmony_ci InstructionOperand* operand) { 12851cb0ef41Sopenharmony_ci incoming_operands_.push_back(operand); 12861cb0ef41Sopenharmony_ci} 12871cb0ef41Sopenharmony_ci 12881cb0ef41Sopenharmony_civoid TopTierRegisterAllocationData::PhiMapValue::CommitAssignment( 12891cb0ef41Sopenharmony_ci const InstructionOperand& assigned) { 12901cb0ef41Sopenharmony_ci for (InstructionOperand* operand : incoming_operands_) { 12911cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(operand, &assigned); 12921cb0ef41Sopenharmony_ci } 12931cb0ef41Sopenharmony_ci} 12941cb0ef41Sopenharmony_ci 12951cb0ef41Sopenharmony_ciTopTierRegisterAllocationData::TopTierRegisterAllocationData( 12961cb0ef41Sopenharmony_ci const RegisterConfiguration* config, Zone* zone, Frame* frame, 12971cb0ef41Sopenharmony_ci InstructionSequence* code, RegisterAllocationFlags flags, 12981cb0ef41Sopenharmony_ci TickCounter* tick_counter, const char* debug_name) 12991cb0ef41Sopenharmony_ci : RegisterAllocationData(Type::kTopTier), 13001cb0ef41Sopenharmony_ci allocation_zone_(zone), 13011cb0ef41Sopenharmony_ci frame_(frame), 13021cb0ef41Sopenharmony_ci code_(code), 13031cb0ef41Sopenharmony_ci debug_name_(debug_name), 13041cb0ef41Sopenharmony_ci config_(config), 13051cb0ef41Sopenharmony_ci phi_map_(allocation_zone()), 13061cb0ef41Sopenharmony_ci live_in_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()), 13071cb0ef41Sopenharmony_ci live_out_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()), 13081cb0ef41Sopenharmony_ci live_ranges_(code->VirtualRegisterCount() * 2, nullptr, 13091cb0ef41Sopenharmony_ci allocation_zone()), 13101cb0ef41Sopenharmony_ci fixed_live_ranges_(kNumberOfFixedRangesPerRegister * 13111cb0ef41Sopenharmony_ci this->config()->num_general_registers(), 13121cb0ef41Sopenharmony_ci nullptr, allocation_zone()), 13131cb0ef41Sopenharmony_ci fixed_float_live_ranges_(allocation_zone()), 13141cb0ef41Sopenharmony_ci fixed_double_live_ranges_(kNumberOfFixedRangesPerRegister * 13151cb0ef41Sopenharmony_ci this->config()->num_double_registers(), 13161cb0ef41Sopenharmony_ci nullptr, allocation_zone()), 13171cb0ef41Sopenharmony_ci fixed_simd128_live_ranges_(allocation_zone()), 13181cb0ef41Sopenharmony_ci spill_ranges_(code->VirtualRegisterCount(), nullptr, allocation_zone()), 13191cb0ef41Sopenharmony_ci delayed_references_(allocation_zone()), 13201cb0ef41Sopenharmony_ci assigned_registers_(nullptr), 13211cb0ef41Sopenharmony_ci assigned_double_registers_(nullptr), 13221cb0ef41Sopenharmony_ci virtual_register_count_(code->VirtualRegisterCount()), 13231cb0ef41Sopenharmony_ci preassigned_slot_ranges_(zone), 13241cb0ef41Sopenharmony_ci spill_state_(code->InstructionBlockCount(), ZoneVector<LiveRange*>(zone), 13251cb0ef41Sopenharmony_ci zone), 13261cb0ef41Sopenharmony_ci flags_(flags), 13271cb0ef41Sopenharmony_ci tick_counter_(tick_counter), 13281cb0ef41Sopenharmony_ci slot_for_const_range_(zone) { 13291cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine) { 13301cb0ef41Sopenharmony_ci fixed_float_live_ranges_.resize( 13311cb0ef41Sopenharmony_ci kNumberOfFixedRangesPerRegister * this->config()->num_float_registers(), 13321cb0ef41Sopenharmony_ci nullptr); 13331cb0ef41Sopenharmony_ci fixed_simd128_live_ranges_.resize( 13341cb0ef41Sopenharmony_ci kNumberOfFixedRangesPerRegister * 13351cb0ef41Sopenharmony_ci this->config()->num_simd128_registers(), 13361cb0ef41Sopenharmony_ci nullptr); 13371cb0ef41Sopenharmony_ci } else if (kFPAliasing == AliasingKind::kIndependent) { 13381cb0ef41Sopenharmony_ci fixed_simd128_live_ranges_.resize( 13391cb0ef41Sopenharmony_ci kNumberOfFixedRangesPerRegister * 13401cb0ef41Sopenharmony_ci this->config()->num_simd128_registers(), 13411cb0ef41Sopenharmony_ci nullptr); 13421cb0ef41Sopenharmony_ci } 13431cb0ef41Sopenharmony_ci 13441cb0ef41Sopenharmony_ci assigned_registers_ = code_zone()->New<BitVector>( 13451cb0ef41Sopenharmony_ci this->config()->num_general_registers(), code_zone()); 13461cb0ef41Sopenharmony_ci assigned_double_registers_ = code_zone()->New<BitVector>( 13471cb0ef41Sopenharmony_ci this->config()->num_double_registers(), code_zone()); 13481cb0ef41Sopenharmony_ci fixed_register_use_ = code_zone()->New<BitVector>( 13491cb0ef41Sopenharmony_ci this->config()->num_general_registers(), code_zone()); 13501cb0ef41Sopenharmony_ci fixed_fp_register_use_ = code_zone()->New<BitVector>( 13511cb0ef41Sopenharmony_ci this->config()->num_double_registers(), code_zone()); 13521cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kIndependent) { 13531cb0ef41Sopenharmony_ci assigned_simd128_registers_ = code_zone()->New<BitVector>( 13541cb0ef41Sopenharmony_ci this->config()->num_simd128_registers(), code_zone()); 13551cb0ef41Sopenharmony_ci fixed_simd128_register_use_ = code_zone()->New<BitVector>( 13561cb0ef41Sopenharmony_ci this->config()->num_simd128_registers(), code_zone()); 13571cb0ef41Sopenharmony_ci } 13581cb0ef41Sopenharmony_ci 13591cb0ef41Sopenharmony_ci this->frame()->SetAllocatedRegisters(assigned_registers_); 13601cb0ef41Sopenharmony_ci this->frame()->SetAllocatedDoubleRegisters(assigned_double_registers_); 13611cb0ef41Sopenharmony_ci} 13621cb0ef41Sopenharmony_ci 13631cb0ef41Sopenharmony_ciMoveOperands* TopTierRegisterAllocationData::AddGapMove( 13641cb0ef41Sopenharmony_ci int index, Instruction::GapPosition position, 13651cb0ef41Sopenharmony_ci const InstructionOperand& from, const InstructionOperand& to) { 13661cb0ef41Sopenharmony_ci Instruction* instr = code()->InstructionAt(index); 13671cb0ef41Sopenharmony_ci ParallelMove* moves = instr->GetOrCreateParallelMove(position, code_zone()); 13681cb0ef41Sopenharmony_ci return moves->AddMove(from, to); 13691cb0ef41Sopenharmony_ci} 13701cb0ef41Sopenharmony_ci 13711cb0ef41Sopenharmony_ciMachineRepresentation TopTierRegisterAllocationData::RepresentationFor( 13721cb0ef41Sopenharmony_ci int virtual_register) { 13731cb0ef41Sopenharmony_ci DCHECK_LT(virtual_register, code()->VirtualRegisterCount()); 13741cb0ef41Sopenharmony_ci return code()->GetRepresentation(virtual_register); 13751cb0ef41Sopenharmony_ci} 13761cb0ef41Sopenharmony_ci 13771cb0ef41Sopenharmony_ciTopLevelLiveRange* TopTierRegisterAllocationData::GetOrCreateLiveRangeFor( 13781cb0ef41Sopenharmony_ci int index) { 13791cb0ef41Sopenharmony_ci if (index >= static_cast<int>(live_ranges().size())) { 13801cb0ef41Sopenharmony_ci live_ranges().resize(index + 1, nullptr); 13811cb0ef41Sopenharmony_ci } 13821cb0ef41Sopenharmony_ci TopLevelLiveRange* result = live_ranges()[index]; 13831cb0ef41Sopenharmony_ci if (result == nullptr) { 13841cb0ef41Sopenharmony_ci result = NewLiveRange(index, RepresentationFor(index)); 13851cb0ef41Sopenharmony_ci live_ranges()[index] = result; 13861cb0ef41Sopenharmony_ci } 13871cb0ef41Sopenharmony_ci DCHECK_EQ(live_ranges()[index]->vreg(), index); 13881cb0ef41Sopenharmony_ci return result; 13891cb0ef41Sopenharmony_ci} 13901cb0ef41Sopenharmony_ci 13911cb0ef41Sopenharmony_ciTopLevelLiveRange* TopTierRegisterAllocationData::NewLiveRange( 13921cb0ef41Sopenharmony_ci int index, MachineRepresentation rep) { 13931cb0ef41Sopenharmony_ci return allocation_zone()->New<TopLevelLiveRange>(index, rep); 13941cb0ef41Sopenharmony_ci} 13951cb0ef41Sopenharmony_ci 13961cb0ef41Sopenharmony_ciTopTierRegisterAllocationData::PhiMapValue* 13971cb0ef41Sopenharmony_ciTopTierRegisterAllocationData::InitializePhiMap(const InstructionBlock* block, 13981cb0ef41Sopenharmony_ci PhiInstruction* phi) { 13991cb0ef41Sopenharmony_ci TopTierRegisterAllocationData::PhiMapValue* map_value = 14001cb0ef41Sopenharmony_ci allocation_zone()->New<TopTierRegisterAllocationData::PhiMapValue>( 14011cb0ef41Sopenharmony_ci phi, block, allocation_zone()); 14021cb0ef41Sopenharmony_ci auto res = 14031cb0ef41Sopenharmony_ci phi_map_.insert(std::make_pair(phi->virtual_register(), map_value)); 14041cb0ef41Sopenharmony_ci DCHECK(res.second); 14051cb0ef41Sopenharmony_ci USE(res); 14061cb0ef41Sopenharmony_ci return map_value; 14071cb0ef41Sopenharmony_ci} 14081cb0ef41Sopenharmony_ci 14091cb0ef41Sopenharmony_ciTopTierRegisterAllocationData::PhiMapValue* 14101cb0ef41Sopenharmony_ciTopTierRegisterAllocationData::GetPhiMapValueFor(int virtual_register) { 14111cb0ef41Sopenharmony_ci auto it = phi_map_.find(virtual_register); 14121cb0ef41Sopenharmony_ci DCHECK(it != phi_map_.end()); 14131cb0ef41Sopenharmony_ci return it->second; 14141cb0ef41Sopenharmony_ci} 14151cb0ef41Sopenharmony_ci 14161cb0ef41Sopenharmony_ciTopTierRegisterAllocationData::PhiMapValue* 14171cb0ef41Sopenharmony_ciTopTierRegisterAllocationData::GetPhiMapValueFor(TopLevelLiveRange* top_range) { 14181cb0ef41Sopenharmony_ci return GetPhiMapValueFor(top_range->vreg()); 14191cb0ef41Sopenharmony_ci} 14201cb0ef41Sopenharmony_ci 14211cb0ef41Sopenharmony_cibool TopTierRegisterAllocationData::ExistsUseWithoutDefinition() { 14221cb0ef41Sopenharmony_ci bool found = false; 14231cb0ef41Sopenharmony_ci for (int operand_index : *live_in_sets()[0]) { 14241cb0ef41Sopenharmony_ci found = true; 14251cb0ef41Sopenharmony_ci PrintF("Register allocator error: live v%d reached first block.\n", 14261cb0ef41Sopenharmony_ci operand_index); 14271cb0ef41Sopenharmony_ci LiveRange* range = GetOrCreateLiveRangeFor(operand_index); 14281cb0ef41Sopenharmony_ci PrintF(" (first use is at %d)\n", range->first_pos()->pos().value()); 14291cb0ef41Sopenharmony_ci if (debug_name() == nullptr) { 14301cb0ef41Sopenharmony_ci PrintF("\n"); 14311cb0ef41Sopenharmony_ci } else { 14321cb0ef41Sopenharmony_ci PrintF(" (function: %s)\n", debug_name()); 14331cb0ef41Sopenharmony_ci } 14341cb0ef41Sopenharmony_ci } 14351cb0ef41Sopenharmony_ci return found; 14361cb0ef41Sopenharmony_ci} 14371cb0ef41Sopenharmony_ci 14381cb0ef41Sopenharmony_ci// If a range is defined in a deferred block, we can expect all the range 14391cb0ef41Sopenharmony_ci// to only cover positions in deferred blocks. Otherwise, a block on the 14401cb0ef41Sopenharmony_ci// hot path would be dominated by a deferred block, meaning it is unreachable 14411cb0ef41Sopenharmony_ci// without passing through the deferred block, which is contradictory. 14421cb0ef41Sopenharmony_ci// In particular, when such a range contributes a result back on the hot 14431cb0ef41Sopenharmony_ci// path, it will be as one of the inputs of a phi. In that case, the value 14441cb0ef41Sopenharmony_ci// will be transferred via a move in the Gap::END's of the last instruction 14451cb0ef41Sopenharmony_ci// of a deferred block. 14461cb0ef41Sopenharmony_cibool TopTierRegisterAllocationData::RangesDefinedInDeferredStayInDeferred() { 14471cb0ef41Sopenharmony_ci const size_t live_ranges_size = live_ranges().size(); 14481cb0ef41Sopenharmony_ci for (const TopLevelLiveRange* range : live_ranges()) { 14491cb0ef41Sopenharmony_ci CHECK_EQ(live_ranges_size, 14501cb0ef41Sopenharmony_ci live_ranges().size()); // TODO(neis): crbug.com/831822 14511cb0ef41Sopenharmony_ci if (range == nullptr || range->IsEmpty() || 14521cb0ef41Sopenharmony_ci !code() 14531cb0ef41Sopenharmony_ci ->GetInstructionBlock(range->Start().ToInstructionIndex()) 14541cb0ef41Sopenharmony_ci ->IsDeferred()) { 14551cb0ef41Sopenharmony_ci continue; 14561cb0ef41Sopenharmony_ci } 14571cb0ef41Sopenharmony_ci for (const UseInterval* i = range->first_interval(); i != nullptr; 14581cb0ef41Sopenharmony_ci i = i->next()) { 14591cb0ef41Sopenharmony_ci int first = i->FirstGapIndex(); 14601cb0ef41Sopenharmony_ci int last = i->LastGapIndex(); 14611cb0ef41Sopenharmony_ci for (int instr = first; instr <= last;) { 14621cb0ef41Sopenharmony_ci const InstructionBlock* block = code()->GetInstructionBlock(instr); 14631cb0ef41Sopenharmony_ci if (!block->IsDeferred()) return false; 14641cb0ef41Sopenharmony_ci instr = block->last_instruction_index() + 1; 14651cb0ef41Sopenharmony_ci } 14661cb0ef41Sopenharmony_ci } 14671cb0ef41Sopenharmony_ci } 14681cb0ef41Sopenharmony_ci return true; 14691cb0ef41Sopenharmony_ci} 14701cb0ef41Sopenharmony_ci 14711cb0ef41Sopenharmony_ciSpillRange* TopTierRegisterAllocationData::AssignSpillRangeToLiveRange( 14721cb0ef41Sopenharmony_ci TopLevelLiveRange* range, SpillMode spill_mode) { 14731cb0ef41Sopenharmony_ci using SpillType = TopLevelLiveRange::SpillType; 14741cb0ef41Sopenharmony_ci DCHECK(!range->HasSpillOperand()); 14751cb0ef41Sopenharmony_ci 14761cb0ef41Sopenharmony_ci SpillRange* spill_range = range->GetAllocatedSpillRange(); 14771cb0ef41Sopenharmony_ci if (spill_range == nullptr) { 14781cb0ef41Sopenharmony_ci spill_range = allocation_zone()->New<SpillRange>(range, allocation_zone()); 14791cb0ef41Sopenharmony_ci } 14801cb0ef41Sopenharmony_ci if (spill_mode == SpillMode::kSpillDeferred && 14811cb0ef41Sopenharmony_ci (range->spill_type() != SpillType::kSpillRange)) { 14821cb0ef41Sopenharmony_ci range->set_spill_type(SpillType::kDeferredSpillRange); 14831cb0ef41Sopenharmony_ci } else { 14841cb0ef41Sopenharmony_ci range->set_spill_type(SpillType::kSpillRange); 14851cb0ef41Sopenharmony_ci } 14861cb0ef41Sopenharmony_ci 14871cb0ef41Sopenharmony_ci spill_ranges()[range->vreg()] = spill_range; 14881cb0ef41Sopenharmony_ci return spill_range; 14891cb0ef41Sopenharmony_ci} 14901cb0ef41Sopenharmony_ci 14911cb0ef41Sopenharmony_civoid TopTierRegisterAllocationData::MarkFixedUse(MachineRepresentation rep, 14921cb0ef41Sopenharmony_ci int index) { 14931cb0ef41Sopenharmony_ci switch (rep) { 14941cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 14951cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: 14961cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kOverlap) { 14971cb0ef41Sopenharmony_ci fixed_fp_register_use_->Add(index); 14981cb0ef41Sopenharmony_ci } else if (kFPAliasing == AliasingKind::kIndependent) { 14991cb0ef41Sopenharmony_ci if (rep == MachineRepresentation::kFloat32) { 15001cb0ef41Sopenharmony_ci fixed_fp_register_use_->Add(index); 15011cb0ef41Sopenharmony_ci } else { 15021cb0ef41Sopenharmony_ci fixed_simd128_register_use_->Add(index); 15031cb0ef41Sopenharmony_ci } 15041cb0ef41Sopenharmony_ci } else { 15051cb0ef41Sopenharmony_ci int alias_base_index = -1; 15061cb0ef41Sopenharmony_ci int aliases = config()->GetAliases( 15071cb0ef41Sopenharmony_ci rep, index, MachineRepresentation::kFloat64, &alias_base_index); 15081cb0ef41Sopenharmony_ci DCHECK(aliases > 0 || (aliases == 0 && alias_base_index == -1)); 15091cb0ef41Sopenharmony_ci while (aliases--) { 15101cb0ef41Sopenharmony_ci int aliased_reg = alias_base_index + aliases; 15111cb0ef41Sopenharmony_ci fixed_fp_register_use_->Add(aliased_reg); 15121cb0ef41Sopenharmony_ci } 15131cb0ef41Sopenharmony_ci } 15141cb0ef41Sopenharmony_ci break; 15151cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat64: 15161cb0ef41Sopenharmony_ci fixed_fp_register_use_->Add(index); 15171cb0ef41Sopenharmony_ci break; 15181cb0ef41Sopenharmony_ci default: 15191cb0ef41Sopenharmony_ci DCHECK(!IsFloatingPoint(rep)); 15201cb0ef41Sopenharmony_ci fixed_register_use_->Add(index); 15211cb0ef41Sopenharmony_ci break; 15221cb0ef41Sopenharmony_ci } 15231cb0ef41Sopenharmony_ci} 15241cb0ef41Sopenharmony_ci 15251cb0ef41Sopenharmony_cibool TopTierRegisterAllocationData::HasFixedUse(MachineRepresentation rep, 15261cb0ef41Sopenharmony_ci int index) { 15271cb0ef41Sopenharmony_ci switch (rep) { 15281cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 15291cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: { 15301cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kOverlap) { 15311cb0ef41Sopenharmony_ci return fixed_fp_register_use_->Contains(index); 15321cb0ef41Sopenharmony_ci } else if (kFPAliasing == AliasingKind::kIndependent) { 15331cb0ef41Sopenharmony_ci if (rep == MachineRepresentation::kFloat32) { 15341cb0ef41Sopenharmony_ci return fixed_fp_register_use_->Contains(index); 15351cb0ef41Sopenharmony_ci } else { 15361cb0ef41Sopenharmony_ci return fixed_simd128_register_use_->Contains(index); 15371cb0ef41Sopenharmony_ci } 15381cb0ef41Sopenharmony_ci } else { 15391cb0ef41Sopenharmony_ci int alias_base_index = -1; 15401cb0ef41Sopenharmony_ci int aliases = config()->GetAliases( 15411cb0ef41Sopenharmony_ci rep, index, MachineRepresentation::kFloat64, &alias_base_index); 15421cb0ef41Sopenharmony_ci DCHECK(aliases > 0 || (aliases == 0 && alias_base_index == -1)); 15431cb0ef41Sopenharmony_ci bool result = false; 15441cb0ef41Sopenharmony_ci while (aliases-- && !result) { 15451cb0ef41Sopenharmony_ci int aliased_reg = alias_base_index + aliases; 15461cb0ef41Sopenharmony_ci result |= fixed_fp_register_use_->Contains(aliased_reg); 15471cb0ef41Sopenharmony_ci } 15481cb0ef41Sopenharmony_ci return result; 15491cb0ef41Sopenharmony_ci } 15501cb0ef41Sopenharmony_ci } 15511cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat64: 15521cb0ef41Sopenharmony_ci return fixed_fp_register_use_->Contains(index); 15531cb0ef41Sopenharmony_ci default: 15541cb0ef41Sopenharmony_ci DCHECK(!IsFloatingPoint(rep)); 15551cb0ef41Sopenharmony_ci return fixed_register_use_->Contains(index); 15561cb0ef41Sopenharmony_ci } 15571cb0ef41Sopenharmony_ci} 15581cb0ef41Sopenharmony_ci 15591cb0ef41Sopenharmony_civoid TopTierRegisterAllocationData::MarkAllocated(MachineRepresentation rep, 15601cb0ef41Sopenharmony_ci int index) { 15611cb0ef41Sopenharmony_ci switch (rep) { 15621cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 15631cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: 15641cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kOverlap) { 15651cb0ef41Sopenharmony_ci assigned_double_registers_->Add(index); 15661cb0ef41Sopenharmony_ci } else if (kFPAliasing == AliasingKind::kIndependent) { 15671cb0ef41Sopenharmony_ci if (rep == MachineRepresentation::kFloat32) { 15681cb0ef41Sopenharmony_ci assigned_double_registers_->Add(index); 15691cb0ef41Sopenharmony_ci } else { 15701cb0ef41Sopenharmony_ci assigned_simd128_registers_->Add(index); 15711cb0ef41Sopenharmony_ci } 15721cb0ef41Sopenharmony_ci } else { 15731cb0ef41Sopenharmony_ci int alias_base_index = -1; 15741cb0ef41Sopenharmony_ci int aliases = config()->GetAliases( 15751cb0ef41Sopenharmony_ci rep, index, MachineRepresentation::kFloat64, &alias_base_index); 15761cb0ef41Sopenharmony_ci DCHECK(aliases > 0 || (aliases == 0 && alias_base_index == -1)); 15771cb0ef41Sopenharmony_ci while (aliases--) { 15781cb0ef41Sopenharmony_ci int aliased_reg = alias_base_index + aliases; 15791cb0ef41Sopenharmony_ci assigned_double_registers_->Add(aliased_reg); 15801cb0ef41Sopenharmony_ci } 15811cb0ef41Sopenharmony_ci } 15821cb0ef41Sopenharmony_ci break; 15831cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat64: 15841cb0ef41Sopenharmony_ci assigned_double_registers_->Add(index); 15851cb0ef41Sopenharmony_ci break; 15861cb0ef41Sopenharmony_ci default: 15871cb0ef41Sopenharmony_ci DCHECK(!IsFloatingPoint(rep)); 15881cb0ef41Sopenharmony_ci assigned_registers_->Add(index); 15891cb0ef41Sopenharmony_ci break; 15901cb0ef41Sopenharmony_ci } 15911cb0ef41Sopenharmony_ci} 15921cb0ef41Sopenharmony_ci 15931cb0ef41Sopenharmony_cibool TopTierRegisterAllocationData::IsBlockBoundary( 15941cb0ef41Sopenharmony_ci LifetimePosition pos) const { 15951cb0ef41Sopenharmony_ci return pos.IsFullStart() && 15961cb0ef41Sopenharmony_ci (static_cast<size_t>(pos.ToInstructionIndex()) == 15971cb0ef41Sopenharmony_ci code()->instructions().size() || 15981cb0ef41Sopenharmony_ci code()->GetInstructionBlock(pos.ToInstructionIndex())->code_start() == 15991cb0ef41Sopenharmony_ci pos.ToInstructionIndex()); 16001cb0ef41Sopenharmony_ci} 16011cb0ef41Sopenharmony_ci 16021cb0ef41Sopenharmony_ciConstraintBuilder::ConstraintBuilder(TopTierRegisterAllocationData* data) 16031cb0ef41Sopenharmony_ci : data_(data) {} 16041cb0ef41Sopenharmony_ci 16051cb0ef41Sopenharmony_ciInstructionOperand* ConstraintBuilder::AllocateFixed( 16061cb0ef41Sopenharmony_ci UnallocatedOperand* operand, int pos, bool is_tagged, bool is_input) { 16071cb0ef41Sopenharmony_ci TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); 16081cb0ef41Sopenharmony_ci DCHECK(operand->HasFixedPolicy()); 16091cb0ef41Sopenharmony_ci InstructionOperand allocated; 16101cb0ef41Sopenharmony_ci MachineRepresentation rep = InstructionSequence::DefaultRepresentation(); 16111cb0ef41Sopenharmony_ci int virtual_register = operand->virtual_register(); 16121cb0ef41Sopenharmony_ci if (virtual_register != InstructionOperand::kInvalidVirtualRegister) { 16131cb0ef41Sopenharmony_ci rep = data()->RepresentationFor(virtual_register); 16141cb0ef41Sopenharmony_ci } 16151cb0ef41Sopenharmony_ci if (operand->HasFixedSlotPolicy()) { 16161cb0ef41Sopenharmony_ci allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, rep, 16171cb0ef41Sopenharmony_ci operand->fixed_slot_index()); 16181cb0ef41Sopenharmony_ci } else if (operand->HasFixedRegisterPolicy()) { 16191cb0ef41Sopenharmony_ci DCHECK(!IsFloatingPoint(rep)); 16201cb0ef41Sopenharmony_ci DCHECK(data()->config()->IsAllocatableGeneralCode( 16211cb0ef41Sopenharmony_ci operand->fixed_register_index())); 16221cb0ef41Sopenharmony_ci allocated = AllocatedOperand(AllocatedOperand::REGISTER, rep, 16231cb0ef41Sopenharmony_ci operand->fixed_register_index()); 16241cb0ef41Sopenharmony_ci } else if (operand->HasFixedFPRegisterPolicy()) { 16251cb0ef41Sopenharmony_ci DCHECK(IsFloatingPoint(rep)); 16261cb0ef41Sopenharmony_ci DCHECK_NE(InstructionOperand::kInvalidVirtualRegister, virtual_register); 16271cb0ef41Sopenharmony_ci allocated = AllocatedOperand(AllocatedOperand::REGISTER, rep, 16281cb0ef41Sopenharmony_ci operand->fixed_register_index()); 16291cb0ef41Sopenharmony_ci } else { 16301cb0ef41Sopenharmony_ci UNREACHABLE(); 16311cb0ef41Sopenharmony_ci } 16321cb0ef41Sopenharmony_ci if (is_input && allocated.IsAnyRegister()) { 16331cb0ef41Sopenharmony_ci data()->MarkFixedUse(rep, operand->fixed_register_index()); 16341cb0ef41Sopenharmony_ci } 16351cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(operand, &allocated); 16361cb0ef41Sopenharmony_ci if (is_tagged) { 16371cb0ef41Sopenharmony_ci TRACE("Fixed reg is tagged at %d\n", pos); 16381cb0ef41Sopenharmony_ci Instruction* instr = code()->InstructionAt(pos); 16391cb0ef41Sopenharmony_ci if (instr->HasReferenceMap()) { 16401cb0ef41Sopenharmony_ci instr->reference_map()->RecordReference(*AllocatedOperand::cast(operand)); 16411cb0ef41Sopenharmony_ci } 16421cb0ef41Sopenharmony_ci } 16431cb0ef41Sopenharmony_ci return operand; 16441cb0ef41Sopenharmony_ci} 16451cb0ef41Sopenharmony_ci 16461cb0ef41Sopenharmony_civoid ConstraintBuilder::MeetRegisterConstraints() { 16471cb0ef41Sopenharmony_ci for (InstructionBlock* block : code()->instruction_blocks()) { 16481cb0ef41Sopenharmony_ci data_->tick_counter()->TickAndMaybeEnterSafepoint(); 16491cb0ef41Sopenharmony_ci MeetRegisterConstraints(block); 16501cb0ef41Sopenharmony_ci } 16511cb0ef41Sopenharmony_ci} 16521cb0ef41Sopenharmony_ci 16531cb0ef41Sopenharmony_civoid ConstraintBuilder::MeetRegisterConstraints(const InstructionBlock* block) { 16541cb0ef41Sopenharmony_ci int start = block->first_instruction_index(); 16551cb0ef41Sopenharmony_ci int end = block->last_instruction_index(); 16561cb0ef41Sopenharmony_ci DCHECK_NE(-1, start); 16571cb0ef41Sopenharmony_ci for (int i = start; i <= end; ++i) { 16581cb0ef41Sopenharmony_ci MeetConstraintsBefore(i); 16591cb0ef41Sopenharmony_ci if (i != end) MeetConstraintsAfter(i); 16601cb0ef41Sopenharmony_ci } 16611cb0ef41Sopenharmony_ci // Meet register constraints for the instruction in the end. 16621cb0ef41Sopenharmony_ci MeetRegisterConstraintsForLastInstructionInBlock(block); 16631cb0ef41Sopenharmony_ci} 16641cb0ef41Sopenharmony_ci 16651cb0ef41Sopenharmony_civoid ConstraintBuilder::MeetRegisterConstraintsForLastInstructionInBlock( 16661cb0ef41Sopenharmony_ci const InstructionBlock* block) { 16671cb0ef41Sopenharmony_ci int end = block->last_instruction_index(); 16681cb0ef41Sopenharmony_ci Instruction* last_instruction = code()->InstructionAt(end); 16691cb0ef41Sopenharmony_ci for (size_t i = 0; i < last_instruction->OutputCount(); i++) { 16701cb0ef41Sopenharmony_ci InstructionOperand* output_operand = last_instruction->OutputAt(i); 16711cb0ef41Sopenharmony_ci DCHECK(!output_operand->IsConstant()); 16721cb0ef41Sopenharmony_ci UnallocatedOperand* output = UnallocatedOperand::cast(output_operand); 16731cb0ef41Sopenharmony_ci int output_vreg = output->virtual_register(); 16741cb0ef41Sopenharmony_ci TopLevelLiveRange* range = data()->GetOrCreateLiveRangeFor(output_vreg); 16751cb0ef41Sopenharmony_ci bool assigned = false; 16761cb0ef41Sopenharmony_ci if (output->HasFixedPolicy()) { 16771cb0ef41Sopenharmony_ci AllocateFixed(output, -1, false, false); 16781cb0ef41Sopenharmony_ci // This value is produced on the stack, we never need to spill it. 16791cb0ef41Sopenharmony_ci if (output->IsStackSlot()) { 16801cb0ef41Sopenharmony_ci DCHECK(LocationOperand::cast(output)->index() < 16811cb0ef41Sopenharmony_ci data()->frame()->GetSpillSlotCount()); 16821cb0ef41Sopenharmony_ci range->SetSpillOperand(LocationOperand::cast(output)); 16831cb0ef41Sopenharmony_ci range->SetSpillStartIndex(end); 16841cb0ef41Sopenharmony_ci assigned = true; 16851cb0ef41Sopenharmony_ci } 16861cb0ef41Sopenharmony_ci 16871cb0ef41Sopenharmony_ci for (const RpoNumber& succ : block->successors()) { 16881cb0ef41Sopenharmony_ci const InstructionBlock* successor = code()->InstructionBlockAt(succ); 16891cb0ef41Sopenharmony_ci DCHECK_EQ(1, successor->PredecessorCount()); 16901cb0ef41Sopenharmony_ci int gap_index = successor->first_instruction_index(); 16911cb0ef41Sopenharmony_ci // Create an unconstrained operand for the same virtual register 16921cb0ef41Sopenharmony_ci // and insert a gap move from the fixed output to the operand. 16931cb0ef41Sopenharmony_ci UnallocatedOperand output_copy(UnallocatedOperand::REGISTER_OR_SLOT, 16941cb0ef41Sopenharmony_ci output_vreg); 16951cb0ef41Sopenharmony_ci data()->AddGapMove(gap_index, Instruction::START, *output, output_copy); 16961cb0ef41Sopenharmony_ci } 16971cb0ef41Sopenharmony_ci } 16981cb0ef41Sopenharmony_ci 16991cb0ef41Sopenharmony_ci if (!assigned) { 17001cb0ef41Sopenharmony_ci for (const RpoNumber& succ : block->successors()) { 17011cb0ef41Sopenharmony_ci const InstructionBlock* successor = code()->InstructionBlockAt(succ); 17021cb0ef41Sopenharmony_ci DCHECK_EQ(1, successor->PredecessorCount()); 17031cb0ef41Sopenharmony_ci int gap_index = successor->first_instruction_index(); 17041cb0ef41Sopenharmony_ci range->RecordSpillLocation(allocation_zone(), gap_index, output); 17051cb0ef41Sopenharmony_ci range->SetSpillStartIndex(gap_index); 17061cb0ef41Sopenharmony_ci } 17071cb0ef41Sopenharmony_ci } 17081cb0ef41Sopenharmony_ci } 17091cb0ef41Sopenharmony_ci} 17101cb0ef41Sopenharmony_ci 17111cb0ef41Sopenharmony_civoid ConstraintBuilder::MeetConstraintsAfter(int instr_index) { 17121cb0ef41Sopenharmony_ci Instruction* first = code()->InstructionAt(instr_index); 17131cb0ef41Sopenharmony_ci // Handle fixed temporaries. 17141cb0ef41Sopenharmony_ci for (size_t i = 0; i < first->TempCount(); i++) { 17151cb0ef41Sopenharmony_ci UnallocatedOperand* temp = UnallocatedOperand::cast(first->TempAt(i)); 17161cb0ef41Sopenharmony_ci if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false, false); 17171cb0ef41Sopenharmony_ci } 17181cb0ef41Sopenharmony_ci // Handle constant/fixed output operands. 17191cb0ef41Sopenharmony_ci for (size_t i = 0; i < first->OutputCount(); i++) { 17201cb0ef41Sopenharmony_ci InstructionOperand* output = first->OutputAt(i); 17211cb0ef41Sopenharmony_ci if (output->IsConstant()) { 17221cb0ef41Sopenharmony_ci int output_vreg = ConstantOperand::cast(output)->virtual_register(); 17231cb0ef41Sopenharmony_ci TopLevelLiveRange* range = data()->GetOrCreateLiveRangeFor(output_vreg); 17241cb0ef41Sopenharmony_ci range->SetSpillStartIndex(instr_index + 1); 17251cb0ef41Sopenharmony_ci range->SetSpillOperand(output); 17261cb0ef41Sopenharmony_ci continue; 17271cb0ef41Sopenharmony_ci } 17281cb0ef41Sopenharmony_ci UnallocatedOperand* first_output = UnallocatedOperand::cast(output); 17291cb0ef41Sopenharmony_ci TopLevelLiveRange* range = 17301cb0ef41Sopenharmony_ci data()->GetOrCreateLiveRangeFor(first_output->virtual_register()); 17311cb0ef41Sopenharmony_ci bool assigned = false; 17321cb0ef41Sopenharmony_ci if (first_output->HasFixedPolicy()) { 17331cb0ef41Sopenharmony_ci int output_vreg = first_output->virtual_register(); 17341cb0ef41Sopenharmony_ci UnallocatedOperand output_copy(UnallocatedOperand::REGISTER_OR_SLOT, 17351cb0ef41Sopenharmony_ci output_vreg); 17361cb0ef41Sopenharmony_ci bool is_tagged = code()->IsReference(output_vreg); 17371cb0ef41Sopenharmony_ci if (first_output->HasSecondaryStorage()) { 17381cb0ef41Sopenharmony_ci range->MarkHasPreassignedSlot(); 17391cb0ef41Sopenharmony_ci data()->preassigned_slot_ranges().push_back( 17401cb0ef41Sopenharmony_ci std::make_pair(range, first_output->GetSecondaryStorage())); 17411cb0ef41Sopenharmony_ci } 17421cb0ef41Sopenharmony_ci AllocateFixed(first_output, instr_index, is_tagged, false); 17431cb0ef41Sopenharmony_ci 17441cb0ef41Sopenharmony_ci // This value is produced on the stack, we never need to spill it. 17451cb0ef41Sopenharmony_ci if (first_output->IsStackSlot()) { 17461cb0ef41Sopenharmony_ci DCHECK(LocationOperand::cast(first_output)->index() < 17471cb0ef41Sopenharmony_ci data()->frame()->GetTotalFrameSlotCount()); 17481cb0ef41Sopenharmony_ci range->SetSpillOperand(LocationOperand::cast(first_output)); 17491cb0ef41Sopenharmony_ci range->SetSpillStartIndex(instr_index + 1); 17501cb0ef41Sopenharmony_ci assigned = true; 17511cb0ef41Sopenharmony_ci } 17521cb0ef41Sopenharmony_ci data()->AddGapMove(instr_index + 1, Instruction::START, *first_output, 17531cb0ef41Sopenharmony_ci output_copy); 17541cb0ef41Sopenharmony_ci } 17551cb0ef41Sopenharmony_ci // Make sure we add a gap move for spilling (if we have not done 17561cb0ef41Sopenharmony_ci // so already). 17571cb0ef41Sopenharmony_ci if (!assigned) { 17581cb0ef41Sopenharmony_ci range->RecordSpillLocation(allocation_zone(), instr_index + 1, 17591cb0ef41Sopenharmony_ci first_output); 17601cb0ef41Sopenharmony_ci range->SetSpillStartIndex(instr_index + 1); 17611cb0ef41Sopenharmony_ci } 17621cb0ef41Sopenharmony_ci } 17631cb0ef41Sopenharmony_ci} 17641cb0ef41Sopenharmony_ci 17651cb0ef41Sopenharmony_civoid ConstraintBuilder::MeetConstraintsBefore(int instr_index) { 17661cb0ef41Sopenharmony_ci Instruction* second = code()->InstructionAt(instr_index); 17671cb0ef41Sopenharmony_ci // Handle fixed input operands of second instruction. 17681cb0ef41Sopenharmony_ci ZoneVector<TopLevelLiveRange*>* spilled_consts = nullptr; 17691cb0ef41Sopenharmony_ci for (size_t i = 0; i < second->InputCount(); i++) { 17701cb0ef41Sopenharmony_ci InstructionOperand* input = second->InputAt(i); 17711cb0ef41Sopenharmony_ci if (input->IsImmediate()) { 17721cb0ef41Sopenharmony_ci continue; // Ignore immediates. 17731cb0ef41Sopenharmony_ci } 17741cb0ef41Sopenharmony_ci UnallocatedOperand* cur_input = UnallocatedOperand::cast(input); 17751cb0ef41Sopenharmony_ci if (cur_input->HasSlotPolicy()) { 17761cb0ef41Sopenharmony_ci TopLevelLiveRange* range = 17771cb0ef41Sopenharmony_ci data()->GetOrCreateLiveRangeFor(cur_input->virtual_register()); 17781cb0ef41Sopenharmony_ci if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { 17791cb0ef41Sopenharmony_ci bool already_spilled = false; 17801cb0ef41Sopenharmony_ci if (spilled_consts == nullptr) { 17811cb0ef41Sopenharmony_ci spilled_consts = 17821cb0ef41Sopenharmony_ci allocation_zone()->New<ZoneVector<TopLevelLiveRange*>>( 17831cb0ef41Sopenharmony_ci allocation_zone()); 17841cb0ef41Sopenharmony_ci } else { 17851cb0ef41Sopenharmony_ci auto it = 17861cb0ef41Sopenharmony_ci std::find(spilled_consts->begin(), spilled_consts->end(), range); 17871cb0ef41Sopenharmony_ci already_spilled = it != spilled_consts->end(); 17881cb0ef41Sopenharmony_ci } 17891cb0ef41Sopenharmony_ci auto it = data()->slot_for_const_range().find(range); 17901cb0ef41Sopenharmony_ci if (it == data()->slot_for_const_range().end()) { 17911cb0ef41Sopenharmony_ci DCHECK(!already_spilled); 17921cb0ef41Sopenharmony_ci int width = ByteWidthForStackSlot(range->representation()); 17931cb0ef41Sopenharmony_ci int index = data()->frame()->AllocateSpillSlot(width); 17941cb0ef41Sopenharmony_ci auto* slot = AllocatedOperand::New(allocation_zone(), 17951cb0ef41Sopenharmony_ci LocationOperand::STACK_SLOT, 17961cb0ef41Sopenharmony_ci range->representation(), index); 17971cb0ef41Sopenharmony_ci it = data()->slot_for_const_range().emplace(range, slot).first; 17981cb0ef41Sopenharmony_ci } 17991cb0ef41Sopenharmony_ci if (!already_spilled) { 18001cb0ef41Sopenharmony_ci auto* slot = it->second; 18011cb0ef41Sopenharmony_ci int input_vreg = cur_input->virtual_register(); 18021cb0ef41Sopenharmony_ci UnallocatedOperand input_copy(UnallocatedOperand::REGISTER_OR_SLOT, 18031cb0ef41Sopenharmony_ci input_vreg); 18041cb0ef41Sopenharmony_ci // Spill at every use position for simplicity, this case is very rare. 18051cb0ef41Sopenharmony_ci data()->AddGapMove(instr_index, Instruction::END, input_copy, *slot); 18061cb0ef41Sopenharmony_ci spilled_consts->push_back(range); 18071cb0ef41Sopenharmony_ci } 18081cb0ef41Sopenharmony_ci } 18091cb0ef41Sopenharmony_ci } 18101cb0ef41Sopenharmony_ci if (cur_input->HasFixedPolicy()) { 18111cb0ef41Sopenharmony_ci int input_vreg = cur_input->virtual_register(); 18121cb0ef41Sopenharmony_ci UnallocatedOperand input_copy(UnallocatedOperand::REGISTER_OR_SLOT, 18131cb0ef41Sopenharmony_ci input_vreg); 18141cb0ef41Sopenharmony_ci bool is_tagged = code()->IsReference(input_vreg); 18151cb0ef41Sopenharmony_ci AllocateFixed(cur_input, instr_index, is_tagged, true); 18161cb0ef41Sopenharmony_ci data()->AddGapMove(instr_index, Instruction::END, input_copy, *cur_input); 18171cb0ef41Sopenharmony_ci } 18181cb0ef41Sopenharmony_ci } 18191cb0ef41Sopenharmony_ci // Handle "output same as input" for second instruction. 18201cb0ef41Sopenharmony_ci for (size_t i = 0; i < second->OutputCount(); i++) { 18211cb0ef41Sopenharmony_ci InstructionOperand* output = second->OutputAt(i); 18221cb0ef41Sopenharmony_ci if (!output->IsUnallocated()) continue; 18231cb0ef41Sopenharmony_ci UnallocatedOperand* second_output = UnallocatedOperand::cast(output); 18241cb0ef41Sopenharmony_ci if (!second_output->HasSameAsInputPolicy()) continue; 18251cb0ef41Sopenharmony_ci DCHECK_EQ(0, i); // Only valid for first output. 18261cb0ef41Sopenharmony_ci UnallocatedOperand* cur_input = 18271cb0ef41Sopenharmony_ci UnallocatedOperand::cast(second->InputAt(second_output->input_index())); 18281cb0ef41Sopenharmony_ci int output_vreg = second_output->virtual_register(); 18291cb0ef41Sopenharmony_ci int input_vreg = cur_input->virtual_register(); 18301cb0ef41Sopenharmony_ci UnallocatedOperand input_copy(UnallocatedOperand::REGISTER_OR_SLOT, 18311cb0ef41Sopenharmony_ci input_vreg); 18321cb0ef41Sopenharmony_ci *cur_input = 18331cb0ef41Sopenharmony_ci UnallocatedOperand(*cur_input, second_output->virtual_register()); 18341cb0ef41Sopenharmony_ci MoveOperands* gap_move = data()->AddGapMove(instr_index, Instruction::END, 18351cb0ef41Sopenharmony_ci input_copy, *cur_input); 18361cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(gap_move); 18371cb0ef41Sopenharmony_ci if (code()->IsReference(input_vreg) && !code()->IsReference(output_vreg)) { 18381cb0ef41Sopenharmony_ci if (second->HasReferenceMap()) { 18391cb0ef41Sopenharmony_ci TopTierRegisterAllocationData::DelayedReference delayed_reference = { 18401cb0ef41Sopenharmony_ci second->reference_map(), &gap_move->source()}; 18411cb0ef41Sopenharmony_ci data()->delayed_references().push_back(delayed_reference); 18421cb0ef41Sopenharmony_ci } 18431cb0ef41Sopenharmony_ci } 18441cb0ef41Sopenharmony_ci } 18451cb0ef41Sopenharmony_ci} 18461cb0ef41Sopenharmony_ci 18471cb0ef41Sopenharmony_civoid ConstraintBuilder::ResolvePhis() { 18481cb0ef41Sopenharmony_ci // Process the blocks in reverse order. 18491cb0ef41Sopenharmony_ci for (InstructionBlock* block : base::Reversed(code()->instruction_blocks())) { 18501cb0ef41Sopenharmony_ci data_->tick_counter()->TickAndMaybeEnterSafepoint(); 18511cb0ef41Sopenharmony_ci ResolvePhis(block); 18521cb0ef41Sopenharmony_ci } 18531cb0ef41Sopenharmony_ci} 18541cb0ef41Sopenharmony_ci 18551cb0ef41Sopenharmony_civoid ConstraintBuilder::ResolvePhis(const InstructionBlock* block) { 18561cb0ef41Sopenharmony_ci for (PhiInstruction* phi : block->phis()) { 18571cb0ef41Sopenharmony_ci int phi_vreg = phi->virtual_register(); 18581cb0ef41Sopenharmony_ci TopTierRegisterAllocationData::PhiMapValue* map_value = 18591cb0ef41Sopenharmony_ci data()->InitializePhiMap(block, phi); 18601cb0ef41Sopenharmony_ci InstructionOperand& output = phi->output(); 18611cb0ef41Sopenharmony_ci // Map the destination operands, so the commitment phase can find them. 18621cb0ef41Sopenharmony_ci for (size_t i = 0; i < phi->operands().size(); ++i) { 18631cb0ef41Sopenharmony_ci InstructionBlock* cur_block = 18641cb0ef41Sopenharmony_ci code()->InstructionBlockAt(block->predecessors()[i]); 18651cb0ef41Sopenharmony_ci UnallocatedOperand input(UnallocatedOperand::REGISTER_OR_SLOT, 18661cb0ef41Sopenharmony_ci phi->operands()[i]); 18671cb0ef41Sopenharmony_ci MoveOperands* move = data()->AddGapMove( 18681cb0ef41Sopenharmony_ci cur_block->last_instruction_index(), Instruction::END, input, output); 18691cb0ef41Sopenharmony_ci map_value->AddOperand(&move->destination()); 18701cb0ef41Sopenharmony_ci DCHECK(!code() 18711cb0ef41Sopenharmony_ci ->InstructionAt(cur_block->last_instruction_index()) 18721cb0ef41Sopenharmony_ci ->HasReferenceMap()); 18731cb0ef41Sopenharmony_ci } 18741cb0ef41Sopenharmony_ci TopLevelLiveRange* live_range = data()->GetOrCreateLiveRangeFor(phi_vreg); 18751cb0ef41Sopenharmony_ci int gap_index = block->first_instruction_index(); 18761cb0ef41Sopenharmony_ci live_range->RecordSpillLocation(allocation_zone(), gap_index, &output); 18771cb0ef41Sopenharmony_ci live_range->SetSpillStartIndex(gap_index); 18781cb0ef41Sopenharmony_ci // We use the phi-ness of some nodes in some later heuristics. 18791cb0ef41Sopenharmony_ci live_range->set_is_phi(true); 18801cb0ef41Sopenharmony_ci live_range->set_is_non_loop_phi(!block->IsLoopHeader()); 18811cb0ef41Sopenharmony_ci } 18821cb0ef41Sopenharmony_ci} 18831cb0ef41Sopenharmony_ci 18841cb0ef41Sopenharmony_ciLiveRangeBuilder::LiveRangeBuilder(TopTierRegisterAllocationData* data, 18851cb0ef41Sopenharmony_ci Zone* local_zone) 18861cb0ef41Sopenharmony_ci : data_(data), phi_hints_(local_zone) {} 18871cb0ef41Sopenharmony_ci 18881cb0ef41Sopenharmony_ciBitVector* LiveRangeBuilder::ComputeLiveOut( 18891cb0ef41Sopenharmony_ci const InstructionBlock* block, TopTierRegisterAllocationData* data) { 18901cb0ef41Sopenharmony_ci size_t block_index = block->rpo_number().ToSize(); 18911cb0ef41Sopenharmony_ci BitVector* live_out = data->live_out_sets()[block_index]; 18921cb0ef41Sopenharmony_ci if (live_out == nullptr) { 18931cb0ef41Sopenharmony_ci // Compute live out for the given block, except not including backward 18941cb0ef41Sopenharmony_ci // successor edges. 18951cb0ef41Sopenharmony_ci Zone* zone = data->allocation_zone(); 18961cb0ef41Sopenharmony_ci const InstructionSequence* code = data->code(); 18971cb0ef41Sopenharmony_ci 18981cb0ef41Sopenharmony_ci live_out = zone->New<BitVector>(code->VirtualRegisterCount(), zone); 18991cb0ef41Sopenharmony_ci 19001cb0ef41Sopenharmony_ci // Process all successor blocks. 19011cb0ef41Sopenharmony_ci for (const RpoNumber& succ : block->successors()) { 19021cb0ef41Sopenharmony_ci // Add values live on entry to the successor. 19031cb0ef41Sopenharmony_ci if (succ <= block->rpo_number()) continue; 19041cb0ef41Sopenharmony_ci BitVector* live_in = data->live_in_sets()[succ.ToSize()]; 19051cb0ef41Sopenharmony_ci if (live_in != nullptr) live_out->Union(*live_in); 19061cb0ef41Sopenharmony_ci 19071cb0ef41Sopenharmony_ci // All phi input operands corresponding to this successor edge are live 19081cb0ef41Sopenharmony_ci // out from this block. 19091cb0ef41Sopenharmony_ci const InstructionBlock* successor = code->InstructionBlockAt(succ); 19101cb0ef41Sopenharmony_ci size_t index = successor->PredecessorIndexOf(block->rpo_number()); 19111cb0ef41Sopenharmony_ci DCHECK(index < successor->PredecessorCount()); 19121cb0ef41Sopenharmony_ci for (PhiInstruction* phi : successor->phis()) { 19131cb0ef41Sopenharmony_ci live_out->Add(phi->operands()[index]); 19141cb0ef41Sopenharmony_ci } 19151cb0ef41Sopenharmony_ci } 19161cb0ef41Sopenharmony_ci data->live_out_sets()[block_index] = live_out; 19171cb0ef41Sopenharmony_ci } 19181cb0ef41Sopenharmony_ci return live_out; 19191cb0ef41Sopenharmony_ci} 19201cb0ef41Sopenharmony_ci 19211cb0ef41Sopenharmony_civoid LiveRangeBuilder::AddInitialIntervals(const InstructionBlock* block, 19221cb0ef41Sopenharmony_ci BitVector* live_out) { 19231cb0ef41Sopenharmony_ci // Add an interval that includes the entire block to the live range for 19241cb0ef41Sopenharmony_ci // each live_out value. 19251cb0ef41Sopenharmony_ci LifetimePosition start = LifetimePosition::GapFromInstructionIndex( 19261cb0ef41Sopenharmony_ci block->first_instruction_index()); 19271cb0ef41Sopenharmony_ci LifetimePosition end = LifetimePosition::InstructionFromInstructionIndex( 19281cb0ef41Sopenharmony_ci block->last_instruction_index()) 19291cb0ef41Sopenharmony_ci .NextStart(); 19301cb0ef41Sopenharmony_ci for (int operand_index : *live_out) { 19311cb0ef41Sopenharmony_ci TopLevelLiveRange* range = data()->GetOrCreateLiveRangeFor(operand_index); 19321cb0ef41Sopenharmony_ci range->AddUseInterval(start, end, allocation_zone(), 19331cb0ef41Sopenharmony_ci data()->is_trace_alloc()); 19341cb0ef41Sopenharmony_ci } 19351cb0ef41Sopenharmony_ci} 19361cb0ef41Sopenharmony_ci 19371cb0ef41Sopenharmony_ciint LiveRangeBuilder::FixedFPLiveRangeID(int index, MachineRepresentation rep) { 19381cb0ef41Sopenharmony_ci int result = -index - 1; 19391cb0ef41Sopenharmony_ci switch (rep) { 19401cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: 19411cb0ef41Sopenharmony_ci result -= 19421cb0ef41Sopenharmony_ci kNumberOfFixedRangesPerRegister * config()->num_float_registers(); 19431cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 19441cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 19451cb0ef41Sopenharmony_ci result -= 19461cb0ef41Sopenharmony_ci kNumberOfFixedRangesPerRegister * config()->num_double_registers(); 19471cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 19481cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat64: 19491cb0ef41Sopenharmony_ci result -= 19501cb0ef41Sopenharmony_ci kNumberOfFixedRangesPerRegister * config()->num_general_registers(); 19511cb0ef41Sopenharmony_ci break; 19521cb0ef41Sopenharmony_ci default: 19531cb0ef41Sopenharmony_ci UNREACHABLE(); 19541cb0ef41Sopenharmony_ci } 19551cb0ef41Sopenharmony_ci return result; 19561cb0ef41Sopenharmony_ci} 19571cb0ef41Sopenharmony_ci 19581cb0ef41Sopenharmony_ciTopLevelLiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index, 19591cb0ef41Sopenharmony_ci SpillMode spill_mode) { 19601cb0ef41Sopenharmony_ci int offset = spill_mode == SpillMode::kSpillAtDefinition 19611cb0ef41Sopenharmony_ci ? 0 19621cb0ef41Sopenharmony_ci : config()->num_general_registers(); 19631cb0ef41Sopenharmony_ci DCHECK(index < config()->num_general_registers()); 19641cb0ef41Sopenharmony_ci TopLevelLiveRange* result = data()->fixed_live_ranges()[offset + index]; 19651cb0ef41Sopenharmony_ci if (result == nullptr) { 19661cb0ef41Sopenharmony_ci MachineRepresentation rep = InstructionSequence::DefaultRepresentation(); 19671cb0ef41Sopenharmony_ci result = data()->NewLiveRange(FixedLiveRangeID(offset + index), rep); 19681cb0ef41Sopenharmony_ci DCHECK(result->IsFixed()); 19691cb0ef41Sopenharmony_ci result->set_assigned_register(index); 19701cb0ef41Sopenharmony_ci data()->MarkAllocated(rep, index); 19711cb0ef41Sopenharmony_ci if (spill_mode == SpillMode::kSpillDeferred) { 19721cb0ef41Sopenharmony_ci result->set_deferred_fixed(); 19731cb0ef41Sopenharmony_ci } 19741cb0ef41Sopenharmony_ci data()->fixed_live_ranges()[offset + index] = result; 19751cb0ef41Sopenharmony_ci } 19761cb0ef41Sopenharmony_ci return result; 19771cb0ef41Sopenharmony_ci} 19781cb0ef41Sopenharmony_ci 19791cb0ef41Sopenharmony_ciTopLevelLiveRange* LiveRangeBuilder::FixedFPLiveRangeFor( 19801cb0ef41Sopenharmony_ci int index, MachineRepresentation rep, SpillMode spill_mode) { 19811cb0ef41Sopenharmony_ci int num_regs = config()->num_double_registers(); 19821cb0ef41Sopenharmony_ci ZoneVector<TopLevelLiveRange*>* live_ranges = 19831cb0ef41Sopenharmony_ci &data()->fixed_double_live_ranges(); 19841cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine) { 19851cb0ef41Sopenharmony_ci switch (rep) { 19861cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 19871cb0ef41Sopenharmony_ci num_regs = config()->num_float_registers(); 19881cb0ef41Sopenharmony_ci live_ranges = &data()->fixed_float_live_ranges(); 19891cb0ef41Sopenharmony_ci break; 19901cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: 19911cb0ef41Sopenharmony_ci num_regs = config()->num_simd128_registers(); 19921cb0ef41Sopenharmony_ci live_ranges = &data()->fixed_simd128_live_ranges(); 19931cb0ef41Sopenharmony_ci break; 19941cb0ef41Sopenharmony_ci default: 19951cb0ef41Sopenharmony_ci break; 19961cb0ef41Sopenharmony_ci } 19971cb0ef41Sopenharmony_ci } 19981cb0ef41Sopenharmony_ci 19991cb0ef41Sopenharmony_ci int offset = spill_mode == SpillMode::kSpillAtDefinition ? 0 : num_regs; 20001cb0ef41Sopenharmony_ci 20011cb0ef41Sopenharmony_ci DCHECK(index < num_regs); 20021cb0ef41Sopenharmony_ci USE(num_regs); 20031cb0ef41Sopenharmony_ci TopLevelLiveRange* result = (*live_ranges)[offset + index]; 20041cb0ef41Sopenharmony_ci if (result == nullptr) { 20051cb0ef41Sopenharmony_ci result = data()->NewLiveRange(FixedFPLiveRangeID(offset + index, rep), rep); 20061cb0ef41Sopenharmony_ci DCHECK(result->IsFixed()); 20071cb0ef41Sopenharmony_ci result->set_assigned_register(index); 20081cb0ef41Sopenharmony_ci data()->MarkAllocated(rep, index); 20091cb0ef41Sopenharmony_ci if (spill_mode == SpillMode::kSpillDeferred) { 20101cb0ef41Sopenharmony_ci result->set_deferred_fixed(); 20111cb0ef41Sopenharmony_ci } 20121cb0ef41Sopenharmony_ci (*live_ranges)[offset + index] = result; 20131cb0ef41Sopenharmony_ci } 20141cb0ef41Sopenharmony_ci return result; 20151cb0ef41Sopenharmony_ci} 20161cb0ef41Sopenharmony_ci 20171cb0ef41Sopenharmony_ciTopLevelLiveRange* LiveRangeBuilder::FixedSIMD128LiveRangeFor( 20181cb0ef41Sopenharmony_ci int index, SpillMode spill_mode) { 20191cb0ef41Sopenharmony_ci DCHECK_EQ(kFPAliasing, AliasingKind::kIndependent); 20201cb0ef41Sopenharmony_ci int num_regs = config()->num_simd128_registers(); 20211cb0ef41Sopenharmony_ci ZoneVector<TopLevelLiveRange*>* live_ranges = 20221cb0ef41Sopenharmony_ci &data()->fixed_simd128_live_ranges(); 20231cb0ef41Sopenharmony_ci int offset = spill_mode == SpillMode::kSpillAtDefinition ? 0 : num_regs; 20241cb0ef41Sopenharmony_ci 20251cb0ef41Sopenharmony_ci DCHECK(index < num_regs); 20261cb0ef41Sopenharmony_ci USE(num_regs); 20271cb0ef41Sopenharmony_ci TopLevelLiveRange* result = (*live_ranges)[offset + index]; 20281cb0ef41Sopenharmony_ci if (result == nullptr) { 20291cb0ef41Sopenharmony_ci result = data()->NewLiveRange( 20301cb0ef41Sopenharmony_ci FixedFPLiveRangeID(offset + index, MachineRepresentation::kSimd128), 20311cb0ef41Sopenharmony_ci MachineRepresentation::kSimd128); 20321cb0ef41Sopenharmony_ci DCHECK(result->IsFixed()); 20331cb0ef41Sopenharmony_ci result->set_assigned_register(index); 20341cb0ef41Sopenharmony_ci data()->MarkAllocated(MachineRepresentation::kSimd128, index); 20351cb0ef41Sopenharmony_ci if (spill_mode == SpillMode::kSpillDeferred) { 20361cb0ef41Sopenharmony_ci result->set_deferred_fixed(); 20371cb0ef41Sopenharmony_ci } 20381cb0ef41Sopenharmony_ci (*live_ranges)[offset + index] = result; 20391cb0ef41Sopenharmony_ci } 20401cb0ef41Sopenharmony_ci return result; 20411cb0ef41Sopenharmony_ci} 20421cb0ef41Sopenharmony_ci 20431cb0ef41Sopenharmony_ciTopLevelLiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand, 20441cb0ef41Sopenharmony_ci SpillMode spill_mode) { 20451cb0ef41Sopenharmony_ci if (operand->IsUnallocated()) { 20461cb0ef41Sopenharmony_ci return data()->GetOrCreateLiveRangeFor( 20471cb0ef41Sopenharmony_ci UnallocatedOperand::cast(operand)->virtual_register()); 20481cb0ef41Sopenharmony_ci } else if (operand->IsConstant()) { 20491cb0ef41Sopenharmony_ci return data()->GetOrCreateLiveRangeFor( 20501cb0ef41Sopenharmony_ci ConstantOperand::cast(operand)->virtual_register()); 20511cb0ef41Sopenharmony_ci } else if (operand->IsRegister()) { 20521cb0ef41Sopenharmony_ci return FixedLiveRangeFor( 20531cb0ef41Sopenharmony_ci LocationOperand::cast(operand)->GetRegister().code(), spill_mode); 20541cb0ef41Sopenharmony_ci } else if (operand->IsFPRegister()) { 20551cb0ef41Sopenharmony_ci LocationOperand* op = LocationOperand::cast(operand); 20561cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kIndependent && 20571cb0ef41Sopenharmony_ci op->representation() == MachineRepresentation::kSimd128) { 20581cb0ef41Sopenharmony_ci return FixedSIMD128LiveRangeFor(op->register_code(), spill_mode); 20591cb0ef41Sopenharmony_ci } 20601cb0ef41Sopenharmony_ci return FixedFPLiveRangeFor(op->register_code(), op->representation(), 20611cb0ef41Sopenharmony_ci spill_mode); 20621cb0ef41Sopenharmony_ci } else { 20631cb0ef41Sopenharmony_ci return nullptr; 20641cb0ef41Sopenharmony_ci } 20651cb0ef41Sopenharmony_ci} 20661cb0ef41Sopenharmony_ci 20671cb0ef41Sopenharmony_ciUsePosition* LiveRangeBuilder::NewUsePosition(LifetimePosition pos, 20681cb0ef41Sopenharmony_ci InstructionOperand* operand, 20691cb0ef41Sopenharmony_ci void* hint, 20701cb0ef41Sopenharmony_ci UsePositionHintType hint_type) { 20711cb0ef41Sopenharmony_ci return allocation_zone()->New<UsePosition>(pos, operand, hint, hint_type); 20721cb0ef41Sopenharmony_ci} 20731cb0ef41Sopenharmony_ci 20741cb0ef41Sopenharmony_ciUsePosition* LiveRangeBuilder::Define(LifetimePosition position, 20751cb0ef41Sopenharmony_ci InstructionOperand* operand, void* hint, 20761cb0ef41Sopenharmony_ci UsePositionHintType hint_type, 20771cb0ef41Sopenharmony_ci SpillMode spill_mode) { 20781cb0ef41Sopenharmony_ci TopLevelLiveRange* range = LiveRangeFor(operand, spill_mode); 20791cb0ef41Sopenharmony_ci if (range == nullptr) return nullptr; 20801cb0ef41Sopenharmony_ci 20811cb0ef41Sopenharmony_ci if (range->IsEmpty() || range->Start() > position) { 20821cb0ef41Sopenharmony_ci // Can happen if there is a definition without use. 20831cb0ef41Sopenharmony_ci range->AddUseInterval(position, position.NextStart(), allocation_zone(), 20841cb0ef41Sopenharmony_ci data()->is_trace_alloc()); 20851cb0ef41Sopenharmony_ci range->AddUsePosition(NewUsePosition(position.NextStart()), 20861cb0ef41Sopenharmony_ci data()->is_trace_alloc()); 20871cb0ef41Sopenharmony_ci } else { 20881cb0ef41Sopenharmony_ci range->ShortenTo(position, data()->is_trace_alloc()); 20891cb0ef41Sopenharmony_ci } 20901cb0ef41Sopenharmony_ci if (!operand->IsUnallocated()) return nullptr; 20911cb0ef41Sopenharmony_ci UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); 20921cb0ef41Sopenharmony_ci UsePosition* use_pos = 20931cb0ef41Sopenharmony_ci NewUsePosition(position, unalloc_operand, hint, hint_type); 20941cb0ef41Sopenharmony_ci range->AddUsePosition(use_pos, data()->is_trace_alloc()); 20951cb0ef41Sopenharmony_ci return use_pos; 20961cb0ef41Sopenharmony_ci} 20971cb0ef41Sopenharmony_ci 20981cb0ef41Sopenharmony_ciUsePosition* LiveRangeBuilder::Use(LifetimePosition block_start, 20991cb0ef41Sopenharmony_ci LifetimePosition position, 21001cb0ef41Sopenharmony_ci InstructionOperand* operand, void* hint, 21011cb0ef41Sopenharmony_ci UsePositionHintType hint_type, 21021cb0ef41Sopenharmony_ci SpillMode spill_mode) { 21031cb0ef41Sopenharmony_ci TopLevelLiveRange* range = LiveRangeFor(operand, spill_mode); 21041cb0ef41Sopenharmony_ci if (range == nullptr) return nullptr; 21051cb0ef41Sopenharmony_ci UsePosition* use_pos = nullptr; 21061cb0ef41Sopenharmony_ci if (operand->IsUnallocated()) { 21071cb0ef41Sopenharmony_ci UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); 21081cb0ef41Sopenharmony_ci use_pos = NewUsePosition(position, unalloc_operand, hint, hint_type); 21091cb0ef41Sopenharmony_ci range->AddUsePosition(use_pos, data()->is_trace_alloc()); 21101cb0ef41Sopenharmony_ci } 21111cb0ef41Sopenharmony_ci range->AddUseInterval(block_start, position, allocation_zone(), 21121cb0ef41Sopenharmony_ci data()->is_trace_alloc()); 21131cb0ef41Sopenharmony_ci return use_pos; 21141cb0ef41Sopenharmony_ci} 21151cb0ef41Sopenharmony_ci 21161cb0ef41Sopenharmony_civoid LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, 21171cb0ef41Sopenharmony_ci BitVector* live) { 21181cb0ef41Sopenharmony_ci int block_start = block->first_instruction_index(); 21191cb0ef41Sopenharmony_ci LifetimePosition block_start_position = 21201cb0ef41Sopenharmony_ci LifetimePosition::GapFromInstructionIndex(block_start); 21211cb0ef41Sopenharmony_ci bool fixed_float_live_ranges = false; 21221cb0ef41Sopenharmony_ci bool fixed_simd128_live_ranges = false; 21231cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine) { 21241cb0ef41Sopenharmony_ci int mask = data()->code()->representation_mask(); 21251cb0ef41Sopenharmony_ci fixed_float_live_ranges = (mask & kFloat32Bit) != 0; 21261cb0ef41Sopenharmony_ci fixed_simd128_live_ranges = (mask & kSimd128Bit) != 0; 21271cb0ef41Sopenharmony_ci } else if (kFPAliasing == AliasingKind::kIndependent) { 21281cb0ef41Sopenharmony_ci int mask = data()->code()->representation_mask(); 21291cb0ef41Sopenharmony_ci fixed_simd128_live_ranges = (mask & kSimd128Bit) != 0; 21301cb0ef41Sopenharmony_ci } 21311cb0ef41Sopenharmony_ci SpillMode spill_mode = SpillModeForBlock(block); 21321cb0ef41Sopenharmony_ci 21331cb0ef41Sopenharmony_ci for (int index = block->last_instruction_index(); index >= block_start; 21341cb0ef41Sopenharmony_ci index--) { 21351cb0ef41Sopenharmony_ci LifetimePosition curr_position = 21361cb0ef41Sopenharmony_ci LifetimePosition::InstructionFromInstructionIndex(index); 21371cb0ef41Sopenharmony_ci Instruction* instr = code()->InstructionAt(index); 21381cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(instr); 21391cb0ef41Sopenharmony_ci DCHECK(curr_position.IsInstructionPosition()); 21401cb0ef41Sopenharmony_ci // Process output, inputs, and temps of this instruction. 21411cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->OutputCount(); i++) { 21421cb0ef41Sopenharmony_ci InstructionOperand* output = instr->OutputAt(i); 21431cb0ef41Sopenharmony_ci if (output->IsUnallocated()) { 21441cb0ef41Sopenharmony_ci // Unsupported. 21451cb0ef41Sopenharmony_ci DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy()); 21461cb0ef41Sopenharmony_ci int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); 21471cb0ef41Sopenharmony_ci live->Remove(out_vreg); 21481cb0ef41Sopenharmony_ci } else if (output->IsConstant()) { 21491cb0ef41Sopenharmony_ci int out_vreg = ConstantOperand::cast(output)->virtual_register(); 21501cb0ef41Sopenharmony_ci live->Remove(out_vreg); 21511cb0ef41Sopenharmony_ci } 21521cb0ef41Sopenharmony_ci if (block->IsHandler() && index == block_start && output->IsAllocated() && 21531cb0ef41Sopenharmony_ci output->IsRegister() && 21541cb0ef41Sopenharmony_ci AllocatedOperand::cast(output)->GetRegister() == 21551cb0ef41Sopenharmony_ci v8::internal::kReturnRegister0) { 21561cb0ef41Sopenharmony_ci // The register defined here is blocked from gap start - it is the 21571cb0ef41Sopenharmony_ci // exception value. 21581cb0ef41Sopenharmony_ci // TODO(mtrofin): should we explore an explicit opcode for 21591cb0ef41Sopenharmony_ci // the first instruction in the handler? 21601cb0ef41Sopenharmony_ci Define(LifetimePosition::GapFromInstructionIndex(index), output, 21611cb0ef41Sopenharmony_ci spill_mode); 21621cb0ef41Sopenharmony_ci } else { 21631cb0ef41Sopenharmony_ci Define(curr_position, output, spill_mode); 21641cb0ef41Sopenharmony_ci } 21651cb0ef41Sopenharmony_ci } 21661cb0ef41Sopenharmony_ci 21671cb0ef41Sopenharmony_ci if (instr->ClobbersRegisters()) { 21681cb0ef41Sopenharmony_ci for (int i = 0; i < config()->num_allocatable_general_registers(); ++i) { 21691cb0ef41Sopenharmony_ci // Create a UseInterval at this instruction for all fixed registers, 21701cb0ef41Sopenharmony_ci // (including the instruction outputs). Adding another UseInterval here 21711cb0ef41Sopenharmony_ci // is OK because AddUseInterval will just merge it with the existing 21721cb0ef41Sopenharmony_ci // one at the end of the range. 21731cb0ef41Sopenharmony_ci int code = config()->GetAllocatableGeneralCode(i); 21741cb0ef41Sopenharmony_ci TopLevelLiveRange* range = FixedLiveRangeFor(code, spill_mode); 21751cb0ef41Sopenharmony_ci range->AddUseInterval(curr_position, curr_position.End(), 21761cb0ef41Sopenharmony_ci allocation_zone(), data()->is_trace_alloc()); 21771cb0ef41Sopenharmony_ci } 21781cb0ef41Sopenharmony_ci } 21791cb0ef41Sopenharmony_ci 21801cb0ef41Sopenharmony_ci if (instr->ClobbersDoubleRegisters()) { 21811cb0ef41Sopenharmony_ci for (int i = 0; i < config()->num_allocatable_double_registers(); ++i) { 21821cb0ef41Sopenharmony_ci // Add a UseInterval for all DoubleRegisters. See comment above for 21831cb0ef41Sopenharmony_ci // general registers. 21841cb0ef41Sopenharmony_ci int code = config()->GetAllocatableDoubleCode(i); 21851cb0ef41Sopenharmony_ci TopLevelLiveRange* range = FixedFPLiveRangeFor( 21861cb0ef41Sopenharmony_ci code, MachineRepresentation::kFloat64, spill_mode); 21871cb0ef41Sopenharmony_ci range->AddUseInterval(curr_position, curr_position.End(), 21881cb0ef41Sopenharmony_ci allocation_zone(), data()->is_trace_alloc()); 21891cb0ef41Sopenharmony_ci } 21901cb0ef41Sopenharmony_ci // Clobber fixed float registers on archs with non-simple aliasing. 21911cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine) { 21921cb0ef41Sopenharmony_ci if (fixed_float_live_ranges) { 21931cb0ef41Sopenharmony_ci for (int i = 0; i < config()->num_allocatable_float_registers(); 21941cb0ef41Sopenharmony_ci ++i) { 21951cb0ef41Sopenharmony_ci // Add a UseInterval for all FloatRegisters. See comment above for 21961cb0ef41Sopenharmony_ci // general registers. 21971cb0ef41Sopenharmony_ci int code = config()->GetAllocatableFloatCode(i); 21981cb0ef41Sopenharmony_ci TopLevelLiveRange* range = FixedFPLiveRangeFor( 21991cb0ef41Sopenharmony_ci code, MachineRepresentation::kFloat32, spill_mode); 22001cb0ef41Sopenharmony_ci range->AddUseInterval(curr_position, curr_position.End(), 22011cb0ef41Sopenharmony_ci allocation_zone(), data()->is_trace_alloc()); 22021cb0ef41Sopenharmony_ci } 22031cb0ef41Sopenharmony_ci } 22041cb0ef41Sopenharmony_ci if (fixed_simd128_live_ranges) { 22051cb0ef41Sopenharmony_ci for (int i = 0; i < config()->num_allocatable_simd128_registers(); 22061cb0ef41Sopenharmony_ci ++i) { 22071cb0ef41Sopenharmony_ci int code = config()->GetAllocatableSimd128Code(i); 22081cb0ef41Sopenharmony_ci TopLevelLiveRange* range = FixedFPLiveRangeFor( 22091cb0ef41Sopenharmony_ci code, MachineRepresentation::kSimd128, spill_mode); 22101cb0ef41Sopenharmony_ci range->AddUseInterval(curr_position, curr_position.End(), 22111cb0ef41Sopenharmony_ci allocation_zone(), data()->is_trace_alloc()); 22121cb0ef41Sopenharmony_ci } 22131cb0ef41Sopenharmony_ci } 22141cb0ef41Sopenharmony_ci } else if (kFPAliasing == AliasingKind::kIndependent) { 22151cb0ef41Sopenharmony_ci if (fixed_simd128_live_ranges) { 22161cb0ef41Sopenharmony_ci for (int i = 0; i < config()->num_allocatable_simd128_registers(); 22171cb0ef41Sopenharmony_ci ++i) { 22181cb0ef41Sopenharmony_ci int code = config()->GetAllocatableSimd128Code(i); 22191cb0ef41Sopenharmony_ci TopLevelLiveRange* range = 22201cb0ef41Sopenharmony_ci FixedSIMD128LiveRangeFor(code, spill_mode); 22211cb0ef41Sopenharmony_ci range->AddUseInterval(curr_position, curr_position.End(), 22221cb0ef41Sopenharmony_ci allocation_zone(), data()->is_trace_alloc()); 22231cb0ef41Sopenharmony_ci } 22241cb0ef41Sopenharmony_ci } 22251cb0ef41Sopenharmony_ci } 22261cb0ef41Sopenharmony_ci } 22271cb0ef41Sopenharmony_ci 22281cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->InputCount(); i++) { 22291cb0ef41Sopenharmony_ci InstructionOperand* input = instr->InputAt(i); 22301cb0ef41Sopenharmony_ci if (input->IsImmediate()) { 22311cb0ef41Sopenharmony_ci continue; // Ignore immediates. 22321cb0ef41Sopenharmony_ci } 22331cb0ef41Sopenharmony_ci LifetimePosition use_pos; 22341cb0ef41Sopenharmony_ci if (input->IsUnallocated() && 22351cb0ef41Sopenharmony_ci UnallocatedOperand::cast(input)->IsUsedAtStart()) { 22361cb0ef41Sopenharmony_ci use_pos = curr_position; 22371cb0ef41Sopenharmony_ci } else { 22381cb0ef41Sopenharmony_ci use_pos = curr_position.End(); 22391cb0ef41Sopenharmony_ci } 22401cb0ef41Sopenharmony_ci 22411cb0ef41Sopenharmony_ci if (input->IsUnallocated()) { 22421cb0ef41Sopenharmony_ci UnallocatedOperand* unalloc = UnallocatedOperand::cast(input); 22431cb0ef41Sopenharmony_ci int vreg = unalloc->virtual_register(); 22441cb0ef41Sopenharmony_ci live->Add(vreg); 22451cb0ef41Sopenharmony_ci if (unalloc->HasSlotPolicy()) { 22461cb0ef41Sopenharmony_ci data()->GetOrCreateLiveRangeFor(vreg)->register_slot_use( 22471cb0ef41Sopenharmony_ci block->IsDeferred() 22481cb0ef41Sopenharmony_ci ? TopLevelLiveRange::SlotUseKind::kDeferredSlotUse 22491cb0ef41Sopenharmony_ci : TopLevelLiveRange::SlotUseKind::kGeneralSlotUse); 22501cb0ef41Sopenharmony_ci } 22511cb0ef41Sopenharmony_ci } 22521cb0ef41Sopenharmony_ci Use(block_start_position, use_pos, input, spill_mode); 22531cb0ef41Sopenharmony_ci } 22541cb0ef41Sopenharmony_ci 22551cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->TempCount(); i++) { 22561cb0ef41Sopenharmony_ci InstructionOperand* temp = instr->TempAt(i); 22571cb0ef41Sopenharmony_ci // Unsupported. 22581cb0ef41Sopenharmony_ci DCHECK_IMPLIES(temp->IsUnallocated(), 22591cb0ef41Sopenharmony_ci !UnallocatedOperand::cast(temp)->HasSlotPolicy()); 22601cb0ef41Sopenharmony_ci if (instr->ClobbersTemps()) { 22611cb0ef41Sopenharmony_ci if (temp->IsRegister()) continue; 22621cb0ef41Sopenharmony_ci if (temp->IsUnallocated()) { 22631cb0ef41Sopenharmony_ci UnallocatedOperand* temp_unalloc = UnallocatedOperand::cast(temp); 22641cb0ef41Sopenharmony_ci if (temp_unalloc->HasFixedPolicy()) { 22651cb0ef41Sopenharmony_ci continue; 22661cb0ef41Sopenharmony_ci } 22671cb0ef41Sopenharmony_ci } 22681cb0ef41Sopenharmony_ci } 22691cb0ef41Sopenharmony_ci Use(block_start_position, curr_position.End(), temp, spill_mode); 22701cb0ef41Sopenharmony_ci Define(curr_position, temp, spill_mode); 22711cb0ef41Sopenharmony_ci } 22721cb0ef41Sopenharmony_ci 22731cb0ef41Sopenharmony_ci // Process the moves of the instruction's gaps, making their sources live. 22741cb0ef41Sopenharmony_ci const Instruction::GapPosition kPositions[] = {Instruction::END, 22751cb0ef41Sopenharmony_ci Instruction::START}; 22761cb0ef41Sopenharmony_ci curr_position = curr_position.PrevStart(); 22771cb0ef41Sopenharmony_ci DCHECK(curr_position.IsGapPosition()); 22781cb0ef41Sopenharmony_ci for (const Instruction::GapPosition& position : kPositions) { 22791cb0ef41Sopenharmony_ci ParallelMove* move = instr->GetParallelMove(position); 22801cb0ef41Sopenharmony_ci if (move == nullptr) continue; 22811cb0ef41Sopenharmony_ci if (position == Instruction::END) { 22821cb0ef41Sopenharmony_ci curr_position = curr_position.End(); 22831cb0ef41Sopenharmony_ci } else { 22841cb0ef41Sopenharmony_ci curr_position = curr_position.Start(); 22851cb0ef41Sopenharmony_ci } 22861cb0ef41Sopenharmony_ci for (MoveOperands* cur : *move) { 22871cb0ef41Sopenharmony_ci InstructionOperand& from = cur->source(); 22881cb0ef41Sopenharmony_ci InstructionOperand& to = cur->destination(); 22891cb0ef41Sopenharmony_ci void* hint = &to; 22901cb0ef41Sopenharmony_ci UsePositionHintType hint_type = UsePosition::HintTypeForOperand(to); 22911cb0ef41Sopenharmony_ci UsePosition* to_use = nullptr; 22921cb0ef41Sopenharmony_ci int phi_vreg = -1; 22931cb0ef41Sopenharmony_ci if (to.IsUnallocated()) { 22941cb0ef41Sopenharmony_ci int to_vreg = UnallocatedOperand::cast(to).virtual_register(); 22951cb0ef41Sopenharmony_ci TopLevelLiveRange* to_range = 22961cb0ef41Sopenharmony_ci data()->GetOrCreateLiveRangeFor(to_vreg); 22971cb0ef41Sopenharmony_ci if (to_range->is_phi()) { 22981cb0ef41Sopenharmony_ci phi_vreg = to_vreg; 22991cb0ef41Sopenharmony_ci if (to_range->is_non_loop_phi()) { 23001cb0ef41Sopenharmony_ci hint = to_range->current_hint_position(); 23011cb0ef41Sopenharmony_ci hint_type = hint == nullptr ? UsePositionHintType::kNone 23021cb0ef41Sopenharmony_ci : UsePositionHintType::kUsePos; 23031cb0ef41Sopenharmony_ci } else { 23041cb0ef41Sopenharmony_ci hint_type = UsePositionHintType::kPhi; 23051cb0ef41Sopenharmony_ci hint = data()->GetPhiMapValueFor(to_vreg); 23061cb0ef41Sopenharmony_ci } 23071cb0ef41Sopenharmony_ci } else { 23081cb0ef41Sopenharmony_ci if (live->Contains(to_vreg)) { 23091cb0ef41Sopenharmony_ci to_use = 23101cb0ef41Sopenharmony_ci Define(curr_position, &to, &from, 23111cb0ef41Sopenharmony_ci UsePosition::HintTypeForOperand(from), spill_mode); 23121cb0ef41Sopenharmony_ci live->Remove(to_vreg); 23131cb0ef41Sopenharmony_ci } else { 23141cb0ef41Sopenharmony_ci cur->Eliminate(); 23151cb0ef41Sopenharmony_ci continue; 23161cb0ef41Sopenharmony_ci } 23171cb0ef41Sopenharmony_ci } 23181cb0ef41Sopenharmony_ci } else { 23191cb0ef41Sopenharmony_ci Define(curr_position, &to, spill_mode); 23201cb0ef41Sopenharmony_ci } 23211cb0ef41Sopenharmony_ci UsePosition* from_use = Use(block_start_position, curr_position, &from, 23221cb0ef41Sopenharmony_ci hint, hint_type, spill_mode); 23231cb0ef41Sopenharmony_ci // Mark range live. 23241cb0ef41Sopenharmony_ci if (from.IsUnallocated()) { 23251cb0ef41Sopenharmony_ci live->Add(UnallocatedOperand::cast(from).virtual_register()); 23261cb0ef41Sopenharmony_ci } 23271cb0ef41Sopenharmony_ci // When the value is moved to a register to meet input constraints, 23281cb0ef41Sopenharmony_ci // we should consider this value use similar as a register use in the 23291cb0ef41Sopenharmony_ci // backward spilling heuristics, even though this value use is not 23301cb0ef41Sopenharmony_ci // register benefical at the AllocateBlockedReg stage. 23311cb0ef41Sopenharmony_ci if (to.IsAnyRegister() || 23321cb0ef41Sopenharmony_ci (to.IsUnallocated() && 23331cb0ef41Sopenharmony_ci UnallocatedOperand::cast(&to)->HasRegisterPolicy())) { 23341cb0ef41Sopenharmony_ci from_use->set_spill_detrimental(); 23351cb0ef41Sopenharmony_ci } 23361cb0ef41Sopenharmony_ci // Resolve use position hints just created. 23371cb0ef41Sopenharmony_ci if (to_use != nullptr && from_use != nullptr) { 23381cb0ef41Sopenharmony_ci to_use->ResolveHint(from_use); 23391cb0ef41Sopenharmony_ci from_use->ResolveHint(to_use); 23401cb0ef41Sopenharmony_ci } 23411cb0ef41Sopenharmony_ci DCHECK_IMPLIES(to_use != nullptr, to_use->IsResolved()); 23421cb0ef41Sopenharmony_ci DCHECK_IMPLIES(from_use != nullptr, from_use->IsResolved()); 23431cb0ef41Sopenharmony_ci // Potentially resolve phi hint. 23441cb0ef41Sopenharmony_ci if (phi_vreg != -1) ResolvePhiHint(&from, from_use); 23451cb0ef41Sopenharmony_ci } 23461cb0ef41Sopenharmony_ci } 23471cb0ef41Sopenharmony_ci } 23481cb0ef41Sopenharmony_ci} 23491cb0ef41Sopenharmony_ci 23501cb0ef41Sopenharmony_civoid LiveRangeBuilder::ProcessPhis(const InstructionBlock* block, 23511cb0ef41Sopenharmony_ci BitVector* live) { 23521cb0ef41Sopenharmony_ci for (PhiInstruction* phi : block->phis()) { 23531cb0ef41Sopenharmony_ci // The live range interval already ends at the first instruction of the 23541cb0ef41Sopenharmony_ci // block. 23551cb0ef41Sopenharmony_ci int phi_vreg = phi->virtual_register(); 23561cb0ef41Sopenharmony_ci live->Remove(phi_vreg); 23571cb0ef41Sopenharmony_ci // Select a hint from a predecessor block that precedes this block in the 23581cb0ef41Sopenharmony_ci // rpo order. In order of priority: 23591cb0ef41Sopenharmony_ci // - Avoid hints from deferred blocks. 23601cb0ef41Sopenharmony_ci // - Prefer hints from allocated (or explicit) operands. 23611cb0ef41Sopenharmony_ci // - Prefer hints from empty blocks (containing just parallel moves and a 23621cb0ef41Sopenharmony_ci // jump). In these cases, if we can elide the moves, the jump threader 23631cb0ef41Sopenharmony_ci // is likely to be able to elide the jump. 23641cb0ef41Sopenharmony_ci // The enforcement of hinting in rpo order is required because hint 23651cb0ef41Sopenharmony_ci // resolution that happens later in the compiler pipeline visits 23661cb0ef41Sopenharmony_ci // instructions in reverse rpo order, relying on the fact that phis are 23671cb0ef41Sopenharmony_ci // encountered before their hints. 23681cb0ef41Sopenharmony_ci InstructionOperand* hint = nullptr; 23691cb0ef41Sopenharmony_ci int hint_preference = 0; 23701cb0ef41Sopenharmony_ci 23711cb0ef41Sopenharmony_ci // The cost of hinting increases with the number of predecessors. At the 23721cb0ef41Sopenharmony_ci // same time, the typical benefit decreases, since this hinting only 23731cb0ef41Sopenharmony_ci // optimises the execution path through one predecessor. A limit of 2 is 23741cb0ef41Sopenharmony_ci // sufficient to hit the common if/else pattern. 23751cb0ef41Sopenharmony_ci int predecessor_limit = 2; 23761cb0ef41Sopenharmony_ci 23771cb0ef41Sopenharmony_ci for (RpoNumber predecessor : block->predecessors()) { 23781cb0ef41Sopenharmony_ci const InstructionBlock* predecessor_block = 23791cb0ef41Sopenharmony_ci code()->InstructionBlockAt(predecessor); 23801cb0ef41Sopenharmony_ci DCHECK_EQ(predecessor_block->rpo_number(), predecessor); 23811cb0ef41Sopenharmony_ci 23821cb0ef41Sopenharmony_ci // Only take hints from earlier rpo numbers. 23831cb0ef41Sopenharmony_ci if (predecessor >= block->rpo_number()) continue; 23841cb0ef41Sopenharmony_ci 23851cb0ef41Sopenharmony_ci // Look up the predecessor instruction. 23861cb0ef41Sopenharmony_ci const Instruction* predecessor_instr = 23871cb0ef41Sopenharmony_ci GetLastInstruction(code(), predecessor_block); 23881cb0ef41Sopenharmony_ci InstructionOperand* predecessor_hint = nullptr; 23891cb0ef41Sopenharmony_ci // Phis are assigned in the END position of the last instruction in each 23901cb0ef41Sopenharmony_ci // predecessor block. 23911cb0ef41Sopenharmony_ci for (MoveOperands* move : 23921cb0ef41Sopenharmony_ci *predecessor_instr->GetParallelMove(Instruction::END)) { 23931cb0ef41Sopenharmony_ci InstructionOperand& to = move->destination(); 23941cb0ef41Sopenharmony_ci if (to.IsUnallocated() && 23951cb0ef41Sopenharmony_ci UnallocatedOperand::cast(to).virtual_register() == phi_vreg) { 23961cb0ef41Sopenharmony_ci predecessor_hint = &move->source(); 23971cb0ef41Sopenharmony_ci break; 23981cb0ef41Sopenharmony_ci } 23991cb0ef41Sopenharmony_ci } 24001cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(predecessor_hint); 24011cb0ef41Sopenharmony_ci 24021cb0ef41Sopenharmony_ci // For each predecessor, generate a score according to the priorities 24031cb0ef41Sopenharmony_ci // described above, and pick the best one. Flags in higher-order bits have 24041cb0ef41Sopenharmony_ci // a higher priority than those in lower-order bits. 24051cb0ef41Sopenharmony_ci int predecessor_hint_preference = 0; 24061cb0ef41Sopenharmony_ci const int kNotDeferredBlockPreference = (1 << 2); 24071cb0ef41Sopenharmony_ci const int kMoveIsAllocatedPreference = (1 << 1); 24081cb0ef41Sopenharmony_ci const int kBlockIsEmptyPreference = (1 << 0); 24091cb0ef41Sopenharmony_ci 24101cb0ef41Sopenharmony_ci // - Avoid hints from deferred blocks. 24111cb0ef41Sopenharmony_ci if (!predecessor_block->IsDeferred()) { 24121cb0ef41Sopenharmony_ci predecessor_hint_preference |= kNotDeferredBlockPreference; 24131cb0ef41Sopenharmony_ci } 24141cb0ef41Sopenharmony_ci 24151cb0ef41Sopenharmony_ci // - Prefer hints from allocated operands. 24161cb0ef41Sopenharmony_ci // 24171cb0ef41Sopenharmony_ci // Already-allocated operands are typically assigned using the parallel 24181cb0ef41Sopenharmony_ci // moves on the last instruction. For example: 24191cb0ef41Sopenharmony_ci // 24201cb0ef41Sopenharmony_ci // gap (v101 = [x0|R|w32]) (v100 = v101) 24211cb0ef41Sopenharmony_ci // ArchJmp 24221cb0ef41Sopenharmony_ci // ... 24231cb0ef41Sopenharmony_ci // phi: v100 = v101 v102 24241cb0ef41Sopenharmony_ci // 24251cb0ef41Sopenharmony_ci // We have already found the END move, so look for a matching START move 24261cb0ef41Sopenharmony_ci // from an allocated operand. 24271cb0ef41Sopenharmony_ci // 24281cb0ef41Sopenharmony_ci // Note that we cannot simply look up data()->live_ranges()[vreg] here 24291cb0ef41Sopenharmony_ci // because the live ranges are still being built when this function is 24301cb0ef41Sopenharmony_ci // called. 24311cb0ef41Sopenharmony_ci // TODO(v8): Find a way to separate hinting from live range analysis in 24321cb0ef41Sopenharmony_ci // BuildLiveRanges so that we can use the O(1) live-range look-up. 24331cb0ef41Sopenharmony_ci auto moves = predecessor_instr->GetParallelMove(Instruction::START); 24341cb0ef41Sopenharmony_ci if (moves != nullptr) { 24351cb0ef41Sopenharmony_ci for (MoveOperands* move : *moves) { 24361cb0ef41Sopenharmony_ci InstructionOperand& to = move->destination(); 24371cb0ef41Sopenharmony_ci if (predecessor_hint->Equals(to)) { 24381cb0ef41Sopenharmony_ci if (move->source().IsAllocated()) { 24391cb0ef41Sopenharmony_ci predecessor_hint_preference |= kMoveIsAllocatedPreference; 24401cb0ef41Sopenharmony_ci } 24411cb0ef41Sopenharmony_ci break; 24421cb0ef41Sopenharmony_ci } 24431cb0ef41Sopenharmony_ci } 24441cb0ef41Sopenharmony_ci } 24451cb0ef41Sopenharmony_ci 24461cb0ef41Sopenharmony_ci // - Prefer hints from empty blocks. 24471cb0ef41Sopenharmony_ci if (predecessor_block->last_instruction_index() == 24481cb0ef41Sopenharmony_ci predecessor_block->first_instruction_index()) { 24491cb0ef41Sopenharmony_ci predecessor_hint_preference |= kBlockIsEmptyPreference; 24501cb0ef41Sopenharmony_ci } 24511cb0ef41Sopenharmony_ci 24521cb0ef41Sopenharmony_ci if ((hint == nullptr) || 24531cb0ef41Sopenharmony_ci (predecessor_hint_preference > hint_preference)) { 24541cb0ef41Sopenharmony_ci // Take the hint from this predecessor. 24551cb0ef41Sopenharmony_ci hint = predecessor_hint; 24561cb0ef41Sopenharmony_ci hint_preference = predecessor_hint_preference; 24571cb0ef41Sopenharmony_ci } 24581cb0ef41Sopenharmony_ci 24591cb0ef41Sopenharmony_ci if (--predecessor_limit <= 0) break; 24601cb0ef41Sopenharmony_ci } 24611cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(hint); 24621cb0ef41Sopenharmony_ci 24631cb0ef41Sopenharmony_ci LifetimePosition block_start = LifetimePosition::GapFromInstructionIndex( 24641cb0ef41Sopenharmony_ci block->first_instruction_index()); 24651cb0ef41Sopenharmony_ci UsePosition* use_pos = Define(block_start, &phi->output(), hint, 24661cb0ef41Sopenharmony_ci UsePosition::HintTypeForOperand(*hint), 24671cb0ef41Sopenharmony_ci SpillModeForBlock(block)); 24681cb0ef41Sopenharmony_ci MapPhiHint(hint, use_pos); 24691cb0ef41Sopenharmony_ci } 24701cb0ef41Sopenharmony_ci} 24711cb0ef41Sopenharmony_ci 24721cb0ef41Sopenharmony_civoid LiveRangeBuilder::ProcessLoopHeader(const InstructionBlock* block, 24731cb0ef41Sopenharmony_ci BitVector* live) { 24741cb0ef41Sopenharmony_ci DCHECK(block->IsLoopHeader()); 24751cb0ef41Sopenharmony_ci // Add a live range stretching from the first loop instruction to the last 24761cb0ef41Sopenharmony_ci // for each value live on entry to the header. 24771cb0ef41Sopenharmony_ci LifetimePosition start = LifetimePosition::GapFromInstructionIndex( 24781cb0ef41Sopenharmony_ci block->first_instruction_index()); 24791cb0ef41Sopenharmony_ci LifetimePosition end = LifetimePosition::GapFromInstructionIndex( 24801cb0ef41Sopenharmony_ci code()->LastLoopInstructionIndex(block)) 24811cb0ef41Sopenharmony_ci .NextFullStart(); 24821cb0ef41Sopenharmony_ci for (int operand_index : *live) { 24831cb0ef41Sopenharmony_ci TopLevelLiveRange* range = data()->GetOrCreateLiveRangeFor(operand_index); 24841cb0ef41Sopenharmony_ci range->EnsureInterval(start, end, allocation_zone(), 24851cb0ef41Sopenharmony_ci data()->is_trace_alloc()); 24861cb0ef41Sopenharmony_ci } 24871cb0ef41Sopenharmony_ci // Insert all values into the live in sets of all blocks in the loop. 24881cb0ef41Sopenharmony_ci for (int i = block->rpo_number().ToInt() + 1; i < block->loop_end().ToInt(); 24891cb0ef41Sopenharmony_ci ++i) { 24901cb0ef41Sopenharmony_ci live_in_sets()[i]->Union(*live); 24911cb0ef41Sopenharmony_ci } 24921cb0ef41Sopenharmony_ci} 24931cb0ef41Sopenharmony_ci 24941cb0ef41Sopenharmony_civoid LiveRangeBuilder::BuildLiveRanges() { 24951cb0ef41Sopenharmony_ci // Process the blocks in reverse order. 24961cb0ef41Sopenharmony_ci for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0; 24971cb0ef41Sopenharmony_ci --block_id) { 24981cb0ef41Sopenharmony_ci data_->tick_counter()->TickAndMaybeEnterSafepoint(); 24991cb0ef41Sopenharmony_ci InstructionBlock* block = 25001cb0ef41Sopenharmony_ci code()->InstructionBlockAt(RpoNumber::FromInt(block_id)); 25011cb0ef41Sopenharmony_ci BitVector* live = ComputeLiveOut(block, data()); 25021cb0ef41Sopenharmony_ci // Initially consider all live_out values live for the entire block. We 25031cb0ef41Sopenharmony_ci // will shorten these intervals if necessary. 25041cb0ef41Sopenharmony_ci AddInitialIntervals(block, live); 25051cb0ef41Sopenharmony_ci // Process the instructions in reverse order, generating and killing 25061cb0ef41Sopenharmony_ci // live values. 25071cb0ef41Sopenharmony_ci ProcessInstructions(block, live); 25081cb0ef41Sopenharmony_ci // All phi output operands are killed by this block. 25091cb0ef41Sopenharmony_ci ProcessPhis(block, live); 25101cb0ef41Sopenharmony_ci // Now live is live_in for this block except not including values live 25111cb0ef41Sopenharmony_ci // out on backward successor edges. 25121cb0ef41Sopenharmony_ci if (block->IsLoopHeader()) ProcessLoopHeader(block, live); 25131cb0ef41Sopenharmony_ci live_in_sets()[block_id] = live; 25141cb0ef41Sopenharmony_ci } 25151cb0ef41Sopenharmony_ci // Postprocess the ranges. 25161cb0ef41Sopenharmony_ci const size_t live_ranges_size = data()->live_ranges().size(); 25171cb0ef41Sopenharmony_ci for (TopLevelLiveRange* range : data()->live_ranges()) { 25181cb0ef41Sopenharmony_ci data_->tick_counter()->TickAndMaybeEnterSafepoint(); 25191cb0ef41Sopenharmony_ci CHECK_EQ(live_ranges_size, 25201cb0ef41Sopenharmony_ci data()->live_ranges().size()); // TODO(neis): crbug.com/831822 25211cb0ef41Sopenharmony_ci if (range == nullptr) continue; 25221cb0ef41Sopenharmony_ci // Give slots to all ranges with a non fixed slot use. 25231cb0ef41Sopenharmony_ci if (range->has_slot_use() && range->HasNoSpillType()) { 25241cb0ef41Sopenharmony_ci SpillMode spill_mode = 25251cb0ef41Sopenharmony_ci range->slot_use_kind() == 25261cb0ef41Sopenharmony_ci TopLevelLiveRange::SlotUseKind::kDeferredSlotUse 25271cb0ef41Sopenharmony_ci ? SpillMode::kSpillDeferred 25281cb0ef41Sopenharmony_ci : SpillMode::kSpillAtDefinition; 25291cb0ef41Sopenharmony_ci data()->AssignSpillRangeToLiveRange(range, spill_mode); 25301cb0ef41Sopenharmony_ci } 25311cb0ef41Sopenharmony_ci // TODO(bmeurer): This is a horrible hack to make sure that for constant 25321cb0ef41Sopenharmony_ci // live ranges, every use requires the constant to be in a register. 25331cb0ef41Sopenharmony_ci // Without this hack, all uses with "any" policy would get the constant 25341cb0ef41Sopenharmony_ci // operand assigned. 25351cb0ef41Sopenharmony_ci if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { 25361cb0ef41Sopenharmony_ci for (UsePosition* pos = range->first_pos(); pos != nullptr; 25371cb0ef41Sopenharmony_ci pos = pos->next()) { 25381cb0ef41Sopenharmony_ci if (pos->type() == UsePositionType::kRequiresSlot || 25391cb0ef41Sopenharmony_ci pos->type() == UsePositionType::kRegisterOrSlotOrConstant) { 25401cb0ef41Sopenharmony_ci continue; 25411cb0ef41Sopenharmony_ci } 25421cb0ef41Sopenharmony_ci UsePositionType new_type = UsePositionType::kRegisterOrSlot; 25431cb0ef41Sopenharmony_ci // Can't mark phis as needing a register. 25441cb0ef41Sopenharmony_ci if (!pos->pos().IsGapPosition()) { 25451cb0ef41Sopenharmony_ci new_type = UsePositionType::kRequiresRegister; 25461cb0ef41Sopenharmony_ci } 25471cb0ef41Sopenharmony_ci pos->set_type(new_type, true); 25481cb0ef41Sopenharmony_ci } 25491cb0ef41Sopenharmony_ci } 25501cb0ef41Sopenharmony_ci range->ResetCurrentHintPosition(); 25511cb0ef41Sopenharmony_ci } 25521cb0ef41Sopenharmony_ci for (auto preassigned : data()->preassigned_slot_ranges()) { 25531cb0ef41Sopenharmony_ci TopLevelLiveRange* range = preassigned.first; 25541cb0ef41Sopenharmony_ci int slot_id = preassigned.second; 25551cb0ef41Sopenharmony_ci SpillRange* spill = range->HasSpillRange() 25561cb0ef41Sopenharmony_ci ? range->GetSpillRange() 25571cb0ef41Sopenharmony_ci : data()->AssignSpillRangeToLiveRange( 25581cb0ef41Sopenharmony_ci range, SpillMode::kSpillAtDefinition); 25591cb0ef41Sopenharmony_ci spill->set_assigned_slot(slot_id); 25601cb0ef41Sopenharmony_ci } 25611cb0ef41Sopenharmony_ci#ifdef DEBUG 25621cb0ef41Sopenharmony_ci Verify(); 25631cb0ef41Sopenharmony_ci#endif 25641cb0ef41Sopenharmony_ci} 25651cb0ef41Sopenharmony_ci 25661cb0ef41Sopenharmony_civoid LiveRangeBuilder::MapPhiHint(InstructionOperand* operand, 25671cb0ef41Sopenharmony_ci UsePosition* use_pos) { 25681cb0ef41Sopenharmony_ci DCHECK(!use_pos->IsResolved()); 25691cb0ef41Sopenharmony_ci auto res = phi_hints_.insert(std::make_pair(operand, use_pos)); 25701cb0ef41Sopenharmony_ci DCHECK(res.second); 25711cb0ef41Sopenharmony_ci USE(res); 25721cb0ef41Sopenharmony_ci} 25731cb0ef41Sopenharmony_ci 25741cb0ef41Sopenharmony_civoid LiveRangeBuilder::ResolvePhiHint(InstructionOperand* operand, 25751cb0ef41Sopenharmony_ci UsePosition* use_pos) { 25761cb0ef41Sopenharmony_ci auto it = phi_hints_.find(operand); 25771cb0ef41Sopenharmony_ci if (it == phi_hints_.end()) return; 25781cb0ef41Sopenharmony_ci DCHECK(!it->second->IsResolved()); 25791cb0ef41Sopenharmony_ci it->second->ResolveHint(use_pos); 25801cb0ef41Sopenharmony_ci} 25811cb0ef41Sopenharmony_ci 25821cb0ef41Sopenharmony_civoid LiveRangeBuilder::Verify() const { 25831cb0ef41Sopenharmony_ci for (auto& hint : phi_hints_) { 25841cb0ef41Sopenharmony_ci CHECK(hint.second->IsResolved()); 25851cb0ef41Sopenharmony_ci } 25861cb0ef41Sopenharmony_ci for (const TopLevelLiveRange* current : data()->live_ranges()) { 25871cb0ef41Sopenharmony_ci if (current != nullptr && !current->IsEmpty()) { 25881cb0ef41Sopenharmony_ci // New LiveRanges should not be split. 25891cb0ef41Sopenharmony_ci CHECK_NULL(current->next()); 25901cb0ef41Sopenharmony_ci // General integrity check. 25911cb0ef41Sopenharmony_ci current->Verify(); 25921cb0ef41Sopenharmony_ci const UseInterval* first = current->first_interval(); 25931cb0ef41Sopenharmony_ci if (first->next() == nullptr) continue; 25941cb0ef41Sopenharmony_ci 25951cb0ef41Sopenharmony_ci // Consecutive intervals should not end and start in the same block, 25961cb0ef41Sopenharmony_ci // otherwise the intervals should have been joined, because the 25971cb0ef41Sopenharmony_ci // variable is live throughout that block. 25981cb0ef41Sopenharmony_ci CHECK(NextIntervalStartsInDifferentBlocks(first)); 25991cb0ef41Sopenharmony_ci 26001cb0ef41Sopenharmony_ci for (const UseInterval* i = first->next(); i != nullptr; i = i->next()) { 26011cb0ef41Sopenharmony_ci // Except for the first interval, the other intevals must start at 26021cb0ef41Sopenharmony_ci // a block boundary, otherwise data wouldn't flow to them. 26031cb0ef41Sopenharmony_ci CHECK(IntervalStartsAtBlockBoundary(i)); 26041cb0ef41Sopenharmony_ci // The last instruction of the predecessors of the block the interval 26051cb0ef41Sopenharmony_ci // starts must be covered by the range. 26061cb0ef41Sopenharmony_ci CHECK(IntervalPredecessorsCoveredByRange(i, current)); 26071cb0ef41Sopenharmony_ci if (i->next() != nullptr) { 26081cb0ef41Sopenharmony_ci // Check the consecutive intervals property, except for the last 26091cb0ef41Sopenharmony_ci // interval, where it doesn't apply. 26101cb0ef41Sopenharmony_ci CHECK(NextIntervalStartsInDifferentBlocks(i)); 26111cb0ef41Sopenharmony_ci } 26121cb0ef41Sopenharmony_ci } 26131cb0ef41Sopenharmony_ci } 26141cb0ef41Sopenharmony_ci } 26151cb0ef41Sopenharmony_ci} 26161cb0ef41Sopenharmony_ci 26171cb0ef41Sopenharmony_cibool LiveRangeBuilder::IntervalStartsAtBlockBoundary( 26181cb0ef41Sopenharmony_ci const UseInterval* interval) const { 26191cb0ef41Sopenharmony_ci LifetimePosition start = interval->start(); 26201cb0ef41Sopenharmony_ci if (!start.IsFullStart()) return false; 26211cb0ef41Sopenharmony_ci int instruction_index = start.ToInstructionIndex(); 26221cb0ef41Sopenharmony_ci const InstructionBlock* block = 26231cb0ef41Sopenharmony_ci data()->code()->GetInstructionBlock(instruction_index); 26241cb0ef41Sopenharmony_ci return block->first_instruction_index() == instruction_index; 26251cb0ef41Sopenharmony_ci} 26261cb0ef41Sopenharmony_ci 26271cb0ef41Sopenharmony_cibool LiveRangeBuilder::IntervalPredecessorsCoveredByRange( 26281cb0ef41Sopenharmony_ci const UseInterval* interval, const TopLevelLiveRange* range) const { 26291cb0ef41Sopenharmony_ci LifetimePosition start = interval->start(); 26301cb0ef41Sopenharmony_ci int instruction_index = start.ToInstructionIndex(); 26311cb0ef41Sopenharmony_ci const InstructionBlock* block = 26321cb0ef41Sopenharmony_ci data()->code()->GetInstructionBlock(instruction_index); 26331cb0ef41Sopenharmony_ci for (RpoNumber pred_index : block->predecessors()) { 26341cb0ef41Sopenharmony_ci const InstructionBlock* predecessor = 26351cb0ef41Sopenharmony_ci data()->code()->InstructionBlockAt(pred_index); 26361cb0ef41Sopenharmony_ci LifetimePosition last_pos = LifetimePosition::GapFromInstructionIndex( 26371cb0ef41Sopenharmony_ci predecessor->last_instruction_index()); 26381cb0ef41Sopenharmony_ci last_pos = last_pos.NextStart().End(); 26391cb0ef41Sopenharmony_ci if (!range->Covers(last_pos)) return false; 26401cb0ef41Sopenharmony_ci } 26411cb0ef41Sopenharmony_ci return true; 26421cb0ef41Sopenharmony_ci} 26431cb0ef41Sopenharmony_ci 26441cb0ef41Sopenharmony_cibool LiveRangeBuilder::NextIntervalStartsInDifferentBlocks( 26451cb0ef41Sopenharmony_ci const UseInterval* interval) const { 26461cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(interval->next()); 26471cb0ef41Sopenharmony_ci LifetimePosition end = interval->end(); 26481cb0ef41Sopenharmony_ci LifetimePosition next_start = interval->next()->start(); 26491cb0ef41Sopenharmony_ci // Since end is not covered, but the previous position is, move back a 26501cb0ef41Sopenharmony_ci // position 26511cb0ef41Sopenharmony_ci end = end.IsStart() ? end.PrevStart().End() : end.Start(); 26521cb0ef41Sopenharmony_ci int last_covered_index = end.ToInstructionIndex(); 26531cb0ef41Sopenharmony_ci const InstructionBlock* block = 26541cb0ef41Sopenharmony_ci data()->code()->GetInstructionBlock(last_covered_index); 26551cb0ef41Sopenharmony_ci const InstructionBlock* next_block = 26561cb0ef41Sopenharmony_ci data()->code()->GetInstructionBlock(next_start.ToInstructionIndex()); 26571cb0ef41Sopenharmony_ci return block->rpo_number() < next_block->rpo_number(); 26581cb0ef41Sopenharmony_ci} 26591cb0ef41Sopenharmony_ci 26601cb0ef41Sopenharmony_civoid BundleBuilder::BuildBundles() { 26611cb0ef41Sopenharmony_ci TRACE("Build bundles\n"); 26621cb0ef41Sopenharmony_ci // Process the blocks in reverse order. 26631cb0ef41Sopenharmony_ci for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0; 26641cb0ef41Sopenharmony_ci --block_id) { 26651cb0ef41Sopenharmony_ci InstructionBlock* block = 26661cb0ef41Sopenharmony_ci code()->InstructionBlockAt(RpoNumber::FromInt(block_id)); 26671cb0ef41Sopenharmony_ci TRACE("Block B%d\n", block_id); 26681cb0ef41Sopenharmony_ci for (auto phi : block->phis()) { 26691cb0ef41Sopenharmony_ci LiveRange* out_range = 26701cb0ef41Sopenharmony_ci data()->GetOrCreateLiveRangeFor(phi->virtual_register()); 26711cb0ef41Sopenharmony_ci LiveRangeBundle* out = out_range->get_bundle(); 26721cb0ef41Sopenharmony_ci if (out == nullptr) { 26731cb0ef41Sopenharmony_ci out = data()->allocation_zone()->New<LiveRangeBundle>( 26741cb0ef41Sopenharmony_ci data()->allocation_zone(), next_bundle_id_++); 26751cb0ef41Sopenharmony_ci out->TryAddRange(out_range); 26761cb0ef41Sopenharmony_ci } 26771cb0ef41Sopenharmony_ci TRACE("Processing phi for v%d with %d:%d\n", phi->virtual_register(), 26781cb0ef41Sopenharmony_ci out_range->TopLevel()->vreg(), out_range->relative_id()); 26791cb0ef41Sopenharmony_ci bool phi_interferes_with_backedge_input = false; 26801cb0ef41Sopenharmony_ci for (auto input : phi->operands()) { 26811cb0ef41Sopenharmony_ci LiveRange* input_range = data()->GetOrCreateLiveRangeFor(input); 26821cb0ef41Sopenharmony_ci TRACE("Input value v%d with range %d:%d\n", input, 26831cb0ef41Sopenharmony_ci input_range->TopLevel()->vreg(), input_range->relative_id()); 26841cb0ef41Sopenharmony_ci LiveRangeBundle* input_bundle = input_range->get_bundle(); 26851cb0ef41Sopenharmony_ci if (input_bundle != nullptr) { 26861cb0ef41Sopenharmony_ci TRACE("Merge\n"); 26871cb0ef41Sopenharmony_ci LiveRangeBundle* merged = LiveRangeBundle::TryMerge( 26881cb0ef41Sopenharmony_ci out, input_bundle, data()->is_trace_alloc()); 26891cb0ef41Sopenharmony_ci if (merged != nullptr) { 26901cb0ef41Sopenharmony_ci DCHECK_EQ(out_range->get_bundle(), merged); 26911cb0ef41Sopenharmony_ci DCHECK_EQ(input_range->get_bundle(), merged); 26921cb0ef41Sopenharmony_ci out = merged; 26931cb0ef41Sopenharmony_ci TRACE("Merged %d and %d to %d\n", phi->virtual_register(), input, 26941cb0ef41Sopenharmony_ci out->id()); 26951cb0ef41Sopenharmony_ci } else if (input_range->Start() > out_range->Start()) { 26961cb0ef41Sopenharmony_ci // We are only interested in values defined after the phi, because 26971cb0ef41Sopenharmony_ci // those are values that will go over a back-edge. 26981cb0ef41Sopenharmony_ci phi_interferes_with_backedge_input = true; 26991cb0ef41Sopenharmony_ci } 27001cb0ef41Sopenharmony_ci } else { 27011cb0ef41Sopenharmony_ci TRACE("Add\n"); 27021cb0ef41Sopenharmony_ci if (out->TryAddRange(input_range)) { 27031cb0ef41Sopenharmony_ci TRACE("Added %d and %d to %d\n", phi->virtual_register(), input, 27041cb0ef41Sopenharmony_ci out->id()); 27051cb0ef41Sopenharmony_ci } else if (input_range->Start() > out_range->Start()) { 27061cb0ef41Sopenharmony_ci // We are only interested in values defined after the phi, because 27071cb0ef41Sopenharmony_ci // those are values that will go over a back-edge. 27081cb0ef41Sopenharmony_ci phi_interferes_with_backedge_input = true; 27091cb0ef41Sopenharmony_ci } 27101cb0ef41Sopenharmony_ci } 27111cb0ef41Sopenharmony_ci } 27121cb0ef41Sopenharmony_ci // Spilling the phi at the loop header is not beneficial if there is 27131cb0ef41Sopenharmony_ci // a back-edge with an input for the phi that interferes with the phi's 27141cb0ef41Sopenharmony_ci // value, because in case that input gets spilled it might introduce 27151cb0ef41Sopenharmony_ci // a stack-to-stack move at the back-edge. 27161cb0ef41Sopenharmony_ci if (phi_interferes_with_backedge_input) 27171cb0ef41Sopenharmony_ci out_range->TopLevel()->set_spilling_at_loop_header_not_beneficial(); 27181cb0ef41Sopenharmony_ci } 27191cb0ef41Sopenharmony_ci TRACE("Done block B%d\n", block_id); 27201cb0ef41Sopenharmony_ci } 27211cb0ef41Sopenharmony_ci} 27221cb0ef41Sopenharmony_ci 27231cb0ef41Sopenharmony_cibool LiveRangeBundle::TryAddRange(LiveRange* range) { 27241cb0ef41Sopenharmony_ci DCHECK_NULL(range->get_bundle()); 27251cb0ef41Sopenharmony_ci // We may only add a new live range if its use intervals do not 27261cb0ef41Sopenharmony_ci // overlap with existing intervals in the bundle. 27271cb0ef41Sopenharmony_ci if (UsesOverlap(range->first_interval())) return false; 27281cb0ef41Sopenharmony_ci ranges_.insert(range); 27291cb0ef41Sopenharmony_ci range->set_bundle(this); 27301cb0ef41Sopenharmony_ci InsertUses(range->first_interval()); 27311cb0ef41Sopenharmony_ci return true; 27321cb0ef41Sopenharmony_ci} 27331cb0ef41Sopenharmony_ci 27341cb0ef41Sopenharmony_ciLiveRangeBundle* LiveRangeBundle::TryMerge(LiveRangeBundle* lhs, 27351cb0ef41Sopenharmony_ci LiveRangeBundle* rhs, 27361cb0ef41Sopenharmony_ci bool trace_alloc) { 27371cb0ef41Sopenharmony_ci if (rhs == lhs) return lhs; 27381cb0ef41Sopenharmony_ci 27391cb0ef41Sopenharmony_ci auto iter1 = lhs->uses_.begin(); 27401cb0ef41Sopenharmony_ci auto iter2 = rhs->uses_.begin(); 27411cb0ef41Sopenharmony_ci 27421cb0ef41Sopenharmony_ci while (iter1 != lhs->uses_.end() && iter2 != rhs->uses_.end()) { 27431cb0ef41Sopenharmony_ci if (iter1->start >= iter2->end) { 27441cb0ef41Sopenharmony_ci ++iter2; 27451cb0ef41Sopenharmony_ci } else if (iter2->start >= iter1->end) { 27461cb0ef41Sopenharmony_ci ++iter1; 27471cb0ef41Sopenharmony_ci } else { 27481cb0ef41Sopenharmony_ci TRACE_COND(trace_alloc, "No merge %d:%d %d:%d\n", iter1->start, 27491cb0ef41Sopenharmony_ci iter1->end, iter2->start, iter2->end); 27501cb0ef41Sopenharmony_ci return nullptr; 27511cb0ef41Sopenharmony_ci } 27521cb0ef41Sopenharmony_ci } 27531cb0ef41Sopenharmony_ci // Uses are disjoint, merging is possible. 27541cb0ef41Sopenharmony_ci if (lhs->uses_.size() < rhs->uses_.size()) { 27551cb0ef41Sopenharmony_ci // Merge the smallest bundle into the biggest. 27561cb0ef41Sopenharmony_ci std::swap(lhs, rhs); 27571cb0ef41Sopenharmony_ci } 27581cb0ef41Sopenharmony_ci for (auto it = rhs->ranges_.begin(); it != rhs->ranges_.end(); ++it) { 27591cb0ef41Sopenharmony_ci (*it)->set_bundle(lhs); 27601cb0ef41Sopenharmony_ci lhs->InsertUses((*it)->first_interval()); 27611cb0ef41Sopenharmony_ci } 27621cb0ef41Sopenharmony_ci lhs->ranges_.insert(rhs->ranges_.begin(), rhs->ranges_.end()); 27631cb0ef41Sopenharmony_ci rhs->ranges_.clear(); 27641cb0ef41Sopenharmony_ci return lhs; 27651cb0ef41Sopenharmony_ci} 27661cb0ef41Sopenharmony_ci 27671cb0ef41Sopenharmony_civoid LiveRangeBundle::MergeSpillRangesAndClear() { 27681cb0ef41Sopenharmony_ci DCHECK_IMPLIES(ranges_.empty(), uses_.empty()); 27691cb0ef41Sopenharmony_ci SpillRange* target = nullptr; 27701cb0ef41Sopenharmony_ci for (auto range : ranges_) { 27711cb0ef41Sopenharmony_ci if (range->TopLevel()->HasSpillRange()) { 27721cb0ef41Sopenharmony_ci SpillRange* current = range->TopLevel()->GetSpillRange(); 27731cb0ef41Sopenharmony_ci if (target == nullptr) { 27741cb0ef41Sopenharmony_ci target = current; 27751cb0ef41Sopenharmony_ci } else if (target != current) { 27761cb0ef41Sopenharmony_ci target->TryMerge(current); 27771cb0ef41Sopenharmony_ci } 27781cb0ef41Sopenharmony_ci } 27791cb0ef41Sopenharmony_ci } 27801cb0ef41Sopenharmony_ci // Clear the fields so that we don't try to merge the spill ranges again when 27811cb0ef41Sopenharmony_ci // we hit the same bundle from a different LiveRange in AssignSpillSlots. 27821cb0ef41Sopenharmony_ci // LiveRangeBundles are not used after this. 27831cb0ef41Sopenharmony_ci ranges_.clear(); 27841cb0ef41Sopenharmony_ci uses_.clear(); 27851cb0ef41Sopenharmony_ci} 27861cb0ef41Sopenharmony_ci 27871cb0ef41Sopenharmony_ciRegisterAllocator::RegisterAllocator(TopTierRegisterAllocationData* data, 27881cb0ef41Sopenharmony_ci RegisterKind kind) 27891cb0ef41Sopenharmony_ci : data_(data), 27901cb0ef41Sopenharmony_ci mode_(kind), 27911cb0ef41Sopenharmony_ci num_registers_(GetRegisterCount(data->config(), kind)), 27921cb0ef41Sopenharmony_ci num_allocatable_registers_( 27931cb0ef41Sopenharmony_ci GetAllocatableRegisterCount(data->config(), kind)), 27941cb0ef41Sopenharmony_ci allocatable_register_codes_( 27951cb0ef41Sopenharmony_ci GetAllocatableRegisterCodes(data->config(), kind)), 27961cb0ef41Sopenharmony_ci check_fp_aliasing_(false) { 27971cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && kind == RegisterKind::kDouble) { 27981cb0ef41Sopenharmony_ci check_fp_aliasing_ = (data->code()->representation_mask() & 27991cb0ef41Sopenharmony_ci (kFloat32Bit | kSimd128Bit)) != 0; 28001cb0ef41Sopenharmony_ci } 28011cb0ef41Sopenharmony_ci} 28021cb0ef41Sopenharmony_ci 28031cb0ef41Sopenharmony_ciLifetimePosition RegisterAllocator::GetSplitPositionForInstruction( 28041cb0ef41Sopenharmony_ci const LiveRange* range, int instruction_index) { 28051cb0ef41Sopenharmony_ci LifetimePosition ret = LifetimePosition::Invalid(); 28061cb0ef41Sopenharmony_ci 28071cb0ef41Sopenharmony_ci ret = LifetimePosition::GapFromInstructionIndex(instruction_index); 28081cb0ef41Sopenharmony_ci if (range->Start() >= ret || ret >= range->End()) { 28091cb0ef41Sopenharmony_ci return LifetimePosition::Invalid(); 28101cb0ef41Sopenharmony_ci } 28111cb0ef41Sopenharmony_ci return ret; 28121cb0ef41Sopenharmony_ci} 28131cb0ef41Sopenharmony_ci 28141cb0ef41Sopenharmony_civoid RegisterAllocator::SplitAndSpillRangesDefinedByMemoryOperand() { 28151cb0ef41Sopenharmony_ci size_t initial_range_count = data()->live_ranges().size(); 28161cb0ef41Sopenharmony_ci for (size_t i = 0; i < initial_range_count; ++i) { 28171cb0ef41Sopenharmony_ci CHECK_EQ(initial_range_count, 28181cb0ef41Sopenharmony_ci data()->live_ranges().size()); // TODO(neis): crbug.com/831822 28191cb0ef41Sopenharmony_ci TopLevelLiveRange* range = data()->live_ranges()[i]; 28201cb0ef41Sopenharmony_ci if (!CanProcessRange(range)) continue; 28211cb0ef41Sopenharmony_ci // Only assume defined by memory operand if we are guaranteed to spill it or 28221cb0ef41Sopenharmony_ci // it has a spill operand. 28231cb0ef41Sopenharmony_ci if (range->HasNoSpillType() || 28241cb0ef41Sopenharmony_ci (range->HasSpillRange() && !range->has_non_deferred_slot_use())) { 28251cb0ef41Sopenharmony_ci continue; 28261cb0ef41Sopenharmony_ci } 28271cb0ef41Sopenharmony_ci LifetimePosition start = range->Start(); 28281cb0ef41Sopenharmony_ci TRACE("Live range %d:%d is defined by a spill operand.\n", 28291cb0ef41Sopenharmony_ci range->TopLevel()->vreg(), range->relative_id()); 28301cb0ef41Sopenharmony_ci LifetimePosition next_pos = start; 28311cb0ef41Sopenharmony_ci if (next_pos.IsGapPosition()) { 28321cb0ef41Sopenharmony_ci next_pos = next_pos.NextStart(); 28331cb0ef41Sopenharmony_ci } 28341cb0ef41Sopenharmony_ci 28351cb0ef41Sopenharmony_ci UsePosition* pos = range->NextUsePositionRegisterIsBeneficial(next_pos); 28361cb0ef41Sopenharmony_ci // If the range already has a spill operand and it doesn't need a 28371cb0ef41Sopenharmony_ci // register immediately, split it and spill the first part of the range. 28381cb0ef41Sopenharmony_ci if (pos == nullptr) { 28391cb0ef41Sopenharmony_ci Spill(range, SpillMode::kSpillAtDefinition); 28401cb0ef41Sopenharmony_ci } else if (pos->pos() > range->Start().NextStart()) { 28411cb0ef41Sopenharmony_ci // Do not spill live range eagerly if use position that can benefit from 28421cb0ef41Sopenharmony_ci // the register is too close to the start of live range. 28431cb0ef41Sopenharmony_ci LifetimePosition split_pos = GetSplitPositionForInstruction( 28441cb0ef41Sopenharmony_ci range, pos->pos().ToInstructionIndex()); 28451cb0ef41Sopenharmony_ci // There is no place to split, so we can't split and spill. 28461cb0ef41Sopenharmony_ci if (!split_pos.IsValid()) continue; 28471cb0ef41Sopenharmony_ci 28481cb0ef41Sopenharmony_ci split_pos = 28491cb0ef41Sopenharmony_ci FindOptimalSplitPos(range->Start().NextFullStart(), split_pos); 28501cb0ef41Sopenharmony_ci 28511cb0ef41Sopenharmony_ci SplitRangeAt(range, split_pos); 28521cb0ef41Sopenharmony_ci Spill(range, SpillMode::kSpillAtDefinition); 28531cb0ef41Sopenharmony_ci } 28541cb0ef41Sopenharmony_ci } 28551cb0ef41Sopenharmony_ci} 28561cb0ef41Sopenharmony_ci 28571cb0ef41Sopenharmony_ciLiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, 28581cb0ef41Sopenharmony_ci LifetimePosition pos) { 28591cb0ef41Sopenharmony_ci DCHECK(!range->TopLevel()->IsFixed()); 28601cb0ef41Sopenharmony_ci TRACE("Splitting live range %d:%d at %d\n", range->TopLevel()->vreg(), 28611cb0ef41Sopenharmony_ci range->relative_id(), pos.value()); 28621cb0ef41Sopenharmony_ci 28631cb0ef41Sopenharmony_ci if (pos <= range->Start()) return range; 28641cb0ef41Sopenharmony_ci 28651cb0ef41Sopenharmony_ci // We can't properly connect liveranges if splitting occurred at the end 28661cb0ef41Sopenharmony_ci // a block. 28671cb0ef41Sopenharmony_ci DCHECK(pos.IsStart() || pos.IsGapPosition() || 28681cb0ef41Sopenharmony_ci (GetInstructionBlock(code(), pos)->last_instruction_index() != 28691cb0ef41Sopenharmony_ci pos.ToInstructionIndex())); 28701cb0ef41Sopenharmony_ci 28711cb0ef41Sopenharmony_ci LiveRange* result = range->SplitAt(pos, allocation_zone()); 28721cb0ef41Sopenharmony_ci return result; 28731cb0ef41Sopenharmony_ci} 28741cb0ef41Sopenharmony_ci 28751cb0ef41Sopenharmony_ciLiveRange* RegisterAllocator::SplitBetween(LiveRange* range, 28761cb0ef41Sopenharmony_ci LifetimePosition start, 28771cb0ef41Sopenharmony_ci LifetimePosition end) { 28781cb0ef41Sopenharmony_ci DCHECK(!range->TopLevel()->IsFixed()); 28791cb0ef41Sopenharmony_ci TRACE("Splitting live range %d:%d in position between [%d, %d]\n", 28801cb0ef41Sopenharmony_ci range->TopLevel()->vreg(), range->relative_id(), start.value(), 28811cb0ef41Sopenharmony_ci end.value()); 28821cb0ef41Sopenharmony_ci 28831cb0ef41Sopenharmony_ci LifetimePosition split_pos = FindOptimalSplitPos(start, end); 28841cb0ef41Sopenharmony_ci DCHECK(split_pos >= start); 28851cb0ef41Sopenharmony_ci return SplitRangeAt(range, split_pos); 28861cb0ef41Sopenharmony_ci} 28871cb0ef41Sopenharmony_ci 28881cb0ef41Sopenharmony_ciLifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start, 28891cb0ef41Sopenharmony_ci LifetimePosition end) { 28901cb0ef41Sopenharmony_ci int start_instr = start.ToInstructionIndex(); 28911cb0ef41Sopenharmony_ci int end_instr = end.ToInstructionIndex(); 28921cb0ef41Sopenharmony_ci DCHECK_LE(start_instr, end_instr); 28931cb0ef41Sopenharmony_ci 28941cb0ef41Sopenharmony_ci // We have no choice 28951cb0ef41Sopenharmony_ci if (start_instr == end_instr) return end; 28961cb0ef41Sopenharmony_ci 28971cb0ef41Sopenharmony_ci const InstructionBlock* start_block = GetInstructionBlock(code(), start); 28981cb0ef41Sopenharmony_ci const InstructionBlock* end_block = GetInstructionBlock(code(), end); 28991cb0ef41Sopenharmony_ci 29001cb0ef41Sopenharmony_ci if (end_block == start_block) { 29011cb0ef41Sopenharmony_ci // The interval is split in the same basic block. Split at the latest 29021cb0ef41Sopenharmony_ci // possible position. 29031cb0ef41Sopenharmony_ci return end; 29041cb0ef41Sopenharmony_ci } 29051cb0ef41Sopenharmony_ci 29061cb0ef41Sopenharmony_ci const InstructionBlock* block = end_block; 29071cb0ef41Sopenharmony_ci // Find header of outermost loop. 29081cb0ef41Sopenharmony_ci do { 29091cb0ef41Sopenharmony_ci const InstructionBlock* loop = GetContainingLoop(code(), block); 29101cb0ef41Sopenharmony_ci if (loop == nullptr || 29111cb0ef41Sopenharmony_ci loop->rpo_number().ToInt() <= start_block->rpo_number().ToInt()) { 29121cb0ef41Sopenharmony_ci // No more loops or loop starts before the lifetime start. 29131cb0ef41Sopenharmony_ci break; 29141cb0ef41Sopenharmony_ci } 29151cb0ef41Sopenharmony_ci block = loop; 29161cb0ef41Sopenharmony_ci } while (true); 29171cb0ef41Sopenharmony_ci 29181cb0ef41Sopenharmony_ci // We did not find any suitable outer loop. Split at the latest possible 29191cb0ef41Sopenharmony_ci // position unless end_block is a loop header itself. 29201cb0ef41Sopenharmony_ci if (block == end_block && !end_block->IsLoopHeader()) return end; 29211cb0ef41Sopenharmony_ci 29221cb0ef41Sopenharmony_ci return LifetimePosition::GapFromInstructionIndex( 29231cb0ef41Sopenharmony_ci block->first_instruction_index()); 29241cb0ef41Sopenharmony_ci} 29251cb0ef41Sopenharmony_ci 29261cb0ef41Sopenharmony_ciLifetimePosition RegisterAllocator::FindOptimalSpillingPos( 29271cb0ef41Sopenharmony_ci LiveRange* range, LifetimePosition pos, SpillMode spill_mode, 29281cb0ef41Sopenharmony_ci LiveRange** begin_spill_out) { 29291cb0ef41Sopenharmony_ci *begin_spill_out = range; 29301cb0ef41Sopenharmony_ci // TODO(herhut): Be more clever here as long as we do not move pos out of 29311cb0ef41Sopenharmony_ci // deferred code. 29321cb0ef41Sopenharmony_ci if (spill_mode == SpillMode::kSpillDeferred) return pos; 29331cb0ef41Sopenharmony_ci const InstructionBlock* block = GetInstructionBlock(code(), pos.Start()); 29341cb0ef41Sopenharmony_ci const InstructionBlock* loop_header = 29351cb0ef41Sopenharmony_ci block->IsLoopHeader() ? block : GetContainingLoop(code(), block); 29361cb0ef41Sopenharmony_ci if (loop_header == nullptr) return pos; 29371cb0ef41Sopenharmony_ci 29381cb0ef41Sopenharmony_ci while (loop_header != nullptr) { 29391cb0ef41Sopenharmony_ci // We are going to spill live range inside the loop. 29401cb0ef41Sopenharmony_ci // If possible try to move spilling position backwards to loop header. 29411cb0ef41Sopenharmony_ci // This will reduce number of memory moves on the back edge. 29421cb0ef41Sopenharmony_ci LifetimePosition loop_start = LifetimePosition::GapFromInstructionIndex( 29431cb0ef41Sopenharmony_ci loop_header->first_instruction_index()); 29441cb0ef41Sopenharmony_ci // Stop if we moved to a loop header before the value is defined or 29451cb0ef41Sopenharmony_ci // at the define position that is not beneficial to spill. 29461cb0ef41Sopenharmony_ci if (range->TopLevel()->Start() > loop_start || 29471cb0ef41Sopenharmony_ci (range->TopLevel()->Start() == loop_start && 29481cb0ef41Sopenharmony_ci range->TopLevel()->SpillAtLoopHeaderNotBeneficial())) 29491cb0ef41Sopenharmony_ci return pos; 29501cb0ef41Sopenharmony_ci 29511cb0ef41Sopenharmony_ci LiveRange* live_at_header = range->TopLevel()->GetChildCovers(loop_start); 29521cb0ef41Sopenharmony_ci 29531cb0ef41Sopenharmony_ci if (live_at_header != nullptr && !live_at_header->spilled()) { 29541cb0ef41Sopenharmony_ci for (LiveRange* check_use = live_at_header; 29551cb0ef41Sopenharmony_ci check_use != nullptr && check_use->Start() < pos; 29561cb0ef41Sopenharmony_ci check_use = check_use->next()) { 29571cb0ef41Sopenharmony_ci // If we find a use for which spilling is detrimental, don't spill 29581cb0ef41Sopenharmony_ci // at the loop header 29591cb0ef41Sopenharmony_ci UsePosition* next_use = 29601cb0ef41Sopenharmony_ci check_use->NextUsePositionSpillDetrimental(loop_start); 29611cb0ef41Sopenharmony_ci // UsePosition at the end of a UseInterval may 29621cb0ef41Sopenharmony_ci // have the same value as the start of next range. 29631cb0ef41Sopenharmony_ci if (next_use != nullptr && next_use->pos() <= pos) { 29641cb0ef41Sopenharmony_ci return pos; 29651cb0ef41Sopenharmony_ci } 29661cb0ef41Sopenharmony_ci } 29671cb0ef41Sopenharmony_ci // No register beneficial use inside the loop before the pos. 29681cb0ef41Sopenharmony_ci *begin_spill_out = live_at_header; 29691cb0ef41Sopenharmony_ci pos = loop_start; 29701cb0ef41Sopenharmony_ci } 29711cb0ef41Sopenharmony_ci 29721cb0ef41Sopenharmony_ci // Try hoisting out to an outer loop. 29731cb0ef41Sopenharmony_ci loop_header = GetContainingLoop(code(), loop_header); 29741cb0ef41Sopenharmony_ci } 29751cb0ef41Sopenharmony_ci return pos; 29761cb0ef41Sopenharmony_ci} 29771cb0ef41Sopenharmony_ci 29781cb0ef41Sopenharmony_civoid RegisterAllocator::Spill(LiveRange* range, SpillMode spill_mode) { 29791cb0ef41Sopenharmony_ci DCHECK(!range->spilled()); 29801cb0ef41Sopenharmony_ci DCHECK(spill_mode == SpillMode::kSpillAtDefinition || 29811cb0ef41Sopenharmony_ci GetInstructionBlock(code(), range->Start())->IsDeferred()); 29821cb0ef41Sopenharmony_ci TopLevelLiveRange* first = range->TopLevel(); 29831cb0ef41Sopenharmony_ci TRACE("Spilling live range %d:%d mode %d\n", first->vreg(), 29841cb0ef41Sopenharmony_ci range->relative_id(), spill_mode); 29851cb0ef41Sopenharmony_ci 29861cb0ef41Sopenharmony_ci TRACE("Starting spill type is %d\n", static_cast<int>(first->spill_type())); 29871cb0ef41Sopenharmony_ci if (first->HasNoSpillType()) { 29881cb0ef41Sopenharmony_ci TRACE("New spill range needed"); 29891cb0ef41Sopenharmony_ci data()->AssignSpillRangeToLiveRange(first, spill_mode); 29901cb0ef41Sopenharmony_ci } 29911cb0ef41Sopenharmony_ci // Upgrade the spillmode, in case this was only spilled in deferred code so 29921cb0ef41Sopenharmony_ci // far. 29931cb0ef41Sopenharmony_ci if ((spill_mode == SpillMode::kSpillAtDefinition) && 29941cb0ef41Sopenharmony_ci (first->spill_type() == 29951cb0ef41Sopenharmony_ci TopLevelLiveRange::SpillType::kDeferredSpillRange)) { 29961cb0ef41Sopenharmony_ci TRACE("Upgrading\n"); 29971cb0ef41Sopenharmony_ci first->set_spill_type(TopLevelLiveRange::SpillType::kSpillRange); 29981cb0ef41Sopenharmony_ci } 29991cb0ef41Sopenharmony_ci TRACE("Final spill type is %d\n", static_cast<int>(first->spill_type())); 30001cb0ef41Sopenharmony_ci range->Spill(); 30011cb0ef41Sopenharmony_ci} 30021cb0ef41Sopenharmony_ci 30031cb0ef41Sopenharmony_ciconst char* RegisterAllocator::RegisterName(int register_code) const { 30041cb0ef41Sopenharmony_ci if (register_code == kUnassignedRegister) return "unassigned"; 30051cb0ef41Sopenharmony_ci switch (mode()) { 30061cb0ef41Sopenharmony_ci case RegisterKind::kGeneral: 30071cb0ef41Sopenharmony_ci return i::RegisterName(Register::from_code(register_code)); 30081cb0ef41Sopenharmony_ci case RegisterKind::kDouble: 30091cb0ef41Sopenharmony_ci return i::RegisterName(DoubleRegister::from_code(register_code)); 30101cb0ef41Sopenharmony_ci case RegisterKind::kSimd128: 30111cb0ef41Sopenharmony_ci return i::RegisterName(Simd128Register::from_code(register_code)); 30121cb0ef41Sopenharmony_ci } 30131cb0ef41Sopenharmony_ci} 30141cb0ef41Sopenharmony_ci 30151cb0ef41Sopenharmony_ciLinearScanAllocator::LinearScanAllocator(TopTierRegisterAllocationData* data, 30161cb0ef41Sopenharmony_ci RegisterKind kind, Zone* local_zone) 30171cb0ef41Sopenharmony_ci : RegisterAllocator(data, kind), 30181cb0ef41Sopenharmony_ci unhandled_live_ranges_(local_zone), 30191cb0ef41Sopenharmony_ci active_live_ranges_(local_zone), 30201cb0ef41Sopenharmony_ci inactive_live_ranges_(num_registers(), InactiveLiveRangeQueue(local_zone), 30211cb0ef41Sopenharmony_ci local_zone), 30221cb0ef41Sopenharmony_ci next_active_ranges_change_(LifetimePosition::Invalid()), 30231cb0ef41Sopenharmony_ci next_inactive_ranges_change_(LifetimePosition::Invalid()) { 30241cb0ef41Sopenharmony_ci active_live_ranges().reserve(8); 30251cb0ef41Sopenharmony_ci} 30261cb0ef41Sopenharmony_ci 30271cb0ef41Sopenharmony_civoid LinearScanAllocator::MaybeSpillPreviousRanges(LiveRange* begin_range, 30281cb0ef41Sopenharmony_ci LifetimePosition begin_pos, 30291cb0ef41Sopenharmony_ci LiveRange* end_range) { 30301cb0ef41Sopenharmony_ci // Spill begin_range after begin_pos, then spill every live range of this 30311cb0ef41Sopenharmony_ci // virtual register until but excluding end_range. 30321cb0ef41Sopenharmony_ci DCHECK(begin_range->Covers(begin_pos)); 30331cb0ef41Sopenharmony_ci DCHECK_EQ(begin_range->TopLevel(), end_range->TopLevel()); 30341cb0ef41Sopenharmony_ci 30351cb0ef41Sopenharmony_ci if (begin_range != end_range) { 30361cb0ef41Sopenharmony_ci DCHECK_LE(begin_range->End(), end_range->Start()); 30371cb0ef41Sopenharmony_ci if (!begin_range->spilled()) { 30381cb0ef41Sopenharmony_ci SpillAfter(begin_range, begin_pos, SpillMode::kSpillAtDefinition); 30391cb0ef41Sopenharmony_ci } 30401cb0ef41Sopenharmony_ci for (LiveRange* range = begin_range->next(); range != end_range; 30411cb0ef41Sopenharmony_ci range = range->next()) { 30421cb0ef41Sopenharmony_ci if (!range->spilled()) { 30431cb0ef41Sopenharmony_ci range->Spill(); 30441cb0ef41Sopenharmony_ci } 30451cb0ef41Sopenharmony_ci } 30461cb0ef41Sopenharmony_ci } 30471cb0ef41Sopenharmony_ci} 30481cb0ef41Sopenharmony_ci 30491cb0ef41Sopenharmony_civoid LinearScanAllocator::MaybeUndoPreviousSplit(LiveRange* range) { 30501cb0ef41Sopenharmony_ci if (range->next() != nullptr && range->next()->ShouldRecombine()) { 30511cb0ef41Sopenharmony_ci LiveRange* to_remove = range->next(); 30521cb0ef41Sopenharmony_ci TRACE("Recombining %d:%d with %d\n", range->TopLevel()->vreg(), 30531cb0ef41Sopenharmony_ci range->relative_id(), to_remove->relative_id()); 30541cb0ef41Sopenharmony_ci 30551cb0ef41Sopenharmony_ci // Remove the range from unhandled, as attaching it will change its 30561cb0ef41Sopenharmony_ci // state and hence ordering in the unhandled set. 30571cb0ef41Sopenharmony_ci auto removed_cnt = unhandled_live_ranges().erase(to_remove); 30581cb0ef41Sopenharmony_ci DCHECK_EQ(removed_cnt, 1); 30591cb0ef41Sopenharmony_ci USE(removed_cnt); 30601cb0ef41Sopenharmony_ci 30611cb0ef41Sopenharmony_ci range->AttachToNext(); 30621cb0ef41Sopenharmony_ci } else if (range->next() != nullptr) { 30631cb0ef41Sopenharmony_ci TRACE("No recombine for %d:%d to %d\n", range->TopLevel()->vreg(), 30641cb0ef41Sopenharmony_ci range->relative_id(), range->next()->relative_id()); 30651cb0ef41Sopenharmony_ci } 30661cb0ef41Sopenharmony_ci} 30671cb0ef41Sopenharmony_ci 30681cb0ef41Sopenharmony_civoid LinearScanAllocator::SpillNotLiveRanges(RangeWithRegisterSet* to_be_live, 30691cb0ef41Sopenharmony_ci LifetimePosition position, 30701cb0ef41Sopenharmony_ci SpillMode spill_mode) { 30711cb0ef41Sopenharmony_ci for (auto it = active_live_ranges().begin(); 30721cb0ef41Sopenharmony_ci it != active_live_ranges().end();) { 30731cb0ef41Sopenharmony_ci LiveRange* active_range = *it; 30741cb0ef41Sopenharmony_ci TopLevelLiveRange* toplevel = (*it)->TopLevel(); 30751cb0ef41Sopenharmony_ci auto found = to_be_live->find({toplevel, kUnassignedRegister}); 30761cb0ef41Sopenharmony_ci if (found == to_be_live->end()) { 30771cb0ef41Sopenharmony_ci // Is not contained in {to_be_live}, spill it. 30781cb0ef41Sopenharmony_ci // Fixed registers are exempt from this. They might have been 30791cb0ef41Sopenharmony_ci // added from inactive at the block boundary but we know that 30801cb0ef41Sopenharmony_ci // they cannot conflict as they are built before register 30811cb0ef41Sopenharmony_ci // allocation starts. It would be algorithmically fine to split 30821cb0ef41Sopenharmony_ci // them and reschedule but the code does not allow to do this. 30831cb0ef41Sopenharmony_ci if (toplevel->IsFixed()) { 30841cb0ef41Sopenharmony_ci TRACE("Keeping reactivated fixed range for %s\n", 30851cb0ef41Sopenharmony_ci RegisterName(toplevel->assigned_register())); 30861cb0ef41Sopenharmony_ci ++it; 30871cb0ef41Sopenharmony_ci } else { 30881cb0ef41Sopenharmony_ci // When spilling a previously spilled/reloaded range, we add back the 30891cb0ef41Sopenharmony_ci // tail that we might have split off when we reloaded/spilled it 30901cb0ef41Sopenharmony_ci // previously. Otherwise we might keep generating small split-offs. 30911cb0ef41Sopenharmony_ci MaybeUndoPreviousSplit(active_range); 30921cb0ef41Sopenharmony_ci TRACE("Putting back %d:%d\n", toplevel->vreg(), 30931cb0ef41Sopenharmony_ci active_range->relative_id()); 30941cb0ef41Sopenharmony_ci LiveRange* split = SplitRangeAt(active_range, position); 30951cb0ef41Sopenharmony_ci DCHECK_NE(split, active_range); 30961cb0ef41Sopenharmony_ci 30971cb0ef41Sopenharmony_ci // Make sure we revisit this range once it has a use that requires 30981cb0ef41Sopenharmony_ci // a register. 30991cb0ef41Sopenharmony_ci UsePosition* next_use = split->NextRegisterPosition(position); 31001cb0ef41Sopenharmony_ci if (next_use != nullptr) { 31011cb0ef41Sopenharmony_ci // Move to the start of the gap before use so that we have a space 31021cb0ef41Sopenharmony_ci // to perform the potential reload. Otherwise, do not spill but add 31031cb0ef41Sopenharmony_ci // to unhandled for reallocation. 31041cb0ef41Sopenharmony_ci LifetimePosition revisit_at = next_use->pos().FullStart(); 31051cb0ef41Sopenharmony_ci TRACE("Next use at %d\n", revisit_at.value()); 31061cb0ef41Sopenharmony_ci if (!data()->IsBlockBoundary(revisit_at)) { 31071cb0ef41Sopenharmony_ci // Leave some space so we have enough gap room. 31081cb0ef41Sopenharmony_ci revisit_at = revisit_at.PrevStart().FullStart(); 31091cb0ef41Sopenharmony_ci } 31101cb0ef41Sopenharmony_ci // If this range became life right at the block boundary that we are 31111cb0ef41Sopenharmony_ci // currently processing, we do not need to split it. Instead move it 31121cb0ef41Sopenharmony_ci // to unhandled right away. 31131cb0ef41Sopenharmony_ci if (position < revisit_at) { 31141cb0ef41Sopenharmony_ci LiveRange* third_part = SplitRangeAt(split, revisit_at); 31151cb0ef41Sopenharmony_ci DCHECK_NE(split, third_part); 31161cb0ef41Sopenharmony_ci Spill(split, spill_mode); 31171cb0ef41Sopenharmony_ci TRACE("Marking %d:%d to recombine\n", toplevel->vreg(), 31181cb0ef41Sopenharmony_ci third_part->relative_id()); 31191cb0ef41Sopenharmony_ci third_part->SetRecombine(); 31201cb0ef41Sopenharmony_ci AddToUnhandled(third_part); 31211cb0ef41Sopenharmony_ci } else { 31221cb0ef41Sopenharmony_ci AddToUnhandled(split); 31231cb0ef41Sopenharmony_ci } 31241cb0ef41Sopenharmony_ci } else { 31251cb0ef41Sopenharmony_ci Spill(split, spill_mode); 31261cb0ef41Sopenharmony_ci } 31271cb0ef41Sopenharmony_ci it = ActiveToHandled(it); 31281cb0ef41Sopenharmony_ci } 31291cb0ef41Sopenharmony_ci } else { 31301cb0ef41Sopenharmony_ci // This range is contained in {to_be_live}, so we can keep it. 31311cb0ef41Sopenharmony_ci int expected_register = (*found).expected_register; 31321cb0ef41Sopenharmony_ci to_be_live->erase(found); 31331cb0ef41Sopenharmony_ci if (expected_register == active_range->assigned_register()) { 31341cb0ef41Sopenharmony_ci // Was life and in correct register, simply pass through. 31351cb0ef41Sopenharmony_ci TRACE("Keeping %d:%d in %s\n", toplevel->vreg(), 31361cb0ef41Sopenharmony_ci active_range->relative_id(), 31371cb0ef41Sopenharmony_ci RegisterName(active_range->assigned_register())); 31381cb0ef41Sopenharmony_ci ++it; 31391cb0ef41Sopenharmony_ci } else { 31401cb0ef41Sopenharmony_ci // Was life but wrong register. Split and schedule for 31411cb0ef41Sopenharmony_ci // allocation. 31421cb0ef41Sopenharmony_ci TRACE("Scheduling %d:%d\n", toplevel->vreg(), 31431cb0ef41Sopenharmony_ci active_range->relative_id()); 31441cb0ef41Sopenharmony_ci LiveRange* split = SplitRangeAt(active_range, position); 31451cb0ef41Sopenharmony_ci split->set_controlflow_hint(expected_register); 31461cb0ef41Sopenharmony_ci AddToUnhandled(split); 31471cb0ef41Sopenharmony_ci it = ActiveToHandled(it); 31481cb0ef41Sopenharmony_ci } 31491cb0ef41Sopenharmony_ci } 31501cb0ef41Sopenharmony_ci } 31511cb0ef41Sopenharmony_ci} 31521cb0ef41Sopenharmony_ci 31531cb0ef41Sopenharmony_ciLiveRange* LinearScanAllocator::AssignRegisterOnReload(LiveRange* range, 31541cb0ef41Sopenharmony_ci int reg) { 31551cb0ef41Sopenharmony_ci // We know the register is currently free but it might be in 31561cb0ef41Sopenharmony_ci // use by a currently inactive range. So we might not be able 31571cb0ef41Sopenharmony_ci // to reload for the full distance. In such case, split here. 31581cb0ef41Sopenharmony_ci // TODO(herhut): 31591cb0ef41Sopenharmony_ci // It might be better if we could use the normal unhandled queue and 31601cb0ef41Sopenharmony_ci // give reloading registers pecedence. That way we would compute the 31611cb0ef41Sopenharmony_ci // intersection for the entire future. 31621cb0ef41Sopenharmony_ci LifetimePosition new_end = range->End(); 31631cb0ef41Sopenharmony_ci for (int cur_reg = 0; cur_reg < num_registers(); ++cur_reg) { 31641cb0ef41Sopenharmony_ci if ((kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) && 31651cb0ef41Sopenharmony_ci cur_reg != reg) { 31661cb0ef41Sopenharmony_ci continue; 31671cb0ef41Sopenharmony_ci } 31681cb0ef41Sopenharmony_ci for (const LiveRange* cur_inactive : inactive_live_ranges(cur_reg)) { 31691cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && check_fp_aliasing() && 31701cb0ef41Sopenharmony_ci !data()->config()->AreAliases(cur_inactive->representation(), cur_reg, 31711cb0ef41Sopenharmony_ci range->representation(), reg)) { 31721cb0ef41Sopenharmony_ci continue; 31731cb0ef41Sopenharmony_ci } 31741cb0ef41Sopenharmony_ci if (new_end <= cur_inactive->NextStart()) { 31751cb0ef41Sopenharmony_ci // Inactive ranges are sorted by their next start, so the remaining 31761cb0ef41Sopenharmony_ci // ranges cannot contribute to new_end. 31771cb0ef41Sopenharmony_ci break; 31781cb0ef41Sopenharmony_ci } 31791cb0ef41Sopenharmony_ci auto next_intersection = cur_inactive->FirstIntersection(range); 31801cb0ef41Sopenharmony_ci if (!next_intersection.IsValid()) continue; 31811cb0ef41Sopenharmony_ci new_end = std::min(new_end, next_intersection); 31821cb0ef41Sopenharmony_ci } 31831cb0ef41Sopenharmony_ci } 31841cb0ef41Sopenharmony_ci if (new_end != range->End()) { 31851cb0ef41Sopenharmony_ci TRACE("Found new end for %d:%d at %d\n", range->TopLevel()->vreg(), 31861cb0ef41Sopenharmony_ci range->relative_id(), new_end.value()); 31871cb0ef41Sopenharmony_ci LiveRange* tail = SplitRangeAt(range, new_end); 31881cb0ef41Sopenharmony_ci AddToUnhandled(tail); 31891cb0ef41Sopenharmony_ci } 31901cb0ef41Sopenharmony_ci SetLiveRangeAssignedRegister(range, reg); 31911cb0ef41Sopenharmony_ci return range; 31921cb0ef41Sopenharmony_ci} 31931cb0ef41Sopenharmony_ci 31941cb0ef41Sopenharmony_civoid LinearScanAllocator::ReloadLiveRanges( 31951cb0ef41Sopenharmony_ci RangeWithRegisterSet const& to_be_live, LifetimePosition position) { 31961cb0ef41Sopenharmony_ci // Assumption: All ranges in {to_be_live} are currently spilled and there are 31971cb0ef41Sopenharmony_ci // no conflicting registers in the active ranges. 31981cb0ef41Sopenharmony_ci // The former is ensured by SpillNotLiveRanges, the latter is by construction 31991cb0ef41Sopenharmony_ci // of the to_be_live set. 32001cb0ef41Sopenharmony_ci for (RangeWithRegister range_with_register : to_be_live) { 32011cb0ef41Sopenharmony_ci TopLevelLiveRange* range = range_with_register.range; 32021cb0ef41Sopenharmony_ci int reg = range_with_register.expected_register; 32031cb0ef41Sopenharmony_ci LiveRange* to_resurrect = range->GetChildCovers(position); 32041cb0ef41Sopenharmony_ci if (to_resurrect == nullptr) { 32051cb0ef41Sopenharmony_ci // While the range was life until the end of the predecessor block, it is 32061cb0ef41Sopenharmony_ci // not live in this block. Either there is a lifetime gap or the range 32071cb0ef41Sopenharmony_ci // died. 32081cb0ef41Sopenharmony_ci TRACE("No candidate for %d at %d\n", range->vreg(), position.value()); 32091cb0ef41Sopenharmony_ci } else { 32101cb0ef41Sopenharmony_ci // We might be resurrecting a range that we spilled until its next use 32111cb0ef41Sopenharmony_ci // before. In such cases, we have to unsplit it before processing as 32121cb0ef41Sopenharmony_ci // otherwise we might get register changes from one range to the other 32131cb0ef41Sopenharmony_ci // in the middle of blocks. 32141cb0ef41Sopenharmony_ci // If there is a gap between this range and the next, we can just keep 32151cb0ef41Sopenharmony_ci // it as a register change won't hurt. 32161cb0ef41Sopenharmony_ci MaybeUndoPreviousSplit(to_resurrect); 32171cb0ef41Sopenharmony_ci if (to_resurrect->Start() == position) { 32181cb0ef41Sopenharmony_ci // This range already starts at this block. It might have been spilled, 32191cb0ef41Sopenharmony_ci // so we have to unspill it. Otherwise, it is already in the unhandled 32201cb0ef41Sopenharmony_ci // queue waiting for processing. 32211cb0ef41Sopenharmony_ci DCHECK(!to_resurrect->HasRegisterAssigned()); 32221cb0ef41Sopenharmony_ci TRACE("Reload %d:%d starting at %d itself\n", range->vreg(), 32231cb0ef41Sopenharmony_ci to_resurrect->relative_id(), position.value()); 32241cb0ef41Sopenharmony_ci if (to_resurrect->spilled()) { 32251cb0ef41Sopenharmony_ci to_resurrect->Unspill(); 32261cb0ef41Sopenharmony_ci to_resurrect->set_controlflow_hint(reg); 32271cb0ef41Sopenharmony_ci AddToUnhandled(to_resurrect); 32281cb0ef41Sopenharmony_ci } else { 32291cb0ef41Sopenharmony_ci // Assign the preassigned register if we know. Otherwise, nothing to 32301cb0ef41Sopenharmony_ci // do as already in unhandeled. 32311cb0ef41Sopenharmony_ci if (reg != kUnassignedRegister) { 32321cb0ef41Sopenharmony_ci auto erased_cnt = unhandled_live_ranges().erase(to_resurrect); 32331cb0ef41Sopenharmony_ci DCHECK_EQ(erased_cnt, 1); 32341cb0ef41Sopenharmony_ci USE(erased_cnt); 32351cb0ef41Sopenharmony_ci // We know that there is no conflict with active ranges, so just 32361cb0ef41Sopenharmony_ci // assign the register to the range. 32371cb0ef41Sopenharmony_ci to_resurrect = AssignRegisterOnReload(to_resurrect, reg); 32381cb0ef41Sopenharmony_ci AddToActive(to_resurrect); 32391cb0ef41Sopenharmony_ci } 32401cb0ef41Sopenharmony_ci } 32411cb0ef41Sopenharmony_ci } else { 32421cb0ef41Sopenharmony_ci // This range was spilled before. We have to split it and schedule the 32431cb0ef41Sopenharmony_ci // second part for allocation (or assign the register if we know). 32441cb0ef41Sopenharmony_ci DCHECK(to_resurrect->spilled()); 32451cb0ef41Sopenharmony_ci LiveRange* split = SplitRangeAt(to_resurrect, position); 32461cb0ef41Sopenharmony_ci TRACE("Reload %d:%d starting at %d as %d\n", range->vreg(), 32471cb0ef41Sopenharmony_ci to_resurrect->relative_id(), split->Start().value(), 32481cb0ef41Sopenharmony_ci split->relative_id()); 32491cb0ef41Sopenharmony_ci DCHECK_NE(split, to_resurrect); 32501cb0ef41Sopenharmony_ci if (reg != kUnassignedRegister) { 32511cb0ef41Sopenharmony_ci // We know that there is no conflict with active ranges, so just 32521cb0ef41Sopenharmony_ci // assign the register to the range. 32531cb0ef41Sopenharmony_ci split = AssignRegisterOnReload(split, reg); 32541cb0ef41Sopenharmony_ci AddToActive(split); 32551cb0ef41Sopenharmony_ci } else { 32561cb0ef41Sopenharmony_ci // Let normal register assignment find a suitable register. 32571cb0ef41Sopenharmony_ci split->set_controlflow_hint(reg); 32581cb0ef41Sopenharmony_ci AddToUnhandled(split); 32591cb0ef41Sopenharmony_ci } 32601cb0ef41Sopenharmony_ci } 32611cb0ef41Sopenharmony_ci } 32621cb0ef41Sopenharmony_ci } 32631cb0ef41Sopenharmony_ci} 32641cb0ef41Sopenharmony_ci 32651cb0ef41Sopenharmony_ciRpoNumber LinearScanAllocator::ChooseOneOfTwoPredecessorStates( 32661cb0ef41Sopenharmony_ci InstructionBlock* current_block, LifetimePosition boundary) { 32671cb0ef41Sopenharmony_ci using SmallRangeVector = 32681cb0ef41Sopenharmony_ci base::SmallVector<TopLevelLiveRange*, 32691cb0ef41Sopenharmony_ci RegisterConfiguration::kMaxRegisters>; 32701cb0ef41Sopenharmony_ci // Pick the state that would generate the least spill/reloads. 32711cb0ef41Sopenharmony_ci // Compute vectors of ranges with imminent use for both sides. 32721cb0ef41Sopenharmony_ci // As GetChildCovers is cached, it is cheaper to repeatedly 32731cb0ef41Sopenharmony_ci // call is rather than compute a shared set first. 32741cb0ef41Sopenharmony_ci auto& left = data()->GetSpillState(current_block->predecessors()[0]); 32751cb0ef41Sopenharmony_ci auto& right = data()->GetSpillState(current_block->predecessors()[1]); 32761cb0ef41Sopenharmony_ci SmallRangeVector left_used; 32771cb0ef41Sopenharmony_ci for (const auto item : left) { 32781cb0ef41Sopenharmony_ci LiveRange* at_next_block = item->TopLevel()->GetChildCovers(boundary); 32791cb0ef41Sopenharmony_ci if (at_next_block != nullptr && 32801cb0ef41Sopenharmony_ci at_next_block->NextUsePositionRegisterIsBeneficial(boundary) != 32811cb0ef41Sopenharmony_ci nullptr) { 32821cb0ef41Sopenharmony_ci left_used.emplace_back(item->TopLevel()); 32831cb0ef41Sopenharmony_ci } 32841cb0ef41Sopenharmony_ci } 32851cb0ef41Sopenharmony_ci SmallRangeVector right_used; 32861cb0ef41Sopenharmony_ci for (const auto item : right) { 32871cb0ef41Sopenharmony_ci LiveRange* at_next_block = item->TopLevel()->GetChildCovers(boundary); 32881cb0ef41Sopenharmony_ci if (at_next_block != nullptr && 32891cb0ef41Sopenharmony_ci at_next_block->NextUsePositionRegisterIsBeneficial(boundary) != 32901cb0ef41Sopenharmony_ci nullptr) { 32911cb0ef41Sopenharmony_ci right_used.emplace_back(item->TopLevel()); 32921cb0ef41Sopenharmony_ci } 32931cb0ef41Sopenharmony_ci } 32941cb0ef41Sopenharmony_ci if (left_used.empty() && right_used.empty()) { 32951cb0ef41Sopenharmony_ci // There are no beneficial register uses. Look at any use at 32961cb0ef41Sopenharmony_ci // all. We do not account for all uses, like flowing into a phi. 32971cb0ef41Sopenharmony_ci // So we just look at ranges still being live. 32981cb0ef41Sopenharmony_ci TRACE("Looking at only uses\n"); 32991cb0ef41Sopenharmony_ci for (const auto item : left) { 33001cb0ef41Sopenharmony_ci LiveRange* at_next_block = item->TopLevel()->GetChildCovers(boundary); 33011cb0ef41Sopenharmony_ci if (at_next_block != nullptr && 33021cb0ef41Sopenharmony_ci at_next_block->NextUsePosition(boundary) != nullptr) { 33031cb0ef41Sopenharmony_ci left_used.emplace_back(item->TopLevel()); 33041cb0ef41Sopenharmony_ci } 33051cb0ef41Sopenharmony_ci } 33061cb0ef41Sopenharmony_ci for (const auto item : right) { 33071cb0ef41Sopenharmony_ci LiveRange* at_next_block = item->TopLevel()->GetChildCovers(boundary); 33081cb0ef41Sopenharmony_ci if (at_next_block != nullptr && 33091cb0ef41Sopenharmony_ci at_next_block->NextUsePosition(boundary) != nullptr) { 33101cb0ef41Sopenharmony_ci right_used.emplace_back(item->TopLevel()); 33111cb0ef41Sopenharmony_ci } 33121cb0ef41Sopenharmony_ci } 33131cb0ef41Sopenharmony_ci } 33141cb0ef41Sopenharmony_ci // Now left_used and right_used contains those ranges that matter. 33151cb0ef41Sopenharmony_ci // Count which side matches this most. 33161cb0ef41Sopenharmony_ci TRACE("Vote went %zu vs %zu\n", left_used.size(), right_used.size()); 33171cb0ef41Sopenharmony_ci return left_used.size() > right_used.size() 33181cb0ef41Sopenharmony_ci ? current_block->predecessors()[0] 33191cb0ef41Sopenharmony_ci : current_block->predecessors()[1]; 33201cb0ef41Sopenharmony_ci} 33211cb0ef41Sopenharmony_ci 33221cb0ef41Sopenharmony_cibool LinearScanAllocator::CheckConflict(MachineRepresentation rep, int reg, 33231cb0ef41Sopenharmony_ci RangeWithRegisterSet* to_be_live) { 33241cb0ef41Sopenharmony_ci for (RangeWithRegister range_with_reg : *to_be_live) { 33251cb0ef41Sopenharmony_ci if (data()->config()->AreAliases(range_with_reg.range->representation(), 33261cb0ef41Sopenharmony_ci range_with_reg.expected_register, rep, 33271cb0ef41Sopenharmony_ci reg)) { 33281cb0ef41Sopenharmony_ci return true; 33291cb0ef41Sopenharmony_ci } 33301cb0ef41Sopenharmony_ci } 33311cb0ef41Sopenharmony_ci return false; 33321cb0ef41Sopenharmony_ci} 33331cb0ef41Sopenharmony_ci 33341cb0ef41Sopenharmony_civoid LinearScanAllocator::ComputeStateFromManyPredecessors( 33351cb0ef41Sopenharmony_ci InstructionBlock* current_block, RangeWithRegisterSet* to_be_live) { 33361cb0ef41Sopenharmony_ci struct Vote { 33371cb0ef41Sopenharmony_ci size_t count; 33381cb0ef41Sopenharmony_ci int used_registers[RegisterConfiguration::kMaxRegisters]; 33391cb0ef41Sopenharmony_ci }; 33401cb0ef41Sopenharmony_ci struct TopLevelLiveRangeComparator { 33411cb0ef41Sopenharmony_ci bool operator()(const TopLevelLiveRange* lhs, 33421cb0ef41Sopenharmony_ci const TopLevelLiveRange* rhs) const { 33431cb0ef41Sopenharmony_ci return lhs->vreg() < rhs->vreg(); 33441cb0ef41Sopenharmony_ci } 33451cb0ef41Sopenharmony_ci }; 33461cb0ef41Sopenharmony_ci ZoneMap<TopLevelLiveRange*, Vote, TopLevelLiveRangeComparator> counts( 33471cb0ef41Sopenharmony_ci data()->allocation_zone()); 33481cb0ef41Sopenharmony_ci int deferred_blocks = 0; 33491cb0ef41Sopenharmony_ci for (RpoNumber pred : current_block->predecessors()) { 33501cb0ef41Sopenharmony_ci if (!ConsiderBlockForControlFlow(current_block, pred)) { 33511cb0ef41Sopenharmony_ci // Back edges of a loop count as deferred here too. 33521cb0ef41Sopenharmony_ci deferred_blocks++; 33531cb0ef41Sopenharmony_ci continue; 33541cb0ef41Sopenharmony_ci } 33551cb0ef41Sopenharmony_ci const auto& pred_state = data()->GetSpillState(pred); 33561cb0ef41Sopenharmony_ci for (LiveRange* range : pred_state) { 33571cb0ef41Sopenharmony_ci // We might have spilled the register backwards, so the range we 33581cb0ef41Sopenharmony_ci // stored might have lost its register. Ignore those. 33591cb0ef41Sopenharmony_ci if (!range->HasRegisterAssigned()) continue; 33601cb0ef41Sopenharmony_ci TopLevelLiveRange* toplevel = range->TopLevel(); 33611cb0ef41Sopenharmony_ci auto previous = counts.find(toplevel); 33621cb0ef41Sopenharmony_ci if (previous == counts.end()) { 33631cb0ef41Sopenharmony_ci auto result = counts.emplace(std::make_pair(toplevel, Vote{1, {0}})); 33641cb0ef41Sopenharmony_ci CHECK(result.second); 33651cb0ef41Sopenharmony_ci result.first->second.used_registers[range->assigned_register()]++; 33661cb0ef41Sopenharmony_ci } else { 33671cb0ef41Sopenharmony_ci previous->second.count++; 33681cb0ef41Sopenharmony_ci previous->second.used_registers[range->assigned_register()]++; 33691cb0ef41Sopenharmony_ci } 33701cb0ef41Sopenharmony_ci } 33711cb0ef41Sopenharmony_ci } 33721cb0ef41Sopenharmony_ci 33731cb0ef41Sopenharmony_ci // Choose the live ranges from the majority. 33741cb0ef41Sopenharmony_ci const size_t majority = 33751cb0ef41Sopenharmony_ci (current_block->PredecessorCount() + 2 - deferred_blocks) / 2; 33761cb0ef41Sopenharmony_ci bool taken_registers[RegisterConfiguration::kMaxRegisters] = {false}; 33771cb0ef41Sopenharmony_ci auto assign_to_live = [this, counts, majority]( 33781cb0ef41Sopenharmony_ci std::function<bool(TopLevelLiveRange*)> filter, 33791cb0ef41Sopenharmony_ci RangeWithRegisterSet* to_be_live, 33801cb0ef41Sopenharmony_ci bool* taken_registers) { 33811cb0ef41Sopenharmony_ci bool check_aliasing = 33821cb0ef41Sopenharmony_ci kFPAliasing == AliasingKind::kCombine && check_fp_aliasing(); 33831cb0ef41Sopenharmony_ci for (const auto& val : counts) { 33841cb0ef41Sopenharmony_ci if (!filter(val.first)) continue; 33851cb0ef41Sopenharmony_ci if (val.second.count >= majority) { 33861cb0ef41Sopenharmony_ci int register_max = 0; 33871cb0ef41Sopenharmony_ci int reg = kUnassignedRegister; 33881cb0ef41Sopenharmony_ci bool conflict = false; 33891cb0ef41Sopenharmony_ci int num_regs = num_registers(); 33901cb0ef41Sopenharmony_ci int num_codes = num_allocatable_registers(); 33911cb0ef41Sopenharmony_ci const int* codes = allocatable_register_codes(); 33921cb0ef41Sopenharmony_ci MachineRepresentation rep = val.first->representation(); 33931cb0ef41Sopenharmony_ci if (check_aliasing && (rep == MachineRepresentation::kFloat32 || 33941cb0ef41Sopenharmony_ci rep == MachineRepresentation::kSimd128)) 33951cb0ef41Sopenharmony_ci GetFPRegisterSet(rep, &num_regs, &num_codes, &codes); 33961cb0ef41Sopenharmony_ci for (int idx = 0; idx < num_regs; idx++) { 33971cb0ef41Sopenharmony_ci int uses = val.second.used_registers[idx]; 33981cb0ef41Sopenharmony_ci if (uses == 0) continue; 33991cb0ef41Sopenharmony_ci if (uses > register_max || (conflict && uses == register_max)) { 34001cb0ef41Sopenharmony_ci reg = idx; 34011cb0ef41Sopenharmony_ci register_max = uses; 34021cb0ef41Sopenharmony_ci conflict = check_aliasing ? CheckConflict(rep, reg, to_be_live) 34031cb0ef41Sopenharmony_ci : taken_registers[reg]; 34041cb0ef41Sopenharmony_ci } 34051cb0ef41Sopenharmony_ci } 34061cb0ef41Sopenharmony_ci if (conflict) { 34071cb0ef41Sopenharmony_ci reg = kUnassignedRegister; 34081cb0ef41Sopenharmony_ci } else if (!check_aliasing) { 34091cb0ef41Sopenharmony_ci taken_registers[reg] = true; 34101cb0ef41Sopenharmony_ci } 34111cb0ef41Sopenharmony_ci to_be_live->emplace(val.first, reg); 34121cb0ef41Sopenharmony_ci TRACE("Reset %d as live due vote %zu in %s\n", 34131cb0ef41Sopenharmony_ci val.first->TopLevel()->vreg(), val.second.count, 34141cb0ef41Sopenharmony_ci RegisterName(reg)); 34151cb0ef41Sopenharmony_ci } 34161cb0ef41Sopenharmony_ci } 34171cb0ef41Sopenharmony_ci }; 34181cb0ef41Sopenharmony_ci // First round, process fixed registers, as these have precedence. 34191cb0ef41Sopenharmony_ci // There is only one fixed range per register, so we cannot have 34201cb0ef41Sopenharmony_ci // conflicts. 34211cb0ef41Sopenharmony_ci assign_to_live([](TopLevelLiveRange* r) { return r->IsFixed(); }, to_be_live, 34221cb0ef41Sopenharmony_ci taken_registers); 34231cb0ef41Sopenharmony_ci // Second round, process the rest. 34241cb0ef41Sopenharmony_ci assign_to_live([](TopLevelLiveRange* r) { return !r->IsFixed(); }, to_be_live, 34251cb0ef41Sopenharmony_ci taken_registers); 34261cb0ef41Sopenharmony_ci} 34271cb0ef41Sopenharmony_ci 34281cb0ef41Sopenharmony_cibool LinearScanAllocator::ConsiderBlockForControlFlow( 34291cb0ef41Sopenharmony_ci InstructionBlock* current_block, RpoNumber predecessor) { 34301cb0ef41Sopenharmony_ci // We ignore predecessors on back edges when looking for control flow effects, 34311cb0ef41Sopenharmony_ci // as those lie in the future of allocation and we have no data yet. Also, 34321cb0ef41Sopenharmony_ci // deferred bocks are ignored on deferred to non-deferred boundaries, as we do 34331cb0ef41Sopenharmony_ci // not want them to influence allocation of non deferred code. 34341cb0ef41Sopenharmony_ci return (predecessor < current_block->rpo_number()) && 34351cb0ef41Sopenharmony_ci (current_block->IsDeferred() || 34361cb0ef41Sopenharmony_ci !code()->InstructionBlockAt(predecessor)->IsDeferred()); 34371cb0ef41Sopenharmony_ci} 34381cb0ef41Sopenharmony_ci 34391cb0ef41Sopenharmony_civoid LinearScanAllocator::UpdateDeferredFixedRanges(SpillMode spill_mode, 34401cb0ef41Sopenharmony_ci InstructionBlock* block) { 34411cb0ef41Sopenharmony_ci if (spill_mode == SpillMode::kSpillDeferred) { 34421cb0ef41Sopenharmony_ci LifetimePosition max = LifetimePosition::InstructionFromInstructionIndex( 34431cb0ef41Sopenharmony_ci LastDeferredInstructionIndex(block)); 34441cb0ef41Sopenharmony_ci // Adds range back to inactive, resolving resulting conflicts. 34451cb0ef41Sopenharmony_ci auto add_to_inactive = [this, max](LiveRange* range) { 34461cb0ef41Sopenharmony_ci AddToInactive(range); 34471cb0ef41Sopenharmony_ci // Splits other if it conflicts with range. Other is placed in unhandled 34481cb0ef41Sopenharmony_ci // for later reallocation. 34491cb0ef41Sopenharmony_ci auto split_conflicting = [this, max](LiveRange* range, LiveRange* other, 34501cb0ef41Sopenharmony_ci std::function<void(LiveRange*)> 34511cb0ef41Sopenharmony_ci update_caches) { 34521cb0ef41Sopenharmony_ci if (other->TopLevel()->IsFixed()) return; 34531cb0ef41Sopenharmony_ci int reg = range->assigned_register(); 34541cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) { 34551cb0ef41Sopenharmony_ci if (other->assigned_register() != reg) { 34561cb0ef41Sopenharmony_ci return; 34571cb0ef41Sopenharmony_ci } 34581cb0ef41Sopenharmony_ci } else { 34591cb0ef41Sopenharmony_ci if (!data()->config()->AreAliases(range->representation(), reg, 34601cb0ef41Sopenharmony_ci other->representation(), 34611cb0ef41Sopenharmony_ci other->assigned_register())) { 34621cb0ef41Sopenharmony_ci return; 34631cb0ef41Sopenharmony_ci } 34641cb0ef41Sopenharmony_ci } 34651cb0ef41Sopenharmony_ci // The inactive range might conflict, so check whether we need to 34661cb0ef41Sopenharmony_ci // split and spill. We can look for the first intersection, as there 34671cb0ef41Sopenharmony_ci // cannot be any intersections in the past, as those would have been a 34681cb0ef41Sopenharmony_ci // conflict then. 34691cb0ef41Sopenharmony_ci LifetimePosition next_start = range->FirstIntersection(other); 34701cb0ef41Sopenharmony_ci if (!next_start.IsValid() || (next_start > max)) { 34711cb0ef41Sopenharmony_ci // There is no conflict or the conflict is outside of the current 34721cb0ef41Sopenharmony_ci // stretch of deferred code. In either case we can ignore the 34731cb0ef41Sopenharmony_ci // inactive range. 34741cb0ef41Sopenharmony_ci return; 34751cb0ef41Sopenharmony_ci } 34761cb0ef41Sopenharmony_ci // They overlap. So we need to split active and reschedule it 34771cb0ef41Sopenharmony_ci // for allocation. 34781cb0ef41Sopenharmony_ci TRACE("Resolving conflict of %d with deferred fixed for register %s\n", 34791cb0ef41Sopenharmony_ci other->TopLevel()->vreg(), 34801cb0ef41Sopenharmony_ci RegisterName(other->assigned_register())); 34811cb0ef41Sopenharmony_ci LiveRange* split_off = 34821cb0ef41Sopenharmony_ci other->SplitAt(next_start, data()->allocation_zone()); 34831cb0ef41Sopenharmony_ci // Try to get the same register after the deferred block. 34841cb0ef41Sopenharmony_ci split_off->set_controlflow_hint(other->assigned_register()); 34851cb0ef41Sopenharmony_ci DCHECK_NE(split_off, other); 34861cb0ef41Sopenharmony_ci AddToUnhandled(split_off); 34871cb0ef41Sopenharmony_ci update_caches(other); 34881cb0ef41Sopenharmony_ci }; 34891cb0ef41Sopenharmony_ci // Now check for conflicts in active and inactive ranges. We might have 34901cb0ef41Sopenharmony_ci // conflicts in inactive, as we do not do this check on every block 34911cb0ef41Sopenharmony_ci // boundary but only on deferred/non-deferred changes but inactive 34921cb0ef41Sopenharmony_ci // live ranges might become live on any block boundary. 34931cb0ef41Sopenharmony_ci for (auto active : active_live_ranges()) { 34941cb0ef41Sopenharmony_ci split_conflicting(range, active, [this](LiveRange* updated) { 34951cb0ef41Sopenharmony_ci next_active_ranges_change_ = 34961cb0ef41Sopenharmony_ci std::min(updated->End(), next_active_ranges_change_); 34971cb0ef41Sopenharmony_ci }); 34981cb0ef41Sopenharmony_ci } 34991cb0ef41Sopenharmony_ci for (int reg = 0; reg < num_registers(); ++reg) { 35001cb0ef41Sopenharmony_ci if ((kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) && 35011cb0ef41Sopenharmony_ci reg != range->assigned_register()) { 35021cb0ef41Sopenharmony_ci continue; 35031cb0ef41Sopenharmony_ci } 35041cb0ef41Sopenharmony_ci for (auto inactive : inactive_live_ranges(reg)) { 35051cb0ef41Sopenharmony_ci if (inactive->NextStart() > max) break; 35061cb0ef41Sopenharmony_ci split_conflicting(range, inactive, [this](LiveRange* updated) { 35071cb0ef41Sopenharmony_ci next_inactive_ranges_change_ = 35081cb0ef41Sopenharmony_ci std::min(updated->End(), next_inactive_ranges_change_); 35091cb0ef41Sopenharmony_ci }); 35101cb0ef41Sopenharmony_ci } 35111cb0ef41Sopenharmony_ci } 35121cb0ef41Sopenharmony_ci }; 35131cb0ef41Sopenharmony_ci if (mode() == RegisterKind::kGeneral) { 35141cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_live_ranges()) { 35151cb0ef41Sopenharmony_ci if (current != nullptr) { 35161cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) { 35171cb0ef41Sopenharmony_ci add_to_inactive(current); 35181cb0ef41Sopenharmony_ci } 35191cb0ef41Sopenharmony_ci } 35201cb0ef41Sopenharmony_ci } 35211cb0ef41Sopenharmony_ci } else if (mode() == RegisterKind::kDouble) { 35221cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_double_live_ranges()) { 35231cb0ef41Sopenharmony_ci if (current != nullptr) { 35241cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) { 35251cb0ef41Sopenharmony_ci add_to_inactive(current); 35261cb0ef41Sopenharmony_ci } 35271cb0ef41Sopenharmony_ci } 35281cb0ef41Sopenharmony_ci } 35291cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && check_fp_aliasing()) { 35301cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_float_live_ranges()) { 35311cb0ef41Sopenharmony_ci if (current != nullptr) { 35321cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) { 35331cb0ef41Sopenharmony_ci add_to_inactive(current); 35341cb0ef41Sopenharmony_ci } 35351cb0ef41Sopenharmony_ci } 35361cb0ef41Sopenharmony_ci } 35371cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_simd128_live_ranges()) { 35381cb0ef41Sopenharmony_ci if (current != nullptr) { 35391cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) { 35401cb0ef41Sopenharmony_ci add_to_inactive(current); 35411cb0ef41Sopenharmony_ci } 35421cb0ef41Sopenharmony_ci } 35431cb0ef41Sopenharmony_ci } 35441cb0ef41Sopenharmony_ci } 35451cb0ef41Sopenharmony_ci } else { 35461cb0ef41Sopenharmony_ci DCHECK_EQ(mode(), RegisterKind::kSimd128); 35471cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_simd128_live_ranges()) { 35481cb0ef41Sopenharmony_ci if (current != nullptr) { 35491cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) { 35501cb0ef41Sopenharmony_ci add_to_inactive(current); 35511cb0ef41Sopenharmony_ci } 35521cb0ef41Sopenharmony_ci } 35531cb0ef41Sopenharmony_ci } 35541cb0ef41Sopenharmony_ci } 35551cb0ef41Sopenharmony_ci } else { 35561cb0ef41Sopenharmony_ci // Remove all ranges. 35571cb0ef41Sopenharmony_ci for (int reg = 0; reg < num_registers(); ++reg) { 35581cb0ef41Sopenharmony_ci for (auto it = inactive_live_ranges(reg).begin(); 35591cb0ef41Sopenharmony_ci it != inactive_live_ranges(reg).end();) { 35601cb0ef41Sopenharmony_ci if ((*it)->TopLevel()->IsDeferredFixed()) { 35611cb0ef41Sopenharmony_ci it = inactive_live_ranges(reg).erase(it); 35621cb0ef41Sopenharmony_ci } else { 35631cb0ef41Sopenharmony_ci ++it; 35641cb0ef41Sopenharmony_ci } 35651cb0ef41Sopenharmony_ci } 35661cb0ef41Sopenharmony_ci } 35671cb0ef41Sopenharmony_ci } 35681cb0ef41Sopenharmony_ci} 35691cb0ef41Sopenharmony_ci 35701cb0ef41Sopenharmony_cibool LinearScanAllocator::BlockIsDeferredOrImmediatePredecessorIsNotDeferred( 35711cb0ef41Sopenharmony_ci const InstructionBlock* block) { 35721cb0ef41Sopenharmony_ci if (block->IsDeferred()) return true; 35731cb0ef41Sopenharmony_ci if (block->PredecessorCount() == 0) return true; 35741cb0ef41Sopenharmony_ci bool pred_is_deferred = false; 35751cb0ef41Sopenharmony_ci for (auto pred : block->predecessors()) { 35761cb0ef41Sopenharmony_ci if (pred.IsNext(block->rpo_number())) { 35771cb0ef41Sopenharmony_ci pred_is_deferred = code()->InstructionBlockAt(pred)->IsDeferred(); 35781cb0ef41Sopenharmony_ci break; 35791cb0ef41Sopenharmony_ci } 35801cb0ef41Sopenharmony_ci } 35811cb0ef41Sopenharmony_ci return !pred_is_deferred; 35821cb0ef41Sopenharmony_ci} 35831cb0ef41Sopenharmony_ci 35841cb0ef41Sopenharmony_cibool LinearScanAllocator::HasNonDeferredPredecessor(InstructionBlock* block) { 35851cb0ef41Sopenharmony_ci for (auto pred : block->predecessors()) { 35861cb0ef41Sopenharmony_ci InstructionBlock* pred_block = code()->InstructionBlockAt(pred); 35871cb0ef41Sopenharmony_ci if (!pred_block->IsDeferred()) return true; 35881cb0ef41Sopenharmony_ci } 35891cb0ef41Sopenharmony_ci return false; 35901cb0ef41Sopenharmony_ci} 35911cb0ef41Sopenharmony_ci 35921cb0ef41Sopenharmony_civoid LinearScanAllocator::AllocateRegisters() { 35931cb0ef41Sopenharmony_ci DCHECK(unhandled_live_ranges().empty()); 35941cb0ef41Sopenharmony_ci DCHECK(active_live_ranges().empty()); 35951cb0ef41Sopenharmony_ci for (int reg = 0; reg < num_registers(); ++reg) { 35961cb0ef41Sopenharmony_ci DCHECK(inactive_live_ranges(reg).empty()); 35971cb0ef41Sopenharmony_ci } 35981cb0ef41Sopenharmony_ci 35991cb0ef41Sopenharmony_ci SplitAndSpillRangesDefinedByMemoryOperand(); 36001cb0ef41Sopenharmony_ci data()->ResetSpillState(); 36011cb0ef41Sopenharmony_ci 36021cb0ef41Sopenharmony_ci if (data()->is_trace_alloc()) { 36031cb0ef41Sopenharmony_ci PrintRangeOverview(); 36041cb0ef41Sopenharmony_ci } 36051cb0ef41Sopenharmony_ci 36061cb0ef41Sopenharmony_ci const size_t live_ranges_size = data()->live_ranges().size(); 36071cb0ef41Sopenharmony_ci for (TopLevelLiveRange* range : data()->live_ranges()) { 36081cb0ef41Sopenharmony_ci CHECK_EQ(live_ranges_size, 36091cb0ef41Sopenharmony_ci data()->live_ranges().size()); // TODO(neis): crbug.com/831822 36101cb0ef41Sopenharmony_ci if (!CanProcessRange(range)) continue; 36111cb0ef41Sopenharmony_ci for (LiveRange* to_add = range; to_add != nullptr; 36121cb0ef41Sopenharmony_ci to_add = to_add->next()) { 36131cb0ef41Sopenharmony_ci if (!to_add->spilled()) { 36141cb0ef41Sopenharmony_ci AddToUnhandled(to_add); 36151cb0ef41Sopenharmony_ci } 36161cb0ef41Sopenharmony_ci } 36171cb0ef41Sopenharmony_ci } 36181cb0ef41Sopenharmony_ci 36191cb0ef41Sopenharmony_ci if (mode() == RegisterKind::kGeneral) { 36201cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_live_ranges()) { 36211cb0ef41Sopenharmony_ci if (current != nullptr) { 36221cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) continue; 36231cb0ef41Sopenharmony_ci AddToInactive(current); 36241cb0ef41Sopenharmony_ci } 36251cb0ef41Sopenharmony_ci } 36261cb0ef41Sopenharmony_ci } else if (mode() == RegisterKind::kDouble) { 36271cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_double_live_ranges()) { 36281cb0ef41Sopenharmony_ci if (current != nullptr) { 36291cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) continue; 36301cb0ef41Sopenharmony_ci AddToInactive(current); 36311cb0ef41Sopenharmony_ci } 36321cb0ef41Sopenharmony_ci } 36331cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && check_fp_aliasing()) { 36341cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_float_live_ranges()) { 36351cb0ef41Sopenharmony_ci if (current != nullptr) { 36361cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) continue; 36371cb0ef41Sopenharmony_ci AddToInactive(current); 36381cb0ef41Sopenharmony_ci } 36391cb0ef41Sopenharmony_ci } 36401cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_simd128_live_ranges()) { 36411cb0ef41Sopenharmony_ci if (current != nullptr) { 36421cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) continue; 36431cb0ef41Sopenharmony_ci AddToInactive(current); 36441cb0ef41Sopenharmony_ci } 36451cb0ef41Sopenharmony_ci } 36461cb0ef41Sopenharmony_ci } 36471cb0ef41Sopenharmony_ci } else { 36481cb0ef41Sopenharmony_ci DCHECK(mode() == RegisterKind::kSimd128); 36491cb0ef41Sopenharmony_ci for (TopLevelLiveRange* current : data()->fixed_simd128_live_ranges()) { 36501cb0ef41Sopenharmony_ci if (current != nullptr) { 36511cb0ef41Sopenharmony_ci if (current->IsDeferredFixed()) continue; 36521cb0ef41Sopenharmony_ci AddToInactive(current); 36531cb0ef41Sopenharmony_ci } 36541cb0ef41Sopenharmony_ci } 36551cb0ef41Sopenharmony_ci } 36561cb0ef41Sopenharmony_ci 36571cb0ef41Sopenharmony_ci RpoNumber last_block = RpoNumber::FromInt(0); 36581cb0ef41Sopenharmony_ci RpoNumber max_blocks = 36591cb0ef41Sopenharmony_ci RpoNumber::FromInt(code()->InstructionBlockCount() - 1); 36601cb0ef41Sopenharmony_ci LifetimePosition next_block_boundary = 36611cb0ef41Sopenharmony_ci LifetimePosition::InstructionFromInstructionIndex( 36621cb0ef41Sopenharmony_ci data() 36631cb0ef41Sopenharmony_ci ->code() 36641cb0ef41Sopenharmony_ci ->InstructionBlockAt(last_block) 36651cb0ef41Sopenharmony_ci ->last_instruction_index()) 36661cb0ef41Sopenharmony_ci .NextFullStart(); 36671cb0ef41Sopenharmony_ci SpillMode spill_mode = SpillMode::kSpillAtDefinition; 36681cb0ef41Sopenharmony_ci 36691cb0ef41Sopenharmony_ci // Process all ranges. We also need to ensure that we have seen all block 36701cb0ef41Sopenharmony_ci // boundaries. Linear scan might have assigned and spilled ranges before 36711cb0ef41Sopenharmony_ci // reaching the last block and hence we would ignore control flow effects for 36721cb0ef41Sopenharmony_ci // those. Not only does this produce a potentially bad assignment, it also 36731cb0ef41Sopenharmony_ci // breaks with the invariant that we undo spills that happen in deferred code 36741cb0ef41Sopenharmony_ci // when crossing a deferred/non-deferred boundary. 36751cb0ef41Sopenharmony_ci while (!unhandled_live_ranges().empty() || last_block < max_blocks) { 36761cb0ef41Sopenharmony_ci data()->tick_counter()->TickAndMaybeEnterSafepoint(); 36771cb0ef41Sopenharmony_ci LiveRange* current = unhandled_live_ranges().empty() 36781cb0ef41Sopenharmony_ci ? nullptr 36791cb0ef41Sopenharmony_ci : *unhandled_live_ranges().begin(); 36801cb0ef41Sopenharmony_ci LifetimePosition position = 36811cb0ef41Sopenharmony_ci current ? current->Start() : next_block_boundary; 36821cb0ef41Sopenharmony_ci#ifdef DEBUG 36831cb0ef41Sopenharmony_ci allocation_finger_ = position; 36841cb0ef41Sopenharmony_ci#endif 36851cb0ef41Sopenharmony_ci // Check whether we just moved across a block boundary. This will trigger 36861cb0ef41Sopenharmony_ci // for the first range that is past the current boundary. 36871cb0ef41Sopenharmony_ci if (position >= next_block_boundary) { 36881cb0ef41Sopenharmony_ci TRACE("Processing boundary at %d leaving %d\n", 36891cb0ef41Sopenharmony_ci next_block_boundary.value(), last_block.ToInt()); 36901cb0ef41Sopenharmony_ci 36911cb0ef41Sopenharmony_ci // Forward state to before block boundary 36921cb0ef41Sopenharmony_ci LifetimePosition end_of_block = next_block_boundary.PrevStart().End(); 36931cb0ef41Sopenharmony_ci ForwardStateTo(end_of_block); 36941cb0ef41Sopenharmony_ci 36951cb0ef41Sopenharmony_ci // Remember this state. 36961cb0ef41Sopenharmony_ci InstructionBlock* current_block = data()->code()->GetInstructionBlock( 36971cb0ef41Sopenharmony_ci next_block_boundary.ToInstructionIndex()); 36981cb0ef41Sopenharmony_ci 36991cb0ef41Sopenharmony_ci // Store current spill state (as the state at end of block). For 37001cb0ef41Sopenharmony_ci // simplicity, we store the active ranges, e.g., the live ranges that 37011cb0ef41Sopenharmony_ci // are not spilled. 37021cb0ef41Sopenharmony_ci data()->RememberSpillState(last_block, active_live_ranges()); 37031cb0ef41Sopenharmony_ci 37041cb0ef41Sopenharmony_ci // Only reset the state if this was not a direct fallthrough. Otherwise 37051cb0ef41Sopenharmony_ci // control flow resolution will get confused (it does not expect changes 37061cb0ef41Sopenharmony_ci // across fallthrough edges.). 37071cb0ef41Sopenharmony_ci bool fallthrough = 37081cb0ef41Sopenharmony_ci (current_block->PredecessorCount() == 1) && 37091cb0ef41Sopenharmony_ci current_block->predecessors()[0].IsNext(current_block->rpo_number()); 37101cb0ef41Sopenharmony_ci 37111cb0ef41Sopenharmony_ci // When crossing a deferred/non-deferred boundary, we have to load or 37121cb0ef41Sopenharmony_ci // remove the deferred fixed ranges from inactive. 37131cb0ef41Sopenharmony_ci if ((spill_mode == SpillMode::kSpillDeferred) != 37141cb0ef41Sopenharmony_ci current_block->IsDeferred()) { 37151cb0ef41Sopenharmony_ci // Update spill mode. 37161cb0ef41Sopenharmony_ci spill_mode = current_block->IsDeferred() 37171cb0ef41Sopenharmony_ci ? SpillMode::kSpillDeferred 37181cb0ef41Sopenharmony_ci : SpillMode::kSpillAtDefinition; 37191cb0ef41Sopenharmony_ci 37201cb0ef41Sopenharmony_ci ForwardStateTo(next_block_boundary); 37211cb0ef41Sopenharmony_ci 37221cb0ef41Sopenharmony_ci#ifdef DEBUG 37231cb0ef41Sopenharmony_ci // Allow allocation at current position. 37241cb0ef41Sopenharmony_ci allocation_finger_ = next_block_boundary; 37251cb0ef41Sopenharmony_ci#endif 37261cb0ef41Sopenharmony_ci UpdateDeferredFixedRanges(spill_mode, current_block); 37271cb0ef41Sopenharmony_ci } 37281cb0ef41Sopenharmony_ci 37291cb0ef41Sopenharmony_ci // Allocation relies on the fact that each non-deferred block has at 37301cb0ef41Sopenharmony_ci // least one non-deferred predecessor. Check this invariant here. 37311cb0ef41Sopenharmony_ci DCHECK_IMPLIES(!current_block->IsDeferred(), 37321cb0ef41Sopenharmony_ci HasNonDeferredPredecessor(current_block)); 37331cb0ef41Sopenharmony_ci 37341cb0ef41Sopenharmony_ci if (!fallthrough) { 37351cb0ef41Sopenharmony_ci#ifdef DEBUG 37361cb0ef41Sopenharmony_ci // Allow allocation at current position. 37371cb0ef41Sopenharmony_ci allocation_finger_ = next_block_boundary; 37381cb0ef41Sopenharmony_ci#endif 37391cb0ef41Sopenharmony_ci 37401cb0ef41Sopenharmony_ci // We are currently at next_block_boundary - 1. Move the state to the 37411cb0ef41Sopenharmony_ci // actual block boundary position. In particular, we have to 37421cb0ef41Sopenharmony_ci // reactivate inactive ranges so that they get rescheduled for 37431cb0ef41Sopenharmony_ci // allocation if they were not live at the predecessors. 37441cb0ef41Sopenharmony_ci ForwardStateTo(next_block_boundary); 37451cb0ef41Sopenharmony_ci 37461cb0ef41Sopenharmony_ci RangeWithRegisterSet to_be_live(data()->allocation_zone()); 37471cb0ef41Sopenharmony_ci 37481cb0ef41Sopenharmony_ci // If we end up deciding to use the state of the immediate 37491cb0ef41Sopenharmony_ci // predecessor, it is better not to perform a change. It would lead to 37501cb0ef41Sopenharmony_ci // the same outcome anyway. 37511cb0ef41Sopenharmony_ci // This may never happen on boundaries between deferred and 37521cb0ef41Sopenharmony_ci // non-deferred code, as we rely on explicit respill to ensure we 37531cb0ef41Sopenharmony_ci // spill at definition. 37541cb0ef41Sopenharmony_ci bool no_change_required = false; 37551cb0ef41Sopenharmony_ci 37561cb0ef41Sopenharmony_ci auto pick_state_from = [this, current_block]( 37571cb0ef41Sopenharmony_ci RpoNumber pred, 37581cb0ef41Sopenharmony_ci RangeWithRegisterSet* to_be_live) -> bool { 37591cb0ef41Sopenharmony_ci TRACE("Using information from B%d\n", pred.ToInt()); 37601cb0ef41Sopenharmony_ci // If this is a fall-through that is not across a deferred 37611cb0ef41Sopenharmony_ci // boundary, there is nothing to do. 37621cb0ef41Sopenharmony_ci bool is_noop = pred.IsNext(current_block->rpo_number()); 37631cb0ef41Sopenharmony_ci if (!is_noop) { 37641cb0ef41Sopenharmony_ci auto& spill_state = data()->GetSpillState(pred); 37651cb0ef41Sopenharmony_ci TRACE("Not a fallthrough. Adding %zu elements...\n", 37661cb0ef41Sopenharmony_ci spill_state.size()); 37671cb0ef41Sopenharmony_ci LifetimePosition pred_end = 37681cb0ef41Sopenharmony_ci LifetimePosition::GapFromInstructionIndex( 37691cb0ef41Sopenharmony_ci this->code()->InstructionBlockAt(pred)->code_end()); 37701cb0ef41Sopenharmony_ci for (const auto range : spill_state) { 37711cb0ef41Sopenharmony_ci // Filter out ranges that were split or had their register 37721cb0ef41Sopenharmony_ci // stolen by backwards working spill heuristics. These have 37731cb0ef41Sopenharmony_ci // been spilled after the fact, so ignore them. 37741cb0ef41Sopenharmony_ci if (range->End() < pred_end || !range->HasRegisterAssigned()) 37751cb0ef41Sopenharmony_ci continue; 37761cb0ef41Sopenharmony_ci to_be_live->emplace(range); 37771cb0ef41Sopenharmony_ci } 37781cb0ef41Sopenharmony_ci } 37791cb0ef41Sopenharmony_ci return is_noop; 37801cb0ef41Sopenharmony_ci }; 37811cb0ef41Sopenharmony_ci 37821cb0ef41Sopenharmony_ci // Multiple cases here: 37831cb0ef41Sopenharmony_ci // 1) We have a single predecessor => this is a control flow split, so 37841cb0ef41Sopenharmony_ci // just restore the predecessor state. 37851cb0ef41Sopenharmony_ci // 2) We have two predecessors => this is a conditional, so break ties 37861cb0ef41Sopenharmony_ci // based on what to do based on forward uses, trying to benefit 37871cb0ef41Sopenharmony_ci // the same branch if in doubt (make one path fast). 37881cb0ef41Sopenharmony_ci // 3) We have many predecessors => this is a switch. Compute union 37891cb0ef41Sopenharmony_ci // based on majority, break ties by looking forward. 37901cb0ef41Sopenharmony_ci if (current_block->PredecessorCount() == 1) { 37911cb0ef41Sopenharmony_ci TRACE("Single predecessor for B%d\n", 37921cb0ef41Sopenharmony_ci current_block->rpo_number().ToInt()); 37931cb0ef41Sopenharmony_ci no_change_required = 37941cb0ef41Sopenharmony_ci pick_state_from(current_block->predecessors()[0], &to_be_live); 37951cb0ef41Sopenharmony_ci } else if (current_block->PredecessorCount() == 2) { 37961cb0ef41Sopenharmony_ci TRACE("Two predecessors for B%d\n", 37971cb0ef41Sopenharmony_ci current_block->rpo_number().ToInt()); 37981cb0ef41Sopenharmony_ci // If one of the branches does not contribute any information, 37991cb0ef41Sopenharmony_ci // e.g. because it is deferred or a back edge, we can short cut 38001cb0ef41Sopenharmony_ci // here right away. 38011cb0ef41Sopenharmony_ci RpoNumber chosen_predecessor = RpoNumber::Invalid(); 38021cb0ef41Sopenharmony_ci if (!ConsiderBlockForControlFlow(current_block, 38031cb0ef41Sopenharmony_ci current_block->predecessors()[0])) { 38041cb0ef41Sopenharmony_ci chosen_predecessor = current_block->predecessors()[1]; 38051cb0ef41Sopenharmony_ci } else if (!ConsiderBlockForControlFlow( 38061cb0ef41Sopenharmony_ci current_block, current_block->predecessors()[1])) { 38071cb0ef41Sopenharmony_ci chosen_predecessor = current_block->predecessors()[0]; 38081cb0ef41Sopenharmony_ci } else { 38091cb0ef41Sopenharmony_ci chosen_predecessor = ChooseOneOfTwoPredecessorStates( 38101cb0ef41Sopenharmony_ci current_block, next_block_boundary); 38111cb0ef41Sopenharmony_ci } 38121cb0ef41Sopenharmony_ci no_change_required = pick_state_from(chosen_predecessor, &to_be_live); 38131cb0ef41Sopenharmony_ci 38141cb0ef41Sopenharmony_ci } else { 38151cb0ef41Sopenharmony_ci // Merge at the end of, e.g., a switch. 38161cb0ef41Sopenharmony_ci ComputeStateFromManyPredecessors(current_block, &to_be_live); 38171cb0ef41Sopenharmony_ci } 38181cb0ef41Sopenharmony_ci 38191cb0ef41Sopenharmony_ci if (!no_change_required) { 38201cb0ef41Sopenharmony_ci SpillNotLiveRanges(&to_be_live, next_block_boundary, spill_mode); 38211cb0ef41Sopenharmony_ci ReloadLiveRanges(to_be_live, next_block_boundary); 38221cb0ef41Sopenharmony_ci } 38231cb0ef41Sopenharmony_ci } 38241cb0ef41Sopenharmony_ci // Update block information 38251cb0ef41Sopenharmony_ci last_block = current_block->rpo_number(); 38261cb0ef41Sopenharmony_ci next_block_boundary = LifetimePosition::InstructionFromInstructionIndex( 38271cb0ef41Sopenharmony_ci current_block->last_instruction_index()) 38281cb0ef41Sopenharmony_ci .NextFullStart(); 38291cb0ef41Sopenharmony_ci 38301cb0ef41Sopenharmony_ci // We might have created new unhandled live ranges, so cycle around the 38311cb0ef41Sopenharmony_ci // loop to make sure we pick the top most range in unhandled for 38321cb0ef41Sopenharmony_ci // processing. 38331cb0ef41Sopenharmony_ci continue; 38341cb0ef41Sopenharmony_ci } 38351cb0ef41Sopenharmony_ci 38361cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(current); 38371cb0ef41Sopenharmony_ci 38381cb0ef41Sopenharmony_ci TRACE("Processing interval %d:%d start=%d\n", current->TopLevel()->vreg(), 38391cb0ef41Sopenharmony_ci current->relative_id(), position.value()); 38401cb0ef41Sopenharmony_ci 38411cb0ef41Sopenharmony_ci // Now we can erase current, as we are sure to process it. 38421cb0ef41Sopenharmony_ci unhandled_live_ranges().erase(unhandled_live_ranges().begin()); 38431cb0ef41Sopenharmony_ci 38441cb0ef41Sopenharmony_ci if (current->IsTopLevel() && TryReuseSpillForPhi(current->TopLevel())) 38451cb0ef41Sopenharmony_ci continue; 38461cb0ef41Sopenharmony_ci 38471cb0ef41Sopenharmony_ci ForwardStateTo(position); 38481cb0ef41Sopenharmony_ci 38491cb0ef41Sopenharmony_ci DCHECK(!current->HasRegisterAssigned() && !current->spilled()); 38501cb0ef41Sopenharmony_ci 38511cb0ef41Sopenharmony_ci ProcessCurrentRange(current, spill_mode); 38521cb0ef41Sopenharmony_ci } 38531cb0ef41Sopenharmony_ci 38541cb0ef41Sopenharmony_ci if (data()->is_trace_alloc()) { 38551cb0ef41Sopenharmony_ci PrintRangeOverview(); 38561cb0ef41Sopenharmony_ci } 38571cb0ef41Sopenharmony_ci} 38581cb0ef41Sopenharmony_ci 38591cb0ef41Sopenharmony_civoid LinearScanAllocator::SetLiveRangeAssignedRegister(LiveRange* range, 38601cb0ef41Sopenharmony_ci int reg) { 38611cb0ef41Sopenharmony_ci data()->MarkAllocated(range->representation(), reg); 38621cb0ef41Sopenharmony_ci range->set_assigned_register(reg); 38631cb0ef41Sopenharmony_ci range->SetUseHints(reg); 38641cb0ef41Sopenharmony_ci range->UpdateBundleRegister(reg); 38651cb0ef41Sopenharmony_ci if (range->IsTopLevel() && range->TopLevel()->is_phi()) { 38661cb0ef41Sopenharmony_ci data()->GetPhiMapValueFor(range->TopLevel())->set_assigned_register(reg); 38671cb0ef41Sopenharmony_ci } 38681cb0ef41Sopenharmony_ci} 38691cb0ef41Sopenharmony_ci 38701cb0ef41Sopenharmony_civoid LinearScanAllocator::AddToActive(LiveRange* range) { 38711cb0ef41Sopenharmony_ci TRACE("Add live range %d:%d in %s to active\n", range->TopLevel()->vreg(), 38721cb0ef41Sopenharmony_ci range->relative_id(), RegisterName(range->assigned_register())); 38731cb0ef41Sopenharmony_ci active_live_ranges().push_back(range); 38741cb0ef41Sopenharmony_ci next_active_ranges_change_ = 38751cb0ef41Sopenharmony_ci std::min(next_active_ranges_change_, range->NextEndAfter(range->Start())); 38761cb0ef41Sopenharmony_ci} 38771cb0ef41Sopenharmony_ci 38781cb0ef41Sopenharmony_civoid LinearScanAllocator::AddToInactive(LiveRange* range) { 38791cb0ef41Sopenharmony_ci TRACE("Add live range %d:%d to inactive\n", range->TopLevel()->vreg(), 38801cb0ef41Sopenharmony_ci range->relative_id()); 38811cb0ef41Sopenharmony_ci next_inactive_ranges_change_ = std::min( 38821cb0ef41Sopenharmony_ci next_inactive_ranges_change_, range->NextStartAfter(range->Start())); 38831cb0ef41Sopenharmony_ci DCHECK(range->HasRegisterAssigned()); 38841cb0ef41Sopenharmony_ci inactive_live_ranges(range->assigned_register()).insert(range); 38851cb0ef41Sopenharmony_ci} 38861cb0ef41Sopenharmony_ci 38871cb0ef41Sopenharmony_civoid LinearScanAllocator::AddToUnhandled(LiveRange* range) { 38881cb0ef41Sopenharmony_ci if (range == nullptr || range->IsEmpty()) return; 38891cb0ef41Sopenharmony_ci DCHECK(!range->HasRegisterAssigned() && !range->spilled()); 38901cb0ef41Sopenharmony_ci DCHECK(allocation_finger_ <= range->Start()); 38911cb0ef41Sopenharmony_ci 38921cb0ef41Sopenharmony_ci TRACE("Add live range %d:%d to unhandled\n", range->TopLevel()->vreg(), 38931cb0ef41Sopenharmony_ci range->relative_id()); 38941cb0ef41Sopenharmony_ci unhandled_live_ranges().insert(range); 38951cb0ef41Sopenharmony_ci} 38961cb0ef41Sopenharmony_ci 38971cb0ef41Sopenharmony_ciZoneVector<LiveRange*>::iterator LinearScanAllocator::ActiveToHandled( 38981cb0ef41Sopenharmony_ci const ZoneVector<LiveRange*>::iterator it) { 38991cb0ef41Sopenharmony_ci TRACE("Moving live range %d:%d from active to handled\n", 39001cb0ef41Sopenharmony_ci (*it)->TopLevel()->vreg(), (*it)->relative_id()); 39011cb0ef41Sopenharmony_ci return active_live_ranges().erase(it); 39021cb0ef41Sopenharmony_ci} 39031cb0ef41Sopenharmony_ci 39041cb0ef41Sopenharmony_ciZoneVector<LiveRange*>::iterator LinearScanAllocator::ActiveToInactive( 39051cb0ef41Sopenharmony_ci const ZoneVector<LiveRange*>::iterator it, LifetimePosition position) { 39061cb0ef41Sopenharmony_ci LiveRange* range = *it; 39071cb0ef41Sopenharmony_ci TRACE("Moving live range %d:%d from active to inactive\n", 39081cb0ef41Sopenharmony_ci (range)->TopLevel()->vreg(), range->relative_id()); 39091cb0ef41Sopenharmony_ci LifetimePosition next_active = range->NextStartAfter(position); 39101cb0ef41Sopenharmony_ci next_inactive_ranges_change_ = 39111cb0ef41Sopenharmony_ci std::min(next_inactive_ranges_change_, next_active); 39121cb0ef41Sopenharmony_ci DCHECK(range->HasRegisterAssigned()); 39131cb0ef41Sopenharmony_ci inactive_live_ranges(range->assigned_register()).insert(range); 39141cb0ef41Sopenharmony_ci return active_live_ranges().erase(it); 39151cb0ef41Sopenharmony_ci} 39161cb0ef41Sopenharmony_ci 39171cb0ef41Sopenharmony_ciLinearScanAllocator::InactiveLiveRangeQueue::iterator 39181cb0ef41Sopenharmony_ciLinearScanAllocator::InactiveToHandled(InactiveLiveRangeQueue::iterator it) { 39191cb0ef41Sopenharmony_ci LiveRange* range = *it; 39201cb0ef41Sopenharmony_ci TRACE("Moving live range %d:%d from inactive to handled\n", 39211cb0ef41Sopenharmony_ci range->TopLevel()->vreg(), range->relative_id()); 39221cb0ef41Sopenharmony_ci int reg = range->assigned_register(); 39231cb0ef41Sopenharmony_ci return inactive_live_ranges(reg).erase(it); 39241cb0ef41Sopenharmony_ci} 39251cb0ef41Sopenharmony_ci 39261cb0ef41Sopenharmony_ciLinearScanAllocator::InactiveLiveRangeQueue::iterator 39271cb0ef41Sopenharmony_ciLinearScanAllocator::InactiveToActive(InactiveLiveRangeQueue::iterator it, 39281cb0ef41Sopenharmony_ci LifetimePosition position) { 39291cb0ef41Sopenharmony_ci LiveRange* range = *it; 39301cb0ef41Sopenharmony_ci active_live_ranges().push_back(range); 39311cb0ef41Sopenharmony_ci TRACE("Moving live range %d:%d from inactive to active\n", 39321cb0ef41Sopenharmony_ci range->TopLevel()->vreg(), range->relative_id()); 39331cb0ef41Sopenharmony_ci next_active_ranges_change_ = 39341cb0ef41Sopenharmony_ci std::min(next_active_ranges_change_, range->NextEndAfter(position)); 39351cb0ef41Sopenharmony_ci int reg = range->assigned_register(); 39361cb0ef41Sopenharmony_ci return inactive_live_ranges(reg).erase(it); 39371cb0ef41Sopenharmony_ci} 39381cb0ef41Sopenharmony_ci 39391cb0ef41Sopenharmony_civoid LinearScanAllocator::ForwardStateTo(LifetimePosition position) { 39401cb0ef41Sopenharmony_ci if (position >= next_active_ranges_change_) { 39411cb0ef41Sopenharmony_ci next_active_ranges_change_ = LifetimePosition::MaxPosition(); 39421cb0ef41Sopenharmony_ci for (auto it = active_live_ranges().begin(); 39431cb0ef41Sopenharmony_ci it != active_live_ranges().end();) { 39441cb0ef41Sopenharmony_ci LiveRange* cur_active = *it; 39451cb0ef41Sopenharmony_ci if (cur_active->End() <= position) { 39461cb0ef41Sopenharmony_ci it = ActiveToHandled(it); 39471cb0ef41Sopenharmony_ci } else if (!cur_active->Covers(position)) { 39481cb0ef41Sopenharmony_ci it = ActiveToInactive(it, position); 39491cb0ef41Sopenharmony_ci } else { 39501cb0ef41Sopenharmony_ci next_active_ranges_change_ = std::min( 39511cb0ef41Sopenharmony_ci next_active_ranges_change_, cur_active->NextEndAfter(position)); 39521cb0ef41Sopenharmony_ci ++it; 39531cb0ef41Sopenharmony_ci } 39541cb0ef41Sopenharmony_ci } 39551cb0ef41Sopenharmony_ci } 39561cb0ef41Sopenharmony_ci 39571cb0ef41Sopenharmony_ci if (position >= next_inactive_ranges_change_) { 39581cb0ef41Sopenharmony_ci next_inactive_ranges_change_ = LifetimePosition::MaxPosition(); 39591cb0ef41Sopenharmony_ci for (int reg = 0; reg < num_registers(); ++reg) { 39601cb0ef41Sopenharmony_ci ZoneVector<LiveRange*> reorder(data()->allocation_zone()); 39611cb0ef41Sopenharmony_ci for (auto it = inactive_live_ranges(reg).begin(); 39621cb0ef41Sopenharmony_ci it != inactive_live_ranges(reg).end();) { 39631cb0ef41Sopenharmony_ci LiveRange* cur_inactive = *it; 39641cb0ef41Sopenharmony_ci if (cur_inactive->End() <= position) { 39651cb0ef41Sopenharmony_ci it = InactiveToHandled(it); 39661cb0ef41Sopenharmony_ci } else if (cur_inactive->Covers(position)) { 39671cb0ef41Sopenharmony_ci it = InactiveToActive(it, position); 39681cb0ef41Sopenharmony_ci } else { 39691cb0ef41Sopenharmony_ci next_inactive_ranges_change_ = 39701cb0ef41Sopenharmony_ci std::min(next_inactive_ranges_change_, 39711cb0ef41Sopenharmony_ci cur_inactive->NextStartAfter(position)); 39721cb0ef41Sopenharmony_ci it = inactive_live_ranges(reg).erase(it); 39731cb0ef41Sopenharmony_ci reorder.push_back(cur_inactive); 39741cb0ef41Sopenharmony_ci } 39751cb0ef41Sopenharmony_ci } 39761cb0ef41Sopenharmony_ci for (LiveRange* range : reorder) { 39771cb0ef41Sopenharmony_ci inactive_live_ranges(reg).insert(range); 39781cb0ef41Sopenharmony_ci } 39791cb0ef41Sopenharmony_ci } 39801cb0ef41Sopenharmony_ci } 39811cb0ef41Sopenharmony_ci} 39821cb0ef41Sopenharmony_ci 39831cb0ef41Sopenharmony_ciint LinearScanAllocator::LastDeferredInstructionIndex(InstructionBlock* start) { 39841cb0ef41Sopenharmony_ci DCHECK(start->IsDeferred()); 39851cb0ef41Sopenharmony_ci RpoNumber last_block = 39861cb0ef41Sopenharmony_ci RpoNumber::FromInt(code()->InstructionBlockCount() - 1); 39871cb0ef41Sopenharmony_ci while ((start->rpo_number() < last_block)) { 39881cb0ef41Sopenharmony_ci InstructionBlock* next = 39891cb0ef41Sopenharmony_ci code()->InstructionBlockAt(start->rpo_number().Next()); 39901cb0ef41Sopenharmony_ci if (!next->IsDeferred()) break; 39911cb0ef41Sopenharmony_ci start = next; 39921cb0ef41Sopenharmony_ci } 39931cb0ef41Sopenharmony_ci return start->last_instruction_index(); 39941cb0ef41Sopenharmony_ci} 39951cb0ef41Sopenharmony_ci 39961cb0ef41Sopenharmony_civoid LinearScanAllocator::GetFPRegisterSet(MachineRepresentation rep, 39971cb0ef41Sopenharmony_ci int* num_regs, int* num_codes, 39981cb0ef41Sopenharmony_ci const int** codes) const { 39991cb0ef41Sopenharmony_ci DCHECK_EQ(kFPAliasing, AliasingKind::kCombine); 40001cb0ef41Sopenharmony_ci if (rep == MachineRepresentation::kFloat32) { 40011cb0ef41Sopenharmony_ci *num_regs = data()->config()->num_float_registers(); 40021cb0ef41Sopenharmony_ci *num_codes = data()->config()->num_allocatable_float_registers(); 40031cb0ef41Sopenharmony_ci *codes = data()->config()->allocatable_float_codes(); 40041cb0ef41Sopenharmony_ci } else if (rep == MachineRepresentation::kSimd128) { 40051cb0ef41Sopenharmony_ci *num_regs = data()->config()->num_simd128_registers(); 40061cb0ef41Sopenharmony_ci *num_codes = data()->config()->num_allocatable_simd128_registers(); 40071cb0ef41Sopenharmony_ci *codes = data()->config()->allocatable_simd128_codes(); 40081cb0ef41Sopenharmony_ci } else { 40091cb0ef41Sopenharmony_ci UNREACHABLE(); 40101cb0ef41Sopenharmony_ci } 40111cb0ef41Sopenharmony_ci} 40121cb0ef41Sopenharmony_ci 40131cb0ef41Sopenharmony_civoid LinearScanAllocator::GetSIMD128RegisterSet(int* num_regs, int* num_codes, 40141cb0ef41Sopenharmony_ci const int** codes) const { 40151cb0ef41Sopenharmony_ci DCHECK_EQ(kFPAliasing, AliasingKind::kIndependent); 40161cb0ef41Sopenharmony_ci 40171cb0ef41Sopenharmony_ci *num_regs = data()->config()->num_simd128_registers(); 40181cb0ef41Sopenharmony_ci *num_codes = data()->config()->num_allocatable_simd128_registers(); 40191cb0ef41Sopenharmony_ci *codes = data()->config()->allocatable_simd128_codes(); 40201cb0ef41Sopenharmony_ci} 40211cb0ef41Sopenharmony_ci 40221cb0ef41Sopenharmony_civoid LinearScanAllocator::FindFreeRegistersForRange( 40231cb0ef41Sopenharmony_ci LiveRange* range, base::Vector<LifetimePosition> positions) { 40241cb0ef41Sopenharmony_ci int num_regs = num_registers(); 40251cb0ef41Sopenharmony_ci int num_codes = num_allocatable_registers(); 40261cb0ef41Sopenharmony_ci const int* codes = allocatable_register_codes(); 40271cb0ef41Sopenharmony_ci MachineRepresentation rep = range->representation(); 40281cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 40291cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kFloat32 || 40301cb0ef41Sopenharmony_ci rep == MachineRepresentation::kSimd128)) { 40311cb0ef41Sopenharmony_ci GetFPRegisterSet(rep, &num_regs, &num_codes, &codes); 40321cb0ef41Sopenharmony_ci } else if (kFPAliasing == AliasingKind::kIndependent && 40331cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kSimd128)) { 40341cb0ef41Sopenharmony_ci GetSIMD128RegisterSet(&num_regs, &num_codes, &codes); 40351cb0ef41Sopenharmony_ci } 40361cb0ef41Sopenharmony_ci DCHECK_GE(positions.length(), num_regs); 40371cb0ef41Sopenharmony_ci 40381cb0ef41Sopenharmony_ci for (int i = 0; i < num_regs; ++i) { 40391cb0ef41Sopenharmony_ci positions[i] = LifetimePosition::MaxPosition(); 40401cb0ef41Sopenharmony_ci } 40411cb0ef41Sopenharmony_ci 40421cb0ef41Sopenharmony_ci for (LiveRange* cur_active : active_live_ranges()) { 40431cb0ef41Sopenharmony_ci int cur_reg = cur_active->assigned_register(); 40441cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) { 40451cb0ef41Sopenharmony_ci positions[cur_reg] = LifetimePosition::GapFromInstructionIndex(0); 40461cb0ef41Sopenharmony_ci TRACE("Register %s is free until pos %d (1) due to %d\n", 40471cb0ef41Sopenharmony_ci RegisterName(cur_reg), 40481cb0ef41Sopenharmony_ci LifetimePosition::GapFromInstructionIndex(0).value(), 40491cb0ef41Sopenharmony_ci cur_active->TopLevel()->vreg()); 40501cb0ef41Sopenharmony_ci } else { 40511cb0ef41Sopenharmony_ci int alias_base_index = -1; 40521cb0ef41Sopenharmony_ci int aliases = data()->config()->GetAliases( 40531cb0ef41Sopenharmony_ci cur_active->representation(), cur_reg, rep, &alias_base_index); 40541cb0ef41Sopenharmony_ci DCHECK(aliases > 0 || (aliases == 0 && alias_base_index == -1)); 40551cb0ef41Sopenharmony_ci while (aliases--) { 40561cb0ef41Sopenharmony_ci int aliased_reg = alias_base_index + aliases; 40571cb0ef41Sopenharmony_ci positions[aliased_reg] = LifetimePosition::GapFromInstructionIndex(0); 40581cb0ef41Sopenharmony_ci } 40591cb0ef41Sopenharmony_ci } 40601cb0ef41Sopenharmony_ci } 40611cb0ef41Sopenharmony_ci 40621cb0ef41Sopenharmony_ci for (int cur_reg = 0; cur_reg < num_regs; ++cur_reg) { 40631cb0ef41Sopenharmony_ci for (LiveRange* cur_inactive : inactive_live_ranges(cur_reg)) { 40641cb0ef41Sopenharmony_ci DCHECK_GT(cur_inactive->End(), range->Start()); 40651cb0ef41Sopenharmony_ci CHECK_EQ(cur_inactive->assigned_register(), cur_reg); 40661cb0ef41Sopenharmony_ci // No need to carry out intersections, when this register won't be 40671cb0ef41Sopenharmony_ci // interesting to this range anyway. 40681cb0ef41Sopenharmony_ci // TODO(mtrofin): extend to aliased ranges, too. 40691cb0ef41Sopenharmony_ci if ((kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) && 40701cb0ef41Sopenharmony_ci (positions[cur_reg] <= cur_inactive->NextStart() || 40711cb0ef41Sopenharmony_ci range->End() <= cur_inactive->NextStart())) { 40721cb0ef41Sopenharmony_ci break; 40731cb0ef41Sopenharmony_ci } 40741cb0ef41Sopenharmony_ci LifetimePosition next_intersection = 40751cb0ef41Sopenharmony_ci cur_inactive->FirstIntersection(range); 40761cb0ef41Sopenharmony_ci if (!next_intersection.IsValid()) continue; 40771cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) { 40781cb0ef41Sopenharmony_ci positions[cur_reg] = std::min(positions[cur_reg], next_intersection); 40791cb0ef41Sopenharmony_ci TRACE("Register %s is free until pos %d (2)\n", RegisterName(cur_reg), 40801cb0ef41Sopenharmony_ci positions[cur_reg].value()); 40811cb0ef41Sopenharmony_ci } else { 40821cb0ef41Sopenharmony_ci int alias_base_index = -1; 40831cb0ef41Sopenharmony_ci int aliases = data()->config()->GetAliases( 40841cb0ef41Sopenharmony_ci cur_inactive->representation(), cur_reg, rep, &alias_base_index); 40851cb0ef41Sopenharmony_ci DCHECK(aliases > 0 || (aliases == 0 && alias_base_index == -1)); 40861cb0ef41Sopenharmony_ci while (aliases--) { 40871cb0ef41Sopenharmony_ci int aliased_reg = alias_base_index + aliases; 40881cb0ef41Sopenharmony_ci positions[aliased_reg] = 40891cb0ef41Sopenharmony_ci std::min(positions[aliased_reg], next_intersection); 40901cb0ef41Sopenharmony_ci } 40911cb0ef41Sopenharmony_ci } 40921cb0ef41Sopenharmony_ci } 40931cb0ef41Sopenharmony_ci } 40941cb0ef41Sopenharmony_ci} 40951cb0ef41Sopenharmony_ci 40961cb0ef41Sopenharmony_ci// High-level register allocation summary: 40971cb0ef41Sopenharmony_ci// 40981cb0ef41Sopenharmony_ci// We attempt to first allocate the preferred (hint) register. If that is not 40991cb0ef41Sopenharmony_ci// possible, we find a register that's free, and allocate that. If that's not 41001cb0ef41Sopenharmony_ci// possible, we search for a register to steal from a range that was allocated. 41011cb0ef41Sopenharmony_ci// The goal is to optimize for throughput by avoiding register-to-memory moves, 41021cb0ef41Sopenharmony_ci// which are expensive. 41031cb0ef41Sopenharmony_civoid LinearScanAllocator::ProcessCurrentRange(LiveRange* current, 41041cb0ef41Sopenharmony_ci SpillMode spill_mode) { 41051cb0ef41Sopenharmony_ci base::EmbeddedVector<LifetimePosition, RegisterConfiguration::kMaxRegisters> 41061cb0ef41Sopenharmony_ci free_until_pos; 41071cb0ef41Sopenharmony_ci FindFreeRegistersForRange(current, free_until_pos); 41081cb0ef41Sopenharmony_ci if (!TryAllocatePreferredReg(current, free_until_pos)) { 41091cb0ef41Sopenharmony_ci if (!TryAllocateFreeReg(current, free_until_pos)) { 41101cb0ef41Sopenharmony_ci AllocateBlockedReg(current, spill_mode); 41111cb0ef41Sopenharmony_ci } 41121cb0ef41Sopenharmony_ci } 41131cb0ef41Sopenharmony_ci if (current->HasRegisterAssigned()) { 41141cb0ef41Sopenharmony_ci AddToActive(current); 41151cb0ef41Sopenharmony_ci } 41161cb0ef41Sopenharmony_ci} 41171cb0ef41Sopenharmony_ci 41181cb0ef41Sopenharmony_cibool LinearScanAllocator::TryAllocatePreferredReg( 41191cb0ef41Sopenharmony_ci LiveRange* current, const base::Vector<LifetimePosition>& free_until_pos) { 41201cb0ef41Sopenharmony_ci int hint_register; 41211cb0ef41Sopenharmony_ci if (current->RegisterFromControlFlow(&hint_register) || 41221cb0ef41Sopenharmony_ci current->FirstHintPosition(&hint_register) != nullptr || 41231cb0ef41Sopenharmony_ci current->RegisterFromBundle(&hint_register)) { 41241cb0ef41Sopenharmony_ci TRACE( 41251cb0ef41Sopenharmony_ci "Found reg hint %s (free until [%d) for live range %d:%d (end %d[).\n", 41261cb0ef41Sopenharmony_ci RegisterName(hint_register), free_until_pos[hint_register].value(), 41271cb0ef41Sopenharmony_ci current->TopLevel()->vreg(), current->relative_id(), 41281cb0ef41Sopenharmony_ci current->End().value()); 41291cb0ef41Sopenharmony_ci 41301cb0ef41Sopenharmony_ci // The desired register is free until the end of the current live range. 41311cb0ef41Sopenharmony_ci if (free_until_pos[hint_register] >= current->End()) { 41321cb0ef41Sopenharmony_ci TRACE("Assigning preferred reg %s to live range %d:%d\n", 41331cb0ef41Sopenharmony_ci RegisterName(hint_register), current->TopLevel()->vreg(), 41341cb0ef41Sopenharmony_ci current->relative_id()); 41351cb0ef41Sopenharmony_ci SetLiveRangeAssignedRegister(current, hint_register); 41361cb0ef41Sopenharmony_ci return true; 41371cb0ef41Sopenharmony_ci } 41381cb0ef41Sopenharmony_ci } 41391cb0ef41Sopenharmony_ci return false; 41401cb0ef41Sopenharmony_ci} 41411cb0ef41Sopenharmony_ci 41421cb0ef41Sopenharmony_ciint LinearScanAllocator::PickRegisterThatIsAvailableLongest( 41431cb0ef41Sopenharmony_ci LiveRange* current, int hint_reg, 41441cb0ef41Sopenharmony_ci const base::Vector<LifetimePosition>& free_until_pos) { 41451cb0ef41Sopenharmony_ci int num_regs = 0; // used only for the call to GetFPRegisterSet. 41461cb0ef41Sopenharmony_ci int num_codes = num_allocatable_registers(); 41471cb0ef41Sopenharmony_ci const int* codes = allocatable_register_codes(); 41481cb0ef41Sopenharmony_ci MachineRepresentation rep = current->representation(); 41491cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 41501cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kFloat32 || 41511cb0ef41Sopenharmony_ci rep == MachineRepresentation::kSimd128)) { 41521cb0ef41Sopenharmony_ci GetFPRegisterSet(rep, &num_regs, &num_codes, &codes); 41531cb0ef41Sopenharmony_ci } else if (kFPAliasing == AliasingKind::kIndependent && 41541cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kSimd128)) { 41551cb0ef41Sopenharmony_ci GetSIMD128RegisterSet(&num_regs, &num_codes, &codes); 41561cb0ef41Sopenharmony_ci } 41571cb0ef41Sopenharmony_ci 41581cb0ef41Sopenharmony_ci DCHECK_GE(free_until_pos.length(), num_codes); 41591cb0ef41Sopenharmony_ci 41601cb0ef41Sopenharmony_ci // Find the register which stays free for the longest time. Check for 41611cb0ef41Sopenharmony_ci // the hinted register first, as we might want to use that one. Only 41621cb0ef41Sopenharmony_ci // count full instructions for free ranges, as an instruction's internal 41631cb0ef41Sopenharmony_ci // positions do not help but might shadow a hinted register. This is 41641cb0ef41Sopenharmony_ci // typically the case for function calls, where all registered are 41651cb0ef41Sopenharmony_ci // cloberred after the call except for the argument registers, which are 41661cb0ef41Sopenharmony_ci // set before the call. Hence, the argument registers always get ignored, 41671cb0ef41Sopenharmony_ci // as their available time is shorter. 41681cb0ef41Sopenharmony_ci int reg = (hint_reg == kUnassignedRegister) ? codes[0] : hint_reg; 41691cb0ef41Sopenharmony_ci int current_free = free_until_pos[reg].ToInstructionIndex(); 41701cb0ef41Sopenharmony_ci for (int i = 0; i < num_codes; ++i) { 41711cb0ef41Sopenharmony_ci int code = codes[i]; 41721cb0ef41Sopenharmony_ci // Prefer registers that have no fixed uses to avoid blocking later hints. 41731cb0ef41Sopenharmony_ci // We use the first register that has no fixed uses to ensure we use 41741cb0ef41Sopenharmony_ci // byte addressable registers in ia32 first. 41751cb0ef41Sopenharmony_ci int candidate_free = free_until_pos[code].ToInstructionIndex(); 41761cb0ef41Sopenharmony_ci TRACE("Register %s in free until %d\n", RegisterName(code), candidate_free); 41771cb0ef41Sopenharmony_ci if ((candidate_free > current_free) || 41781cb0ef41Sopenharmony_ci (candidate_free == current_free && reg != hint_reg && 41791cb0ef41Sopenharmony_ci (data()->HasFixedUse(current->representation(), reg) && 41801cb0ef41Sopenharmony_ci !data()->HasFixedUse(current->representation(), code)))) { 41811cb0ef41Sopenharmony_ci reg = code; 41821cb0ef41Sopenharmony_ci current_free = candidate_free; 41831cb0ef41Sopenharmony_ci } 41841cb0ef41Sopenharmony_ci } 41851cb0ef41Sopenharmony_ci 41861cb0ef41Sopenharmony_ci return reg; 41871cb0ef41Sopenharmony_ci} 41881cb0ef41Sopenharmony_ci 41891cb0ef41Sopenharmony_cibool LinearScanAllocator::TryAllocateFreeReg( 41901cb0ef41Sopenharmony_ci LiveRange* current, const base::Vector<LifetimePosition>& free_until_pos) { 41911cb0ef41Sopenharmony_ci // Compute register hint, if such exists. 41921cb0ef41Sopenharmony_ci int hint_reg = kUnassignedRegister; 41931cb0ef41Sopenharmony_ci current->RegisterFromControlFlow(&hint_reg) || 41941cb0ef41Sopenharmony_ci current->FirstHintPosition(&hint_reg) != nullptr || 41951cb0ef41Sopenharmony_ci current->RegisterFromBundle(&hint_reg); 41961cb0ef41Sopenharmony_ci 41971cb0ef41Sopenharmony_ci int reg = 41981cb0ef41Sopenharmony_ci PickRegisterThatIsAvailableLongest(current, hint_reg, free_until_pos); 41991cb0ef41Sopenharmony_ci 42001cb0ef41Sopenharmony_ci LifetimePosition pos = free_until_pos[reg]; 42011cb0ef41Sopenharmony_ci 42021cb0ef41Sopenharmony_ci if (pos <= current->Start()) { 42031cb0ef41Sopenharmony_ci // All registers are blocked. 42041cb0ef41Sopenharmony_ci return false; 42051cb0ef41Sopenharmony_ci } 42061cb0ef41Sopenharmony_ci 42071cb0ef41Sopenharmony_ci if (pos < current->End()) { 42081cb0ef41Sopenharmony_ci // Register reg is available at the range start but becomes blocked before 42091cb0ef41Sopenharmony_ci // the range end. Split current before the position where it becomes 42101cb0ef41Sopenharmony_ci // blocked. Shift the split position to the last gap position. This is to 42111cb0ef41Sopenharmony_ci // ensure that if a connecting move is needed, that move coincides with the 42121cb0ef41Sopenharmony_ci // start of the range that it defines. See crbug.com/1182985. 42131cb0ef41Sopenharmony_ci LifetimePosition gap_pos = 42141cb0ef41Sopenharmony_ci pos.IsGapPosition() ? pos : pos.FullStart().End(); 42151cb0ef41Sopenharmony_ci if (gap_pos <= current->Start()) return false; 42161cb0ef41Sopenharmony_ci LiveRange* tail = SplitRangeAt(current, gap_pos); 42171cb0ef41Sopenharmony_ci AddToUnhandled(tail); 42181cb0ef41Sopenharmony_ci 42191cb0ef41Sopenharmony_ci // Try to allocate preferred register once more. 42201cb0ef41Sopenharmony_ci if (TryAllocatePreferredReg(current, free_until_pos)) return true; 42211cb0ef41Sopenharmony_ci } 42221cb0ef41Sopenharmony_ci 42231cb0ef41Sopenharmony_ci // Register reg is available at the range start and is free until the range 42241cb0ef41Sopenharmony_ci // end. 42251cb0ef41Sopenharmony_ci DCHECK_GE(pos, current->End()); 42261cb0ef41Sopenharmony_ci TRACE("Assigning free reg %s to live range %d:%d\n", RegisterName(reg), 42271cb0ef41Sopenharmony_ci current->TopLevel()->vreg(), current->relative_id()); 42281cb0ef41Sopenharmony_ci SetLiveRangeAssignedRegister(current, reg); 42291cb0ef41Sopenharmony_ci 42301cb0ef41Sopenharmony_ci return true; 42311cb0ef41Sopenharmony_ci} 42321cb0ef41Sopenharmony_ci 42331cb0ef41Sopenharmony_civoid LinearScanAllocator::AllocateBlockedReg(LiveRange* current, 42341cb0ef41Sopenharmony_ci SpillMode spill_mode) { 42351cb0ef41Sopenharmony_ci UsePosition* register_use = current->NextRegisterPosition(current->Start()); 42361cb0ef41Sopenharmony_ci if (register_use == nullptr) { 42371cb0ef41Sopenharmony_ci // There is no use in the current live range that requires a register. 42381cb0ef41Sopenharmony_ci // We can just spill it. 42391cb0ef41Sopenharmony_ci LiveRange* begin_spill = nullptr; 42401cb0ef41Sopenharmony_ci LifetimePosition spill_pos = FindOptimalSpillingPos( 42411cb0ef41Sopenharmony_ci current, current->Start(), spill_mode, &begin_spill); 42421cb0ef41Sopenharmony_ci MaybeSpillPreviousRanges(begin_spill, spill_pos, current); 42431cb0ef41Sopenharmony_ci Spill(current, spill_mode); 42441cb0ef41Sopenharmony_ci return; 42451cb0ef41Sopenharmony_ci } 42461cb0ef41Sopenharmony_ci 42471cb0ef41Sopenharmony_ci MachineRepresentation rep = current->representation(); 42481cb0ef41Sopenharmony_ci 42491cb0ef41Sopenharmony_ci // use_pos keeps track of positions a register/alias is used at. 42501cb0ef41Sopenharmony_ci // block_pos keeps track of positions where a register/alias is blocked 42511cb0ef41Sopenharmony_ci // from. 42521cb0ef41Sopenharmony_ci base::EmbeddedVector<LifetimePosition, RegisterConfiguration::kMaxRegisters> 42531cb0ef41Sopenharmony_ci use_pos(LifetimePosition::MaxPosition()); 42541cb0ef41Sopenharmony_ci base::EmbeddedVector<LifetimePosition, RegisterConfiguration::kMaxRegisters> 42551cb0ef41Sopenharmony_ci block_pos(LifetimePosition::MaxPosition()); 42561cb0ef41Sopenharmony_ci 42571cb0ef41Sopenharmony_ci for (LiveRange* range : active_live_ranges()) { 42581cb0ef41Sopenharmony_ci int cur_reg = range->assigned_register(); 42591cb0ef41Sopenharmony_ci bool is_fixed_or_cant_spill = 42601cb0ef41Sopenharmony_ci range->TopLevel()->IsFixed() || !range->CanBeSpilled(current->Start()); 42611cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) { 42621cb0ef41Sopenharmony_ci if (is_fixed_or_cant_spill) { 42631cb0ef41Sopenharmony_ci block_pos[cur_reg] = use_pos[cur_reg] = 42641cb0ef41Sopenharmony_ci LifetimePosition::GapFromInstructionIndex(0); 42651cb0ef41Sopenharmony_ci } else { 42661cb0ef41Sopenharmony_ci DCHECK_NE(LifetimePosition::GapFromInstructionIndex(0), 42671cb0ef41Sopenharmony_ci block_pos[cur_reg]); 42681cb0ef41Sopenharmony_ci use_pos[cur_reg] = 42691cb0ef41Sopenharmony_ci range->NextLifetimePositionRegisterIsBeneficial(current->Start()); 42701cb0ef41Sopenharmony_ci } 42711cb0ef41Sopenharmony_ci } else { 42721cb0ef41Sopenharmony_ci int alias_base_index = -1; 42731cb0ef41Sopenharmony_ci int aliases = data()->config()->GetAliases( 42741cb0ef41Sopenharmony_ci range->representation(), cur_reg, rep, &alias_base_index); 42751cb0ef41Sopenharmony_ci DCHECK(aliases > 0 || (aliases == 0 && alias_base_index == -1)); 42761cb0ef41Sopenharmony_ci while (aliases--) { 42771cb0ef41Sopenharmony_ci int aliased_reg = alias_base_index + aliases; 42781cb0ef41Sopenharmony_ci if (is_fixed_or_cant_spill) { 42791cb0ef41Sopenharmony_ci block_pos[aliased_reg] = use_pos[aliased_reg] = 42801cb0ef41Sopenharmony_ci LifetimePosition::GapFromInstructionIndex(0); 42811cb0ef41Sopenharmony_ci } else { 42821cb0ef41Sopenharmony_ci use_pos[aliased_reg] = 42831cb0ef41Sopenharmony_ci std::min(block_pos[aliased_reg], 42841cb0ef41Sopenharmony_ci range->NextLifetimePositionRegisterIsBeneficial( 42851cb0ef41Sopenharmony_ci current->Start())); 42861cb0ef41Sopenharmony_ci } 42871cb0ef41Sopenharmony_ci } 42881cb0ef41Sopenharmony_ci } 42891cb0ef41Sopenharmony_ci } 42901cb0ef41Sopenharmony_ci 42911cb0ef41Sopenharmony_ci for (int cur_reg = 0; cur_reg < num_registers(); ++cur_reg) { 42921cb0ef41Sopenharmony_ci for (LiveRange* range : inactive_live_ranges(cur_reg)) { 42931cb0ef41Sopenharmony_ci DCHECK(range->End() > current->Start()); 42941cb0ef41Sopenharmony_ci DCHECK_EQ(range->assigned_register(), cur_reg); 42951cb0ef41Sopenharmony_ci bool is_fixed = range->TopLevel()->IsFixed(); 42961cb0ef41Sopenharmony_ci 42971cb0ef41Sopenharmony_ci // Don't perform costly intersections if they are guaranteed to not update 42981cb0ef41Sopenharmony_ci // block_pos or use_pos. 42991cb0ef41Sopenharmony_ci // TODO(mtrofin): extend to aliased ranges, too. 43001cb0ef41Sopenharmony_ci if ((kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing())) { 43011cb0ef41Sopenharmony_ci DCHECK_LE(use_pos[cur_reg], block_pos[cur_reg]); 43021cb0ef41Sopenharmony_ci if (block_pos[cur_reg] <= range->NextStart()) break; 43031cb0ef41Sopenharmony_ci if (!is_fixed && use_pos[cur_reg] <= range->NextStart()) continue; 43041cb0ef41Sopenharmony_ci } 43051cb0ef41Sopenharmony_ci 43061cb0ef41Sopenharmony_ci LifetimePosition next_intersection = range->FirstIntersection(current); 43071cb0ef41Sopenharmony_ci if (!next_intersection.IsValid()) continue; 43081cb0ef41Sopenharmony_ci 43091cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) { 43101cb0ef41Sopenharmony_ci if (is_fixed) { 43111cb0ef41Sopenharmony_ci block_pos[cur_reg] = std::min(block_pos[cur_reg], next_intersection); 43121cb0ef41Sopenharmony_ci use_pos[cur_reg] = std::min(block_pos[cur_reg], use_pos[cur_reg]); 43131cb0ef41Sopenharmony_ci } else { 43141cb0ef41Sopenharmony_ci use_pos[cur_reg] = std::min(use_pos[cur_reg], next_intersection); 43151cb0ef41Sopenharmony_ci } 43161cb0ef41Sopenharmony_ci } else { 43171cb0ef41Sopenharmony_ci int alias_base_index = -1; 43181cb0ef41Sopenharmony_ci int aliases = data()->config()->GetAliases( 43191cb0ef41Sopenharmony_ci range->representation(), cur_reg, rep, &alias_base_index); 43201cb0ef41Sopenharmony_ci DCHECK(aliases > 0 || (aliases == 0 && alias_base_index == -1)); 43211cb0ef41Sopenharmony_ci while (aliases--) { 43221cb0ef41Sopenharmony_ci int aliased_reg = alias_base_index + aliases; 43231cb0ef41Sopenharmony_ci if (is_fixed) { 43241cb0ef41Sopenharmony_ci block_pos[aliased_reg] = 43251cb0ef41Sopenharmony_ci std::min(block_pos[aliased_reg], next_intersection); 43261cb0ef41Sopenharmony_ci use_pos[aliased_reg] = 43271cb0ef41Sopenharmony_ci std::min(block_pos[aliased_reg], use_pos[aliased_reg]); 43281cb0ef41Sopenharmony_ci } else { 43291cb0ef41Sopenharmony_ci use_pos[aliased_reg] = 43301cb0ef41Sopenharmony_ci std::min(use_pos[aliased_reg], next_intersection); 43311cb0ef41Sopenharmony_ci } 43321cb0ef41Sopenharmony_ci } 43331cb0ef41Sopenharmony_ci } 43341cb0ef41Sopenharmony_ci } 43351cb0ef41Sopenharmony_ci } 43361cb0ef41Sopenharmony_ci 43371cb0ef41Sopenharmony_ci // Compute register hint if it exists. 43381cb0ef41Sopenharmony_ci int hint_reg = kUnassignedRegister; 43391cb0ef41Sopenharmony_ci current->RegisterFromControlFlow(&hint_reg) || 43401cb0ef41Sopenharmony_ci register_use->HintRegister(&hint_reg) || 43411cb0ef41Sopenharmony_ci current->RegisterFromBundle(&hint_reg); 43421cb0ef41Sopenharmony_ci int reg = PickRegisterThatIsAvailableLongest(current, hint_reg, use_pos); 43431cb0ef41Sopenharmony_ci 43441cb0ef41Sopenharmony_ci if (use_pos[reg] < register_use->pos()) { 43451cb0ef41Sopenharmony_ci // If there is a gap position before the next register use, we can 43461cb0ef41Sopenharmony_ci // spill until there. The gap position will then fit the fill move. 43471cb0ef41Sopenharmony_ci if (LifetimePosition::ExistsGapPositionBetween(current->Start(), 43481cb0ef41Sopenharmony_ci register_use->pos())) { 43491cb0ef41Sopenharmony_ci SpillBetween(current, current->Start(), register_use->pos(), spill_mode); 43501cb0ef41Sopenharmony_ci return; 43511cb0ef41Sopenharmony_ci } 43521cb0ef41Sopenharmony_ci } 43531cb0ef41Sopenharmony_ci 43541cb0ef41Sopenharmony_ci // When in deferred spilling mode avoid stealing registers beyond the current 43551cb0ef41Sopenharmony_ci // deferred region. This is required as we otherwise might spill an inactive 43561cb0ef41Sopenharmony_ci // range with a start outside of deferred code and that would not be reloaded. 43571cb0ef41Sopenharmony_ci LifetimePosition new_end = current->End(); 43581cb0ef41Sopenharmony_ci if (spill_mode == SpillMode::kSpillDeferred) { 43591cb0ef41Sopenharmony_ci InstructionBlock* deferred_block = 43601cb0ef41Sopenharmony_ci code()->GetInstructionBlock(current->Start().ToInstructionIndex()); 43611cb0ef41Sopenharmony_ci new_end = 43621cb0ef41Sopenharmony_ci std::min(new_end, LifetimePosition::GapFromInstructionIndex( 43631cb0ef41Sopenharmony_ci LastDeferredInstructionIndex(deferred_block))); 43641cb0ef41Sopenharmony_ci } 43651cb0ef41Sopenharmony_ci 43661cb0ef41Sopenharmony_ci // We couldn't spill until the next register use. Split before the register 43671cb0ef41Sopenharmony_ci // is blocked, if applicable. 43681cb0ef41Sopenharmony_ci if (block_pos[reg] < new_end) { 43691cb0ef41Sopenharmony_ci // Register becomes blocked before the current range end. Split before that 43701cb0ef41Sopenharmony_ci // position. 43711cb0ef41Sopenharmony_ci new_end = block_pos[reg].Start(); 43721cb0ef41Sopenharmony_ci } 43731cb0ef41Sopenharmony_ci 43741cb0ef41Sopenharmony_ci // If there is no register available at all, we can only spill this range. 43751cb0ef41Sopenharmony_ci // Happens for instance on entry to deferred code where registers might 43761cb0ef41Sopenharmony_ci // become blocked yet we aim to reload ranges. 43771cb0ef41Sopenharmony_ci if (new_end == current->Start()) { 43781cb0ef41Sopenharmony_ci SpillBetween(current, new_end, register_use->pos(), spill_mode); 43791cb0ef41Sopenharmony_ci return; 43801cb0ef41Sopenharmony_ci } 43811cb0ef41Sopenharmony_ci 43821cb0ef41Sopenharmony_ci // Split at the new end if we found one. 43831cb0ef41Sopenharmony_ci if (new_end != current->End()) { 43841cb0ef41Sopenharmony_ci LiveRange* tail = SplitBetween(current, current->Start(), new_end); 43851cb0ef41Sopenharmony_ci AddToUnhandled(tail); 43861cb0ef41Sopenharmony_ci } 43871cb0ef41Sopenharmony_ci 43881cb0ef41Sopenharmony_ci // Register reg is not blocked for the whole range. 43891cb0ef41Sopenharmony_ci DCHECK(block_pos[reg] >= current->End()); 43901cb0ef41Sopenharmony_ci TRACE("Assigning blocked reg %s to live range %d:%d\n", RegisterName(reg), 43911cb0ef41Sopenharmony_ci current->TopLevel()->vreg(), current->relative_id()); 43921cb0ef41Sopenharmony_ci SetLiveRangeAssignedRegister(current, reg); 43931cb0ef41Sopenharmony_ci 43941cb0ef41Sopenharmony_ci // This register was not free. Thus we need to find and spill 43951cb0ef41Sopenharmony_ci // parts of active and inactive live regions that use the same register 43961cb0ef41Sopenharmony_ci // at the same lifetime positions as current. 43971cb0ef41Sopenharmony_ci SplitAndSpillIntersecting(current, spill_mode); 43981cb0ef41Sopenharmony_ci} 43991cb0ef41Sopenharmony_ci 44001cb0ef41Sopenharmony_civoid LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current, 44011cb0ef41Sopenharmony_ci SpillMode spill_mode) { 44021cb0ef41Sopenharmony_ci DCHECK(current->HasRegisterAssigned()); 44031cb0ef41Sopenharmony_ci int reg = current->assigned_register(); 44041cb0ef41Sopenharmony_ci LifetimePosition split_pos = current->Start(); 44051cb0ef41Sopenharmony_ci for (auto it = active_live_ranges().begin(); 44061cb0ef41Sopenharmony_ci it != active_live_ranges().end();) { 44071cb0ef41Sopenharmony_ci LiveRange* range = *it; 44081cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) { 44091cb0ef41Sopenharmony_ci if (range->assigned_register() != reg) { 44101cb0ef41Sopenharmony_ci ++it; 44111cb0ef41Sopenharmony_ci continue; 44121cb0ef41Sopenharmony_ci } 44131cb0ef41Sopenharmony_ci } else { 44141cb0ef41Sopenharmony_ci if (!data()->config()->AreAliases(current->representation(), reg, 44151cb0ef41Sopenharmony_ci range->representation(), 44161cb0ef41Sopenharmony_ci range->assigned_register())) { 44171cb0ef41Sopenharmony_ci ++it; 44181cb0ef41Sopenharmony_ci continue; 44191cb0ef41Sopenharmony_ci } 44201cb0ef41Sopenharmony_ci } 44211cb0ef41Sopenharmony_ci 44221cb0ef41Sopenharmony_ci UsePosition* next_pos = range->NextRegisterPosition(current->Start()); 44231cb0ef41Sopenharmony_ci LiveRange* begin_spill = nullptr; 44241cb0ef41Sopenharmony_ci LifetimePosition spill_pos = 44251cb0ef41Sopenharmony_ci FindOptimalSpillingPos(range, split_pos, spill_mode, &begin_spill); 44261cb0ef41Sopenharmony_ci MaybeSpillPreviousRanges(begin_spill, spill_pos, range); 44271cb0ef41Sopenharmony_ci if (next_pos == nullptr) { 44281cb0ef41Sopenharmony_ci SpillAfter(range, spill_pos, spill_mode); 44291cb0ef41Sopenharmony_ci } else { 44301cb0ef41Sopenharmony_ci // When spilling between spill_pos and next_pos ensure that the range 44311cb0ef41Sopenharmony_ci // remains spilled at least until the start of the current live range. 44321cb0ef41Sopenharmony_ci // This guarantees that we will not introduce new unhandled ranges that 44331cb0ef41Sopenharmony_ci // start before the current range as this violates allocation invariants 44341cb0ef41Sopenharmony_ci // and will lead to an inconsistent state of active and inactive 44351cb0ef41Sopenharmony_ci // live-ranges: ranges are allocated in order of their start positions, 44361cb0ef41Sopenharmony_ci // ranges are retired from active/inactive when the start of the 44371cb0ef41Sopenharmony_ci // current live-range is larger than their end. 44381cb0ef41Sopenharmony_ci DCHECK(LifetimePosition::ExistsGapPositionBetween(current->Start(), 44391cb0ef41Sopenharmony_ci next_pos->pos())); 44401cb0ef41Sopenharmony_ci SpillBetweenUntil(range, spill_pos, current->Start(), next_pos->pos(), 44411cb0ef41Sopenharmony_ci spill_mode); 44421cb0ef41Sopenharmony_ci } 44431cb0ef41Sopenharmony_ci it = ActiveToHandled(it); 44441cb0ef41Sopenharmony_ci } 44451cb0ef41Sopenharmony_ci 44461cb0ef41Sopenharmony_ci for (int cur_reg = 0; cur_reg < num_registers(); ++cur_reg) { 44471cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || !check_fp_aliasing()) { 44481cb0ef41Sopenharmony_ci if (cur_reg != reg) continue; 44491cb0ef41Sopenharmony_ci } 44501cb0ef41Sopenharmony_ci for (auto it = inactive_live_ranges(cur_reg).begin(); 44511cb0ef41Sopenharmony_ci it != inactive_live_ranges(cur_reg).end();) { 44521cb0ef41Sopenharmony_ci LiveRange* range = *it; 44531cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && check_fp_aliasing() && 44541cb0ef41Sopenharmony_ci !data()->config()->AreAliases(current->representation(), reg, 44551cb0ef41Sopenharmony_ci range->representation(), cur_reg)) { 44561cb0ef41Sopenharmony_ci ++it; 44571cb0ef41Sopenharmony_ci continue; 44581cb0ef41Sopenharmony_ci } 44591cb0ef41Sopenharmony_ci DCHECK(range->End() > current->Start()); 44601cb0ef41Sopenharmony_ci if (range->TopLevel()->IsFixed()) { 44611cb0ef41Sopenharmony_ci ++it; 44621cb0ef41Sopenharmony_ci continue; 44631cb0ef41Sopenharmony_ci } 44641cb0ef41Sopenharmony_ci 44651cb0ef41Sopenharmony_ci LifetimePosition next_intersection = range->FirstIntersection(current); 44661cb0ef41Sopenharmony_ci if (next_intersection.IsValid()) { 44671cb0ef41Sopenharmony_ci UsePosition* next_pos = range->NextRegisterPosition(current->Start()); 44681cb0ef41Sopenharmony_ci if (next_pos == nullptr) { 44691cb0ef41Sopenharmony_ci SpillAfter(range, split_pos, spill_mode); 44701cb0ef41Sopenharmony_ci } else { 44711cb0ef41Sopenharmony_ci next_intersection = std::min(next_intersection, next_pos->pos()); 44721cb0ef41Sopenharmony_ci SpillBetween(range, split_pos, next_intersection, spill_mode); 44731cb0ef41Sopenharmony_ci } 44741cb0ef41Sopenharmony_ci it = InactiveToHandled(it); 44751cb0ef41Sopenharmony_ci } else { 44761cb0ef41Sopenharmony_ci ++it; 44771cb0ef41Sopenharmony_ci } 44781cb0ef41Sopenharmony_ci } 44791cb0ef41Sopenharmony_ci } 44801cb0ef41Sopenharmony_ci} 44811cb0ef41Sopenharmony_ci 44821cb0ef41Sopenharmony_cibool LinearScanAllocator::TryReuseSpillForPhi(TopLevelLiveRange* range) { 44831cb0ef41Sopenharmony_ci if (!range->is_phi()) return false; 44841cb0ef41Sopenharmony_ci 44851cb0ef41Sopenharmony_ci DCHECK(!range->HasSpillOperand()); 44861cb0ef41Sopenharmony_ci // Check how many operands belong to the same bundle as the output. 44871cb0ef41Sopenharmony_ci LiveRangeBundle* out_bundle = range->get_bundle(); 44881cb0ef41Sopenharmony_ci TopTierRegisterAllocationData::PhiMapValue* phi_map_value = 44891cb0ef41Sopenharmony_ci data()->GetPhiMapValueFor(range); 44901cb0ef41Sopenharmony_ci const PhiInstruction* phi = phi_map_value->phi(); 44911cb0ef41Sopenharmony_ci const InstructionBlock* block = phi_map_value->block(); 44921cb0ef41Sopenharmony_ci // Count the number of spilled operands. 44931cb0ef41Sopenharmony_ci size_t spilled_count = 0; 44941cb0ef41Sopenharmony_ci for (size_t i = 0; i < phi->operands().size(); i++) { 44951cb0ef41Sopenharmony_ci int op = phi->operands()[i]; 44961cb0ef41Sopenharmony_ci LiveRange* op_range = data()->GetOrCreateLiveRangeFor(op); 44971cb0ef41Sopenharmony_ci if (!op_range->TopLevel()->HasSpillRange()) continue; 44981cb0ef41Sopenharmony_ci const InstructionBlock* pred = 44991cb0ef41Sopenharmony_ci code()->InstructionBlockAt(block->predecessors()[i]); 45001cb0ef41Sopenharmony_ci LifetimePosition pred_end = 45011cb0ef41Sopenharmony_ci LifetimePosition::InstructionFromInstructionIndex( 45021cb0ef41Sopenharmony_ci pred->last_instruction_index()); 45031cb0ef41Sopenharmony_ci while (op_range != nullptr && !op_range->CanCover(pred_end)) { 45041cb0ef41Sopenharmony_ci op_range = op_range->next(); 45051cb0ef41Sopenharmony_ci } 45061cb0ef41Sopenharmony_ci if (op_range != nullptr && op_range->spilled() && 45071cb0ef41Sopenharmony_ci op_range->get_bundle() == out_bundle) { 45081cb0ef41Sopenharmony_ci spilled_count++; 45091cb0ef41Sopenharmony_ci } 45101cb0ef41Sopenharmony_ci } 45111cb0ef41Sopenharmony_ci 45121cb0ef41Sopenharmony_ci // Only continue if more than half of the operands are spilled to the same 45131cb0ef41Sopenharmony_ci // slot (because part of same bundle). 45141cb0ef41Sopenharmony_ci if (spilled_count * 2 <= phi->operands().size()) { 45151cb0ef41Sopenharmony_ci return false; 45161cb0ef41Sopenharmony_ci } 45171cb0ef41Sopenharmony_ci 45181cb0ef41Sopenharmony_ci // If the range does not need register soon, spill it to the merged 45191cb0ef41Sopenharmony_ci // spill range. 45201cb0ef41Sopenharmony_ci LifetimePosition next_pos = range->Start(); 45211cb0ef41Sopenharmony_ci if (next_pos.IsGapPosition()) next_pos = next_pos.NextStart(); 45221cb0ef41Sopenharmony_ci UsePosition* pos = range->NextUsePositionRegisterIsBeneficial(next_pos); 45231cb0ef41Sopenharmony_ci if (pos == nullptr) { 45241cb0ef41Sopenharmony_ci Spill(range, SpillMode::kSpillAtDefinition); 45251cb0ef41Sopenharmony_ci return true; 45261cb0ef41Sopenharmony_ci } else if (pos->pos() > range->Start().NextStart()) { 45271cb0ef41Sopenharmony_ci SpillBetween(range, range->Start(), pos->pos(), 45281cb0ef41Sopenharmony_ci SpillMode::kSpillAtDefinition); 45291cb0ef41Sopenharmony_ci return true; 45301cb0ef41Sopenharmony_ci } 45311cb0ef41Sopenharmony_ci return false; 45321cb0ef41Sopenharmony_ci} 45331cb0ef41Sopenharmony_ci 45341cb0ef41Sopenharmony_civoid LinearScanAllocator::SpillAfter(LiveRange* range, LifetimePosition pos, 45351cb0ef41Sopenharmony_ci SpillMode spill_mode) { 45361cb0ef41Sopenharmony_ci LiveRange* second_part = SplitRangeAt(range, pos); 45371cb0ef41Sopenharmony_ci Spill(second_part, spill_mode); 45381cb0ef41Sopenharmony_ci} 45391cb0ef41Sopenharmony_ci 45401cb0ef41Sopenharmony_civoid LinearScanAllocator::SpillBetween(LiveRange* range, LifetimePosition start, 45411cb0ef41Sopenharmony_ci LifetimePosition end, 45421cb0ef41Sopenharmony_ci SpillMode spill_mode) { 45431cb0ef41Sopenharmony_ci SpillBetweenUntil(range, start, start, end, spill_mode); 45441cb0ef41Sopenharmony_ci} 45451cb0ef41Sopenharmony_ci 45461cb0ef41Sopenharmony_civoid LinearScanAllocator::SpillBetweenUntil(LiveRange* range, 45471cb0ef41Sopenharmony_ci LifetimePosition start, 45481cb0ef41Sopenharmony_ci LifetimePosition until, 45491cb0ef41Sopenharmony_ci LifetimePosition end, 45501cb0ef41Sopenharmony_ci SpillMode spill_mode) { 45511cb0ef41Sopenharmony_ci CHECK(start < end); 45521cb0ef41Sopenharmony_ci LiveRange* second_part = SplitRangeAt(range, start); 45531cb0ef41Sopenharmony_ci 45541cb0ef41Sopenharmony_ci if (second_part->Start() < end) { 45551cb0ef41Sopenharmony_ci // The split result intersects with [start, end[. 45561cb0ef41Sopenharmony_ci // Split it at position between ]start+1, end[, spill the middle part 45571cb0ef41Sopenharmony_ci // and put the rest to unhandled. 45581cb0ef41Sopenharmony_ci 45591cb0ef41Sopenharmony_ci // Make sure that the third part always starts after the start of the 45601cb0ef41Sopenharmony_ci // second part, as that likely is the current position of the register 45611cb0ef41Sopenharmony_ci // allocator and we cannot add ranges to unhandled that start before 45621cb0ef41Sopenharmony_ci // the current position. 45631cb0ef41Sopenharmony_ci LifetimePosition split_start = std::max(second_part->Start().End(), until); 45641cb0ef41Sopenharmony_ci 45651cb0ef41Sopenharmony_ci // If end is an actual use (which it typically is) we have to split 45661cb0ef41Sopenharmony_ci // so that there is a gap before so that we have space for moving the 45671cb0ef41Sopenharmony_ci // value into its position. 45681cb0ef41Sopenharmony_ci // However, if we have no choice, split right where asked. 45691cb0ef41Sopenharmony_ci LifetimePosition third_part_end = 45701cb0ef41Sopenharmony_ci std::max(split_start, end.PrevStart().End()); 45711cb0ef41Sopenharmony_ci // Instead of spliting right after or even before the block boundary, 45721cb0ef41Sopenharmony_ci // split on the boumndary to avoid extra moves. 45731cb0ef41Sopenharmony_ci if (data()->IsBlockBoundary(end.Start())) { 45741cb0ef41Sopenharmony_ci third_part_end = std::max(split_start, end.Start()); 45751cb0ef41Sopenharmony_ci } 45761cb0ef41Sopenharmony_ci 45771cb0ef41Sopenharmony_ci LiveRange* third_part = 45781cb0ef41Sopenharmony_ci SplitBetween(second_part, split_start, third_part_end); 45791cb0ef41Sopenharmony_ci if (GetInstructionBlock(data()->code(), second_part->Start()) 45801cb0ef41Sopenharmony_ci ->IsDeferred()) { 45811cb0ef41Sopenharmony_ci // Try to use the same register as before. 45821cb0ef41Sopenharmony_ci TRACE("Setting control flow hint for %d:%d to %s\n", 45831cb0ef41Sopenharmony_ci third_part->TopLevel()->vreg(), third_part->relative_id(), 45841cb0ef41Sopenharmony_ci RegisterName(range->controlflow_hint())); 45851cb0ef41Sopenharmony_ci third_part->set_controlflow_hint(range->controlflow_hint()); 45861cb0ef41Sopenharmony_ci } 45871cb0ef41Sopenharmony_ci 45881cb0ef41Sopenharmony_ci AddToUnhandled(third_part); 45891cb0ef41Sopenharmony_ci // This can happen, even if we checked for start < end above, as we fiddle 45901cb0ef41Sopenharmony_ci // with the end location. However, we are guaranteed to be after or at 45911cb0ef41Sopenharmony_ci // until, so this is fine. 45921cb0ef41Sopenharmony_ci if (third_part != second_part) { 45931cb0ef41Sopenharmony_ci Spill(second_part, spill_mode); 45941cb0ef41Sopenharmony_ci } 45951cb0ef41Sopenharmony_ci } else { 45961cb0ef41Sopenharmony_ci // The split result does not intersect with [start, end[. 45971cb0ef41Sopenharmony_ci // Nothing to spill. Just put it to unhandled as whole. 45981cb0ef41Sopenharmony_ci AddToUnhandled(second_part); 45991cb0ef41Sopenharmony_ci } 46001cb0ef41Sopenharmony_ci} 46011cb0ef41Sopenharmony_ci 46021cb0ef41Sopenharmony_ciOperandAssigner::OperandAssigner(TopTierRegisterAllocationData* data) 46031cb0ef41Sopenharmony_ci : data_(data) {} 46041cb0ef41Sopenharmony_ci 46051cb0ef41Sopenharmony_civoid OperandAssigner::DecideSpillingMode() { 46061cb0ef41Sopenharmony_ci for (auto range : data()->live_ranges()) { 46071cb0ef41Sopenharmony_ci data()->tick_counter()->TickAndMaybeEnterSafepoint(); 46081cb0ef41Sopenharmony_ci int max_blocks = data()->code()->InstructionBlockCount(); 46091cb0ef41Sopenharmony_ci if (range != nullptr && range->IsSpilledOnlyInDeferredBlocks(data())) { 46101cb0ef41Sopenharmony_ci // If the range is spilled only in deferred blocks and starts in 46111cb0ef41Sopenharmony_ci // a non-deferred block, we transition its representation here so 46121cb0ef41Sopenharmony_ci // that the LiveRangeConnector processes them correctly. If, 46131cb0ef41Sopenharmony_ci // however, they start in a deferred block, we uograde them to 46141cb0ef41Sopenharmony_ci // spill at definition, as that definition is in a deferred block 46151cb0ef41Sopenharmony_ci // anyway. While this is an optimization, the code in LiveRangeConnector 46161cb0ef41Sopenharmony_ci // relies on it! 46171cb0ef41Sopenharmony_ci if (GetInstructionBlock(data()->code(), range->Start())->IsDeferred()) { 46181cb0ef41Sopenharmony_ci TRACE("Live range %d is spilled and alive in deferred code only\n", 46191cb0ef41Sopenharmony_ci range->vreg()); 46201cb0ef41Sopenharmony_ci range->TransitionRangeToSpillAtDefinition(); 46211cb0ef41Sopenharmony_ci } else { 46221cb0ef41Sopenharmony_ci TRACE("Live range %d is spilled deferred code only but alive outside\n", 46231cb0ef41Sopenharmony_ci range->vreg()); 46241cb0ef41Sopenharmony_ci range->TransitionRangeToDeferredSpill(data()->allocation_zone(), 46251cb0ef41Sopenharmony_ci max_blocks); 46261cb0ef41Sopenharmony_ci } 46271cb0ef41Sopenharmony_ci } 46281cb0ef41Sopenharmony_ci } 46291cb0ef41Sopenharmony_ci} 46301cb0ef41Sopenharmony_ci 46311cb0ef41Sopenharmony_civoid OperandAssigner::AssignSpillSlots() { 46321cb0ef41Sopenharmony_ci for (auto range : data()->live_ranges()) { 46331cb0ef41Sopenharmony_ci data()->tick_counter()->TickAndMaybeEnterSafepoint(); 46341cb0ef41Sopenharmony_ci if (range != nullptr && range->get_bundle() != nullptr) { 46351cb0ef41Sopenharmony_ci range->get_bundle()->MergeSpillRangesAndClear(); 46361cb0ef41Sopenharmony_ci } 46371cb0ef41Sopenharmony_ci } 46381cb0ef41Sopenharmony_ci ZoneVector<SpillRange*>& spill_ranges = data()->spill_ranges(); 46391cb0ef41Sopenharmony_ci // Merge disjoint spill ranges 46401cb0ef41Sopenharmony_ci for (size_t i = 0; i < spill_ranges.size(); ++i) { 46411cb0ef41Sopenharmony_ci data()->tick_counter()->TickAndMaybeEnterSafepoint(); 46421cb0ef41Sopenharmony_ci SpillRange* range = spill_ranges[i]; 46431cb0ef41Sopenharmony_ci if (range == nullptr) continue; 46441cb0ef41Sopenharmony_ci if (range->IsEmpty()) continue; 46451cb0ef41Sopenharmony_ci for (size_t j = i + 1; j < spill_ranges.size(); ++j) { 46461cb0ef41Sopenharmony_ci SpillRange* other = spill_ranges[j]; 46471cb0ef41Sopenharmony_ci if (other != nullptr && !other->IsEmpty()) { 46481cb0ef41Sopenharmony_ci range->TryMerge(other); 46491cb0ef41Sopenharmony_ci } 46501cb0ef41Sopenharmony_ci } 46511cb0ef41Sopenharmony_ci } 46521cb0ef41Sopenharmony_ci // Allocate slots for the merged spill ranges. 46531cb0ef41Sopenharmony_ci for (SpillRange* range : spill_ranges) { 46541cb0ef41Sopenharmony_ci data()->tick_counter()->TickAndMaybeEnterSafepoint(); 46551cb0ef41Sopenharmony_ci if (range == nullptr || range->IsEmpty()) continue; 46561cb0ef41Sopenharmony_ci if (!range->HasSlot()) { 46571cb0ef41Sopenharmony_ci // Allocate a new operand referring to the spill slot, aligned to the 46581cb0ef41Sopenharmony_ci // operand size. 46591cb0ef41Sopenharmony_ci int width = range->byte_width(); 46601cb0ef41Sopenharmony_ci int index = data()->frame()->AllocateSpillSlot(width, width); 46611cb0ef41Sopenharmony_ci range->set_assigned_slot(index); 46621cb0ef41Sopenharmony_ci } 46631cb0ef41Sopenharmony_ci } 46641cb0ef41Sopenharmony_ci} 46651cb0ef41Sopenharmony_ci 46661cb0ef41Sopenharmony_civoid OperandAssigner::CommitAssignment() { 46671cb0ef41Sopenharmony_ci const size_t live_ranges_size = data()->live_ranges().size(); 46681cb0ef41Sopenharmony_ci for (TopLevelLiveRange* top_range : data()->live_ranges()) { 46691cb0ef41Sopenharmony_ci data()->tick_counter()->TickAndMaybeEnterSafepoint(); 46701cb0ef41Sopenharmony_ci CHECK_EQ(live_ranges_size, 46711cb0ef41Sopenharmony_ci data()->live_ranges().size()); // TODO(neis): crbug.com/831822 46721cb0ef41Sopenharmony_ci if (top_range == nullptr || top_range->IsEmpty()) continue; 46731cb0ef41Sopenharmony_ci InstructionOperand spill_operand; 46741cb0ef41Sopenharmony_ci if (top_range->HasSpillOperand()) { 46751cb0ef41Sopenharmony_ci auto it = data()->slot_for_const_range().find(top_range); 46761cb0ef41Sopenharmony_ci if (it != data()->slot_for_const_range().end()) { 46771cb0ef41Sopenharmony_ci spill_operand = *it->second; 46781cb0ef41Sopenharmony_ci } else { 46791cb0ef41Sopenharmony_ci spill_operand = *top_range->GetSpillOperand(); 46801cb0ef41Sopenharmony_ci } 46811cb0ef41Sopenharmony_ci } else if (top_range->HasSpillRange()) { 46821cb0ef41Sopenharmony_ci spill_operand = top_range->GetSpillRangeOperand(); 46831cb0ef41Sopenharmony_ci } 46841cb0ef41Sopenharmony_ci if (top_range->is_phi()) { 46851cb0ef41Sopenharmony_ci data()->GetPhiMapValueFor(top_range)->CommitAssignment( 46861cb0ef41Sopenharmony_ci top_range->GetAssignedOperand()); 46871cb0ef41Sopenharmony_ci } 46881cb0ef41Sopenharmony_ci for (LiveRange* range = top_range; range != nullptr; 46891cb0ef41Sopenharmony_ci range = range->next()) { 46901cb0ef41Sopenharmony_ci InstructionOperand assigned = range->GetAssignedOperand(); 46911cb0ef41Sopenharmony_ci DCHECK(!assigned.IsUnallocated()); 46921cb0ef41Sopenharmony_ci range->ConvertUsesToOperand(assigned, spill_operand); 46931cb0ef41Sopenharmony_ci } 46941cb0ef41Sopenharmony_ci 46951cb0ef41Sopenharmony_ci if (!spill_operand.IsInvalid()) { 46961cb0ef41Sopenharmony_ci // If this top level range has a child spilled in a deferred block, we use 46971cb0ef41Sopenharmony_ci // the range and control flow connection mechanism instead of spilling at 46981cb0ef41Sopenharmony_ci // definition. Refer to the ConnectLiveRanges and ResolveControlFlow 46991cb0ef41Sopenharmony_ci // phases. Normally, when we spill at definition, we do not insert a 47001cb0ef41Sopenharmony_ci // connecting move when a successor child range is spilled - because the 47011cb0ef41Sopenharmony_ci // spilled range picks up its value from the slot which was assigned at 47021cb0ef41Sopenharmony_ci // definition. For ranges that are determined to spill only in deferred 47031cb0ef41Sopenharmony_ci // blocks, we let ConnectLiveRanges and ResolveControlFlow find the blocks 47041cb0ef41Sopenharmony_ci // where a spill operand is expected, and then finalize by inserting the 47051cb0ef41Sopenharmony_ci // spills in the deferred blocks dominators. 47061cb0ef41Sopenharmony_ci if (!top_range->IsSpilledOnlyInDeferredBlocks(data()) && 47071cb0ef41Sopenharmony_ci !top_range->HasGeneralSpillRange()) { 47081cb0ef41Sopenharmony_ci // Spill at definition if the range isn't spilled in a way that will be 47091cb0ef41Sopenharmony_ci // handled later. 47101cb0ef41Sopenharmony_ci top_range->FilterSpillMoves(data(), spill_operand); 47111cb0ef41Sopenharmony_ci top_range->CommitSpillMoves(data(), spill_operand); 47121cb0ef41Sopenharmony_ci } 47131cb0ef41Sopenharmony_ci } 47141cb0ef41Sopenharmony_ci } 47151cb0ef41Sopenharmony_ci} 47161cb0ef41Sopenharmony_ci 47171cb0ef41Sopenharmony_ciReferenceMapPopulator::ReferenceMapPopulator( 47181cb0ef41Sopenharmony_ci TopTierRegisterAllocationData* data) 47191cb0ef41Sopenharmony_ci : data_(data) {} 47201cb0ef41Sopenharmony_ci 47211cb0ef41Sopenharmony_cibool ReferenceMapPopulator::SafePointsAreInOrder() const { 47221cb0ef41Sopenharmony_ci int safe_point = 0; 47231cb0ef41Sopenharmony_ci for (ReferenceMap* map : *data()->code()->reference_maps()) { 47241cb0ef41Sopenharmony_ci if (safe_point > map->instruction_position()) return false; 47251cb0ef41Sopenharmony_ci safe_point = map->instruction_position(); 47261cb0ef41Sopenharmony_ci } 47271cb0ef41Sopenharmony_ci return true; 47281cb0ef41Sopenharmony_ci} 47291cb0ef41Sopenharmony_ci 47301cb0ef41Sopenharmony_civoid ReferenceMapPopulator::PopulateReferenceMaps() { 47311cb0ef41Sopenharmony_ci DCHECK(SafePointsAreInOrder()); 47321cb0ef41Sopenharmony_ci // Map all delayed references. 47331cb0ef41Sopenharmony_ci for (TopTierRegisterAllocationData::DelayedReference& delayed_reference : 47341cb0ef41Sopenharmony_ci data()->delayed_references()) { 47351cb0ef41Sopenharmony_ci delayed_reference.map->RecordReference( 47361cb0ef41Sopenharmony_ci AllocatedOperand::cast(*delayed_reference.operand)); 47371cb0ef41Sopenharmony_ci } 47381cb0ef41Sopenharmony_ci // Iterate over all safe point positions and record a pointer 47391cb0ef41Sopenharmony_ci // for all spilled live ranges at this point. 47401cb0ef41Sopenharmony_ci int last_range_start = 0; 47411cb0ef41Sopenharmony_ci const ReferenceMapDeque* reference_maps = data()->code()->reference_maps(); 47421cb0ef41Sopenharmony_ci ReferenceMapDeque::const_iterator first_it = reference_maps->begin(); 47431cb0ef41Sopenharmony_ci const size_t live_ranges_size = data()->live_ranges().size(); 47441cb0ef41Sopenharmony_ci // We break the invariant that live ranges are indexed by their vregs here. 47451cb0ef41Sopenharmony_ci // This is ok because we don't use that invariant here, and this is the last 47461cb0ef41Sopenharmony_ci // phase. 47471cb0ef41Sopenharmony_ci std::sort(data()->live_ranges().begin(), data()->live_ranges().end(), 47481cb0ef41Sopenharmony_ci [](TopLevelLiveRange* a, TopLevelLiveRange* b) { 47491cb0ef41Sopenharmony_ci if (!a || a->IsEmpty()) return false; 47501cb0ef41Sopenharmony_ci if (!b || b->IsEmpty()) return true; 47511cb0ef41Sopenharmony_ci return a->Start() < b->Start(); 47521cb0ef41Sopenharmony_ci }); 47531cb0ef41Sopenharmony_ci for (TopLevelLiveRange* range : data()->live_ranges()) { 47541cb0ef41Sopenharmony_ci CHECK_EQ(live_ranges_size, 47551cb0ef41Sopenharmony_ci data()->live_ranges().size()); // TODO(neis): crbug.com/831822 47561cb0ef41Sopenharmony_ci if (range == nullptr) continue; 47571cb0ef41Sopenharmony_ci // Skip non-reference values. 47581cb0ef41Sopenharmony_ci if (!data()->code()->IsReference(range->vreg())) continue; 47591cb0ef41Sopenharmony_ci // Skip empty live ranges. 47601cb0ef41Sopenharmony_ci if (range->IsEmpty()) continue; 47611cb0ef41Sopenharmony_ci if (range->has_preassigned_slot()) continue; 47621cb0ef41Sopenharmony_ci 47631cb0ef41Sopenharmony_ci // Find the extent of the range and its children. 47641cb0ef41Sopenharmony_ci int start = range->Start().ToInstructionIndex(); 47651cb0ef41Sopenharmony_ci int end = 0; 47661cb0ef41Sopenharmony_ci for (LiveRange* cur = range; cur != nullptr; cur = cur->next()) { 47671cb0ef41Sopenharmony_ci LifetimePosition this_end = cur->End(); 47681cb0ef41Sopenharmony_ci if (this_end.ToInstructionIndex() > end) 47691cb0ef41Sopenharmony_ci end = this_end.ToInstructionIndex(); 47701cb0ef41Sopenharmony_ci DCHECK(cur->Start().ToInstructionIndex() >= start); 47711cb0ef41Sopenharmony_ci } 47721cb0ef41Sopenharmony_ci 47731cb0ef41Sopenharmony_ci // Ranges should be sorted, so that the first reference map in the current 47741cb0ef41Sopenharmony_ci // live range has to be after {first_it}. 47751cb0ef41Sopenharmony_ci DCHECK_LE(last_range_start, start); 47761cb0ef41Sopenharmony_ci last_range_start = start; 47771cb0ef41Sopenharmony_ci USE(last_range_start); 47781cb0ef41Sopenharmony_ci 47791cb0ef41Sopenharmony_ci // Step across all the safe points that are before the start of this range, 47801cb0ef41Sopenharmony_ci // recording how far we step in order to save doing this for the next range. 47811cb0ef41Sopenharmony_ci for (; first_it != reference_maps->end(); ++first_it) { 47821cb0ef41Sopenharmony_ci ReferenceMap* map = *first_it; 47831cb0ef41Sopenharmony_ci if (map->instruction_position() >= start) break; 47841cb0ef41Sopenharmony_ci } 47851cb0ef41Sopenharmony_ci 47861cb0ef41Sopenharmony_ci InstructionOperand spill_operand; 47871cb0ef41Sopenharmony_ci if (((range->HasSpillOperand() && 47881cb0ef41Sopenharmony_ci !range->GetSpillOperand()->IsConstant()) || 47891cb0ef41Sopenharmony_ci range->HasSpillRange())) { 47901cb0ef41Sopenharmony_ci if (range->HasSpillOperand()) { 47911cb0ef41Sopenharmony_ci spill_operand = *range->GetSpillOperand(); 47921cb0ef41Sopenharmony_ci } else { 47931cb0ef41Sopenharmony_ci spill_operand = range->GetSpillRangeOperand(); 47941cb0ef41Sopenharmony_ci } 47951cb0ef41Sopenharmony_ci DCHECK(spill_operand.IsStackSlot()); 47961cb0ef41Sopenharmony_ci DCHECK(CanBeTaggedOrCompressedPointer( 47971cb0ef41Sopenharmony_ci AllocatedOperand::cast(spill_operand).representation())); 47981cb0ef41Sopenharmony_ci } 47991cb0ef41Sopenharmony_ci 48001cb0ef41Sopenharmony_ci LiveRange* cur = range; 48011cb0ef41Sopenharmony_ci // Step through the safe points to see whether they are in the range. 48021cb0ef41Sopenharmony_ci for (auto it = first_it; it != reference_maps->end(); ++it) { 48031cb0ef41Sopenharmony_ci ReferenceMap* map = *it; 48041cb0ef41Sopenharmony_ci int safe_point = map->instruction_position(); 48051cb0ef41Sopenharmony_ci 48061cb0ef41Sopenharmony_ci // The safe points are sorted so we can stop searching here. 48071cb0ef41Sopenharmony_ci if (safe_point - 1 > end) break; 48081cb0ef41Sopenharmony_ci 48091cb0ef41Sopenharmony_ci // Advance to the next active range that covers the current 48101cb0ef41Sopenharmony_ci // safe point position. 48111cb0ef41Sopenharmony_ci LifetimePosition safe_point_pos = 48121cb0ef41Sopenharmony_ci LifetimePosition::InstructionFromInstructionIndex(safe_point); 48131cb0ef41Sopenharmony_ci 48141cb0ef41Sopenharmony_ci // Search for the child range (cur) that covers safe_point_pos. If we 48151cb0ef41Sopenharmony_ci // don't find it before the children pass safe_point_pos, keep cur at 48161cb0ef41Sopenharmony_ci // the last child, because the next safe_point_pos may be covered by cur. 48171cb0ef41Sopenharmony_ci // This may happen if cur has more than one interval, and the current 48181cb0ef41Sopenharmony_ci // safe_point_pos is in between intervals. 48191cb0ef41Sopenharmony_ci // For that reason, cur may be at most the last child. 48201cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(cur); 48211cb0ef41Sopenharmony_ci DCHECK(safe_point_pos >= cur->Start() || range == cur); 48221cb0ef41Sopenharmony_ci bool found = false; 48231cb0ef41Sopenharmony_ci while (!found) { 48241cb0ef41Sopenharmony_ci if (cur->Covers(safe_point_pos)) { 48251cb0ef41Sopenharmony_ci found = true; 48261cb0ef41Sopenharmony_ci } else { 48271cb0ef41Sopenharmony_ci LiveRange* next = cur->next(); 48281cb0ef41Sopenharmony_ci if (next == nullptr || next->Start() > safe_point_pos) { 48291cb0ef41Sopenharmony_ci break; 48301cb0ef41Sopenharmony_ci } 48311cb0ef41Sopenharmony_ci cur = next; 48321cb0ef41Sopenharmony_ci } 48331cb0ef41Sopenharmony_ci } 48341cb0ef41Sopenharmony_ci 48351cb0ef41Sopenharmony_ci if (!found) { 48361cb0ef41Sopenharmony_ci continue; 48371cb0ef41Sopenharmony_ci } 48381cb0ef41Sopenharmony_ci 48391cb0ef41Sopenharmony_ci // Check if the live range is spilled and the safe point is after 48401cb0ef41Sopenharmony_ci // the spill position. 48411cb0ef41Sopenharmony_ci int spill_index = range->IsSpilledOnlyInDeferredBlocks(data()) || 48421cb0ef41Sopenharmony_ci range->LateSpillingSelected() 48431cb0ef41Sopenharmony_ci ? cur->Start().ToInstructionIndex() 48441cb0ef41Sopenharmony_ci : range->spill_start_index(); 48451cb0ef41Sopenharmony_ci 48461cb0ef41Sopenharmony_ci if (!spill_operand.IsInvalid() && safe_point >= spill_index) { 48471cb0ef41Sopenharmony_ci TRACE("Pointer for range %d (spilled at %d) at safe point %d\n", 48481cb0ef41Sopenharmony_ci range->vreg(), spill_index, safe_point); 48491cb0ef41Sopenharmony_ci map->RecordReference(AllocatedOperand::cast(spill_operand)); 48501cb0ef41Sopenharmony_ci } 48511cb0ef41Sopenharmony_ci 48521cb0ef41Sopenharmony_ci if (!cur->spilled()) { 48531cb0ef41Sopenharmony_ci TRACE( 48541cb0ef41Sopenharmony_ci "Pointer in register for range %d:%d (start at %d) " 48551cb0ef41Sopenharmony_ci "at safe point %d\n", 48561cb0ef41Sopenharmony_ci range->vreg(), cur->relative_id(), cur->Start().value(), 48571cb0ef41Sopenharmony_ci safe_point); 48581cb0ef41Sopenharmony_ci InstructionOperand operand = cur->GetAssignedOperand(); 48591cb0ef41Sopenharmony_ci DCHECK(!operand.IsStackSlot()); 48601cb0ef41Sopenharmony_ci DCHECK(CanBeTaggedOrCompressedPointer( 48611cb0ef41Sopenharmony_ci AllocatedOperand::cast(operand).representation())); 48621cb0ef41Sopenharmony_ci map->RecordReference(AllocatedOperand::cast(operand)); 48631cb0ef41Sopenharmony_ci } 48641cb0ef41Sopenharmony_ci } 48651cb0ef41Sopenharmony_ci } 48661cb0ef41Sopenharmony_ci} 48671cb0ef41Sopenharmony_ci 48681cb0ef41Sopenharmony_ciLiveRangeConnector::LiveRangeConnector(TopTierRegisterAllocationData* data) 48691cb0ef41Sopenharmony_ci : data_(data) {} 48701cb0ef41Sopenharmony_ci 48711cb0ef41Sopenharmony_cibool LiveRangeConnector::CanEagerlyResolveControlFlow( 48721cb0ef41Sopenharmony_ci const InstructionBlock* block) const { 48731cb0ef41Sopenharmony_ci if (block->PredecessorCount() != 1) return false; 48741cb0ef41Sopenharmony_ci return block->predecessors()[0].IsNext(block->rpo_number()); 48751cb0ef41Sopenharmony_ci} 48761cb0ef41Sopenharmony_ci 48771cb0ef41Sopenharmony_civoid LiveRangeConnector::ResolveControlFlow(Zone* local_zone) { 48781cb0ef41Sopenharmony_ci // Lazily linearize live ranges in memory for fast lookup. 48791cb0ef41Sopenharmony_ci LiveRangeFinder finder(data(), local_zone); 48801cb0ef41Sopenharmony_ci ZoneVector<BitVector*>& live_in_sets = data()->live_in_sets(); 48811cb0ef41Sopenharmony_ci for (const InstructionBlock* block : code()->instruction_blocks()) { 48821cb0ef41Sopenharmony_ci if (CanEagerlyResolveControlFlow(block)) continue; 48831cb0ef41Sopenharmony_ci BitVector* live = live_in_sets[block->rpo_number().ToInt()]; 48841cb0ef41Sopenharmony_ci auto it = live->begin(); 48851cb0ef41Sopenharmony_ci auto end = live->end(); 48861cb0ef41Sopenharmony_ci while (it != end) { 48871cb0ef41Sopenharmony_ci data()->tick_counter()->TickAndMaybeEnterSafepoint(); 48881cb0ef41Sopenharmony_ci int vreg = *it; 48891cb0ef41Sopenharmony_ci LiveRangeBoundArray* array = finder.ArrayFor(vreg); 48901cb0ef41Sopenharmony_ci for (const RpoNumber& pred : block->predecessors()) { 48911cb0ef41Sopenharmony_ci FindResult result; 48921cb0ef41Sopenharmony_ci const InstructionBlock* pred_block = code()->InstructionBlockAt(pred); 48931cb0ef41Sopenharmony_ci if (!array->FindConnectableSubranges(block, pred_block, &result)) { 48941cb0ef41Sopenharmony_ci continue; 48951cb0ef41Sopenharmony_ci } 48961cb0ef41Sopenharmony_ci InstructionOperand pred_op = result.pred_cover_->GetAssignedOperand(); 48971cb0ef41Sopenharmony_ci InstructionOperand cur_op = result.cur_cover_->GetAssignedOperand(); 48981cb0ef41Sopenharmony_ci if (pred_op.Equals(cur_op)) continue; 48991cb0ef41Sopenharmony_ci if (!pred_op.IsAnyRegister() && cur_op.IsAnyRegister()) { 49001cb0ef41Sopenharmony_ci // We're doing a reload. 49011cb0ef41Sopenharmony_ci // We don't need to, if: 49021cb0ef41Sopenharmony_ci // 1) there's no register use in this block, and 49031cb0ef41Sopenharmony_ci // 2) the range ends before the block does, and 49041cb0ef41Sopenharmony_ci // 3) we don't have a successor, or the successor is spilled. 49051cb0ef41Sopenharmony_ci LifetimePosition block_start = 49061cb0ef41Sopenharmony_ci LifetimePosition::GapFromInstructionIndex(block->code_start()); 49071cb0ef41Sopenharmony_ci LifetimePosition block_end = 49081cb0ef41Sopenharmony_ci LifetimePosition::GapFromInstructionIndex(block->code_end()); 49091cb0ef41Sopenharmony_ci const LiveRange* current = result.cur_cover_; 49101cb0ef41Sopenharmony_ci // Note that this is not the successor if we have control flow! 49111cb0ef41Sopenharmony_ci // However, in the following condition, we only refer to it if it 49121cb0ef41Sopenharmony_ci // begins in the current block, in which case we can safely declare it 49131cb0ef41Sopenharmony_ci // to be the successor. 49141cb0ef41Sopenharmony_ci const LiveRange* successor = current->next(); 49151cb0ef41Sopenharmony_ci if (current->End() < block_end && 49161cb0ef41Sopenharmony_ci (successor == nullptr || successor->spilled())) { 49171cb0ef41Sopenharmony_ci // verify point 1: no register use. We can go to the end of the 49181cb0ef41Sopenharmony_ci // range, since it's all within the block. 49191cb0ef41Sopenharmony_ci 49201cb0ef41Sopenharmony_ci bool uses_reg = false; 49211cb0ef41Sopenharmony_ci for (const UsePosition* use = current->NextUsePosition(block_start); 49221cb0ef41Sopenharmony_ci use != nullptr; use = use->next()) { 49231cb0ef41Sopenharmony_ci if (use->operand()->IsAnyRegister()) { 49241cb0ef41Sopenharmony_ci uses_reg = true; 49251cb0ef41Sopenharmony_ci break; 49261cb0ef41Sopenharmony_ci } 49271cb0ef41Sopenharmony_ci } 49281cb0ef41Sopenharmony_ci if (!uses_reg) continue; 49291cb0ef41Sopenharmony_ci } 49301cb0ef41Sopenharmony_ci if (current->TopLevel()->IsSpilledOnlyInDeferredBlocks(data()) && 49311cb0ef41Sopenharmony_ci pred_block->IsDeferred()) { 49321cb0ef41Sopenharmony_ci // The spill location should be defined in pred_block, so add 49331cb0ef41Sopenharmony_ci // pred_block to the list of blocks requiring a spill operand. 49341cb0ef41Sopenharmony_ci TRACE("Adding B%d to list of spill blocks for %d\n", 49351cb0ef41Sopenharmony_ci pred_block->rpo_number().ToInt(), 49361cb0ef41Sopenharmony_ci current->TopLevel()->vreg()); 49371cb0ef41Sopenharmony_ci current->TopLevel() 49381cb0ef41Sopenharmony_ci ->GetListOfBlocksRequiringSpillOperands(data()) 49391cb0ef41Sopenharmony_ci ->Add(pred_block->rpo_number().ToInt()); 49401cb0ef41Sopenharmony_ci } 49411cb0ef41Sopenharmony_ci } 49421cb0ef41Sopenharmony_ci int move_loc = ResolveControlFlow(block, cur_op, pred_block, pred_op); 49431cb0ef41Sopenharmony_ci USE(move_loc); 49441cb0ef41Sopenharmony_ci DCHECK_IMPLIES( 49451cb0ef41Sopenharmony_ci result.cur_cover_->TopLevel()->IsSpilledOnlyInDeferredBlocks( 49461cb0ef41Sopenharmony_ci data()) && 49471cb0ef41Sopenharmony_ci !(pred_op.IsAnyRegister() && cur_op.IsAnyRegister()) && 49481cb0ef41Sopenharmony_ci move_loc != -1, 49491cb0ef41Sopenharmony_ci code()->GetInstructionBlock(move_loc)->IsDeferred()); 49501cb0ef41Sopenharmony_ci } 49511cb0ef41Sopenharmony_ci ++it; 49521cb0ef41Sopenharmony_ci } 49531cb0ef41Sopenharmony_ci } 49541cb0ef41Sopenharmony_ci 49551cb0ef41Sopenharmony_ci // At this stage, we collected blocks needing a spill operand due to reloads 49561cb0ef41Sopenharmony_ci // from ConnectRanges and from ResolveControlFlow. Time to commit the spills 49571cb0ef41Sopenharmony_ci // for deferred blocks. This is a convenient time to commit spills for general 49581cb0ef41Sopenharmony_ci // spill ranges also, because they need to use the LiveRangeFinder. 49591cb0ef41Sopenharmony_ci const size_t live_ranges_size = data()->live_ranges().size(); 49601cb0ef41Sopenharmony_ci SpillPlacer spill_placer(&finder, data(), local_zone); 49611cb0ef41Sopenharmony_ci for (TopLevelLiveRange* top : data()->live_ranges()) { 49621cb0ef41Sopenharmony_ci CHECK_EQ(live_ranges_size, 49631cb0ef41Sopenharmony_ci data()->live_ranges().size()); // TODO(neis): crbug.com/831822 49641cb0ef41Sopenharmony_ci if (top == nullptr || top->IsEmpty()) continue; 49651cb0ef41Sopenharmony_ci if (top->IsSpilledOnlyInDeferredBlocks(data())) { 49661cb0ef41Sopenharmony_ci CommitSpillsInDeferredBlocks(top, finder.ArrayFor(top->vreg()), 49671cb0ef41Sopenharmony_ci local_zone); 49681cb0ef41Sopenharmony_ci } else if (top->HasGeneralSpillRange()) { 49691cb0ef41Sopenharmony_ci spill_placer.Add(top); 49701cb0ef41Sopenharmony_ci } 49711cb0ef41Sopenharmony_ci } 49721cb0ef41Sopenharmony_ci} 49731cb0ef41Sopenharmony_ci 49741cb0ef41Sopenharmony_ciint LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block, 49751cb0ef41Sopenharmony_ci const InstructionOperand& cur_op, 49761cb0ef41Sopenharmony_ci const InstructionBlock* pred, 49771cb0ef41Sopenharmony_ci const InstructionOperand& pred_op) { 49781cb0ef41Sopenharmony_ci DCHECK(!pred_op.Equals(cur_op)); 49791cb0ef41Sopenharmony_ci int gap_index; 49801cb0ef41Sopenharmony_ci Instruction::GapPosition position; 49811cb0ef41Sopenharmony_ci if (block->PredecessorCount() == 1) { 49821cb0ef41Sopenharmony_ci gap_index = block->first_instruction_index(); 49831cb0ef41Sopenharmony_ci position = Instruction::START; 49841cb0ef41Sopenharmony_ci } else { 49851cb0ef41Sopenharmony_ci Instruction* last = code()->InstructionAt(pred->last_instruction_index()); 49861cb0ef41Sopenharmony_ci // The connecting move might invalidate uses of the destination operand in 49871cb0ef41Sopenharmony_ci // the deoptimization call. See crbug.com/v8/12218. Omitting the move is 49881cb0ef41Sopenharmony_ci // safe since the deopt call exits the current code. 49891cb0ef41Sopenharmony_ci if (last->IsDeoptimizeCall()) { 49901cb0ef41Sopenharmony_ci return -1; 49911cb0ef41Sopenharmony_ci } 49921cb0ef41Sopenharmony_ci // In every other case the last instruction should not participate in 49931cb0ef41Sopenharmony_ci // register allocation, or it could interfere with the connecting move. 49941cb0ef41Sopenharmony_ci for (size_t i = 0; i < last->InputCount(); ++i) { 49951cb0ef41Sopenharmony_ci DCHECK(last->InputAt(i)->IsImmediate()); 49961cb0ef41Sopenharmony_ci } 49971cb0ef41Sopenharmony_ci DCHECK_EQ(1, pred->SuccessorCount()); 49981cb0ef41Sopenharmony_ci DCHECK(!code() 49991cb0ef41Sopenharmony_ci ->InstructionAt(pred->last_instruction_index()) 50001cb0ef41Sopenharmony_ci ->HasReferenceMap()); 50011cb0ef41Sopenharmony_ci gap_index = pred->last_instruction_index(); 50021cb0ef41Sopenharmony_ci position = Instruction::END; 50031cb0ef41Sopenharmony_ci } 50041cb0ef41Sopenharmony_ci data()->AddGapMove(gap_index, position, pred_op, cur_op); 50051cb0ef41Sopenharmony_ci return gap_index; 50061cb0ef41Sopenharmony_ci} 50071cb0ef41Sopenharmony_ci 50081cb0ef41Sopenharmony_civoid LiveRangeConnector::ConnectRanges(Zone* local_zone) { 50091cb0ef41Sopenharmony_ci DelayedInsertionMap delayed_insertion_map(local_zone); 50101cb0ef41Sopenharmony_ci const size_t live_ranges_size = data()->live_ranges().size(); 50111cb0ef41Sopenharmony_ci for (TopLevelLiveRange* top_range : data()->live_ranges()) { 50121cb0ef41Sopenharmony_ci CHECK_EQ(live_ranges_size, 50131cb0ef41Sopenharmony_ci data()->live_ranges().size()); // TODO(neis): crbug.com/831822 50141cb0ef41Sopenharmony_ci if (top_range == nullptr) continue; 50151cb0ef41Sopenharmony_ci bool connect_spilled = top_range->IsSpilledOnlyInDeferredBlocks(data()); 50161cb0ef41Sopenharmony_ci LiveRange* first_range = top_range; 50171cb0ef41Sopenharmony_ci for (LiveRange *second_range = first_range->next(); second_range != nullptr; 50181cb0ef41Sopenharmony_ci first_range = second_range, second_range = second_range->next()) { 50191cb0ef41Sopenharmony_ci LifetimePosition pos = second_range->Start(); 50201cb0ef41Sopenharmony_ci // Add gap move if the two live ranges touch and there is no block 50211cb0ef41Sopenharmony_ci // boundary. 50221cb0ef41Sopenharmony_ci if (second_range->spilled()) continue; 50231cb0ef41Sopenharmony_ci if (first_range->End() != pos) continue; 50241cb0ef41Sopenharmony_ci if (data()->IsBlockBoundary(pos) && 50251cb0ef41Sopenharmony_ci !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) { 50261cb0ef41Sopenharmony_ci continue; 50271cb0ef41Sopenharmony_ci } 50281cb0ef41Sopenharmony_ci InstructionOperand prev_operand = first_range->GetAssignedOperand(); 50291cb0ef41Sopenharmony_ci InstructionOperand cur_operand = second_range->GetAssignedOperand(); 50301cb0ef41Sopenharmony_ci if (prev_operand.Equals(cur_operand)) continue; 50311cb0ef41Sopenharmony_ci bool delay_insertion = false; 50321cb0ef41Sopenharmony_ci Instruction::GapPosition gap_pos; 50331cb0ef41Sopenharmony_ci int gap_index = pos.ToInstructionIndex(); 50341cb0ef41Sopenharmony_ci if (connect_spilled && !prev_operand.IsAnyRegister() && 50351cb0ef41Sopenharmony_ci cur_operand.IsAnyRegister()) { 50361cb0ef41Sopenharmony_ci const InstructionBlock* block = code()->GetInstructionBlock(gap_index); 50371cb0ef41Sopenharmony_ci DCHECK(block->IsDeferred()); 50381cb0ef41Sopenharmony_ci // Performing a reload in this block, meaning the spill operand must 50391cb0ef41Sopenharmony_ci // be defined here. 50401cb0ef41Sopenharmony_ci top_range->GetListOfBlocksRequiringSpillOperands(data())->Add( 50411cb0ef41Sopenharmony_ci block->rpo_number().ToInt()); 50421cb0ef41Sopenharmony_ci } 50431cb0ef41Sopenharmony_ci 50441cb0ef41Sopenharmony_ci if (pos.IsGapPosition()) { 50451cb0ef41Sopenharmony_ci gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; 50461cb0ef41Sopenharmony_ci } else { 50471cb0ef41Sopenharmony_ci if (pos.IsStart()) { 50481cb0ef41Sopenharmony_ci delay_insertion = true; 50491cb0ef41Sopenharmony_ci } else { 50501cb0ef41Sopenharmony_ci gap_index++; 50511cb0ef41Sopenharmony_ci } 50521cb0ef41Sopenharmony_ci gap_pos = delay_insertion ? Instruction::END : Instruction::START; 50531cb0ef41Sopenharmony_ci } 50541cb0ef41Sopenharmony_ci // Reloads or spills for spilled in deferred blocks ranges must happen 50551cb0ef41Sopenharmony_ci // only in deferred blocks. 50561cb0ef41Sopenharmony_ci DCHECK_IMPLIES(connect_spilled && !(prev_operand.IsAnyRegister() && 50571cb0ef41Sopenharmony_ci cur_operand.IsAnyRegister()), 50581cb0ef41Sopenharmony_ci code()->GetInstructionBlock(gap_index)->IsDeferred()); 50591cb0ef41Sopenharmony_ci 50601cb0ef41Sopenharmony_ci ParallelMove* move = 50611cb0ef41Sopenharmony_ci code()->InstructionAt(gap_index)->GetOrCreateParallelMove( 50621cb0ef41Sopenharmony_ci gap_pos, code_zone()); 50631cb0ef41Sopenharmony_ci if (!delay_insertion) { 50641cb0ef41Sopenharmony_ci move->AddMove(prev_operand, cur_operand); 50651cb0ef41Sopenharmony_ci } else { 50661cb0ef41Sopenharmony_ci delayed_insertion_map.insert( 50671cb0ef41Sopenharmony_ci std::make_pair(std::make_pair(move, prev_operand), cur_operand)); 50681cb0ef41Sopenharmony_ci } 50691cb0ef41Sopenharmony_ci } 50701cb0ef41Sopenharmony_ci } 50711cb0ef41Sopenharmony_ci if (delayed_insertion_map.empty()) return; 50721cb0ef41Sopenharmony_ci // Insert all the moves which should occur after the stored move. 50731cb0ef41Sopenharmony_ci ZoneVector<MoveOperands*> to_insert(local_zone); 50741cb0ef41Sopenharmony_ci ZoneVector<MoveOperands*> to_eliminate(local_zone); 50751cb0ef41Sopenharmony_ci to_insert.reserve(4); 50761cb0ef41Sopenharmony_ci to_eliminate.reserve(4); 50771cb0ef41Sopenharmony_ci ParallelMove* moves = delayed_insertion_map.begin()->first.first; 50781cb0ef41Sopenharmony_ci for (auto it = delayed_insertion_map.begin();; ++it) { 50791cb0ef41Sopenharmony_ci bool done = it == delayed_insertion_map.end(); 50801cb0ef41Sopenharmony_ci if (done || it->first.first != moves) { 50811cb0ef41Sopenharmony_ci // Commit the MoveOperands for current ParallelMove. 50821cb0ef41Sopenharmony_ci for (MoveOperands* move : to_eliminate) { 50831cb0ef41Sopenharmony_ci move->Eliminate(); 50841cb0ef41Sopenharmony_ci } 50851cb0ef41Sopenharmony_ci for (MoveOperands* move : to_insert) { 50861cb0ef41Sopenharmony_ci moves->push_back(move); 50871cb0ef41Sopenharmony_ci } 50881cb0ef41Sopenharmony_ci if (done) break; 50891cb0ef41Sopenharmony_ci // Reset state. 50901cb0ef41Sopenharmony_ci to_eliminate.clear(); 50911cb0ef41Sopenharmony_ci to_insert.clear(); 50921cb0ef41Sopenharmony_ci moves = it->first.first; 50931cb0ef41Sopenharmony_ci } 50941cb0ef41Sopenharmony_ci // Gather all MoveOperands for a single ParallelMove. 50951cb0ef41Sopenharmony_ci MoveOperands* move = 50961cb0ef41Sopenharmony_ci code_zone()->New<MoveOperands>(it->first.second, it->second); 50971cb0ef41Sopenharmony_ci moves->PrepareInsertAfter(move, &to_eliminate); 50981cb0ef41Sopenharmony_ci to_insert.push_back(move); 50991cb0ef41Sopenharmony_ci } 51001cb0ef41Sopenharmony_ci} 51011cb0ef41Sopenharmony_ci 51021cb0ef41Sopenharmony_civoid LiveRangeConnector::CommitSpillsInDeferredBlocks( 51031cb0ef41Sopenharmony_ci TopLevelLiveRange* range, LiveRangeBoundArray* array, Zone* temp_zone) { 51041cb0ef41Sopenharmony_ci DCHECK(range->IsSpilledOnlyInDeferredBlocks(data())); 51051cb0ef41Sopenharmony_ci DCHECK(!range->spilled()); 51061cb0ef41Sopenharmony_ci 51071cb0ef41Sopenharmony_ci InstructionSequence* code = data()->code(); 51081cb0ef41Sopenharmony_ci InstructionOperand spill_operand = range->GetSpillRangeOperand(); 51091cb0ef41Sopenharmony_ci 51101cb0ef41Sopenharmony_ci TRACE("Live Range %d will be spilled only in deferred blocks.\n", 51111cb0ef41Sopenharmony_ci range->vreg()); 51121cb0ef41Sopenharmony_ci // If we have ranges that aren't spilled but require the operand on the stack, 51131cb0ef41Sopenharmony_ci // make sure we insert the spill. 51141cb0ef41Sopenharmony_ci for (const LiveRange* child = range; child != nullptr; 51151cb0ef41Sopenharmony_ci child = child->next()) { 51161cb0ef41Sopenharmony_ci for (const UsePosition* pos = child->first_pos(); pos != nullptr; 51171cb0ef41Sopenharmony_ci pos = pos->next()) { 51181cb0ef41Sopenharmony_ci if (pos->type() != UsePositionType::kRequiresSlot && !child->spilled()) 51191cb0ef41Sopenharmony_ci continue; 51201cb0ef41Sopenharmony_ci range->AddBlockRequiringSpillOperand( 51211cb0ef41Sopenharmony_ci code->GetInstructionBlock(pos->pos().ToInstructionIndex()) 51221cb0ef41Sopenharmony_ci ->rpo_number(), 51231cb0ef41Sopenharmony_ci data()); 51241cb0ef41Sopenharmony_ci } 51251cb0ef41Sopenharmony_ci } 51261cb0ef41Sopenharmony_ci 51271cb0ef41Sopenharmony_ci ZoneQueue<int> worklist(temp_zone); 51281cb0ef41Sopenharmony_ci 51291cb0ef41Sopenharmony_ci for (int block_id : *range->GetListOfBlocksRequiringSpillOperands(data())) { 51301cb0ef41Sopenharmony_ci worklist.push(block_id); 51311cb0ef41Sopenharmony_ci } 51321cb0ef41Sopenharmony_ci 51331cb0ef41Sopenharmony_ci ZoneSet<std::pair<RpoNumber, int>> done_moves(temp_zone); 51341cb0ef41Sopenharmony_ci // Seek the deferred blocks that dominate locations requiring spill operands, 51351cb0ef41Sopenharmony_ci // and spill there. We only need to spill at the start of such blocks. 51361cb0ef41Sopenharmony_ci BitVector done_blocks( 51371cb0ef41Sopenharmony_ci range->GetListOfBlocksRequiringSpillOperands(data())->length(), 51381cb0ef41Sopenharmony_ci temp_zone); 51391cb0ef41Sopenharmony_ci while (!worklist.empty()) { 51401cb0ef41Sopenharmony_ci int block_id = worklist.front(); 51411cb0ef41Sopenharmony_ci worklist.pop(); 51421cb0ef41Sopenharmony_ci if (done_blocks.Contains(block_id)) continue; 51431cb0ef41Sopenharmony_ci done_blocks.Add(block_id); 51441cb0ef41Sopenharmony_ci InstructionBlock* spill_block = 51451cb0ef41Sopenharmony_ci code->InstructionBlockAt(RpoNumber::FromInt(block_id)); 51461cb0ef41Sopenharmony_ci 51471cb0ef41Sopenharmony_ci for (const RpoNumber& pred : spill_block->predecessors()) { 51481cb0ef41Sopenharmony_ci const InstructionBlock* pred_block = code->InstructionBlockAt(pred); 51491cb0ef41Sopenharmony_ci 51501cb0ef41Sopenharmony_ci if (pred_block->IsDeferred()) { 51511cb0ef41Sopenharmony_ci worklist.push(pred_block->rpo_number().ToInt()); 51521cb0ef41Sopenharmony_ci } else { 51531cb0ef41Sopenharmony_ci LifetimePosition pred_end = 51541cb0ef41Sopenharmony_ci LifetimePosition::InstructionFromInstructionIndex( 51551cb0ef41Sopenharmony_ci pred_block->last_instruction_index()); 51561cb0ef41Sopenharmony_ci 51571cb0ef41Sopenharmony_ci LiveRangeBound* bound = array->Find(pred_end); 51581cb0ef41Sopenharmony_ci 51591cb0ef41Sopenharmony_ci InstructionOperand pred_op = bound->range_->GetAssignedOperand(); 51601cb0ef41Sopenharmony_ci 51611cb0ef41Sopenharmony_ci RpoNumber spill_block_number = spill_block->rpo_number(); 51621cb0ef41Sopenharmony_ci if (done_moves.find(std::make_pair( 51631cb0ef41Sopenharmony_ci spill_block_number, range->vreg())) == done_moves.end()) { 51641cb0ef41Sopenharmony_ci TRACE("Spilling deferred spill for range %d at B%d\n", range->vreg(), 51651cb0ef41Sopenharmony_ci spill_block_number.ToInt()); 51661cb0ef41Sopenharmony_ci data()->AddGapMove(spill_block->first_instruction_index(), 51671cb0ef41Sopenharmony_ci Instruction::GapPosition::START, pred_op, 51681cb0ef41Sopenharmony_ci spill_operand); 51691cb0ef41Sopenharmony_ci done_moves.insert(std::make_pair(spill_block_number, range->vreg())); 51701cb0ef41Sopenharmony_ci spill_block->mark_needs_frame(); 51711cb0ef41Sopenharmony_ci } 51721cb0ef41Sopenharmony_ci } 51731cb0ef41Sopenharmony_ci } 51741cb0ef41Sopenharmony_ci } 51751cb0ef41Sopenharmony_ci} 51761cb0ef41Sopenharmony_ci 51771cb0ef41Sopenharmony_ci#undef TRACE 51781cb0ef41Sopenharmony_ci#undef TRACE_COND 51791cb0ef41Sopenharmony_ci 51801cb0ef41Sopenharmony_ci} // namespace compiler 51811cb0ef41Sopenharmony_ci} // namespace internal 51821cb0ef41Sopenharmony_ci} // namespace v8 5183