[turbofan] split register allocator into little pieces

R=titzer@chromium.org

BUG=

Review URL: https://codereview.chromium.org/1094063002

Cr-Commit-Position: refs/heads/master@{#27946}
This commit is contained in:
dcarney 2015-04-20 09:15:34 -07:00 committed by Commit bot
parent f557d75360
commit 497c537310
5 changed files with 1655 additions and 1505 deletions

View File

@ -407,7 +407,7 @@ class GraphC1Visualizer {
void PrintSchedule(const char* phase, const Schedule* schedule,
const SourcePositionTable* positions,
const InstructionSequence* instructions);
void PrintAllocator(const char* phase, const RegisterAllocator* allocator);
void PrintLiveRanges(const char* phase, const RegisterAllocationData* data);
Zone* zone() const { return zone_; }
private:
@ -693,20 +693,20 @@ void GraphC1Visualizer::PrintSchedule(const char* phase,
}
void GraphC1Visualizer::PrintAllocator(const char* phase,
const RegisterAllocator* allocator) {
void GraphC1Visualizer::PrintLiveRanges(const char* phase,
const RegisterAllocationData* data) {
Tag tag(this, "intervals");
PrintStringProperty("name", phase);
for (auto range : allocator->fixed_double_live_ranges()) {
for (auto range : data->fixed_double_live_ranges()) {
PrintLiveRange(range, "fixed");
}
for (auto range : allocator->fixed_live_ranges()) {
for (auto range : data->fixed_live_ranges()) {
PrintLiveRange(range, "fixed");
}
for (auto range : allocator->live_ranges()) {
for (auto range : data->live_ranges()) {
PrintLiveRange(range, "object");
}
}
@ -791,9 +791,10 @@ std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
}
std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) {
std::ostream& operator<<(std::ostream& os,
const AsC1VRegisterAllocationData& ac) {
Zone tmp_zone;
GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_);
GraphC1Visualizer(os, &tmp_zone).PrintLiveRanges(ac.phase_, ac.data_);
return os;
}

View File

@ -16,7 +16,7 @@ namespace compiler {
class Graph;
class InstructionSequence;
class RegisterAllocator;
class RegisterAllocationData;
class Schedule;
class SourcePositionTable;
@ -67,18 +67,19 @@ struct AsC1V {
const char* phase_;
};
struct AsC1VAllocator {
explicit AsC1VAllocator(const char* phase,
const RegisterAllocator* allocator = NULL)
: phase_(phase), allocator_(allocator) {}
struct AsC1VRegisterAllocationData {
explicit AsC1VRegisterAllocationData(
const char* phase, const RegisterAllocationData* data = nullptr)
: phase_(phase), data_(data) {}
const char* phase_;
const RegisterAllocator* allocator_;
const RegisterAllocationData* data_;
};
std::ostream& operator<<(std::ostream& os, const AsDOT& ad);
std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac);
std::ostream& operator<<(std::ostream& os, const AsC1V& ac);
std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac);
std::ostream& operator<<(std::ostream& os,
const AsC1VRegisterAllocationData& ac);
} // namespace compiler
} // namespace internal

View File

@ -81,7 +81,9 @@ class PipelineData {
instruction_zone_(instruction_zone_scope_.zone()),
sequence_(nullptr),
frame_(nullptr),
register_allocator_(nullptr) {
register_allocation_zone_scope_(zone_pool_),
register_allocation_zone_(register_allocation_zone_scope_.zone()),
register_allocation_data_(nullptr) {
PhaseScope scope(pipeline_statistics, "init pipeline data");
graph_ = new (graph_zone_) Graph(graph_zone_);
source_positions_.Reset(new SourcePositionTable(graph_));
@ -121,7 +123,9 @@ class PipelineData {
instruction_zone_(instruction_zone_scope_.zone()),
sequence_(nullptr),
frame_(nullptr),
register_allocator_(nullptr) {}
register_allocation_zone_scope_(zone_pool_),
register_allocation_zone_(register_allocation_zone_scope_.zone()),
register_allocation_data_(nullptr) {}
// For register allocation testing entry point.
PipelineData(ZonePool* zone_pool, CompilationInfo* info,
@ -148,9 +152,12 @@ class PipelineData {
instruction_zone_(sequence->zone()),
sequence_(sequence),
frame_(nullptr),
register_allocator_(nullptr) {}
register_allocation_zone_scope_(zone_pool_),
register_allocation_zone_(register_allocation_zone_scope_.zone()),
register_allocation_data_(nullptr) {}
~PipelineData() {
DeleteRegisterAllocationZone();
DeleteInstructionZone();
DeleteGraphZone();
}
@ -200,7 +207,11 @@ class PipelineData {
Zone* instruction_zone() const { return instruction_zone_; }
InstructionSequence* sequence() const { return sequence_; }
Frame* frame() const { return frame_; }
RegisterAllocator* register_allocator() const { return register_allocator_; }
Zone* register_allocation_zone() const { return register_allocation_zone_; }
RegisterAllocationData* register_allocation_data() const {
return register_allocation_data_;
}
void DeleteGraphZone() {
// Destroy objects with destructors first.
@ -226,11 +237,17 @@ class PipelineData {
instruction_zone_ = nullptr;
sequence_ = nullptr;
frame_ = nullptr;
register_allocator_ = nullptr;
}
void DeleteRegisterAllocationZone() {
if (register_allocation_zone_ == nullptr) return;
register_allocation_zone_scope_.Destroy();
register_allocation_zone_ = nullptr;
register_allocation_data_ = nullptr;
}
void InitializeInstructionSequence() {
DCHECK(!sequence_);
DCHECK(sequence_ == nullptr);
InstructionBlocks* instruction_blocks =
InstructionSequence::InstructionBlocksFor(instruction_zone(),
schedule());
@ -238,14 +255,14 @@ class PipelineData {
info()->isolate(), instruction_zone(), instruction_blocks);
}
void InitializeRegisterAllocator(Zone* local_zone,
const RegisterConfiguration* config,
const char* debug_name) {
DCHECK(!register_allocator_);
DCHECK(!frame_);
void InitializeLiveRangeBuilder(const RegisterConfiguration* config,
const char* debug_name) {
DCHECK(frame_ == nullptr);
DCHECK(register_allocation_data_ == nullptr);
frame_ = new (instruction_zone()) Frame();
register_allocator_ = new (instruction_zone())
RegisterAllocator(config, local_zone, frame(), sequence(), debug_name);
register_allocation_data_ = new (register_allocation_zone())
RegisterAllocationData(config, register_allocation_zone(), frame(),
sequence(), debug_name);
}
private:
@ -281,7 +298,13 @@ class PipelineData {
Zone* instruction_zone_;
InstructionSequence* sequence_;
Frame* frame_;
RegisterAllocator* register_allocator_;
// All objects in the following group of fields are allocated in
// register_allocation_zone_. They are all set to NULL when the zone is
// destroyed.
ZonePool::Scope register_allocation_zone_scope_;
Zone* register_allocation_zone_;
RegisterAllocationData* register_allocation_data_;
DISALLOW_COPY_AND_ASSIGN(PipelineData);
};
@ -693,7 +716,8 @@ struct MeetRegisterConstraintsPhase {
static const char* phase_name() { return "meet register constraints"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->MeetRegisterConstraints();
LiveRangeBuilder builder(data->register_allocation_data());
builder.MeetRegisterConstraints();
}
};
@ -702,7 +726,8 @@ struct ResolvePhisPhase {
static const char* phase_name() { return "resolve phis"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->ResolvePhis();
LiveRangeBuilder builder(data->register_allocation_data());
builder.ResolvePhis();
}
};
@ -711,7 +736,8 @@ struct BuildLiveRangesPhase {
static const char* phase_name() { return "build live ranges"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->BuildLiveRanges();
LiveRangeBuilder builder(data->register_allocation_data());
builder.BuildLiveRanges();
}
};
@ -720,7 +746,9 @@ struct AllocateGeneralRegistersPhase {
static const char* phase_name() { return "allocate general registers"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->AllocateGeneralRegisters();
LinearScanAllocator allocator(data->register_allocation_data(),
GENERAL_REGISTERS);
allocator.AllocateRegisters();
}
};
@ -729,7 +757,9 @@ struct AllocateDoubleRegistersPhase {
static const char* phase_name() { return "allocate double registers"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->AllocateDoubleRegisters();
LinearScanAllocator allocator(data->register_allocation_data(),
DOUBLE_REGISTERS);
allocator.AllocateRegisters();
}
};
@ -738,7 +768,8 @@ struct AssignSpillSlotsPhase {
static const char* phase_name() { return "assign spill slots"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->AssignSpillSlots();
OperandAssigner assigner(data->register_allocation_data());
assigner.AssignSpillSlots();
}
};
@ -747,7 +778,8 @@ struct CommitAssignmentPhase {
static const char* phase_name() { return "commit assignment"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->CommitAssignment();
OperandAssigner assigner(data->register_allocation_data());
assigner.CommitAssignment();
}
};
@ -756,7 +788,8 @@ struct PopulateReferenceMapsPhase {
static const char* phase_name() { return "populate pointer maps"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->PopulateReferenceMaps();
ReferenceMapPopulator populator(data->register_allocation_data());
populator.PopulateReferenceMaps();
}
};
@ -765,7 +798,8 @@ struct ConnectRangesPhase {
static const char* phase_name() { return "connect ranges"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->ConnectRanges();
LiveRangeConnector connector(data->register_allocation_data());
connector.ConnectRanges(temp_zone);
}
};
@ -774,7 +808,8 @@ struct ResolveControlFlowPhase {
static const char* phase_name() { return "resolve control flow"; }
void Run(PipelineData* data, Zone* temp_zone) {
data->register_allocator()->ResolveControlFlow();
LiveRangeConnector connector(data->register_allocation_data());
connector.ResolveControlFlow();
}
};
@ -1216,9 +1251,7 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
debug_name = GetDebugName(data->info());
#endif
ZonePool::Scope zone_scope(data->zone_pool());
data->InitializeRegisterAllocator(zone_scope.zone(), config,
debug_name.get());
data->InitializeLiveRangeBuilder(config, debug_name.get());
if (info()->is_osr()) {
OsrHelper osr_helper(info());
osr_helper.SetupFrame(data->frame());
@ -1234,7 +1267,7 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
<< printable;
}
if (verifier != nullptr) {
CHECK(!data->register_allocator()->ExistsUseWithoutDefinition());
CHECK(!data->register_allocation_data()->ExistsUseWithoutDefinition());
}
Run<AllocateGeneralRegistersPhase>();
Run<AllocateDoubleRegistersPhase>();
@ -1262,8 +1295,11 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) {
TurboCfgFile tcf(data->isolate());
tcf << AsC1VAllocator("CodeGen", data->register_allocator());
tcf << AsC1VRegisterAllocationData("CodeGen",
data->register_allocation_data());
}
data->DeleteRegisterAllocationZone();
}
} // namespace compiler

File diff suppressed because it is too large Load Diff

View File

@ -340,17 +340,18 @@ class LiveRange final : public ZoneObject {
// Shorten the most recently added interval by setting a new start.
void ShortenTo(LifetimePosition start);
#ifdef DEBUG
// True if target overlaps an existing interval.
bool HasOverlap(UseInterval* target) const;
void Verify() const;
#endif
void ConvertUsesToOperand(const InstructionOperand& op,
InstructionOperand* spill_op);
void set_kind(RegisterKind kind) { kind_ = kind; }
private:
struct SpillAtDefinitionList;
void ConvertUsesToOperand(const InstructionOperand& op,
InstructionOperand* spill_op);
UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const;
void AdvanceLastProcessedMarker(UseInterval* to_start_of,
LifetimePosition but_not_past) const;
@ -381,8 +382,6 @@ class LiveRange final : public ZoneObject {
};
SpillAtDefinitionList* spills_at_definition_;
friend class RegisterAllocator; // Assigns to kind_.
DISALLOW_COPY_AND_ASSIGN(LiveRange);
};
@ -412,23 +411,107 @@ class SpillRange final : public ZoneObject {
};
class RegisterAllocator final : public ZoneObject {
class RegisterAllocationData final : public ZoneObject {
public:
explicit RegisterAllocator(const RegisterConfiguration* config,
Zone* local_zone, Frame* frame,
InstructionSequence* code,
const char* debug_name = nullptr);
class PhiMapValue : public ZoneObject {
public:
PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone)
: phi(phi), block(block), incoming_moves(zone) {
incoming_moves.reserve(phi->operands().size());
}
PhiInstruction* const phi;
const InstructionBlock* const block;
ZoneVector<MoveOperands*> incoming_moves;
};
typedef ZoneMap<int, PhiMapValue*> PhiMap;
RegisterAllocationData(const RegisterConfiguration* config,
Zone* allocation_zone, Frame* frame,
InstructionSequence* code,
const char* debug_name = nullptr);
const ZoneVector<LiveRange*>& live_ranges() const { return live_ranges_; }
ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; }
const ZoneVector<LiveRange*>& fixed_live_ranges() const {
return fixed_live_ranges_;
}
ZoneVector<LiveRange*>& fixed_live_ranges() { return fixed_live_ranges_; }
ZoneVector<LiveRange*>& fixed_double_live_ranges() {
return fixed_double_live_ranges_;
}
const ZoneVector<LiveRange*>& fixed_double_live_ranges() const {
return fixed_double_live_ranges_;
}
const ZoneVector<BitVector*>& live_in_sets() const { return live_in_sets_; }
ZoneVector<BitVector*>& live_in_sets() { return live_in_sets_; }
ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; }
const ZoneVector<SpillRange*>& spill_ranges() const { return spill_ranges_; }
InstructionSequence* code() const { return code_; }
// This zone is for datastructures only needed during register allocation.
Zone* local_zone() const { return local_zone_; }
// This zone is for datastructures only needed during register allocation
// phases.
Zone* allocation_zone() const { return allocation_zone_; }
// This zone is for InstructionOperands and moves that live beyond register
// allocation.
Zone* code_zone() const { return code()->zone(); }
const PhiMap& phi_map() const { return phi_map_; }
PhiMap& phi_map() { return phi_map_; }
Frame* frame() const { return frame_; }
const char* debug_name() const { return debug_name_; }
const RegisterConfiguration* config() const { return config_; }
void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
LiveRange* LiveRangeFor(int index);
Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment);
SpillRange* AssignSpillRangeToLiveRange(LiveRange* range);
MoveOperands* AddGapMove(int index, Instruction::GapPosition position,
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);
}
bool ExistsUseWithoutDefinition();
// Creates a new live range.
LiveRange* NewLiveRange(int index);
private:
Zone* const allocation_zone_;
Frame* const frame_;
InstructionSequence* const code_;
const char* const debug_name_;
const RegisterConfiguration* const config_;
PhiMap phi_map_;
ZoneVector<BitVector*> live_in_sets_;
ZoneVector<LiveRange*> live_ranges_;
ZoneVector<LiveRange*> fixed_live_ranges_;
ZoneVector<LiveRange*> fixed_double_live_ranges_;
ZoneVector<SpillRange*> spill_ranges_;
BitVector* assigned_registers_;
BitVector* assigned_double_registers_;
DISALLOW_COPY_AND_ASSIGN(RegisterAllocationData);
};
class LiveRangeBuilder final : public ZoneObject {
public:
explicit LiveRangeBuilder(RegisterAllocationData* data);
// Phase 1 : insert moves to account for fixed register operands.
void MeetRegisterConstraints();
@ -439,54 +522,32 @@ class RegisterAllocator final : public ZoneObject {
// Phase 3: compute liveness of all virtual register.
void BuildLiveRanges();
bool ExistsUseWithoutDefinition();
// Phase 4: compute register assignments.
void AllocateGeneralRegisters();
void AllocateDoubleRegisters();
// Phase 5: assign spill splots.
void AssignSpillSlots();
// Phase 6: commit assignment.
void CommitAssignment();
// Phase 7: compute values for pointer maps.
void PopulateReferenceMaps();
// Phase 8: reconnect split ranges with moves.
void ConnectRanges();
// Phase 9: insert moves to connect ranges across basic blocks.
void ResolveControlFlow();
private:
int GetVirtualRegister() { return code()->NextVirtualRegister(); }
// Checks whether the value of a given virtual register is a reference.
// TODO(titzer): rename this to IsReference.
bool HasTaggedValue(int virtual_register) const;
// Returns the register kind required by the given virtual register.
RegisterKind RequiredRegisterKind(int virtual_register) const;
// Creates a new live range.
LiveRange* NewLiveRange(int index);
// This zone is for InstructionOperands and moves that live beyond register
// allocation.
RegisterAllocationData* data() const { return data_; }
InstructionSequence* code() const { return data()->code(); }
Zone* allocation_zone() const { return data()->allocation_zone(); }
Zone* code_zone() const { return code()->zone(); }
const RegisterConfiguration* config() const { return data()->config(); }
ZoneVector<BitVector*>& live_in_sets() const {
return data()->live_in_sets();
}
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<SpillRange*>& spill_ranges() { return data()->spill_ranges(); }
RegisterAllocationData::PhiMap& phi_map() { return data()->phi_map(); }
BitVector* assigned_registers() { return assigned_registers_; }
BitVector* assigned_double_registers() { return assigned_double_registers_; }
Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
bool IsReference(int virtual_register) const {
return data()->IsReference(virtual_register);
}
#ifdef DEBUG
void Verify() const;
#endif
void AllocateRegisters();
bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const;
bool SafePointsAreInOrder() const;
// Liveness analysis support.
BitVector* ComputeLiveOut(const InstructionBlock* block);
@ -501,6 +562,16 @@ class RegisterAllocator final : public ZoneObject {
const InstructionBlock* block);
void ResolvePhis(const InstructionBlock* block);
LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
static int FixedLiveRangeID(int index) { return -index - 1; }
int FixedDoubleLiveRangeID(int index);
LiveRange* FixedLiveRangeFor(int index);
LiveRange* FixedDoubleLiveRangeFor(int index);
Instruction* GetLastInstruction(const InstructionBlock* block);
// Returns the register kind required by the given virtual register.
RegisterKind RequiredRegisterKind(int virtual_register) const;
// Helper methods for building intervals.
InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos,
bool is_tagged);
@ -509,9 +580,36 @@ class RegisterAllocator final : public ZoneObject {
InstructionOperand* hint);
void Use(LifetimePosition block_start, LifetimePosition position,
InstructionOperand* operand, InstructionOperand* hint);
MoveOperands* AddGapMove(int index, Instruction::GapPosition position,
const InstructionOperand& from,
const InstructionOperand& to);
RegisterAllocationData* const data_;
DISALLOW_COPY_AND_ASSIGN(LiveRangeBuilder);
};
class LinearScanAllocator final : public ZoneObject {
public:
explicit LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind);
// Phase 4: compute register assignments.
void AllocateRegisters();
private:
RegisterAllocationData* data() const { return data_; }
InstructionSequence* code() const { return data()->code(); }
Zone* allocation_zone() const { return data()->allocation_zone(); }
Zone* code_zone() const { return code()->zone(); }
const RegisterConfiguration* config() const { return data()->config(); }
Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
int GetVirtualRegister() { return code()->NextVirtualRegister(); }
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.
void AddToActive(LiveRange* range);
@ -529,7 +627,6 @@ class RegisterAllocator final : public ZoneObject {
bool TryReuseSpillForPhi(LiveRange* range);
bool TryAllocateFreeReg(LiveRange* range);
void AllocateBlockedReg(LiveRange* range);
SpillRange* AssignSpillRangeToLiveRange(LiveRange* range);
// Live range splitting helpers.
@ -571,40 +668,26 @@ class RegisterAllocator final : public ZoneObject {
LifetimePosition pos);
void Spill(LiveRange* range);
bool IsBlockBoundary(LifetimePosition pos);
// Helper methods for resolving control flow.
void ResolveControlFlow(const InstructionBlock* block,
const InstructionOperand& cur_op,
const InstructionBlock* pred,
const InstructionOperand& pred_op);
void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
// Return the block which contains give lifetime position.
const InstructionBlock* GetInstructionBlock(LifetimePosition pos);
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;
static int FixedLiveRangeID(int index) { return -index - 1; }
int FixedDoubleLiveRangeID(int index);
LiveRange* FixedLiveRangeFor(int index);
LiveRange* FixedDoubleLiveRangeFor(int index);
LiveRange* LiveRangeFor(int index);
Instruction* GetLastInstruction(const InstructionBlock* block);
int RegisterCount() const { return num_registers_; }
const char* RegisterName(int allocation_index);
Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment);
Frame* frame() const { return frame_; }
const char* debug_name() const { return debug_name_; }
const RegisterConfiguration* config() const { return config_; }
ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; }
ZoneVector<LiveRange*>& fixed_live_ranges() { return fixed_live_ranges_; }
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 fixed_double_live_ranges_;
return data()->fixed_double_live_ranges();
}
ZoneVector<LiveRange*>& unhandled_live_ranges() {
return unhandled_live_ranges_;
@ -613,54 +696,92 @@ class RegisterAllocator final : public ZoneObject {
ZoneVector<LiveRange*>& inactive_live_ranges() {
return inactive_live_ranges_;
}
ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; }
ZoneVector<SpillRange*>& spill_ranges() { return data()->spill_ranges(); }
RegisterAllocationData::PhiMap& phi_map() { return data()->phi_map(); }
class PhiMapValue : public ZoneObject {
public:
PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone)
: phi(phi), block(block), incoming_moves(zone) {
incoming_moves.reserve(phi->operands().size());
}
PhiInstruction* const phi;
const InstructionBlock* const block;
ZoneVector<MoveOperands*> incoming_moves;
};
typedef ZoneMap<int, PhiMapValue*> PhiMap;
RegisterAllocationData* const data_;
const RegisterKind mode_;
const int num_registers_;
Zone* const local_zone_;
Frame* const frame_;
InstructionSequence* const code_;
const char* const debug_name_;
const RegisterConfiguration* config_;
PhiMap phi_map_;
// During liveness analysis keep a mapping from block id to live_in sets
// for blocks already analyzed.
ZoneVector<BitVector*> live_in_sets_;
// Liveness analysis results.
ZoneVector<LiveRange*> live_ranges_;
// Lists of live ranges
ZoneVector<LiveRange*> fixed_live_ranges_;
ZoneVector<LiveRange*> fixed_double_live_ranges_;
ZoneVector<LiveRange*> unhandled_live_ranges_;
ZoneVector<LiveRange*> active_live_ranges_;
ZoneVector<LiveRange*> inactive_live_ranges_;
ZoneVector<SpillRange*> spill_ranges_;
RegisterKind mode_;
int num_registers_;
BitVector* assigned_registers_;
BitVector* assigned_double_registers_;
#ifdef DEBUG
LifetimePosition allocation_finger_;
#endif
DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
DISALLOW_COPY_AND_ASSIGN(LinearScanAllocator);
};
class OperandAssigner final : public ZoneObject {
public:
explicit OperandAssigner(RegisterAllocationData* data);
// Phase 5: assign spill splots.
void AssignSpillSlots();
// Phase 6: commit assignment.
void CommitAssignment();
private:
RegisterAllocationData* data() const { return data_; }
RegisterAllocationData* const data_;
DISALLOW_COPY_AND_ASSIGN(OperandAssigner);
};
class ReferenceMapPopulator final : public ZoneObject {
public:
explicit ReferenceMapPopulator(RegisterAllocationData* data);
// Phase 7: compute values for pointer maps.
void PopulateReferenceMaps();
private:
bool SafePointsAreInOrder() const;
bool IsReference(int virtual_register) const {
return data()->IsReference(virtual_register);
}
RegisterAllocationData* data() const { return data_; }
RegisterAllocationData* const data_;
DISALLOW_COPY_AND_ASSIGN(ReferenceMapPopulator);
};
class LiveRangeConnector final : public ZoneObject {
public:
explicit LiveRangeConnector(RegisterAllocationData* data);
// Phase 8: reconnect split ranges with moves.
void ConnectRanges(Zone* temp_zone);
// Phase 9: insert moves to connect ranges across basic blocks.
void ResolveControlFlow();
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,
const InstructionBlock* pred,
const InstructionOperand& pred_op);
InstructionSequence* code() const { return data()->code(); }
Zone* code_zone() const { return code()->zone(); }
RegisterAllocationData* data() const { return data_; }
RegisterAllocationData* const data_;
DISALLOW_COPY_AND_ASSIGN(LiveRangeConnector);
};
} // namespace compiler