v->erase(it);
}
+
+int GetRegisterCount(const RegisterConfiguration* cfg, RegisterKind kind) {
+ return kind == DOUBLE_REGISTERS ? cfg->num_aliased_double_registers()
+ : cfg->num_general_registers();
+}
+
+
+const ZoneVector<LiveRange*>& GetFixedRegisters(
+ const RegisterAllocationData* data, RegisterKind kind) {
+ return kind == DOUBLE_REGISTERS ? data->fixed_double_live_ranges()
+ : data->fixed_live_ranges();
+}
+
+
+const InstructionBlock* GetContainingLoop(const InstructionSequence* sequence,
+ const InstructionBlock* block) {
+ auto index = block->loop_header();
+ if (!index.IsValid()) return nullptr;
+ return sequence->InstructionBlockAt(index);
+}
+
+
+const InstructionBlock* GetInstructionBlock(const InstructionSequence* code,
+ LifetimePosition pos) {
+ return code->GetInstructionBlock(pos.ToInstructionIndex());
+}
+
+
+bool IsBlockBoundary(const InstructionSequence* code, LifetimePosition pos) {
+ return pos.IsFullStart() &&
+ code->GetInstructionBlock(pos.ToInstructionIndex())->code_start() ==
+ pos.ToInstructionIndex();
+}
+
+
} // namespace
};
-LiveRange::LiveRange(int id, Zone* zone)
+LiveRange::LiveRange(int id)
: id_(id),
spilled_(false),
has_slot_use_(false),
// Partition original use positions to the two live ranges.
if (use_before != nullptr) {
- use_before->next_ = nullptr;
+ use_before->set_next(nullptr);
} else {
first_pos_ = nullptr;
}
}
auto new_interval = new (zone) UseInterval(start, new_end);
- new_interval->next_ = first_interval_;
+ new_interval->set_next(first_interval_);
first_interval_ = new_interval;
if (new_interval->next() == nullptr) {
last_interval_ = new_interval;
// that each new use interval either precedes or intersects with
// last added interval.
DCHECK(start.Value() < first_interval_->end().Value());
- first_interval_->start_ = Min(start, first_interval_->start_);
- first_interval_->end_ = Max(end, first_interval_->end_);
+ first_interval_->set_start(Min(start, first_interval_->start()));
+ first_interval_->set_end(Max(end, first_interval_->end()));
}
}
}
use_pos->set_next(first_pos_);
first_pos_ = use_pos;
} else {
- use_pos->next_ = prev->next_;
- prev->next_ = use_pos;
+ use_pos->set_next(prev->next());
+ prev->set_next(use_pos);
}
if (prev_hint == nullptr && use_pos->HasHint()) {
LiveRange* RegisterAllocationData::NewLiveRange(int index) {
- // The LiveRange object itself can go in the local zone, but the
- // InstructionOperand needs to go in the code zone, since it may survive
- // register allocation.
- return new (allocation_zone()) LiveRange(index, code_zone());
+ return new (allocation_zone()) LiveRange(index);
}
// Without this hack, all uses with "any" policy would get the constant
// operand assigned.
if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) {
- for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) {
+ for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next()) {
if (pos->type() == UsePositionType::kRequiresSlot) continue;
UsePositionType new_type = UsePositionType::kAny;
// Can't mark phis as needing a register.
LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data,
- RegisterKind kind)
+ RegisterKind kind, Zone* local_zone)
: data_(data),
mode_(kind),
- num_registers_(kind == DOUBLE_REGISTERS
- ? config()->num_aliased_double_registers()
- : config()->num_general_registers()),
- unhandled_live_ranges_(allocation_zone()),
- active_live_ranges_(allocation_zone()),
- inactive_live_ranges_(allocation_zone()) {
+ num_registers_(GetRegisterCount(data->config(), kind)),
+ unhandled_live_ranges_(local_zone),
+ active_live_ranges_(local_zone),
+ inactive_live_ranges_(local_zone) {
unhandled_live_ranges().reserve(
static_cast<size_t>(code()->VirtualRegisterCount() * 2));
active_live_ranges().reserve(8);
DCHECK(active_live_ranges().empty());
DCHECK(inactive_live_ranges().empty());
- if (mode_ == DOUBLE_REGISTERS) {
- for (auto current : fixed_double_live_ranges()) {
- if (current != nullptr) AddToInactive(current);
- }
- } else {
- DCHECK(mode_ == GENERAL_REGISTERS);
- for (auto current : fixed_live_ranges()) {
- if (current != nullptr) AddToInactive(current);
+ auto& fixed_ranges = GetFixedRegisters(data(), mode_);
+ for (auto current : fixed_ranges) {
+ if (current != nullptr) {
+ DCHECK_EQ(mode_, current->Kind());
+ AddToInactive(current);
}
}
}
-const char* LinearScanAllocator::RegisterName(int allocation_index) {
+const char* LinearScanAllocator::RegisterName(int allocation_index) const {
if (mode_ == GENERAL_REGISTERS) {
return config()->general_register_name(allocation_index);
} else {
bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) {
LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters];
- for (int i = 0; i < num_registers_; i++) {
+ for (int i = 0; i < num_registers(); i++) {
free_until_pos[i] = LifetimePosition::MaxPosition();
}
if (free_until_pos[register_index].Value() >= current->End().Value()) {
TRACE("Assigning preferred reg %s to live range %d\n",
RegisterName(register_index), current->id());
- SetLiveRangeAssignedRegister(current, register_index);
+ data()->SetLiveRangeAssignedRegister(current, register_index);
return true;
}
}
// Find the register which stays free for the longest time.
int reg = 0;
- for (int i = 1; i < RegisterCount(); ++i) {
+ for (int i = 1; i < num_registers(); ++i) {
if (free_until_pos[i].Value() > free_until_pos[reg].Value()) {
reg = i;
}
DCHECK(pos.Value() >= current->End().Value());
TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg),
current->id());
- SetLiveRangeAssignedRegister(current, reg);
+ data()->SetLiveRangeAssignedRegister(current, reg);
return true;
}
LifetimePosition use_pos[RegisterConfiguration::kMaxDoubleRegisters];
LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters];
- for (int i = 0; i < num_registers_; i++) {
+ for (int i = 0; i < num_registers(); i++) {
use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
}
}
int reg = 0;
- for (int i = 1; i < RegisterCount(); ++i) {
+ for (int i = 1; i < num_registers(); ++i) {
if (use_pos[i].Value() > use_pos[reg].Value()) {
reg = i;
}
DCHECK(block_pos[reg].Value() >= current->End().Value());
TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg),
current->id());
- SetLiveRangeAssignedRegister(current, reg);
+ data()->SetLiveRangeAssignedRegister(current, reg);
// This register was not free. Thus we need to find and spill
// parts of active and inactive live regions that use the same register
}
-static const InstructionBlock* GetContainingLoop(
- const InstructionSequence* sequence, const InstructionBlock* block) {
- auto index = block->loop_header();
- if (!index.IsValid()) return nullptr;
- return sequence->InstructionBlockAt(index);
-}
-
-
LifetimePosition LinearScanAllocator::FindOptimalSpillingPos(
LiveRange* range, LifetimePosition pos) {
- auto block = GetInstructionBlock(pos.Start());
+ auto block = GetInstructionBlock(code(), pos.Start());
auto loop_header =
block->IsLoopHeader() ? block : GetContainingLoop(code(), block);
for (size_t i = 0; i < phi->operands().size(); i++) {
int op = phi->operands()[i];
LiveRange* op_range = LiveRangeFor(op);
- if (op_range->GetSpillRange() == nullptr) continue;
+ if (!op_range->HasSpillRange()) continue;
auto pred = code()->InstructionBlockAt(block->predecessors()[i]);
auto pred_end = LifetimePosition::InstructionFromInstructionIndex(
pred->last_instruction_index());
for (size_t i = 1; i < phi->operands().size(); i++) {
int op = phi->operands()[i];
auto op_range = LiveRangeFor(op);
+ if (!op_range->HasSpillRange()) continue;
auto op_spill = op_range->GetSpillRange();
- if (op_spill != nullptr &&
- (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill))) {
+ if (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill)) {
num_merged++;
}
}
// We can't properly connect liveranges if splitting occurred at the end
// a block.
DCHECK(pos.IsStart() || pos.IsGapPosition() ||
- (code()->GetInstructionBlock(pos.ToInstructionIndex()))
- ->last_instruction_index() != pos.ToInstructionIndex());
+ (GetInstructionBlock(code(), pos)->last_instruction_index() !=
+ pos.ToInstructionIndex()));
- int vreg = GetVirtualRegister();
+ int vreg = code()->NextVirtualRegister();
auto result = LiveRangeFor(vreg);
range->SplitAt(pos, result, allocation_zone());
return result;
// We have no choice
if (start_instr == end_instr) return end;
- auto start_block = GetInstructionBlock(start);
- auto end_block = GetInstructionBlock(end);
+ auto start_block = GetInstructionBlock(code(), start);
+ auto end_block = GetInstructionBlock(code(), end);
if (end_block == start_block) {
// The interval is split in the same basic block. Split at the latest
// Split it at position between ]start+1, end[, spill the middle part
// and put the rest to unhandled.
auto third_part_end = end.PrevStart().End();
- if (data()->IsBlockBoundary(end.Start())) {
+ if (IsBlockBoundary(code(), end.Start())) {
third_part_end = end.Start();
}
auto third_part = SplitBetween(
class LiveRangeFinder {
public:
- explicit LiveRangeFinder(const RegisterAllocationData* data)
+ explicit LiveRangeFinder(const RegisterAllocationData* data, Zone* zone)
: data_(data),
bounds_length_(static_cast<int>(data_->live_ranges().size())),
- bounds_(data_->allocation_zone()->NewArray<LiveRangeBoundArray>(
- bounds_length_)) {
+ bounds_(zone->NewArray<LiveRangeBoundArray>(bounds_length_)),
+ zone_(zone) {
for (int i = 0; i < bounds_length_; ++i) {
new (&bounds_[i]) LiveRangeBoundArray();
}
DCHECK(range != nullptr && !range->IsEmpty());
auto array = &bounds_[operand_index];
if (array->ShouldInitialize()) {
- array->Initialize(data_->allocation_zone(), range);
+ array->Initialize(zone_, range);
}
return array;
}
const RegisterAllocationData* const data_;
const int bounds_length_;
LiveRangeBoundArray* const bounds_;
+ Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder);
};
}
-void LiveRangeConnector::ResolveControlFlow() {
+void LiveRangeConnector::ResolveControlFlow(Zone* local_zone) {
// Lazily linearize live ranges in memory for fast lookup.
- LiveRangeFinder finder(data());
+ LiveRangeFinder finder(data(), local_zone);
auto& live_in_sets = data()->live_in_sets();
for (auto block : code()->instruction_blocks()) {
if (CanEagerlyResolveControlFlow(block)) continue;
}
-void LiveRangeConnector::ConnectRanges(Zone* temp_zone) {
+void LiveRangeConnector::ConnectRanges(Zone* local_zone) {
ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand>
- delayed_insertion_map(temp_zone);
+ delayed_insertion_map(local_zone);
for (auto first_range : data()->live_ranges()) {
if (first_range == nullptr || first_range->IsChild()) continue;
for (auto second_range = first_range->next(); second_range != nullptr;
// boundary.
if (second_range->IsSpilled()) continue;
if (first_range->End().Value() != pos.Value()) continue;
- if (data()->IsBlockBoundary(pos) &&
- !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) {
+ if (IsBlockBoundary(code(), pos) &&
+ !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) {
continue;
}
auto prev_operand = first_range->GetAssignedOperand();
}
if (delayed_insertion_map.empty()) return;
// Insert all the moves which should occur after the stored move.
- ZoneVector<MoveOperands*> to_insert(temp_zone);
- ZoneVector<MoveOperands*> to_eliminate(temp_zone);
+ ZoneVector<MoveOperands*> to_insert(local_zone);
+ ZoneVector<MoveOperands*> to_eliminate(local_zone);
to_insert.reserve(4);
to_eliminate.reserve(4);
auto moves = delayed_insertion_map.begin()->first.first;
}
LifetimePosition start() const { return start_; }
+ void set_start(LifetimePosition start) { start_ = start; }
LifetimePosition end() const { return end_; }
+ void set_end(LifetimePosition end) { end_ = end; }
UseInterval* next() const { return next_; }
+ void set_next(UseInterval* next) { next_ = next; }
// Split this interval at the given position without effecting the
// live range that owns it. The interval must contain the position.
return start_.Value() <= point.Value() && point.Value() < end_.Value();
}
- void set_start(LifetimePosition start) { start_ = start; }
- void set_next(UseInterval* next) { next_ = next; }
-
+ private:
LifetimePosition start_;
LifetimePosition end_;
UseInterval* next_;
- private:
DISALLOW_COPY_AND_ASSIGN(UseInterval);
};
void set_next(UsePosition* next) { next_ = next; }
void set_type(UsePositionType type, bool register_beneficial);
+ private:
+ typedef BitField8<UsePositionType, 0, 2> TypeField;
+ typedef BitField8<bool, 2, 1> RegisterBeneficialField;
+
InstructionOperand* const operand_;
InstructionOperand* const hint_;
LifetimePosition const pos_;
UsePosition* next_;
-
- private:
- typedef BitField8<UsePositionType, 0, 2> TypeField;
- typedef BitField8<bool, 2, 1> RegisterBeneficialField;
uint8_t flags_;
DISALLOW_COPY_AND_ASSIGN(UsePosition);
public:
static const int kInvalidAssignment = 0x7fffffff;
- LiveRange(int id, Zone* zone);
+ explicit LiveRange(int id);
UseInterval* first_interval() const { return first_interval_; }
UsePosition* first_pos() const { return first_pos_; }
enum class SpillType { kNoSpillType, kSpillOperand, kSpillRange };
SpillType spill_type() const { return spill_type_; }
InstructionOperand* GetSpillOperand() const {
- return spill_type_ == SpillType::kSpillOperand ? spill_operand_ : nullptr;
+ DCHECK(spill_type_ == SpillType::kSpillOperand);
+ return spill_operand_;
}
SpillRange* GetSpillRange() const {
- return spill_type_ == SpillType::kSpillRange ? spill_range_ : nullptr;
+ DCHECK(spill_type_ == SpillType::kSpillRange);
+ return spill_range_;
}
bool HasNoSpillType() const { return spill_type_ == SpillType::kNoSpillType; }
bool HasSpillOperand() const {
void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
LiveRange* LiveRangeFor(int index);
- Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
+ Instruction* InstructionAt(int index) const {
+ return code()->InstructionAt(index);
+ }
void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment);
SpillRange* AssignSpillRangeToLiveRange(LiveRange* range);
const InstructionOperand& from,
const InstructionOperand& to);
- bool IsBlockBoundary(LifetimePosition pos) {
- return pos.IsFullStart() &&
- code()
- ->GetInstructionBlock(pos.ToInstructionIndex())
- ->code_start() == pos.ToInstructionIndex();
- }
-
- const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const {
- return code()->GetInstructionBlock(pos.ToInstructionIndex());
- }
-
bool IsReference(int virtual_register) const {
return code()->IsReference(virtual_register);
}
class LinearScanAllocator final : public ZoneObject {
public:
- explicit LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind);
+ LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind,
+ Zone* local_zone);
// Phase 4: compute register assignments.
void AllocateRegisters();
Zone* allocation_zone() const { return data()->allocation_zone(); }
Zone* code_zone() const { return code()->zone(); }
const RegisterConfiguration* config() const { return data()->config(); }
+ int num_registers() const { return num_registers_; }
+ const char* RegisterName(int allocation_index) const;
- Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
-
- int GetVirtualRegister() { return code()->NextVirtualRegister(); }
+ ZoneVector<LiveRange*>& live_ranges() { return data()->live_ranges(); }
+ ZoneVector<LiveRange*>& unhandled_live_ranges() {
+ return unhandled_live_ranges_;
+ }
+ ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; }
+ ZoneVector<LiveRange*>& inactive_live_ranges() {
+ return inactive_live_ranges_;
+ }
+ ZoneVector<SpillRange*>& spill_ranges() { return data()->spill_ranges(); }
+ RegisterAllocationData::PhiMap& phi_map() { return data()->phi_map(); }
+ Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
bool IsReference(int virtual_register) const {
return data()->IsReference(virtual_register);
}
-
LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
// Helper methods for updating the life range lists.
LifetimePosition FindOptimalSplitPos(LifetimePosition start,
LifetimePosition end);
+ void Spill(LiveRange* range);
+
// Spill the given life range after position pos.
void SpillAfter(LiveRange* range, LifetimePosition pos);
LifetimePosition FindOptimalSpillingPos(LiveRange* range,
LifetimePosition pos);
- void Spill(LiveRange* range);
-
- // Return the block which contains give lifetime position.
- const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const {
- return data()->GetInstructionBlock(pos);
- }
-
- void SetLiveRangeAssignedRegister(LiveRange* range, int reg) {
- data()->SetLiveRangeAssignedRegister(range, reg);
- }
-
- // Helper methods for the fixed registers.
- int RegisterCount() const { return num_registers_; }
- const char* RegisterName(int allocation_index);
-
- ZoneVector<LiveRange*>& live_ranges() { return data()->live_ranges(); }
- ZoneVector<LiveRange*>& fixed_live_ranges() {
- return data()->fixed_live_ranges();
- }
- ZoneVector<LiveRange*>& fixed_double_live_ranges() {
- return data()->fixed_double_live_ranges();
- }
- ZoneVector<LiveRange*>& unhandled_live_ranges() {
- return unhandled_live_ranges_;
- }
- ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; }
- ZoneVector<LiveRange*>& inactive_live_ranges() {
- return inactive_live_ranges_;
- }
- ZoneVector<SpillRange*>& spill_ranges() { return data()->spill_ranges(); }
- RegisterAllocationData::PhiMap& phi_map() { return data()->phi_map(); }
-
RegisterAllocationData* const data_;
const RegisterKind mode_;
const int num_registers_;
explicit LiveRangeConnector(RegisterAllocationData* data);
// Phase 8: reconnect split ranges with moves.
- void ConnectRanges(Zone* temp_zone);
+ void ConnectRanges(Zone* local_zone);
// Phase 9: insert moves to connect ranges across basic blocks.
- void ResolveControlFlow();
+ void ResolveControlFlow(Zone* local_zone);
private:
- const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const {
- return data()->GetInstructionBlock(pos);
- }
bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const;
void ResolveControlFlow(const InstructionBlock* block,
const InstructionOperand& cur_op,