11cb0ef41Sopenharmony_ci// Copyright 2022 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/maglev/maglev-regalloc.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/base/bits.h"
81cb0ef41Sopenharmony_ci#include "src/base/logging.h"
91cb0ef41Sopenharmony_ci#include "src/codegen/register.h"
101cb0ef41Sopenharmony_ci#include "src/codegen/reglist.h"
111cb0ef41Sopenharmony_ci#include "src/compiler/backend/instruction.h"
121cb0ef41Sopenharmony_ci#include "src/maglev/maglev-compilation-unit.h"
131cb0ef41Sopenharmony_ci#include "src/maglev/maglev-graph-labeller.h"
141cb0ef41Sopenharmony_ci#include "src/maglev/maglev-graph-printer.h"
151cb0ef41Sopenharmony_ci#include "src/maglev/maglev-graph-processor.h"
161cb0ef41Sopenharmony_ci#include "src/maglev/maglev-graph.h"
171cb0ef41Sopenharmony_ci#include "src/maglev/maglev-interpreter-frame-state.h"
181cb0ef41Sopenharmony_ci#include "src/maglev/maglev-ir.h"
191cb0ef41Sopenharmony_ci#include "src/maglev/maglev-regalloc-data.h"
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_cinamespace v8 {
221cb0ef41Sopenharmony_cinamespace internal {
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_cinamespace maglev {
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_cinamespace {
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ciconstexpr RegisterStateFlags initialized_node{true, false};
291cb0ef41Sopenharmony_ciconstexpr RegisterStateFlags initialized_merge{true, true};
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciusing BlockReverseIterator = std::vector<BasicBlock>::reverse_iterator;
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci// A target is a fallthrough of a control node if its ID is the next ID
341cb0ef41Sopenharmony_ci// after the control node.
351cb0ef41Sopenharmony_ci//
361cb0ef41Sopenharmony_ci// TODO(leszeks): Consider using the block iterator instead.
371cb0ef41Sopenharmony_cibool IsTargetOfNodeFallthrough(ControlNode* node, BasicBlock* target) {
381cb0ef41Sopenharmony_ci  return node->id() + 1 == target->first_id();
391cb0ef41Sopenharmony_ci}
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ciControlNode* NearestPostDominatingHole(ControlNode* node) {
421cb0ef41Sopenharmony_ci  // Conditional control nodes don't cause holes themselves. So, the nearest
431cb0ef41Sopenharmony_ci  // post-dominating hole is the conditional control node's next post-dominating
441cb0ef41Sopenharmony_ci  // hole.
451cb0ef41Sopenharmony_ci  if (node->Is<ConditionalControlNode>()) {
461cb0ef41Sopenharmony_ci    return node->next_post_dominating_hole();
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  // If the node is a Jump, it may be a hole, but only if it is not a
501cb0ef41Sopenharmony_ci  // fallthrough (jump to the immediately next block). Otherwise, it will point
511cb0ef41Sopenharmony_ci  // to the nearest post-dominating hole in its own "next" field.
521cb0ef41Sopenharmony_ci  if (Jump* jump = node->TryCast<Jump>()) {
531cb0ef41Sopenharmony_ci    if (IsTargetOfNodeFallthrough(jump, jump->target())) {
541cb0ef41Sopenharmony_ci      return jump->next_post_dominating_hole();
551cb0ef41Sopenharmony_ci    }
561cb0ef41Sopenharmony_ci  }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  return node;
591cb0ef41Sopenharmony_ci}
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_cibool IsLiveAtTarget(ValueNode* node, ControlNode* source, BasicBlock* target) {
621cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(node);
631cb0ef41Sopenharmony_ci  DCHECK(!node->is_dead());
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  // If we're looping, a value can only be live if it was live before the loop.
661cb0ef41Sopenharmony_ci  if (target->control_node()->id() <= source->id()) {
671cb0ef41Sopenharmony_ci    // Gap moves may already be inserted in the target, so skip over those.
681cb0ef41Sopenharmony_ci    return node->id() < target->FirstNonGapMoveId();
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci  // TODO(verwaest): This should be true but isn't because we don't yet
711cb0ef41Sopenharmony_ci  // eliminate dead code.
721cb0ef41Sopenharmony_ci  // DCHECK_GT(node->next_use, source->id());
731cb0ef41Sopenharmony_ci  // TODO(verwaest): Since we don't support deopt yet we can only deal with
741cb0ef41Sopenharmony_ci  // direct branches. Add support for holes.
751cb0ef41Sopenharmony_ci  return node->live_range().end >= target->first_id();
761cb0ef41Sopenharmony_ci}
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci}  // namespace
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ciStraightForwardRegisterAllocator::StraightForwardRegisterAllocator(
811cb0ef41Sopenharmony_ci    MaglevCompilationUnit* compilation_unit, Graph* graph)
821cb0ef41Sopenharmony_ci    : compilation_unit_(compilation_unit) {
831cb0ef41Sopenharmony_ci  ComputePostDominatingHoles(graph);
841cb0ef41Sopenharmony_ci  AllocateRegisters(graph);
851cb0ef41Sopenharmony_ci  graph->set_stack_slots(top_of_stack_);
861cb0ef41Sopenharmony_ci}
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ciStraightForwardRegisterAllocator::~StraightForwardRegisterAllocator() = default;
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci// Compute, for all forward control nodes (i.e. excluding Return and JumpLoop) a
911cb0ef41Sopenharmony_ci// tree of post-dominating control flow holes.
921cb0ef41Sopenharmony_ci//
931cb0ef41Sopenharmony_ci// Control flow which interrupts linear control flow fallthrough for basic
941cb0ef41Sopenharmony_ci// blocks is considered to introduce a control flow "hole".
951cb0ef41Sopenharmony_ci//
961cb0ef41Sopenharmony_ci//                   A──────┐                │
971cb0ef41Sopenharmony_ci//                   │ Jump │                │
981cb0ef41Sopenharmony_ci//                   └──┬───┘                │
991cb0ef41Sopenharmony_ci//                  {   │  B──────┐          │
1001cb0ef41Sopenharmony_ci//     Control flow {   │  │ Jump │          │ Linear control flow
1011cb0ef41Sopenharmony_ci//     hole after A {   │  └─┬────┘          │
1021cb0ef41Sopenharmony_ci//                  {   ▼    ▼ Fallthrough   │
1031cb0ef41Sopenharmony_ci//                     C──────┐              │
1041cb0ef41Sopenharmony_ci//                     │Return│              │
1051cb0ef41Sopenharmony_ci//                     └──────┘              ▼
1061cb0ef41Sopenharmony_ci//
1071cb0ef41Sopenharmony_ci// It is interesting, for each such hole, to know what the next hole will be
1081cb0ef41Sopenharmony_ci// that we will unconditionally reach on our way to an exit node. Such
1091cb0ef41Sopenharmony_ci// subsequent holes are in "post-dominators" of the current block.
1101cb0ef41Sopenharmony_ci//
1111cb0ef41Sopenharmony_ci// As an example, consider the following CFG, with the annotated holes. The
1121cb0ef41Sopenharmony_ci// post-dominating hole tree is the transitive closure of the post-dominator
1131cb0ef41Sopenharmony_ci// tree, up to nodes which are holes (in this example, A, D, F and H).
1141cb0ef41Sopenharmony_ci//
1151cb0ef41Sopenharmony_ci//                       CFG               Immediate       Post-dominating
1161cb0ef41Sopenharmony_ci//                                      post-dominators          holes
1171cb0ef41Sopenharmony_ci//                   A──────┐
1181cb0ef41Sopenharmony_ci//                   │ Jump │               A                 A
1191cb0ef41Sopenharmony_ci//                   └──┬───┘               │                 │
1201cb0ef41Sopenharmony_ci//                  {   │  B──────┐         │                 │
1211cb0ef41Sopenharmony_ci//     Control flow {   │  │ Jump │         │   B             │       B
1221cb0ef41Sopenharmony_ci//     hole after A {   │  └─┬────┘         │   │             │       │
1231cb0ef41Sopenharmony_ci//                  {   ▼    ▼              │   │             │       │
1241cb0ef41Sopenharmony_ci//                     C──────┐             │   │             │       │
1251cb0ef41Sopenharmony_ci//                     │Branch│             └►C◄┘             │   C   │
1261cb0ef41Sopenharmony_ci//                     └┬────┬┘               │               │   │   │
1271cb0ef41Sopenharmony_ci//                      ▼    │                │               │   │   │
1281cb0ef41Sopenharmony_ci//                   D──────┐│                │               │   │   │
1291cb0ef41Sopenharmony_ci//                   │ Jump ││              D │               │ D │   │
1301cb0ef41Sopenharmony_ci//                   └──┬───┘▼              │ │               │ │ │   │
1311cb0ef41Sopenharmony_ci//                  {   │  E──────┐         │ │               │ │ │   │
1321cb0ef41Sopenharmony_ci//     Control flow {   │  │ Jump │         │ │ E             │ │ │ E │
1331cb0ef41Sopenharmony_ci//     hole after D {   │  └─┬────┘         │ │ │             │ │ │ │ │
1341cb0ef41Sopenharmony_ci//                  {   ▼    ▼              │ │ │             │ │ │ │ │
1351cb0ef41Sopenharmony_ci//                     F──────┐             │ ▼ │             │ │ ▼ │ │
1361cb0ef41Sopenharmony_ci//                     │ Jump │             └►F◄┘             └─┴►F◄┴─┘
1371cb0ef41Sopenharmony_ci//                     └─────┬┘               │                   │
1381cb0ef41Sopenharmony_ci//                  {        │  G──────┐      │                   │
1391cb0ef41Sopenharmony_ci//     Control flow {        │  │ Jump │      │ G                 │ G
1401cb0ef41Sopenharmony_ci//     hole after F {        │  └─┬────┘      │ │                 │ │
1411cb0ef41Sopenharmony_ci//                  {        ▼    ▼           │ │                 │ │
1421cb0ef41Sopenharmony_ci//                          H──────┐          ▼ │                 ▼ │
1431cb0ef41Sopenharmony_ci//                          │Return│          H◄┘                 H◄┘
1441cb0ef41Sopenharmony_ci//                          └──────┘
1451cb0ef41Sopenharmony_ci//
1461cb0ef41Sopenharmony_ci// Since we only care about forward control, loop jumps are treated the same as
1471cb0ef41Sopenharmony_ci// returns -- they terminate the post-dominating hole chain.
1481cb0ef41Sopenharmony_ci//
1491cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::ComputePostDominatingHoles(
1501cb0ef41Sopenharmony_ci    Graph* graph) {
1511cb0ef41Sopenharmony_ci  // For all blocks, find the list of jumps that jump over code unreachable from
1521cb0ef41Sopenharmony_ci  // the block. Such a list of jumps terminates in return or jumploop.
1531cb0ef41Sopenharmony_ci  for (BasicBlock* block : base::Reversed(*graph)) {
1541cb0ef41Sopenharmony_ci    ControlNode* control = block->control_node();
1551cb0ef41Sopenharmony_ci    if (auto node = control->TryCast<Jump>()) {
1561cb0ef41Sopenharmony_ci      // If the current control node is a jump, prepend it to the list of jumps
1571cb0ef41Sopenharmony_ci      // at the target.
1581cb0ef41Sopenharmony_ci      control->set_next_post_dominating_hole(
1591cb0ef41Sopenharmony_ci          NearestPostDominatingHole(node->target()->control_node()));
1601cb0ef41Sopenharmony_ci    } else if (auto node = control->TryCast<ConditionalControlNode>()) {
1611cb0ef41Sopenharmony_ci      ControlNode* first =
1621cb0ef41Sopenharmony_ci          NearestPostDominatingHole(node->if_true()->control_node());
1631cb0ef41Sopenharmony_ci      ControlNode* second =
1641cb0ef41Sopenharmony_ci          NearestPostDominatingHole(node->if_false()->control_node());
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci      // Either find the merge-point of both branches, or the highest reachable
1671cb0ef41Sopenharmony_ci      // control-node of the longest branch after the last node of the shortest
1681cb0ef41Sopenharmony_ci      // branch.
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci      // As long as there's no merge-point.
1711cb0ef41Sopenharmony_ci      while (first != second) {
1721cb0ef41Sopenharmony_ci        // Walk the highest branch to find where it goes.
1731cb0ef41Sopenharmony_ci        if (first->id() > second->id()) std::swap(first, second);
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci        // If the first branch returns or jumps back, we've found highest
1761cb0ef41Sopenharmony_ci        // reachable control-node of the longest branch (the second control
1771cb0ef41Sopenharmony_ci        // node).
1781cb0ef41Sopenharmony_ci        if (first->Is<Return>() || first->Is<Deopt>() ||
1791cb0ef41Sopenharmony_ci            first->Is<JumpLoop>()) {
1801cb0ef41Sopenharmony_ci          control->set_next_post_dominating_hole(second);
1811cb0ef41Sopenharmony_ci          break;
1821cb0ef41Sopenharmony_ci        }
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci        // Continue one step along the highest branch. This may cross over the
1851cb0ef41Sopenharmony_ci        // lowest branch in case it returns or loops. If labelled blocks are
1861cb0ef41Sopenharmony_ci        // involved such swapping of which branch is the highest branch can
1871cb0ef41Sopenharmony_ci        // occur multiple times until a return/jumploop/merge is discovered.
1881cb0ef41Sopenharmony_ci        first = first->next_post_dominating_hole();
1891cb0ef41Sopenharmony_ci      }
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci      // Once the branches merged, we've found the gap-chain that's relevant for
1921cb0ef41Sopenharmony_ci      // the control node.
1931cb0ef41Sopenharmony_ci      control->set_next_post_dominating_hole(first);
1941cb0ef41Sopenharmony_ci    }
1951cb0ef41Sopenharmony_ci  }
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::PrintLiveRegs() const {
1991cb0ef41Sopenharmony_ci  bool first = true;
2001cb0ef41Sopenharmony_ci  for (Register reg : used_registers()) {
2011cb0ef41Sopenharmony_ci    ValueNode* node = GetRegisterValue(reg);
2021cb0ef41Sopenharmony_ci    if (first) {
2031cb0ef41Sopenharmony_ci      first = false;
2041cb0ef41Sopenharmony_ci    } else {
2051cb0ef41Sopenharmony_ci      printing_visitor_->os() << ", ";
2061cb0ef41Sopenharmony_ci    }
2071cb0ef41Sopenharmony_ci    printing_visitor_->os() << reg << "=v" << node->id();
2081cb0ef41Sopenharmony_ci  }
2091cb0ef41Sopenharmony_ci}
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::AllocateRegisters(Graph* graph) {
2121cb0ef41Sopenharmony_ci  if (FLAG_trace_maglev_regalloc) {
2131cb0ef41Sopenharmony_ci    printing_visitor_.reset(new MaglevPrintingVisitor(std::cout));
2141cb0ef41Sopenharmony_ci    printing_visitor_->PreProcessGraph(compilation_unit_, graph);
2151cb0ef41Sopenharmony_ci  }
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci  for (block_it_ = graph->begin(); block_it_ != graph->end(); ++block_it_) {
2181cb0ef41Sopenharmony_ci    BasicBlock* block = *block_it_;
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci    // Restore mergepoint state.
2211cb0ef41Sopenharmony_ci    if (block->has_state()) {
2221cb0ef41Sopenharmony_ci      InitializeRegisterValues(block->state()->register_state());
2231cb0ef41Sopenharmony_ci    }
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci    if (FLAG_trace_maglev_regalloc) {
2261cb0ef41Sopenharmony_ci      printing_visitor_->PreProcessBasicBlock(compilation_unit_, block);
2271cb0ef41Sopenharmony_ci      printing_visitor_->os() << "live regs: ";
2281cb0ef41Sopenharmony_ci      PrintLiveRegs();
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ci      ControlNode* control = NearestPostDominatingHole(block->control_node());
2311cb0ef41Sopenharmony_ci      if (!control->Is<JumpLoop>()) {
2321cb0ef41Sopenharmony_ci        printing_visitor_->os() << "\n[holes:";
2331cb0ef41Sopenharmony_ci        while (true) {
2341cb0ef41Sopenharmony_ci          if (control->Is<Jump>()) {
2351cb0ef41Sopenharmony_ci            BasicBlock* target = control->Cast<Jump>()->target();
2361cb0ef41Sopenharmony_ci            printing_visitor_->os()
2371cb0ef41Sopenharmony_ci                << " " << control->id() << "-" << target->first_id();
2381cb0ef41Sopenharmony_ci            control = control->next_post_dominating_hole();
2391cb0ef41Sopenharmony_ci            DCHECK_NOT_NULL(control);
2401cb0ef41Sopenharmony_ci            continue;
2411cb0ef41Sopenharmony_ci          } else if (control->Is<Return>()) {
2421cb0ef41Sopenharmony_ci            printing_visitor_->os() << " " << control->id() << ".";
2431cb0ef41Sopenharmony_ci            break;
2441cb0ef41Sopenharmony_ci          } else if (control->Is<Deopt>()) {
2451cb0ef41Sopenharmony_ci            printing_visitor_->os() << " " << control->id() << "✖️";
2461cb0ef41Sopenharmony_ci            break;
2471cb0ef41Sopenharmony_ci          } else if (control->Is<JumpLoop>()) {
2481cb0ef41Sopenharmony_ci            printing_visitor_->os() << " " << control->id() << "↰";
2491cb0ef41Sopenharmony_ci            break;
2501cb0ef41Sopenharmony_ci          }
2511cb0ef41Sopenharmony_ci          UNREACHABLE();
2521cb0ef41Sopenharmony_ci        }
2531cb0ef41Sopenharmony_ci        printing_visitor_->os() << "]";
2541cb0ef41Sopenharmony_ci      }
2551cb0ef41Sopenharmony_ci      printing_visitor_->os() << std::endl;
2561cb0ef41Sopenharmony_ci    }
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci    // Activate phis.
2591cb0ef41Sopenharmony_ci    if (block->has_phi()) {
2601cb0ef41Sopenharmony_ci      // Firstly, make the phi live, and try to assign it to an input
2611cb0ef41Sopenharmony_ci      // location.
2621cb0ef41Sopenharmony_ci      for (Phi* phi : *block->phis()) {
2631cb0ef41Sopenharmony_ci        phi->SetNoSpillOrHint();
2641cb0ef41Sopenharmony_ci        TryAllocateToInput(phi);
2651cb0ef41Sopenharmony_ci      }
2661cb0ef41Sopenharmony_ci      // Secondly try to assign the phi to a free register.
2671cb0ef41Sopenharmony_ci      for (Phi* phi : *block->phis()) {
2681cb0ef41Sopenharmony_ci        if (phi->result().operand().IsAllocated()) continue;
2691cb0ef41Sopenharmony_ci        compiler::InstructionOperand allocation = TryAllocateRegister(phi);
2701cb0ef41Sopenharmony_ci        if (allocation.IsAllocated()) {
2711cb0ef41Sopenharmony_ci          phi->result().SetAllocated(
2721cb0ef41Sopenharmony_ci              compiler::AllocatedOperand::cast(allocation));
2731cb0ef41Sopenharmony_ci          if (FLAG_trace_maglev_regalloc) {
2741cb0ef41Sopenharmony_ci            printing_visitor_->Process(
2751cb0ef41Sopenharmony_ci                phi, ProcessingState(compilation_unit_, block_it_));
2761cb0ef41Sopenharmony_ci            printing_visitor_->os()
2771cb0ef41Sopenharmony_ci                << "phi (new reg) " << phi->result().operand() << std::endl;
2781cb0ef41Sopenharmony_ci          }
2791cb0ef41Sopenharmony_ci        }
2801cb0ef41Sopenharmony_ci      }
2811cb0ef41Sopenharmony_ci      // Finally just use a stack slot.
2821cb0ef41Sopenharmony_ci      for (Phi* phi : *block->phis()) {
2831cb0ef41Sopenharmony_ci        if (phi->result().operand().IsAllocated()) continue;
2841cb0ef41Sopenharmony_ci        AllocateSpillSlot(phi);
2851cb0ef41Sopenharmony_ci        // TODO(verwaest): Will this be used at all?
2861cb0ef41Sopenharmony_ci        phi->result().SetAllocated(phi->spill_slot());
2871cb0ef41Sopenharmony_ci        if (FLAG_trace_maglev_regalloc) {
2881cb0ef41Sopenharmony_ci          printing_visitor_->Process(
2891cb0ef41Sopenharmony_ci              phi, ProcessingState(compilation_unit_, block_it_));
2901cb0ef41Sopenharmony_ci          printing_visitor_->os()
2911cb0ef41Sopenharmony_ci              << "phi (stack) " << phi->result().operand() << std::endl;
2921cb0ef41Sopenharmony_ci        }
2931cb0ef41Sopenharmony_ci      }
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci      if (FLAG_trace_maglev_regalloc) {
2961cb0ef41Sopenharmony_ci        printing_visitor_->os() << "live regs: ";
2971cb0ef41Sopenharmony_ci        PrintLiveRegs();
2981cb0ef41Sopenharmony_ci        printing_visitor_->os() << std::endl;
2991cb0ef41Sopenharmony_ci      }
3001cb0ef41Sopenharmony_ci    }
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci    node_it_ = block->nodes().begin();
3031cb0ef41Sopenharmony_ci    for (; node_it_ != block->nodes().end(); ++node_it_) {
3041cb0ef41Sopenharmony_ci      AllocateNode(*node_it_);
3051cb0ef41Sopenharmony_ci    }
3061cb0ef41Sopenharmony_ci    AllocateControlNode(block->control_node(), block);
3071cb0ef41Sopenharmony_ci  }
3081cb0ef41Sopenharmony_ci}
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::UpdateUse(
3111cb0ef41Sopenharmony_ci    ValueNode* node, InputLocation* input_location) {
3121cb0ef41Sopenharmony_ci  DCHECK(!node->is_dead());
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci  // Update the next use.
3151cb0ef41Sopenharmony_ci  node->set_next_use(input_location->next_use_id());
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_ci  if (!node->is_dead()) return;
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci  // If a value is dead, make sure it's cleared.
3201cb0ef41Sopenharmony_ci  FreeRegisters(node);
3211cb0ef41Sopenharmony_ci}
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::UpdateUse(
3241cb0ef41Sopenharmony_ci    const EagerDeoptInfo& deopt_info) {
3251cb0ef41Sopenharmony_ci  const CompactInterpreterFrameState* checkpoint_state =
3261cb0ef41Sopenharmony_ci      deopt_info.state.register_frame;
3271cb0ef41Sopenharmony_ci  int index = 0;
3281cb0ef41Sopenharmony_ci  checkpoint_state->ForEachValue(
3291cb0ef41Sopenharmony_ci      *compilation_unit_, [&](ValueNode* node, interpreter::Register reg) {
3301cb0ef41Sopenharmony_ci        InputLocation* input = &deopt_info.input_locations[index++];
3311cb0ef41Sopenharmony_ci        input->InjectAllocated(node->allocation());
3321cb0ef41Sopenharmony_ci        UpdateUse(node, input);
3331cb0ef41Sopenharmony_ci      });
3341cb0ef41Sopenharmony_ci}
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::UpdateUse(
3371cb0ef41Sopenharmony_ci    const LazyDeoptInfo& deopt_info) {
3381cb0ef41Sopenharmony_ci  const CompactInterpreterFrameState* checkpoint_state =
3391cb0ef41Sopenharmony_ci      deopt_info.state.register_frame;
3401cb0ef41Sopenharmony_ci  int index = 0;
3411cb0ef41Sopenharmony_ci  checkpoint_state->ForEachValue(
3421cb0ef41Sopenharmony_ci      *compilation_unit_, [&](ValueNode* node, interpreter::Register reg) {
3431cb0ef41Sopenharmony_ci        // Skip over the result location.
3441cb0ef41Sopenharmony_ci        if (reg == deopt_info.result_location) return;
3451cb0ef41Sopenharmony_ci        InputLocation* input = &deopt_info.input_locations[index++];
3461cb0ef41Sopenharmony_ci        input->InjectAllocated(node->allocation());
3471cb0ef41Sopenharmony_ci        UpdateUse(node, input);
3481cb0ef41Sopenharmony_ci      });
3491cb0ef41Sopenharmony_ci}
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::AllocateNode(Node* node) {
3521cb0ef41Sopenharmony_ci  for (Input& input : *node) AssignInput(input);
3531cb0ef41Sopenharmony_ci  AssignTemporaries(node);
3541cb0ef41Sopenharmony_ci  if (node->properties().can_eager_deopt()) {
3551cb0ef41Sopenharmony_ci    UpdateUse(*node->eager_deopt_info());
3561cb0ef41Sopenharmony_ci  }
3571cb0ef41Sopenharmony_ci  for (Input& input : *node) UpdateUse(&input);
3581cb0ef41Sopenharmony_ci
3591cb0ef41Sopenharmony_ci  if (node->properties().is_call()) SpillAndClearRegisters();
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci  // Allocate node output.
3621cb0ef41Sopenharmony_ci  if (node->Is<ValueNode>()) AllocateNodeResult(node->Cast<ValueNode>());
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci  // Lazy deopts are semantically after the node, so update them last.
3651cb0ef41Sopenharmony_ci  if (node->properties().can_lazy_deopt()) {
3661cb0ef41Sopenharmony_ci    UpdateUse(*node->lazy_deopt_info());
3671cb0ef41Sopenharmony_ci  }
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_ci  if (FLAG_trace_maglev_regalloc) {
3701cb0ef41Sopenharmony_ci    printing_visitor_->Process(node,
3711cb0ef41Sopenharmony_ci                               ProcessingState(compilation_unit_, block_it_));
3721cb0ef41Sopenharmony_ci    printing_visitor_->os() << "live regs: ";
3731cb0ef41Sopenharmony_ci    PrintLiveRegs();
3741cb0ef41Sopenharmony_ci    printing_visitor_->os() << "\n";
3751cb0ef41Sopenharmony_ci  }
3761cb0ef41Sopenharmony_ci}
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::AllocateNodeResult(ValueNode* node) {
3791cb0ef41Sopenharmony_ci  DCHECK(!node->Is<Phi>());
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  node->SetNoSpillOrHint();
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci  compiler::UnallocatedOperand operand =
3841cb0ef41Sopenharmony_ci      compiler::UnallocatedOperand::cast(node->result().operand());
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci  if (operand.basic_policy() == compiler::UnallocatedOperand::FIXED_SLOT) {
3871cb0ef41Sopenharmony_ci    DCHECK(node->Is<InitialValue>());
3881cb0ef41Sopenharmony_ci    DCHECK_LT(operand.fixed_slot_index(), 0);
3891cb0ef41Sopenharmony_ci    // Set the stack slot to exactly where the value is.
3901cb0ef41Sopenharmony_ci    compiler::AllocatedOperand location(compiler::AllocatedOperand::STACK_SLOT,
3911cb0ef41Sopenharmony_ci                                        MachineRepresentation::kTagged,
3921cb0ef41Sopenharmony_ci                                        operand.fixed_slot_index());
3931cb0ef41Sopenharmony_ci    node->result().SetAllocated(location);
3941cb0ef41Sopenharmony_ci    node->Spill(location);
3951cb0ef41Sopenharmony_ci    return;
3961cb0ef41Sopenharmony_ci  }
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  switch (operand.extended_policy()) {
3991cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::FIXED_REGISTER: {
4001cb0ef41Sopenharmony_ci      Register r = Register::from_code(operand.fixed_register_index());
4011cb0ef41Sopenharmony_ci      node->result().SetAllocated(ForceAllocate(r, node));
4021cb0ef41Sopenharmony_ci      break;
4031cb0ef41Sopenharmony_ci    }
4041cb0ef41Sopenharmony_ci
4051cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::MUST_HAVE_REGISTER:
4061cb0ef41Sopenharmony_ci      node->result().SetAllocated(AllocateRegister(node));
4071cb0ef41Sopenharmony_ci      break;
4081cb0ef41Sopenharmony_ci
4091cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::SAME_AS_INPUT: {
4101cb0ef41Sopenharmony_ci      Input& input = node->input(operand.input_index());
4111cb0ef41Sopenharmony_ci      Register r = input.AssignedRegister();
4121cb0ef41Sopenharmony_ci      node->result().SetAllocated(ForceAllocate(r, node));
4131cb0ef41Sopenharmony_ci      break;
4141cb0ef41Sopenharmony_ci    }
4151cb0ef41Sopenharmony_ci
4161cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT:
4171cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::NONE:
4181cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::FIXED_FP_REGISTER:
4191cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::MUST_HAVE_SLOT:
4201cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::REGISTER_OR_SLOT:
4211cb0ef41Sopenharmony_ci      UNREACHABLE();
4221cb0ef41Sopenharmony_ci  }
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_ci  // Immediately kill the register use if the node doesn't have a valid
4251cb0ef41Sopenharmony_ci  // live-range.
4261cb0ef41Sopenharmony_ci  // TODO(verwaest): Remove once we can avoid allocating such registers.
4271cb0ef41Sopenharmony_ci  if (!node->has_valid_live_range() &&
4281cb0ef41Sopenharmony_ci      node->result().operand().IsAnyRegister()) {
4291cb0ef41Sopenharmony_ci    DCHECK(node->has_register());
4301cb0ef41Sopenharmony_ci    FreeRegisters(node);
4311cb0ef41Sopenharmony_ci    DCHECK(!node->has_register());
4321cb0ef41Sopenharmony_ci    DCHECK(node->is_dead());
4331cb0ef41Sopenharmony_ci  }
4341cb0ef41Sopenharmony_ci}
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::DropRegisterValue(Register reg) {
4371cb0ef41Sopenharmony_ci  // The register should not already be free.
4381cb0ef41Sopenharmony_ci  DCHECK(!free_registers_.has(reg));
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  ValueNode* node = GetRegisterValue(reg);
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci  // Remove the register from the node's list.
4431cb0ef41Sopenharmony_ci  node->RemoveRegister(reg);
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci  // Return if the removed value already has another register or is spilled.
4461cb0ef41Sopenharmony_ci  if (node->has_register() || node->is_spilled()) return;
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci  // Try to move the value to another register.
4491cb0ef41Sopenharmony_ci  if (free_registers_ != kEmptyRegList) {
4501cb0ef41Sopenharmony_ci    Register target_reg = free_registers_.PopFirst();
4511cb0ef41Sopenharmony_ci    SetRegister(target_reg, node);
4521cb0ef41Sopenharmony_ci    // Emit a gapmove.
4531cb0ef41Sopenharmony_ci    compiler::AllocatedOperand source(compiler::LocationOperand::REGISTER,
4541cb0ef41Sopenharmony_ci                                      MachineRepresentation::kTagged,
4551cb0ef41Sopenharmony_ci                                      reg.code());
4561cb0ef41Sopenharmony_ci    compiler::AllocatedOperand target(compiler::LocationOperand::REGISTER,
4571cb0ef41Sopenharmony_ci                                      MachineRepresentation::kTagged,
4581cb0ef41Sopenharmony_ci                                      target_reg.code());
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci    if (FLAG_trace_maglev_regalloc) {
4611cb0ef41Sopenharmony_ci      printing_visitor_->os()
4621cb0ef41Sopenharmony_ci          << "gap move: " << PrintNodeLabel(graph_labeller(), node) << ": "
4631cb0ef41Sopenharmony_ci          << target << " ← " << source << std::endl;
4641cb0ef41Sopenharmony_ci    }
4651cb0ef41Sopenharmony_ci    AddMoveBeforeCurrentNode(source, target);
4661cb0ef41Sopenharmony_ci    return;
4671cb0ef41Sopenharmony_ci  }
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ci  // If all else fails, spill the value.
4701cb0ef41Sopenharmony_ci  Spill(node);
4711cb0ef41Sopenharmony_ci}
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::InitializeConditionalBranchRegisters(
4741cb0ef41Sopenharmony_ci    ConditionalControlNode* control_node, BasicBlock* target) {
4751cb0ef41Sopenharmony_ci  if (target->is_empty_block()) {
4761cb0ef41Sopenharmony_ci    // Jumping over an empty block, so we're in fact merging.
4771cb0ef41Sopenharmony_ci    Jump* jump = target->control_node()->Cast<Jump>();
4781cb0ef41Sopenharmony_ci    target = jump->target();
4791cb0ef41Sopenharmony_ci    return MergeRegisterValues(control_node, target, jump->predecessor_id());
4801cb0ef41Sopenharmony_ci  }
4811cb0ef41Sopenharmony_ci  if (target->has_state()) {
4821cb0ef41Sopenharmony_ci    // Not a fall-through branch, copy the state over.
4831cb0ef41Sopenharmony_ci    return InitializeBranchTargetRegisterValues(control_node, target);
4841cb0ef41Sopenharmony_ci  }
4851cb0ef41Sopenharmony_ci  // Clear dead fall-through registers.
4861cb0ef41Sopenharmony_ci  DCHECK_EQ(control_node->id() + 1, target->first_id());
4871cb0ef41Sopenharmony_ci  RegList registers = used_registers();
4881cb0ef41Sopenharmony_ci  while (registers != kEmptyRegList) {
4891cb0ef41Sopenharmony_ci    Register reg = registers.PopFirst();
4901cb0ef41Sopenharmony_ci    ValueNode* node = GetRegisterValue(reg);
4911cb0ef41Sopenharmony_ci    if (!IsLiveAtTarget(node, control_node, target)) {
4921cb0ef41Sopenharmony_ci      FreeRegisters(node);
4931cb0ef41Sopenharmony_ci      // Update the registers we're visiting to avoid revisiting this node.
4941cb0ef41Sopenharmony_ci      registers.clear(free_registers_);
4951cb0ef41Sopenharmony_ci    }
4961cb0ef41Sopenharmony_ci  }
4971cb0ef41Sopenharmony_ci}
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::AllocateControlNode(ControlNode* node,
5001cb0ef41Sopenharmony_ci                                                           BasicBlock* block) {
5011cb0ef41Sopenharmony_ci  for (Input& input : *node) AssignInput(input);
5021cb0ef41Sopenharmony_ci  AssignTemporaries(node);
5031cb0ef41Sopenharmony_ci  if (node->properties().can_eager_deopt()) {
5041cb0ef41Sopenharmony_ci    UpdateUse(*node->eager_deopt_info());
5051cb0ef41Sopenharmony_ci  }
5061cb0ef41Sopenharmony_ci  for (Input& input : *node) UpdateUse(&input);
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci  if (node->properties().is_call()) SpillAndClearRegisters();
5091cb0ef41Sopenharmony_ci
5101cb0ef41Sopenharmony_ci  // Inject allocation into target phis.
5111cb0ef41Sopenharmony_ci  if (auto unconditional = node->TryCast<UnconditionalControlNode>()) {
5121cb0ef41Sopenharmony_ci    BasicBlock* target = unconditional->target();
5131cb0ef41Sopenharmony_ci    if (target->has_phi()) {
5141cb0ef41Sopenharmony_ci      Phi::List* phis = target->phis();
5151cb0ef41Sopenharmony_ci      for (Phi* phi : *phis) {
5161cb0ef41Sopenharmony_ci        Input& input = phi->input(block->predecessor_id());
5171cb0ef41Sopenharmony_ci        input.InjectAllocated(input.node()->allocation());
5181cb0ef41Sopenharmony_ci      }
5191cb0ef41Sopenharmony_ci      for (Phi* phi : *phis) UpdateUse(&phi->input(block->predecessor_id()));
5201cb0ef41Sopenharmony_ci    }
5211cb0ef41Sopenharmony_ci  }
5221cb0ef41Sopenharmony_ci
5231cb0ef41Sopenharmony_ci  // TODO(verwaest): This isn't a good idea :)
5241cb0ef41Sopenharmony_ci  if (node->properties().can_eager_deopt()) SpillRegisters();
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci  // Merge register values. Values only flowing into phis and not being
5271cb0ef41Sopenharmony_ci  // independently live will be killed as part of the merge.
5281cb0ef41Sopenharmony_ci  if (auto unconditional = node->TryCast<UnconditionalControlNode>()) {
5291cb0ef41Sopenharmony_ci    // Empty blocks are immediately merged at the control of their predecessor.
5301cb0ef41Sopenharmony_ci    if (!block->is_empty_block()) {
5311cb0ef41Sopenharmony_ci      MergeRegisterValues(unconditional, unconditional->target(),
5321cb0ef41Sopenharmony_ci                          block->predecessor_id());
5331cb0ef41Sopenharmony_ci    }
5341cb0ef41Sopenharmony_ci  } else if (auto conditional = node->TryCast<ConditionalControlNode>()) {
5351cb0ef41Sopenharmony_ci    InitializeConditionalBranchRegisters(conditional, conditional->if_true());
5361cb0ef41Sopenharmony_ci    InitializeConditionalBranchRegisters(conditional, conditional->if_false());
5371cb0ef41Sopenharmony_ci  }
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_ci  if (FLAG_trace_maglev_regalloc) {
5401cb0ef41Sopenharmony_ci    printing_visitor_->Process(node,
5411cb0ef41Sopenharmony_ci                               ProcessingState(compilation_unit_, block_it_));
5421cb0ef41Sopenharmony_ci  }
5431cb0ef41Sopenharmony_ci}
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::TryAllocateToInput(Phi* phi) {
5461cb0ef41Sopenharmony_ci  // Try allocate phis to a register used by any of the inputs.
5471cb0ef41Sopenharmony_ci  for (Input& input : *phi) {
5481cb0ef41Sopenharmony_ci    if (input.operand().IsRegister()) {
5491cb0ef41Sopenharmony_ci      Register reg = input.AssignedRegister();
5501cb0ef41Sopenharmony_ci      if (free_registers_.has(reg)) {
5511cb0ef41Sopenharmony_ci        phi->result().SetAllocated(ForceAllocate(reg, phi));
5521cb0ef41Sopenharmony_ci        if (FLAG_trace_maglev_regalloc) {
5531cb0ef41Sopenharmony_ci          printing_visitor_->Process(
5541cb0ef41Sopenharmony_ci              phi, ProcessingState(compilation_unit_, block_it_));
5551cb0ef41Sopenharmony_ci          printing_visitor_->os()
5561cb0ef41Sopenharmony_ci              << "phi (reuse) " << input.operand() << std::endl;
5571cb0ef41Sopenharmony_ci        }
5581cb0ef41Sopenharmony_ci        return;
5591cb0ef41Sopenharmony_ci      }
5601cb0ef41Sopenharmony_ci    }
5611cb0ef41Sopenharmony_ci  }
5621cb0ef41Sopenharmony_ci}
5631cb0ef41Sopenharmony_ci
5641cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::AddMoveBeforeCurrentNode(
5651cb0ef41Sopenharmony_ci    compiler::AllocatedOperand source, compiler::AllocatedOperand target) {
5661cb0ef41Sopenharmony_ci  GapMove* gap_move =
5671cb0ef41Sopenharmony_ci      Node::New<GapMove>(compilation_unit_->zone(), {}, source, target);
5681cb0ef41Sopenharmony_ci  if (compilation_unit_->has_graph_labeller()) {
5691cb0ef41Sopenharmony_ci    graph_labeller()->RegisterNode(gap_move);
5701cb0ef41Sopenharmony_ci  }
5711cb0ef41Sopenharmony_ci  if (*node_it_ == nullptr) {
5721cb0ef41Sopenharmony_ci    // We're at the control node, so append instead.
5731cb0ef41Sopenharmony_ci    (*block_it_)->nodes().Add(gap_move);
5741cb0ef41Sopenharmony_ci    node_it_ = (*block_it_)->nodes().end();
5751cb0ef41Sopenharmony_ci  } else {
5761cb0ef41Sopenharmony_ci    DCHECK_NE(node_it_, (*block_it_)->nodes().end());
5771cb0ef41Sopenharmony_ci    node_it_.InsertBefore(gap_move);
5781cb0ef41Sopenharmony_ci  }
5791cb0ef41Sopenharmony_ci}
5801cb0ef41Sopenharmony_ci
5811cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::Spill(ValueNode* node) {
5821cb0ef41Sopenharmony_ci  if (node->is_spilled()) return;
5831cb0ef41Sopenharmony_ci  AllocateSpillSlot(node);
5841cb0ef41Sopenharmony_ci  if (FLAG_trace_maglev_regalloc) {
5851cb0ef41Sopenharmony_ci    printing_visitor_->os()
5861cb0ef41Sopenharmony_ci        << "spill: " << node->spill_slot() << " ← "
5871cb0ef41Sopenharmony_ci        << PrintNodeLabel(graph_labeller(), node) << std::endl;
5881cb0ef41Sopenharmony_ci  }
5891cb0ef41Sopenharmony_ci}
5901cb0ef41Sopenharmony_ci
5911cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::AssignInput(Input& input) {
5921cb0ef41Sopenharmony_ci  compiler::UnallocatedOperand operand =
5931cb0ef41Sopenharmony_ci      compiler::UnallocatedOperand::cast(input.operand());
5941cb0ef41Sopenharmony_ci  ValueNode* node = input.node();
5951cb0ef41Sopenharmony_ci  compiler::AllocatedOperand location = node->allocation();
5961cb0ef41Sopenharmony_ci
5971cb0ef41Sopenharmony_ci  switch (operand.extended_policy()) {
5981cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::REGISTER_OR_SLOT:
5991cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT:
6001cb0ef41Sopenharmony_ci      input.SetAllocated(location);
6011cb0ef41Sopenharmony_ci      break;
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::FIXED_REGISTER: {
6041cb0ef41Sopenharmony_ci      Register reg = Register::from_code(operand.fixed_register_index());
6051cb0ef41Sopenharmony_ci      input.SetAllocated(ForceAllocate(reg, node));
6061cb0ef41Sopenharmony_ci      break;
6071cb0ef41Sopenharmony_ci    }
6081cb0ef41Sopenharmony_ci
6091cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::MUST_HAVE_REGISTER:
6101cb0ef41Sopenharmony_ci      if (location.IsAnyRegister()) {
6111cb0ef41Sopenharmony_ci        input.SetAllocated(location);
6121cb0ef41Sopenharmony_ci      } else {
6131cb0ef41Sopenharmony_ci        input.SetAllocated(AllocateRegister(node));
6141cb0ef41Sopenharmony_ci      }
6151cb0ef41Sopenharmony_ci      break;
6161cb0ef41Sopenharmony_ci
6171cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::FIXED_FP_REGISTER:
6181cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::SAME_AS_INPUT:
6191cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::NONE:
6201cb0ef41Sopenharmony_ci    case compiler::UnallocatedOperand::MUST_HAVE_SLOT:
6211cb0ef41Sopenharmony_ci      UNREACHABLE();
6221cb0ef41Sopenharmony_ci  }
6231cb0ef41Sopenharmony_ci
6241cb0ef41Sopenharmony_ci  compiler::AllocatedOperand allocated =
6251cb0ef41Sopenharmony_ci      compiler::AllocatedOperand::cast(input.operand());
6261cb0ef41Sopenharmony_ci  if (location != allocated) {
6271cb0ef41Sopenharmony_ci    if (FLAG_trace_maglev_regalloc) {
6281cb0ef41Sopenharmony_ci      printing_visitor_->os()
6291cb0ef41Sopenharmony_ci          << "gap move: " << allocated << " ← " << location << std::endl;
6301cb0ef41Sopenharmony_ci    }
6311cb0ef41Sopenharmony_ci    AddMoveBeforeCurrentNode(location, allocated);
6321cb0ef41Sopenharmony_ci  }
6331cb0ef41Sopenharmony_ci}
6341cb0ef41Sopenharmony_ci
6351cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::SpillRegisters() {
6361cb0ef41Sopenharmony_ci  for (Register reg : used_registers()) {
6371cb0ef41Sopenharmony_ci    ValueNode* node = GetRegisterValue(reg);
6381cb0ef41Sopenharmony_ci    Spill(node);
6391cb0ef41Sopenharmony_ci  }
6401cb0ef41Sopenharmony_ci}
6411cb0ef41Sopenharmony_ci
6421cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::SpillAndClearRegisters() {
6431cb0ef41Sopenharmony_ci  while (used_registers() != kEmptyRegList) {
6441cb0ef41Sopenharmony_ci    Register reg = used_registers().first();
6451cb0ef41Sopenharmony_ci    ValueNode* node = GetRegisterValue(reg);
6461cb0ef41Sopenharmony_ci    Spill(node);
6471cb0ef41Sopenharmony_ci    FreeRegisters(node);
6481cb0ef41Sopenharmony_ci    DCHECK(!used_registers().has(reg));
6491cb0ef41Sopenharmony_ci  }
6501cb0ef41Sopenharmony_ci}
6511cb0ef41Sopenharmony_ci
6521cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::AllocateSpillSlot(ValueNode* node) {
6531cb0ef41Sopenharmony_ci  DCHECK(!node->is_spilled());
6541cb0ef41Sopenharmony_ci  uint32_t free_slot = top_of_stack_++;
6551cb0ef41Sopenharmony_ci  compilation_unit_->push_stack_value_repr(node->value_representation());
6561cb0ef41Sopenharmony_ci  node->Spill(compiler::AllocatedOperand(compiler::AllocatedOperand::STACK_SLOT,
6571cb0ef41Sopenharmony_ci                                         MachineRepresentation::kTagged,
6581cb0ef41Sopenharmony_ci                                         free_slot));
6591cb0ef41Sopenharmony_ci}
6601cb0ef41Sopenharmony_ci
6611cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::FreeSomeRegister() {
6621cb0ef41Sopenharmony_ci  int furthest_use = 0;
6631cb0ef41Sopenharmony_ci  Register best = Register::no_reg();
6641cb0ef41Sopenharmony_ci  for (Register reg : used_registers()) {
6651cb0ef41Sopenharmony_ci    ValueNode* value = GetRegisterValue(reg);
6661cb0ef41Sopenharmony_ci    // The cheapest register to clear is a register containing a value that's
6671cb0ef41Sopenharmony_ci    // contained in another register as well.
6681cb0ef41Sopenharmony_ci    if (value->num_registers() > 1) {
6691cb0ef41Sopenharmony_ci      best = reg;
6701cb0ef41Sopenharmony_ci      break;
6711cb0ef41Sopenharmony_ci    }
6721cb0ef41Sopenharmony_ci    int use = value->next_use();
6731cb0ef41Sopenharmony_ci    if (use > furthest_use) {
6741cb0ef41Sopenharmony_ci      furthest_use = use;
6751cb0ef41Sopenharmony_ci      best = reg;
6761cb0ef41Sopenharmony_ci    }
6771cb0ef41Sopenharmony_ci  }
6781cb0ef41Sopenharmony_ci  DCHECK(best.is_valid());
6791cb0ef41Sopenharmony_ci  DropRegisterValue(best);
6801cb0ef41Sopenharmony_ci  FreeRegister(best);
6811cb0ef41Sopenharmony_ci}
6821cb0ef41Sopenharmony_ci
6831cb0ef41Sopenharmony_cicompiler::AllocatedOperand StraightForwardRegisterAllocator::AllocateRegister(
6841cb0ef41Sopenharmony_ci    ValueNode* node) {
6851cb0ef41Sopenharmony_ci  if (free_registers_ == kEmptyRegList) FreeSomeRegister();
6861cb0ef41Sopenharmony_ci  compiler::InstructionOperand allocation = TryAllocateRegister(node);
6871cb0ef41Sopenharmony_ci  DCHECK(allocation.IsAllocated());
6881cb0ef41Sopenharmony_ci  return compiler::AllocatedOperand::cast(allocation);
6891cb0ef41Sopenharmony_ci}
6901cb0ef41Sopenharmony_ci
6911cb0ef41Sopenharmony_cicompiler::AllocatedOperand StraightForwardRegisterAllocator::ForceAllocate(
6921cb0ef41Sopenharmony_ci    Register reg, ValueNode* node) {
6931cb0ef41Sopenharmony_ci  if (free_registers_.has(reg)) {
6941cb0ef41Sopenharmony_ci    // If it's already free, remove it from the free list.
6951cb0ef41Sopenharmony_ci    free_registers_.clear(reg);
6961cb0ef41Sopenharmony_ci  } else if (GetRegisterValue(reg) == node) {
6971cb0ef41Sopenharmony_ci    return compiler::AllocatedOperand(compiler::LocationOperand::REGISTER,
6981cb0ef41Sopenharmony_ci                                      MachineRepresentation::kTagged,
6991cb0ef41Sopenharmony_ci                                      reg.code());
7001cb0ef41Sopenharmony_ci  } else {
7011cb0ef41Sopenharmony_ci    DropRegisterValue(reg);
7021cb0ef41Sopenharmony_ci  }
7031cb0ef41Sopenharmony_ci#ifdef DEBUG
7041cb0ef41Sopenharmony_ci  DCHECK(!free_registers_.has(reg));
7051cb0ef41Sopenharmony_ci#endif
7061cb0ef41Sopenharmony_ci  SetRegister(reg, node);
7071cb0ef41Sopenharmony_ci  return compiler::AllocatedOperand(compiler::LocationOperand::REGISTER,
7081cb0ef41Sopenharmony_ci                                    MachineRepresentation::kTagged, reg.code());
7091cb0ef41Sopenharmony_ci}
7101cb0ef41Sopenharmony_ci
7111cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::SetRegister(Register reg,
7121cb0ef41Sopenharmony_ci                                                   ValueNode* node) {
7131cb0ef41Sopenharmony_ci  DCHECK(!free_registers_.has(reg));
7141cb0ef41Sopenharmony_ci  register_values_[reg.code()] = node;
7151cb0ef41Sopenharmony_ci  node->AddRegister(reg);
7161cb0ef41Sopenharmony_ci}
7171cb0ef41Sopenharmony_ci
7181cb0ef41Sopenharmony_cicompiler::InstructionOperand
7191cb0ef41Sopenharmony_ciStraightForwardRegisterAllocator::TryAllocateRegister(ValueNode* node) {
7201cb0ef41Sopenharmony_ci  if (free_registers_ == kEmptyRegList) return compiler::InstructionOperand();
7211cb0ef41Sopenharmony_ci  Register reg = free_registers_.PopFirst();
7221cb0ef41Sopenharmony_ci
7231cb0ef41Sopenharmony_ci  // Allocation succeeded. This might have found an existing allocation.
7241cb0ef41Sopenharmony_ci  // Simply update the state anyway.
7251cb0ef41Sopenharmony_ci  SetRegister(reg, node);
7261cb0ef41Sopenharmony_ci  return compiler::AllocatedOperand(compiler::LocationOperand::REGISTER,
7271cb0ef41Sopenharmony_ci                                    MachineRepresentation::kTagged, reg.code());
7281cb0ef41Sopenharmony_ci}
7291cb0ef41Sopenharmony_ci
7301cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::AssignTemporaries(NodeBase* node) {
7311cb0ef41Sopenharmony_ci  int num_temporaries_needed = node->num_temporaries_needed();
7321cb0ef41Sopenharmony_ci  int num_free_registers = free_registers_.Count();
7331cb0ef41Sopenharmony_ci
7341cb0ef41Sopenharmony_ci  // Free extra registers if necessary.
7351cb0ef41Sopenharmony_ci  for (int i = num_free_registers; i < num_temporaries_needed; ++i) {
7361cb0ef41Sopenharmony_ci    FreeSomeRegister();
7371cb0ef41Sopenharmony_ci  }
7381cb0ef41Sopenharmony_ci
7391cb0ef41Sopenharmony_ci  DCHECK_GE(free_registers_.Count(), num_temporaries_needed);
7401cb0ef41Sopenharmony_ci  node->assign_temporaries(free_registers_);
7411cb0ef41Sopenharmony_ci}
7421cb0ef41Sopenharmony_ci
7431cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::InitializeRegisterValues(
7441cb0ef41Sopenharmony_ci    MergePointRegisterState& target_state) {
7451cb0ef41Sopenharmony_ci  // First clear the register state.
7461cb0ef41Sopenharmony_ci  while (used_registers() != kEmptyRegList) {
7471cb0ef41Sopenharmony_ci    Register reg = used_registers().first();
7481cb0ef41Sopenharmony_ci    ValueNode* node = GetRegisterValue(reg);
7491cb0ef41Sopenharmony_ci    FreeRegisters(node);
7501cb0ef41Sopenharmony_ci    DCHECK(!used_registers().has(reg));
7511cb0ef41Sopenharmony_ci  }
7521cb0ef41Sopenharmony_ci
7531cb0ef41Sopenharmony_ci  // All registers should be free by now.
7541cb0ef41Sopenharmony_ci  DCHECK_EQ(free_registers_, kAllocatableGeneralRegisters);
7551cb0ef41Sopenharmony_ci
7561cb0ef41Sopenharmony_ci  // Then fill it in with target information.
7571cb0ef41Sopenharmony_ci  for (auto entry : target_state) {
7581cb0ef41Sopenharmony_ci    Register reg = entry.reg;
7591cb0ef41Sopenharmony_ci
7601cb0ef41Sopenharmony_ci    ValueNode* node;
7611cb0ef41Sopenharmony_ci    RegisterMerge* merge;
7621cb0ef41Sopenharmony_ci    LoadMergeState(entry.state, &node, &merge);
7631cb0ef41Sopenharmony_ci    if (node != nullptr) {
7641cb0ef41Sopenharmony_ci      free_registers_.clear(reg);
7651cb0ef41Sopenharmony_ci      SetRegister(reg, node);
7661cb0ef41Sopenharmony_ci    } else {
7671cb0ef41Sopenharmony_ci      DCHECK(!entry.state.GetPayload().is_merge);
7681cb0ef41Sopenharmony_ci    }
7691cb0ef41Sopenharmony_ci  }
7701cb0ef41Sopenharmony_ci}
7711cb0ef41Sopenharmony_ci
7721cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::EnsureInRegister(
7731cb0ef41Sopenharmony_ci    MergePointRegisterState& target_state, ValueNode* incoming) {
7741cb0ef41Sopenharmony_ci#ifdef DEBUG
7751cb0ef41Sopenharmony_ci  bool found = false;
7761cb0ef41Sopenharmony_ci  for (auto entry : target_state) {
7771cb0ef41Sopenharmony_ci    ValueNode* node;
7781cb0ef41Sopenharmony_ci    RegisterMerge* merge;
7791cb0ef41Sopenharmony_ci    LoadMergeState(entry.state, &node, &merge);
7801cb0ef41Sopenharmony_ci    if (node == incoming) found = true;
7811cb0ef41Sopenharmony_ci  }
7821cb0ef41Sopenharmony_ci  DCHECK(found);
7831cb0ef41Sopenharmony_ci#endif
7841cb0ef41Sopenharmony_ci}
7851cb0ef41Sopenharmony_ci
7861cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::InitializeBranchTargetRegisterValues(
7871cb0ef41Sopenharmony_ci    ControlNode* source, BasicBlock* target) {
7881cb0ef41Sopenharmony_ci  MergePointRegisterState& target_state = target->state()->register_state();
7891cb0ef41Sopenharmony_ci  DCHECK(!target_state.is_initialized());
7901cb0ef41Sopenharmony_ci  for (auto entry : target_state) {
7911cb0ef41Sopenharmony_ci    Register reg = entry.reg;
7921cb0ef41Sopenharmony_ci    ValueNode* node = nullptr;
7931cb0ef41Sopenharmony_ci    if (!free_registers_.has(reg)) {
7941cb0ef41Sopenharmony_ci      node = GetRegisterValue(reg);
7951cb0ef41Sopenharmony_ci      if (!IsLiveAtTarget(node, source, target)) node = nullptr;
7961cb0ef41Sopenharmony_ci    }
7971cb0ef41Sopenharmony_ci    entry.state = {node, initialized_node};
7981cb0ef41Sopenharmony_ci  }
7991cb0ef41Sopenharmony_ci}
8001cb0ef41Sopenharmony_ci
8011cb0ef41Sopenharmony_civoid StraightForwardRegisterAllocator::MergeRegisterValues(ControlNode* control,
8021cb0ef41Sopenharmony_ci                                                           BasicBlock* target,
8031cb0ef41Sopenharmony_ci                                                           int predecessor_id) {
8041cb0ef41Sopenharmony_ci  MergePointRegisterState& target_state = target->state()->register_state();
8051cb0ef41Sopenharmony_ci  if (!target_state.is_initialized()) {
8061cb0ef41Sopenharmony_ci    // This is the first block we're merging, initialize the values.
8071cb0ef41Sopenharmony_ci    return InitializeBranchTargetRegisterValues(control, target);
8081cb0ef41Sopenharmony_ci  }
8091cb0ef41Sopenharmony_ci
8101cb0ef41Sopenharmony_ci  int predecessor_count = target->state()->predecessor_count();
8111cb0ef41Sopenharmony_ci  for (auto entry : target_state) {
8121cb0ef41Sopenharmony_ci    Register reg = entry.reg;
8131cb0ef41Sopenharmony_ci
8141cb0ef41Sopenharmony_ci    ValueNode* node;
8151cb0ef41Sopenharmony_ci    RegisterMerge* merge;
8161cb0ef41Sopenharmony_ci    LoadMergeState(entry.state, &node, &merge);
8171cb0ef41Sopenharmony_ci
8181cb0ef41Sopenharmony_ci    compiler::AllocatedOperand register_info = {
8191cb0ef41Sopenharmony_ci        compiler::LocationOperand::REGISTER, MachineRepresentation::kTagged,
8201cb0ef41Sopenharmony_ci        reg.code()};
8211cb0ef41Sopenharmony_ci
8221cb0ef41Sopenharmony_ci    ValueNode* incoming = nullptr;
8231cb0ef41Sopenharmony_ci    if (!free_registers_.has(reg)) {
8241cb0ef41Sopenharmony_ci      incoming = GetRegisterValue(reg);
8251cb0ef41Sopenharmony_ci      if (!IsLiveAtTarget(incoming, control, target)) {
8261cb0ef41Sopenharmony_ci        incoming = nullptr;
8271cb0ef41Sopenharmony_ci      }
8281cb0ef41Sopenharmony_ci    }
8291cb0ef41Sopenharmony_ci
8301cb0ef41Sopenharmony_ci    if (incoming == node) {
8311cb0ef41Sopenharmony_ci      // We're using the same register as the target already has. If registers
8321cb0ef41Sopenharmony_ci      // are merged, add input information.
8331cb0ef41Sopenharmony_ci      if (merge) merge->operand(predecessor_id) = register_info;
8341cb0ef41Sopenharmony_ci      continue;
8351cb0ef41Sopenharmony_ci    }
8361cb0ef41Sopenharmony_ci
8371cb0ef41Sopenharmony_ci    if (merge) {
8381cb0ef41Sopenharmony_ci      // The register is already occupied with a different node. Figure out
8391cb0ef41Sopenharmony_ci      // where that node is allocated on the incoming branch.
8401cb0ef41Sopenharmony_ci      merge->operand(predecessor_id) = node->allocation();
8411cb0ef41Sopenharmony_ci
8421cb0ef41Sopenharmony_ci      // If there's a value in the incoming state, that value is either
8431cb0ef41Sopenharmony_ci      // already spilled or in another place in the merge state.
8441cb0ef41Sopenharmony_ci      if (incoming != nullptr && incoming->is_spilled()) {
8451cb0ef41Sopenharmony_ci        EnsureInRegister(target_state, incoming);
8461cb0ef41Sopenharmony_ci      }
8471cb0ef41Sopenharmony_ci      continue;
8481cb0ef41Sopenharmony_ci    }
8491cb0ef41Sopenharmony_ci
8501cb0ef41Sopenharmony_ci    DCHECK_IMPLIES(node == nullptr, incoming != nullptr);
8511cb0ef41Sopenharmony_ci    if (node == nullptr && !incoming->is_spilled()) {
8521cb0ef41Sopenharmony_ci      // If the register is unallocated at the merge point, and the incoming
8531cb0ef41Sopenharmony_ci      // value isn't spilled, that means we must have seen it already in a
8541cb0ef41Sopenharmony_ci      // different register.
8551cb0ef41Sopenharmony_ci      EnsureInRegister(target_state, incoming);
8561cb0ef41Sopenharmony_ci      continue;
8571cb0ef41Sopenharmony_ci    }
8581cb0ef41Sopenharmony_ci
8591cb0ef41Sopenharmony_ci    const size_t size = sizeof(RegisterMerge) +
8601cb0ef41Sopenharmony_ci                        predecessor_count * sizeof(compiler::AllocatedOperand);
8611cb0ef41Sopenharmony_ci    void* buffer = compilation_unit_->zone()->Allocate<void*>(size);
8621cb0ef41Sopenharmony_ci    merge = new (buffer) RegisterMerge();
8631cb0ef41Sopenharmony_ci    merge->node = node == nullptr ? incoming : node;
8641cb0ef41Sopenharmony_ci
8651cb0ef41Sopenharmony_ci    // If the register is unallocated at the merge point, allocation so far
8661cb0ef41Sopenharmony_ci    // is the spill slot for the incoming value. Otherwise all incoming
8671cb0ef41Sopenharmony_ci    // branches agree that the current node is in the register info.
8681cb0ef41Sopenharmony_ci    compiler::AllocatedOperand info_so_far =
8691cb0ef41Sopenharmony_ci        node == nullptr
8701cb0ef41Sopenharmony_ci            ? compiler::AllocatedOperand::cast(incoming->spill_slot())
8711cb0ef41Sopenharmony_ci            : register_info;
8721cb0ef41Sopenharmony_ci
8731cb0ef41Sopenharmony_ci    // Initialize the entire array with info_so_far since we don't know in
8741cb0ef41Sopenharmony_ci    // which order we've seen the predecessors so far. Predecessors we
8751cb0ef41Sopenharmony_ci    // haven't seen yet will simply overwrite their entry later.
8761cb0ef41Sopenharmony_ci    for (int i = 0; i < predecessor_count; i++) {
8771cb0ef41Sopenharmony_ci      merge->operand(i) = info_so_far;
8781cb0ef41Sopenharmony_ci    }
8791cb0ef41Sopenharmony_ci    // If the register is unallocated at the merge point, fill in the
8801cb0ef41Sopenharmony_ci    // incoming value. Otherwise find the merge-point node in the incoming
8811cb0ef41Sopenharmony_ci    // state.
8821cb0ef41Sopenharmony_ci    if (node == nullptr) {
8831cb0ef41Sopenharmony_ci      merge->operand(predecessor_id) = register_info;
8841cb0ef41Sopenharmony_ci    } else {
8851cb0ef41Sopenharmony_ci      merge->operand(predecessor_id) = node->allocation();
8861cb0ef41Sopenharmony_ci    }
8871cb0ef41Sopenharmony_ci    entry.state = {merge, initialized_merge};
8881cb0ef41Sopenharmony_ci  }
8891cb0ef41Sopenharmony_ci}
8901cb0ef41Sopenharmony_ci
8911cb0ef41Sopenharmony_ci}  // namespace maglev
8921cb0ef41Sopenharmony_ci}  // namespace internal
8931cb0ef41Sopenharmony_ci}  // namespace v8
894