11cb0ef41Sopenharmony_ci// Copyright 2020 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/mid-tier-register-allocator.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <ostream> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include "src/base/bits.h" 101cb0ef41Sopenharmony_ci#include "src/base/logging.h" 111cb0ef41Sopenharmony_ci#include "src/base/macros.h" 121cb0ef41Sopenharmony_ci#include "src/base/optional.h" 131cb0ef41Sopenharmony_ci#include "src/codegen/machine-type.h" 141cb0ef41Sopenharmony_ci#include "src/codegen/register-configuration.h" 151cb0ef41Sopenharmony_ci#include "src/codegen/tick-counter.h" 161cb0ef41Sopenharmony_ci#include "src/common/globals.h" 171cb0ef41Sopenharmony_ci#include "src/compiler/backend/instruction.h" 181cb0ef41Sopenharmony_ci#include "src/compiler/linkage.h" 191cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 201cb0ef41Sopenharmony_ci#include "src/utils/bit-vector.h" 211cb0ef41Sopenharmony_ci#include "src/zone/zone-containers.h" 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_cinamespace v8 { 241cb0ef41Sopenharmony_cinamespace internal { 251cb0ef41Sopenharmony_cinamespace compiler { 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ciclass RegisterState; 281cb0ef41Sopenharmony_ciclass DeferredBlocksRegion; 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci// BlockState stores details associated with a particular basic block. 311cb0ef41Sopenharmony_ciclass BlockState final { 321cb0ef41Sopenharmony_ci public: 331cb0ef41Sopenharmony_ci BlockState(int block_count, Zone* zone) 341cb0ef41Sopenharmony_ci : general_registers_in_state_(nullptr), 351cb0ef41Sopenharmony_ci double_registers_in_state_(nullptr), 361cb0ef41Sopenharmony_ci deferred_blocks_region_(nullptr), 371cb0ef41Sopenharmony_ci dominated_blocks_(block_count, zone), 381cb0ef41Sopenharmony_ci successors_phi_index_(-1), 391cb0ef41Sopenharmony_ci is_deferred_block_boundary_(false) {} 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci // Returns the RegisterState that applies to the input of this block. Can be 421cb0ef41Sopenharmony_ci // |nullptr| if the no registers of |kind| have been allocated up to this 431cb0ef41Sopenharmony_ci // point. 441cb0ef41Sopenharmony_ci RegisterState* register_in_state(RegisterKind kind); 451cb0ef41Sopenharmony_ci void set_register_in_state(RegisterState* register_state, RegisterKind kind); 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci // Returns a bitvector representing all the basic blocks that are dominated 481cb0ef41Sopenharmony_ci // by this basic block. 491cb0ef41Sopenharmony_ci BitVector* dominated_blocks() { return &dominated_blocks_; } 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci // Set / get this block's index for successor's phi operations. Will return 521cb0ef41Sopenharmony_ci // -1 if this block has no successor's with phi operations. 531cb0ef41Sopenharmony_ci int successors_phi_index() const { return successors_phi_index_; } 541cb0ef41Sopenharmony_ci void set_successors_phi_index(int index) { 551cb0ef41Sopenharmony_ci DCHECK_EQ(successors_phi_index_, -1); 561cb0ef41Sopenharmony_ci successors_phi_index_ = index; 571cb0ef41Sopenharmony_ci } 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci // If this block is deferred, this represents region of deferred blocks 601cb0ef41Sopenharmony_ci // that are directly reachable from this block. 611cb0ef41Sopenharmony_ci DeferredBlocksRegion* deferred_blocks_region() const { 621cb0ef41Sopenharmony_ci return deferred_blocks_region_; 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci void set_deferred_blocks_region(DeferredBlocksRegion* region) { 651cb0ef41Sopenharmony_ci DCHECK_NULL(deferred_blocks_region_); 661cb0ef41Sopenharmony_ci deferred_blocks_region_ = region; 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci // Returns true if this block represents either a transition from 701cb0ef41Sopenharmony_ci // non-deferred to deferred or vice versa. 711cb0ef41Sopenharmony_ci bool is_deferred_block_boundary() const { 721cb0ef41Sopenharmony_ci return is_deferred_block_boundary_; 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci void MarkAsDeferredBlockBoundary() { is_deferred_block_boundary_ = true; } 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(BlockState); 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci private: 791cb0ef41Sopenharmony_ci RegisterState* general_registers_in_state_; 801cb0ef41Sopenharmony_ci RegisterState* double_registers_in_state_; 811cb0ef41Sopenharmony_ci RegisterState* simd128_registers_in_state_; 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci DeferredBlocksRegion* deferred_blocks_region_; 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci BitVector dominated_blocks_; 861cb0ef41Sopenharmony_ci int successors_phi_index_; 871cb0ef41Sopenharmony_ci bool is_deferred_block_boundary_; 881cb0ef41Sopenharmony_ci}; 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ciRegisterState* BlockState::register_in_state(RegisterKind kind) { 911cb0ef41Sopenharmony_ci switch (kind) { 921cb0ef41Sopenharmony_ci case RegisterKind::kGeneral: 931cb0ef41Sopenharmony_ci return general_registers_in_state_; 941cb0ef41Sopenharmony_ci case RegisterKind::kDouble: 951cb0ef41Sopenharmony_ci return double_registers_in_state_; 961cb0ef41Sopenharmony_ci case RegisterKind::kSimd128: 971cb0ef41Sopenharmony_ci return simd128_registers_in_state_; 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci} 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_civoid BlockState::set_register_in_state(RegisterState* register_state, 1021cb0ef41Sopenharmony_ci RegisterKind kind) { 1031cb0ef41Sopenharmony_ci switch (kind) { 1041cb0ef41Sopenharmony_ci case RegisterKind::kGeneral: 1051cb0ef41Sopenharmony_ci DCHECK_NULL(general_registers_in_state_); 1061cb0ef41Sopenharmony_ci general_registers_in_state_ = register_state; 1071cb0ef41Sopenharmony_ci break; 1081cb0ef41Sopenharmony_ci case RegisterKind::kDouble: 1091cb0ef41Sopenharmony_ci DCHECK_NULL(double_registers_in_state_); 1101cb0ef41Sopenharmony_ci double_registers_in_state_ = register_state; 1111cb0ef41Sopenharmony_ci break; 1121cb0ef41Sopenharmony_ci case RegisterKind::kSimd128: 1131cb0ef41Sopenharmony_ci DCHECK_NULL(simd128_registers_in_state_); 1141cb0ef41Sopenharmony_ci simd128_registers_in_state_ = register_state; 1151cb0ef41Sopenharmony_ci break; 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci} 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ciMidTierRegisterAllocationData::MidTierRegisterAllocationData( 1201cb0ef41Sopenharmony_ci const RegisterConfiguration* config, Zone* zone, Frame* frame, 1211cb0ef41Sopenharmony_ci InstructionSequence* code, TickCounter* tick_counter, 1221cb0ef41Sopenharmony_ci const char* debug_name) 1231cb0ef41Sopenharmony_ci : RegisterAllocationData(Type::kMidTier), 1241cb0ef41Sopenharmony_ci allocation_zone_(zone), 1251cb0ef41Sopenharmony_ci frame_(frame), 1261cb0ef41Sopenharmony_ci code_(code), 1271cb0ef41Sopenharmony_ci debug_name_(debug_name), 1281cb0ef41Sopenharmony_ci config_(config), 1291cb0ef41Sopenharmony_ci virtual_register_data_(code->VirtualRegisterCount(), allocation_zone()), 1301cb0ef41Sopenharmony_ci block_states_(allocation_zone()), 1311cb0ef41Sopenharmony_ci reference_map_instructions_(allocation_zone()), 1321cb0ef41Sopenharmony_ci spilled_virtual_registers_(code->VirtualRegisterCount(), 1331cb0ef41Sopenharmony_ci allocation_zone()), 1341cb0ef41Sopenharmony_ci tick_counter_(tick_counter) { 1351cb0ef41Sopenharmony_ci int basic_block_count = code->InstructionBlockCount(); 1361cb0ef41Sopenharmony_ci block_states_.reserve(basic_block_count); 1371cb0ef41Sopenharmony_ci for (int i = 0; i < basic_block_count; i++) { 1381cb0ef41Sopenharmony_ci block_states_.emplace_back(basic_block_count, allocation_zone()); 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci} 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ciMoveOperands* MidTierRegisterAllocationData::AddGapMove( 1431cb0ef41Sopenharmony_ci int instr_index, Instruction::GapPosition position, 1441cb0ef41Sopenharmony_ci const InstructionOperand& from, const InstructionOperand& to) { 1451cb0ef41Sopenharmony_ci Instruction* instr = code()->InstructionAt(instr_index); 1461cb0ef41Sopenharmony_ci ParallelMove* moves = instr->GetOrCreateParallelMove(position, code_zone()); 1471cb0ef41Sopenharmony_ci return moves->AddMove(from, to); 1481cb0ef41Sopenharmony_ci} 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ciMoveOperands* MidTierRegisterAllocationData::AddPendingOperandGapMove( 1511cb0ef41Sopenharmony_ci int instr_index, Instruction::GapPosition position) { 1521cb0ef41Sopenharmony_ci return AddGapMove(instr_index, position, PendingOperand(), PendingOperand()); 1531cb0ef41Sopenharmony_ci} 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ciBlockState& MidTierRegisterAllocationData::block_state(RpoNumber rpo_number) { 1561cb0ef41Sopenharmony_ci return block_states_[rpo_number.ToInt()]; 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ciconst InstructionBlock* MidTierRegisterAllocationData::GetBlock( 1601cb0ef41Sopenharmony_ci RpoNumber rpo_number) { 1611cb0ef41Sopenharmony_ci return code()->InstructionBlockAt(rpo_number); 1621cb0ef41Sopenharmony_ci} 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ciconst InstructionBlock* MidTierRegisterAllocationData::GetBlock( 1651cb0ef41Sopenharmony_ci int instr_index) { 1661cb0ef41Sopenharmony_ci return code()->InstructionAt(instr_index)->block(); 1671cb0ef41Sopenharmony_ci} 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ciconst BitVector* MidTierRegisterAllocationData::GetBlocksDominatedBy( 1701cb0ef41Sopenharmony_ci const InstructionBlock* block) { 1711cb0ef41Sopenharmony_ci return block_state(block->rpo_number()).dominated_blocks(); 1721cb0ef41Sopenharmony_ci} 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci// RegisterIndex represents a particular register of a given kind (depending 1751cb0ef41Sopenharmony_ci// on the RegisterKind of the allocator). 1761cb0ef41Sopenharmony_ciclass RegisterIndex final { 1771cb0ef41Sopenharmony_ci public: 1781cb0ef41Sopenharmony_ci RegisterIndex() : index_(kInvalidIndex) {} 1791cb0ef41Sopenharmony_ci explicit RegisterIndex(int index) : index_(index) {} 1801cb0ef41Sopenharmony_ci static RegisterIndex Invalid() { return RegisterIndex(); } 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci bool is_valid() const { return index_ != kInvalidIndex; } 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci int ToInt() const { 1851cb0ef41Sopenharmony_ci DCHECK(is_valid()); 1861cb0ef41Sopenharmony_ci return index_; 1871cb0ef41Sopenharmony_ci } 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci uintptr_t ToBit(MachineRepresentation rep) const { 1901cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || 1911cb0ef41Sopenharmony_ci rep != MachineRepresentation::kSimd128) { 1921cb0ef41Sopenharmony_ci return 1ull << ToInt(); 1931cb0ef41Sopenharmony_ci } else { 1941cb0ef41Sopenharmony_ci DCHECK_EQ(rep, MachineRepresentation::kSimd128); 1951cb0ef41Sopenharmony_ci return 3ull << ToInt(); 1961cb0ef41Sopenharmony_ci } 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci bool operator==(const RegisterIndex& rhs) const { 2001cb0ef41Sopenharmony_ci return index_ == rhs.index_; 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci bool operator!=(const RegisterIndex& rhs) const { 2031cb0ef41Sopenharmony_ci return index_ != rhs.index_; 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci class Iterator { 2071cb0ef41Sopenharmony_ci public: 2081cb0ef41Sopenharmony_ci explicit Iterator(int index) : index_(index) {} 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci bool operator!=(const Iterator& rhs) const { return index_ != rhs.index_; } 2111cb0ef41Sopenharmony_ci void operator++() { index_++; } 2121cb0ef41Sopenharmony_ci RegisterIndex operator*() const { return RegisterIndex(index_); } 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci private: 2151cb0ef41Sopenharmony_ci int index_; 2161cb0ef41Sopenharmony_ci }; 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci private: 2191cb0ef41Sopenharmony_ci static const int kInvalidIndex = -1; 2201cb0ef41Sopenharmony_ci int8_t index_; 2211cb0ef41Sopenharmony_ci}; 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ci// A Range from [start, end] of instructions, inclusive of start and end. 2241cb0ef41Sopenharmony_ciclass Range { 2251cb0ef41Sopenharmony_ci public: 2261cb0ef41Sopenharmony_ci Range() : start_(kMaxInt), end_(0) {} 2271cb0ef41Sopenharmony_ci Range(int start, int end) : start_(start), end_(end) {} 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci void AddInstr(int index) { 2301cb0ef41Sopenharmony_ci start_ = std::min(start_, index); 2311cb0ef41Sopenharmony_ci end_ = std::max(end_, index); 2321cb0ef41Sopenharmony_ci } 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci void AddRange(const Range& other) { 2351cb0ef41Sopenharmony_ci start_ = std::min(start_, other.start_); 2361cb0ef41Sopenharmony_ci end_ = std::max(end_, other.end_); 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci // Returns true if index is greater than start and less than or equal to end. 2401cb0ef41Sopenharmony_ci bool Contains(int index) { return index >= start_ && index <= end_; } 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci int start() const { return start_; } 2431cb0ef41Sopenharmony_ci int end() const { return end_; } 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci private: 2461cb0ef41Sopenharmony_ci int start_; 2471cb0ef41Sopenharmony_ci int end_; 2481cb0ef41Sopenharmony_ci}; 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci// Represents a connected region of deferred basic blocks. 2511cb0ef41Sopenharmony_ciclass DeferredBlocksRegion final { 2521cb0ef41Sopenharmony_ci public: 2531cb0ef41Sopenharmony_ci explicit DeferredBlocksRegion(Zone* zone, int number_of_blocks) 2541cb0ef41Sopenharmony_ci : spilled_vregs_(zone), 2551cb0ef41Sopenharmony_ci blocks_covered_(number_of_blocks, zone), 2561cb0ef41Sopenharmony_ci is_frozen_(false) {} 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci void AddBlock(RpoNumber block, MidTierRegisterAllocationData* data) { 2591cb0ef41Sopenharmony_ci DCHECK(data->GetBlock(block)->IsDeferred()); 2601cb0ef41Sopenharmony_ci blocks_covered_.Add(block.ToInt()); 2611cb0ef41Sopenharmony_ci data->block_state(block).set_deferred_blocks_region(this); 2621cb0ef41Sopenharmony_ci } 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci // Trys to adds |vreg| to the list of variables to potentially defer their 2651cb0ef41Sopenharmony_ci // output to a spill slot until we enter this deferred block region. Returns 2661cb0ef41Sopenharmony_ci // true if successful. 2671cb0ef41Sopenharmony_ci bool TryDeferSpillOutputUntilEntry(int vreg) { 2681cb0ef41Sopenharmony_ci if (spilled_vregs_.count(vreg) != 0) return true; 2691cb0ef41Sopenharmony_ci if (is_frozen_) return false; 2701cb0ef41Sopenharmony_ci spilled_vregs_.insert(vreg); 2711cb0ef41Sopenharmony_ci return true; 2721cb0ef41Sopenharmony_ci } 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci void FreezeDeferredSpills() { is_frozen_ = true; } 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci ZoneSet<int>::const_iterator begin() const { return spilled_vregs_.begin(); } 2771cb0ef41Sopenharmony_ci ZoneSet<int>::const_iterator end() const { return spilled_vregs_.end(); } 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci const BitVector* blocks_covered() const { return &blocks_covered_; } 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci private: 2821cb0ef41Sopenharmony_ci ZoneSet<int> spilled_vregs_; 2831cb0ef41Sopenharmony_ci BitVector blocks_covered_; 2841cb0ef41Sopenharmony_ci bool is_frozen_; 2851cb0ef41Sopenharmony_ci}; 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci// VirtualRegisterData stores data specific to a particular virtual register, 2881cb0ef41Sopenharmony_ci// and tracks spilled operands for that virtual register. 2891cb0ef41Sopenharmony_ciclass VirtualRegisterData final { 2901cb0ef41Sopenharmony_ci public: 2911cb0ef41Sopenharmony_ci VirtualRegisterData() = default; 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci // Define VirtualRegisterData with the type of output that produces this 2941cb0ef41Sopenharmony_ci // virtual register. 2951cb0ef41Sopenharmony_ci void DefineAsUnallocatedOperand(int virtual_register, 2961cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index, 2971cb0ef41Sopenharmony_ci bool is_deferred_block, 2981cb0ef41Sopenharmony_ci bool is_exceptional_call_output); 2991cb0ef41Sopenharmony_ci void DefineAsFixedSpillOperand(AllocatedOperand* operand, 3001cb0ef41Sopenharmony_ci int virtual_register, 3011cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index, 3021cb0ef41Sopenharmony_ci bool is_deferred_block, 3031cb0ef41Sopenharmony_ci bool is_exceptional_call_output); 3041cb0ef41Sopenharmony_ci void DefineAsConstantOperand(ConstantOperand* operand, 3051cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index, 3061cb0ef41Sopenharmony_ci bool is_deferred_block); 3071cb0ef41Sopenharmony_ci void DefineAsPhi(int virtual_register, MachineRepresentation rep, 3081cb0ef41Sopenharmony_ci int instr_index, bool is_deferred_block); 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci // Spill an operand that is assigned to this virtual register. 3111cb0ef41Sopenharmony_ci void SpillOperand(InstructionOperand* operand, int instr_index, 3121cb0ef41Sopenharmony_ci bool has_constant_policy, 3131cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci // Emit gap moves to / from the spill slot. 3161cb0ef41Sopenharmony_ci void EmitGapMoveToInputFromSpillSlot(InstructionOperand to_operand, 3171cb0ef41Sopenharmony_ci int instr_index, 3181cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 3191cb0ef41Sopenharmony_ci void EmitGapMoveFromOutputToSpillSlot(InstructionOperand from_operand, 3201cb0ef41Sopenharmony_ci const InstructionBlock* current_block, 3211cb0ef41Sopenharmony_ci int instr_index, 3221cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 3231cb0ef41Sopenharmony_ci void EmitGapMoveToSpillSlot(InstructionOperand from_operand, int instr_index, 3241cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ci // Adds pending spills for deferred-blocks. 3271cb0ef41Sopenharmony_ci void AddDeferredSpillUse(int instr_index, 3281cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 3291cb0ef41Sopenharmony_ci void AddDeferredSpillOutput(AllocatedOperand allocated_op, int instr_index, 3301cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci // Accessors for spill operand, which may still be pending allocation. 3331cb0ef41Sopenharmony_ci bool HasSpillOperand() const { return spill_operand_ != nullptr; } 3341cb0ef41Sopenharmony_ci InstructionOperand* spill_operand() const { 3351cb0ef41Sopenharmony_ci DCHECK(HasSpillOperand()); 3361cb0ef41Sopenharmony_ci return spill_operand_; 3371cb0ef41Sopenharmony_ci } 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci bool HasPendingSpillOperand() const { 3401cb0ef41Sopenharmony_ci return HasSpillOperand() && spill_operand_->IsPending(); 3411cb0ef41Sopenharmony_ci } 3421cb0ef41Sopenharmony_ci bool HasAllocatedSpillOperand() const { 3431cb0ef41Sopenharmony_ci return HasSpillOperand() && spill_operand_->IsAllocated(); 3441cb0ef41Sopenharmony_ci } 3451cb0ef41Sopenharmony_ci bool HasConstantSpillOperand() const { 3461cb0ef41Sopenharmony_ci return HasSpillOperand() && spill_operand_->IsConstant(); 3471cb0ef41Sopenharmony_ci } 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci // Returns true if the virtual register should be spilled when it is output. 3501cb0ef41Sopenharmony_ci bool NeedsSpillAtOutput() const { return needs_spill_at_output_; } 3511cb0ef41Sopenharmony_ci 3521cb0ef41Sopenharmony_ci void MarkAsNeedsSpillAtOutput() { 3531cb0ef41Sopenharmony_ci if (HasConstantSpillOperand()) return; 3541cb0ef41Sopenharmony_ci needs_spill_at_output_ = true; 3551cb0ef41Sopenharmony_ci if (HasSpillRange()) spill_range()->ClearDeferredBlockSpills(); 3561cb0ef41Sopenharmony_ci } 3571cb0ef41Sopenharmony_ci 3581cb0ef41Sopenharmony_ci // Returns true if the virtual register should be spilled at entry to deferred 3591cb0ef41Sopenharmony_ci // blocks in which it is spilled (to avoid spilling on output on 3601cb0ef41Sopenharmony_ci // non-deferred blocks). 3611cb0ef41Sopenharmony_ci bool NeedsSpillAtDeferredBlocks() const; 3621cb0ef41Sopenharmony_ci void EmitDeferredSpillOutputs(MidTierRegisterAllocationData* data); 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ci bool IsSpilledAt(int instr_index, MidTierRegisterAllocationData* data) { 3651cb0ef41Sopenharmony_ci DCHECK_GE(instr_index, output_instr_index()); 3661cb0ef41Sopenharmony_ci if (NeedsSpillAtOutput() || HasConstantSpillOperand()) return true; 3671cb0ef41Sopenharmony_ci if (HasSpillOperand() && data->GetBlock(instr_index)->IsDeferred()) { 3681cb0ef41Sopenharmony_ci return true; 3691cb0ef41Sopenharmony_ci } 3701cb0ef41Sopenharmony_ci return false; 3711cb0ef41Sopenharmony_ci } 3721cb0ef41Sopenharmony_ci 3731cb0ef41Sopenharmony_ci // Allocates pending spill operands to the |allocated| spill slot. 3741cb0ef41Sopenharmony_ci void AllocatePendingSpillOperand(const AllocatedOperand& allocated); 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci int vreg() const { return vreg_; } 3771cb0ef41Sopenharmony_ci MachineRepresentation rep() const { return rep_; } 3781cb0ef41Sopenharmony_ci int output_instr_index() const { return output_instr_index_; } 3791cb0ef41Sopenharmony_ci bool is_constant() const { return is_constant_; } 3801cb0ef41Sopenharmony_ci bool is_phi() const { return is_phi_; } 3811cb0ef41Sopenharmony_ci bool is_defined_in_deferred_block() const { 3821cb0ef41Sopenharmony_ci return is_defined_in_deferred_block_; 3831cb0ef41Sopenharmony_ci } 3841cb0ef41Sopenharmony_ci bool is_exceptional_call_output() const { 3851cb0ef41Sopenharmony_ci return is_exceptional_call_output_; 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ci struct DeferredSpillSlotOutput { 3891cb0ef41Sopenharmony_ci public: 3901cb0ef41Sopenharmony_ci explicit DeferredSpillSlotOutput(int instr, AllocatedOperand op, 3911cb0ef41Sopenharmony_ci const BitVector* blocks) 3921cb0ef41Sopenharmony_ci : instr_index(instr), operand(op), live_blocks(blocks) {} 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci int instr_index; 3951cb0ef41Sopenharmony_ci AllocatedOperand operand; 3961cb0ef41Sopenharmony_ci const BitVector* live_blocks; 3971cb0ef41Sopenharmony_ci }; 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ci // Represents the range of instructions for which this virtual register needs 4001cb0ef41Sopenharmony_ci // to be spilled on the stack. 4011cb0ef41Sopenharmony_ci class SpillRange : public ZoneObject { 4021cb0ef41Sopenharmony_ci public: 4031cb0ef41Sopenharmony_ci // Defines a spill range for an output operand. 4041cb0ef41Sopenharmony_ci SpillRange(int definition_instr_index, 4051cb0ef41Sopenharmony_ci const InstructionBlock* definition_block, 4061cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) 4071cb0ef41Sopenharmony_ci : live_range_(definition_instr_index, definition_instr_index), 4081cb0ef41Sopenharmony_ci live_blocks_(data->GetBlocksDominatedBy(definition_block)), 4091cb0ef41Sopenharmony_ci deferred_spill_outputs_(nullptr) {} 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ci // Defines a spill range for a Phi variable. 4121cb0ef41Sopenharmony_ci SpillRange(const InstructionBlock* phi_block, 4131cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) 4141cb0ef41Sopenharmony_ci : live_range_(phi_block->first_instruction_index(), 4151cb0ef41Sopenharmony_ci phi_block->first_instruction_index()), 4161cb0ef41Sopenharmony_ci live_blocks_(data->GetBlocksDominatedBy(phi_block)), 4171cb0ef41Sopenharmony_ci deferred_spill_outputs_(nullptr) { 4181cb0ef41Sopenharmony_ci // For phis, add the gap move instructions in the predecssor blocks to 4191cb0ef41Sopenharmony_ci // the live range. 4201cb0ef41Sopenharmony_ci for (RpoNumber pred_rpo : phi_block->predecessors()) { 4211cb0ef41Sopenharmony_ci const InstructionBlock* block = data->GetBlock(pred_rpo); 4221cb0ef41Sopenharmony_ci live_range_.AddInstr(block->last_instruction_index()); 4231cb0ef41Sopenharmony_ci } 4241cb0ef41Sopenharmony_ci } 4251cb0ef41Sopenharmony_ci 4261cb0ef41Sopenharmony_ci SpillRange(const SpillRange&) = delete; 4271cb0ef41Sopenharmony_ci SpillRange& operator=(const SpillRange&) = delete; 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci bool IsLiveAt(int instr_index, InstructionBlock* block) { 4301cb0ef41Sopenharmony_ci if (!live_range_.Contains(instr_index)) return false; 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ci int block_rpo = block->rpo_number().ToInt(); 4331cb0ef41Sopenharmony_ci if (!live_blocks_->Contains(block_rpo)) return false; 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci if (!HasDeferredBlockSpills()) { 4361cb0ef41Sopenharmony_ci return true; 4371cb0ef41Sopenharmony_ci } else { 4381cb0ef41Sopenharmony_ci // If this spill range is only output for deferred block, then the spill 4391cb0ef41Sopenharmony_ci // slot will only be live for the deferred blocks, not all blocks that 4401cb0ef41Sopenharmony_ci // the virtual register is live. 4411cb0ef41Sopenharmony_ci for (auto deferred_spill_output : *deferred_spill_outputs()) { 4421cb0ef41Sopenharmony_ci if (deferred_spill_output.live_blocks->Contains(block_rpo)) { 4431cb0ef41Sopenharmony_ci return true; 4441cb0ef41Sopenharmony_ci } 4451cb0ef41Sopenharmony_ci } 4461cb0ef41Sopenharmony_ci return false; 4471cb0ef41Sopenharmony_ci } 4481cb0ef41Sopenharmony_ci } 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ci void ExtendRangeTo(int instr_index) { live_range_.AddInstr(instr_index); } 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_ci void AddDeferredSpillOutput(AllocatedOperand allocated_op, int instr_index, 4531cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 4541cb0ef41Sopenharmony_ci if (deferred_spill_outputs_ == nullptr) { 4551cb0ef41Sopenharmony_ci Zone* zone = data->allocation_zone(); 4561cb0ef41Sopenharmony_ci deferred_spill_outputs_ = 4571cb0ef41Sopenharmony_ci zone->New<ZoneVector<DeferredSpillSlotOutput>>(zone); 4581cb0ef41Sopenharmony_ci } 4591cb0ef41Sopenharmony_ci const InstructionBlock* block = data->GetBlock(instr_index); 4601cb0ef41Sopenharmony_ci DCHECK_EQ(block->first_instruction_index(), instr_index); 4611cb0ef41Sopenharmony_ci BlockState& block_state = data->block_state(block->rpo_number()); 4621cb0ef41Sopenharmony_ci const BitVector* deferred_blocks = 4631cb0ef41Sopenharmony_ci block_state.deferred_blocks_region()->blocks_covered(); 4641cb0ef41Sopenharmony_ci deferred_spill_outputs_->emplace_back(instr_index, allocated_op, 4651cb0ef41Sopenharmony_ci deferred_blocks); 4661cb0ef41Sopenharmony_ci } 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci void ClearDeferredBlockSpills() { deferred_spill_outputs_ = nullptr; } 4691cb0ef41Sopenharmony_ci bool HasDeferredBlockSpills() const { 4701cb0ef41Sopenharmony_ci return deferred_spill_outputs_ != nullptr; 4711cb0ef41Sopenharmony_ci } 4721cb0ef41Sopenharmony_ci const ZoneVector<DeferredSpillSlotOutput>* deferred_spill_outputs() const { 4731cb0ef41Sopenharmony_ci DCHECK(HasDeferredBlockSpills()); 4741cb0ef41Sopenharmony_ci return deferred_spill_outputs_; 4751cb0ef41Sopenharmony_ci } 4761cb0ef41Sopenharmony_ci 4771cb0ef41Sopenharmony_ci Range& live_range() { return live_range_; } 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci private: 4801cb0ef41Sopenharmony_ci Range live_range_; 4811cb0ef41Sopenharmony_ci const BitVector* live_blocks_; 4821cb0ef41Sopenharmony_ci ZoneVector<DeferredSpillSlotOutput>* deferred_spill_outputs_; 4831cb0ef41Sopenharmony_ci }; 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci bool HasSpillRange() const { return spill_range_ != nullptr; } 4861cb0ef41Sopenharmony_ci SpillRange* spill_range() const { 4871cb0ef41Sopenharmony_ci DCHECK(HasSpillRange()); 4881cb0ef41Sopenharmony_ci return spill_range_; 4891cb0ef41Sopenharmony_ci } 4901cb0ef41Sopenharmony_ci 4911cb0ef41Sopenharmony_ci private: 4921cb0ef41Sopenharmony_ci void Initialize(int virtual_register, MachineRepresentation rep, 4931cb0ef41Sopenharmony_ci InstructionOperand* spill_operand, int instr_index, 4941cb0ef41Sopenharmony_ci bool is_phi, bool is_constant, 4951cb0ef41Sopenharmony_ci bool is_defined_in_deferred_block, 4961cb0ef41Sopenharmony_ci bool is_exceptional_call_output); 4971cb0ef41Sopenharmony_ci 4981cb0ef41Sopenharmony_ci void AddSpillUse(int instr_index, MidTierRegisterAllocationData* data); 4991cb0ef41Sopenharmony_ci void AddPendingSpillOperand(PendingOperand* pending_operand); 5001cb0ef41Sopenharmony_ci void EnsureSpillRange(MidTierRegisterAllocationData* data); 5011cb0ef41Sopenharmony_ci bool TrySpillOnEntryToDeferred(MidTierRegisterAllocationData* data, 5021cb0ef41Sopenharmony_ci const InstructionBlock* block); 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci InstructionOperand* spill_operand_; 5051cb0ef41Sopenharmony_ci SpillRange* spill_range_; 5061cb0ef41Sopenharmony_ci int output_instr_index_; 5071cb0ef41Sopenharmony_ci 5081cb0ef41Sopenharmony_ci int vreg_; 5091cb0ef41Sopenharmony_ci MachineRepresentation rep_; 5101cb0ef41Sopenharmony_ci bool is_phi_ : 1; 5111cb0ef41Sopenharmony_ci bool is_constant_ : 1; 5121cb0ef41Sopenharmony_ci bool is_defined_in_deferred_block_ : 1; 5131cb0ef41Sopenharmony_ci bool needs_spill_at_output_ : 1; 5141cb0ef41Sopenharmony_ci bool is_exceptional_call_output_ : 1; 5151cb0ef41Sopenharmony_ci}; 5161cb0ef41Sopenharmony_ci 5171cb0ef41Sopenharmony_ciVirtualRegisterData& MidTierRegisterAllocationData::VirtualRegisterDataFor( 5181cb0ef41Sopenharmony_ci int virtual_register) { 5191cb0ef41Sopenharmony_ci DCHECK_GE(virtual_register, 0); 5201cb0ef41Sopenharmony_ci DCHECK_LT(virtual_register, virtual_register_data_.size()); 5211cb0ef41Sopenharmony_ci return virtual_register_data_[virtual_register]; 5221cb0ef41Sopenharmony_ci} 5231cb0ef41Sopenharmony_ci 5241cb0ef41Sopenharmony_civoid VirtualRegisterData::Initialize(int virtual_register, 5251cb0ef41Sopenharmony_ci MachineRepresentation rep, 5261cb0ef41Sopenharmony_ci InstructionOperand* spill_operand, 5271cb0ef41Sopenharmony_ci int instr_index, bool is_phi, 5281cb0ef41Sopenharmony_ci bool is_constant, 5291cb0ef41Sopenharmony_ci bool is_defined_in_deferred_block, 5301cb0ef41Sopenharmony_ci bool is_exceptional_call_output) { 5311cb0ef41Sopenharmony_ci vreg_ = virtual_register; 5321cb0ef41Sopenharmony_ci rep_ = rep; 5331cb0ef41Sopenharmony_ci spill_operand_ = spill_operand; 5341cb0ef41Sopenharmony_ci spill_range_ = nullptr; 5351cb0ef41Sopenharmony_ci output_instr_index_ = instr_index; 5361cb0ef41Sopenharmony_ci is_phi_ = is_phi; 5371cb0ef41Sopenharmony_ci is_constant_ = is_constant; 5381cb0ef41Sopenharmony_ci is_defined_in_deferred_block_ = is_defined_in_deferred_block; 5391cb0ef41Sopenharmony_ci needs_spill_at_output_ = !is_constant_ && spill_operand_ != nullptr; 5401cb0ef41Sopenharmony_ci is_exceptional_call_output_ = is_exceptional_call_output; 5411cb0ef41Sopenharmony_ci} 5421cb0ef41Sopenharmony_ci 5431cb0ef41Sopenharmony_civoid VirtualRegisterData::DefineAsConstantOperand(ConstantOperand* operand, 5441cb0ef41Sopenharmony_ci MachineRepresentation rep, 5451cb0ef41Sopenharmony_ci int instr_index, 5461cb0ef41Sopenharmony_ci bool is_deferred_block) { 5471cb0ef41Sopenharmony_ci Initialize(operand->virtual_register(), rep, operand, instr_index, false, 5481cb0ef41Sopenharmony_ci true, is_deferred_block, false); 5491cb0ef41Sopenharmony_ci} 5501cb0ef41Sopenharmony_ci 5511cb0ef41Sopenharmony_civoid VirtualRegisterData::DefineAsFixedSpillOperand( 5521cb0ef41Sopenharmony_ci AllocatedOperand* operand, int virtual_register, MachineRepresentation rep, 5531cb0ef41Sopenharmony_ci int instr_index, bool is_deferred_block, bool is_exceptional_call_output) { 5541cb0ef41Sopenharmony_ci Initialize(virtual_register, rep, operand, instr_index, false, false, 5551cb0ef41Sopenharmony_ci is_deferred_block, is_exceptional_call_output); 5561cb0ef41Sopenharmony_ci} 5571cb0ef41Sopenharmony_ci 5581cb0ef41Sopenharmony_civoid VirtualRegisterData::DefineAsUnallocatedOperand( 5591cb0ef41Sopenharmony_ci int virtual_register, MachineRepresentation rep, int instr_index, 5601cb0ef41Sopenharmony_ci bool is_deferred_block, bool is_exceptional_call_output) { 5611cb0ef41Sopenharmony_ci Initialize(virtual_register, rep, nullptr, instr_index, false, false, 5621cb0ef41Sopenharmony_ci is_deferred_block, is_exceptional_call_output); 5631cb0ef41Sopenharmony_ci} 5641cb0ef41Sopenharmony_ci 5651cb0ef41Sopenharmony_civoid VirtualRegisterData::DefineAsPhi(int virtual_register, 5661cb0ef41Sopenharmony_ci MachineRepresentation rep, 5671cb0ef41Sopenharmony_ci int instr_index, bool is_deferred_block) { 5681cb0ef41Sopenharmony_ci Initialize(virtual_register, rep, nullptr, instr_index, true, false, 5691cb0ef41Sopenharmony_ci is_deferred_block, false); 5701cb0ef41Sopenharmony_ci} 5711cb0ef41Sopenharmony_ci 5721cb0ef41Sopenharmony_civoid VirtualRegisterData::EnsureSpillRange( 5731cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 5741cb0ef41Sopenharmony_ci DCHECK(!HasConstantSpillOperand()); 5751cb0ef41Sopenharmony_ci 5761cb0ef41Sopenharmony_ci if (HasSpillRange()) return; 5771cb0ef41Sopenharmony_ci 5781cb0ef41Sopenharmony_ci const InstructionBlock* definition_block = 5791cb0ef41Sopenharmony_ci data->GetBlock(output_instr_index_); 5801cb0ef41Sopenharmony_ci if (is_phi()) { 5811cb0ef41Sopenharmony_ci // Define a spill slot that is defined for the phi's range. 5821cb0ef41Sopenharmony_ci spill_range_ = 5831cb0ef41Sopenharmony_ci data->allocation_zone()->New<SpillRange>(definition_block, data); 5841cb0ef41Sopenharmony_ci } else { 5851cb0ef41Sopenharmony_ci if (is_exceptional_call_output()) { 5861cb0ef41Sopenharmony_ci // If this virtual register is output by a call which has an exception 5871cb0ef41Sopenharmony_ci // catch handler, then the output will only be live in the IfSuccess 5881cb0ef41Sopenharmony_ci // successor block, not the IfException side, so make the definition block 5891cb0ef41Sopenharmony_ci // the IfSuccess successor block explicitly. 5901cb0ef41Sopenharmony_ci DCHECK_EQ(output_instr_index_, 5911cb0ef41Sopenharmony_ci definition_block->last_instruction_index() - 1); 5921cb0ef41Sopenharmony_ci DCHECK_EQ(definition_block->SuccessorCount(), 2); 5931cb0ef41Sopenharmony_ci DCHECK(data->GetBlock(definition_block->successors()[1])->IsHandler()); 5941cb0ef41Sopenharmony_ci definition_block = data->GetBlock(definition_block->successors()[0]); 5951cb0ef41Sopenharmony_ci } 5961cb0ef41Sopenharmony_ci // The spill slot will be defined after the instruction that outputs it. 5971cb0ef41Sopenharmony_ci spill_range_ = data->allocation_zone()->New<SpillRange>( 5981cb0ef41Sopenharmony_ci output_instr_index_ + 1, definition_block, data); 5991cb0ef41Sopenharmony_ci } 6001cb0ef41Sopenharmony_ci data->spilled_virtual_registers().Add(vreg()); 6011cb0ef41Sopenharmony_ci} 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_civoid VirtualRegisterData::AddSpillUse(int instr_index, 6041cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 6051cb0ef41Sopenharmony_ci if (HasConstantSpillOperand()) return; 6061cb0ef41Sopenharmony_ci 6071cb0ef41Sopenharmony_ci EnsureSpillRange(data); 6081cb0ef41Sopenharmony_ci spill_range_->ExtendRangeTo(instr_index); 6091cb0ef41Sopenharmony_ci 6101cb0ef41Sopenharmony_ci const InstructionBlock* block = data->GetBlock(instr_index); 6111cb0ef41Sopenharmony_ci if (!TrySpillOnEntryToDeferred(data, block)) { 6121cb0ef41Sopenharmony_ci MarkAsNeedsSpillAtOutput(); 6131cb0ef41Sopenharmony_ci } 6141cb0ef41Sopenharmony_ci} 6151cb0ef41Sopenharmony_ci 6161cb0ef41Sopenharmony_civoid VirtualRegisterData::AddDeferredSpillUse( 6171cb0ef41Sopenharmony_ci int instr_index, MidTierRegisterAllocationData* data) { 6181cb0ef41Sopenharmony_ci DCHECK(data->GetBlock(instr_index)->IsDeferred()); 6191cb0ef41Sopenharmony_ci DCHECK(!is_defined_in_deferred_block()); 6201cb0ef41Sopenharmony_ci AddSpillUse(instr_index, data); 6211cb0ef41Sopenharmony_ci} 6221cb0ef41Sopenharmony_ci 6231cb0ef41Sopenharmony_cibool VirtualRegisterData::TrySpillOnEntryToDeferred( 6241cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data, const InstructionBlock* block) { 6251cb0ef41Sopenharmony_ci BlockState& block_state = data->block_state(block->rpo_number()); 6261cb0ef41Sopenharmony_ci if (!NeedsSpillAtOutput() && block->IsDeferred() && 6271cb0ef41Sopenharmony_ci !is_defined_in_deferred_block() && !is_constant()) { 6281cb0ef41Sopenharmony_ci return block_state.deferred_blocks_region()->TryDeferSpillOutputUntilEntry( 6291cb0ef41Sopenharmony_ci vreg()); 6301cb0ef41Sopenharmony_ci } 6311cb0ef41Sopenharmony_ci return false; 6321cb0ef41Sopenharmony_ci} 6331cb0ef41Sopenharmony_ci 6341cb0ef41Sopenharmony_civoid VirtualRegisterData::AddDeferredSpillOutput( 6351cb0ef41Sopenharmony_ci AllocatedOperand allocated_op, int instr_index, 6361cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 6371cb0ef41Sopenharmony_ci DCHECK(!NeedsSpillAtOutput()); 6381cb0ef41Sopenharmony_ci DCHECK(HasSpillRange()); 6391cb0ef41Sopenharmony_ci spill_range_->AddDeferredSpillOutput(allocated_op, instr_index, data); 6401cb0ef41Sopenharmony_ci} 6411cb0ef41Sopenharmony_ci 6421cb0ef41Sopenharmony_civoid VirtualRegisterData::SpillOperand(InstructionOperand* operand, 6431cb0ef41Sopenharmony_ci int instr_index, 6441cb0ef41Sopenharmony_ci bool has_constant_policy, 6451cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 6461cb0ef41Sopenharmony_ci if (!has_constant_policy && HasConstantSpillOperand()) { 6471cb0ef41Sopenharmony_ci // Reset the constant spill operand to force a real spill slot since this 6481cb0ef41Sopenharmony_ci // operand can't use the constant spill operand. 6491cb0ef41Sopenharmony_ci spill_operand_ = nullptr; 6501cb0ef41Sopenharmony_ci DCHECK(!HasConstantSpillOperand()); 6511cb0ef41Sopenharmony_ci } 6521cb0ef41Sopenharmony_ci AddSpillUse(instr_index, data); 6531cb0ef41Sopenharmony_ci if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) { 6541cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(operand, spill_operand()); 6551cb0ef41Sopenharmony_ci } else { 6561cb0ef41Sopenharmony_ci PendingOperand pending_op; 6571cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(operand, &pending_op); 6581cb0ef41Sopenharmony_ci AddPendingSpillOperand(PendingOperand::cast(operand)); 6591cb0ef41Sopenharmony_ci } 6601cb0ef41Sopenharmony_ci} 6611cb0ef41Sopenharmony_ci 6621cb0ef41Sopenharmony_cibool VirtualRegisterData::NeedsSpillAtDeferredBlocks() const { 6631cb0ef41Sopenharmony_ci return HasSpillRange() && spill_range()->HasDeferredBlockSpills(); 6641cb0ef41Sopenharmony_ci} 6651cb0ef41Sopenharmony_ci 6661cb0ef41Sopenharmony_civoid VirtualRegisterData::EmitDeferredSpillOutputs( 6671cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 6681cb0ef41Sopenharmony_ci DCHECK(NeedsSpillAtDeferredBlocks()); 6691cb0ef41Sopenharmony_ci for (auto deferred_spill : *spill_range()->deferred_spill_outputs()) { 6701cb0ef41Sopenharmony_ci EmitGapMoveToSpillSlot(deferred_spill.operand, deferred_spill.instr_index, 6711cb0ef41Sopenharmony_ci data); 6721cb0ef41Sopenharmony_ci } 6731cb0ef41Sopenharmony_ci} 6741cb0ef41Sopenharmony_ci 6751cb0ef41Sopenharmony_civoid VirtualRegisterData::EmitGapMoveToInputFromSpillSlot( 6761cb0ef41Sopenharmony_ci InstructionOperand to_operand, int instr_index, 6771cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 6781cb0ef41Sopenharmony_ci AddSpillUse(instr_index, data); 6791cb0ef41Sopenharmony_ci DCHECK(!to_operand.IsPending()); 6801cb0ef41Sopenharmony_ci if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) { 6811cb0ef41Sopenharmony_ci data->AddGapMove(instr_index, Instruction::END, *spill_operand(), 6821cb0ef41Sopenharmony_ci to_operand); 6831cb0ef41Sopenharmony_ci } else { 6841cb0ef41Sopenharmony_ci MoveOperands* move_ops = 6851cb0ef41Sopenharmony_ci data->AddPendingOperandGapMove(instr_index, Instruction::END); 6861cb0ef41Sopenharmony_ci AddPendingSpillOperand(PendingOperand::cast(&move_ops->source())); 6871cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(&move_ops->destination(), &to_operand); 6881cb0ef41Sopenharmony_ci } 6891cb0ef41Sopenharmony_ci} 6901cb0ef41Sopenharmony_ci 6911cb0ef41Sopenharmony_civoid VirtualRegisterData::EmitGapMoveToSpillSlot( 6921cb0ef41Sopenharmony_ci InstructionOperand from_operand, int instr_index, 6931cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 6941cb0ef41Sopenharmony_ci AddSpillUse(instr_index, data); 6951cb0ef41Sopenharmony_ci if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) { 6961cb0ef41Sopenharmony_ci data->AddGapMove(instr_index, Instruction::START, from_operand, 6971cb0ef41Sopenharmony_ci *spill_operand()); 6981cb0ef41Sopenharmony_ci } else { 6991cb0ef41Sopenharmony_ci MoveOperands* move_ops = 7001cb0ef41Sopenharmony_ci data->AddPendingOperandGapMove(instr_index, Instruction::START); 7011cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(&move_ops->source(), &from_operand); 7021cb0ef41Sopenharmony_ci AddPendingSpillOperand(PendingOperand::cast(&move_ops->destination())); 7031cb0ef41Sopenharmony_ci } 7041cb0ef41Sopenharmony_ci} 7051cb0ef41Sopenharmony_ci 7061cb0ef41Sopenharmony_civoid VirtualRegisterData::EmitGapMoveFromOutputToSpillSlot( 7071cb0ef41Sopenharmony_ci InstructionOperand from_operand, const InstructionBlock* current_block, 7081cb0ef41Sopenharmony_ci int instr_index, MidTierRegisterAllocationData* data) { 7091cb0ef41Sopenharmony_ci DCHECK_EQ(data->GetBlock(instr_index), current_block); 7101cb0ef41Sopenharmony_ci if (instr_index == current_block->last_instruction_index()) { 7111cb0ef41Sopenharmony_ci // Add gap move to the first instruction of every successor block. 7121cb0ef41Sopenharmony_ci for (const RpoNumber& succ : current_block->successors()) { 7131cb0ef41Sopenharmony_ci const InstructionBlock* successor = data->GetBlock(succ); 7141cb0ef41Sopenharmony_ci DCHECK_EQ(1, successor->PredecessorCount()); 7151cb0ef41Sopenharmony_ci EmitGapMoveToSpillSlot(from_operand, successor->first_instruction_index(), 7161cb0ef41Sopenharmony_ci data); 7171cb0ef41Sopenharmony_ci } 7181cb0ef41Sopenharmony_ci } else { 7191cb0ef41Sopenharmony_ci // Add gap move to the next instruction. 7201cb0ef41Sopenharmony_ci EmitGapMoveToSpillSlot(from_operand, instr_index + 1, data); 7211cb0ef41Sopenharmony_ci } 7221cb0ef41Sopenharmony_ci} 7231cb0ef41Sopenharmony_ci 7241cb0ef41Sopenharmony_civoid VirtualRegisterData::AddPendingSpillOperand(PendingOperand* pending_op) { 7251cb0ef41Sopenharmony_ci DCHECK(HasSpillRange()); 7261cb0ef41Sopenharmony_ci DCHECK_NULL(pending_op->next()); 7271cb0ef41Sopenharmony_ci if (HasSpillOperand()) { 7281cb0ef41Sopenharmony_ci pending_op->set_next(PendingOperand::cast(spill_operand())); 7291cb0ef41Sopenharmony_ci } 7301cb0ef41Sopenharmony_ci spill_operand_ = pending_op; 7311cb0ef41Sopenharmony_ci} 7321cb0ef41Sopenharmony_ci 7331cb0ef41Sopenharmony_civoid VirtualRegisterData::AllocatePendingSpillOperand( 7341cb0ef41Sopenharmony_ci const AllocatedOperand& allocated) { 7351cb0ef41Sopenharmony_ci DCHECK(!HasAllocatedSpillOperand() && !HasConstantSpillOperand()); 7361cb0ef41Sopenharmony_ci PendingOperand* current = PendingOperand::cast(spill_operand_); 7371cb0ef41Sopenharmony_ci while (current) { 7381cb0ef41Sopenharmony_ci PendingOperand* next = current->next(); 7391cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(current, &allocated); 7401cb0ef41Sopenharmony_ci current = next; 7411cb0ef41Sopenharmony_ci } 7421cb0ef41Sopenharmony_ci} 7431cb0ef41Sopenharmony_ci 7441cb0ef41Sopenharmony_ci// RegisterState represents the state of the |kind| registers at a particular 7451cb0ef41Sopenharmony_ci// point in program execution. The RegisterState can be cloned or merged with 7461cb0ef41Sopenharmony_ci// other RegisterStates to model branches and merges in program control flow. 7471cb0ef41Sopenharmony_ciclass RegisterState final : public ZoneObject { 7481cb0ef41Sopenharmony_ci public: 7491cb0ef41Sopenharmony_ci static RegisterState* New(RegisterKind kind, int num_allocatable_registers, 7501cb0ef41Sopenharmony_ci Zone* zone) { 7511cb0ef41Sopenharmony_ci return zone->New<RegisterState>(kind, num_allocatable_registers, zone); 7521cb0ef41Sopenharmony_ci } 7531cb0ef41Sopenharmony_ci 7541cb0ef41Sopenharmony_ci RegisterState(RegisterKind kind, int num_allocatable_registers, Zone* zone); 7551cb0ef41Sopenharmony_ci RegisterState(const RegisterState& other) V8_NOEXCEPT; 7561cb0ef41Sopenharmony_ci 7571cb0ef41Sopenharmony_ci bool IsAllocated(RegisterIndex reg); 7581cb0ef41Sopenharmony_ci bool IsShared(RegisterIndex reg); 7591cb0ef41Sopenharmony_ci int VirtualRegisterForRegister(RegisterIndex reg); 7601cb0ef41Sopenharmony_ci 7611cb0ef41Sopenharmony_ci // Commit the |reg| with the |allocated| operand. 7621cb0ef41Sopenharmony_ci void Commit(RegisterIndex reg, AllocatedOperand allocated, 7631cb0ef41Sopenharmony_ci InstructionOperand* operand, MidTierRegisterAllocationData* data); 7641cb0ef41Sopenharmony_ci 7651cb0ef41Sopenharmony_ci // Spill the contents of |reg| for an instruction in |current_block| using 7661cb0ef41Sopenharmony_ci // the |allocated| operand to commit the spill gap move. 7671cb0ef41Sopenharmony_ci void Spill(RegisterIndex reg, AllocatedOperand allocated, 7681cb0ef41Sopenharmony_ci const InstructionBlock* current_block, 7691cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 7701cb0ef41Sopenharmony_ci 7711cb0ef41Sopenharmony_ci // Add a pending spill of the contents of |reg| at the exit point of a 7721cb0ef41Sopenharmony_ci // deferred block at |instr_index| using |allocated| operand to commit the 7731cb0ef41Sopenharmony_ci // spill gap move, if the register never gets spilled in a non-deferred block. 7741cb0ef41Sopenharmony_ci void SpillForDeferred(RegisterIndex reg, AllocatedOperand allocated, 7751cb0ef41Sopenharmony_ci int instr_index, MidTierRegisterAllocationData* data); 7761cb0ef41Sopenharmony_ci 7771cb0ef41Sopenharmony_ci // Add a pending gap move from |reg| to |virtual_register|'s spill at the 7781cb0ef41Sopenharmony_ci // entry point of a deferred block at |instr_index|, if the |virtual_register| 7791cb0ef41Sopenharmony_ci // never spilled in a non-deferred block. 7801cb0ef41Sopenharmony_ci void MoveToSpillSlotOnDeferred(RegisterIndex reg, int virtual_register, 7811cb0ef41Sopenharmony_ci int instr_index, 7821cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 7831cb0ef41Sopenharmony_ci 7841cb0ef41Sopenharmony_ci // Allocate |reg| to |virtual_register| for the instruction at |instr_index|. 7851cb0ef41Sopenharmony_ci // If the register is later spilled, a gap move will be added immediately 7861cb0ef41Sopenharmony_ci // before |instr_index| to move |virtual_register| into this register. 7871cb0ef41Sopenharmony_ci void AllocateUse(RegisterIndex reg, int virtual_register, 7881cb0ef41Sopenharmony_ci InstructionOperand* operand, int instr_index, 7891cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 7901cb0ef41Sopenharmony_ci 7911cb0ef41Sopenharmony_ci // Allocate |reg| as a pending use of |virtual_register| for |operand| in the 7921cb0ef41Sopenharmony_ci // instruction at |instr_index|. If |virtual_register| later gets committed to 7931cb0ef41Sopenharmony_ci // this register, then |operand| will be too, otherwise |operand| will be 7941cb0ef41Sopenharmony_ci // replaced with |virtual_register|'s spill operand. 7951cb0ef41Sopenharmony_ci void AllocatePendingUse(RegisterIndex reg, int virtual_register, 7961cb0ef41Sopenharmony_ci InstructionOperand* operand, bool can_be_constant, 7971cb0ef41Sopenharmony_ci int instr_index); 7981cb0ef41Sopenharmony_ci 7991cb0ef41Sopenharmony_ci // Mark that the register is holding a phi operand that is yet to be allocated 8001cb0ef41Sopenharmony_ci // by the source block in the gap just before the last instruction in the 8011cb0ef41Sopenharmony_ci // source block. 8021cb0ef41Sopenharmony_ci void UseForPhiGapMove(RegisterIndex reg); 8031cb0ef41Sopenharmony_ci bool IsPhiGapMove(RegisterIndex reg); 8041cb0ef41Sopenharmony_ci 8051cb0ef41Sopenharmony_ci // Returns true if |reg| only has pending uses allocated to it. 8061cb0ef41Sopenharmony_ci bool HasPendingUsesOnly(RegisterIndex reg); 8071cb0ef41Sopenharmony_ci 8081cb0ef41Sopenharmony_ci // Clone this RegisterState for a successor block. 8091cb0ef41Sopenharmony_ci RegisterState* Clone(); 8101cb0ef41Sopenharmony_ci 8111cb0ef41Sopenharmony_ci // Copy register details for |reg| from |source| to |this| RegisterState. 8121cb0ef41Sopenharmony_ci void CopyFrom(RegisterIndex reg, RegisterState* source); 8131cb0ef41Sopenharmony_ci 8141cb0ef41Sopenharmony_ci // Returns true if the register details for |reg| are equal in |source| and 8151cb0ef41Sopenharmony_ci // |this| RegisterStates. 8161cb0ef41Sopenharmony_ci bool Equals(RegisterIndex reg, RegisterState* source); 8171cb0ef41Sopenharmony_ci 8181cb0ef41Sopenharmony_ci // Signals that the registers in this state are going to be shared across 8191cb0ef41Sopenharmony_ci // |shared_use_count| blocks. 8201cb0ef41Sopenharmony_ci void AddSharedUses(int shared_use_count); 8211cb0ef41Sopenharmony_ci 8221cb0ef41Sopenharmony_ci // When merging multiple block's RegisterState into the successor block with 8231cb0ef41Sopenharmony_ci // |this| RegisterState, commit |reg| as being merged from a given predecessor 8241cb0ef41Sopenharmony_ci // block. 8251cb0ef41Sopenharmony_ci void CommitAtMerge(RegisterIndex reg); 8261cb0ef41Sopenharmony_ci 8271cb0ef41Sopenharmony_ci // Resets |reg| if it has register data that was shared with other basic 8281cb0ef41Sopenharmony_ci // blocks and was spilled in those blocks. 8291cb0ef41Sopenharmony_ci void ResetIfSpilledWhileShared(RegisterIndex reg); 8301cb0ef41Sopenharmony_ci 8311cb0ef41Sopenharmony_ci // Enable range-based for on allocatable register indices. 8321cb0ef41Sopenharmony_ci RegisterIndex::Iterator begin() const { return RegisterIndex::Iterator(0); } 8331cb0ef41Sopenharmony_ci RegisterIndex::Iterator end() const { 8341cb0ef41Sopenharmony_ci return RegisterIndex::Iterator(num_allocatable_registers()); 8351cb0ef41Sopenharmony_ci } 8361cb0ef41Sopenharmony_ci 8371cb0ef41Sopenharmony_ci private: 8381cb0ef41Sopenharmony_ci // Represents a particular register and details of what virtual_register it is 8391cb0ef41Sopenharmony_ci // currently holding, and how it should be updated if committed or spilled. 8401cb0ef41Sopenharmony_ci class Register final : public ZoneObject { 8411cb0ef41Sopenharmony_ci public: 8421cb0ef41Sopenharmony_ci Register(); 8431cb0ef41Sopenharmony_ci void Reset(); 8441cb0ef41Sopenharmony_ci 8451cb0ef41Sopenharmony_ci // Operations for committing, spilling and allocating uses of the register. 8461cb0ef41Sopenharmony_ci void Commit(AllocatedOperand allocated_operand, 8471cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 8481cb0ef41Sopenharmony_ci void Spill(AllocatedOperand allocated_op, 8491cb0ef41Sopenharmony_ci const InstructionBlock* current_block, 8501cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 8511cb0ef41Sopenharmony_ci void Use(int virtual_register, int instr_index); 8521cb0ef41Sopenharmony_ci void PendingUse(InstructionOperand* operand, int virtual_register, 8531cb0ef41Sopenharmony_ci bool can_be_constant, int instr_index); 8541cb0ef41Sopenharmony_ci void SpillForDeferred(AllocatedOperand allocated, int instr_index, 8551cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 8561cb0ef41Sopenharmony_ci void MoveToSpillSlotOnDeferred(int virtual_register, int instr_index, 8571cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 8581cb0ef41Sopenharmony_ci 8591cb0ef41Sopenharmony_ci // Mark register as holding a phi. 8601cb0ef41Sopenharmony_ci void MarkAsPhiMove(); 8611cb0ef41Sopenharmony_ci bool is_phi_gap_move() const { return is_phi_gap_move_; } 8621cb0ef41Sopenharmony_ci 8631cb0ef41Sopenharmony_ci // The register has deferred block spills, that will be emitted if the 8641cb0ef41Sopenharmony_ci // register is committed without having been spilled in a non-deferred block 8651cb0ef41Sopenharmony_ci void AddDeferredBlockSpill(int instr_index, bool on_exit, Zone* zone); 8661cb0ef41Sopenharmony_ci bool has_deferred_block_spills() const { 8671cb0ef41Sopenharmony_ci return deferred_block_spills_.has_value(); 8681cb0ef41Sopenharmony_ci } 8691cb0ef41Sopenharmony_ci 8701cb0ef41Sopenharmony_ci // Operations related to dealing with a Register that is shared across 8711cb0ef41Sopenharmony_ci // multiple basic blocks. 8721cb0ef41Sopenharmony_ci void CommitAtMerge(); 8731cb0ef41Sopenharmony_ci void AddSharedUses(int shared_use_count); 8741cb0ef41Sopenharmony_ci bool is_shared() const { return is_shared_; } 8751cb0ef41Sopenharmony_ci bool was_spilled_while_shared() const { 8761cb0ef41Sopenharmony_ci return is_shared() && !is_allocated(); 8771cb0ef41Sopenharmony_ci } 8781cb0ef41Sopenharmony_ci 8791cb0ef41Sopenharmony_ci bool is_allocated() const { 8801cb0ef41Sopenharmony_ci return virtual_register_ != InstructionOperand::kInvalidVirtualRegister; 8811cb0ef41Sopenharmony_ci } 8821cb0ef41Sopenharmony_ci 8831cb0ef41Sopenharmony_ci // The current virtual register held by this register. 8841cb0ef41Sopenharmony_ci int virtual_register() const { return virtual_register_; } 8851cb0ef41Sopenharmony_ci 8861cb0ef41Sopenharmony_ci // The instruction index for the last use of the current in-progress 8871cb0ef41Sopenharmony_ci // allocation of this register in the instruction stream. Used both 8881cb0ef41Sopenharmony_ci // as the instruction too add a gap move if |needs_gap_move_on_spill| and 8891cb0ef41Sopenharmony_ci // the intruction which the virtual register's spill range should be 8901cb0ef41Sopenharmony_ci // extended too if the register is spilled. 8911cb0ef41Sopenharmony_ci int last_use_instr_index() const { return last_use_instr_index_; } 8921cb0ef41Sopenharmony_ci 8931cb0ef41Sopenharmony_ci // Returns true if a gap move should be added if the register is spilled. 8941cb0ef41Sopenharmony_ci bool needs_gap_move_on_spill() const { return needs_gap_move_on_spill_; } 8951cb0ef41Sopenharmony_ci 8961cb0ef41Sopenharmony_ci // Returns a threaded list of the operands that have pending uses of this 8971cb0ef41Sopenharmony_ci // register and will be resolved either to the register, or a spill slot 8981cb0ef41Sopenharmony_ci // depending on whether this register is spilled or committed. 8991cb0ef41Sopenharmony_ci PendingOperand* pending_uses() const { return pending_uses_; } 9001cb0ef41Sopenharmony_ci 9011cb0ef41Sopenharmony_ci private: 9021cb0ef41Sopenharmony_ci struct DeferredBlockSpill { 9031cb0ef41Sopenharmony_ci DeferredBlockSpill(int instr, bool on_exit) 9041cb0ef41Sopenharmony_ci : instr_index(instr), on_deferred_exit(on_exit) {} 9051cb0ef41Sopenharmony_ci 9061cb0ef41Sopenharmony_ci int instr_index; 9071cb0ef41Sopenharmony_ci bool on_deferred_exit; 9081cb0ef41Sopenharmony_ci }; 9091cb0ef41Sopenharmony_ci 9101cb0ef41Sopenharmony_ci void SpillPendingUses(MidTierRegisterAllocationData* data); 9111cb0ef41Sopenharmony_ci void SpillPhiGapMove(AllocatedOperand allocated_op, 9121cb0ef41Sopenharmony_ci const InstructionBlock* block, 9131cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 9141cb0ef41Sopenharmony_ci 9151cb0ef41Sopenharmony_ci bool needs_gap_move_on_spill_; 9161cb0ef41Sopenharmony_ci bool is_shared_; 9171cb0ef41Sopenharmony_ci bool is_phi_gap_move_; 9181cb0ef41Sopenharmony_ci bool pending_uses_can_use_constant_; 9191cb0ef41Sopenharmony_ci int last_use_instr_index_; 9201cb0ef41Sopenharmony_ci 9211cb0ef41Sopenharmony_ci int num_commits_required_; 9221cb0ef41Sopenharmony_ci int virtual_register_; 9231cb0ef41Sopenharmony_ci PendingOperand* pending_uses_; 9241cb0ef41Sopenharmony_ci base::Optional<ZoneVector<DeferredBlockSpill>> deferred_block_spills_; 9251cb0ef41Sopenharmony_ci }; 9261cb0ef41Sopenharmony_ci 9271cb0ef41Sopenharmony_ci void ResetDataFor(RegisterIndex reg); 9281cb0ef41Sopenharmony_ci 9291cb0ef41Sopenharmony_ci bool HasRegisterData(RegisterIndex reg); 9301cb0ef41Sopenharmony_ci void EnsureRegisterData(RegisterIndex reg); 9311cb0ef41Sopenharmony_ci 9321cb0ef41Sopenharmony_ci int num_allocatable_registers() const { 9331cb0ef41Sopenharmony_ci return static_cast<int>(register_data_.size()); 9341cb0ef41Sopenharmony_ci } 9351cb0ef41Sopenharmony_ci Register& reg_data(RegisterIndex reg); 9361cb0ef41Sopenharmony_ci Zone* zone() const { return zone_; } 9371cb0ef41Sopenharmony_ci 9381cb0ef41Sopenharmony_ci ZoneVector<Register*> register_data_; 9391cb0ef41Sopenharmony_ci Zone* zone_; 9401cb0ef41Sopenharmony_ci}; 9411cb0ef41Sopenharmony_ci 9421cb0ef41Sopenharmony_ciRegisterState::Register::Register() { Reset(); } 9431cb0ef41Sopenharmony_ci 9441cb0ef41Sopenharmony_civoid RegisterState::Register::Reset() { 9451cb0ef41Sopenharmony_ci is_shared_ = false; 9461cb0ef41Sopenharmony_ci is_phi_gap_move_ = false; 9471cb0ef41Sopenharmony_ci needs_gap_move_on_spill_ = false; 9481cb0ef41Sopenharmony_ci pending_uses_can_use_constant_ = true; 9491cb0ef41Sopenharmony_ci last_use_instr_index_ = -1; 9501cb0ef41Sopenharmony_ci num_commits_required_ = 0; 9511cb0ef41Sopenharmony_ci virtual_register_ = InstructionOperand::kInvalidVirtualRegister; 9521cb0ef41Sopenharmony_ci pending_uses_ = nullptr; 9531cb0ef41Sopenharmony_ci deferred_block_spills_.reset(); 9541cb0ef41Sopenharmony_ci} 9551cb0ef41Sopenharmony_ci 9561cb0ef41Sopenharmony_civoid RegisterState::Register::Use(int virtual_register, int instr_index) { 9571cb0ef41Sopenharmony_ci // A register can have many pending uses, but should only ever have a single 9581cb0ef41Sopenharmony_ci // non-pending use, since any subsiquent use will commit the preceeding use 9591cb0ef41Sopenharmony_ci // first. 9601cb0ef41Sopenharmony_ci DCHECK(!is_allocated()); 9611cb0ef41Sopenharmony_ci DCHECK(!is_shared()); 9621cb0ef41Sopenharmony_ci needs_gap_move_on_spill_ = true; 9631cb0ef41Sopenharmony_ci virtual_register_ = virtual_register; 9641cb0ef41Sopenharmony_ci last_use_instr_index_ = instr_index; 9651cb0ef41Sopenharmony_ci num_commits_required_ = 1; 9661cb0ef41Sopenharmony_ci} 9671cb0ef41Sopenharmony_ci 9681cb0ef41Sopenharmony_civoid RegisterState::Register::PendingUse(InstructionOperand* operand, 9691cb0ef41Sopenharmony_ci int virtual_register, 9701cb0ef41Sopenharmony_ci bool can_be_constant, 9711cb0ef41Sopenharmony_ci int instr_index) { 9721cb0ef41Sopenharmony_ci DCHECK(!was_spilled_while_shared()); 9731cb0ef41Sopenharmony_ci if (!is_allocated()) { 9741cb0ef41Sopenharmony_ci virtual_register_ = virtual_register; 9751cb0ef41Sopenharmony_ci last_use_instr_index_ = instr_index; 9761cb0ef41Sopenharmony_ci num_commits_required_ = 1; 9771cb0ef41Sopenharmony_ci } 9781cb0ef41Sopenharmony_ci DCHECK_EQ(virtual_register_, virtual_register); 9791cb0ef41Sopenharmony_ci pending_uses_can_use_constant_ &= can_be_constant; 9801cb0ef41Sopenharmony_ci 9811cb0ef41Sopenharmony_ci PendingOperand pending_op(pending_uses()); 9821cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(operand, &pending_op); 9831cb0ef41Sopenharmony_ci pending_uses_ = PendingOperand::cast(operand); 9841cb0ef41Sopenharmony_ci} 9851cb0ef41Sopenharmony_ci 9861cb0ef41Sopenharmony_civoid RegisterState::Register::MarkAsPhiMove() { 9871cb0ef41Sopenharmony_ci DCHECK(is_allocated()); 9881cb0ef41Sopenharmony_ci is_phi_gap_move_ = true; 9891cb0ef41Sopenharmony_ci} 9901cb0ef41Sopenharmony_ci 9911cb0ef41Sopenharmony_civoid RegisterState::Register::AddDeferredBlockSpill(int instr_index, 9921cb0ef41Sopenharmony_ci bool on_exit, Zone* zone) { 9931cb0ef41Sopenharmony_ci DCHECK(is_allocated()); 9941cb0ef41Sopenharmony_ci if (!deferred_block_spills_) { 9951cb0ef41Sopenharmony_ci deferred_block_spills_.emplace(zone); 9961cb0ef41Sopenharmony_ci } 9971cb0ef41Sopenharmony_ci deferred_block_spills_->emplace_back(instr_index, on_exit); 9981cb0ef41Sopenharmony_ci} 9991cb0ef41Sopenharmony_ci 10001cb0ef41Sopenharmony_civoid RegisterState::Register::AddSharedUses(int shared_use_count) { 10011cb0ef41Sopenharmony_ci DCHECK(!was_spilled_while_shared()); 10021cb0ef41Sopenharmony_ci is_shared_ = true; 10031cb0ef41Sopenharmony_ci num_commits_required_ += shared_use_count; 10041cb0ef41Sopenharmony_ci} 10051cb0ef41Sopenharmony_ci 10061cb0ef41Sopenharmony_civoid RegisterState::Register::CommitAtMerge() { 10071cb0ef41Sopenharmony_ci DCHECK(is_shared()); 10081cb0ef41Sopenharmony_ci DCHECK(is_allocated()); 10091cb0ef41Sopenharmony_ci --num_commits_required_; 10101cb0ef41Sopenharmony_ci // We should still have commits required that will be resolved in the merge 10111cb0ef41Sopenharmony_ci // block. 10121cb0ef41Sopenharmony_ci DCHECK_GT(num_commits_required_, 0); 10131cb0ef41Sopenharmony_ci} 10141cb0ef41Sopenharmony_ci 10151cb0ef41Sopenharmony_civoid RegisterState::Register::Commit(AllocatedOperand allocated_op, 10161cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 10171cb0ef41Sopenharmony_ci DCHECK(is_allocated()); 10181cb0ef41Sopenharmony_ci DCHECK_GT(num_commits_required_, 0); 10191cb0ef41Sopenharmony_ci 10201cb0ef41Sopenharmony_ci if (--num_commits_required_ == 0) { 10211cb0ef41Sopenharmony_ci // Allocate all pending uses to |allocated_op| if this commit is non-shared, 10221cb0ef41Sopenharmony_ci // or if it is the final commit required on a register data shared across 10231cb0ef41Sopenharmony_ci // blocks. 10241cb0ef41Sopenharmony_ci PendingOperand* pending_use = pending_uses(); 10251cb0ef41Sopenharmony_ci while (pending_use) { 10261cb0ef41Sopenharmony_ci PendingOperand* next = pending_use->next(); 10271cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(pending_use, &allocated_op); 10281cb0ef41Sopenharmony_ci pending_use = next; 10291cb0ef41Sopenharmony_ci } 10301cb0ef41Sopenharmony_ci pending_uses_ = nullptr; 10311cb0ef41Sopenharmony_ci 10321cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 10331cb0ef41Sopenharmony_ci data->VirtualRegisterDataFor(virtual_register()); 10341cb0ef41Sopenharmony_ci 10351cb0ef41Sopenharmony_ci // If there are deferred block gap moves pending, emit them now that the 10361cb0ef41Sopenharmony_ci // register has been committed. 10371cb0ef41Sopenharmony_ci if (has_deferred_block_spills()) { 10381cb0ef41Sopenharmony_ci for (DeferredBlockSpill& spill : *deferred_block_spills_) { 10391cb0ef41Sopenharmony_ci if (spill.on_deferred_exit) { 10401cb0ef41Sopenharmony_ci vreg_data.EmitGapMoveToInputFromSpillSlot(allocated_op, 10411cb0ef41Sopenharmony_ci spill.instr_index, data); 10421cb0ef41Sopenharmony_ci } else if (!vreg_data.NeedsSpillAtOutput()) { 10431cb0ef41Sopenharmony_ci vreg_data.AddDeferredSpillOutput(allocated_op, spill.instr_index, 10441cb0ef41Sopenharmony_ci data); 10451cb0ef41Sopenharmony_ci } 10461cb0ef41Sopenharmony_ci } 10471cb0ef41Sopenharmony_ci } 10481cb0ef41Sopenharmony_ci 10491cb0ef41Sopenharmony_ci // If this register was used as a phi gap move, then it being commited 10501cb0ef41Sopenharmony_ci // is the point at which we have output the Phi. 10511cb0ef41Sopenharmony_ci if (is_phi_gap_move() && vreg_data.NeedsSpillAtDeferredBlocks()) { 10521cb0ef41Sopenharmony_ci vreg_data.EmitDeferredSpillOutputs(data); 10531cb0ef41Sopenharmony_ci } 10541cb0ef41Sopenharmony_ci } 10551cb0ef41Sopenharmony_ci DCHECK_IMPLIES(num_commits_required_ > 0, is_shared()); 10561cb0ef41Sopenharmony_ci} 10571cb0ef41Sopenharmony_ci 10581cb0ef41Sopenharmony_civoid RegisterState::Register::Spill(AllocatedOperand allocated_op, 10591cb0ef41Sopenharmony_ci const InstructionBlock* current_block, 10601cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 10611cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 10621cb0ef41Sopenharmony_ci data->VirtualRegisterDataFor(virtual_register()); 10631cb0ef41Sopenharmony_ci SpillPendingUses(data); 10641cb0ef41Sopenharmony_ci if (is_phi_gap_move()) { 10651cb0ef41Sopenharmony_ci SpillPhiGapMove(allocated_op, current_block, data); 10661cb0ef41Sopenharmony_ci } 10671cb0ef41Sopenharmony_ci if (needs_gap_move_on_spill()) { 10681cb0ef41Sopenharmony_ci vreg_data.EmitGapMoveToInputFromSpillSlot(allocated_op, 10691cb0ef41Sopenharmony_ci last_use_instr_index(), data); 10701cb0ef41Sopenharmony_ci } 10711cb0ef41Sopenharmony_ci if (has_deferred_block_spills() || !current_block->IsDeferred()) { 10721cb0ef41Sopenharmony_ci vreg_data.MarkAsNeedsSpillAtOutput(); 10731cb0ef41Sopenharmony_ci } 10741cb0ef41Sopenharmony_ci // TODO(1180335): Doing a full reset here shouldn't be necessary, but 10751cb0ef41Sopenharmony_ci // investigate if it fixes crbug.com/1180335. 10761cb0ef41Sopenharmony_ci bool is_shared = is_shared_; 10771cb0ef41Sopenharmony_ci Reset(); 10781cb0ef41Sopenharmony_ci is_shared_ = is_shared; 10791cb0ef41Sopenharmony_ci DCHECK_IMPLIES(is_shared_, was_spilled_while_shared()); 10801cb0ef41Sopenharmony_ci} 10811cb0ef41Sopenharmony_ci 10821cb0ef41Sopenharmony_civoid RegisterState::Register::SpillPhiGapMove( 10831cb0ef41Sopenharmony_ci AllocatedOperand allocated_op, const InstructionBlock* current_block, 10841cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 10851cb0ef41Sopenharmony_ci DCHECK_EQ(current_block->SuccessorCount(), 1); 10861cb0ef41Sopenharmony_ci const InstructionBlock* phi_block = 10871cb0ef41Sopenharmony_ci data->GetBlock(current_block->successors()[0]); 10881cb0ef41Sopenharmony_ci 10891cb0ef41Sopenharmony_ci // Add gap moves to the spilled phi for all blocks we previously allocated 10901cb0ef41Sopenharmony_ci // assuming the the phi was in a register. 10911cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 10921cb0ef41Sopenharmony_ci data->VirtualRegisterDataFor(virtual_register()); 10931cb0ef41Sopenharmony_ci for (RpoNumber predecessor : phi_block->predecessors()) { 10941cb0ef41Sopenharmony_ci // If the predecessor has a lower rpo number than the current block, then 10951cb0ef41Sopenharmony_ci // we have already processed it, so add the required gap move. 10961cb0ef41Sopenharmony_ci if (predecessor > current_block->rpo_number()) { 10971cb0ef41Sopenharmony_ci const InstructionBlock* predecessor_block = data->GetBlock(predecessor); 10981cb0ef41Sopenharmony_ci vreg_data.EmitGapMoveToSpillSlot( 10991cb0ef41Sopenharmony_ci allocated_op, predecessor_block->last_instruction_index(), data); 11001cb0ef41Sopenharmony_ci } 11011cb0ef41Sopenharmony_ci } 11021cb0ef41Sopenharmony_ci} 11031cb0ef41Sopenharmony_ci 11041cb0ef41Sopenharmony_civoid RegisterState::Register::SpillPendingUses( 11051cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 11061cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 11071cb0ef41Sopenharmony_ci data->VirtualRegisterDataFor(virtual_register()); 11081cb0ef41Sopenharmony_ci PendingOperand* pending_use = pending_uses(); 11091cb0ef41Sopenharmony_ci while (pending_use) { 11101cb0ef41Sopenharmony_ci // Spill all the pending operands associated with this register. 11111cb0ef41Sopenharmony_ci PendingOperand* next = pending_use->next(); 11121cb0ef41Sopenharmony_ci vreg_data.SpillOperand(pending_use, last_use_instr_index(), 11131cb0ef41Sopenharmony_ci pending_uses_can_use_constant_, data); 11141cb0ef41Sopenharmony_ci pending_use = next; 11151cb0ef41Sopenharmony_ci } 11161cb0ef41Sopenharmony_ci pending_uses_ = nullptr; 11171cb0ef41Sopenharmony_ci} 11181cb0ef41Sopenharmony_ci 11191cb0ef41Sopenharmony_civoid RegisterState::Register::SpillForDeferred( 11201cb0ef41Sopenharmony_ci AllocatedOperand allocated, int instr_index, 11211cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 11221cb0ef41Sopenharmony_ci DCHECK(is_allocated()); 11231cb0ef41Sopenharmony_ci DCHECK(is_shared()); 11241cb0ef41Sopenharmony_ci // Add a pending deferred spill, then commit the register (with the commit 11251cb0ef41Sopenharmony_ci // being fullfilled by the deferred spill if the register is fully commited). 11261cb0ef41Sopenharmony_ci data->VirtualRegisterDataFor(virtual_register()) 11271cb0ef41Sopenharmony_ci .AddDeferredSpillUse(instr_index, data); 11281cb0ef41Sopenharmony_ci AddDeferredBlockSpill(instr_index, true, data->allocation_zone()); 11291cb0ef41Sopenharmony_ci Commit(allocated, data); 11301cb0ef41Sopenharmony_ci} 11311cb0ef41Sopenharmony_ci 11321cb0ef41Sopenharmony_civoid RegisterState::Register::MoveToSpillSlotOnDeferred( 11331cb0ef41Sopenharmony_ci int virtual_register, int instr_index, 11341cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 11351cb0ef41Sopenharmony_ci DCHECK(!was_spilled_while_shared()); 11361cb0ef41Sopenharmony_ci if (!is_allocated()) { 11371cb0ef41Sopenharmony_ci virtual_register_ = virtual_register; 11381cb0ef41Sopenharmony_ci last_use_instr_index_ = instr_index; 11391cb0ef41Sopenharmony_ci num_commits_required_ = 1; 11401cb0ef41Sopenharmony_ci } 11411cb0ef41Sopenharmony_ci AddDeferredBlockSpill(instr_index, false, data->allocation_zone()); 11421cb0ef41Sopenharmony_ci} 11431cb0ef41Sopenharmony_ci 11441cb0ef41Sopenharmony_ciRegisterState::RegisterState(RegisterKind kind, int num_allocatable_registers, 11451cb0ef41Sopenharmony_ci Zone* zone) 11461cb0ef41Sopenharmony_ci : register_data_(num_allocatable_registers, zone), zone_(zone) {} 11471cb0ef41Sopenharmony_ci 11481cb0ef41Sopenharmony_ciRegisterState::RegisterState(const RegisterState& other) V8_NOEXCEPT 11491cb0ef41Sopenharmony_ci : register_data_(other.register_data_.begin(), other.register_data_.end(), 11501cb0ef41Sopenharmony_ci other.zone_), 11511cb0ef41Sopenharmony_ci zone_(other.zone_) {} 11521cb0ef41Sopenharmony_ci 11531cb0ef41Sopenharmony_ciint RegisterState::VirtualRegisterForRegister(RegisterIndex reg) { 11541cb0ef41Sopenharmony_ci if (IsAllocated(reg)) { 11551cb0ef41Sopenharmony_ci return reg_data(reg).virtual_register(); 11561cb0ef41Sopenharmony_ci } else { 11571cb0ef41Sopenharmony_ci return InstructionOperand::kInvalidVirtualRegister; 11581cb0ef41Sopenharmony_ci } 11591cb0ef41Sopenharmony_ci} 11601cb0ef41Sopenharmony_ci 11611cb0ef41Sopenharmony_cibool RegisterState::IsPhiGapMove(RegisterIndex reg) { 11621cb0ef41Sopenharmony_ci DCHECK(IsAllocated(reg)); 11631cb0ef41Sopenharmony_ci return reg_data(reg).is_phi_gap_move(); 11641cb0ef41Sopenharmony_ci} 11651cb0ef41Sopenharmony_ci 11661cb0ef41Sopenharmony_civoid RegisterState::Commit(RegisterIndex reg, AllocatedOperand allocated, 11671cb0ef41Sopenharmony_ci InstructionOperand* operand, 11681cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 11691cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(operand, &allocated); 11701cb0ef41Sopenharmony_ci if (IsAllocated(reg)) { 11711cb0ef41Sopenharmony_ci reg_data(reg).Commit(allocated, data); 11721cb0ef41Sopenharmony_ci ResetDataFor(reg); 11731cb0ef41Sopenharmony_ci } 11741cb0ef41Sopenharmony_ci} 11751cb0ef41Sopenharmony_ci 11761cb0ef41Sopenharmony_civoid RegisterState::Spill(RegisterIndex reg, AllocatedOperand allocated, 11771cb0ef41Sopenharmony_ci const InstructionBlock* current_block, 11781cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 11791cb0ef41Sopenharmony_ci DCHECK(IsAllocated(reg)); 11801cb0ef41Sopenharmony_ci reg_data(reg).Spill(allocated, current_block, data); 11811cb0ef41Sopenharmony_ci ResetDataFor(reg); 11821cb0ef41Sopenharmony_ci} 11831cb0ef41Sopenharmony_ci 11841cb0ef41Sopenharmony_civoid RegisterState::SpillForDeferred(RegisterIndex reg, 11851cb0ef41Sopenharmony_ci AllocatedOperand allocated, 11861cb0ef41Sopenharmony_ci int instr_index, 11871cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 11881cb0ef41Sopenharmony_ci DCHECK(IsAllocated(reg)); 11891cb0ef41Sopenharmony_ci reg_data(reg).SpillForDeferred(allocated, instr_index, data); 11901cb0ef41Sopenharmony_ci ResetDataFor(reg); 11911cb0ef41Sopenharmony_ci} 11921cb0ef41Sopenharmony_ci 11931cb0ef41Sopenharmony_civoid RegisterState::MoveToSpillSlotOnDeferred( 11941cb0ef41Sopenharmony_ci RegisterIndex reg, int virtual_register, int instr_index, 11951cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 11961cb0ef41Sopenharmony_ci EnsureRegisterData(reg); 11971cb0ef41Sopenharmony_ci reg_data(reg).MoveToSpillSlotOnDeferred(virtual_register, instr_index, data); 11981cb0ef41Sopenharmony_ci} 11991cb0ef41Sopenharmony_ci 12001cb0ef41Sopenharmony_civoid RegisterState::AllocateUse(RegisterIndex reg, int virtual_register, 12011cb0ef41Sopenharmony_ci InstructionOperand* operand, int instr_index, 12021cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) { 12031cb0ef41Sopenharmony_ci EnsureRegisterData(reg); 12041cb0ef41Sopenharmony_ci reg_data(reg).Use(virtual_register, instr_index); 12051cb0ef41Sopenharmony_ci} 12061cb0ef41Sopenharmony_ci 12071cb0ef41Sopenharmony_civoid RegisterState::AllocatePendingUse(RegisterIndex reg, int virtual_register, 12081cb0ef41Sopenharmony_ci InstructionOperand* operand, 12091cb0ef41Sopenharmony_ci bool can_be_constant, int instr_index) { 12101cb0ef41Sopenharmony_ci EnsureRegisterData(reg); 12111cb0ef41Sopenharmony_ci reg_data(reg).PendingUse(operand, virtual_register, can_be_constant, 12121cb0ef41Sopenharmony_ci instr_index); 12131cb0ef41Sopenharmony_ci} 12141cb0ef41Sopenharmony_ci 12151cb0ef41Sopenharmony_civoid RegisterState::UseForPhiGapMove(RegisterIndex reg) { 12161cb0ef41Sopenharmony_ci DCHECK(IsAllocated(reg)); 12171cb0ef41Sopenharmony_ci reg_data(reg).MarkAsPhiMove(); 12181cb0ef41Sopenharmony_ci} 12191cb0ef41Sopenharmony_ci 12201cb0ef41Sopenharmony_ciRegisterState::Register& RegisterState::reg_data(RegisterIndex reg) { 12211cb0ef41Sopenharmony_ci DCHECK(HasRegisterData(reg)); 12221cb0ef41Sopenharmony_ci return *register_data_[reg.ToInt()]; 12231cb0ef41Sopenharmony_ci} 12241cb0ef41Sopenharmony_ci 12251cb0ef41Sopenharmony_cibool RegisterState::IsShared(RegisterIndex reg) { 12261cb0ef41Sopenharmony_ci return HasRegisterData(reg) && reg_data(reg).is_shared(); 12271cb0ef41Sopenharmony_ci} 12281cb0ef41Sopenharmony_ci 12291cb0ef41Sopenharmony_cibool RegisterState::IsAllocated(RegisterIndex reg) { 12301cb0ef41Sopenharmony_ci return HasRegisterData(reg) && reg_data(reg).is_allocated(); 12311cb0ef41Sopenharmony_ci} 12321cb0ef41Sopenharmony_ci 12331cb0ef41Sopenharmony_cibool RegisterState::HasPendingUsesOnly(RegisterIndex reg) { 12341cb0ef41Sopenharmony_ci DCHECK(IsAllocated(reg)); 12351cb0ef41Sopenharmony_ci return !reg_data(reg).needs_gap_move_on_spill(); 12361cb0ef41Sopenharmony_ci} 12371cb0ef41Sopenharmony_ci 12381cb0ef41Sopenharmony_civoid RegisterState::ResetDataFor(RegisterIndex reg) { 12391cb0ef41Sopenharmony_ci DCHECK(HasRegisterData(reg)); 12401cb0ef41Sopenharmony_ci if (reg_data(reg).is_shared()) { 12411cb0ef41Sopenharmony_ci register_data_[reg.ToInt()] = nullptr; 12421cb0ef41Sopenharmony_ci } else { 12431cb0ef41Sopenharmony_ci reg_data(reg).Reset(); 12441cb0ef41Sopenharmony_ci } 12451cb0ef41Sopenharmony_ci} 12461cb0ef41Sopenharmony_ci 12471cb0ef41Sopenharmony_cibool RegisterState::HasRegisterData(RegisterIndex reg) { 12481cb0ef41Sopenharmony_ci DCHECK_LT(reg.ToInt(), register_data_.size()); 12491cb0ef41Sopenharmony_ci return register_data_[reg.ToInt()] != nullptr; 12501cb0ef41Sopenharmony_ci} 12511cb0ef41Sopenharmony_ci 12521cb0ef41Sopenharmony_civoid RegisterState::EnsureRegisterData(RegisterIndex reg) { 12531cb0ef41Sopenharmony_ci if (!HasRegisterData(reg)) { 12541cb0ef41Sopenharmony_ci register_data_[reg.ToInt()] = zone()->New<RegisterState::Register>(); 12551cb0ef41Sopenharmony_ci } 12561cb0ef41Sopenharmony_ci} 12571cb0ef41Sopenharmony_ci 12581cb0ef41Sopenharmony_civoid RegisterState::ResetIfSpilledWhileShared(RegisterIndex reg) { 12591cb0ef41Sopenharmony_ci if (HasRegisterData(reg) && reg_data(reg).was_spilled_while_shared()) { 12601cb0ef41Sopenharmony_ci ResetDataFor(reg); 12611cb0ef41Sopenharmony_ci } 12621cb0ef41Sopenharmony_ci} 12631cb0ef41Sopenharmony_ci 12641cb0ef41Sopenharmony_civoid RegisterState::CommitAtMerge(RegisterIndex reg) { 12651cb0ef41Sopenharmony_ci DCHECK(IsAllocated(reg)); 12661cb0ef41Sopenharmony_ci reg_data(reg).CommitAtMerge(); 12671cb0ef41Sopenharmony_ci} 12681cb0ef41Sopenharmony_ci 12691cb0ef41Sopenharmony_civoid RegisterState::CopyFrom(RegisterIndex reg, RegisterState* source) { 12701cb0ef41Sopenharmony_ci register_data_[reg.ToInt()] = source->register_data_[reg.ToInt()]; 12711cb0ef41Sopenharmony_ci} 12721cb0ef41Sopenharmony_ci 12731cb0ef41Sopenharmony_cibool RegisterState::Equals(RegisterIndex reg, RegisterState* other) { 12741cb0ef41Sopenharmony_ci return register_data_[reg.ToInt()] == other->register_data_[reg.ToInt()]; 12751cb0ef41Sopenharmony_ci} 12761cb0ef41Sopenharmony_ci 12771cb0ef41Sopenharmony_civoid RegisterState::AddSharedUses(int shared_use_count) { 12781cb0ef41Sopenharmony_ci for (RegisterIndex reg : *this) { 12791cb0ef41Sopenharmony_ci if (HasRegisterData(reg)) { 12801cb0ef41Sopenharmony_ci reg_data(reg).AddSharedUses(shared_use_count); 12811cb0ef41Sopenharmony_ci } 12821cb0ef41Sopenharmony_ci } 12831cb0ef41Sopenharmony_ci} 12841cb0ef41Sopenharmony_ci 12851cb0ef41Sopenharmony_ciRegisterState* RegisterState::Clone() { 12861cb0ef41Sopenharmony_ci return zone_->New<RegisterState>(*this); 12871cb0ef41Sopenharmony_ci} 12881cb0ef41Sopenharmony_ci 12891cb0ef41Sopenharmony_ciclass RegisterBitVector { 12901cb0ef41Sopenharmony_ci public: 12911cb0ef41Sopenharmony_ci RegisterBitVector() : bits_(0) {} 12921cb0ef41Sopenharmony_ci 12931cb0ef41Sopenharmony_ci bool operator==(const RegisterBitVector& other) const { 12941cb0ef41Sopenharmony_ci return bits_ == other.bits_; 12951cb0ef41Sopenharmony_ci } 12961cb0ef41Sopenharmony_ci 12971cb0ef41Sopenharmony_ci bool Contains(RegisterIndex reg, MachineRepresentation rep) const { 12981cb0ef41Sopenharmony_ci return bits_ & reg.ToBit(rep); 12991cb0ef41Sopenharmony_ci } 13001cb0ef41Sopenharmony_ci 13011cb0ef41Sopenharmony_ci RegisterIndex GetFirstSet() const { 13021cb0ef41Sopenharmony_ci return RegisterIndex(base::bits::CountTrailingZeros(bits_)); 13031cb0ef41Sopenharmony_ci } 13041cb0ef41Sopenharmony_ci 13051cb0ef41Sopenharmony_ci RegisterIndex GetFirstCleared(int max_reg) const { 13061cb0ef41Sopenharmony_ci int reg_index = base::bits::CountTrailingZeros(~bits_); 13071cb0ef41Sopenharmony_ci if (reg_index < max_reg) { 13081cb0ef41Sopenharmony_ci return RegisterIndex(reg_index); 13091cb0ef41Sopenharmony_ci } else { 13101cb0ef41Sopenharmony_ci return RegisterIndex::Invalid(); 13111cb0ef41Sopenharmony_ci } 13121cb0ef41Sopenharmony_ci } 13131cb0ef41Sopenharmony_ci 13141cb0ef41Sopenharmony_ci void Add(RegisterIndex reg, MachineRepresentation rep) { 13151cb0ef41Sopenharmony_ci bits_ |= reg.ToBit(rep); 13161cb0ef41Sopenharmony_ci } 13171cb0ef41Sopenharmony_ci 13181cb0ef41Sopenharmony_ci void Clear(RegisterIndex reg, MachineRepresentation rep) { 13191cb0ef41Sopenharmony_ci bits_ &= ~reg.ToBit(rep); 13201cb0ef41Sopenharmony_ci } 13211cb0ef41Sopenharmony_ci 13221cb0ef41Sopenharmony_ci RegisterBitVector Union(const RegisterBitVector& other) { 13231cb0ef41Sopenharmony_ci return RegisterBitVector(bits_ | other.bits_); 13241cb0ef41Sopenharmony_ci } 13251cb0ef41Sopenharmony_ci 13261cb0ef41Sopenharmony_ci void Reset() { bits_ = 0; } 13271cb0ef41Sopenharmony_ci bool IsEmpty() const { return bits_ == 0; } 13281cb0ef41Sopenharmony_ci 13291cb0ef41Sopenharmony_ci private: 13301cb0ef41Sopenharmony_ci friend std::ostream& operator<<(std::ostream&, RegisterBitVector); 13311cb0ef41Sopenharmony_ci explicit RegisterBitVector(uintptr_t bits) : bits_(bits) {} 13321cb0ef41Sopenharmony_ci 13331cb0ef41Sopenharmony_ci static_assert(RegisterConfiguration::kMaxRegisters <= sizeof(uintptr_t) * 8, 13341cb0ef41Sopenharmony_ci "Maximum registers must fit in uintptr_t bitmap"); 13351cb0ef41Sopenharmony_ci uintptr_t bits_; 13361cb0ef41Sopenharmony_ci}; 13371cb0ef41Sopenharmony_ci 13381cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os, RegisterBitVector register_bits) { 13391cb0ef41Sopenharmony_ci return os << std::hex << register_bits.bits_ << std::dec; 13401cb0ef41Sopenharmony_ci} 13411cb0ef41Sopenharmony_ci 13421cb0ef41Sopenharmony_ci// A SinglePassRegisterAllocator is a fast register allocator that does a single 13431cb0ef41Sopenharmony_ci// pass through the instruction stream without performing any live-range 13441cb0ef41Sopenharmony_ci// analysis beforehand. It deals with a single RegisterKind, either general or 13451cb0ef41Sopenharmony_ci// double registers, with the MidTierRegisterAllocator choosing the correct 13461cb0ef41Sopenharmony_ci// SinglePassRegisterAllocator based on a values representation. 13471cb0ef41Sopenharmony_ciclass SinglePassRegisterAllocator final { 13481cb0ef41Sopenharmony_ci public: 13491cb0ef41Sopenharmony_ci SinglePassRegisterAllocator(RegisterKind kind, 13501cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data); 13511cb0ef41Sopenharmony_ci 13521cb0ef41Sopenharmony_ci // Convert to / from a register code and a register index. 13531cb0ef41Sopenharmony_ci RegisterIndex FromRegCode(int reg_code, MachineRepresentation rep) const; 13541cb0ef41Sopenharmony_ci int ToRegCode(RegisterIndex index, MachineRepresentation rep) const; 13551cb0ef41Sopenharmony_ci 13561cb0ef41Sopenharmony_ci // Allocation routines used to allocate a particular operand to either a 13571cb0ef41Sopenharmony_ci // register or a spill slot. 13581cb0ef41Sopenharmony_ci void AllocateConstantOutput(ConstantOperand* operand, 13591cb0ef41Sopenharmony_ci VirtualRegisterData& vreg, int instr_index); 13601cb0ef41Sopenharmony_ci void AllocateOutput(UnallocatedOperand* operand, VirtualRegisterData& vreg, 13611cb0ef41Sopenharmony_ci int instr_index); 13621cb0ef41Sopenharmony_ci void AllocateInput(UnallocatedOperand* operand, VirtualRegisterData& vreg, 13631cb0ef41Sopenharmony_ci int instr_index); 13641cb0ef41Sopenharmony_ci void AllocateSameInputOutput(UnallocatedOperand* output, 13651cb0ef41Sopenharmony_ci UnallocatedOperand* input, 13661cb0ef41Sopenharmony_ci VirtualRegisterData& output_vreg, 13671cb0ef41Sopenharmony_ci VirtualRegisterData& input_vreg, 13681cb0ef41Sopenharmony_ci int instr_index); 13691cb0ef41Sopenharmony_ci void AllocateGapMoveInput(UnallocatedOperand* operand, 13701cb0ef41Sopenharmony_ci VirtualRegisterData& vreg, int instr_index); 13711cb0ef41Sopenharmony_ci void AllocateTemp(UnallocatedOperand* operand, int virtual_register, 13721cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index); 13731cb0ef41Sopenharmony_ci void AllocatePhi(VirtualRegisterData& virtual_register, 13741cb0ef41Sopenharmony_ci const InstructionBlock* block); 13751cb0ef41Sopenharmony_ci void AllocatePhiGapMove(VirtualRegisterData& to_vreg, 13761cb0ef41Sopenharmony_ci VirtualRegisterData& from_vreg, int instr_index); 13771cb0ef41Sopenharmony_ci 13781cb0ef41Sopenharmony_ci // Reserve any fixed registers for the operands on an instruction before doing 13791cb0ef41Sopenharmony_ci // allocation on the operands. 13801cb0ef41Sopenharmony_ci void ReserveFixedInputRegister(const UnallocatedOperand* operand, 13811cb0ef41Sopenharmony_ci int virtual_register, 13821cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index); 13831cb0ef41Sopenharmony_ci void ReserveFixedTempRegister(const UnallocatedOperand* operand, 13841cb0ef41Sopenharmony_ci int virtual_register, MachineRepresentation rep, 13851cb0ef41Sopenharmony_ci int instr_index); 13861cb0ef41Sopenharmony_ci void ReserveFixedOutputRegister(const UnallocatedOperand* operand, 13871cb0ef41Sopenharmony_ci int virtual_register, 13881cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index); 13891cb0ef41Sopenharmony_ci 13901cb0ef41Sopenharmony_ci // Spills all registers that are currently holding data, for example, due to 13911cb0ef41Sopenharmony_ci // an instruction that clobbers all registers. 13921cb0ef41Sopenharmony_ci void SpillAllRegisters(); 13931cb0ef41Sopenharmony_ci 13941cb0ef41Sopenharmony_ci // Inform the allocator that we are starting / ending a block or ending 13951cb0ef41Sopenharmony_ci // allocation for the current instruction. 13961cb0ef41Sopenharmony_ci void StartBlock(const InstructionBlock* block); 13971cb0ef41Sopenharmony_ci void EndBlock(const InstructionBlock* block); 13981cb0ef41Sopenharmony_ci void EndInstruction(); 13991cb0ef41Sopenharmony_ci 14001cb0ef41Sopenharmony_ci void UpdateForDeferredBlock(int instr_index); 14011cb0ef41Sopenharmony_ci void AllocateDeferredBlockSpillOutput(int instr_index, 14021cb0ef41Sopenharmony_ci RpoNumber deferred_block, 14031cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register); 14041cb0ef41Sopenharmony_ci 14051cb0ef41Sopenharmony_ci RegisterKind kind() const { return kind_; } 14061cb0ef41Sopenharmony_ci BitVector* assigned_registers() const { return assigned_registers_; } 14071cb0ef41Sopenharmony_ci 14081cb0ef41Sopenharmony_ci private: 14091cb0ef41Sopenharmony_ci enum class UsePosition { 14101cb0ef41Sopenharmony_ci // Operand used at start of instruction. 14111cb0ef41Sopenharmony_ci kStart, 14121cb0ef41Sopenharmony_ci // Operand used at end of instruction. 14131cb0ef41Sopenharmony_ci kEnd, 14141cb0ef41Sopenharmony_ci // Operand is used at both the start and end of instruction. 14151cb0ef41Sopenharmony_ci kAll, 14161cb0ef41Sopenharmony_ci // Operand is not used in the instruction (used when initializing register 14171cb0ef41Sopenharmony_ci // state on block entry). 14181cb0ef41Sopenharmony_ci kNone, 14191cb0ef41Sopenharmony_ci }; 14201cb0ef41Sopenharmony_ci 14211cb0ef41Sopenharmony_ci // The allocator is initialized without any RegisterState by default to avoid 14221cb0ef41Sopenharmony_ci // having to allocate per-block allocator state for functions that don't 14231cb0ef41Sopenharmony_ci // allocate registers of a particular type. All allocation functions should 14241cb0ef41Sopenharmony_ci // call EnsureRegisterState to allocate a RegisterState if necessary. 14251cb0ef41Sopenharmony_ci void EnsureRegisterState(); 14261cb0ef41Sopenharmony_ci 14271cb0ef41Sopenharmony_ci // Clone the register state from |successor| into the current register state. 14281cb0ef41Sopenharmony_ci void CloneStateFrom(RpoNumber successor); 14291cb0ef41Sopenharmony_ci 14301cb0ef41Sopenharmony_ci // Merge the register state of |successors| into the current register state. 14311cb0ef41Sopenharmony_ci void MergeStateFrom(const InstructionBlock::Successors& successors); 14321cb0ef41Sopenharmony_ci 14331cb0ef41Sopenharmony_ci // Spill a register in a previously processed successor block when merging 14341cb0ef41Sopenharmony_ci // state into the current block. 14351cb0ef41Sopenharmony_ci void SpillRegisterAtMerge(RegisterState* reg_state, RegisterIndex reg, 14361cb0ef41Sopenharmony_ci MachineRepresentation rep); 14371cb0ef41Sopenharmony_ci 14381cb0ef41Sopenharmony_ci // Introduce a gap move to move |virtual_register| from reg |from| to reg |to| 14391cb0ef41Sopenharmony_ci // on entry to a |successor| block. 14401cb0ef41Sopenharmony_ci void MoveRegisterOnMerge(RegisterIndex from, RegisterIndex to, 14411cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register, 14421cb0ef41Sopenharmony_ci RpoNumber successor, RegisterState* succ_state); 14431cb0ef41Sopenharmony_ci 14441cb0ef41Sopenharmony_ci // Update the virtual register data with the data in register_state_. 14451cb0ef41Sopenharmony_ci void UpdateVirtualRegisterState(); 14461cb0ef41Sopenharmony_ci 14471cb0ef41Sopenharmony_ci // Returns true if |virtual_register| is defined after use position |pos| at 14481cb0ef41Sopenharmony_ci // |instr_index|. 14491cb0ef41Sopenharmony_ci bool DefinedAfter(int virtual_register, int instr_index, UsePosition pos); 14501cb0ef41Sopenharmony_ci 14511cb0ef41Sopenharmony_ci // Allocate |reg| to |virtual_register| for |operand| of the instruction at 14521cb0ef41Sopenharmony_ci // |instr_index|. The register will be reserved for this use for the specified 14531cb0ef41Sopenharmony_ci // |pos| use position. 14541cb0ef41Sopenharmony_ci void AllocateUse(RegisterIndex reg, VirtualRegisterData& virtual_register, 14551cb0ef41Sopenharmony_ci InstructionOperand* operand, int instr_index, 14561cb0ef41Sopenharmony_ci UsePosition pos); 14571cb0ef41Sopenharmony_ci 14581cb0ef41Sopenharmony_ci // Allocate |reg| to |virtual_register| as a pending use (i.e., only if the 14591cb0ef41Sopenharmony_ci // register is not subsequently spilled) for |operand| of the instruction at 14601cb0ef41Sopenharmony_ci // |instr_index|. 14611cb0ef41Sopenharmony_ci void AllocatePendingUse(RegisterIndex reg, 14621cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register, 14631cb0ef41Sopenharmony_ci InstructionOperand* operand, bool can_be_constant, 14641cb0ef41Sopenharmony_ci int instr_index); 14651cb0ef41Sopenharmony_ci 14661cb0ef41Sopenharmony_ci // Allocate |operand| to |reg| and add a gap move to move |virtual_register| 14671cb0ef41Sopenharmony_ci // to this register for the instruction at |instr_index|. |reg| will be 14681cb0ef41Sopenharmony_ci // reserved for this use for the specified |pos| use position. 14691cb0ef41Sopenharmony_ci void AllocateUseWithMove(RegisterIndex reg, 14701cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register, 14711cb0ef41Sopenharmony_ci UnallocatedOperand* operand, int instr_index, 14721cb0ef41Sopenharmony_ci UsePosition pos); 14731cb0ef41Sopenharmony_ci 14741cb0ef41Sopenharmony_ci void CommitRegister(RegisterIndex reg, int virtual_register, 14751cb0ef41Sopenharmony_ci MachineRepresentation rep, InstructionOperand* operand, 14761cb0ef41Sopenharmony_ci UsePosition pos); 14771cb0ef41Sopenharmony_ci void SpillRegister(RegisterIndex reg); 14781cb0ef41Sopenharmony_ci void SpillRegisterAndPotentialSimdSibling(RegisterIndex reg, 14791cb0ef41Sopenharmony_ci MachineRepresentation rep); 14801cb0ef41Sopenharmony_ci void SpillRegisterForVirtualRegister(int virtual_register); 14811cb0ef41Sopenharmony_ci 14821cb0ef41Sopenharmony_ci // Pre-emptively spill the register at the exit of deferred blocks such that 14831cb0ef41Sopenharmony_ci // uses of this register in non-deferred blocks don't need to be spilled. 14841cb0ef41Sopenharmony_ci void SpillRegisterForDeferred(RegisterIndex reg, int instr_index); 14851cb0ef41Sopenharmony_ci 14861cb0ef41Sopenharmony_ci // Returns an AllocatedOperand corresponding to the use of |reg| for 14871cb0ef41Sopenharmony_ci // |virtual_register|. 14881cb0ef41Sopenharmony_ci AllocatedOperand AllocatedOperandForReg(RegisterIndex reg, 14891cb0ef41Sopenharmony_ci MachineRepresentation rep); 14901cb0ef41Sopenharmony_ci 14911cb0ef41Sopenharmony_ci void ReserveFixedRegister(const UnallocatedOperand* operand, 14921cb0ef41Sopenharmony_ci int virtual_register, MachineRepresentation rep, 14931cb0ef41Sopenharmony_ci int instr_index, UsePosition pos); 14941cb0ef41Sopenharmony_ci RegisterIndex AllocateOutput(UnallocatedOperand* operand, 14951cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data, int instr_index, 14961cb0ef41Sopenharmony_ci UsePosition pos); 14971cb0ef41Sopenharmony_ci void EmitGapMoveFromOutput(InstructionOperand from, InstructionOperand to, 14981cb0ef41Sopenharmony_ci int instr_index); 14991cb0ef41Sopenharmony_ci 15001cb0ef41Sopenharmony_ci // Helper functions to choose the best register for a given operand. 15011cb0ef41Sopenharmony_ci V8_INLINE RegisterIndex 15021cb0ef41Sopenharmony_ci ChooseRegisterFor(VirtualRegisterData& virtual_register, int instr_index, 15031cb0ef41Sopenharmony_ci UsePosition pos, bool must_use_register); 15041cb0ef41Sopenharmony_ci V8_INLINE RegisterIndex ChooseRegisterFor(MachineRepresentation rep, 15051cb0ef41Sopenharmony_ci UsePosition pos, 15061cb0ef41Sopenharmony_ci bool must_use_register); 15071cb0ef41Sopenharmony_ci V8_INLINE RegisterIndex ChooseFreeRegister(MachineRepresentation rep, 15081cb0ef41Sopenharmony_ci UsePosition pos); 15091cb0ef41Sopenharmony_ci V8_INLINE RegisterIndex ChooseFreeRegister( 15101cb0ef41Sopenharmony_ci const RegisterBitVector& allocated_regs, MachineRepresentation rep); 15111cb0ef41Sopenharmony_ci V8_INLINE RegisterIndex ChooseRegisterToSpill(MachineRepresentation rep, 15121cb0ef41Sopenharmony_ci UsePosition pos); 15131cb0ef41Sopenharmony_ci 15141cb0ef41Sopenharmony_ci // Assign, free and mark use's of |reg| for a |virtual_register| at use 15151cb0ef41Sopenharmony_ci // position |pos|. 15161cb0ef41Sopenharmony_ci V8_INLINE void AssignRegister(RegisterIndex reg, int virtual_register, 15171cb0ef41Sopenharmony_ci MachineRepresentation rep, UsePosition pos); 15181cb0ef41Sopenharmony_ci V8_INLINE void FreeRegister(RegisterIndex reg, int virtual_register, 15191cb0ef41Sopenharmony_ci MachineRepresentation rep); 15201cb0ef41Sopenharmony_ci V8_INLINE void MarkRegisterUse(RegisterIndex reg, MachineRepresentation rep, 15211cb0ef41Sopenharmony_ci UsePosition pos); 15221cb0ef41Sopenharmony_ci V8_INLINE RegisterBitVector InUseBitmap(UsePosition pos); 15231cb0ef41Sopenharmony_ci V8_INLINE bool IsValidForRep(RegisterIndex reg, MachineRepresentation rep); 15241cb0ef41Sopenharmony_ci 15251cb0ef41Sopenharmony_ci // Return the register allocated to |virtual_register|, if any. 15261cb0ef41Sopenharmony_ci RegisterIndex RegisterForVirtualRegister(int virtual_register); 15271cb0ef41Sopenharmony_ci // Return the virtual register being held by |reg|, or kInvalidVirtualRegister 15281cb0ef41Sopenharmony_ci // if |reg| is unallocated. 15291cb0ef41Sopenharmony_ci int VirtualRegisterForRegister(RegisterIndex reg); 15301cb0ef41Sopenharmony_ci 15311cb0ef41Sopenharmony_ci // Returns true if |reg| is unallocated or holds |virtual_register|. 15321cb0ef41Sopenharmony_ci bool IsFreeOrSameVirtualRegister(RegisterIndex reg, int virtual_register); 15331cb0ef41Sopenharmony_ci // Returns true if |virtual_register| is unallocated or is allocated to |reg|. 15341cb0ef41Sopenharmony_ci bool VirtualRegisterIsUnallocatedOrInReg(int virtual_register, 15351cb0ef41Sopenharmony_ci RegisterIndex reg); 15361cb0ef41Sopenharmony_ci 15371cb0ef41Sopenharmony_ci // If {if kFPAliasing kind is COMBINE}, two FP registers alias one SIMD 15381cb0ef41Sopenharmony_ci // register. This returns the index of the higher aliasing FP register from 15391cb0ef41Sopenharmony_ci // the SIMD register index (which is the same as the lower register index). 15401cb0ef41Sopenharmony_ci RegisterIndex simdSibling(RegisterIndex reg) const { 15411cb0ef41Sopenharmony_ci CHECK_EQ(kFPAliasing, AliasingKind::kCombine); // Statically evaluated. 15421cb0ef41Sopenharmony_ci RegisterIndex sibling = RegisterIndex{reg.ToInt() + 1}; 15431cb0ef41Sopenharmony_ci#ifdef DEBUG 15441cb0ef41Sopenharmony_ci // Check that {reg} is indeed the lower SIMD half and {sibling} is the 15451cb0ef41Sopenharmony_ci // upper half. 15461cb0ef41Sopenharmony_ci int double_reg_base_code; 15471cb0ef41Sopenharmony_ci DCHECK_EQ(2, data_->config()->GetAliases( 15481cb0ef41Sopenharmony_ci MachineRepresentation::kSimd128, 15491cb0ef41Sopenharmony_ci ToRegCode(reg, MachineRepresentation::kSimd128), 15501cb0ef41Sopenharmony_ci MachineRepresentation::kFloat64, &double_reg_base_code)); 15511cb0ef41Sopenharmony_ci DCHECK_EQ(reg, FromRegCode(double_reg_base_code, 15521cb0ef41Sopenharmony_ci MachineRepresentation::kFloat64)); 15531cb0ef41Sopenharmony_ci DCHECK_EQ(sibling, FromRegCode(double_reg_base_code + 1, 15541cb0ef41Sopenharmony_ci MachineRepresentation::kFloat64)); 15551cb0ef41Sopenharmony_ci#endif // DEBUG 15561cb0ef41Sopenharmony_ci return sibling; 15571cb0ef41Sopenharmony_ci } 15581cb0ef41Sopenharmony_ci 15591cb0ef41Sopenharmony_ci // Returns a RegisterBitVector representing the allocated registers in 15601cb0ef41Sopenharmony_ci // reg_state. 15611cb0ef41Sopenharmony_ci RegisterBitVector GetAllocatedRegBitVector(RegisterState* reg_state); 15621cb0ef41Sopenharmony_ci 15631cb0ef41Sopenharmony_ci // Check the consistency of reg->vreg and vreg->reg mappings if a debug build. 15641cb0ef41Sopenharmony_ci void CheckConsistency(); 15651cb0ef41Sopenharmony_ci 15661cb0ef41Sopenharmony_ci VirtualRegisterData& VirtualRegisterDataFor(int virtual_register) const { 15671cb0ef41Sopenharmony_ci return data_->VirtualRegisterDataFor(virtual_register); 15681cb0ef41Sopenharmony_ci } 15691cb0ef41Sopenharmony_ci 15701cb0ef41Sopenharmony_ci // Virtual register to register mapping. 15711cb0ef41Sopenharmony_ci ZoneVector<RegisterIndex> virtual_register_to_reg_; 15721cb0ef41Sopenharmony_ci 15731cb0ef41Sopenharmony_ci // Current register state during allocation. 15741cb0ef41Sopenharmony_ci RegisterState* register_state_; 15751cb0ef41Sopenharmony_ci 15761cb0ef41Sopenharmony_ci // The current block being processed. 15771cb0ef41Sopenharmony_ci const InstructionBlock* current_block_; 15781cb0ef41Sopenharmony_ci 15791cb0ef41Sopenharmony_ci const RegisterKind kind_; 15801cb0ef41Sopenharmony_ci const int num_allocatable_registers_; 15811cb0ef41Sopenharmony_ci ZoneVector<RegisterIndex> reg_code_to_index_; 15821cb0ef41Sopenharmony_ci const int* index_to_reg_code_; 15831cb0ef41Sopenharmony_ci BitVector* assigned_registers_; 15841cb0ef41Sopenharmony_ci 15851cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data_; 15861cb0ef41Sopenharmony_ci 15871cb0ef41Sopenharmony_ci RegisterBitVector in_use_at_instr_start_bits_; 15881cb0ef41Sopenharmony_ci RegisterBitVector in_use_at_instr_end_bits_; 15891cb0ef41Sopenharmony_ci RegisterBitVector allocated_registers_bits_; 15901cb0ef41Sopenharmony_ci RegisterBitVector same_input_output_registers_bits_; 15911cb0ef41Sopenharmony_ci 15921cb0ef41Sopenharmony_ci // These fields are only used when kFPAliasing == COMBINE. 15931cb0ef41Sopenharmony_ci base::Optional<ZoneVector<RegisterIndex>> float32_reg_code_to_index_; 15941cb0ef41Sopenharmony_ci base::Optional<ZoneVector<int>> index_to_float32_reg_code_; 15951cb0ef41Sopenharmony_ci base::Optional<ZoneVector<RegisterIndex>> simd128_reg_code_to_index_; 15961cb0ef41Sopenharmony_ci base::Optional<ZoneVector<int>> index_to_simd128_reg_code_; 15971cb0ef41Sopenharmony_ci}; 15981cb0ef41Sopenharmony_ci 15991cb0ef41Sopenharmony_ciSinglePassRegisterAllocator::SinglePassRegisterAllocator( 16001cb0ef41Sopenharmony_ci RegisterKind kind, MidTierRegisterAllocationData* data) 16011cb0ef41Sopenharmony_ci : virtual_register_to_reg_(data->code()->VirtualRegisterCount(), 16021cb0ef41Sopenharmony_ci data->allocation_zone()), 16031cb0ef41Sopenharmony_ci register_state_(nullptr), 16041cb0ef41Sopenharmony_ci current_block_(nullptr), 16051cb0ef41Sopenharmony_ci kind_(kind), 16061cb0ef41Sopenharmony_ci num_allocatable_registers_( 16071cb0ef41Sopenharmony_ci GetAllocatableRegisterCount(data->config(), kind)), 16081cb0ef41Sopenharmony_ci reg_code_to_index_(GetRegisterCount(data->config(), kind), 16091cb0ef41Sopenharmony_ci data->allocation_zone()), 16101cb0ef41Sopenharmony_ci index_to_reg_code_(GetAllocatableRegisterCodes(data->config(), kind)), 16111cb0ef41Sopenharmony_ci assigned_registers_(data->code_zone()->New<BitVector>( 16121cb0ef41Sopenharmony_ci GetRegisterCount(data->config(), kind), data->code_zone())), 16131cb0ef41Sopenharmony_ci data_(data), 16141cb0ef41Sopenharmony_ci in_use_at_instr_start_bits_(), 16151cb0ef41Sopenharmony_ci in_use_at_instr_end_bits_(), 16161cb0ef41Sopenharmony_ci allocated_registers_bits_(), 16171cb0ef41Sopenharmony_ci same_input_output_registers_bits_() { 16181cb0ef41Sopenharmony_ci for (int i = 0; i < num_allocatable_registers_; i++) { 16191cb0ef41Sopenharmony_ci int reg_code = index_to_reg_code_[i]; 16201cb0ef41Sopenharmony_ci reg_code_to_index_[reg_code] = RegisterIndex(i); 16211cb0ef41Sopenharmony_ci } 16221cb0ef41Sopenharmony_ci 16231cb0ef41Sopenharmony_ci // If the architecture has COMBINE FP aliasing, initialize float and 16241cb0ef41Sopenharmony_ci // simd128 specific register details. 16251cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && kind == RegisterKind::kDouble) { 16261cb0ef41Sopenharmony_ci const RegisterConfiguration* config = data->config(); 16271cb0ef41Sopenharmony_ci 16281cb0ef41Sopenharmony_ci // Float registers. 16291cb0ef41Sopenharmony_ci float32_reg_code_to_index_.emplace(config->num_float_registers(), 16301cb0ef41Sopenharmony_ci data->allocation_zone()); 16311cb0ef41Sopenharmony_ci index_to_float32_reg_code_.emplace(num_allocatable_registers_, -1, 16321cb0ef41Sopenharmony_ci data->allocation_zone()); 16331cb0ef41Sopenharmony_ci for (int i = 0; i < config->num_allocatable_float_registers(); i++) { 16341cb0ef41Sopenharmony_ci int reg_code = config->allocatable_float_codes()[i]; 16351cb0ef41Sopenharmony_ci // Only add even float register codes to avoid overlapping multiple float 16361cb0ef41Sopenharmony_ci // registers on each RegisterIndex. 16371cb0ef41Sopenharmony_ci if (reg_code % 2 != 0) continue; 16381cb0ef41Sopenharmony_ci int double_reg_base_code; 16391cb0ef41Sopenharmony_ci CHECK_EQ(1, config->GetAliases(MachineRepresentation::kFloat32, reg_code, 16401cb0ef41Sopenharmony_ci MachineRepresentation::kFloat64, 16411cb0ef41Sopenharmony_ci &double_reg_base_code)); 16421cb0ef41Sopenharmony_ci RegisterIndex double_reg(reg_code_to_index_[double_reg_base_code]); 16431cb0ef41Sopenharmony_ci float32_reg_code_to_index_->at(reg_code) = double_reg; 16441cb0ef41Sopenharmony_ci index_to_float32_reg_code_->at(double_reg.ToInt()) = reg_code; 16451cb0ef41Sopenharmony_ci } 16461cb0ef41Sopenharmony_ci 16471cb0ef41Sopenharmony_ci // Simd128 registers. 16481cb0ef41Sopenharmony_ci simd128_reg_code_to_index_.emplace(config->num_simd128_registers(), 16491cb0ef41Sopenharmony_ci data->allocation_zone()); 16501cb0ef41Sopenharmony_ci index_to_simd128_reg_code_.emplace(num_allocatable_registers_, -1, 16511cb0ef41Sopenharmony_ci data->allocation_zone()); 16521cb0ef41Sopenharmony_ci for (int i = 0; i < config->num_allocatable_simd128_registers(); i++) { 16531cb0ef41Sopenharmony_ci int reg_code = config->allocatable_simd128_codes()[i]; 16541cb0ef41Sopenharmony_ci int double_reg_base_code; 16551cb0ef41Sopenharmony_ci CHECK_EQ(2, config->GetAliases(MachineRepresentation::kSimd128, reg_code, 16561cb0ef41Sopenharmony_ci MachineRepresentation::kFloat64, 16571cb0ef41Sopenharmony_ci &double_reg_base_code)); 16581cb0ef41Sopenharmony_ci RegisterIndex double_reg{reg_code_to_index_[double_reg_base_code]}; 16591cb0ef41Sopenharmony_ci // We later rely on the fact that the two aliasing double registers are at 16601cb0ef41Sopenharmony_ci // consecutive indexes. 16611cb0ef41Sopenharmony_ci DCHECK_EQ(double_reg.ToInt() + 1, 16621cb0ef41Sopenharmony_ci reg_code_to_index_[double_reg_base_code + 1].ToInt()); 16631cb0ef41Sopenharmony_ci simd128_reg_code_to_index_->at(reg_code) = double_reg; 16641cb0ef41Sopenharmony_ci index_to_simd128_reg_code_->at(double_reg.ToInt()) = reg_code; 16651cb0ef41Sopenharmony_ci } 16661cb0ef41Sopenharmony_ci } 16671cb0ef41Sopenharmony_ci} 16681cb0ef41Sopenharmony_ci 16691cb0ef41Sopenharmony_ciint SinglePassRegisterAllocator::VirtualRegisterForRegister(RegisterIndex reg) { 16701cb0ef41Sopenharmony_ci return register_state_->VirtualRegisterForRegister(reg); 16711cb0ef41Sopenharmony_ci} 16721cb0ef41Sopenharmony_ci 16731cb0ef41Sopenharmony_ciRegisterIndex SinglePassRegisterAllocator::RegisterForVirtualRegister( 16741cb0ef41Sopenharmony_ci int virtual_register) { 16751cb0ef41Sopenharmony_ci DCHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister); 16761cb0ef41Sopenharmony_ci return virtual_register_to_reg_[virtual_register]; 16771cb0ef41Sopenharmony_ci} 16781cb0ef41Sopenharmony_ci 16791cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::UpdateForDeferredBlock(int instr_index) { 16801cb0ef41Sopenharmony_ci if (!register_state_) return; 16811cb0ef41Sopenharmony_ci for (RegisterIndex reg : *register_state_) { 16821cb0ef41Sopenharmony_ci SpillRegisterForDeferred(reg, instr_index); 16831cb0ef41Sopenharmony_ci } 16841cb0ef41Sopenharmony_ci} 16851cb0ef41Sopenharmony_ci 16861cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::EndInstruction() { 16871cb0ef41Sopenharmony_ci in_use_at_instr_end_bits_.Reset(); 16881cb0ef41Sopenharmony_ci in_use_at_instr_start_bits_.Reset(); 16891cb0ef41Sopenharmony_ci same_input_output_registers_bits_.Reset(); 16901cb0ef41Sopenharmony_ci} 16911cb0ef41Sopenharmony_ci 16921cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::StartBlock(const InstructionBlock* block) { 16931cb0ef41Sopenharmony_ci DCHECK_NULL(register_state_); 16941cb0ef41Sopenharmony_ci DCHECK_NULL(current_block_); 16951cb0ef41Sopenharmony_ci DCHECK(in_use_at_instr_start_bits_.IsEmpty()); 16961cb0ef41Sopenharmony_ci DCHECK(in_use_at_instr_end_bits_.IsEmpty()); 16971cb0ef41Sopenharmony_ci DCHECK(allocated_registers_bits_.IsEmpty()); 16981cb0ef41Sopenharmony_ci DCHECK(same_input_output_registers_bits_.IsEmpty()); 16991cb0ef41Sopenharmony_ci 17001cb0ef41Sopenharmony_ci // Update the current block we are processing. 17011cb0ef41Sopenharmony_ci current_block_ = block; 17021cb0ef41Sopenharmony_ci 17031cb0ef41Sopenharmony_ci if (block->SuccessorCount() == 1) { 17041cb0ef41Sopenharmony_ci // If we have only a single successor, we can directly clone our state 17051cb0ef41Sopenharmony_ci // from that successor. 17061cb0ef41Sopenharmony_ci CloneStateFrom(block->successors()[0]); 17071cb0ef41Sopenharmony_ci } else if (block->SuccessorCount() > 1) { 17081cb0ef41Sopenharmony_ci // If we have multiple successors, merge the state from all the successors 17091cb0ef41Sopenharmony_ci // into our block. 17101cb0ef41Sopenharmony_ci MergeStateFrom(block->successors()); 17111cb0ef41Sopenharmony_ci } 17121cb0ef41Sopenharmony_ci} 17131cb0ef41Sopenharmony_ci 17141cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::EndBlock(const InstructionBlock* block) { 17151cb0ef41Sopenharmony_ci DCHECK(in_use_at_instr_start_bits_.IsEmpty()); 17161cb0ef41Sopenharmony_ci DCHECK(in_use_at_instr_end_bits_.IsEmpty()); 17171cb0ef41Sopenharmony_ci DCHECK(same_input_output_registers_bits_.IsEmpty()); 17181cb0ef41Sopenharmony_ci 17191cb0ef41Sopenharmony_ci // If we didn't allocate any registers of this kind, or we have reached the 17201cb0ef41Sopenharmony_ci // start, nothing to do here. 17211cb0ef41Sopenharmony_ci if (!register_state_ || block->PredecessorCount() == 0) { 17221cb0ef41Sopenharmony_ci current_block_ = nullptr; 17231cb0ef41Sopenharmony_ci return; 17241cb0ef41Sopenharmony_ci } 17251cb0ef41Sopenharmony_ci 17261cb0ef41Sopenharmony_ci if (block->PredecessorCount() > 1) { 17271cb0ef41Sopenharmony_ci register_state_->AddSharedUses(static_cast<int>(block->PredecessorCount()) - 17281cb0ef41Sopenharmony_ci 1); 17291cb0ef41Sopenharmony_ci } 17301cb0ef41Sopenharmony_ci 17311cb0ef41Sopenharmony_ci BlockState& block_state = data_->block_state(block->rpo_number()); 17321cb0ef41Sopenharmony_ci block_state.set_register_in_state(register_state_, kind()); 17331cb0ef41Sopenharmony_ci 17341cb0ef41Sopenharmony_ci // Remove virtual register to register mappings and clear register state. 17351cb0ef41Sopenharmony_ci // We will update the register state when starting the next block. 17361cb0ef41Sopenharmony_ci while (!allocated_registers_bits_.IsEmpty()) { 17371cb0ef41Sopenharmony_ci RegisterIndex reg = allocated_registers_bits_.GetFirstSet(); 17381cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 17391cb0ef41Sopenharmony_ci data_->VirtualRegisterDataFor(VirtualRegisterForRegister(reg)); 17401cb0ef41Sopenharmony_ci FreeRegister(reg, vreg_data.vreg(), vreg_data.rep()); 17411cb0ef41Sopenharmony_ci } 17421cb0ef41Sopenharmony_ci current_block_ = nullptr; 17431cb0ef41Sopenharmony_ci register_state_ = nullptr; 17441cb0ef41Sopenharmony_ci} 17451cb0ef41Sopenharmony_ci 17461cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::CloneStateFrom(RpoNumber successor) { 17471cb0ef41Sopenharmony_ci BlockState& block_state = data_->block_state(successor); 17481cb0ef41Sopenharmony_ci RegisterState* successor_registers = block_state.register_in_state(kind()); 17491cb0ef41Sopenharmony_ci if (successor_registers != nullptr) { 17501cb0ef41Sopenharmony_ci if (data_->GetBlock(successor)->PredecessorCount() == 1) { 17511cb0ef41Sopenharmony_ci // Avoids cloning for successors where we are the only predecessor. 17521cb0ef41Sopenharmony_ci register_state_ = successor_registers; 17531cb0ef41Sopenharmony_ci } else { 17541cb0ef41Sopenharmony_ci register_state_ = successor_registers->Clone(); 17551cb0ef41Sopenharmony_ci } 17561cb0ef41Sopenharmony_ci UpdateVirtualRegisterState(); 17571cb0ef41Sopenharmony_ci } 17581cb0ef41Sopenharmony_ci} 17591cb0ef41Sopenharmony_ci 17601cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::MergeStateFrom( 17611cb0ef41Sopenharmony_ci const InstructionBlock::Successors& successors) { 17621cb0ef41Sopenharmony_ci for (RpoNumber successor : successors) { 17631cb0ef41Sopenharmony_ci BlockState& block_state = data_->block_state(successor); 17641cb0ef41Sopenharmony_ci RegisterState* successor_registers = block_state.register_in_state(kind()); 17651cb0ef41Sopenharmony_ci if (successor_registers == nullptr) { 17661cb0ef41Sopenharmony_ci continue; 17671cb0ef41Sopenharmony_ci } 17681cb0ef41Sopenharmony_ci 17691cb0ef41Sopenharmony_ci if (register_state_ == nullptr) { 17701cb0ef41Sopenharmony_ci // If we haven't merged any register state yet, just use successor's 17711cb0ef41Sopenharmony_ci // register directly. 17721cb0ef41Sopenharmony_ci register_state_ = successor_registers; 17731cb0ef41Sopenharmony_ci UpdateVirtualRegisterState(); 17741cb0ef41Sopenharmony_ci } else { 17751cb0ef41Sopenharmony_ci // Otherwise try to merge our state with the existing state. 17761cb0ef41Sopenharmony_ci RegisterBitVector processed_regs; 17771cb0ef41Sopenharmony_ci RegisterBitVector succ_allocated_regs = 17781cb0ef41Sopenharmony_ci GetAllocatedRegBitVector(successor_registers); 17791cb0ef41Sopenharmony_ci for (RegisterIndex reg : *successor_registers) { 17801cb0ef41Sopenharmony_ci // If |reg| isn't allocated in successor registers, nothing to do. 17811cb0ef41Sopenharmony_ci if (!successor_registers->IsAllocated(reg)) continue; 17821cb0ef41Sopenharmony_ci 17831cb0ef41Sopenharmony_ci int virtual_register = 17841cb0ef41Sopenharmony_ci successor_registers->VirtualRegisterForRegister(reg); 17851cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 17861cb0ef41Sopenharmony_ci VirtualRegisterDataFor(virtual_register); 17871cb0ef41Sopenharmony_ci MachineRepresentation rep = vreg_data.rep(); 17881cb0ef41Sopenharmony_ci 17891cb0ef41Sopenharmony_ci // If we have already processed |reg|, e.g., adding gap move to that 17901cb0ef41Sopenharmony_ci // register, then we can continue. 17911cb0ef41Sopenharmony_ci if (processed_regs.Contains(reg, rep)) continue; 17921cb0ef41Sopenharmony_ci processed_regs.Add(reg, rep); 17931cb0ef41Sopenharmony_ci 17941cb0ef41Sopenharmony_ci bool reg_in_use = register_state_->IsAllocated(reg); 17951cb0ef41Sopenharmony_ci // For COMBINE FP aliasing, the register is also "in use" if the 17961cb0ef41Sopenharmony_ci // FP register for the upper half is allocated. 17971cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 17981cb0ef41Sopenharmony_ci rep == MachineRepresentation::kSimd128) { 17991cb0ef41Sopenharmony_ci reg_in_use |= register_state_->IsAllocated(simdSibling(reg)); 18001cb0ef41Sopenharmony_ci } 18011cb0ef41Sopenharmony_ci // Similarly (but the other way around), the register might be the upper 18021cb0ef41Sopenharmony_ci // half of a SIMD register that is allocated. 18031cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 18041cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kFloat64 || 18051cb0ef41Sopenharmony_ci rep == MachineRepresentation::kFloat32)) { 18061cb0ef41Sopenharmony_ci int simd_reg_code; 18071cb0ef41Sopenharmony_ci CHECK_EQ(1, data_->config()->GetAliases( 18081cb0ef41Sopenharmony_ci rep, ToRegCode(reg, rep), 18091cb0ef41Sopenharmony_ci MachineRepresentation::kSimd128, &simd_reg_code)); 18101cb0ef41Sopenharmony_ci // Sanity check: The SIMD reg code should be the shifted FP reg code. 18111cb0ef41Sopenharmony_ci DCHECK_EQ(simd_reg_code, 18121cb0ef41Sopenharmony_ci ToRegCode(reg, rep) >> 18131cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kFloat64 ? 1 : 2)); 18141cb0ef41Sopenharmony_ci RegisterIndex simd_reg = 18151cb0ef41Sopenharmony_ci FromRegCode(simd_reg_code, MachineRepresentation::kSimd128); 18161cb0ef41Sopenharmony_ci reg_in_use |= 18171cb0ef41Sopenharmony_ci simd_reg.is_valid() && register_state_->IsAllocated(simd_reg) && 18181cb0ef41Sopenharmony_ci VirtualRegisterDataFor(VirtualRegisterForRegister(simd_reg)) 18191cb0ef41Sopenharmony_ci .rep() == MachineRepresentation::kSimd128; 18201cb0ef41Sopenharmony_ci } 18211cb0ef41Sopenharmony_ci 18221cb0ef41Sopenharmony_ci if (!reg_in_use) { 18231cb0ef41Sopenharmony_ci DCHECK(successor_registers->IsAllocated(reg)); 18241cb0ef41Sopenharmony_ci if (RegisterForVirtualRegister(virtual_register).is_valid()) { 18251cb0ef41Sopenharmony_ci // If we already hold the virtual register in a different register 18261cb0ef41Sopenharmony_ci // then spill this register in the sucessor block to avoid 18271cb0ef41Sopenharmony_ci // invalidating the 1:1 vreg<->reg mapping. 18281cb0ef41Sopenharmony_ci // TODO(rmcilroy): Add a gap move to avoid spilling. 18291cb0ef41Sopenharmony_ci SpillRegisterAtMerge(successor_registers, reg, rep); 18301cb0ef41Sopenharmony_ci continue; 18311cb0ef41Sopenharmony_ci } 18321cb0ef41Sopenharmony_ci // Register is free in our current register state, so merge the 18331cb0ef41Sopenharmony_ci // successor block's register details into it. 18341cb0ef41Sopenharmony_ci register_state_->CopyFrom(reg, successor_registers); 18351cb0ef41Sopenharmony_ci AssignRegister(reg, virtual_register, rep, UsePosition::kNone); 18361cb0ef41Sopenharmony_ci continue; 18371cb0ef41Sopenharmony_ci } 18381cb0ef41Sopenharmony_ci 18391cb0ef41Sopenharmony_ci // Register is in use in the current register state. 18401cb0ef41Sopenharmony_ci if (successor_registers->Equals(reg, register_state_)) { 18411cb0ef41Sopenharmony_ci // Both match, keep the merged register data. 18421cb0ef41Sopenharmony_ci register_state_->CommitAtMerge(reg); 18431cb0ef41Sopenharmony_ci continue; 18441cb0ef41Sopenharmony_ci } 18451cb0ef41Sopenharmony_ci // Try to find a new register for this successor register in the 18461cb0ef41Sopenharmony_ci // merge block, and add a gap move on entry of the successor block. 18471cb0ef41Sopenharmony_ci RegisterIndex new_reg = RegisterForVirtualRegister(virtual_register); 18481cb0ef41Sopenharmony_ci if (!new_reg.is_valid()) { 18491cb0ef41Sopenharmony_ci new_reg = ChooseFreeRegister( 18501cb0ef41Sopenharmony_ci allocated_registers_bits_.Union(succ_allocated_regs), rep); 18511cb0ef41Sopenharmony_ci } else if (new_reg != reg) { 18521cb0ef41Sopenharmony_ci // Spill the |new_reg| in the successor block to be able to use it 18531cb0ef41Sopenharmony_ci // for this gap move. It would be spilled anyway since it contains 18541cb0ef41Sopenharmony_ci // a different virtual register than the merge block. 18551cb0ef41Sopenharmony_ci SpillRegisterAtMerge(successor_registers, new_reg, rep); 18561cb0ef41Sopenharmony_ci } 18571cb0ef41Sopenharmony_ci 18581cb0ef41Sopenharmony_ci if (new_reg.is_valid()) { 18591cb0ef41Sopenharmony_ci MoveRegisterOnMerge(new_reg, reg, vreg_data, successor, 18601cb0ef41Sopenharmony_ci successor_registers); 18611cb0ef41Sopenharmony_ci processed_regs.Add(new_reg, rep); 18621cb0ef41Sopenharmony_ci } else { 18631cb0ef41Sopenharmony_ci SpillRegisterAtMerge(successor_registers, reg, rep); 18641cb0ef41Sopenharmony_ci } 18651cb0ef41Sopenharmony_ci } 18661cb0ef41Sopenharmony_ci } 18671cb0ef41Sopenharmony_ci } 18681cb0ef41Sopenharmony_ci} 18691cb0ef41Sopenharmony_ci 18701cb0ef41Sopenharmony_ciRegisterBitVector SinglePassRegisterAllocator::GetAllocatedRegBitVector( 18711cb0ef41Sopenharmony_ci RegisterState* reg_state) { 18721cb0ef41Sopenharmony_ci RegisterBitVector allocated_regs; 18731cb0ef41Sopenharmony_ci for (RegisterIndex reg : *reg_state) { 18741cb0ef41Sopenharmony_ci if (reg_state->IsAllocated(reg)) { 18751cb0ef41Sopenharmony_ci VirtualRegisterData virtual_register = 18761cb0ef41Sopenharmony_ci VirtualRegisterDataFor(reg_state->VirtualRegisterForRegister(reg)); 18771cb0ef41Sopenharmony_ci allocated_regs.Add(reg, virtual_register.rep()); 18781cb0ef41Sopenharmony_ci } 18791cb0ef41Sopenharmony_ci } 18801cb0ef41Sopenharmony_ci return allocated_regs; 18811cb0ef41Sopenharmony_ci} 18821cb0ef41Sopenharmony_ci 18831cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::SpillRegisterAtMerge( 18841cb0ef41Sopenharmony_ci RegisterState* reg_state, RegisterIndex reg, MachineRepresentation rep) { 18851cb0ef41Sopenharmony_ci DCHECK_NE(reg_state, register_state_); 18861cb0ef41Sopenharmony_ci if (reg_state->IsAllocated(reg)) { 18871cb0ef41Sopenharmony_ci int virtual_register = reg_state->VirtualRegisterForRegister(reg); 18881cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 18891cb0ef41Sopenharmony_ci data_->VirtualRegisterDataFor(virtual_register); 18901cb0ef41Sopenharmony_ci AllocatedOperand allocated = AllocatedOperandForReg(reg, vreg_data.rep()); 18911cb0ef41Sopenharmony_ci reg_state->Spill(reg, allocated, current_block_, data_); 18921cb0ef41Sopenharmony_ci } 18931cb0ef41Sopenharmony_ci // Also spill the "simd sibling" register if we want to use {reg} for SIMD. 18941cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 18951cb0ef41Sopenharmony_ci rep == MachineRepresentation::kSimd128) { 18961cb0ef41Sopenharmony_ci RegisterIndex sibling = simdSibling(reg); 18971cb0ef41Sopenharmony_ci if (reg_state->IsAllocated(sibling)) { 18981cb0ef41Sopenharmony_ci int virtual_register = reg_state->VirtualRegisterForRegister(sibling); 18991cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 19001cb0ef41Sopenharmony_ci data_->VirtualRegisterDataFor(virtual_register); 19011cb0ef41Sopenharmony_ci AllocatedOperand allocated = 19021cb0ef41Sopenharmony_ci AllocatedOperandForReg(sibling, vreg_data.rep()); 19031cb0ef41Sopenharmony_ci reg_state->Spill(sibling, allocated, current_block_, data_); 19041cb0ef41Sopenharmony_ci } 19051cb0ef41Sopenharmony_ci } 19061cb0ef41Sopenharmony_ci // Similarly, spill the whole SIMD register if we want to use a part of it. 19071cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 19081cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kFloat64 || 19091cb0ef41Sopenharmony_ci rep == MachineRepresentation::kFloat32)) { 19101cb0ef41Sopenharmony_ci int simd_reg_code; 19111cb0ef41Sopenharmony_ci CHECK_EQ(1, data_->config()->GetAliases(rep, ToRegCode(reg, rep), 19121cb0ef41Sopenharmony_ci MachineRepresentation::kSimd128, 19131cb0ef41Sopenharmony_ci &simd_reg_code)); 19141cb0ef41Sopenharmony_ci // Sanity check: The SIMD register code should be the shifted {reg_code}. 19151cb0ef41Sopenharmony_ci DCHECK_EQ(simd_reg_code, 19161cb0ef41Sopenharmony_ci ToRegCode(reg, rep) >> 19171cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kFloat64 ? 1 : 2)); 19181cb0ef41Sopenharmony_ci RegisterIndex simd_reg = 19191cb0ef41Sopenharmony_ci FromRegCode(simd_reg_code, MachineRepresentation::kSimd128); 19201cb0ef41Sopenharmony_ci DCHECK(!simd_reg.is_valid() || simd_reg == reg || 19211cb0ef41Sopenharmony_ci simdSibling(simd_reg) == reg); 19221cb0ef41Sopenharmony_ci if (simd_reg.is_valid() && reg_state->IsAllocated(simd_reg)) { 19231cb0ef41Sopenharmony_ci int virtual_register = reg_state->VirtualRegisterForRegister(simd_reg); 19241cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 19251cb0ef41Sopenharmony_ci data_->VirtualRegisterDataFor(virtual_register); 19261cb0ef41Sopenharmony_ci if (vreg_data.rep() == MachineRepresentation::kSimd128) { 19271cb0ef41Sopenharmony_ci AllocatedOperand allocated = 19281cb0ef41Sopenharmony_ci AllocatedOperandForReg(simd_reg, vreg_data.rep()); 19291cb0ef41Sopenharmony_ci reg_state->Spill(simd_reg, allocated, current_block_, data_); 19301cb0ef41Sopenharmony_ci } 19311cb0ef41Sopenharmony_ci } 19321cb0ef41Sopenharmony_ci } 19331cb0ef41Sopenharmony_ci} 19341cb0ef41Sopenharmony_ci 19351cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::MoveRegisterOnMerge( 19361cb0ef41Sopenharmony_ci RegisterIndex from, RegisterIndex to, VirtualRegisterData& virtual_register, 19371cb0ef41Sopenharmony_ci RpoNumber successor, RegisterState* succ_state) { 19381cb0ef41Sopenharmony_ci int instr_index = data_->GetBlock(successor)->first_instruction_index(); 19391cb0ef41Sopenharmony_ci MoveOperands* move = 19401cb0ef41Sopenharmony_ci data_->AddPendingOperandGapMove(instr_index, Instruction::START); 19411cb0ef41Sopenharmony_ci succ_state->Commit(to, AllocatedOperandForReg(to, virtual_register.rep()), 19421cb0ef41Sopenharmony_ci &move->destination(), data_); 19431cb0ef41Sopenharmony_ci AllocatePendingUse(from, virtual_register, &move->source(), true, 19441cb0ef41Sopenharmony_ci instr_index); 19451cb0ef41Sopenharmony_ci} 19461cb0ef41Sopenharmony_ci 19471cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::UpdateVirtualRegisterState() { 19481cb0ef41Sopenharmony_ci // Update to the new register state and update vreg_to_register map and 19491cb0ef41Sopenharmony_ci // resetting any shared registers that were spilled by another block. 19501cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(register_state_); 19511cb0ef41Sopenharmony_ci for (RegisterIndex reg : *register_state_) { 19521cb0ef41Sopenharmony_ci register_state_->ResetIfSpilledWhileShared(reg); 19531cb0ef41Sopenharmony_ci int virtual_register = VirtualRegisterForRegister(reg); 19541cb0ef41Sopenharmony_ci if (virtual_register != InstructionOperand::kInvalidVirtualRegister) { 19551cb0ef41Sopenharmony_ci MachineRepresentation rep = 19561cb0ef41Sopenharmony_ci data_->VirtualRegisterDataFor(virtual_register).rep(); 19571cb0ef41Sopenharmony_ci AssignRegister(reg, virtual_register, rep, UsePosition::kNone); 19581cb0ef41Sopenharmony_ci } 19591cb0ef41Sopenharmony_ci } 19601cb0ef41Sopenharmony_ci CheckConsistency(); 19611cb0ef41Sopenharmony_ci} 19621cb0ef41Sopenharmony_ci 19631cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::CheckConsistency() { 19641cb0ef41Sopenharmony_ci#ifdef DEBUG 19651cb0ef41Sopenharmony_ci int virtual_register = -1; 19661cb0ef41Sopenharmony_ci for (RegisterIndex reg : virtual_register_to_reg_) { 19671cb0ef41Sopenharmony_ci ++virtual_register; 19681cb0ef41Sopenharmony_ci if (!reg.is_valid()) continue; 19691cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(register_state_); 19701cb0ef41Sopenharmony_ci // The register must be set to allocated. 19711cb0ef41Sopenharmony_ci DCHECK(register_state_->IsAllocated(reg)); 19721cb0ef41Sopenharmony_ci // reg <-> vreg linking is consistent. 19731cb0ef41Sopenharmony_ci DCHECK_EQ(virtual_register, VirtualRegisterForRegister(reg)); 19741cb0ef41Sopenharmony_ci } 19751cb0ef41Sopenharmony_ci DCHECK_EQ(data_->code()->VirtualRegisterCount() - 1, virtual_register); 19761cb0ef41Sopenharmony_ci 19771cb0ef41Sopenharmony_ci RegisterBitVector used_registers; 19781cb0ef41Sopenharmony_ci for (RegisterIndex reg : *register_state_) { 19791cb0ef41Sopenharmony_ci if (!register_state_->IsAllocated(reg)) continue; 19801cb0ef41Sopenharmony_ci int virtual_register = VirtualRegisterForRegister(reg); 19811cb0ef41Sopenharmony_ci // reg <-> vreg linking is consistent. 19821cb0ef41Sopenharmony_ci DCHECK_EQ(reg, RegisterForVirtualRegister(virtual_register)); 19831cb0ef41Sopenharmony_ci MachineRepresentation rep = VirtualRegisterDataFor(virtual_register).rep(); 19841cb0ef41Sopenharmony_ci // Allocated registers do not overlap. 19851cb0ef41Sopenharmony_ci DCHECK(!used_registers.Contains(reg, rep)); 19861cb0ef41Sopenharmony_ci used_registers.Add(reg, rep); 19871cb0ef41Sopenharmony_ci } 19881cb0ef41Sopenharmony_ci // The {allocated_registers_bits_} bitvector is accurate. 19891cb0ef41Sopenharmony_ci DCHECK_EQ(used_registers, allocated_registers_bits_); 19901cb0ef41Sopenharmony_ci#endif 19911cb0ef41Sopenharmony_ci} 19921cb0ef41Sopenharmony_ci 19931cb0ef41Sopenharmony_ciRegisterIndex SinglePassRegisterAllocator::FromRegCode( 19941cb0ef41Sopenharmony_ci int reg_code, MachineRepresentation rep) const { 19951cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 19961cb0ef41Sopenharmony_ci kind() == RegisterKind::kDouble) { 19971cb0ef41Sopenharmony_ci if (rep == MachineRepresentation::kFloat32) { 19981cb0ef41Sopenharmony_ci return RegisterIndex(float32_reg_code_to_index_->at(reg_code)); 19991cb0ef41Sopenharmony_ci } else if (rep == MachineRepresentation::kSimd128) { 20001cb0ef41Sopenharmony_ci return RegisterIndex(simd128_reg_code_to_index_->at(reg_code)); 20011cb0ef41Sopenharmony_ci } 20021cb0ef41Sopenharmony_ci DCHECK_EQ(rep, MachineRepresentation::kFloat64); 20031cb0ef41Sopenharmony_ci } 20041cb0ef41Sopenharmony_ci 20051cb0ef41Sopenharmony_ci return RegisterIndex(reg_code_to_index_[reg_code]); 20061cb0ef41Sopenharmony_ci} 20071cb0ef41Sopenharmony_ci 20081cb0ef41Sopenharmony_ciint SinglePassRegisterAllocator::ToRegCode(RegisterIndex reg, 20091cb0ef41Sopenharmony_ci MachineRepresentation rep) const { 20101cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 20111cb0ef41Sopenharmony_ci kind() == RegisterKind::kDouble) { 20121cb0ef41Sopenharmony_ci if (rep == MachineRepresentation::kFloat32) { 20131cb0ef41Sopenharmony_ci DCHECK_NE(-1, index_to_float32_reg_code_->at(reg.ToInt())); 20141cb0ef41Sopenharmony_ci return index_to_float32_reg_code_->at(reg.ToInt()); 20151cb0ef41Sopenharmony_ci } else if (rep == MachineRepresentation::kSimd128) { 20161cb0ef41Sopenharmony_ci DCHECK_NE(-1, index_to_simd128_reg_code_->at(reg.ToInt())); 20171cb0ef41Sopenharmony_ci return index_to_simd128_reg_code_->at(reg.ToInt()); 20181cb0ef41Sopenharmony_ci } 20191cb0ef41Sopenharmony_ci DCHECK_EQ(rep, MachineRepresentation::kFloat64); 20201cb0ef41Sopenharmony_ci } 20211cb0ef41Sopenharmony_ci return index_to_reg_code_[reg.ToInt()]; 20221cb0ef41Sopenharmony_ci} 20231cb0ef41Sopenharmony_ci 20241cb0ef41Sopenharmony_cibool SinglePassRegisterAllocator::VirtualRegisterIsUnallocatedOrInReg( 20251cb0ef41Sopenharmony_ci int virtual_register, RegisterIndex reg) { 20261cb0ef41Sopenharmony_ci RegisterIndex existing_reg = RegisterForVirtualRegister(virtual_register); 20271cb0ef41Sopenharmony_ci return !existing_reg.is_valid() || existing_reg == reg; 20281cb0ef41Sopenharmony_ci} 20291cb0ef41Sopenharmony_ci 20301cb0ef41Sopenharmony_cibool SinglePassRegisterAllocator::IsFreeOrSameVirtualRegister( 20311cb0ef41Sopenharmony_ci RegisterIndex reg, int virtual_register) { 20321cb0ef41Sopenharmony_ci int allocated_vreg = VirtualRegisterForRegister(reg); 20331cb0ef41Sopenharmony_ci return allocated_vreg == InstructionOperand::kInvalidVirtualRegister || 20341cb0ef41Sopenharmony_ci allocated_vreg == virtual_register; 20351cb0ef41Sopenharmony_ci} 20361cb0ef41Sopenharmony_ci 20371cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::EmitGapMoveFromOutput(InstructionOperand from, 20381cb0ef41Sopenharmony_ci InstructionOperand to, 20391cb0ef41Sopenharmony_ci int instr_index) { 20401cb0ef41Sopenharmony_ci DCHECK(from.IsAllocated()); 20411cb0ef41Sopenharmony_ci DCHECK(to.IsAllocated()); 20421cb0ef41Sopenharmony_ci const InstructionBlock* block = current_block_; 20431cb0ef41Sopenharmony_ci DCHECK_EQ(data_->GetBlock(instr_index), block); 20441cb0ef41Sopenharmony_ci if (instr_index == block->last_instruction_index()) { 20451cb0ef41Sopenharmony_ci // Add gap move to the first instruction of every successor block. 20461cb0ef41Sopenharmony_ci for (const RpoNumber& succ : block->successors()) { 20471cb0ef41Sopenharmony_ci const InstructionBlock* successor = data_->GetBlock(succ); 20481cb0ef41Sopenharmony_ci DCHECK_EQ(1, successor->PredecessorCount()); 20491cb0ef41Sopenharmony_ci data_->AddGapMove(successor->first_instruction_index(), 20501cb0ef41Sopenharmony_ci Instruction::START, from, to); 20511cb0ef41Sopenharmony_ci } 20521cb0ef41Sopenharmony_ci } else { 20531cb0ef41Sopenharmony_ci data_->AddGapMove(instr_index + 1, Instruction::START, from, to); 20541cb0ef41Sopenharmony_ci } 20551cb0ef41Sopenharmony_ci} 20561cb0ef41Sopenharmony_ci 20571cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AssignRegister(RegisterIndex reg, 20581cb0ef41Sopenharmony_ci int virtual_register, 20591cb0ef41Sopenharmony_ci MachineRepresentation rep, 20601cb0ef41Sopenharmony_ci UsePosition pos) { 20611cb0ef41Sopenharmony_ci assigned_registers()->Add(ToRegCode(reg, rep)); 20621cb0ef41Sopenharmony_ci allocated_registers_bits_.Add(reg, rep); 20631cb0ef41Sopenharmony_ci MarkRegisterUse(reg, rep, pos); 20641cb0ef41Sopenharmony_ci if (virtual_register != InstructionOperand::kInvalidVirtualRegister) { 20651cb0ef41Sopenharmony_ci virtual_register_to_reg_[virtual_register] = reg; 20661cb0ef41Sopenharmony_ci } 20671cb0ef41Sopenharmony_ci} 20681cb0ef41Sopenharmony_ci 20691cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::MarkRegisterUse(RegisterIndex reg, 20701cb0ef41Sopenharmony_ci MachineRepresentation rep, 20711cb0ef41Sopenharmony_ci UsePosition pos) { 20721cb0ef41Sopenharmony_ci if (pos == UsePosition::kStart || pos == UsePosition::kAll) { 20731cb0ef41Sopenharmony_ci in_use_at_instr_start_bits_.Add(reg, rep); 20741cb0ef41Sopenharmony_ci } 20751cb0ef41Sopenharmony_ci if (pos == UsePosition::kEnd || pos == UsePosition::kAll) { 20761cb0ef41Sopenharmony_ci in_use_at_instr_end_bits_.Add(reg, rep); 20771cb0ef41Sopenharmony_ci } 20781cb0ef41Sopenharmony_ci} 20791cb0ef41Sopenharmony_ci 20801cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::FreeRegister(RegisterIndex reg, 20811cb0ef41Sopenharmony_ci int virtual_register, 20821cb0ef41Sopenharmony_ci MachineRepresentation rep) { 20831cb0ef41Sopenharmony_ci allocated_registers_bits_.Clear(reg, rep); 20841cb0ef41Sopenharmony_ci if (virtual_register != InstructionOperand::kInvalidVirtualRegister) { 20851cb0ef41Sopenharmony_ci virtual_register_to_reg_[virtual_register] = RegisterIndex::Invalid(); 20861cb0ef41Sopenharmony_ci } 20871cb0ef41Sopenharmony_ci} 20881cb0ef41Sopenharmony_ci 20891cb0ef41Sopenharmony_ciRegisterIndex SinglePassRegisterAllocator::ChooseRegisterFor( 20901cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register, int instr_index, UsePosition pos, 20911cb0ef41Sopenharmony_ci bool must_use_register) { 20921cb0ef41Sopenharmony_ci DCHECK_NE(pos, UsePosition::kNone); 20931cb0ef41Sopenharmony_ci MachineRepresentation rep = virtual_register.rep(); 20941cb0ef41Sopenharmony_ci 20951cb0ef41Sopenharmony_ci // If register is already allocated to the virtual register, use that. 20961cb0ef41Sopenharmony_ci RegisterIndex reg = RegisterForVirtualRegister(virtual_register.vreg()); 20971cb0ef41Sopenharmony_ci 20981cb0ef41Sopenharmony_ci // If we don't need a register, only try to allocate one if the virtual 20991cb0ef41Sopenharmony_ci // register hasn't yet been spilled, to try to avoid spilling it. 21001cb0ef41Sopenharmony_ci if (!reg.is_valid() && (must_use_register || 21011cb0ef41Sopenharmony_ci !virtual_register.IsSpilledAt(instr_index, data_))) { 21021cb0ef41Sopenharmony_ci reg = ChooseRegisterFor(rep, pos, must_use_register); 21031cb0ef41Sopenharmony_ci } else if (reg.is_valid() && 21041cb0ef41Sopenharmony_ci same_input_output_registers_bits_.Contains(reg, rep) && 21051cb0ef41Sopenharmony_ci pos != UsePosition::kStart) { 21061cb0ef41Sopenharmony_ci // If we are trying to allocate a register that was used as a 21071cb0ef41Sopenharmony_ci // same_input_output operand, then we can't use it for an input that expands 21081cb0ef41Sopenharmony_ci // past UsePosition::kStart. 21091cb0ef41Sopenharmony_ci if (must_use_register) { 21101cb0ef41Sopenharmony_ci // Use a new register instead. 21111cb0ef41Sopenharmony_ci reg = ChooseRegisterFor(rep, pos, must_use_register); 21121cb0ef41Sopenharmony_ci } else { 21131cb0ef41Sopenharmony_ci // Use a spill slot. 21141cb0ef41Sopenharmony_ci reg = RegisterIndex::Invalid(); 21151cb0ef41Sopenharmony_ci } 21161cb0ef41Sopenharmony_ci } 21171cb0ef41Sopenharmony_ci return reg; 21181cb0ef41Sopenharmony_ci} 21191cb0ef41Sopenharmony_ci 21201cb0ef41Sopenharmony_ciRegisterIndex SinglePassRegisterAllocator::ChooseRegisterFor( 21211cb0ef41Sopenharmony_ci MachineRepresentation rep, UsePosition pos, bool must_use_register) { 21221cb0ef41Sopenharmony_ci DCHECK_NE(pos, UsePosition::kNone); 21231cb0ef41Sopenharmony_ci RegisterIndex reg = ChooseFreeRegister(rep, pos); 21241cb0ef41Sopenharmony_ci if (!reg.is_valid() && must_use_register) { 21251cb0ef41Sopenharmony_ci reg = ChooseRegisterToSpill(rep, pos); 21261cb0ef41Sopenharmony_ci SpillRegisterAndPotentialSimdSibling(reg, rep); 21271cb0ef41Sopenharmony_ci } 21281cb0ef41Sopenharmony_ci return reg; 21291cb0ef41Sopenharmony_ci} 21301cb0ef41Sopenharmony_ci 21311cb0ef41Sopenharmony_ciRegisterBitVector SinglePassRegisterAllocator::InUseBitmap(UsePosition pos) { 21321cb0ef41Sopenharmony_ci switch (pos) { 21331cb0ef41Sopenharmony_ci case UsePosition::kStart: 21341cb0ef41Sopenharmony_ci return in_use_at_instr_start_bits_; 21351cb0ef41Sopenharmony_ci case UsePosition::kEnd: 21361cb0ef41Sopenharmony_ci return in_use_at_instr_end_bits_; 21371cb0ef41Sopenharmony_ci case UsePosition::kAll: 21381cb0ef41Sopenharmony_ci return in_use_at_instr_start_bits_.Union(in_use_at_instr_end_bits_); 21391cb0ef41Sopenharmony_ci case UsePosition::kNone: 21401cb0ef41Sopenharmony_ci UNREACHABLE(); 21411cb0ef41Sopenharmony_ci } 21421cb0ef41Sopenharmony_ci} 21431cb0ef41Sopenharmony_ci 21441cb0ef41Sopenharmony_cibool SinglePassRegisterAllocator::IsValidForRep(RegisterIndex reg, 21451cb0ef41Sopenharmony_ci MachineRepresentation rep) { 21461cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || 21471cb0ef41Sopenharmony_ci kind() == RegisterKind::kGeneral) { 21481cb0ef41Sopenharmony_ci return true; 21491cb0ef41Sopenharmony_ci } else { 21501cb0ef41Sopenharmony_ci switch (rep) { 21511cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 21521cb0ef41Sopenharmony_ci return index_to_float32_reg_code_->at(reg.ToInt()) != -1; 21531cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat64: 21541cb0ef41Sopenharmony_ci return true; 21551cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: 21561cb0ef41Sopenharmony_ci return index_to_simd128_reg_code_->at(reg.ToInt()) != -1; 21571cb0ef41Sopenharmony_ci default: 21581cb0ef41Sopenharmony_ci UNREACHABLE(); 21591cb0ef41Sopenharmony_ci } 21601cb0ef41Sopenharmony_ci } 21611cb0ef41Sopenharmony_ci} 21621cb0ef41Sopenharmony_ci 21631cb0ef41Sopenharmony_ciRegisterIndex SinglePassRegisterAllocator::ChooseFreeRegister( 21641cb0ef41Sopenharmony_ci MachineRepresentation rep, UsePosition pos) { 21651cb0ef41Sopenharmony_ci // Take the first free, non-blocked register, if available. 21661cb0ef41Sopenharmony_ci // TODO(rmcilroy): Consider a better heuristic. 21671cb0ef41Sopenharmony_ci RegisterBitVector allocated_or_in_use = 21681cb0ef41Sopenharmony_ci InUseBitmap(pos).Union(allocated_registers_bits_); 21691cb0ef41Sopenharmony_ci return ChooseFreeRegister(allocated_or_in_use, rep); 21701cb0ef41Sopenharmony_ci} 21711cb0ef41Sopenharmony_ci 21721cb0ef41Sopenharmony_ciRegisterIndex SinglePassRegisterAllocator::ChooseFreeRegister( 21731cb0ef41Sopenharmony_ci const RegisterBitVector& allocated_regs, MachineRepresentation rep) { 21741cb0ef41Sopenharmony_ci RegisterIndex chosen_reg = RegisterIndex::Invalid(); 21751cb0ef41Sopenharmony_ci if (kFPAliasing != AliasingKind::kCombine || 21761cb0ef41Sopenharmony_ci kind() == RegisterKind::kGeneral) { 21771cb0ef41Sopenharmony_ci chosen_reg = allocated_regs.GetFirstCleared(num_allocatable_registers_); 21781cb0ef41Sopenharmony_ci } else { 21791cb0ef41Sopenharmony_ci // If we don't have simple fp aliasing, we need to check each register 21801cb0ef41Sopenharmony_ci // individually to get one with the required representation. 21811cb0ef41Sopenharmony_ci for (RegisterIndex reg : *register_state_) { 21821cb0ef41Sopenharmony_ci if (IsValidForRep(reg, rep) && !allocated_regs.Contains(reg, rep)) { 21831cb0ef41Sopenharmony_ci chosen_reg = reg; 21841cb0ef41Sopenharmony_ci break; 21851cb0ef41Sopenharmony_ci } 21861cb0ef41Sopenharmony_ci } 21871cb0ef41Sopenharmony_ci } 21881cb0ef41Sopenharmony_ci 21891cb0ef41Sopenharmony_ci DCHECK_IMPLIES(chosen_reg.is_valid(), IsValidForRep(chosen_reg, rep)); 21901cb0ef41Sopenharmony_ci return chosen_reg; 21911cb0ef41Sopenharmony_ci} 21921cb0ef41Sopenharmony_ci 21931cb0ef41Sopenharmony_ciRegisterIndex SinglePassRegisterAllocator::ChooseRegisterToSpill( 21941cb0ef41Sopenharmony_ci MachineRepresentation rep, UsePosition pos) { 21951cb0ef41Sopenharmony_ci RegisterBitVector in_use = InUseBitmap(pos); 21961cb0ef41Sopenharmony_ci 21971cb0ef41Sopenharmony_ci // Choose a register that will need to be spilled. Preferentially choose: 21981cb0ef41Sopenharmony_ci // - A register with only pending uses, to avoid having to add a gap move for 21991cb0ef41Sopenharmony_ci // a non-pending use. 22001cb0ef41Sopenharmony_ci // - A register holding a virtual register that has already been spilled, to 22011cb0ef41Sopenharmony_ci // avoid adding a new gap move to spill the virtual register when it is 22021cb0ef41Sopenharmony_ci // output. 22031cb0ef41Sopenharmony_ci // - Prefer the register holding the virtual register with the earliest 22041cb0ef41Sopenharmony_ci // definition point, since it is more likely to be spilled anyway. 22051cb0ef41Sopenharmony_ci RegisterIndex chosen_reg; 22061cb0ef41Sopenharmony_ci int earliest_definition = kMaxInt; 22071cb0ef41Sopenharmony_ci bool pending_only_use = false; 22081cb0ef41Sopenharmony_ci bool already_spilled = false; 22091cb0ef41Sopenharmony_ci for (RegisterIndex reg : *register_state_) { 22101cb0ef41Sopenharmony_ci // Skip if register is in use, or not valid for representation. 22111cb0ef41Sopenharmony_ci if (!IsValidForRep(reg, rep) || in_use.Contains(reg, rep)) continue; 22121cb0ef41Sopenharmony_ci // With non-simple FP aliasing, a SIMD register might block more than one FP 22131cb0ef41Sopenharmony_ci // register. 22141cb0ef41Sopenharmony_ci DCHECK_IMPLIES(kFPAliasing != AliasingKind::kCombine, 22151cb0ef41Sopenharmony_ci register_state_->IsAllocated(reg)); 22161cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 22171cb0ef41Sopenharmony_ci !register_state_->IsAllocated(reg)) 22181cb0ef41Sopenharmony_ci continue; 22191cb0ef41Sopenharmony_ci 22201cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 22211cb0ef41Sopenharmony_ci VirtualRegisterDataFor(VirtualRegisterForRegister(reg)); 22221cb0ef41Sopenharmony_ci if ((!pending_only_use && register_state_->HasPendingUsesOnly(reg)) || 22231cb0ef41Sopenharmony_ci (!already_spilled && vreg_data.HasSpillOperand()) || 22241cb0ef41Sopenharmony_ci vreg_data.output_instr_index() < earliest_definition) { 22251cb0ef41Sopenharmony_ci chosen_reg = reg; 22261cb0ef41Sopenharmony_ci earliest_definition = vreg_data.output_instr_index(); 22271cb0ef41Sopenharmony_ci pending_only_use = register_state_->HasPendingUsesOnly(reg); 22281cb0ef41Sopenharmony_ci already_spilled = vreg_data.HasSpillOperand(); 22291cb0ef41Sopenharmony_ci } 22301cb0ef41Sopenharmony_ci } 22311cb0ef41Sopenharmony_ci 22321cb0ef41Sopenharmony_ci // There should always be an unblocked register available. 22331cb0ef41Sopenharmony_ci DCHECK(chosen_reg.is_valid()); 22341cb0ef41Sopenharmony_ci DCHECK(IsValidForRep(chosen_reg, rep)); 22351cb0ef41Sopenharmony_ci return chosen_reg; 22361cb0ef41Sopenharmony_ci} 22371cb0ef41Sopenharmony_ci 22381cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::CommitRegister(RegisterIndex reg, 22391cb0ef41Sopenharmony_ci int virtual_register, 22401cb0ef41Sopenharmony_ci MachineRepresentation rep, 22411cb0ef41Sopenharmony_ci InstructionOperand* operand, 22421cb0ef41Sopenharmony_ci UsePosition pos) { 22431cb0ef41Sopenharmony_ci // Committing the output operation, and mark the register use in this 22441cb0ef41Sopenharmony_ci // instruction, then mark it as free going forward. 22451cb0ef41Sopenharmony_ci AllocatedOperand allocated = AllocatedOperandForReg(reg, rep); 22461cb0ef41Sopenharmony_ci register_state_->Commit(reg, allocated, operand, data_); 22471cb0ef41Sopenharmony_ci MarkRegisterUse(reg, rep, pos); 22481cb0ef41Sopenharmony_ci FreeRegister(reg, virtual_register, rep); 22491cb0ef41Sopenharmony_ci CheckConsistency(); 22501cb0ef41Sopenharmony_ci} 22511cb0ef41Sopenharmony_ci 22521cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::SpillRegister(RegisterIndex reg) { 22531cb0ef41Sopenharmony_ci if (!register_state_->IsAllocated(reg)) return; 22541cb0ef41Sopenharmony_ci 22551cb0ef41Sopenharmony_ci // Spill the register and free register. 22561cb0ef41Sopenharmony_ci int virtual_register = VirtualRegisterForRegister(reg); 22571cb0ef41Sopenharmony_ci MachineRepresentation rep = VirtualRegisterDataFor(virtual_register).rep(); 22581cb0ef41Sopenharmony_ci AllocatedOperand allocated = AllocatedOperandForReg(reg, rep); 22591cb0ef41Sopenharmony_ci register_state_->Spill(reg, allocated, current_block_, data_); 22601cb0ef41Sopenharmony_ci FreeRegister(reg, virtual_register, rep); 22611cb0ef41Sopenharmony_ci} 22621cb0ef41Sopenharmony_ci 22631cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::SpillRegisterAndPotentialSimdSibling( 22641cb0ef41Sopenharmony_ci RegisterIndex reg, MachineRepresentation rep) { 22651cb0ef41Sopenharmony_ci SpillRegister(reg); 22661cb0ef41Sopenharmony_ci 22671cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 22681cb0ef41Sopenharmony_ci rep == MachineRepresentation::kSimd128) { 22691cb0ef41Sopenharmony_ci SpillRegister(simdSibling(reg)); 22701cb0ef41Sopenharmony_ci } 22711cb0ef41Sopenharmony_ci} 22721cb0ef41Sopenharmony_ci 22731cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::SpillAllRegisters() { 22741cb0ef41Sopenharmony_ci if (!register_state_) return; 22751cb0ef41Sopenharmony_ci 22761cb0ef41Sopenharmony_ci for (RegisterIndex reg : *register_state_) { 22771cb0ef41Sopenharmony_ci SpillRegister(reg); 22781cb0ef41Sopenharmony_ci } 22791cb0ef41Sopenharmony_ci} 22801cb0ef41Sopenharmony_ci 22811cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::SpillRegisterForVirtualRegister( 22821cb0ef41Sopenharmony_ci int virtual_register) { 22831cb0ef41Sopenharmony_ci DCHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister); 22841cb0ef41Sopenharmony_ci RegisterIndex reg = RegisterForVirtualRegister(virtual_register); 22851cb0ef41Sopenharmony_ci if (reg.is_valid()) { 22861cb0ef41Sopenharmony_ci SpillRegister(reg); 22871cb0ef41Sopenharmony_ci } 22881cb0ef41Sopenharmony_ci} 22891cb0ef41Sopenharmony_ci 22901cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::SpillRegisterForDeferred(RegisterIndex reg, 22911cb0ef41Sopenharmony_ci int instr_index) { 22921cb0ef41Sopenharmony_ci // Committing the output operation, and mark the register use in this 22931cb0ef41Sopenharmony_ci // instruction, then mark it as free going forward. 22941cb0ef41Sopenharmony_ci if (register_state_->IsAllocated(reg) && register_state_->IsShared(reg)) { 22951cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register = 22961cb0ef41Sopenharmony_ci data_->VirtualRegisterDataFor(VirtualRegisterForRegister(reg)); 22971cb0ef41Sopenharmony_ci AllocatedOperand allocated = 22981cb0ef41Sopenharmony_ci AllocatedOperandForReg(reg, virtual_register.rep()); 22991cb0ef41Sopenharmony_ci register_state_->SpillForDeferred(reg, allocated, instr_index, data_); 23001cb0ef41Sopenharmony_ci FreeRegister(reg, virtual_register.vreg(), virtual_register.rep()); 23011cb0ef41Sopenharmony_ci } 23021cb0ef41Sopenharmony_ci CheckConsistency(); 23031cb0ef41Sopenharmony_ci} 23041cb0ef41Sopenharmony_ci 23051cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateDeferredBlockSpillOutput( 23061cb0ef41Sopenharmony_ci int instr_index, RpoNumber deferred_block, 23071cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register) { 23081cb0ef41Sopenharmony_ci DCHECK(data_->GetBlock(deferred_block)->IsDeferred()); 23091cb0ef41Sopenharmony_ci DCHECK(virtual_register.HasSpillRange()); 23101cb0ef41Sopenharmony_ci if (!virtual_register.NeedsSpillAtOutput() && 23111cb0ef41Sopenharmony_ci !DefinedAfter(virtual_register.vreg(), instr_index, UsePosition::kEnd)) { 23121cb0ef41Sopenharmony_ci // If a register has been assigned to the virtual register, and the virtual 23131cb0ef41Sopenharmony_ci // register still doesn't need to be spilled at it's output, and add a 23141cb0ef41Sopenharmony_ci // pending move to output the virtual register to it's spill slot on entry 23151cb0ef41Sopenharmony_ci // of the deferred block (to avoid spilling on in non-deferred code). 23161cb0ef41Sopenharmony_ci // TODO(rmcilroy): Consider assigning a register even if the virtual 23171cb0ef41Sopenharmony_ci // register isn't yet assigned - currently doing this regresses performance. 23181cb0ef41Sopenharmony_ci RegisterIndex reg = RegisterForVirtualRegister(virtual_register.vreg()); 23191cb0ef41Sopenharmony_ci if (reg.is_valid()) { 23201cb0ef41Sopenharmony_ci int deferred_block_start = 23211cb0ef41Sopenharmony_ci data_->GetBlock(deferred_block)->first_instruction_index(); 23221cb0ef41Sopenharmony_ci register_state_->MoveToSpillSlotOnDeferred(reg, virtual_register.vreg(), 23231cb0ef41Sopenharmony_ci deferred_block_start, data_); 23241cb0ef41Sopenharmony_ci return; 23251cb0ef41Sopenharmony_ci } else { 23261cb0ef41Sopenharmony_ci virtual_register.MarkAsNeedsSpillAtOutput(); 23271cb0ef41Sopenharmony_ci } 23281cb0ef41Sopenharmony_ci } 23291cb0ef41Sopenharmony_ci} 23301cb0ef41Sopenharmony_ci 23311cb0ef41Sopenharmony_ciAllocatedOperand SinglePassRegisterAllocator::AllocatedOperandForReg( 23321cb0ef41Sopenharmony_ci RegisterIndex reg, MachineRepresentation rep) { 23331cb0ef41Sopenharmony_ci return AllocatedOperand(AllocatedOperand::REGISTER, rep, ToRegCode(reg, rep)); 23341cb0ef41Sopenharmony_ci} 23351cb0ef41Sopenharmony_ci 23361cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateUse( 23371cb0ef41Sopenharmony_ci RegisterIndex reg, VirtualRegisterData& virtual_register, 23381cb0ef41Sopenharmony_ci InstructionOperand* operand, int instr_index, UsePosition pos) { 23391cb0ef41Sopenharmony_ci DCHECK(IsFreeOrSameVirtualRegister(reg, virtual_register.vreg())); 23401cb0ef41Sopenharmony_ci 23411cb0ef41Sopenharmony_ci AllocatedOperand allocated = 23421cb0ef41Sopenharmony_ci AllocatedOperandForReg(reg, virtual_register.rep()); 23431cb0ef41Sopenharmony_ci register_state_->Commit(reg, allocated, operand, data_); 23441cb0ef41Sopenharmony_ci register_state_->AllocateUse(reg, virtual_register.vreg(), operand, 23451cb0ef41Sopenharmony_ci instr_index, data_); 23461cb0ef41Sopenharmony_ci AssignRegister(reg, virtual_register.vreg(), virtual_register.rep(), pos); 23471cb0ef41Sopenharmony_ci CheckConsistency(); 23481cb0ef41Sopenharmony_ci} 23491cb0ef41Sopenharmony_ci 23501cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocatePendingUse( 23511cb0ef41Sopenharmony_ci RegisterIndex reg, VirtualRegisterData& virtual_register, 23521cb0ef41Sopenharmony_ci InstructionOperand* operand, bool can_be_constant, int instr_index) { 23531cb0ef41Sopenharmony_ci DCHECK(IsFreeOrSameVirtualRegister(reg, virtual_register.vreg())); 23541cb0ef41Sopenharmony_ci 23551cb0ef41Sopenharmony_ci register_state_->AllocatePendingUse(reg, virtual_register.vreg(), operand, 23561cb0ef41Sopenharmony_ci can_be_constant, instr_index); 23571cb0ef41Sopenharmony_ci // Since this is a pending use and the operand doesn't need to use a register, 23581cb0ef41Sopenharmony_ci // allocate with UsePosition::kNone to avoid blocking it's use by other 23591cb0ef41Sopenharmony_ci // operands in this instruction. 23601cb0ef41Sopenharmony_ci AssignRegister(reg, virtual_register.vreg(), virtual_register.rep(), 23611cb0ef41Sopenharmony_ci UsePosition::kNone); 23621cb0ef41Sopenharmony_ci CheckConsistency(); 23631cb0ef41Sopenharmony_ci} 23641cb0ef41Sopenharmony_ci 23651cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateUseWithMove( 23661cb0ef41Sopenharmony_ci RegisterIndex reg, VirtualRegisterData& virtual_register, 23671cb0ef41Sopenharmony_ci UnallocatedOperand* operand, int instr_index, UsePosition pos) { 23681cb0ef41Sopenharmony_ci AllocatedOperand to = AllocatedOperandForReg(reg, virtual_register.rep()); 23691cb0ef41Sopenharmony_ci UnallocatedOperand from = 23701cb0ef41Sopenharmony_ci UnallocatedOperand(UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, 23711cb0ef41Sopenharmony_ci virtual_register.vreg()); 23721cb0ef41Sopenharmony_ci data_->AddGapMove(instr_index, Instruction::END, from, to); 23731cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(operand, &to); 23741cb0ef41Sopenharmony_ci MarkRegisterUse(reg, virtual_register.rep(), pos); 23751cb0ef41Sopenharmony_ci CheckConsistency(); 23761cb0ef41Sopenharmony_ci} 23771cb0ef41Sopenharmony_ci 23781cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateInput( 23791cb0ef41Sopenharmony_ci UnallocatedOperand* operand, VirtualRegisterData& virtual_register, 23801cb0ef41Sopenharmony_ci int instr_index) { 23811cb0ef41Sopenharmony_ci EnsureRegisterState(); 23821cb0ef41Sopenharmony_ci 23831cb0ef41Sopenharmony_ci // Spill slot policy operands. 23841cb0ef41Sopenharmony_ci if (operand->HasFixedSlotPolicy()) { 23851cb0ef41Sopenharmony_ci // If the operand is from a fixed slot, allocate it to that fixed slot, 23861cb0ef41Sopenharmony_ci // then add a gap move from an unconstrained copy of that input operand, 23871cb0ef41Sopenharmony_ci // and spill the gap move's input operand. 23881cb0ef41Sopenharmony_ci // TODO(rmcilroy): We could allocate a register for the gap move however 23891cb0ef41Sopenharmony_ci // we would need to wait until we've done all the allocations for the 23901cb0ef41Sopenharmony_ci // instruction since the allocation needs to reflect the state before 23911cb0ef41Sopenharmony_ci // the instruction (at the gap move). For now spilling is fine since 23921cb0ef41Sopenharmony_ci // fixed slot inputs are uncommon. 23931cb0ef41Sopenharmony_ci UnallocatedOperand input_copy( 23941cb0ef41Sopenharmony_ci UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, 23951cb0ef41Sopenharmony_ci virtual_register.vreg()); 23961cb0ef41Sopenharmony_ci AllocatedOperand allocated = 23971cb0ef41Sopenharmony_ci AllocatedOperand(AllocatedOperand::STACK_SLOT, virtual_register.rep(), 23981cb0ef41Sopenharmony_ci operand->fixed_slot_index()); 23991cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(operand, &allocated); 24001cb0ef41Sopenharmony_ci MoveOperands* move_op = 24011cb0ef41Sopenharmony_ci data_->AddGapMove(instr_index, Instruction::END, input_copy, *operand); 24021cb0ef41Sopenharmony_ci virtual_register.SpillOperand(&move_op->source(), instr_index, true, data_); 24031cb0ef41Sopenharmony_ci return; 24041cb0ef41Sopenharmony_ci } else if (operand->HasSlotPolicy()) { 24051cb0ef41Sopenharmony_ci virtual_register.SpillOperand(operand, instr_index, false, data_); 24061cb0ef41Sopenharmony_ci return; 24071cb0ef41Sopenharmony_ci } 24081cb0ef41Sopenharmony_ci 24091cb0ef41Sopenharmony_ci // Otherwise try to allocate a register for the operation. 24101cb0ef41Sopenharmony_ci UsePosition pos = 24111cb0ef41Sopenharmony_ci operand->IsUsedAtStart() ? UsePosition::kStart : UsePosition::kAll; 24121cb0ef41Sopenharmony_ci if (operand->HasFixedRegisterPolicy() || 24131cb0ef41Sopenharmony_ci operand->HasFixedFPRegisterPolicy()) { 24141cb0ef41Sopenharmony_ci // With a fixed register operand, we must use that register. 24151cb0ef41Sopenharmony_ci RegisterIndex reg = 24161cb0ef41Sopenharmony_ci FromRegCode(operand->fixed_register_index(), virtual_register.rep()); 24171cb0ef41Sopenharmony_ci if (!VirtualRegisterIsUnallocatedOrInReg(virtual_register.vreg(), reg)) { 24181cb0ef41Sopenharmony_ci // If the virtual register is already in a different register, then just 24191cb0ef41Sopenharmony_ci // add a gap move from that register to the fixed register. 24201cb0ef41Sopenharmony_ci AllocateUseWithMove(reg, virtual_register, operand, instr_index, pos); 24211cb0ef41Sopenharmony_ci } else { 24221cb0ef41Sopenharmony_ci // Otherwise allocate a use of the fixed register for |virtual_register|. 24231cb0ef41Sopenharmony_ci AllocateUse(reg, virtual_register, operand, instr_index, pos); 24241cb0ef41Sopenharmony_ci } 24251cb0ef41Sopenharmony_ci } else { 24261cb0ef41Sopenharmony_ci bool must_use_register = operand->HasRegisterPolicy(); 24271cb0ef41Sopenharmony_ci RegisterIndex reg = ChooseRegisterFor(virtual_register, instr_index, pos, 24281cb0ef41Sopenharmony_ci must_use_register); 24291cb0ef41Sopenharmony_ci 24301cb0ef41Sopenharmony_ci if (!reg.is_valid()) { 24311cb0ef41Sopenharmony_ci // The register will have been spilled at this use. 24321cb0ef41Sopenharmony_ci virtual_register.SpillOperand( 24331cb0ef41Sopenharmony_ci operand, instr_index, operand->HasRegisterOrSlotOrConstantPolicy(), 24341cb0ef41Sopenharmony_ci data_); 24351cb0ef41Sopenharmony_ci } else if (!must_use_register) { 24361cb0ef41Sopenharmony_ci // We might later dedice to spill this register; allocate a pending use. 24371cb0ef41Sopenharmony_ci AllocatePendingUse(reg, virtual_register, operand, 24381cb0ef41Sopenharmony_ci operand->HasRegisterOrSlotOrConstantPolicy(), 24391cb0ef41Sopenharmony_ci instr_index); 24401cb0ef41Sopenharmony_ci } else if (VirtualRegisterIsUnallocatedOrInReg(virtual_register.vreg(), 24411cb0ef41Sopenharmony_ci reg)) { 24421cb0ef41Sopenharmony_ci // The register is directly usable. 24431cb0ef41Sopenharmony_ci AllocateUse(reg, virtual_register, operand, instr_index, pos); 24441cb0ef41Sopenharmony_ci } else { 24451cb0ef41Sopenharmony_ci // We assigned another register to the vreg before. {ChooseRegisterFor} 24461cb0ef41Sopenharmony_ci // chose a different one (e.g. to fulfill a "unique register" constraint 24471cb0ef41Sopenharmony_ci // for a vreg that was previously used for the input corresponding to the 24481cb0ef41Sopenharmony_ci // "same as input" output), so add a gap move to copy the input value to 24491cb0ef41Sopenharmony_ci // that new register. 24501cb0ef41Sopenharmony_ci AllocateUseWithMove(reg, virtual_register, operand, instr_index, pos); 24511cb0ef41Sopenharmony_ci } 24521cb0ef41Sopenharmony_ci } 24531cb0ef41Sopenharmony_ci} 24541cb0ef41Sopenharmony_ci 24551cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateGapMoveInput( 24561cb0ef41Sopenharmony_ci UnallocatedOperand* operand, VirtualRegisterData& vreg_data, 24571cb0ef41Sopenharmony_ci int instr_index) { 24581cb0ef41Sopenharmony_ci EnsureRegisterState(); 24591cb0ef41Sopenharmony_ci // Gap move inputs should be unconstrained. 24601cb0ef41Sopenharmony_ci DCHECK(operand->HasRegisterOrSlotOrConstantPolicy()); 24611cb0ef41Sopenharmony_ci RegisterIndex reg = 24621cb0ef41Sopenharmony_ci ChooseRegisterFor(vreg_data, instr_index, UsePosition::kStart, false); 24631cb0ef41Sopenharmony_ci if (reg.is_valid()) { 24641cb0ef41Sopenharmony_ci AllocatePendingUse(reg, vreg_data, operand, true, instr_index); 24651cb0ef41Sopenharmony_ci } else { 24661cb0ef41Sopenharmony_ci vreg_data.SpillOperand(operand, instr_index, true, data_); 24671cb0ef41Sopenharmony_ci } 24681cb0ef41Sopenharmony_ci} 24691cb0ef41Sopenharmony_ci 24701cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateConstantOutput( 24711cb0ef41Sopenharmony_ci ConstantOperand* operand, VirtualRegisterData& vreg_data, int instr_index) { 24721cb0ef41Sopenharmony_ci EnsureRegisterState(); 24731cb0ef41Sopenharmony_ci // If the constant is allocated to a register, spill it now to add the 24741cb0ef41Sopenharmony_ci // necessary gap moves from the constant operand to the register. 24751cb0ef41Sopenharmony_ci SpillRegisterForVirtualRegister(vreg_data.vreg()); 24761cb0ef41Sopenharmony_ci if (vreg_data.NeedsSpillAtOutput()) { 24771cb0ef41Sopenharmony_ci vreg_data.EmitGapMoveFromOutputToSpillSlot(*operand, current_block_, 24781cb0ef41Sopenharmony_ci instr_index, data_); 24791cb0ef41Sopenharmony_ci } 24801cb0ef41Sopenharmony_ci} 24811cb0ef41Sopenharmony_ci 24821cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateOutput(UnallocatedOperand* operand, 24831cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data, 24841cb0ef41Sopenharmony_ci int instr_index) { 24851cb0ef41Sopenharmony_ci AllocateOutput(operand, vreg_data, instr_index, UsePosition::kEnd); 24861cb0ef41Sopenharmony_ci} 24871cb0ef41Sopenharmony_ci 24881cb0ef41Sopenharmony_ciRegisterIndex SinglePassRegisterAllocator::AllocateOutput( 24891cb0ef41Sopenharmony_ci UnallocatedOperand* operand, VirtualRegisterData& vreg_data, 24901cb0ef41Sopenharmony_ci int instr_index, UsePosition pos) { 24911cb0ef41Sopenharmony_ci EnsureRegisterState(); 24921cb0ef41Sopenharmony_ci int virtual_register = vreg_data.vreg(); 24931cb0ef41Sopenharmony_ci 24941cb0ef41Sopenharmony_ci RegisterIndex reg; 24951cb0ef41Sopenharmony_ci if (operand->HasSlotPolicy() || operand->HasFixedSlotPolicy()) { 24961cb0ef41Sopenharmony_ci // We can't allocate a register for output given the policy, so make sure 24971cb0ef41Sopenharmony_ci // to spill the register holding this virtual register if any. 24981cb0ef41Sopenharmony_ci SpillRegisterForVirtualRegister(virtual_register); 24991cb0ef41Sopenharmony_ci reg = RegisterIndex::Invalid(); 25001cb0ef41Sopenharmony_ci } else if (operand->HasFixedPolicy()) { 25011cb0ef41Sopenharmony_ci reg = FromRegCode(operand->fixed_register_index(), vreg_data.rep()); 25021cb0ef41Sopenharmony_ci } else { 25031cb0ef41Sopenharmony_ci reg = ChooseRegisterFor(vreg_data, instr_index, pos, 25041cb0ef41Sopenharmony_ci operand->HasRegisterPolicy()); 25051cb0ef41Sopenharmony_ci } 25061cb0ef41Sopenharmony_ci 25071cb0ef41Sopenharmony_ci // TODO(rmcilroy): support secondary storage. 25081cb0ef41Sopenharmony_ci if (!reg.is_valid()) { 25091cb0ef41Sopenharmony_ci vreg_data.SpillOperand(operand, instr_index, false, data_); 25101cb0ef41Sopenharmony_ci } else { 25111cb0ef41Sopenharmony_ci InstructionOperand move_output_to; 25121cb0ef41Sopenharmony_ci if (!VirtualRegisterIsUnallocatedOrInReg(virtual_register, reg)) { 25131cb0ef41Sopenharmony_ci // If the |virtual register| was in a different register (e.g., due to 25141cb0ef41Sopenharmony_ci // the output having a fixed register), then commit its use in that 25151cb0ef41Sopenharmony_ci // register here, and move it from the output operand below. 25161cb0ef41Sopenharmony_ci RegisterIndex existing_reg = RegisterForVirtualRegister(virtual_register); 25171cb0ef41Sopenharmony_ci // Don't mark |existing_reg| as used in this instruction, since it is used 25181cb0ef41Sopenharmony_ci // in the (already allocated) following instruction's gap-move. 25191cb0ef41Sopenharmony_ci CommitRegister(existing_reg, vreg_data.vreg(), vreg_data.rep(), 25201cb0ef41Sopenharmony_ci &move_output_to, UsePosition::kNone); 25211cb0ef41Sopenharmony_ci } 25221cb0ef41Sopenharmony_ci CommitRegister(reg, vreg_data.vreg(), vreg_data.rep(), operand, pos); 25231cb0ef41Sopenharmony_ci if (move_output_to.IsAllocated()) { 25241cb0ef41Sopenharmony_ci // Emit a move from output to the register that the |virtual_register| was 25251cb0ef41Sopenharmony_ci // allocated to. 25261cb0ef41Sopenharmony_ci EmitGapMoveFromOutput(*operand, move_output_to, instr_index); 25271cb0ef41Sopenharmony_ci } 25281cb0ef41Sopenharmony_ci if (vreg_data.NeedsSpillAtOutput()) { 25291cb0ef41Sopenharmony_ci vreg_data.EmitGapMoveFromOutputToSpillSlot( 25301cb0ef41Sopenharmony_ci *AllocatedOperand::cast(operand), current_block_, instr_index, data_); 25311cb0ef41Sopenharmony_ci } else if (vreg_data.NeedsSpillAtDeferredBlocks()) { 25321cb0ef41Sopenharmony_ci vreg_data.EmitDeferredSpillOutputs(data_); 25331cb0ef41Sopenharmony_ci } 25341cb0ef41Sopenharmony_ci } 25351cb0ef41Sopenharmony_ci 25361cb0ef41Sopenharmony_ci return reg; 25371cb0ef41Sopenharmony_ci} 25381cb0ef41Sopenharmony_ci 25391cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateSameInputOutput( 25401cb0ef41Sopenharmony_ci UnallocatedOperand* output, UnallocatedOperand* input, 25411cb0ef41Sopenharmony_ci VirtualRegisterData& output_vreg_data, VirtualRegisterData& input_vreg_data, 25421cb0ef41Sopenharmony_ci int instr_index) { 25431cb0ef41Sopenharmony_ci EnsureRegisterState(); 25441cb0ef41Sopenharmony_ci int input_vreg = input_vreg_data.vreg(); 25451cb0ef41Sopenharmony_ci int output_vreg = output_vreg_data.vreg(); 25461cb0ef41Sopenharmony_ci 25471cb0ef41Sopenharmony_ci // The input operand has the details of the register constraints, so replace 25481cb0ef41Sopenharmony_ci // the output operand with a copy of the input, with the output's vreg. 25491cb0ef41Sopenharmony_ci UnallocatedOperand output_as_input(*input, output_vreg); 25501cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(output, &output_as_input); 25511cb0ef41Sopenharmony_ci RegisterIndex reg = 25521cb0ef41Sopenharmony_ci AllocateOutput(output, output_vreg_data, instr_index, UsePosition::kAll); 25531cb0ef41Sopenharmony_ci 25541cb0ef41Sopenharmony_ci if (reg.is_valid()) { 25551cb0ef41Sopenharmony_ci // Replace the input operand with an unallocated fixed register policy for 25561cb0ef41Sopenharmony_ci // the same register. 25571cb0ef41Sopenharmony_ci UnallocatedOperand::ExtendedPolicy policy = 25581cb0ef41Sopenharmony_ci kind() == RegisterKind::kGeneral 25591cb0ef41Sopenharmony_ci ? UnallocatedOperand::FIXED_REGISTER 25601cb0ef41Sopenharmony_ci : UnallocatedOperand::FIXED_FP_REGISTER; 25611cb0ef41Sopenharmony_ci MachineRepresentation rep = input_vreg_data.rep(); 25621cb0ef41Sopenharmony_ci UnallocatedOperand fixed_input(policy, ToRegCode(reg, rep), input_vreg); 25631cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(input, &fixed_input); 25641cb0ef41Sopenharmony_ci same_input_output_registers_bits_.Add(reg, rep); 25651cb0ef41Sopenharmony_ci } else { 25661cb0ef41Sopenharmony_ci // Output was spilled. Due to the SameAsInput allocation policy, we need to 25671cb0ef41Sopenharmony_ci // make the input operand the same as the output, i.e., the output virtual 25681cb0ef41Sopenharmony_ci // register's spill slot. As such, spill this input operand using the output 25691cb0ef41Sopenharmony_ci // virtual register's spill slot, then add a gap-move to move the input 25701cb0ef41Sopenharmony_ci // value into this spill slot. 25711cb0ef41Sopenharmony_ci output_vreg_data.SpillOperand(input, instr_index, false, data_); 25721cb0ef41Sopenharmony_ci 25731cb0ef41Sopenharmony_ci // Add an unconstrained gap move for the input virtual register. 25741cb0ef41Sopenharmony_ci UnallocatedOperand unconstrained_input( 25751cb0ef41Sopenharmony_ci UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, input_vreg); 25761cb0ef41Sopenharmony_ci MoveOperands* move_ops = data_->AddGapMove( 25771cb0ef41Sopenharmony_ci instr_index, Instruction::END, unconstrained_input, PendingOperand()); 25781cb0ef41Sopenharmony_ci output_vreg_data.SpillOperand(&move_ops->destination(), instr_index, true, 25791cb0ef41Sopenharmony_ci data_); 25801cb0ef41Sopenharmony_ci } 25811cb0ef41Sopenharmony_ci} 25821cb0ef41Sopenharmony_ci 25831cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocateTemp(UnallocatedOperand* operand, 25841cb0ef41Sopenharmony_ci int virtual_register, 25851cb0ef41Sopenharmony_ci MachineRepresentation rep, 25861cb0ef41Sopenharmony_ci int instr_index) { 25871cb0ef41Sopenharmony_ci EnsureRegisterState(); 25881cb0ef41Sopenharmony_ci RegisterIndex reg; 25891cb0ef41Sopenharmony_ci DCHECK(!operand->HasFixedSlotPolicy()); 25901cb0ef41Sopenharmony_ci if (operand->HasSlotPolicy()) { 25911cb0ef41Sopenharmony_ci reg = RegisterIndex::Invalid(); 25921cb0ef41Sopenharmony_ci } else if (operand->HasFixedRegisterPolicy() || 25931cb0ef41Sopenharmony_ci operand->HasFixedFPRegisterPolicy()) { 25941cb0ef41Sopenharmony_ci reg = FromRegCode(operand->fixed_register_index(), rep); 25951cb0ef41Sopenharmony_ci } else { 25961cb0ef41Sopenharmony_ci reg = 25971cb0ef41Sopenharmony_ci ChooseRegisterFor(rep, UsePosition::kAll, operand->HasRegisterPolicy()); 25981cb0ef41Sopenharmony_ci } 25991cb0ef41Sopenharmony_ci 26001cb0ef41Sopenharmony_ci if (reg.is_valid()) { 26011cb0ef41Sopenharmony_ci DCHECK(virtual_register == InstructionOperand::kInvalidVirtualRegister || 26021cb0ef41Sopenharmony_ci VirtualRegisterIsUnallocatedOrInReg(virtual_register, reg)); 26031cb0ef41Sopenharmony_ci CommitRegister(reg, virtual_register, rep, operand, UsePosition::kAll); 26041cb0ef41Sopenharmony_ci } else { 26051cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = VirtualRegisterDataFor(virtual_register); 26061cb0ef41Sopenharmony_ci vreg_data.SpillOperand(operand, instr_index, 26071cb0ef41Sopenharmony_ci operand->HasRegisterOrSlotOrConstantPolicy(), data_); 26081cb0ef41Sopenharmony_ci } 26091cb0ef41Sopenharmony_ci} 26101cb0ef41Sopenharmony_ci 26111cb0ef41Sopenharmony_cibool SinglePassRegisterAllocator::DefinedAfter(int virtual_register, 26121cb0ef41Sopenharmony_ci int instr_index, 26131cb0ef41Sopenharmony_ci UsePosition pos) { 26141cb0ef41Sopenharmony_ci if (virtual_register == InstructionOperand::kInvalidVirtualRegister) 26151cb0ef41Sopenharmony_ci return false; 26161cb0ef41Sopenharmony_ci int defined_at = 26171cb0ef41Sopenharmony_ci VirtualRegisterDataFor(virtual_register).output_instr_index(); 26181cb0ef41Sopenharmony_ci return defined_at > instr_index || 26191cb0ef41Sopenharmony_ci (defined_at == instr_index && pos == UsePosition::kStart); 26201cb0ef41Sopenharmony_ci} 26211cb0ef41Sopenharmony_ci 26221cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::ReserveFixedInputRegister( 26231cb0ef41Sopenharmony_ci const UnallocatedOperand* operand, int virtual_register, 26241cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index) { 26251cb0ef41Sopenharmony_ci ReserveFixedRegister( 26261cb0ef41Sopenharmony_ci operand, virtual_register, rep, instr_index, 26271cb0ef41Sopenharmony_ci operand->IsUsedAtStart() ? UsePosition::kStart : UsePosition::kAll); 26281cb0ef41Sopenharmony_ci} 26291cb0ef41Sopenharmony_ci 26301cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::ReserveFixedTempRegister( 26311cb0ef41Sopenharmony_ci const UnallocatedOperand* operand, int virtual_register, 26321cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index) { 26331cb0ef41Sopenharmony_ci ReserveFixedRegister(operand, virtual_register, rep, instr_index, 26341cb0ef41Sopenharmony_ci UsePosition::kAll); 26351cb0ef41Sopenharmony_ci} 26361cb0ef41Sopenharmony_ci 26371cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::ReserveFixedOutputRegister( 26381cb0ef41Sopenharmony_ci const UnallocatedOperand* operand, int virtual_register, 26391cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index) { 26401cb0ef41Sopenharmony_ci ReserveFixedRegister(operand, virtual_register, rep, instr_index, 26411cb0ef41Sopenharmony_ci UsePosition::kEnd); 26421cb0ef41Sopenharmony_ci} 26431cb0ef41Sopenharmony_ci 26441cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::ReserveFixedRegister( 26451cb0ef41Sopenharmony_ci const UnallocatedOperand* operand, int virtual_register, 26461cb0ef41Sopenharmony_ci MachineRepresentation rep, int instr_index, UsePosition pos) { 26471cb0ef41Sopenharmony_ci EnsureRegisterState(); 26481cb0ef41Sopenharmony_ci int reg_code = operand->fixed_register_index(); 26491cb0ef41Sopenharmony_ci RegisterIndex reg = FromRegCode(reg_code, rep); 26501cb0ef41Sopenharmony_ci if (!IsFreeOrSameVirtualRegister(reg, virtual_register) && 26511cb0ef41Sopenharmony_ci !DefinedAfter(virtual_register, instr_index, pos)) { 26521cb0ef41Sopenharmony_ci // If register is in-use by a different virtual register, spill it now. 26531cb0ef41Sopenharmony_ci // TODO(rmcilroy): Consider moving to a unconstrained register instead of 26541cb0ef41Sopenharmony_ci // spilling. 26551cb0ef41Sopenharmony_ci SpillRegister(reg); 26561cb0ef41Sopenharmony_ci } 26571cb0ef41Sopenharmony_ci // Also potentially spill the "sibling SIMD register" on architectures where a 26581cb0ef41Sopenharmony_ci // SIMD register aliases two FP registers. 26591cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 26601cb0ef41Sopenharmony_ci rep == MachineRepresentation::kSimd128) { 26611cb0ef41Sopenharmony_ci if (register_state_->IsAllocated(simdSibling(reg)) && 26621cb0ef41Sopenharmony_ci !DefinedAfter(virtual_register, instr_index, pos)) { 26631cb0ef41Sopenharmony_ci SpillRegister(simdSibling(reg)); 26641cb0ef41Sopenharmony_ci } 26651cb0ef41Sopenharmony_ci } 26661cb0ef41Sopenharmony_ci // Similarly (but the other way around), spill a SIMD register that (partly) 26671cb0ef41Sopenharmony_ci // overlaps with a fixed FP register. 26681cb0ef41Sopenharmony_ci if (kFPAliasing == AliasingKind::kCombine && 26691cb0ef41Sopenharmony_ci (rep == MachineRepresentation::kFloat64 || 26701cb0ef41Sopenharmony_ci rep == MachineRepresentation::kFloat32)) { 26711cb0ef41Sopenharmony_ci int simd_reg_code; 26721cb0ef41Sopenharmony_ci CHECK_EQ( 26731cb0ef41Sopenharmony_ci 1, data_->config()->GetAliases( 26741cb0ef41Sopenharmony_ci rep, reg_code, MachineRepresentation::kSimd128, &simd_reg_code)); 26751cb0ef41Sopenharmony_ci // Sanity check: The SIMD register code should be the shifted {reg_code}. 26761cb0ef41Sopenharmony_ci DCHECK_EQ(simd_reg_code, 26771cb0ef41Sopenharmony_ci reg_code >> (rep == MachineRepresentation::kFloat64 ? 1 : 2)); 26781cb0ef41Sopenharmony_ci RegisterIndex simd_reg = 26791cb0ef41Sopenharmony_ci FromRegCode(simd_reg_code, MachineRepresentation::kSimd128); 26801cb0ef41Sopenharmony_ci DCHECK(simd_reg == reg || simdSibling(simd_reg) == reg); 26811cb0ef41Sopenharmony_ci int allocated_vreg = VirtualRegisterForRegister(simd_reg); 26821cb0ef41Sopenharmony_ci if (simd_reg != reg && 26831cb0ef41Sopenharmony_ci allocated_vreg != InstructionOperand::kInvalidVirtualRegister && 26841cb0ef41Sopenharmony_ci VirtualRegisterDataFor(allocated_vreg).rep() == 26851cb0ef41Sopenharmony_ci MachineRepresentation::kSimd128 && 26861cb0ef41Sopenharmony_ci !DefinedAfter(virtual_register, instr_index, pos)) { 26871cb0ef41Sopenharmony_ci SpillRegister(simd_reg); 26881cb0ef41Sopenharmony_ci } 26891cb0ef41Sopenharmony_ci } 26901cb0ef41Sopenharmony_ci 26911cb0ef41Sopenharmony_ci MarkRegisterUse(reg, rep, pos); 26921cb0ef41Sopenharmony_ci} 26931cb0ef41Sopenharmony_ci 26941cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocatePhiGapMove( 26951cb0ef41Sopenharmony_ci VirtualRegisterData& to_vreg, VirtualRegisterData& from_vreg, 26961cb0ef41Sopenharmony_ci int instr_index) { 26971cb0ef41Sopenharmony_ci EnsureRegisterState(); 26981cb0ef41Sopenharmony_ci RegisterIndex from_register = RegisterForVirtualRegister(from_vreg.vreg()); 26991cb0ef41Sopenharmony_ci RegisterIndex to_register = RegisterForVirtualRegister(to_vreg.vreg()); 27001cb0ef41Sopenharmony_ci 27011cb0ef41Sopenharmony_ci // If to_register isn't marked as a phi gap move, we can't use it as such. 27021cb0ef41Sopenharmony_ci if (to_register.is_valid() && !register_state_->IsPhiGapMove(to_register)) { 27031cb0ef41Sopenharmony_ci to_register = RegisterIndex::Invalid(); 27041cb0ef41Sopenharmony_ci } 27051cb0ef41Sopenharmony_ci 27061cb0ef41Sopenharmony_ci if (to_register.is_valid() && !from_register.is_valid()) { 27071cb0ef41Sopenharmony_ci // If |to| virtual register is allocated to a register, and the |from| 27081cb0ef41Sopenharmony_ci // virtual register isn't allocated, then commit this register and 27091cb0ef41Sopenharmony_ci // re-allocate it to the |from| virtual register. 27101cb0ef41Sopenharmony_ci InstructionOperand operand; 27111cb0ef41Sopenharmony_ci CommitRegister(to_register, to_vreg.vreg(), to_vreg.rep(), &operand, 27121cb0ef41Sopenharmony_ci UsePosition::kAll); 27131cb0ef41Sopenharmony_ci AllocateUse(to_register, from_vreg, &operand, instr_index, 27141cb0ef41Sopenharmony_ci UsePosition::kAll); 27151cb0ef41Sopenharmony_ci } else { 27161cb0ef41Sopenharmony_ci // Otherwise add a gap move. 27171cb0ef41Sopenharmony_ci MoveOperands* move = 27181cb0ef41Sopenharmony_ci data_->AddPendingOperandGapMove(instr_index, Instruction::END); 27191cb0ef41Sopenharmony_ci PendingOperand* to_operand = PendingOperand::cast(&move->destination()); 27201cb0ef41Sopenharmony_ci PendingOperand* from_operand = PendingOperand::cast(&move->source()); 27211cb0ef41Sopenharmony_ci 27221cb0ef41Sopenharmony_ci // Commit the |to| side to either a register or the pending spills. 27231cb0ef41Sopenharmony_ci if (to_register.is_valid()) { 27241cb0ef41Sopenharmony_ci CommitRegister(to_register, to_vreg.vreg(), to_vreg.rep(), to_operand, 27251cb0ef41Sopenharmony_ci UsePosition::kAll); 27261cb0ef41Sopenharmony_ci } else { 27271cb0ef41Sopenharmony_ci to_vreg.SpillOperand(to_operand, instr_index, true, data_); 27281cb0ef41Sopenharmony_ci } 27291cb0ef41Sopenharmony_ci 27301cb0ef41Sopenharmony_ci // The from side is unconstrained. 27311cb0ef41Sopenharmony_ci UnallocatedOperand unconstrained_input( 27321cb0ef41Sopenharmony_ci UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, from_vreg.vreg()); 27331cb0ef41Sopenharmony_ci InstructionOperand::ReplaceWith(from_operand, &unconstrained_input); 27341cb0ef41Sopenharmony_ci } 27351cb0ef41Sopenharmony_ci} 27361cb0ef41Sopenharmony_ci 27371cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::AllocatePhi( 27381cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register, const InstructionBlock* block) { 27391cb0ef41Sopenharmony_ci if (virtual_register.NeedsSpillAtOutput() || block->IsLoopHeader()) { 27401cb0ef41Sopenharmony_ci // If the Phi needs to be spilled, just spill here directly so that all 27411cb0ef41Sopenharmony_ci // gap moves into the Phi move into the spill slot. 27421cb0ef41Sopenharmony_ci SpillRegisterForVirtualRegister(virtual_register.vreg()); 27431cb0ef41Sopenharmony_ci } else { 27441cb0ef41Sopenharmony_ci RegisterIndex reg = RegisterForVirtualRegister(virtual_register.vreg()); 27451cb0ef41Sopenharmony_ci if (reg.is_valid()) { 27461cb0ef41Sopenharmony_ci // If the register is valid, assign it as a phi gap move to be processed 27471cb0ef41Sopenharmony_ci // at the successor blocks. If no register or spill slot was used then 27481cb0ef41Sopenharmony_ci // the virtual register was never used. 27491cb0ef41Sopenharmony_ci register_state_->UseForPhiGapMove(reg); 27501cb0ef41Sopenharmony_ci } 27511cb0ef41Sopenharmony_ci } 27521cb0ef41Sopenharmony_ci} 27531cb0ef41Sopenharmony_ci 27541cb0ef41Sopenharmony_civoid SinglePassRegisterAllocator::EnsureRegisterState() { 27551cb0ef41Sopenharmony_ci if (V8_UNLIKELY(!register_state_)) { 27561cb0ef41Sopenharmony_ci register_state_ = RegisterState::New(kind(), num_allocatable_registers_, 27571cb0ef41Sopenharmony_ci data_->allocation_zone()); 27581cb0ef41Sopenharmony_ci } 27591cb0ef41Sopenharmony_ci} 27601cb0ef41Sopenharmony_ci 27611cb0ef41Sopenharmony_ciclass MidTierOutputProcessor final { 27621cb0ef41Sopenharmony_ci public: 27631cb0ef41Sopenharmony_ci explicit MidTierOutputProcessor(MidTierRegisterAllocationData* data); 27641cb0ef41Sopenharmony_ci 27651cb0ef41Sopenharmony_ci void InitializeBlockState(const InstructionBlock* block); 27661cb0ef41Sopenharmony_ci void DefineOutputs(const InstructionBlock* block); 27671cb0ef41Sopenharmony_ci 27681cb0ef41Sopenharmony_ci private: 27691cb0ef41Sopenharmony_ci void PopulateDeferredBlockRegion(RpoNumber initial_block); 27701cb0ef41Sopenharmony_ci 27711cb0ef41Sopenharmony_ci VirtualRegisterData& VirtualRegisterDataFor(int virtual_register) const { 27721cb0ef41Sopenharmony_ci return data_->VirtualRegisterDataFor(virtual_register); 27731cb0ef41Sopenharmony_ci } 27741cb0ef41Sopenharmony_ci MachineRepresentation RepresentationFor(int virtual_register) const { 27751cb0ef41Sopenharmony_ci DCHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister); 27761cb0ef41Sopenharmony_ci DCHECK_LT(virtual_register, code()->VirtualRegisterCount()); 27771cb0ef41Sopenharmony_ci return code()->GetRepresentation(virtual_register); 27781cb0ef41Sopenharmony_ci } 27791cb0ef41Sopenharmony_ci 27801cb0ef41Sopenharmony_ci bool IsDeferredBlockBoundary(const ZoneVector<RpoNumber>& blocks) { 27811cb0ef41Sopenharmony_ci return blocks.size() == 1 && !data_->GetBlock(blocks[0])->IsDeferred(); 27821cb0ef41Sopenharmony_ci } 27831cb0ef41Sopenharmony_ci 27841cb0ef41Sopenharmony_ci InstructionSequence* code() const { return data_->code(); } 27851cb0ef41Sopenharmony_ci Zone* zone() const { return data_->allocation_zone(); } 27861cb0ef41Sopenharmony_ci 27871cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* const data_; 27881cb0ef41Sopenharmony_ci ZoneQueue<RpoNumber> deferred_blocks_worklist_; 27891cb0ef41Sopenharmony_ci ZoneSet<RpoNumber> deferred_blocks_processed_; 27901cb0ef41Sopenharmony_ci}; 27911cb0ef41Sopenharmony_ci 27921cb0ef41Sopenharmony_ciMidTierOutputProcessor::MidTierOutputProcessor( 27931cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) 27941cb0ef41Sopenharmony_ci : data_(data), 27951cb0ef41Sopenharmony_ci deferred_blocks_worklist_(data->allocation_zone()), 27961cb0ef41Sopenharmony_ci deferred_blocks_processed_(data->allocation_zone()) {} 27971cb0ef41Sopenharmony_ci 27981cb0ef41Sopenharmony_civoid MidTierOutputProcessor::PopulateDeferredBlockRegion( 27991cb0ef41Sopenharmony_ci RpoNumber initial_block) { 28001cb0ef41Sopenharmony_ci DeferredBlocksRegion* deferred_blocks_region = 28011cb0ef41Sopenharmony_ci zone()->New<DeferredBlocksRegion>(zone(), 28021cb0ef41Sopenharmony_ci code()->InstructionBlockCount()); 28031cb0ef41Sopenharmony_ci DCHECK(deferred_blocks_worklist_.empty()); 28041cb0ef41Sopenharmony_ci deferred_blocks_worklist_.push(initial_block); 28051cb0ef41Sopenharmony_ci deferred_blocks_processed_.insert(initial_block); 28061cb0ef41Sopenharmony_ci while (!deferred_blocks_worklist_.empty()) { 28071cb0ef41Sopenharmony_ci RpoNumber current = deferred_blocks_worklist_.front(); 28081cb0ef41Sopenharmony_ci deferred_blocks_worklist_.pop(); 28091cb0ef41Sopenharmony_ci deferred_blocks_region->AddBlock(current, data_); 28101cb0ef41Sopenharmony_ci 28111cb0ef41Sopenharmony_ci const InstructionBlock* curr_block = data_->GetBlock(current); 28121cb0ef41Sopenharmony_ci // Check for whether the predecessor blocks are still deferred. 28131cb0ef41Sopenharmony_ci if (IsDeferredBlockBoundary(curr_block->predecessors())) { 28141cb0ef41Sopenharmony_ci // If not, mark the predecessor as having a deferred successor. 28151cb0ef41Sopenharmony_ci data_->block_state(curr_block->predecessors()[0]) 28161cb0ef41Sopenharmony_ci .MarkAsDeferredBlockBoundary(); 28171cb0ef41Sopenharmony_ci } else { 28181cb0ef41Sopenharmony_ci // Otherwise process predecessors. 28191cb0ef41Sopenharmony_ci for (RpoNumber pred : curr_block->predecessors()) { 28201cb0ef41Sopenharmony_ci if (deferred_blocks_processed_.count(pred) == 0) { 28211cb0ef41Sopenharmony_ci deferred_blocks_worklist_.push(pred); 28221cb0ef41Sopenharmony_ci deferred_blocks_processed_.insert(pred); 28231cb0ef41Sopenharmony_ci } 28241cb0ef41Sopenharmony_ci } 28251cb0ef41Sopenharmony_ci } 28261cb0ef41Sopenharmony_ci 28271cb0ef41Sopenharmony_ci // Check for whether the successor blocks are still deferred. 28281cb0ef41Sopenharmony_ci // Process any unprocessed successors if we aren't at a boundary. 28291cb0ef41Sopenharmony_ci if (IsDeferredBlockBoundary(curr_block->successors())) { 28301cb0ef41Sopenharmony_ci // If not, mark the predecessor as having a deferred successor. 28311cb0ef41Sopenharmony_ci data_->block_state(current).MarkAsDeferredBlockBoundary(); 28321cb0ef41Sopenharmony_ci } else { 28331cb0ef41Sopenharmony_ci // Otherwise process successors. 28341cb0ef41Sopenharmony_ci for (RpoNumber succ : curr_block->successors()) { 28351cb0ef41Sopenharmony_ci if (deferred_blocks_processed_.count(succ) == 0) { 28361cb0ef41Sopenharmony_ci deferred_blocks_worklist_.push(succ); 28371cb0ef41Sopenharmony_ci deferred_blocks_processed_.insert(succ); 28381cb0ef41Sopenharmony_ci } 28391cb0ef41Sopenharmony_ci } 28401cb0ef41Sopenharmony_ci } 28411cb0ef41Sopenharmony_ci } 28421cb0ef41Sopenharmony_ci} 28431cb0ef41Sopenharmony_ci 28441cb0ef41Sopenharmony_civoid MidTierOutputProcessor::InitializeBlockState( 28451cb0ef41Sopenharmony_ci const InstructionBlock* block) { 28461cb0ef41Sopenharmony_ci // Update our predecessor blocks with their successors_phi_index if we have 28471cb0ef41Sopenharmony_ci // phis. 28481cb0ef41Sopenharmony_ci if (block->phis().size()) { 28491cb0ef41Sopenharmony_ci for (int i = 0; i < static_cast<int>(block->PredecessorCount()); ++i) { 28501cb0ef41Sopenharmony_ci data_->block_state(block->predecessors()[i]).set_successors_phi_index(i); 28511cb0ef41Sopenharmony_ci } 28521cb0ef41Sopenharmony_ci } 28531cb0ef41Sopenharmony_ci 28541cb0ef41Sopenharmony_ci BlockState& block_state = data_->block_state(block->rpo_number()); 28551cb0ef41Sopenharmony_ci 28561cb0ef41Sopenharmony_ci if (block->IsDeferred() && !block_state.deferred_blocks_region()) { 28571cb0ef41Sopenharmony_ci PopulateDeferredBlockRegion(block->rpo_number()); 28581cb0ef41Sopenharmony_ci } 28591cb0ef41Sopenharmony_ci 28601cb0ef41Sopenharmony_ci // Mark this block as dominating itself. 28611cb0ef41Sopenharmony_ci block_state.dominated_blocks()->Add(block->rpo_number().ToInt()); 28621cb0ef41Sopenharmony_ci 28631cb0ef41Sopenharmony_ci if (block->dominator().IsValid()) { 28641cb0ef41Sopenharmony_ci // Add all the blocks this block dominates to its dominator. 28651cb0ef41Sopenharmony_ci BlockState& dominator_block_state = data_->block_state(block->dominator()); 28661cb0ef41Sopenharmony_ci dominator_block_state.dominated_blocks()->Union( 28671cb0ef41Sopenharmony_ci *block_state.dominated_blocks()); 28681cb0ef41Sopenharmony_ci } else { 28691cb0ef41Sopenharmony_ci // Only the first block shouldn't have a dominator. 28701cb0ef41Sopenharmony_ci DCHECK_EQ(block, code()->instruction_blocks().front()); 28711cb0ef41Sopenharmony_ci } 28721cb0ef41Sopenharmony_ci} 28731cb0ef41Sopenharmony_ci 28741cb0ef41Sopenharmony_civoid MidTierOutputProcessor::DefineOutputs(const InstructionBlock* block) { 28751cb0ef41Sopenharmony_ci int block_start = block->first_instruction_index(); 28761cb0ef41Sopenharmony_ci bool is_deferred = block->IsDeferred(); 28771cb0ef41Sopenharmony_ci 28781cb0ef41Sopenharmony_ci for (int index = block->last_instruction_index(); index >= block_start; 28791cb0ef41Sopenharmony_ci index--) { 28801cb0ef41Sopenharmony_ci Instruction* instr = code()->InstructionAt(index); 28811cb0ef41Sopenharmony_ci 28821cb0ef41Sopenharmony_ci // For each instruction, define details of the output with the associated 28831cb0ef41Sopenharmony_ci // virtual register data. 28841cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->OutputCount(); i++) { 28851cb0ef41Sopenharmony_ci InstructionOperand* output = instr->OutputAt(i); 28861cb0ef41Sopenharmony_ci if (output->IsConstant()) { 28871cb0ef41Sopenharmony_ci ConstantOperand* constant_operand = ConstantOperand::cast(output); 28881cb0ef41Sopenharmony_ci int virtual_register = constant_operand->virtual_register(); 28891cb0ef41Sopenharmony_ci MachineRepresentation rep = RepresentationFor(virtual_register); 28901cb0ef41Sopenharmony_ci VirtualRegisterDataFor(virtual_register) 28911cb0ef41Sopenharmony_ci .DefineAsConstantOperand(constant_operand, rep, index, is_deferred); 28921cb0ef41Sopenharmony_ci } else { 28931cb0ef41Sopenharmony_ci DCHECK(output->IsUnallocated()); 28941cb0ef41Sopenharmony_ci UnallocatedOperand* unallocated_operand = 28951cb0ef41Sopenharmony_ci UnallocatedOperand::cast(output); 28961cb0ef41Sopenharmony_ci int virtual_register = unallocated_operand->virtual_register(); 28971cb0ef41Sopenharmony_ci MachineRepresentation rep = RepresentationFor(virtual_register); 28981cb0ef41Sopenharmony_ci bool is_exceptional_call_output = 28991cb0ef41Sopenharmony_ci instr->IsCallWithDescriptorFlags() && 29001cb0ef41Sopenharmony_ci instr->HasCallDescriptorFlag(CallDescriptor::kHasExceptionHandler); 29011cb0ef41Sopenharmony_ci if (unallocated_operand->HasFixedSlotPolicy()) { 29021cb0ef41Sopenharmony_ci // If output has a fixed slot policy, allocate its spill operand now 29031cb0ef41Sopenharmony_ci // so that the register allocator can use this knowledge. 29041cb0ef41Sopenharmony_ci AllocatedOperand* fixed_spill_operand = 29051cb0ef41Sopenharmony_ci AllocatedOperand::New(zone(), AllocatedOperand::STACK_SLOT, rep, 29061cb0ef41Sopenharmony_ci unallocated_operand->fixed_slot_index()); 29071cb0ef41Sopenharmony_ci VirtualRegisterDataFor(virtual_register) 29081cb0ef41Sopenharmony_ci .DefineAsFixedSpillOperand(fixed_spill_operand, virtual_register, 29091cb0ef41Sopenharmony_ci rep, index, is_deferred, 29101cb0ef41Sopenharmony_ci is_exceptional_call_output); 29111cb0ef41Sopenharmony_ci } else { 29121cb0ef41Sopenharmony_ci VirtualRegisterDataFor(virtual_register) 29131cb0ef41Sopenharmony_ci .DefineAsUnallocatedOperand(virtual_register, rep, index, 29141cb0ef41Sopenharmony_ci is_deferred, 29151cb0ef41Sopenharmony_ci is_exceptional_call_output); 29161cb0ef41Sopenharmony_ci } 29171cb0ef41Sopenharmony_ci } 29181cb0ef41Sopenharmony_ci } 29191cb0ef41Sopenharmony_ci 29201cb0ef41Sopenharmony_ci // Mark any instructions that require reference maps for later reference map 29211cb0ef41Sopenharmony_ci // processing. 29221cb0ef41Sopenharmony_ci if (instr->HasReferenceMap()) { 29231cb0ef41Sopenharmony_ci data_->reference_map_instructions().push_back(index); 29241cb0ef41Sopenharmony_ci } 29251cb0ef41Sopenharmony_ci } 29261cb0ef41Sopenharmony_ci 29271cb0ef41Sopenharmony_ci // Define phi output operands. 29281cb0ef41Sopenharmony_ci for (PhiInstruction* phi : block->phis()) { 29291cb0ef41Sopenharmony_ci int virtual_register = phi->virtual_register(); 29301cb0ef41Sopenharmony_ci MachineRepresentation rep = RepresentationFor(virtual_register); 29311cb0ef41Sopenharmony_ci VirtualRegisterDataFor(virtual_register) 29321cb0ef41Sopenharmony_ci .DefineAsPhi(virtual_register, rep, block->first_instruction_index(), 29331cb0ef41Sopenharmony_ci is_deferred); 29341cb0ef41Sopenharmony_ci } 29351cb0ef41Sopenharmony_ci} 29361cb0ef41Sopenharmony_ci 29371cb0ef41Sopenharmony_civoid DefineOutputs(MidTierRegisterAllocationData* data) { 29381cb0ef41Sopenharmony_ci MidTierOutputProcessor processor(data); 29391cb0ef41Sopenharmony_ci 29401cb0ef41Sopenharmony_ci for (const InstructionBlock* block : 29411cb0ef41Sopenharmony_ci base::Reversed(data->code()->instruction_blocks())) { 29421cb0ef41Sopenharmony_ci data->tick_counter()->TickAndMaybeEnterSafepoint(); 29431cb0ef41Sopenharmony_ci 29441cb0ef41Sopenharmony_ci processor.InitializeBlockState(block); 29451cb0ef41Sopenharmony_ci processor.DefineOutputs(block); 29461cb0ef41Sopenharmony_ci } 29471cb0ef41Sopenharmony_ci} 29481cb0ef41Sopenharmony_ci 29491cb0ef41Sopenharmony_ciclass MidTierRegisterAllocator final { 29501cb0ef41Sopenharmony_ci public: 29511cb0ef41Sopenharmony_ci explicit MidTierRegisterAllocator(MidTierRegisterAllocationData* data); 29521cb0ef41Sopenharmony_ci MidTierRegisterAllocator(const MidTierRegisterAllocator&) = delete; 29531cb0ef41Sopenharmony_ci MidTierRegisterAllocator& operator=(const MidTierRegisterAllocator&) = delete; 29541cb0ef41Sopenharmony_ci 29551cb0ef41Sopenharmony_ci void AllocateRegisters(const InstructionBlock* block); 29561cb0ef41Sopenharmony_ci void UpdateSpillRangesForLoops(); 29571cb0ef41Sopenharmony_ci 29581cb0ef41Sopenharmony_ci SinglePassRegisterAllocator& general_reg_allocator() { 29591cb0ef41Sopenharmony_ci return general_reg_allocator_; 29601cb0ef41Sopenharmony_ci } 29611cb0ef41Sopenharmony_ci SinglePassRegisterAllocator& double_reg_allocator() { 29621cb0ef41Sopenharmony_ci return double_reg_allocator_; 29631cb0ef41Sopenharmony_ci } 29641cb0ef41Sopenharmony_ci 29651cb0ef41Sopenharmony_ci private: 29661cb0ef41Sopenharmony_ci void AllocatePhis(const InstructionBlock* block); 29671cb0ef41Sopenharmony_ci void AllocatePhiGapMoves(const InstructionBlock* block); 29681cb0ef41Sopenharmony_ci 29691cb0ef41Sopenharmony_ci bool IsFixedRegisterPolicy(const UnallocatedOperand* operand); 29701cb0ef41Sopenharmony_ci void ReserveFixedRegisters(int instr_index); 29711cb0ef41Sopenharmony_ci 29721cb0ef41Sopenharmony_ci SinglePassRegisterAllocator& AllocatorFor(MachineRepresentation rep); 29731cb0ef41Sopenharmony_ci 29741cb0ef41Sopenharmony_ci VirtualRegisterData& VirtualRegisterDataFor(int virtual_register) const { 29751cb0ef41Sopenharmony_ci return data_->VirtualRegisterDataFor(virtual_register); 29761cb0ef41Sopenharmony_ci } 29771cb0ef41Sopenharmony_ci InstructionSequence* code() const { return data_->code(); } 29781cb0ef41Sopenharmony_ci Zone* allocation_zone() const { return data_->allocation_zone(); } 29791cb0ef41Sopenharmony_ci 29801cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* const data_; 29811cb0ef41Sopenharmony_ci SinglePassRegisterAllocator general_reg_allocator_; 29821cb0ef41Sopenharmony_ci SinglePassRegisterAllocator double_reg_allocator_; 29831cb0ef41Sopenharmony_ci}; 29841cb0ef41Sopenharmony_ci 29851cb0ef41Sopenharmony_ciMidTierRegisterAllocator::MidTierRegisterAllocator( 29861cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) 29871cb0ef41Sopenharmony_ci : data_(data), 29881cb0ef41Sopenharmony_ci general_reg_allocator_(RegisterKind::kGeneral, data), 29891cb0ef41Sopenharmony_ci double_reg_allocator_(RegisterKind::kDouble, data) {} 29901cb0ef41Sopenharmony_ci 29911cb0ef41Sopenharmony_civoid MidTierRegisterAllocator::AllocateRegisters( 29921cb0ef41Sopenharmony_ci const InstructionBlock* block) { 29931cb0ef41Sopenharmony_ci RpoNumber block_rpo = block->rpo_number(); 29941cb0ef41Sopenharmony_ci bool is_deferred_block_boundary = 29951cb0ef41Sopenharmony_ci data_->block_state(block_rpo).is_deferred_block_boundary(); 29961cb0ef41Sopenharmony_ci 29971cb0ef41Sopenharmony_ci general_reg_allocator_.StartBlock(block); 29981cb0ef41Sopenharmony_ci double_reg_allocator_.StartBlock(block); 29991cb0ef41Sopenharmony_ci 30001cb0ef41Sopenharmony_ci // If the block is not deferred but has deferred successors, then try to 30011cb0ef41Sopenharmony_ci // output spill slots for virtual_registers that are only spilled in the 30021cb0ef41Sopenharmony_ci // deferred blocks at the start of those deferred blocks to avoid spilling 30031cb0ef41Sopenharmony_ci // them at their output in non-deferred blocks. 30041cb0ef41Sopenharmony_ci if (is_deferred_block_boundary && !block->IsDeferred()) { 30051cb0ef41Sopenharmony_ci for (RpoNumber successor : block->successors()) { 30061cb0ef41Sopenharmony_ci if (!data_->GetBlock(successor)->IsDeferred()) continue; 30071cb0ef41Sopenharmony_ci DCHECK_GT(successor, block_rpo); 30081cb0ef41Sopenharmony_ci DeferredBlocksRegion* deferred_region = 30091cb0ef41Sopenharmony_ci data_->block_state(successor).deferred_blocks_region(); 30101cb0ef41Sopenharmony_ci // Freeze the deferred spills on the region to ensure no more are added to 30111cb0ef41Sopenharmony_ci // this region after the spills for this entry point have already been 30121cb0ef41Sopenharmony_ci // emitted. 30131cb0ef41Sopenharmony_ci deferred_region->FreezeDeferredSpills(); 30141cb0ef41Sopenharmony_ci for (const int virtual_register : *deferred_region) { 30151cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 30161cb0ef41Sopenharmony_ci VirtualRegisterDataFor(virtual_register); 30171cb0ef41Sopenharmony_ci AllocatorFor(vreg_data.rep()) 30181cb0ef41Sopenharmony_ci .AllocateDeferredBlockSpillOutput(block->last_instruction_index(), 30191cb0ef41Sopenharmony_ci successor, vreg_data); 30201cb0ef41Sopenharmony_ci } 30211cb0ef41Sopenharmony_ci } 30221cb0ef41Sopenharmony_ci } 30231cb0ef41Sopenharmony_ci 30241cb0ef41Sopenharmony_ci // Allocate registers for instructions in reverse, from the end of the block 30251cb0ef41Sopenharmony_ci // to the start. 30261cb0ef41Sopenharmony_ci int block_start = block->first_instruction_index(); 30271cb0ef41Sopenharmony_ci for (int instr_index = block->last_instruction_index(); 30281cb0ef41Sopenharmony_ci instr_index >= block_start; instr_index--) { 30291cb0ef41Sopenharmony_ci Instruction* instr = code()->InstructionAt(instr_index); 30301cb0ef41Sopenharmony_ci 30311cb0ef41Sopenharmony_ci // Reserve any fixed register operands to prevent the register being 30321cb0ef41Sopenharmony_ci // allocated to another operand. 30331cb0ef41Sopenharmony_ci ReserveFixedRegisters(instr_index); 30341cb0ef41Sopenharmony_ci 30351cb0ef41Sopenharmony_ci // Allocate outputs. 30361cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->OutputCount(); i++) { 30371cb0ef41Sopenharmony_ci InstructionOperand* output = instr->OutputAt(i); 30381cb0ef41Sopenharmony_ci DCHECK(!output->IsAllocated()); 30391cb0ef41Sopenharmony_ci if (output->IsConstant()) { 30401cb0ef41Sopenharmony_ci ConstantOperand* constant_operand = ConstantOperand::cast(output); 30411cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 30421cb0ef41Sopenharmony_ci VirtualRegisterDataFor(constant_operand->virtual_register()); 30431cb0ef41Sopenharmony_ci AllocatorFor(vreg_data.rep()) 30441cb0ef41Sopenharmony_ci .AllocateConstantOutput(constant_operand, vreg_data, instr_index); 30451cb0ef41Sopenharmony_ci } else { 30461cb0ef41Sopenharmony_ci UnallocatedOperand* unallocated_output = 30471cb0ef41Sopenharmony_ci UnallocatedOperand::cast(output); 30481cb0ef41Sopenharmony_ci VirtualRegisterData& output_vreg_data = 30491cb0ef41Sopenharmony_ci VirtualRegisterDataFor(unallocated_output->virtual_register()); 30501cb0ef41Sopenharmony_ci 30511cb0ef41Sopenharmony_ci if (unallocated_output->HasSameAsInputPolicy()) { 30521cb0ef41Sopenharmony_ci DCHECK_EQ(i, 0); 30531cb0ef41Sopenharmony_ci UnallocatedOperand* unallocated_input = UnallocatedOperand::cast( 30541cb0ef41Sopenharmony_ci instr->InputAt(unallocated_output->input_index())); 30551cb0ef41Sopenharmony_ci VirtualRegisterData& input_vreg_data = 30561cb0ef41Sopenharmony_ci VirtualRegisterDataFor(unallocated_input->virtual_register()); 30571cb0ef41Sopenharmony_ci DCHECK_EQ(AllocatorFor(output_vreg_data.rep()).kind(), 30581cb0ef41Sopenharmony_ci AllocatorFor(input_vreg_data.rep()).kind()); 30591cb0ef41Sopenharmony_ci AllocatorFor(output_vreg_data.rep()) 30601cb0ef41Sopenharmony_ci .AllocateSameInputOutput(unallocated_output, unallocated_input, 30611cb0ef41Sopenharmony_ci output_vreg_data, input_vreg_data, 30621cb0ef41Sopenharmony_ci instr_index); 30631cb0ef41Sopenharmony_ci } else { 30641cb0ef41Sopenharmony_ci AllocatorFor(output_vreg_data.rep()) 30651cb0ef41Sopenharmony_ci .AllocateOutput(unallocated_output, output_vreg_data, 30661cb0ef41Sopenharmony_ci instr_index); 30671cb0ef41Sopenharmony_ci } 30681cb0ef41Sopenharmony_ci } 30691cb0ef41Sopenharmony_ci } 30701cb0ef41Sopenharmony_ci 30711cb0ef41Sopenharmony_ci if (instr->ClobbersRegisters()) { 30721cb0ef41Sopenharmony_ci general_reg_allocator_.SpillAllRegisters(); 30731cb0ef41Sopenharmony_ci } 30741cb0ef41Sopenharmony_ci if (instr->ClobbersDoubleRegisters()) { 30751cb0ef41Sopenharmony_ci double_reg_allocator_.SpillAllRegisters(); 30761cb0ef41Sopenharmony_ci } 30771cb0ef41Sopenharmony_ci 30781cb0ef41Sopenharmony_ci // Allocate temporaries. 30791cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->TempCount(); i++) { 30801cb0ef41Sopenharmony_ci UnallocatedOperand* temp = UnallocatedOperand::cast(instr->TempAt(i)); 30811cb0ef41Sopenharmony_ci int virtual_register = temp->virtual_register(); 30821cb0ef41Sopenharmony_ci MachineRepresentation rep = 30831cb0ef41Sopenharmony_ci virtual_register == InstructionOperand::kInvalidVirtualRegister 30841cb0ef41Sopenharmony_ci ? InstructionSequence::DefaultRepresentation() 30851cb0ef41Sopenharmony_ci : code()->GetRepresentation(virtual_register); 30861cb0ef41Sopenharmony_ci AllocatorFor(rep).AllocateTemp(temp, virtual_register, rep, instr_index); 30871cb0ef41Sopenharmony_ci } 30881cb0ef41Sopenharmony_ci 30891cb0ef41Sopenharmony_ci // Allocate inputs that are used across the whole instruction. 30901cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->InputCount(); i++) { 30911cb0ef41Sopenharmony_ci if (!instr->InputAt(i)->IsUnallocated()) continue; 30921cb0ef41Sopenharmony_ci UnallocatedOperand* input = UnallocatedOperand::cast(instr->InputAt(i)); 30931cb0ef41Sopenharmony_ci if (input->IsUsedAtStart()) continue; 30941cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 30951cb0ef41Sopenharmony_ci VirtualRegisterDataFor(input->virtual_register()); 30961cb0ef41Sopenharmony_ci AllocatorFor(vreg_data.rep()) 30971cb0ef41Sopenharmony_ci .AllocateInput(input, vreg_data, instr_index); 30981cb0ef41Sopenharmony_ci } 30991cb0ef41Sopenharmony_ci 31001cb0ef41Sopenharmony_ci // Then allocate inputs that are only used at the start of the instruction. 31011cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->InputCount(); i++) { 31021cb0ef41Sopenharmony_ci if (!instr->InputAt(i)->IsUnallocated()) continue; 31031cb0ef41Sopenharmony_ci UnallocatedOperand* input = UnallocatedOperand::cast(instr->InputAt(i)); 31041cb0ef41Sopenharmony_ci DCHECK(input->IsUsedAtStart()); 31051cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 31061cb0ef41Sopenharmony_ci VirtualRegisterDataFor(input->virtual_register()); 31071cb0ef41Sopenharmony_ci AllocatorFor(vreg_data.rep()) 31081cb0ef41Sopenharmony_ci .AllocateInput(input, vreg_data, instr_index); 31091cb0ef41Sopenharmony_ci } 31101cb0ef41Sopenharmony_ci 31111cb0ef41Sopenharmony_ci // If we are allocating for the last instruction in the block, allocate any 31121cb0ef41Sopenharmony_ci // phi gap move operations that are needed to resolve phis in our successor. 31131cb0ef41Sopenharmony_ci if (instr_index == block->last_instruction_index()) { 31141cb0ef41Sopenharmony_ci AllocatePhiGapMoves(block); 31151cb0ef41Sopenharmony_ci 31161cb0ef41Sopenharmony_ci // If this block is deferred but it's successor isn't, update the state to 31171cb0ef41Sopenharmony_ci // limit spills to the deferred blocks where possible. 31181cb0ef41Sopenharmony_ci if (is_deferred_block_boundary && block->IsDeferred()) { 31191cb0ef41Sopenharmony_ci general_reg_allocator_.UpdateForDeferredBlock(instr_index); 31201cb0ef41Sopenharmony_ci double_reg_allocator_.UpdateForDeferredBlock(instr_index); 31211cb0ef41Sopenharmony_ci } 31221cb0ef41Sopenharmony_ci } 31231cb0ef41Sopenharmony_ci 31241cb0ef41Sopenharmony_ci // Allocate any unallocated gap move inputs. 31251cb0ef41Sopenharmony_ci ParallelMove* moves = instr->GetParallelMove(Instruction::END); 31261cb0ef41Sopenharmony_ci if (moves != nullptr) { 31271cb0ef41Sopenharmony_ci for (MoveOperands* move : *moves) { 31281cb0ef41Sopenharmony_ci DCHECK(!move->destination().IsUnallocated()); 31291cb0ef41Sopenharmony_ci if (move->source().IsUnallocated()) { 31301cb0ef41Sopenharmony_ci UnallocatedOperand* source = 31311cb0ef41Sopenharmony_ci UnallocatedOperand::cast(&move->source()); 31321cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 31331cb0ef41Sopenharmony_ci VirtualRegisterDataFor(source->virtual_register()); 31341cb0ef41Sopenharmony_ci AllocatorFor(vreg_data.rep()) 31351cb0ef41Sopenharmony_ci .AllocateGapMoveInput(source, vreg_data, instr_index); 31361cb0ef41Sopenharmony_ci } 31371cb0ef41Sopenharmony_ci } 31381cb0ef41Sopenharmony_ci } 31391cb0ef41Sopenharmony_ci 31401cb0ef41Sopenharmony_ci general_reg_allocator_.EndInstruction(); 31411cb0ef41Sopenharmony_ci double_reg_allocator_.EndInstruction(); 31421cb0ef41Sopenharmony_ci } 31431cb0ef41Sopenharmony_ci 31441cb0ef41Sopenharmony_ci // For now we spill all registers at a loop header. 31451cb0ef41Sopenharmony_ci // TODO(rmcilroy): Add support for register allocations across loops. 31461cb0ef41Sopenharmony_ci if (block->IsLoopHeader()) { 31471cb0ef41Sopenharmony_ci general_reg_allocator_.SpillAllRegisters(); 31481cb0ef41Sopenharmony_ci double_reg_allocator_.SpillAllRegisters(); 31491cb0ef41Sopenharmony_ci } 31501cb0ef41Sopenharmony_ci 31511cb0ef41Sopenharmony_ci AllocatePhis(block); 31521cb0ef41Sopenharmony_ci 31531cb0ef41Sopenharmony_ci general_reg_allocator_.EndBlock(block); 31541cb0ef41Sopenharmony_ci double_reg_allocator_.EndBlock(block); 31551cb0ef41Sopenharmony_ci} 31561cb0ef41Sopenharmony_ci 31571cb0ef41Sopenharmony_ciSinglePassRegisterAllocator& MidTierRegisterAllocator::AllocatorFor( 31581cb0ef41Sopenharmony_ci MachineRepresentation rep) { 31591cb0ef41Sopenharmony_ci return IsFloatingPoint(rep) ? double_reg_allocator_ : general_reg_allocator_; 31601cb0ef41Sopenharmony_ci} 31611cb0ef41Sopenharmony_ci 31621cb0ef41Sopenharmony_cibool MidTierRegisterAllocator::IsFixedRegisterPolicy( 31631cb0ef41Sopenharmony_ci const UnallocatedOperand* operand) { 31641cb0ef41Sopenharmony_ci return operand->HasFixedRegisterPolicy() || 31651cb0ef41Sopenharmony_ci operand->HasFixedFPRegisterPolicy(); 31661cb0ef41Sopenharmony_ci} 31671cb0ef41Sopenharmony_ci 31681cb0ef41Sopenharmony_civoid MidTierRegisterAllocator::ReserveFixedRegisters(int instr_index) { 31691cb0ef41Sopenharmony_ci Instruction* instr = code()->InstructionAt(instr_index); 31701cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->OutputCount(); i++) { 31711cb0ef41Sopenharmony_ci if (!instr->OutputAt(i)->IsUnallocated()) continue; 31721cb0ef41Sopenharmony_ci const UnallocatedOperand* operand = 31731cb0ef41Sopenharmony_ci UnallocatedOperand::cast(instr->OutputAt(i)); 31741cb0ef41Sopenharmony_ci if (operand->HasSameAsInputPolicy()) { 31751cb0ef41Sopenharmony_ci DCHECK_EQ(i, 0); 31761cb0ef41Sopenharmony_ci // Input operand has the register constraints, use it here to reserve the 31771cb0ef41Sopenharmony_ci // register for the output (it will be reserved for input below). 31781cb0ef41Sopenharmony_ci operand = 31791cb0ef41Sopenharmony_ci UnallocatedOperand::cast(instr->InputAt(operand->input_index())); 31801cb0ef41Sopenharmony_ci } 31811cb0ef41Sopenharmony_ci if (IsFixedRegisterPolicy(operand)) { 31821cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 31831cb0ef41Sopenharmony_ci VirtualRegisterDataFor(operand->virtual_register()); 31841cb0ef41Sopenharmony_ci AllocatorFor(vreg_data.rep()) 31851cb0ef41Sopenharmony_ci .ReserveFixedOutputRegister(operand, vreg_data.vreg(), 31861cb0ef41Sopenharmony_ci vreg_data.rep(), instr_index); 31871cb0ef41Sopenharmony_ci } 31881cb0ef41Sopenharmony_ci } 31891cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->TempCount(); i++) { 31901cb0ef41Sopenharmony_ci if (!instr->TempAt(i)->IsUnallocated()) continue; 31911cb0ef41Sopenharmony_ci const UnallocatedOperand* operand = 31921cb0ef41Sopenharmony_ci UnallocatedOperand::cast(instr->TempAt(i)); 31931cb0ef41Sopenharmony_ci if (IsFixedRegisterPolicy(operand)) { 31941cb0ef41Sopenharmony_ci int virtual_register = operand->virtual_register(); 31951cb0ef41Sopenharmony_ci MachineRepresentation rep = 31961cb0ef41Sopenharmony_ci virtual_register == InstructionOperand::kInvalidVirtualRegister 31971cb0ef41Sopenharmony_ci ? InstructionSequence::DefaultRepresentation() 31981cb0ef41Sopenharmony_ci : code()->GetRepresentation(virtual_register); 31991cb0ef41Sopenharmony_ci AllocatorFor(rep).ReserveFixedTempRegister(operand, virtual_register, rep, 32001cb0ef41Sopenharmony_ci instr_index); 32011cb0ef41Sopenharmony_ci } 32021cb0ef41Sopenharmony_ci } 32031cb0ef41Sopenharmony_ci for (size_t i = 0; i < instr->InputCount(); i++) { 32041cb0ef41Sopenharmony_ci if (!instr->InputAt(i)->IsUnallocated()) continue; 32051cb0ef41Sopenharmony_ci const UnallocatedOperand* operand = 32061cb0ef41Sopenharmony_ci UnallocatedOperand::cast(instr->InputAt(i)); 32071cb0ef41Sopenharmony_ci if (IsFixedRegisterPolicy(operand)) { 32081cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = 32091cb0ef41Sopenharmony_ci VirtualRegisterDataFor(operand->virtual_register()); 32101cb0ef41Sopenharmony_ci AllocatorFor(vreg_data.rep()) 32111cb0ef41Sopenharmony_ci .ReserveFixedInputRegister(operand, vreg_data.vreg(), vreg_data.rep(), 32121cb0ef41Sopenharmony_ci instr_index); 32131cb0ef41Sopenharmony_ci } 32141cb0ef41Sopenharmony_ci } 32151cb0ef41Sopenharmony_ci} 32161cb0ef41Sopenharmony_ci 32171cb0ef41Sopenharmony_civoid MidTierRegisterAllocator::AllocatePhiGapMoves( 32181cb0ef41Sopenharmony_ci const InstructionBlock* block) { 32191cb0ef41Sopenharmony_ci int successors_phi_index = 32201cb0ef41Sopenharmony_ci data_->block_state(block->rpo_number()).successors_phi_index(); 32211cb0ef41Sopenharmony_ci 32221cb0ef41Sopenharmony_ci // If successors_phi_index is -1 there are no phi's in the successor. 32231cb0ef41Sopenharmony_ci if (successors_phi_index == -1) return; 32241cb0ef41Sopenharmony_ci 32251cb0ef41Sopenharmony_ci // The last instruction of a block with phis can't require reference maps 32261cb0ef41Sopenharmony_ci // since we won't record phi gap moves that get spilled when populating the 32271cb0ef41Sopenharmony_ci // reference maps 32281cb0ef41Sopenharmony_ci int instr_index = block->last_instruction_index(); 32291cb0ef41Sopenharmony_ci DCHECK(!code()->InstructionAt(instr_index)->HasReferenceMap()); 32301cb0ef41Sopenharmony_ci 32311cb0ef41Sopenharmony_ci // If there are phis, we only have a single successor due to edge-split form. 32321cb0ef41Sopenharmony_ci DCHECK_EQ(block->SuccessorCount(), 1); 32331cb0ef41Sopenharmony_ci const InstructionBlock* successor = data_->GetBlock(block->successors()[0]); 32341cb0ef41Sopenharmony_ci 32351cb0ef41Sopenharmony_ci for (PhiInstruction* phi : successor->phis()) { 32361cb0ef41Sopenharmony_ci VirtualRegisterData& to_vreg = 32371cb0ef41Sopenharmony_ci VirtualRegisterDataFor(phi->virtual_register()); 32381cb0ef41Sopenharmony_ci VirtualRegisterData& from_vreg = 32391cb0ef41Sopenharmony_ci VirtualRegisterDataFor(phi->operands()[successors_phi_index]); 32401cb0ef41Sopenharmony_ci 32411cb0ef41Sopenharmony_ci AllocatorFor(to_vreg.rep()) 32421cb0ef41Sopenharmony_ci .AllocatePhiGapMove(to_vreg, from_vreg, instr_index); 32431cb0ef41Sopenharmony_ci } 32441cb0ef41Sopenharmony_ci} 32451cb0ef41Sopenharmony_ci 32461cb0ef41Sopenharmony_civoid MidTierRegisterAllocator::AllocatePhis(const InstructionBlock* block) { 32471cb0ef41Sopenharmony_ci for (PhiInstruction* phi : block->phis()) { 32481cb0ef41Sopenharmony_ci VirtualRegisterData& virtual_register = 32491cb0ef41Sopenharmony_ci VirtualRegisterDataFor(phi->virtual_register()); 32501cb0ef41Sopenharmony_ci AllocatorFor(virtual_register.rep()).AllocatePhi(virtual_register, block); 32511cb0ef41Sopenharmony_ci } 32521cb0ef41Sopenharmony_ci} 32531cb0ef41Sopenharmony_ci 32541cb0ef41Sopenharmony_civoid MidTierRegisterAllocator::UpdateSpillRangesForLoops() { 32551cb0ef41Sopenharmony_ci // Extend the spill range of any spill that crosses a loop header to 32561cb0ef41Sopenharmony_ci // the full loop. 32571cb0ef41Sopenharmony_ci for (InstructionBlock* block : code()->instruction_blocks()) { 32581cb0ef41Sopenharmony_ci if (block->IsLoopHeader()) { 32591cb0ef41Sopenharmony_ci RpoNumber last_loop_block = 32601cb0ef41Sopenharmony_ci RpoNumber::FromInt(block->loop_end().ToInt() - 1); 32611cb0ef41Sopenharmony_ci int last_loop_instr = 32621cb0ef41Sopenharmony_ci data_->GetBlock(last_loop_block)->last_instruction_index(); 32631cb0ef41Sopenharmony_ci // Extend spill range for all spilled values that are live on entry to the 32641cb0ef41Sopenharmony_ci // loop header. 32651cb0ef41Sopenharmony_ci for (int vreg : data_->spilled_virtual_registers()) { 32661cb0ef41Sopenharmony_ci const VirtualRegisterData& vreg_data = VirtualRegisterDataFor(vreg); 32671cb0ef41Sopenharmony_ci if (vreg_data.HasSpillRange() && 32681cb0ef41Sopenharmony_ci vreg_data.spill_range()->IsLiveAt(block->first_instruction_index(), 32691cb0ef41Sopenharmony_ci block)) { 32701cb0ef41Sopenharmony_ci vreg_data.spill_range()->ExtendRangeTo(last_loop_instr); 32711cb0ef41Sopenharmony_ci } 32721cb0ef41Sopenharmony_ci } 32731cb0ef41Sopenharmony_ci } 32741cb0ef41Sopenharmony_ci } 32751cb0ef41Sopenharmony_ci} 32761cb0ef41Sopenharmony_ci 32771cb0ef41Sopenharmony_civoid AllocateRegisters(MidTierRegisterAllocationData* data) { 32781cb0ef41Sopenharmony_ci MidTierRegisterAllocator allocator(data); 32791cb0ef41Sopenharmony_ci for (InstructionBlock* block : 32801cb0ef41Sopenharmony_ci base::Reversed(data->code()->instruction_blocks())) { 32811cb0ef41Sopenharmony_ci data->tick_counter()->TickAndMaybeEnterSafepoint(); 32821cb0ef41Sopenharmony_ci allocator.AllocateRegisters(block); 32831cb0ef41Sopenharmony_ci } 32841cb0ef41Sopenharmony_ci 32851cb0ef41Sopenharmony_ci allocator.UpdateSpillRangesForLoops(); 32861cb0ef41Sopenharmony_ci 32871cb0ef41Sopenharmony_ci data->frame()->SetAllocatedRegisters( 32881cb0ef41Sopenharmony_ci allocator.general_reg_allocator().assigned_registers()); 32891cb0ef41Sopenharmony_ci data->frame()->SetAllocatedDoubleRegisters( 32901cb0ef41Sopenharmony_ci allocator.double_reg_allocator().assigned_registers()); 32911cb0ef41Sopenharmony_ci} 32921cb0ef41Sopenharmony_ci 32931cb0ef41Sopenharmony_ci// Spill slot allocator for mid-tier register allocation. 32941cb0ef41Sopenharmony_ciclass MidTierSpillSlotAllocator final { 32951cb0ef41Sopenharmony_ci public: 32961cb0ef41Sopenharmony_ci explicit MidTierSpillSlotAllocator(MidTierRegisterAllocationData* data); 32971cb0ef41Sopenharmony_ci MidTierSpillSlotAllocator(const MidTierSpillSlotAllocator&) = delete; 32981cb0ef41Sopenharmony_ci MidTierSpillSlotAllocator& operator=(const MidTierSpillSlotAllocator&) = 32991cb0ef41Sopenharmony_ci delete; 33001cb0ef41Sopenharmony_ci 33011cb0ef41Sopenharmony_ci void Allocate(VirtualRegisterData* virtual_register); 33021cb0ef41Sopenharmony_ci 33031cb0ef41Sopenharmony_ci private: 33041cb0ef41Sopenharmony_ci class SpillSlot; 33051cb0ef41Sopenharmony_ci 33061cb0ef41Sopenharmony_ci void AdvanceTo(int instr_index); 33071cb0ef41Sopenharmony_ci SpillSlot* GetFreeSpillSlot(int byte_width); 33081cb0ef41Sopenharmony_ci 33091cb0ef41Sopenharmony_ci InstructionSequence* code() const { return data_->code(); } 33101cb0ef41Sopenharmony_ci Frame* frame() const { return data_->frame(); } 33111cb0ef41Sopenharmony_ci Zone* zone() const { return data_->allocation_zone(); } 33121cb0ef41Sopenharmony_ci 33131cb0ef41Sopenharmony_ci struct OrderByLastUse { 33141cb0ef41Sopenharmony_ci bool operator()(const SpillSlot* a, const SpillSlot* b) const; 33151cb0ef41Sopenharmony_ci }; 33161cb0ef41Sopenharmony_ci 33171cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* const data_; 33181cb0ef41Sopenharmony_ci ZonePriorityQueue<SpillSlot*, OrderByLastUse> allocated_slots_; 33191cb0ef41Sopenharmony_ci ZoneLinkedList<SpillSlot*> free_slots_; 33201cb0ef41Sopenharmony_ci int position_; 33211cb0ef41Sopenharmony_ci}; 33221cb0ef41Sopenharmony_ci 33231cb0ef41Sopenharmony_ciclass MidTierSpillSlotAllocator::SpillSlot : public ZoneObject { 33241cb0ef41Sopenharmony_ci public: 33251cb0ef41Sopenharmony_ci SpillSlot(int stack_slot, int byte_width) 33261cb0ef41Sopenharmony_ci : stack_slot_(stack_slot), byte_width_(byte_width), range_() {} 33271cb0ef41Sopenharmony_ci SpillSlot(const SpillSlot&) = delete; 33281cb0ef41Sopenharmony_ci SpillSlot& operator=(const SpillSlot&) = delete; 33291cb0ef41Sopenharmony_ci 33301cb0ef41Sopenharmony_ci void AddRange(const Range& range) { range_.AddRange(range); } 33311cb0ef41Sopenharmony_ci 33321cb0ef41Sopenharmony_ci AllocatedOperand ToOperand(MachineRepresentation rep) const { 33331cb0ef41Sopenharmony_ci return AllocatedOperand(AllocatedOperand::STACK_SLOT, rep, stack_slot_); 33341cb0ef41Sopenharmony_ci } 33351cb0ef41Sopenharmony_ci 33361cb0ef41Sopenharmony_ci int byte_width() const { return byte_width_; } 33371cb0ef41Sopenharmony_ci int last_use() const { return range_.end(); } 33381cb0ef41Sopenharmony_ci 33391cb0ef41Sopenharmony_ci private: 33401cb0ef41Sopenharmony_ci int stack_slot_; 33411cb0ef41Sopenharmony_ci int byte_width_; 33421cb0ef41Sopenharmony_ci Range range_; 33431cb0ef41Sopenharmony_ci}; 33441cb0ef41Sopenharmony_ci 33451cb0ef41Sopenharmony_cibool MidTierSpillSlotAllocator::OrderByLastUse::operator()( 33461cb0ef41Sopenharmony_ci const SpillSlot* a, const SpillSlot* b) const { 33471cb0ef41Sopenharmony_ci return a->last_use() > b->last_use(); 33481cb0ef41Sopenharmony_ci} 33491cb0ef41Sopenharmony_ci 33501cb0ef41Sopenharmony_ciMidTierSpillSlotAllocator::MidTierSpillSlotAllocator( 33511cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) 33521cb0ef41Sopenharmony_ci : data_(data), 33531cb0ef41Sopenharmony_ci allocated_slots_(data->allocation_zone()), 33541cb0ef41Sopenharmony_ci free_slots_(data->allocation_zone()), 33551cb0ef41Sopenharmony_ci position_(0) {} 33561cb0ef41Sopenharmony_ci 33571cb0ef41Sopenharmony_civoid MidTierSpillSlotAllocator::AdvanceTo(int instr_index) { 33581cb0ef41Sopenharmony_ci // Move any slots that are no longer in use to the free slots list. 33591cb0ef41Sopenharmony_ci DCHECK_LE(position_, instr_index); 33601cb0ef41Sopenharmony_ci while (!allocated_slots_.empty() && 33611cb0ef41Sopenharmony_ci instr_index > allocated_slots_.top()->last_use()) { 33621cb0ef41Sopenharmony_ci free_slots_.push_front(allocated_slots_.top()); 33631cb0ef41Sopenharmony_ci allocated_slots_.pop(); 33641cb0ef41Sopenharmony_ci } 33651cb0ef41Sopenharmony_ci position_ = instr_index; 33661cb0ef41Sopenharmony_ci} 33671cb0ef41Sopenharmony_ci 33681cb0ef41Sopenharmony_ciMidTierSpillSlotAllocator::SpillSlot* 33691cb0ef41Sopenharmony_ciMidTierSpillSlotAllocator::GetFreeSpillSlot(int byte_width) { 33701cb0ef41Sopenharmony_ci for (auto it = free_slots_.begin(); it != free_slots_.end(); ++it) { 33711cb0ef41Sopenharmony_ci SpillSlot* slot = *it; 33721cb0ef41Sopenharmony_ci if (slot->byte_width() == byte_width) { 33731cb0ef41Sopenharmony_ci free_slots_.erase(it); 33741cb0ef41Sopenharmony_ci return slot; 33751cb0ef41Sopenharmony_ci } 33761cb0ef41Sopenharmony_ci } 33771cb0ef41Sopenharmony_ci return nullptr; 33781cb0ef41Sopenharmony_ci} 33791cb0ef41Sopenharmony_ci 33801cb0ef41Sopenharmony_civoid MidTierSpillSlotAllocator::Allocate( 33811cb0ef41Sopenharmony_ci VirtualRegisterData* virtual_register) { 33821cb0ef41Sopenharmony_ci DCHECK(virtual_register->HasPendingSpillOperand()); 33831cb0ef41Sopenharmony_ci VirtualRegisterData::SpillRange* spill_range = 33841cb0ef41Sopenharmony_ci virtual_register->spill_range(); 33851cb0ef41Sopenharmony_ci MachineRepresentation rep = virtual_register->rep(); 33861cb0ef41Sopenharmony_ci int byte_width = ByteWidthForStackSlot(rep); 33871cb0ef41Sopenharmony_ci Range live_range = spill_range->live_range(); 33881cb0ef41Sopenharmony_ci 33891cb0ef41Sopenharmony_ci AdvanceTo(live_range.start()); 33901cb0ef41Sopenharmony_ci 33911cb0ef41Sopenharmony_ci // Try to re-use an existing free spill slot. 33921cb0ef41Sopenharmony_ci SpillSlot* slot = GetFreeSpillSlot(byte_width); 33931cb0ef41Sopenharmony_ci if (slot == nullptr) { 33941cb0ef41Sopenharmony_ci // Otherwise allocate a new slot. 33951cb0ef41Sopenharmony_ci int stack_slot_ = frame()->AllocateSpillSlot(byte_width); 33961cb0ef41Sopenharmony_ci slot = zone()->New<SpillSlot>(stack_slot_, byte_width); 33971cb0ef41Sopenharmony_ci } 33981cb0ef41Sopenharmony_ci 33991cb0ef41Sopenharmony_ci // Extend the range of the slot to include this spill range, and allocate the 34001cb0ef41Sopenharmony_ci // pending spill operands with this slot. 34011cb0ef41Sopenharmony_ci slot->AddRange(live_range); 34021cb0ef41Sopenharmony_ci virtual_register->AllocatePendingSpillOperand(slot->ToOperand(rep)); 34031cb0ef41Sopenharmony_ci allocated_slots_.push(slot); 34041cb0ef41Sopenharmony_ci} 34051cb0ef41Sopenharmony_ci 34061cb0ef41Sopenharmony_civoid AllocateSpillSlots(MidTierRegisterAllocationData* data) { 34071cb0ef41Sopenharmony_ci ZoneVector<VirtualRegisterData*> spilled(data->allocation_zone()); 34081cb0ef41Sopenharmony_ci for (int vreg : data->spilled_virtual_registers()) { 34091cb0ef41Sopenharmony_ci VirtualRegisterData& vreg_data = data->VirtualRegisterDataFor(vreg); 34101cb0ef41Sopenharmony_ci if (vreg_data.HasPendingSpillOperand()) { 34111cb0ef41Sopenharmony_ci spilled.push_back(&vreg_data); 34121cb0ef41Sopenharmony_ci } 34131cb0ef41Sopenharmony_ci } 34141cb0ef41Sopenharmony_ci 34151cb0ef41Sopenharmony_ci // Sort the spill ranges by order of their first use to enable linear 34161cb0ef41Sopenharmony_ci // allocation of spill slots. 34171cb0ef41Sopenharmony_ci std::sort(spilled.begin(), spilled.end(), 34181cb0ef41Sopenharmony_ci [](const VirtualRegisterData* a, const VirtualRegisterData* b) { 34191cb0ef41Sopenharmony_ci return a->spill_range()->live_range().start() < 34201cb0ef41Sopenharmony_ci b->spill_range()->live_range().start(); 34211cb0ef41Sopenharmony_ci }); 34221cb0ef41Sopenharmony_ci 34231cb0ef41Sopenharmony_ci // Allocate a spill slot for each virtual register with a spill range. 34241cb0ef41Sopenharmony_ci MidTierSpillSlotAllocator allocator(data); 34251cb0ef41Sopenharmony_ci for (VirtualRegisterData* spill : spilled) { 34261cb0ef41Sopenharmony_ci allocator.Allocate(spill); 34271cb0ef41Sopenharmony_ci } 34281cb0ef41Sopenharmony_ci} 34291cb0ef41Sopenharmony_ci 34301cb0ef41Sopenharmony_ci// Populates reference maps for mid-tier register allocation. 34311cb0ef41Sopenharmony_ciclass MidTierReferenceMapPopulator final { 34321cb0ef41Sopenharmony_ci public: 34331cb0ef41Sopenharmony_ci explicit MidTierReferenceMapPopulator(MidTierRegisterAllocationData* data); 34341cb0ef41Sopenharmony_ci MidTierReferenceMapPopulator(const MidTierReferenceMapPopulator&) = delete; 34351cb0ef41Sopenharmony_ci MidTierReferenceMapPopulator& operator=(const MidTierReferenceMapPopulator&) = 34361cb0ef41Sopenharmony_ci delete; 34371cb0ef41Sopenharmony_ci 34381cb0ef41Sopenharmony_ci void RecordReferences(const VirtualRegisterData& virtual_register); 34391cb0ef41Sopenharmony_ci 34401cb0ef41Sopenharmony_ci private: 34411cb0ef41Sopenharmony_ci InstructionSequence* code() const { return data_->code(); } 34421cb0ef41Sopenharmony_ci 34431cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* const data_; 34441cb0ef41Sopenharmony_ci}; 34451cb0ef41Sopenharmony_ci 34461cb0ef41Sopenharmony_ciMidTierReferenceMapPopulator::MidTierReferenceMapPopulator( 34471cb0ef41Sopenharmony_ci MidTierRegisterAllocationData* data) 34481cb0ef41Sopenharmony_ci : data_(data) {} 34491cb0ef41Sopenharmony_ci 34501cb0ef41Sopenharmony_civoid MidTierReferenceMapPopulator::RecordReferences( 34511cb0ef41Sopenharmony_ci const VirtualRegisterData& virtual_register) { 34521cb0ef41Sopenharmony_ci if (!virtual_register.HasAllocatedSpillOperand()) return; 34531cb0ef41Sopenharmony_ci if (!code()->IsReference(virtual_register.vreg())) return; 34541cb0ef41Sopenharmony_ci 34551cb0ef41Sopenharmony_ci VirtualRegisterData::SpillRange* spill_range = virtual_register.spill_range(); 34561cb0ef41Sopenharmony_ci Range& live_range = spill_range->live_range(); 34571cb0ef41Sopenharmony_ci AllocatedOperand allocated = 34581cb0ef41Sopenharmony_ci *AllocatedOperand::cast(virtual_register.spill_operand()); 34591cb0ef41Sopenharmony_ci for (int instr_index : data_->reference_map_instructions()) { 34601cb0ef41Sopenharmony_ci if (instr_index > live_range.end() || instr_index < live_range.start()) 34611cb0ef41Sopenharmony_ci continue; 34621cb0ef41Sopenharmony_ci Instruction* instr = data_->code()->InstructionAt(instr_index); 34631cb0ef41Sopenharmony_ci DCHECK(instr->HasReferenceMap()); 34641cb0ef41Sopenharmony_ci 34651cb0ef41Sopenharmony_ci if (spill_range->IsLiveAt(instr_index, instr->block())) { 34661cb0ef41Sopenharmony_ci instr->reference_map()->RecordReference(allocated); 34671cb0ef41Sopenharmony_ci } 34681cb0ef41Sopenharmony_ci } 34691cb0ef41Sopenharmony_ci} 34701cb0ef41Sopenharmony_ci 34711cb0ef41Sopenharmony_civoid PopulateReferenceMaps(MidTierRegisterAllocationData* data) { 34721cb0ef41Sopenharmony_ci MidTierReferenceMapPopulator populator(data); 34731cb0ef41Sopenharmony_ci for (int vreg : data->spilled_virtual_registers()) { 34741cb0ef41Sopenharmony_ci populator.RecordReferences(data->VirtualRegisterDataFor(vreg)); 34751cb0ef41Sopenharmony_ci } 34761cb0ef41Sopenharmony_ci} 34771cb0ef41Sopenharmony_ci 34781cb0ef41Sopenharmony_ci} // namespace compiler 34791cb0ef41Sopenharmony_ci} // namespace internal 34801cb0ef41Sopenharmony_ci} // namespace v8 3481