[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:
parent
f557d75360
commit
497c537310
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user