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