[maglev] Use free list for iterating used registers
Don't rely on register_values[index] == nullptr for checking if a register is free, but instead re-use the free register list, and iterate the allocatable_register & ~free_register list when iterating used registers. This also changes the indexing of register_values to be by register code, not allocatable register index. The register state stored on the InterpreterFrameState, however, stays compact (allocatable register count). A new wrapper class + iterator keeps iteration over it and the register_values array in sync. Bug: v8:7700 Change-Id: I7815aa2d4a1f7b7ebafaaafe0727219adcc4dcfe Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3512792 Auto-Submit: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/main@{#79434}
This commit is contained in:
parent
0f5f6024ff
commit
0504331b78
@ -243,6 +243,19 @@ class Register : public CPURegister {
|
||||
return Register::Create(code, kXRegSizeInBits);
|
||||
}
|
||||
|
||||
// Copied from RegisterBase since there's no CPURegister::from_code.
|
||||
static constexpr Register FirstOf(RegList list) {
|
||||
DCHECK_NE(kEmptyRegList, list);
|
||||
return from_code(base::bits::CountTrailingZerosNonZero(list));
|
||||
}
|
||||
|
||||
static constexpr Register TakeFirst(RegList* list) {
|
||||
RegList value = *list;
|
||||
Register result = FirstOf(value);
|
||||
result.RemoveFrom(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* GetSpecialRegisterName(int code) {
|
||||
return (code == kSPRegInternalCode) ? "sp" : "UNKNOWN";
|
||||
}
|
||||
|
@ -55,25 +55,27 @@ class RegisterBase {
|
||||
return is_valid() ? RegList{1} << code() : RegList{};
|
||||
}
|
||||
|
||||
static constexpr SubType AnyOf(RegList list) {
|
||||
static constexpr SubType FirstOf(RegList list) {
|
||||
DCHECK_NE(kEmptyRegList, list);
|
||||
return from_code(base::bits::CountTrailingZeros(list));
|
||||
return SubType::from_code(base::bits::CountTrailingZerosNonZero(list));
|
||||
}
|
||||
|
||||
static constexpr SubType TakeAny(RegList* list) {
|
||||
static constexpr SubType TakeFirst(RegList* list) {
|
||||
RegList value = *list;
|
||||
SubType result = AnyOf(value);
|
||||
SubType result = FirstOf(value);
|
||||
result.RemoveFrom(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr bool IsIn(RegList list) const { return list & bit(); }
|
||||
|
||||
constexpr void InsertInto(RegList* list) const {
|
||||
DCHECK_NE(bit(), (*list) & bit());
|
||||
DCHECK(!IsIn(*list));
|
||||
*list |= bit();
|
||||
}
|
||||
|
||||
constexpr void RemoveFrom(RegList* list) const {
|
||||
DCHECK_EQ(bit(), (*list) & bit());
|
||||
DCHECK(IsIn(*list));
|
||||
*list ^= bit();
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,29 @@ inline constexpr bool AreAliased(RegType first_reg, RegTypes... regs) {
|
||||
}
|
||||
#endif
|
||||
|
||||
class RegListIterator {
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
explicit Iterator(RegList list) : list_(list) {}
|
||||
Register operator*() { return Register::FirstOf(list_); }
|
||||
void operator++() { Register::FirstOf(list_).RemoveFrom(&list_); }
|
||||
bool operator!=(const Iterator& other) const {
|
||||
return list_ != other.list_;
|
||||
}
|
||||
|
||||
private:
|
||||
RegList list_;
|
||||
};
|
||||
|
||||
explicit RegListIterator(RegList list) : list_(list) {}
|
||||
Iterator begin() const { return Iterator(list_); }
|
||||
Iterator end() const { return Iterator(kEmptyRegList); }
|
||||
|
||||
private:
|
||||
RegList list_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -249,11 +249,11 @@ class MaglevCodeGeneratingNodeProcessor {
|
||||
|
||||
__ RecordComment("-- Gap moves:");
|
||||
|
||||
for (int index = 0; index < kAllocatableGeneralRegisterCount; ++index) {
|
||||
for (auto entry : target->state()->register_state()) {
|
||||
RegisterMerge* merge;
|
||||
if (LoadMergeState(target->state()->register_state()[index], &merge)) {
|
||||
if (LoadMergeState(entry.state, &merge)) {
|
||||
compiler::AllocatedOperand source = merge->operand(predecessor_id);
|
||||
Register target_reg = MapIndexToRegister(index);
|
||||
Register target_reg = entry.reg;
|
||||
|
||||
if (FLAG_code_comments) {
|
||||
std::stringstream ss;
|
||||
|
@ -67,6 +67,46 @@ class InterpreterFrameState {
|
||||
RegisterFrameArray<ValueNode*> frame_;
|
||||
};
|
||||
|
||||
class MergePointRegisterState {
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
struct Entry {
|
||||
RegisterState& state;
|
||||
Register reg;
|
||||
};
|
||||
explicit Iterator(RegisterState* value_pointer,
|
||||
RegListIterator::Iterator reg_iterator)
|
||||
: current_value_(value_pointer), reg_iterator_(reg_iterator) {}
|
||||
Entry operator*() { return {*current_value_, *reg_iterator_}; }
|
||||
void operator++() {
|
||||
++current_value_;
|
||||
++reg_iterator_;
|
||||
}
|
||||
bool operator!=(const Iterator& other) const {
|
||||
return current_value_ != other.current_value_;
|
||||
}
|
||||
|
||||
private:
|
||||
RegisterState* current_value_;
|
||||
RegListIterator::Iterator reg_iterator_;
|
||||
};
|
||||
|
||||
bool is_initialized() const { return values_[0].GetPayload().is_initialized; }
|
||||
|
||||
Iterator begin() {
|
||||
return Iterator(values_,
|
||||
RegListIterator::Iterator(kAllocatableGeneralRegisters));
|
||||
}
|
||||
Iterator end() {
|
||||
return Iterator(values_ + kAllocatableGeneralRegisterCount,
|
||||
RegListIterator::Iterator(kEmptyRegList));
|
||||
}
|
||||
|
||||
private:
|
||||
RegisterState values_[kAllocatableGeneralRegisterCount] = {{}};
|
||||
};
|
||||
|
||||
class MergePointInterpreterFrameState {
|
||||
public:
|
||||
void CheckIsLoopPhiIfNeeded(const MaglevCompilationUnit& compilation_unit,
|
||||
@ -161,7 +201,7 @@ class MergePointInterpreterFrameState {
|
||||
DCHECK_LE(predecessors_so_far_, predecessor_count_);
|
||||
}
|
||||
|
||||
RegisterState* register_state() { return register_values_; }
|
||||
MergePointRegisterState& register_state() { return register_state_; }
|
||||
|
||||
// Merges an unmerged framestate with a possibly merged framestate into |this|
|
||||
// framestate.
|
||||
@ -340,10 +380,7 @@ class MergePointInterpreterFrameState {
|
||||
const compiler::BytecodeLivenessState* liveness_ = nullptr;
|
||||
BasicBlock** predecessors_;
|
||||
|
||||
#define N(V) RegisterState{nullptr},
|
||||
RegisterState register_values_[kAllocatableGeneralRegisterCount] = {
|
||||
ALLOCATABLE_GENERAL_REGISTERS(N)};
|
||||
#undef N
|
||||
MergePointRegisterState register_state_;
|
||||
};
|
||||
|
||||
void InterpreterFrameState::CopyFrom(
|
||||
|
@ -507,7 +507,7 @@ void CheckMaps::GenerateCode(MaglevCodeGenState* code_gen_state,
|
||||
const ProcessingState& state) {
|
||||
Register object = ToRegister(actual_map_input());
|
||||
RegList temps = temporaries();
|
||||
Register map_tmp = Register::TakeAny(&temps);
|
||||
Register map_tmp = Register::TakeFirst(&temps);
|
||||
|
||||
__ LoadMap(map_tmp, object);
|
||||
__ Cmp(map_tmp, map().object());
|
||||
|
@ -567,10 +567,7 @@ class ValueNode : public Node {
|
||||
// A node is dead once it has no more upcoming uses.
|
||||
bool is_dead() const { return next_use_ == kInvalidNodeId; }
|
||||
|
||||
void AddRegister(Register reg) {
|
||||
registers_with_result_ =
|
||||
CombineRegLists(registers_with_result_, Register::ListOf(reg));
|
||||
}
|
||||
void AddRegister(Register reg) { reg.InsertInto(®isters_with_result_); }
|
||||
void RemoveRegister(Register reg) { reg.RemoveFrom(®isters_with_result_); }
|
||||
RegList ClearRegisters() {
|
||||
return std::exchange(registers_with_result_, kEmptyRegList);
|
||||
@ -581,7 +578,7 @@ class ValueNode : public Node {
|
||||
if (has_register()) {
|
||||
return compiler::AllocatedOperand(
|
||||
compiler::LocationOperand::REGISTER, MachineRepresentation::kTagged,
|
||||
Register::AnyOf(registers_with_result_).code());
|
||||
Register::FirstOf(registers_with_result_).code());
|
||||
}
|
||||
DCHECK(is_spilled());
|
||||
return compiler::AllocatedOperand::cast(spill_or_hint_);
|
||||
|
@ -20,32 +20,6 @@ static constexpr int kAllocatableGeneralRegisterCount =
|
||||
ALLOCATABLE_GENERAL_REGISTERS(COUNT);
|
||||
#undef COUNT
|
||||
|
||||
constexpr uint8_t MapRegisterToIndex(Register r) {
|
||||
uint8_t count = 0;
|
||||
#define EMIT_BRANCH(V) \
|
||||
if (r == V) return count; \
|
||||
count++;
|
||||
ALLOCATABLE_GENERAL_REGISTERS(EMIT_BRANCH)
|
||||
#undef EMIT_BRANCH
|
||||
// TODO(v8:7700): Re-enable UNREACHABLE once we figure out how to to avoid
|
||||
// the gcc error 'call to non-constexpr function'.
|
||||
// UNREACHABLE();
|
||||
return 255;
|
||||
}
|
||||
|
||||
constexpr Register MapIndexToRegister(int i) {
|
||||
uint8_t count = 0;
|
||||
#define EMIT_BRANCH(V) \
|
||||
if (i == count) return V; \
|
||||
count++;
|
||||
ALLOCATABLE_GENERAL_REGISTERS(EMIT_BRANCH)
|
||||
#undef EMIT_BRANCH
|
||||
// TODO(v8:7700): Re-enable UNREACHABLE once we figure out how to to avoid
|
||||
// the gcc error 'call to non-constexpr function'.
|
||||
// UNREACHABLE();
|
||||
return no_reg;
|
||||
}
|
||||
|
||||
struct RegisterStateFlags {
|
||||
// TODO(v8:7700): Use the good old Flags mechanism.
|
||||
static constexpr int kIsMergeShift = 0;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/logging.h"
|
||||
#include "src/codegen/register.h"
|
||||
#include "src/codegen/reglist.h"
|
||||
#include "src/compiler/backend/instruction.h"
|
||||
#include "src/maglev/maglev-compilation-data.h"
|
||||
@ -58,7 +59,7 @@ ControlNode* NearestPostDominatingHole(ControlNode* node) {
|
||||
}
|
||||
|
||||
bool IsLiveAtTarget(ValueNode* node, ControlNode* source, BasicBlock* target) {
|
||||
if (!node) return false;
|
||||
DCHECK_NOT_NULL(node);
|
||||
|
||||
// TODO(leszeks): We shouldn't have any dead nodes passed into here.
|
||||
if (node->is_dead()) return false;
|
||||
@ -197,15 +198,14 @@ void StraightForwardRegisterAllocator::ComputePostDominatingHoles(
|
||||
|
||||
void StraightForwardRegisterAllocator::PrintLiveRegs() const {
|
||||
bool first = true;
|
||||
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
ValueNode* node = register_values_[i];
|
||||
if (!node) continue;
|
||||
for (Register reg : RegListIterator(used_registers())) {
|
||||
ValueNode* node = GetUsedRegister(reg);
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
printing_visitor_->os() << ", ";
|
||||
}
|
||||
printing_visitor_->os() << MapIndexToRegister(i) << "=v" << node->id();
|
||||
printing_visitor_->os() << reg << "=v" << node->id();
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,27 +410,21 @@ void StraightForwardRegisterAllocator::AllocateNodeResult(ValueNode* node) {
|
||||
}
|
||||
}
|
||||
|
||||
void StraightForwardRegisterAllocator::Free(const Register& reg) {
|
||||
int index = MapRegisterToIndex(reg);
|
||||
ValueNode* node = register_values_[index];
|
||||
void StraightForwardRegisterAllocator::DropRegisterValue(Register reg) {
|
||||
// The register should not already be free.
|
||||
DCHECK(!reg.IsIn(free_registers_));
|
||||
|
||||
// If the register is already free, return.
|
||||
if (!node) return;
|
||||
ValueNode* node = GetUsedRegister(reg);
|
||||
|
||||
// Free the register without adding it to the list.
|
||||
register_values_[index] = nullptr;
|
||||
|
||||
// Remove the register from the list.
|
||||
// Remove the register from the node's list.
|
||||
node->RemoveRegister(reg);
|
||||
// Return if the removed value already has another register.
|
||||
if (node->has_register()) return;
|
||||
|
||||
// If the value is already spilled, return.
|
||||
if (node->is_spilled()) return;
|
||||
// Return if the removed value already has another register or is spilled.
|
||||
if (node->has_register() || node->is_spilled()) return;
|
||||
|
||||
// Try to move the value to another register.
|
||||
if (free_registers_ != kEmptyRegList) {
|
||||
Register target_reg = Register::TakeAny(&free_registers_);
|
||||
Register target_reg = Register::TakeFirst(&free_registers_);
|
||||
SetRegister(target_reg, node);
|
||||
// Emit a gapmove.
|
||||
compiler::AllocatedOperand source(compiler::LocationOperand::REGISTER,
|
||||
@ -467,10 +461,14 @@ void StraightForwardRegisterAllocator::InitializeConditionalBranchRegisters(
|
||||
}
|
||||
// Clear dead fall-through registers.
|
||||
DCHECK_EQ(control_node->id() + 1, target->first_id());
|
||||
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
ValueNode* node = register_values_[i];
|
||||
if (node != nullptr && !IsLiveAtTarget(node, control_node, target)) {
|
||||
RegList registers = used_registers();
|
||||
while (registers != kEmptyRegList) {
|
||||
Register reg = Register::TakeFirst(®isters);
|
||||
ValueNode* node = GetUsedRegister(reg);
|
||||
if (!IsLiveAtTarget(node, control_node, target)) {
|
||||
FreeRegisters(node);
|
||||
// Update the registers we're visiting to avoid revisiting this node.
|
||||
registers &= !free_registers_;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -526,8 +524,7 @@ void StraightForwardRegisterAllocator::TryAllocateToInput(Phi* phi) {
|
||||
for (Input& input : *phi) {
|
||||
if (input.operand().IsRegister()) {
|
||||
Register reg = input.AssignedRegister();
|
||||
int index = MapRegisterToIndex(reg);
|
||||
if (register_values_[index] == nullptr) {
|
||||
if (reg.IsIn(free_registers_)) {
|
||||
phi->result().SetAllocated(ForceAllocate(reg, phi));
|
||||
if (FLAG_trace_maglev_regalloc) {
|
||||
printing_visitor_->Process(
|
||||
@ -614,24 +611,19 @@ void StraightForwardRegisterAllocator::AssignInput(Input& input) {
|
||||
}
|
||||
|
||||
void StraightForwardRegisterAllocator::SpillRegisters() {
|
||||
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
ValueNode* node = register_values_[i];
|
||||
if (!node) continue;
|
||||
for (Register reg : RegListIterator(used_registers())) {
|
||||
ValueNode* node = GetUsedRegister(reg);
|
||||
Spill(node);
|
||||
}
|
||||
}
|
||||
|
||||
void StraightForwardRegisterAllocator::FreeRegister(int i) {
|
||||
register_values_[i] = nullptr;
|
||||
MapIndexToRegister(i).InsertInto(&free_registers_);
|
||||
}
|
||||
|
||||
void StraightForwardRegisterAllocator::SpillAndClearRegisters() {
|
||||
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
ValueNode* node = register_values_[i];
|
||||
if (!node) continue;
|
||||
while (used_registers() != kEmptyRegList) {
|
||||
Register reg = Register::FirstOf(used_registers());
|
||||
ValueNode* node = GetUsedRegister(reg);
|
||||
Spill(node);
|
||||
FreeRegisters(node);
|
||||
DCHECK(!reg.IsIn(used_registers()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -651,16 +643,16 @@ void StraightForwardRegisterAllocator::AllocateSpillSlot(ValueNode* node) {
|
||||
|
||||
void StraightForwardRegisterAllocator::FreeSomeRegister() {
|
||||
int furthest_use = 0;
|
||||
int longest = -1;
|
||||
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
if (!register_values_[i]) continue;
|
||||
int use = register_values_[i]->next_use();
|
||||
Register best = Register::no_reg();
|
||||
for (Register reg : RegListIterator(used_registers())) {
|
||||
int use = GetUsedRegister(reg)->next_use();
|
||||
if (use > furthest_use) {
|
||||
furthest_use = use;
|
||||
longest = i;
|
||||
best = reg;
|
||||
}
|
||||
}
|
||||
FreeRegister(longest);
|
||||
DCHECK(best.is_valid());
|
||||
FreeRegister(best);
|
||||
}
|
||||
|
||||
compiler::AllocatedOperand StraightForwardRegisterAllocator::AllocateRegister(
|
||||
@ -672,21 +664,19 @@ compiler::AllocatedOperand StraightForwardRegisterAllocator::AllocateRegister(
|
||||
}
|
||||
|
||||
compiler::AllocatedOperand StraightForwardRegisterAllocator::ForceAllocate(
|
||||
const Register& reg, ValueNode* node) {
|
||||
if (register_values_[MapRegisterToIndex(reg)] == nullptr) {
|
||||
Register reg, ValueNode* node) {
|
||||
if (reg.IsIn(free_registers_)) {
|
||||
// If it's already free, remove it from the free list.
|
||||
reg.RemoveFrom(&free_registers_);
|
||||
} else if (register_values_[MapRegisterToIndex(reg)] == node) {
|
||||
} else if (GetUsedRegister(reg) == node) {
|
||||
return compiler::AllocatedOperand(compiler::LocationOperand::REGISTER,
|
||||
MachineRepresentation::kTagged,
|
||||
reg.code());
|
||||
} else {
|
||||
Free(reg);
|
||||
DCHECK_NULL(register_values_[MapRegisterToIndex(reg)]);
|
||||
DropRegisterValue(reg);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
DCHECK_NE(free_registers_,
|
||||
CombineRegLists(free_registers_, Register::ListOf(reg)));
|
||||
DCHECK(!reg.IsIn(free_registers_));
|
||||
#endif
|
||||
SetRegister(reg, node);
|
||||
return compiler::AllocatedOperand(compiler::LocationOperand::REGISTER,
|
||||
@ -695,17 +685,15 @@ compiler::AllocatedOperand StraightForwardRegisterAllocator::ForceAllocate(
|
||||
|
||||
void StraightForwardRegisterAllocator::SetRegister(Register reg,
|
||||
ValueNode* node) {
|
||||
int index = MapRegisterToIndex(reg);
|
||||
DCHECK_IMPLIES(register_values_[index] != node,
|
||||
register_values_[index] == nullptr);
|
||||
register_values_[index] = node;
|
||||
DCHECK(!reg.IsIn(free_registers_));
|
||||
register_values_[reg.code()] = node;
|
||||
node->AddRegister(reg);
|
||||
}
|
||||
|
||||
compiler::InstructionOperand
|
||||
StraightForwardRegisterAllocator::TryAllocateRegister(ValueNode* node) {
|
||||
if (free_registers_ == kEmptyRegList) return compiler::InstructionOperand();
|
||||
Register reg = Register::TakeAny(&free_registers_);
|
||||
Register reg = Register::TakeFirst(&free_registers_);
|
||||
|
||||
// Allocation succeeded. This might have found an existing allocation.
|
||||
// Simply update the state anyway.
|
||||
@ -729,79 +717,91 @@ void StraightForwardRegisterAllocator::AssignTemporaries(NodeBase* node) {
|
||||
}
|
||||
|
||||
void StraightForwardRegisterAllocator::InitializeRegisterValues(
|
||||
RegisterState* target_state) {
|
||||
MergePointRegisterState& 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++) {
|
||||
ValueNode* node = register_values_[i];
|
||||
if (!node) continue;
|
||||
node->ClearRegisters();
|
||||
while (used_registers() != kEmptyRegList) {
|
||||
Register reg = Register::FirstOf(used_registers());
|
||||
ValueNode* node = GetUsedRegister(reg);
|
||||
FreeRegisters(node);
|
||||
DCHECK(!reg.IsIn(used_registers()));
|
||||
}
|
||||
|
||||
// Mark no register as free.
|
||||
free_registers_ = kEmptyRegList;
|
||||
// All registers should be free by now.
|
||||
DCHECK_EQ(free_registers_, kAllocatableGeneralRegisters);
|
||||
|
||||
// Then fill it in with target information.
|
||||
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
for (auto entry : target_state) {
|
||||
Register reg = entry.reg;
|
||||
|
||||
ValueNode* node;
|
||||
RegisterMerge* merge;
|
||||
LoadMergeState(target_state[i], &node, &merge);
|
||||
if (node == nullptr) {
|
||||
DCHECK(!target_state[i].GetPayload().is_merge);
|
||||
FreeRegister(i);
|
||||
LoadMergeState(entry.state, &node, &merge);
|
||||
if (node != nullptr) {
|
||||
reg.RemoveFrom(&free_registers_);
|
||||
SetRegister(reg, node);
|
||||
} else {
|
||||
SetRegister(MapIndexToRegister(i), node);
|
||||
DCHECK(!entry.state.GetPayload().is_merge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StraightForwardRegisterAllocator::EnsureInRegister(
|
||||
RegisterState* target_state, ValueNode* incoming) {
|
||||
MergePointRegisterState& target_state, ValueNode* incoming) {
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
for (i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
bool found = false;
|
||||
for (auto entry : target_state) {
|
||||
ValueNode* node;
|
||||
RegisterMerge* merge;
|
||||
LoadMergeState(target_state[i], &node, &merge);
|
||||
if (node == incoming) break;
|
||||
LoadMergeState(entry.state, &node, &merge);
|
||||
if (node == incoming) found = true;
|
||||
}
|
||||
CHECK_NE(kAllocatableGeneralRegisterCount, i);
|
||||
DCHECK(found);
|
||||
#endif
|
||||
}
|
||||
|
||||
void StraightForwardRegisterAllocator::InitializeBranchTargetRegisterValues(
|
||||
ControlNode* source, BasicBlock* target) {
|
||||
RegisterState* target_state = target->state()->register_state();
|
||||
DCHECK(!target_state[0].GetPayload().is_initialized);
|
||||
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
ValueNode* node = register_values_[i];
|
||||
if (!IsLiveAtTarget(node, source, target)) node = nullptr;
|
||||
target_state[i] = {node, initialized_node};
|
||||
MergePointRegisterState& target_state = target->state()->register_state();
|
||||
DCHECK(!target_state.is_initialized());
|
||||
for (auto entry : target_state) {
|
||||
Register reg = entry.reg;
|
||||
ValueNode* node = nullptr;
|
||||
if (!reg.IsIn(free_registers_)) {
|
||||
node = GetUsedRegister(reg);
|
||||
if (!IsLiveAtTarget(node, source, target)) node = nullptr;
|
||||
}
|
||||
entry.state = {node, initialized_node};
|
||||
}
|
||||
}
|
||||
|
||||
void StraightForwardRegisterAllocator::MergeRegisterValues(ControlNode* control,
|
||||
BasicBlock* target,
|
||||
int predecessor_id) {
|
||||
RegisterState* target_state = target->state()->register_state();
|
||||
if (!target_state[0].GetPayload().is_initialized) {
|
||||
MergePointRegisterState& target_state = target->state()->register_state();
|
||||
if (!target_state.is_initialized()) {
|
||||
// This is the first block we're merging, initialize the values.
|
||||
return InitializeBranchTargetRegisterValues(control, target);
|
||||
}
|
||||
|
||||
int predecessor_count = target->state()->predecessor_count();
|
||||
for (int i = 0; i < kAllocatableGeneralRegisterCount; i++) {
|
||||
for (auto entry : target_state) {
|
||||
Register reg = entry.reg;
|
||||
|
||||
ValueNode* node;
|
||||
RegisterMerge* merge;
|
||||
LoadMergeState(target_state[i], &node, &merge);
|
||||
LoadMergeState(entry.state, &node, &merge);
|
||||
|
||||
compiler::AllocatedOperand register_info = {
|
||||
compiler::LocationOperand::REGISTER, MachineRepresentation::kTagged,
|
||||
MapIndexToRegister(i).code()};
|
||||
reg.code()};
|
||||
|
||||
ValueNode* incoming = register_values_[i];
|
||||
if (!IsLiveAtTarget(incoming, control, target)) incoming = nullptr;
|
||||
ValueNode* incoming = nullptr;
|
||||
if (!reg.IsIn(free_registers_)) {
|
||||
incoming = GetUsedRegister(reg);
|
||||
if (!IsLiveAtTarget(incoming, control, target)) {
|
||||
incoming = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (incoming == node) {
|
||||
// We're using the same register as the target already has. If registers
|
||||
@ -849,8 +849,8 @@ void StraightForwardRegisterAllocator::MergeRegisterValues(ControlNode* control,
|
||||
// Initialize the entire array with info_so_far since we don't know in
|
||||
// which order we've seen the predecessors so far. Predecessors we
|
||||
// haven't seen yet will simply overwrite their entry later.
|
||||
for (int j = 0; j < predecessor_count; j++) {
|
||||
merge->operand(j) = info_so_far;
|
||||
for (int i = 0; i < predecessor_count; i++) {
|
||||
merge->operand(i) = info_so_far;
|
||||
}
|
||||
// If the register is unallocated at the merge point, fill in the
|
||||
// incoming value. Otherwise find the merge-point node in the incoming
|
||||
@ -860,7 +860,7 @@ void StraightForwardRegisterAllocator::MergeRegisterValues(ControlNode* control,
|
||||
} else {
|
||||
merge->operand(predecessor_id) = node->allocation();
|
||||
}
|
||||
target_state[i] = {merge, initialized_merge};
|
||||
entry.state = {merge, initialized_merge};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ namespace internal {
|
||||
namespace maglev {
|
||||
|
||||
class MaglevPrintingVisitor;
|
||||
class MergePointRegisterState;
|
||||
|
||||
class StraightForwardRegisterAllocator {
|
||||
public:
|
||||
@ -27,17 +28,19 @@ class StraightForwardRegisterAllocator {
|
||||
int stack_slots() const { return top_of_stack_; }
|
||||
|
||||
private:
|
||||
std::vector<int> future_register_uses_[kAllocatableGeneralRegisterCount];
|
||||
|
||||
#define N(V) nullptr,
|
||||
ValueNode* register_values_[kAllocatableGeneralRegisterCount] = {
|
||||
ALLOCATABLE_GENERAL_REGISTERS(N)};
|
||||
#undef N
|
||||
std::vector<int> future_register_uses_[Register::kNumRegisters];
|
||||
ValueNode* register_values_[Register::kNumRegisters];
|
||||
|
||||
int top_of_stack_ = 0;
|
||||
RegList free_registers_ = kAllocatableGeneralRegisters;
|
||||
std::vector<uint32_t> free_slots_;
|
||||
|
||||
RegList used_registers() const {
|
||||
// Only allocatable registers should be free.
|
||||
DCHECK_EQ(free_registers_, free_registers_ & kAllocatableGeneralRegisters);
|
||||
return kAllocatableGeneralRegisters ^ free_registers_;
|
||||
}
|
||||
|
||||
void ComputePostDominatingHoles(Graph* graph);
|
||||
void AllocateRegisters(Graph* graph);
|
||||
|
||||
@ -54,12 +57,23 @@ class StraightForwardRegisterAllocator {
|
||||
|
||||
void FreeRegisters(ValueNode* node) {
|
||||
RegList list = node->ClearRegisters();
|
||||
while (list != kEmptyRegList) {
|
||||
Register reg = Register::TakeAny(&list);
|
||||
FreeRegister(MapRegisterToIndex(reg));
|
||||
}
|
||||
DCHECK_EQ(free_registers_ & list, kEmptyRegList);
|
||||
free_registers_ |= list;
|
||||
}
|
||||
void FreeRegister(int i);
|
||||
void FreeRegister(Register reg) { reg.InsertInto(&free_registers_); }
|
||||
|
||||
ValueNode* GetUsedRegister(Register reg) const {
|
||||
DCHECK(!reg.IsIn(free_registers_));
|
||||
ValueNode* node = register_values_[reg.code()];
|
||||
DCHECK_NOT_NULL(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
ValueNode* GetMaybeUsedRegister(Register reg) const {
|
||||
if (!reg.IsIn(free_registers_)) return nullptr;
|
||||
return GetUsedRegister(reg);
|
||||
}
|
||||
|
||||
void FreeSomeRegister();
|
||||
void AddMoveBeforeCurrentNode(compiler::AllocatedOperand source,
|
||||
compiler::AllocatedOperand target);
|
||||
@ -70,14 +84,14 @@ class StraightForwardRegisterAllocator {
|
||||
void SpillRegisters();
|
||||
|
||||
compiler::AllocatedOperand AllocateRegister(ValueNode* node);
|
||||
compiler::AllocatedOperand ForceAllocate(const Register& reg,
|
||||
ValueNode* node);
|
||||
compiler::AllocatedOperand ForceAllocate(Register reg, ValueNode* node);
|
||||
void SetRegister(Register reg, ValueNode* node);
|
||||
void Free(const Register& reg);
|
||||
void DropRegisterValue(Register reg);
|
||||
compiler::InstructionOperand TryAllocateRegister(ValueNode* node);
|
||||
|
||||
void InitializeRegisterValues(RegisterState* target_state);
|
||||
void EnsureInRegister(RegisterState* target_state, ValueNode* incoming);
|
||||
void InitializeRegisterValues(MergePointRegisterState& target_state);
|
||||
void EnsureInRegister(MergePointRegisterState& target_state,
|
||||
ValueNode* incoming);
|
||||
|
||||
void InitializeBranchTargetRegisterValues(ControlNode* source,
|
||||
BasicBlock* target);
|
||||
|
Loading…
Reference in New Issue
Block a user