30#ifdef V8_TARGET_ARCH_ARM 
   32#elif V8_TARGET_ARCH_ARM64 
   34#elif V8_TARGET_ARCH_RISCV64 
   36#elif V8_TARGET_ARCH_X64 
   38#elif V8_TARGET_ARCH_S390X 
   41#error "Maglev does not supported this architecture." 
   51constexpr RegisterStateFlags initialized_node{
true, 
false};
 
   52constexpr RegisterStateFlags initialized_merge{
true, 
true};
 
   54using BlockReverseIterator = std::vector<BasicBlock>::reverse_iterator;
 
   60bool IsTargetOfNodeFallthrough(ControlNode* node, BasicBlock* target) {
 
   61  return node->id() + 1 == target->first_id();
 
   64ControlNode* NearestPostDominatingHole(ControlNode* node) {
 
   68  if (node->Is<BranchControlNode>()) {
 
   69    return node->next_post_dominating_hole();
 
   75  if (node->Is<Jump>() || node->Is<CheckpointedJump>()) {
 
   77    if (
auto jmp = node->TryCast<Jump>()) {
 
   78      target = jmp->target();
 
   80      target = node->Cast<CheckpointedJump>()->
target();
 
   82    if (IsTargetOfNodeFallthrough(node, target)) {
 
   83      return node->next_post_dominating_hole();
 
   89  if (Switch* _switch = node->TryCast<Switch>()) {
 
   90    if (_switch->has_fallthrough()) {
 
   91      return _switch->next_post_dominating_hole();
 
   98ControlNode* HighestPostDominatingHole(ControlNode* first,
 
  107    if (first->id() > 
second->id()) std::swap(first, 
second);
 
  112    if (first->Is<TerminalControlNode>() || first->Is<JumpLoop>()) {
 
  120    first = first->next_post_dominating_hole();
 
  128template <
size_t kSize>
 
  129ControlNode* HighestPostDominatingHole(
 
  130    base::SmallVector<ControlNode*, kSize>& holes) {
 
  132  std::sort(holes.begin(), holes.end(),
 
  133            [](ControlNode* first, ControlNode* 
second) {
 
  134              return first->id() > second->id();
 
  138  ControlNode* post_dominating_hole = holes.back();
 
  140  while (holes.size() > 0) {
 
  143    post_dominating_hole =
 
  144        HighestPostDominatingHole(post_dominating_hole, next_hole);
 
  146  return post_dominating_hole;
 
  149bool IsLiveAtTarget(ValueNode* node, ControlNode* source, BasicBlock* target) {
 
  151  DCHECK(!node->has_no_more_uses());
 
  154  if (target->control_node()->id() <= source->id()) {
 
  156    return node->id() < target->FirstNonGapMoveId();
 
  160  if (target->is_loop() && target->state()->is_resumable_loop()) 
return false;
 
  167  return node->live_range().end >= target->first_id();
 
  170bool IsDeadNodeToSkip(Node* node) {
 
  171  if (!node->Is<ValueNode>()) 
return false;
 
  172  ValueNode* value = node->Cast<ValueNode>();
 
  173  return value->has_no_more_uses() &&
 
  174         !value->properties().is_required_when_unused();
 
  183  if (diff == 0) 
return;
 
  184  block->nodes().resize(block->nodes().size() + diff);
 
  185  auto patches_it = 
patches_.end() - 1;
 
  186  for (
auto node_it = block->nodes().end() - 1 - diff;
 
  187       node_it >= block->nodes().begin(); --node_it) {
 
  188    *(node_it + diff) = *node_it;
 
  189    for (; patches_it->diff == (node_it - block->nodes().begin());
 
  192      *(node_it + diff) = patches_it->new_node;
 
 
  205    : compilation_info_(compilation_info),
 
  207      patches_(compilation_info_->zone()),
 
  208      regalloc_info_(regalloc_info) {
 
  219      if (val->result().operand().IsAllocated() &&
 
  220          val->stack_slot() >= tagged_stack_slots) {
 
  221        tagged_stack_slots = val->stack_slot() + 1;
 
  226    uint32_t source_frame_size =
 
  228    uint32_t target_frame_size = tagged_stack_slots + untagged_stack_slots;
 
  229    if (source_frame_size > target_frame_size) {
 
  230      untagged_stack_slots += source_frame_size - target_frame_size;
 
  233#ifdef V8_TARGET_ARCH_ARM64 
  237  if ((tagged_stack_slots + untagged_stack_slots) % 2 == 0) {
 
  238    untagged_stack_slots++;
 
 
  311    if (
auto unconditional_control =
 
  316          unconditional_control->target()->control_node()));
 
  319          NearestPostDominatingHole(branch->if_true()->control_node());
 
  321          NearestPostDominatingHole(branch->if_false()->control_node());
 
  323          HighestPostDominatingHole(first, 
second));
 
  326          switch_node->size() + (switch_node->has_fallthrough() ? 1 : 0);
 
  327      if (num_targets == 1) {
 
  330        DCHECK(!switch_node->has_fallthrough());
 
  332            switch_node->targets()[0].block_ptr()->control_node()));
 
  337      for (
int i = 0; 
i < switch_node->
size(); 
i++) {
 
  338        holes[
i] = NearestPostDominatingHole(
 
  339            switch_node->targets()[
i].block_ptr()->control_node());
 
  341      if (switch_node->has_fallthrough()) {
 
  342        holes[switch_node->size()] = NearestPostDominatingHole(
 
  343            switch_node->fallthrough()->control_node());
 
 
  365  if (
v8_flags.trace_maglev_regalloc) {
 
  372    constant->SetConstantLocation();
 
  375  for (
const auto& [index, constant] : 
graph_->
root()) {
 
  376    constant->SetConstantLocation();
 
  379  for (
const auto& [value, constant] : 
graph_->
smi()) {
 
  380    constant->SetConstantLocation();
 
  384    constant->SetConstantLocation();
 
  387  for (
const auto& [value, constant] : 
graph_->
int32()) {
 
  388    constant->SetConstantLocation();
 
  391  for (
const auto& [value, constant] : 
graph_->
uint32()) {
 
  392    constant->SetConstantLocation();
 
  396    constant->SetConstantLocation();
 
  400    constant->SetConstantLocation();
 
  404    constant->SetConstantLocation();
 
  413    if (block->has_state()) {
 
  414      if (block->state()->is_exception_handler() ||
 
  415          block->state()->IsUnreachableByForwardEdge()) {
 
  423    } 
else if (block->is_edge_split_block()) {
 
  427    if (
v8_flags.trace_maglev_regalloc) {
 
  432      ControlNode* control = NearestPostDominatingHole(block->control_node());
 
  443                << 
" " << control->
id() << 
"-" << target->first_id();
 
  453                << 
" " << control->
id() << 
"-" << first_target->
first_id();
 
  472    if (block->has_phi()) {
 
  476      for (
auto phi_it = phis.
begin(); phi_it != phis.
end();) {
 
  478        if (!phi->has_valid_live_range()) {
 
  484          DCHECK(phi->has_valid_live_range());
 
  490      if (block->is_exception_handler_block()) {
 
  495        for (
Phi* phi : phis) {
 
  497          DCHECK(phi->is_exception_phi());
 
  499            if (!phi->has_no_more_uses()) {
 
  501              if (
v8_flags.trace_maglev_regalloc) {
 
  504                                        << phi->result().operand() << std::endl;
 
  507          } 
else if (phi->owner().is_parameter() &&
 
  508                     phi->owner().is_receiver()) {
 
  526            phi->result().SetAllocated(phi->spill_slot());
 
  533      for (
Phi* phi : phis) {
 
  534        DCHECK(phi->has_valid_live_range());
 
  535        if (phi->result().operand().IsAllocated()) 
continue;
 
  536        if (phi->use_double_register()) {
 
  540            phi->result().SetAllocated(allocation);
 
  542            if (
v8_flags.trace_maglev_regalloc) {
 
  545                  << 
"phi (new reg) " << phi->result().operand() << std::endl;
 
  553            phi->result().SetAllocated(allocation);
 
  555            if (
v8_flags.trace_maglev_regalloc) {
 
  558                  << 
"phi (new reg) " << phi->result().operand() << std::endl;
 
  564      for (
Phi* phi : phis) {
 
  565        DCHECK(phi->has_valid_live_range());
 
  566        if (phi->result().operand().IsAllocated()) 
continue;
 
  569        phi->result().SetAllocated(phi->spill_slot());
 
  570        if (
v8_flags.trace_maglev_regalloc) {
 
  573              << 
"phi (stack) " << phi->result().operand() << std::endl;
 
  577      if (
v8_flags.trace_maglev_regalloc) {
 
  585    DCHECK(AllUsedRegistersLiveAt(block));
 
  591      if (node == 
nullptr) 
continue;
 
  593      if (IsDeadNodeToSkip(node)) {
 
  595        if (
v8_flags.trace_maglev_regalloc) {
 
  597              << 
"Removing unused node " 
  606          DCHECK(!node->properties().can_deopt());
 
  607          node->ForAllInputsInRegallocAssignmentOrder(
 
 
  625  if (node->use_double_register()) {
 
 
  634  if (
v8_flags.trace_maglev_regalloc) {
 
  639  DCHECK(!node->has_no_more_uses());
 
  642  node->advance_next_use(input_location->
next_use_id());
 
  644  if (!node->has_no_more_uses()) 
return;
 
  646  if (
v8_flags.trace_maglev_regalloc) {
 
  655  if (node->is_spilled()) {
 
  657    if (slot.
index() > 0) {
 
  662          slots.free_slots.size() > 0,
 
  663          slots.free_slots.back().freed_at_position <= node->live_range().end);
 
  666      slots.free_slots.emplace_back(slot.
index(), node->live_range().end,
 
 
  678    if (!node->has_register() && !node->is_loadable()) {
 
  681    input->InjectLocation(node->allocation());
 
 
  695    input->InjectLocation(node->loadable_slot());
 
 
  703#define GET_NODE_RESULT_REGISTER_T(RegisterT, AssignedRegisterT) \ 
  704  RegisterT GetNodeResult##RegisterT(Node* node) {               \ 
  705    ValueNode* value_node = node->TryCast<ValueNode>();          \ 
  706    if (!value_node) return RegisterT::no_reg();                 \ 
  707    if (!value_node->result().operand().Is##RegisterT()) {       \ 
  708      return RegisterT::no_reg();                                \ 
  710    return value_node->result().AssignedRegisterT();             \ 
  712GET_NODE_RESULT_REGISTER_T(
Register, AssignedGeneralRegister)
 
  714#undef GET_NODE_RESULT_REGISTER_T 
  725  if (
v8_flags.trace_maglev_regalloc) {
 
  737    if (
v8_flags.trace_maglev_regalloc) {
 
  745  if (node->properties().can_eager_deopt()) {
 
  746    if (
v8_flags.trace_maglev_regalloc) {
 
  753  if (node->properties().can_lazy_deopt()) {
 
  754    if (
v8_flags.trace_maglev_regalloc) {
 
  759    if (node->properties().can_throw()) {
 
  761      if (info->HasExceptionHandler() && !info->ShouldLazyDeopt() &&
 
  762          !node->properties().is_call()) {
 
  765          if (node->live_range().end < block->first_id()) 
return;
 
  778  if (
v8_flags.trace_maglev_regalloc) {
 
  787                 !node->general_temporaries().has(GetNodeResultRegister(node)));
 
  790      !node->double_temporaries().has(GetNodeResultDoubleRegister(node)));
 
 
  802template <
typename RegisterT>
 
  804    RegisterT 
reg, 
bool force_spill) {
 
  812      node->RemoveRegister(
reg);
 
 
  826      compiler::UnallocatedOperand::cast(node->result().operand());
 
  833                                        node->GetMachineRepresentation(),
 
  835    node->result().SetAllocated(location);
 
  836    node->Spill(location);
 
  842      CHECK(node->is_tagged());
 
  871      if (node->has_hint()) input.node()->ClearHint();
 
  896  if (!node->has_valid_live_range() &&
 
  897      node->result().operand().IsAnyRegister()) {
 
  898    DCHECK(node->has_register());
 
  900    DCHECK(!node->has_register());
 
  901    DCHECK(node->has_no_more_uses());
 
 
  905template <
typename RegisterT>
 
  913  if (
v8_flags.trace_maglev_regalloc) {
 
  921  node->RemoveRegister(
reg);
 
  924  if (node->has_register() || node->is_loadable()) 
return;
 
  927  if (!
registers.UnblockedFreeIsEmpty() && !force_spill) {
 
  928    RegisterT target_reg = 
registers.unblocked_free().first();
 
  929    RegisterT hint_reg = node->GetRegisterHint<RegisterT>();
 
  930    if (hint_reg.is_valid() && 
registers.unblocked_free().has(hint_reg)) {
 
  931      target_reg = hint_reg;
 
  934    registers.SetValueWithoutBlocking(target_reg, node);
 
  937                                      mach_repr, 
reg.code());
 
  939                                      mach_repr, target_reg.code());
 
 
  958  DCHECK(!target->is_edge_split_block());
 
  960  if (!target->has_phi()) 
return;
 
  967  for (
auto phi_it = phis.
begin(); phi_it != phis.
end();) {
 
  969    if (!phi->has_valid_live_range()) {
 
  975      Input& input = phi->input(predecessor_id);
 
 
  984bool StraightForwardRegisterAllocator::AllUsedRegistersLiveAt(
 
  986  auto ForAllRegisters = [&](
const auto& 
registers) {
 
  988      if (!IsLiveAtTarget(
registers.GetValue(
reg), control_node, target)) {
 
  998bool StraightForwardRegisterAllocator::AllUsedRegistersLiveAt(
 
  999    BasicBlock* target) {
 
 1000  auto ForAllRegisters = [&](
const auto& 
registers) {
 
 1002      if (
registers.GetValue(
reg)->live_range().end < target->first_id()) {
 
 1016  DCHECK(!target->has_phi());
 
 1018  if (target->has_state()) {
 
 1022  if (target->is_edge_split_block()) {
 
 1026  DCHECK_EQ(control_node->
id() + 1, target->first_id());
 
 1027  DCHECK(AllUsedRegistersLiveAt(control_node, target));
 
 
 1035  DCHECK(!node->properties().can_lazy_deopt());
 
 1037  if (node->Is<
Abort>()) {
 
 1039    DCHECK(node->general_temporaries().is_empty());
 
 1040    DCHECK(node->double_temporaries().is_empty());
 
 1050    if (
v8_flags.trace_maglev_regalloc) {
 
 1053  } 
else if (node->Is<
Deopt>()) {
 
 1055    DCHECK(node->general_temporaries().is_empty());
 
 1056    DCHECK(node->double_temporaries().is_empty());
 
 1064    if (
v8_flags.trace_maglev_regalloc) {
 
 1069    DCHECK(node->general_temporaries().is_empty());
 
 1070    DCHECK(node->double_temporaries().is_empty());
 
 1074    DCHECK(!node->properties().can_eager_deopt());
 
 1075    DCHECK(!node->properties().can_lazy_deopt());
 
 1076    DCHECK(!node->properties().needs_register_snapshot());
 
 1077    DCHECK(!node->properties().is_call());
 
 1079    auto predecessor_id = block->predecessor_id();
 
 1080    auto target = unconditional->target();
 
 1084    if (target->has_phi()) {
 
 1085      for (
Phi* phi : *target->phis()) {
 
 1095    if (
auto jump_loop = node->TryCast<
JumpLoop>()) {
 
 1096      for (
Input& input : jump_loop->used_nodes()) {
 
 1097        if (!input.node()->has_register() && !input.node()->is_loadable()) {
 
 1101          Spill(input.node());
 
 1107    if (
v8_flags.trace_maglev_regalloc) {
 
 1115    DCHECK(!node->properties().can_eager_deopt());
 
 1116    DCHECK(!node->properties().can_lazy_deopt());
 
 1120    DCHECK(!node->properties().needs_register_snapshot());
 
 1131    if (
v8_flags.trace_maglev_regalloc) {
 
 1142      for (
int i = 0; 
i < control_node->size(); 
i++) {
 
 1145      if (control_node->has_fallthrough()) {
 
 1147                                          control_node->fallthrough());
 
 
 1155template <
typename RegisterT>
 
 1159      std::is_same_v<RegisterT, Register>
 
 1163  for (
Input& input : *phi) {
 
 1164    if (input.node()->id() > phi->id()) {
 
 1165      input.node()->SetHint(hint);
 
 
 1172  for (
Input& input : *phi) {
 
 1173    if (input.operand().IsRegister()) {
 
 1181        if (
v8_flags.trace_maglev_regalloc) {
 
 1184              << 
"phi (reuse) " << input.operand() << std::endl;
 
 
 1196  if (source.IsConstant()) {
 
 1198    if (
v8_flags.trace_maglev_regalloc) {
 
 1200          << 
"  constant gap move: " << target << 
" ← " 
 1206    if (
v8_flags.trace_maglev_regalloc) {
 
 1209                              << source << std::endl;
 
 1220  if (
node_it_ == block->nodes().end()) {
 
 1223    block->nodes().push_back(gap_move);
 
 
 1232  if (node->is_loadable()) 
return;
 
 1234  if (
v8_flags.trace_maglev_regalloc) {
 
 1236        << 
"  spill: " << node->spill_slot() << 
" ← " 
 
 1243      compiler::UnallocatedOperand::cast(input.operand());
 
 1250      if (
v8_flags.trace_maglev_regalloc) {
 
 1253            << 
" has arbitrary register\n";
 
 1259      if (
v8_flags.trace_maglev_regalloc) {
 
 1262            << 
" has arbitrary location\n";
 
 1285  if (
v8_flags.trace_maglev_regalloc) {
 
 1288        << 
" in forced " << input.operand() << 
"\n";
 
 1293  if (location != allocated) {
 
 1298  input.node()->ClearHint();
 
 
 1303  if (node->use_double_register()) {
 
 
 1319bool IsInRegisterLocation(
ValueNode* node,
 
 1324  DCHECK_IMPLIES(node->use_double_register(), allocation.IsDoubleRegister());
 
 1325  DCHECK_IMPLIES(!node->use_double_register(), allocation.IsRegister());
 
 1326  if (node->use_double_register()) {
 
 1327    return node->is_in_register(allocation.GetDoubleRegister());
 
 1329    return node->is_in_register(allocation.GetRegister());
 
 1334bool SameAsInput(ValueNode* node, Input& input) {
 
 1335  auto operand = compiler::UnallocatedOperand::cast(node->result().operand());
 
 1336  return operand.HasSameAsInputPolicy() &&
 
 1337         &input == &node->input(operand.input_index());
 
 1340compiler::InstructionOperand InputHint(NodeBase* node, Input& input) {
 
 1341  ValueNode* value_node = node->TryCast<ValueNode>();
 
 1342  if (!value_node) 
return input.node()->hint();
 
 1343  DCHECK(value_node->result().operand().IsUnallocated());
 
 1344  if (SameAsInput(value_node, input)) {
 
 1345    return value_node->hint();
 
 1347    return input.node()->hint();
 
 1356  if (!input.operand().IsUnallocated()) 
return;
 
 1359      compiler::UnallocatedOperand::cast(input.operand());
 
 1370  bool is_clobbered = input.Cloberred();
 
 1374    auto hint = InputHint(result_node, input);
 
 1378      existing_register_location =
 
 1379          node->use_double_register()
 
 1386      auto result_hint = value_node && SameAsInput(value_node, input)
 
 1387                             ? value_node->
hint()
 
 1389      existing_register_location =
 
 1390          node->use_double_register()
 
 1397      if (
v8_flags.trace_maglev_regalloc) {
 
 1400            << (is_clobbered ? 
"clobbered " : 
"") << existing_register_location
 
 1409    DCHECK_NE(existing_location, allocation);
 
 1412    if (
v8_flags.trace_maglev_regalloc) {
 
 1415          << (is_clobbered ? 
"clobbered " : 
"") << allocation << 
" ← " 
 1416          << node->allocation() << 
"\n";
 
 1421  input.SetAllocated(location);
 
 1426  if (is_clobbered && !node->has_no_more_uses()) {
 
 1432  DCHECK_IMPLIES(is_clobbered, !IsInRegisterLocation(node, location));
 
 
 1437  if (!input.operand().IsUnallocated()) 
return;
 
 1440      compiler::UnallocatedOperand::cast(input.operand()).extended_policy(),
 
 1446  input.InjectLocation(location);
 
 1450    if (allocation.IsDoubleRegister()) {
 
 1456  if (
v8_flags.trace_maglev_regalloc) {
 
 1459        << 
" in original " << location << 
"\n";
 
 
 1484  for (
Input& input : *node) {
 
 1485    if (input.operand().IsRegister()) {
 
 1489        FATAL(
"Input node n%d is not in expected register %s",
 
 1492    } 
else if (input.operand().IsDoubleRegister()) {
 
 1496        FATAL(
"Input node n%d is not in expected register %s",
 
 1500      if (input.operand() != input.node()->allocation()) {
 
 1501        std::stringstream ss;
 
 1502        ss << input.operand();
 
 1503        FATAL(
"Input node n%d is not in operand %s",
 
 
 1518    std::stringstream ss;
 
 1522      ss << 
"<" << node << 
">";
 
 1529    if (!node->is_in_register(
reg)) {
 
 1530      FATAL(
"Node %s doesn't think it is in register %s",
 
 1531            NodeNameForFatal(node).c_str(), RegisterName(
reg));
 
 1536    if (!node->is_in_register(
reg)) {
 
 1537      FATAL(
"Node %s doesn't think it is in register %s",
 
 1538            NodeNameForFatal(node).c_str(), RegisterName(
reg));
 
 1542  auto ValidateValueNode = [
this, NodeNameForFatal](
ValueNode* 
node) {
 
 1543    if (node->use_double_register()) {
 
 1546          FATAL(
"Node %s thinks it's in register %s but it's free",
 
 1547                NodeNameForFatal(node).c_str(), RegisterName(
reg));
 
 1549          FATAL(
"Node %s thinks it's in register %s but it contains %s",
 
 1550                NodeNameForFatal(node).c_str(), RegisterName(
reg),
 
 1557          FATAL(
"Node %s thinks it's in register %s but it's free",
 
 1558                NodeNameForFatal(node).c_str(), RegisterName(
reg));
 
 1560          FATAL(
"Node %s thinks it's in register %s but it contains %s",
 
 1561                NodeNameForFatal(node).c_str(), RegisterName(
reg),
 
 1569    if (block->has_phi()) {
 
 1570      for (
Phi* phi : *block->phis()) {
 
 1571        ValidateValueNode(phi);
 
 1574    for (
Node* node : block->nodes()) {
 
 1575      if (node == 
nullptr) 
continue;
 
 1577        if (node->Is<
Identity>()) 
continue;
 
 1578        ValidateValueNode(value_node);
 
 
 1592template <
typename RegisterT>
 
 1598    if (
v8_flags.trace_maglev_regalloc) {
 
 
 1616    if (node->properties().value_representation() ==
 
 1618      snapshot.live_tagged_registers.set(
reg);
 
 1625    if (value_node->use_double_register()) {
 
 1626      snapshot.live_double_registers.clear(
 
 1630      snapshot.live_registers.clear(
reg);
 
 1631      snapshot.live_tagged_registers.clear(
reg);
 
 1634  if (node->properties().can_eager_deopt()) {
 
 1639    InputLocation* input = node->eager_deopt_info()->input_locations();
 
 1640    node->eager_deopt_info()->ForEachInput([&](
ValueNode* node) {
 
 1641      if (input->IsAnyRegister()) {
 
 1642        if (input->IsDoubleRegister()) {
 
 1643          snapshot.live_double_registers.set(input->AssignedDoubleRegister());
 
 1645          snapshot.live_registers.set(input->AssignedGeneralRegister());
 
 1646          if (node->is_tagged()) {
 
 1647            snapshot.live_tagged_registers.set(
 
 1648                input->AssignedGeneralRegister());
 
 1655  node->set_register_snapshot(snapshot);
 
 
 1659  DCHECK(!node->is_loadable());
 
 1661  bool is_tagged = (node->properties().value_representation() ==
 
 1663  uint32_t slot_size = 1;
 
 1674  if (!
v8_flags.maglev_reuse_stack_slots || slot_size > 1 ||
 
 1675      slots.free_slots.empty()) {
 
 1676    free_slot = slots.top + slot_size - 1;
 
 1677    slots.top += slot_size;
 
 1681        std::upper_bound(slots.free_slots.begin(), slots.free_slots.end(),
 
 1683                           return slot_info.freed_at_position >= s;
 
 1687    if (it != slots.free_slots.begin()) {
 
 1694    while (it != slots.free_slots.begin()) {
 
 1695      if (it->double_slot == double_slot) 
break;
 
 1699    if (it != slots.free_slots.begin()) {
 
 1700      CHECK_EQ(double_slot, it->double_slot);
 
 1702      free_slot = it->slot_index;
 
 1703      slots.free_slots.erase(it);
 
 1705      free_slot = slots.top++;
 
 1709                                         representation, free_slot));
 
 
 1712template <
typename RegisterT>
 
 1716  if (
v8_flags.trace_maglev_regalloc) {
 
 1719  int furthest_use = 0;
 
 1720  RegisterT best = RegisterT::no_reg();
 
 1727    if (value->num_registers() > 1) {
 
 1732    if (use > furthest_use) {
 
 1737  if (
v8_flags.trace_maglev_regalloc) {
 
 1739        << 
"  chose " << best << 
" with next use " << furthest_use << 
"\n";
 
 
 1744template <
typename RegisterT>
 
 1760  if (node->use_double_register()) {
 
 
 1774template <
typename RegisterT>
 
 1776  if (hint.IsInvalid()) 
return RegisterT::no_reg();
 
 1777  DCHECK(hint.IsUnallocated());
 
 1778  return RegisterT::from_code(
 
 1779      compiler::UnallocatedOperand::cast(hint).fixed_register_index());
 
 1788template <
typename RegisterT>
 
 1793  if (!
registers.unblocked_free().is_empty()) 
return;
 
 1797  RegisterT hint_reg = GetRegisterHint<RegisterT>(hint);
 
 1813  RegisterT 
reg = hint.IsInvalid()
 
 1815                      : GetRegisterHint<RegisterT>(hint);
 
 
 1821  if (node->use_double_register()) {
 
 
 1830template <
typename RegisterT>
 
 1834  if (
v8_flags.trace_maglev_regalloc) {
 
 1836        << 
"  forcing " << 
reg << 
" to " 
 1845                                      node->GetMachineRepresentation(),
 
 1855                                    node->GetMachineRepresentation(),
 
 
 1861  DCHECK(!node->use_double_register());
 
 
 1867  DCHECK(node->use_double_register());
 
 
 1873  if (input.IsDoubleRegister()) {
 
 
 1885template <
typename RegisterT>
 
 1889                                    node->GetMachineRepresentation(),
 
 1894template <
typename RegisterT>
 
 1895compiler::InstructionOperand
 
 1898  RegTList result_registers = node->result_registers<RegisterT>();
 
 1902  RegTList blocked_result_registers = result_registers & blocked_;
 
 1903  if (!blocked_result_registers.
is_empty()) {
 
 1904    RegisterT 
reg = GetRegisterHint<RegisterT>(hint);
 
 1905    if (!blocked_result_registers.
has(
reg)) {
 
 1906      reg = blocked_result_registers.
first();
 
 1908    return OperandForNodeRegister(node, 
reg);
 
 1911  RegisterT 
reg = result_registers.
first();
 
 1913  return OperandForNodeRegister(node, 
reg);
 
 
 1916template <
typename RegisterT>
 
 1920  RegTList result_excl_blocked = node->result_registers<RegisterT>() - blocked_;
 
 1922  RegisterT 
reg = result_excl_blocked.
first();
 
 1924  return OperandForNodeRegister(node, 
reg);
 
 
 1927template <
typename RegisterT>
 
 1931  RegisterT 
reg = GetRegisterHint<RegisterT>(hint);
 
 1932  if (!unblocked_free().has(
reg)) {
 
 1933    reg = unblocked_free().first();
 
 1935  RemoveFromFree(
reg);
 
 1939  SetValue(
reg, node);
 
 1940  return OperandForNodeRegister(node, 
reg);
 
 
 
 1943template <
typename RegisterT>
 
 1949  for (RegisterT 
reg : fixed_temporaries) {
 
 1959    if constexpr (std::is_same_v<RegisterT, Register>) {
 
 1961          << 
"Fixed Temporaries: " << fixed_temporaries << 
"\n";
 
 1964          << 
"Fixed Double Temporaries: " << fixed_temporaries << 
"\n";
 
 1971  node->temporaries<RegisterT>() = {};
 
 
 1980template <
typename RegisterT>
 
 1985      compiler::UnallocatedOperand::cast(node->result().operand());
 
 1988    DCHECK(node->Is<InitialValue>());
 
 1991  if constexpr (std::is_same_v<RegisterT, Register>) {
 
 1992    if (operand.extended_policy() ==
 
 1997    static_assert(std::is_same_v<RegisterT, DoubleRegister>);
 
 1998    if (operand.extended_policy() ==
 
 2007template <
typename RegisterT>
 
 2010  int num_temporaries_needed = node->num_temporaries_needed<RegisterT>();
 
 2011  if (num_temporaries_needed == 0) 
return;
 
 2016  int remaining_temporaries_needed = num_temporaries_needed;
 
 2021  for (RegisterT 
reg : (
registers.unblocked_free() - reserved)) {
 
 2025    if (--remaining_temporaries_needed == 0) 
break;
 
 2029  for (
int i = 0; 
i < remaining_temporaries_needed; ++
i) {
 
 2039  node->assign_temporaries(temporaries);
 
 2040  if (
v8_flags.trace_maglev_regalloc) {
 
 2041    if constexpr (std::is_same_v<RegisterT, Register>) {
 
 
 2055template <
typename Function>
 
 2058  merge_point_state.ForEachGeneralRegister(
 
 2062  merge_point_state.ForEachDoubleRegister(
 
 
 2069  auto ClearRegisterState = [&](
auto& 
registers) {
 
 
 2098    if (node != 
nullptr) {
 
 2102      DCHECK(!state.GetPayload().is_merge);
 
 
 2114bool StraightForwardRegisterAllocator::IsInRegister(
 
 2121    if (node == incoming) found = 
true;
 
 2124    target_state.ForEachDoubleRegister(find);
 
 2126    target_state.ForEachGeneralRegister(find);
 
 2132bool StraightForwardRegisterAllocator::IsForwardReachable(
 
 2136  while (!queue.empty()) {
 
 2137    BasicBlock* curr = queue.front();
 
 2140    if (curr->contains_node_id(first_id) || curr->contains_node_id(last_id)) {
 
 2144    if (curr->control_node()->Is<JumpLoop>()) {
 
 2150    for (BasicBlock* succ : curr->successors()) {
 
 2151      if (seen.insert(succ).second) {
 
 2155      DCHECK_GT(succ->first_id(), curr->first_id());
 
 2167template <
typename RegisterT>
 
 2172  for (
ValueNode* node : info->second.reload_hints_) {
 
 2175    if (node->has_register()) 
continue;
 
 2177    if (!node->is_loadable()) 
continue;
 
 2178    if ((node->use_double_register() && std::is_same_v<RegisterT, Register>) ||
 
 2179        (!node->use_double_register() &&
 
 2180         std::is_same_v<RegisterT, DoubleRegister>)) {
 
 2183    RegisterT target_reg = node->GetRegisterHint<RegisterT>();
 
 2184    if (!
registers.free().has(target_reg)) {
 
 2191    registers.SetValueWithoutBlocking(target_reg, node);
 
 
 2202  for (
ValueNode* node : info->second.spill_hints_) {
 
 2203    if (!node->has_register()) 
continue;
 
 2206    const bool kForceSpill = 
true;
 
 2207    if (node->use_double_register()) {
 
 
 2222  DCHECK(!target_state.is_initialized());
 
 2228      if (!IsLiveAtTarget(node, source, target)) node = 
nullptr;
 
 2230    state = {
node, initialized_node};
 
 
 2240  DCHECK(target->is_edge_split_block());
 
 2244  DCHECK(!register_state->is_initialized());
 
 2250      if (!IsLiveAtTarget(node, source, target)) node = 
nullptr;
 
 2252    state = {
node, initialized_node};
 
 2256  target->set_edge_split_block_register_state(register_state);
 
 
 2261                                                           int predecessor_id) {
 
 2262  if (target->is_edge_split_block()) {
 
 2267  if (!target_state.is_initialized()) {
 
 2272  if (
v8_flags.trace_maglev_regalloc) {
 
 2276  int predecessor_count = target->state()->predecessor_count();
 
 2295      if (!IsLiveAtTarget(incoming, control, target)) {
 
 2296        if (
v8_flags.trace_maglev_regalloc) {
 
 2299                                  << 
" dead at target\n";
 
 2305    if (incoming == node) {
 
 2308      if (
v8_flags.trace_maglev_regalloc) {
 
 2311              << 
"  " << 
reg << 
" - incoming node same as node: " 
 2315      if (merge) merge->
operand(predecessor_id) = register_info;
 
 2319    if (node == 
nullptr) {
 
 2322    } 
else if (!node->is_loadable() && !node->has_register()) {
 
 2329      if (
v8_flags.trace_maglev_regalloc) {
 
 2332                                << 
", dropping the merge\n";
 
 2337      state = {
nullptr, initialized_node};
 
 2344      merge->
operand(predecessor_id) = node->allocation();
 
 2345      if (
v8_flags.trace_maglev_regalloc) {
 
 2348                                << 
" from " << node->allocation() << 
" \n";
 
 2351      if (incoming != 
nullptr) {
 
 2357            !incoming->
is_loadable() && !IsInRegister(target_state, incoming),
 
 2366    if (node == 
nullptr && !incoming->
is_loadable()) {
 
 2376      if (
v8_flags.trace_maglev_regalloc) {
 
 2378            << 
"  " << 
reg << 
" - can't load incoming " 
 2388    merge->
node = node == 
nullptr ? incoming : 
node;
 
 2394        node == 
nullptr ? incoming->
loadable_slot() : register_info;
 
 2399    for (
int i = 0; 
i < predecessor_count; 
i++) {
 
 2405    if (node == 
nullptr) {
 
 2406      merge->
operand(predecessor_id) = register_info;
 
 2407      if (
v8_flags.trace_maglev_regalloc) {
 
 2410                                << 
" from " << register_info << 
" \n";
 
 2413      merge->
operand(predecessor_id) = node->allocation();
 
 2414      if (
v8_flags.trace_maglev_regalloc) {
 
 2417                                << 
" from " << node->allocation() << 
" \n";
 
 2420    state = {merge, initialized_merge};
 
 
 
 
Iterator RemoveAt(Iterator it)
constexpr RegisterT first() const
constexpr void set(RegisterT reg)
constexpr bool is_empty() const
constexpr bool has(RegisterT reg) const
constexpr unsigned Count() const
static constexpr DwVfpRegister from_code(int8_t code)
static constexpr DwVfpRegister no_reg()
static constexpr Register from_code(int code)
static constexpr Register no_reg()
static constexpr int kExpressionsOffset
static constexpr int kFixedSlotCount
static constexpr int kRegisterFileFromFp
void * Allocate(size_t size)
bool IsAnyLocationOperand() const
bool IsAnyRegister() const
Register GetRegister() const
MachineRepresentation representation() const
static LocationOperand * cast(InstructionOperand *op)
DoubleRegister GetDoubleRegister() const
@ REGISTER_OR_SLOT_OR_CONSTANT
BasicPolicy basic_policy() const
ExtendedPolicy extended_policy() const
int fixed_register_index() const
int fixed_slot_index() const
static constexpr Register virtual_accumulator()
static constexpr Register receiver()
BasicBlock * block_ptr() const
ControlNode * next_post_dominating_hole() const
void set_next_post_dominating_hole(ControlNode *node)
InputLocation * input_locations() const
void ForEachInput(Function &&f)
ZoneMap< int, TaggedIndexConstant * > & tagged_index()
ZoneMap< Address, ExternalConstant * > & external_references()
ZoneMap< uint32_t, Uint32Constant * > & uint32()
BlockConstIterator end() const
compiler::ZoneRefMap< compiler::ObjectRef, Constant * > & constants()
ZoneVector< InitialValue * > & osr_values()
void set_untagged_stack_slots(uint32_t stack_slots)
ZoneMap< int32_t, Int32Constant * > & int32()
void set_tagged_stack_slots(uint32_t stack_slots)
compiler::ZoneRefMap< compiler::HeapObjectRef, TrustedConstant * > & trusted_constants()
BlockConstIterator begin() const
uint32_t min_maglev_stackslots_for_unoptimized_frame_size()
ZoneMap< uint64_t, Float64Constant * > & float64()
ZoneMap< int, SmiConstant * > & smi()
ZoneMap< RootIndex, RootConstant * > & root()
void ForEachInput(Function &&f)
static constexpr DoubleRegList GetAllocatableDoubleRegisters()
static constexpr RegList GetAllocatableRegisters()
MaglevGraphLabeller * graph_labeller() const
bool has_graph_labeller() const
void RegisterNode(const NodeBase *node, const MaglevCompilationUnit *unit, BytecodeOffset bytecode_offset, SourcePosition position)
constexpr bool Is() const
constexpr NodeIdT id() const
static Derived * New(Zone *zone, std::initializer_list< ValueNode * > inputs, Args &&... args)
static constexpr OpProperties Call()
static constexpr OpProperties EagerDeopt()
compiler::AllocatedOperand AllocateRegister(ValueNode *node, const compiler::InstructionOperand &hint=compiler::InstructionOperand())
ValueNode * GetValue(RegisterT reg) const
void AddToFree(RegisterT reg)
void unblock(RegisterT reg)
compiler::InstructionOperand TryChooseInputRegister(ValueNode *node, const compiler::InstructionOperand &hint=compiler::InstructionOperand())
compiler::InstructionOperand TryChooseUnblockedInputRegister(ValueNode *node)
void PrintLiveRegs() const
compiler::AllocatedOperand AllocateRegisterAtEnd(ValueNode *node)
BlockConstIterator block_it_
void AssignFixedInput(Input &input)
void DropRegisterValueAtEnd(RegisterT reg, bool force_spill=false)
RegisterT PickRegisterToFree(RegListBase< RegisterT > reserved)
void SpillAndClearRegisters()
StraightForwardRegisterAllocator(MaglevCompilationInfo *compilation_info, Graph *graph, RegallocInfo *regalloc_info)
void AssignAnyInput(Input &input)
void TryAllocateToInput(Phi *phi)
void FreeRegistersUsedBy(ValueNode *node)
void DropRegisterValue(RegisterFrameState< RegisterT > ®isters, RegisterT reg, bool force_spill=false)
void ForEachMergePointRegisterState(MergePointRegisterState &merge_point_state, Function &&f)
void InitializeBranchTargetRegisterValues(ControlNode *source, BasicBlock *target)
RegisterT FreeUnblockedRegister(RegListBase< RegisterT > reserved=RegListBase< RegisterT >())
void AllocateNodeResult(ValueNode *node)
RegisterFrameState< DoubleRegister > double_registers_
void VerifyRegisterState()
compiler::AllocatedOperand AllocateRegister(ValueNode *node, const compiler::InstructionOperand &hint=compiler::InstructionOperand())
MaglevCompilationInfo * compilation_info_
std::unique_ptr< MaglevPrintingVisitor > printing_visitor_
void ComputePostDominatingHoles()
void InitializeEmptyBlockRegisterValues(ControlNode *source, BasicBlock *target)
void AllocateControlNode(ControlNode *node, BasicBlock *block)
bool IsCurrentNodeLastUseOf(ValueNode *node)
void MarkAsClobbered(ValueNode *node, const compiler::AllocatedOperand &location)
void AssignArbitraryTemporaries(RegisterFrameState< RegisterT > ®isters, NodeBase *node)
void VerifyInputs(NodeBase *node)
compiler::AllocatedOperand ForceAllocate(RegisterFrameState< RegisterT > ®isters, RegisterT reg, ValueNode *node)
RegisterFrameState< RegisterT > & GetRegisterFrameState()
RegisterFrameState< Register > general_registers_
~StraightForwardRegisterAllocator()
ZoneVector< BlockPatch > patches_
void ClearRegisterValues()
void UpdateUse(Input *input)
void HoistLoopReloads(BasicBlock *target, RegisterFrameState< RegisterT > ®isters)
void SaveRegisterSnapshot(NodeBase *node)
void InitializeBranchTargetPhis(int predecessor_id, BasicBlock *target)
void Spill(ValueNode *node)
void InitializeConditionalBranchTarget(ConditionalControlNode *source, BasicBlock *target)
void ApplyPatches(BasicBlock *block)
RegallocInfo * regalloc_info_
void AddMoveBeforeCurrentNode(ValueNode *node, compiler::InstructionOperand source, compiler::AllocatedOperand target)
void EnsureFreeRegisterAtEnd(const compiler::InstructionOperand &hint=compiler::InstructionOperand())
void AllocateNode(Node *node)
void AllocateLazyDeopt(const LazyDeoptInfo &deopt_info)
MaglevGraphLabeller * graph_labeller() const
void SetLoopPhiRegisterHint(Phi *phi, RegisterT reg)
void MergeRegisterValues(ControlNode *control, BasicBlock *target, int predecessor_id)
void AllocateSpillSlot(ValueNode *node)
void InitializeRegisterValues(MergePointRegisterState &target_state)
void AssignFixedTemporaries(RegisterFrameState< RegisterT > ®isters, NodeBase *node)
void AssignArbitraryRegisterInput(NodeBase *result_node, Input &input)
void AllocateEagerDeopt(const EagerDeoptInfo &deopt_info)
void AssignInputs(NodeBase *node)
void HoistLoopSpills(BasicBlock *target)
bool has_fallthrough() const
BasicBlockRef * targets() const
void InjectLocation(compiler::InstructionOperand location)
void SetAllocated(Args &&... args)
compiler::InstructionOperand loadable_slot() const
LiveRange live_range() const
NodeIdT current_next_use() const
constexpr bool use_double_register() const
constexpr MachineRepresentation GetMachineRepresentation() const
const compiler::InstructionOperand & hint() const
LiftoffAssembler::CacheState state
RegListBase< RegisterT > registers
InstructionOperand source
DoubleRegister ToDoubleRegister(const compiler::InstructionOperand &operand)
constexpr bool IsConstantNode(Opcode opcode)
Register ToRegister(const compiler::InstructionOperand &operand)
static constexpr int kNoVreg
bool LoadMergeState(RegisterState state, RegisterMerge **merge)
constexpr bool IsDoubleRepresentation(ValueRepresentation repr)
constexpr int kSystemPointerSize
constexpr Register kReturnRegister0
V8_EXPORT_PRIVATE FlagValues v8_flags
other heap size generate builtins concurrently on separate threads in mksnapshot track concurrent recompilation artificial compilation delay in ms max number of threads that concurrent Turbofan can use(0 for unbounded)") DEFINE_BOOL( stress_concurrent_inlining
constexpr int kDoubleSize
#define CHECK_GE(lhs, rhs)
#define CHECK_GT(lhs, rhs)
#define DCHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
absl::flat_hash_map< BasicBlock::Id, RegallocLoopInfo > loop_info_
compiler::InstructionOperand & operand(size_t i)
std::vector< SpillSlotInfo > free_slots