Commit 2db140b5 authored by Toon Verwaest's avatar Toon Verwaest Committed by V8 LUCI CQ

[maglev] Replace LiveNodeInfo reg with registers

Instead of storing a single register, store the entire RegList. This
simplifies a lot of things. We will use RegLists for free registers etc
too later.

Bug: v8:7700
Change-Id: I32146023c7b9bc9e553e3db98fe034e8cef7d09d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3487994Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Auto-Submit: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79289}
parent 51e81982
......@@ -54,13 +54,23 @@ class RegisterBase {
return is_valid() ? RegList{1} << code() : RegList{};
}
static constexpr SubType AnyOf(RegList list) {
DCHECK_NE(kEmptyRegList, list);
return from_code(base::bits::CountTrailingZeros(list));
}
static constexpr SubType TakeAny(RegList* list) {
RegList& value = *list;
SubType result = from_code(base::bits::CountTrailingZerosNonZero(value));
*list = value & (value - 1);
RegList value = *list;
SubType result = AnyOf(value);
result.RemoveFrom(list);
return result;
}
constexpr void RemoveFrom(RegList* list) const {
DCHECK_EQ(bit(), (*list) & bit());
*list ^= bit();
}
inline constexpr bool operator==(SubType other) const {
return reg_code_ == other.reg_code_;
}
......
......@@ -5,6 +5,7 @@
#include "src/maglev/maglev-regalloc.h"
#include "src/base/logging.h"
#include "src/codegen/reglist.h"
#include "src/compiler/backend/instruction.h"
#include "src/maglev/maglev-compilation-data.h"
#include "src/maglev/maglev-graph-labeller.h"
......@@ -311,78 +312,37 @@ void StraightForwardRegisterAllocator::AllocateRegisters(Graph* graph) {
}
}
class StraightForwardRegisterAllocator::InputsUpdater {
public:
explicit InputsUpdater(StraightForwardRegisterAllocator* allocator,
NodeBase* node)
: allocator_(allocator), use_(node->id()) {}
void UpdateInputUse(const Input& input) {
ValueNode* node = input.node();
auto it = allocator_->values_.find(node);
// If a value is dead, make sure it's cleared.
if (node->live_range().end == use_) {
// Mark the info for clearing by clearing the node.
if (it->second.node == nullptr) return;
if (it->second.reg.is_valid()) {
// Collect values in registers for clearing later.
it->second.node = nullptr;
to_clear_[register_values_to_clear_++] = it;
} else {
// Immediately clear values in stack slots.
Clear(it);
}
} else {
// Otherwise update the next use.
DCHECK_NE(it, allocator_->values_.end());
it->second.next_use = input.next_use_id();
}
}
void StraightForwardRegisterAllocator::UpdateInputUse(uint32_t use,
const Input& input) {
ValueNode* node = input.node();
auto it = values_.find(node);
~InputsUpdater() {
// If no values died, simply return.
if (register_values_to_clear_ == 0) return;
// First clear the registers pointing to to-clear infos.
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
LiveNodeInfo* value = allocator_->register_values_[i];
if (value == nullptr) continue;
if (value->node != nullptr) {
// The value shouldn't be dead yet.
// TODO(verwaest): This won't work yet because of deopt uses.
// DCHECK_GT(value->last_use, use_);
continue;
}
allocator_->FreeRegister(i);
}
// Then clear the infos.
for (int i = 0; i < register_values_to_clear_; i++) Clear(to_clear_[i]);
}
// The value was already cleared through a previous input.
if (it == values_.end()) return;
private:
void Clear(LiveNodeInfoMap::iterator& it) {
// If a value is dead, make sure it's cleared.
if (node->live_range().end == use) {
LiveNodeInfo& info = it->second;
FreeRegisters(&info.registers);
// If the stack slot is a local slot, free it so it can be reused.
if (info.stack_slot.IsAnyStackSlot()) {
compiler::AllocatedOperand slot =
compiler::AllocatedOperand::cast(info.stack_slot);
if (slot.index() > 0) allocator_->free_slots_.push_back(slot.index());
if (slot.index() > 0) free_slots_.push_back(slot.index());
}
allocator_->values_.erase(it);
values_.erase(it);
return;
}
StraightForwardRegisterAllocator* const allocator_;
const uint32_t use_;
LiveNodeInfoMap::iterator to_clear_[kAllocatableGeneralRegisterCount];
int register_values_to_clear_ = 0;
};
// Otherwise update the next use.
it->second.next_use = input.next_use_id();
}
void StraightForwardRegisterAllocator::AllocateNode(Node* node) {
for (Input& input : *node) AssignInput(input);
AssignTemporaries(node);
{
InputsUpdater updater(this, node);
for (Input& input : *node) updater.UpdateInputUse(input);
}
for (Input& input : *node) UpdateInputUse(node->id(), input);
if (node->properties().is_call()) SpillAndClearRegisters();
// TODO(verwaest): This isn't a good idea :)
......@@ -453,10 +413,10 @@ void StraightForwardRegisterAllocator::AllocateNodeResult(ValueNode* node) {
if (!node->has_valid_live_range() &&
node->result().operand().IsAnyRegister()) {
auto it = values_.find(node);
Register reg = it->second.reg;
DCHECK(reg.is_valid());
DCHECK(it->second.has_register());
FreeRegisters(&it->second.registers);
DCHECK(!it->second.has_register());
values_.erase(it);
FreeRegister(MapRegisterToIndex(reg));
}
}
......@@ -470,27 +430,14 @@ void StraightForwardRegisterAllocator::Free(const Register& reg) {
// Free the register without adding it to the list.
register_values_[index] = nullptr;
// If the value we're freeing from the register is already known to be
// assigned to a different register as well, simply reeturn.
if (reg != info->reg) {
DCHECK_EQ(info, register_values_[MapRegisterToIndex(info->reg)]);
return;
}
info->reg = Register::no_reg();
// Remove the register from the list.
reg.RemoveFrom(&info->registers);
// Return if the removed value already has another register.
if (info->has_register()) return;
// If the value is already spilled, return.
if (info->stack_slot.IsAnyStackSlot()) return;
// If the value is already in another register, return.
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
if (register_values_[i] == info) {
// Found an existing register.
info->reg = MapIndexToRegister(i);
return;
}
}
// Try to move the value to another register.
if (free_register_size_ > 0) {
Register target_reg =
......@@ -534,8 +481,7 @@ void StraightForwardRegisterAllocator::InitializeConditionalBranchRegisters(
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
LiveNodeInfo* info = register_values_[i];
if (info != nullptr && !IsLiveAtTarget(info, node, target)) {
info->reg = Register::no_reg();
FreeRegister(i);
FreeRegisters(&info->registers);
}
}
}
......@@ -544,10 +490,7 @@ void StraightForwardRegisterAllocator::AllocateControlNode(ControlNode* node,
BasicBlock* block) {
for (Input& input : *node) AssignInput(input);
AssignTemporaries(node);
{
InputsUpdater updater(this, node);
for (Input& input : *node) updater.UpdateInputUse(input);
}
for (Input& input : *node) UpdateInputUse(node->id(), input);
if (node->properties().is_call()) SpillAndClearRegisters();
......@@ -561,9 +504,8 @@ void StraightForwardRegisterAllocator::AllocateControlNode(ControlNode* node,
LiveNodeInfo& info = values_[input.node()];
input.InjectAllocated(info.allocation());
}
InputsUpdater updater(this, node);
for (Phi* phi : *phis) {
updater.UpdateInputUse(phi->input(block->predecessor_id()));
UpdateInputUse(phi->id(), phi->input(block->predecessor_id()));
}
}
}
......@@ -705,8 +647,7 @@ void StraightForwardRegisterAllocator::SpillAndClearRegisters() {
LiveNodeInfo* info = register_values_[i];
if (info == nullptr) continue;
Spill(info);
info->reg = Register::no_reg();
FreeRegister(i);
FreeRegisters(&info->registers);
}
}
......@@ -762,6 +703,7 @@ compiler::AllocatedOperand StraightForwardRegisterAllocator::ForceAllocate(
const Register& reg, LiveNodeInfo* info) {
if (register_values_[MapRegisterToIndex(reg)] == nullptr) {
// If it's already free, remove it from the free list.
// TODO(verwaest): This should just be a mask.
for (int i = 0; i < free_register_size_; i++) {
if (MapRegisterToIndex(reg) == free_registers_[i]) {
std::swap(free_registers_[i], free_registers_[--free_register_size_]);
......@@ -792,7 +734,7 @@ void StraightForwardRegisterAllocator::SetRegister(Register reg,
DCHECK_IMPLIES(register_values_[index] != info,
register_values_[index] == nullptr);
register_values_[index] = info;
info->reg = reg;
info->registers = CombineRegLists(info->registers, Register::ListOf(reg));
}
compiler::InstructionOperand
......@@ -815,10 +757,12 @@ void StraightForwardRegisterAllocator::AssignTemporaries(NodeBase* node) {
void StraightForwardRegisterAllocator::InitializeRegisterValues(
RegisterState* target_state) {
// First clear the register state.
// TODO(verwaest): We could loop over the list of allocated registers by
// deducing it from the free registers.
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
LiveNodeInfo* info = register_values_[i];
if (info == nullptr) continue;
info->reg = Register::no_reg();
info->registers = kEmptyRegList;
}
// Mark no register as free.
......@@ -832,10 +776,9 @@ void StraightForwardRegisterAllocator::InitializeRegisterValues(
if (node == nullptr) {
DCHECK(!target_state[i].GetPayload().is_merge);
FreeRegister(i);
continue;
} else {
SetRegister(MapIndexToRegister(i), node);
}
register_values_[i] = node;
node->reg = MapIndexToRegister(i);
}
}
......
......@@ -5,6 +5,7 @@
#ifndef V8_MAGLEV_MAGLEV_REGALLOC_H_
#define V8_MAGLEV_MAGLEV_REGALLOC_H_
#include "src/codegen/reglist.h"
#include "src/compiler/backend/instruction.h"
#include "src/maglev/maglev-compilation-data.h"
#include "src/maglev/maglev-graph.h"
......@@ -22,13 +23,15 @@ struct LiveNodeInfo {
uint32_t last_use = 0;
uint32_t next_use = 0;
compiler::InstructionOperand stack_slot = compiler::InstructionOperand();
Register reg = Register::no_reg();
RegList registers = kEmptyRegList;
bool has_register() const { return registers != kEmptyRegList; }
compiler::AllocatedOperand allocation() const {
if (reg.is_valid()) {
if (has_register()) {
return compiler::AllocatedOperand(compiler::LocationOperand::REGISTER,
MachineRepresentation::kTagged,
reg.code());
Register::AnyOf(registers).code());
}
return compiler::AllocatedOperand::cast(stack_slot);
}
......@@ -72,7 +75,7 @@ class StraightForwardRegisterAllocator {
void PrintLiveRegs() const;
class InputsUpdater;
void UpdateInputUse(uint32_t use, const Input& input);
void AllocateControlNode(ControlNode* node, BasicBlock* block);
void AllocateNode(Node* node);
......@@ -81,6 +84,12 @@ class StraightForwardRegisterAllocator {
void AssignTemporaries(NodeBase* node);
void TryAllocateToInput(LiveNodeInfo* info, Phi* phi);
void FreeRegisters(RegList* list) {
while (*list != kEmptyRegList) {
Register reg = Register::TakeAny(list);
FreeRegister(MapRegisterToIndex(reg));
}
}
void FreeRegister(int i);
void FreeSomeRegister();
RegList GetFreeRegisters(int count);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment