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