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