[turbofan] move register allocation phases to pipeline
BUG= R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/727323002 Cr-Commit-Position: refs/heads/master@{#25379}
This commit is contained in:
parent
7e2ebd4c00
commit
032191e9be
@ -43,39 +43,9 @@ namespace compiler {
|
||||
|
||||
class PipelineData {
|
||||
public:
|
||||
PipelineData(CompilationInfo* info, ZonePool* zone_pool,
|
||||
PipelineStatistics* pipeline_statistics)
|
||||
explicit PipelineData(ZonePool* zone_pool, CompilationInfo* info)
|
||||
: isolate_(info->zone()->isolate()),
|
||||
info_(info),
|
||||
outer_zone_(info->zone()),
|
||||
zone_pool_(zone_pool),
|
||||
pipeline_statistics_(pipeline_statistics),
|
||||
compilation_failed_(false),
|
||||
code_(Handle<Code>::null()),
|
||||
graph_zone_scope_(zone_pool_),
|
||||
graph_zone_(graph_zone_scope_.zone()),
|
||||
graph_(new (graph_zone()) Graph(graph_zone())),
|
||||
source_positions_(new SourcePositionTable(graph())),
|
||||
machine_(new (graph_zone()) MachineOperatorBuilder(
|
||||
graph_zone(), kMachPtr,
|
||||
InstructionSelector::SupportedMachineOperatorFlags())),
|
||||
common_(new (graph_zone()) CommonOperatorBuilder(graph_zone())),
|
||||
javascript_(new (graph_zone()) JSOperatorBuilder(graph_zone())),
|
||||
jsgraph_(new (graph_zone())
|
||||
JSGraph(graph(), common(), javascript(), machine())),
|
||||
typer_(new Typer(graph(), info->context())),
|
||||
context_node_(nullptr),
|
||||
schedule_(nullptr),
|
||||
instruction_zone_scope_(zone_pool_),
|
||||
instruction_zone_(instruction_zone_scope_.zone()),
|
||||
sequence_(nullptr),
|
||||
frame_(nullptr) {}
|
||||
|
||||
|
||||
// For machine graph testing only.
|
||||
PipelineData(Graph* graph, Schedule* schedule, ZonePool* zone_pool)
|
||||
: isolate_(graph->zone()->isolate()),
|
||||
info_(nullptr),
|
||||
outer_zone_(nullptr),
|
||||
zone_pool_(zone_pool),
|
||||
pipeline_statistics_(nullptr),
|
||||
@ -83,25 +53,57 @@ class PipelineData {
|
||||
code_(Handle<Code>::null()),
|
||||
graph_zone_scope_(zone_pool_),
|
||||
graph_zone_(nullptr),
|
||||
graph_(graph),
|
||||
source_positions_(new SourcePositionTable(graph)),
|
||||
graph_(nullptr),
|
||||
machine_(nullptr),
|
||||
common_(nullptr),
|
||||
javascript_(nullptr),
|
||||
jsgraph_(nullptr),
|
||||
typer_(nullptr),
|
||||
context_node_(nullptr),
|
||||
schedule_(schedule),
|
||||
schedule_(nullptr),
|
||||
instruction_zone_scope_(zone_pool_),
|
||||
instruction_zone_(instruction_zone_scope_.zone()),
|
||||
instruction_zone_(nullptr),
|
||||
sequence_(nullptr),
|
||||
frame_(nullptr) {}
|
||||
frame_(nullptr),
|
||||
register_allocator_(nullptr) {}
|
||||
|
||||
~PipelineData() {
|
||||
DeleteInstructionZone();
|
||||
DeleteGraphZone();
|
||||
}
|
||||
|
||||
// For main entry point.
|
||||
void Initialize(PipelineStatistics* pipeline_statistics) {
|
||||
outer_zone_ = info()->zone();
|
||||
pipeline_statistics_ = pipeline_statistics;
|
||||
graph_zone_ = graph_zone_scope_.zone();
|
||||
graph_ = new (graph_zone()) Graph(graph_zone());
|
||||
source_positions_.Reset(new SourcePositionTable(graph()));
|
||||
machine_ = new (graph_zone()) MachineOperatorBuilder(
|
||||
graph_zone(), kMachPtr,
|
||||
InstructionSelector::SupportedMachineOperatorFlags());
|
||||
common_ = new (graph_zone()) CommonOperatorBuilder(graph_zone());
|
||||
javascript_ = new (graph_zone()) JSOperatorBuilder(graph_zone());
|
||||
jsgraph_ =
|
||||
new (graph_zone()) JSGraph(graph(), common(), javascript(), machine());
|
||||
typer_.Reset(new Typer(graph(), info()->context()));
|
||||
instruction_zone_ = instruction_zone_scope_.zone();
|
||||
}
|
||||
|
||||
// For machine graph testing entry point.
|
||||
void Initialize(Graph* graph, Schedule* schedule) {
|
||||
graph_ = graph;
|
||||
source_positions_.Reset(new SourcePositionTable(graph));
|
||||
schedule_ = schedule;
|
||||
instruction_zone_ = instruction_zone_scope_.zone();
|
||||
}
|
||||
|
||||
// For register allocation entry point.
|
||||
void Initialize(InstructionSequence* sequence) {
|
||||
instruction_zone_ = sequence->zone();
|
||||
sequence_ = sequence;
|
||||
}
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
CompilationInfo* info() const { return info_; }
|
||||
ZonePool* zone_pool() const { return zone_pool_; }
|
||||
@ -142,15 +144,8 @@ class PipelineData {
|
||||
|
||||
Zone* instruction_zone() const { return instruction_zone_; }
|
||||
InstructionSequence* sequence() const { return sequence_; }
|
||||
void set_sequence(InstructionSequence* sequence) {
|
||||
DCHECK_EQ(nullptr, sequence_);
|
||||
sequence_ = sequence;
|
||||
}
|
||||
Frame* frame() const { return frame_; }
|
||||
void set_frame(Frame* frame) {
|
||||
DCHECK_EQ(nullptr, frame_);
|
||||
frame_ = frame;
|
||||
}
|
||||
RegisterAllocator* register_allocator() const { return register_allocator_; }
|
||||
|
||||
void DeleteGraphZone() {
|
||||
// Destroy objects with destructors first.
|
||||
@ -175,13 +170,33 @@ class PipelineData {
|
||||
instruction_zone_ = nullptr;
|
||||
sequence_ = nullptr;
|
||||
frame_ = nullptr;
|
||||
register_allocator_ = nullptr;
|
||||
}
|
||||
|
||||
void InitializeInstructionSequence() {
|
||||
DCHECK_EQ(nullptr, sequence_);
|
||||
InstructionBlocks* instruction_blocks =
|
||||
InstructionSequence::InstructionBlocksFor(instruction_zone(),
|
||||
schedule());
|
||||
sequence_ = new (instruction_zone())
|
||||
InstructionSequence(instruction_zone(), instruction_blocks);
|
||||
}
|
||||
|
||||
void InitializeRegisterAllocator(Zone* local_zone,
|
||||
const RegisterConfiguration* config,
|
||||
const char* debug_name) {
|
||||
DCHECK_EQ(nullptr, register_allocator_);
|
||||
DCHECK_EQ(nullptr, frame_);
|
||||
frame_ = new (instruction_zone()) Frame();
|
||||
register_allocator_ = new (instruction_zone())
|
||||
RegisterAllocator(config, local_zone, frame(), sequence(), debug_name);
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
CompilationInfo* info_;
|
||||
Zone* outer_zone_;
|
||||
ZonePool* zone_pool_;
|
||||
ZonePool* const zone_pool_;
|
||||
PipelineStatistics* pipeline_statistics_;
|
||||
bool compilation_failed_;
|
||||
Handle<Code> code_;
|
||||
@ -209,6 +224,7 @@ class PipelineData {
|
||||
Zone* instruction_zone_;
|
||||
InstructionSequence* sequence_;
|
||||
Frame* frame_;
|
||||
RegisterAllocator* register_allocator_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PipelineData);
|
||||
};
|
||||
@ -317,15 +333,6 @@ void Pipeline::Run(Arg0 arg_0) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(dcarney): this one should be unecessary.
|
||||
template <typename Phase, typename Arg0, typename Arg1>
|
||||
void Pipeline::Run(Arg0 arg_0, Arg1 arg_1) {
|
||||
PipelineRunScope scope(this->data_, Phase::phase_name());
|
||||
Phase phase;
|
||||
phase.Run(this->data_, scope.zone(), arg_0, arg_1);
|
||||
}
|
||||
|
||||
|
||||
struct GraphBuilderPhase {
|
||||
static const char* phase_name() { return "graph builder"; }
|
||||
|
||||
@ -490,45 +497,74 @@ struct InstructionSelectionPhase {
|
||||
};
|
||||
|
||||
|
||||
// TODO(dcarney): break this up.
|
||||
struct RegisterAllocationPhase {
|
||||
static const char* phase_name() { return nullptr; }
|
||||
struct MeetRegisterConstraintsPhase {
|
||||
static const char* phase_name() { return "meet register constraints"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
int node_count = data->sequence()->VirtualRegisterCount();
|
||||
if (node_count > UnallocatedOperand::kMaxVirtualRegisters) {
|
||||
data->set_compilation_failed();
|
||||
return;
|
||||
}
|
||||
data->register_allocator()->MeetRegisterConstraints();
|
||||
}
|
||||
};
|
||||
|
||||
SmartArrayPointer<char> debug_name;
|
||||
#ifdef DEBUG
|
||||
if (data->info() != nullptr) {
|
||||
debug_name = GetDebugName(data->info());
|
||||
}
|
||||
#endif
|
||||
|
||||
RegisterAllocator allocator(RegisterConfiguration::ArchDefault(), temp_zone,
|
||||
data->frame(), data->sequence(),
|
||||
debug_name.get());
|
||||
struct ResolvePhisPhase {
|
||||
static const char* phase_name() { return "resolve phis"; }
|
||||
|
||||
if (!allocator.Allocate(data->pipeline_statistics())) {
|
||||
data->set_compilation_failed();
|
||||
return;
|
||||
}
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
data->register_allocator()->ResolvePhis();
|
||||
}
|
||||
};
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
PrintableInstructionSequence printable = {
|
||||
RegisterConfiguration::ArchDefault(), data->sequence()};
|
||||
os << "----- Instruction sequence after register allocation -----\n"
|
||||
<< printable;
|
||||
}
|
||||
|
||||
if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) {
|
||||
TurboCfgFile tcf(data->isolate());
|
||||
tcf << AsC1VAllocator("CodeGen", &allocator);
|
||||
}
|
||||
struct BuildLiveRangesPhase {
|
||||
static const char* phase_name() { return "build live ranges"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
data->register_allocator()->BuildLiveRanges();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct AllocateGeneralRegistersPhase {
|
||||
static const char* phase_name() { return "allocate general registers"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
data->register_allocator()->AllocateGeneralRegisters();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct AllocateDoubleRegistersPhase {
|
||||
static const char* phase_name() { return "allocate double registers"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
data->register_allocator()->AllocateDoubleRegisters();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct PopulatePointerMapsPhase {
|
||||
static const char* phase_name() { return "populate pointer maps"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
data->register_allocator()->PopulatePointerMaps();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ConnectRangesPhase {
|
||||
static const char* phase_name() { return "connect ranges"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
data->register_allocator()->ConnectRanges();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ResolveControlFlowPhase {
|
||||
static const char* phase_name() { return "resolve control flow"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
data->register_allocator()->ResolveControlFlow();
|
||||
}
|
||||
};
|
||||
|
||||
@ -536,9 +572,9 @@ struct RegisterAllocationPhase {
|
||||
struct GenerateCodePhase {
|
||||
static const char* phase_name() { return "generate code"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone, Linkage* linkage,
|
||||
CompilationInfo* info) {
|
||||
CodeGenerator generator(data->frame(), linkage, data->sequence(), info);
|
||||
void Run(PipelineData* data, Zone* temp_zone, Linkage* linkage) {
|
||||
CodeGenerator generator(data->frame(), linkage, data->sequence(),
|
||||
data->info());
|
||||
data->set_code(generator.GenerateCode());
|
||||
}
|
||||
};
|
||||
@ -600,6 +636,13 @@ struct VerifyGraphPhase {
|
||||
};
|
||||
|
||||
|
||||
void Pipeline::BeginPhaseKind(const char* phase_kind_name) {
|
||||
if (data_->pipeline_statistics() != NULL) {
|
||||
data_->pipeline_statistics()->BeginPhaseKind("phase_kind_name");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Pipeline::RunPrintAndVerify(const char* phase, bool untyped) {
|
||||
if (FLAG_trace_turbo) {
|
||||
Run<PrintGraphPhase>(phase);
|
||||
@ -630,11 +673,13 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
|
||||
if (FLAG_turbo_stats) {
|
||||
pipeline_statistics.Reset(new PipelineStatistics(info(), &zone_pool));
|
||||
pipeline_statistics->BeginPhaseKind("graph creation");
|
||||
}
|
||||
|
||||
PipelineData data(info(), &zone_pool, pipeline_statistics.get());
|
||||
PipelineData data(&zone_pool, info());
|
||||
this->data_ = &data;
|
||||
data.Initialize(pipeline_statistics.get());
|
||||
|
||||
BeginPhaseKind("graph creation");
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
@ -679,9 +724,7 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
RunPrintAndVerify("Typed");
|
||||
}
|
||||
|
||||
if (!pipeline_statistics.is_empty()) {
|
||||
data.pipeline_statistics()->BeginPhaseKind("lowering");
|
||||
}
|
||||
BeginPhaseKind("lowering");
|
||||
|
||||
if (info()->is_typing_enabled()) {
|
||||
// Lower JSOperators where we can determine types.
|
||||
@ -706,9 +749,7 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
|
||||
RunPrintAndVerify("Lowered generic", true);
|
||||
|
||||
if (!pipeline_statistics.is_empty()) {
|
||||
data.pipeline_statistics()->BeginPhaseKind("block building");
|
||||
}
|
||||
BeginPhaseKind("block building");
|
||||
|
||||
data.source_positions()->RemoveDecorator();
|
||||
|
||||
@ -742,7 +783,8 @@ Handle<Code> Pipeline::GenerateCodeForMachineGraph(Linkage* linkage,
|
||||
Schedule* schedule) {
|
||||
ZonePool zone_pool(isolate());
|
||||
CHECK(SupportedBackend());
|
||||
PipelineData data(graph, schedule, &zone_pool);
|
||||
PipelineData data(&zone_pool, info());
|
||||
data.Initialize(graph, schedule);
|
||||
this->data_ = &data;
|
||||
if (schedule == NULL) {
|
||||
// TODO(rossberg): Should this really be untyped?
|
||||
@ -766,6 +808,20 @@ Handle<Code> Pipeline::GenerateCodeForMachineGraph(Linkage* linkage,
|
||||
}
|
||||
|
||||
|
||||
bool Pipeline::AllocateRegisters(const RegisterConfiguration* config,
|
||||
InstructionSequence* sequence,
|
||||
bool run_verifier) {
|
||||
CompilationInfo info(sequence->zone()->isolate(), sequence->zone());
|
||||
ZonePool zone_pool(sequence->zone()->isolate());
|
||||
PipelineData data(&zone_pool, &info);
|
||||
data.Initialize(sequence);
|
||||
Pipeline pipeline(&info);
|
||||
pipeline.data_ = &data;
|
||||
pipeline.AllocateRegisters(config, run_verifier);
|
||||
return !data.compilation_failed();
|
||||
}
|
||||
|
||||
|
||||
void Pipeline::GenerateCode(Linkage* linkage) {
|
||||
PipelineData* data = this->data_;
|
||||
|
||||
@ -780,11 +836,7 @@ void Pipeline::GenerateCode(Linkage* linkage) {
|
||||
data->schedule());
|
||||
}
|
||||
|
||||
InstructionBlocks* instruction_blocks =
|
||||
InstructionSequence::InstructionBlocksFor(data->instruction_zone(),
|
||||
data->schedule());
|
||||
data->set_sequence(new (data->instruction_zone()) InstructionSequence(
|
||||
data->instruction_zone(), instruction_blocks));
|
||||
data->InitializeInstructionSequence();
|
||||
|
||||
// Select and schedule instructions covering the scheduled graph.
|
||||
Run<InstructionSelectionPhase>(linkage);
|
||||
@ -797,36 +849,23 @@ void Pipeline::GenerateCode(Linkage* linkage) {
|
||||
|
||||
data->DeleteGraphZone();
|
||||
|
||||
if (data->pipeline_statistics() != NULL) {
|
||||
data->pipeline_statistics()->BeginPhaseKind("register allocation");
|
||||
}
|
||||
BeginPhaseKind("register allocation");
|
||||
|
||||
bool run_verifier = false;
|
||||
#ifdef DEBUG
|
||||
// Don't track usage for this zone in compiler stats.
|
||||
Zone verifier_zone(info()->isolate());
|
||||
RegisterAllocatorVerifier verifier(
|
||||
&verifier_zone, RegisterConfiguration::ArchDefault(), data->sequence());
|
||||
run_verifier = true;
|
||||
#endif
|
||||
|
||||
// Allocate registers.
|
||||
data->set_frame(new (data->instruction_zone()) Frame);
|
||||
Run<RegisterAllocationPhase>();
|
||||
AllocateRegisters(RegisterConfiguration::ArchDefault(), run_verifier);
|
||||
if (data->compilation_failed()) {
|
||||
info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
verifier.VerifyAssignment();
|
||||
verifier.VerifyGapMoves();
|
||||
#endif
|
||||
|
||||
if (data->pipeline_statistics() != NULL) {
|
||||
data->pipeline_statistics()->BeginPhaseKind("code generation");
|
||||
}
|
||||
BeginPhaseKind("code generation");
|
||||
|
||||
// Generate native sequence.
|
||||
Run<GenerateCodePhase>(linkage, info());
|
||||
Run<GenerateCodePhase>(linkage);
|
||||
|
||||
if (profiler_data != NULL) {
|
||||
#if ENABLE_DISASSEMBLER
|
||||
@ -838,6 +877,77 @@ void Pipeline::GenerateCode(Linkage* linkage) {
|
||||
}
|
||||
|
||||
|
||||
void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
|
||||
bool run_verifier) {
|
||||
PipelineData* data = this->data_;
|
||||
|
||||
int node_count = data->sequence()->VirtualRegisterCount();
|
||||
if (node_count > UnallocatedOperand::kMaxVirtualRegisters) {
|
||||
data->set_compilation_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't track usage for this zone in compiler stats.
|
||||
SmartPointer<Zone> verifier_zone;
|
||||
RegisterAllocatorVerifier* verifier = nullptr;
|
||||
if (run_verifier) {
|
||||
verifier_zone.Reset(new Zone(info()->isolate()));
|
||||
verifier = new (verifier_zone.get()) RegisterAllocatorVerifier(
|
||||
verifier_zone.get(), config, data->sequence());
|
||||
}
|
||||
|
||||
SmartArrayPointer<char> debug_name;
|
||||
#ifdef DEBUG
|
||||
debug_name = GetDebugName(data->info());
|
||||
#endif
|
||||
|
||||
ZonePool::Scope zone_scope(data->zone_pool());
|
||||
data->InitializeRegisterAllocator(zone_scope.zone(), config,
|
||||
debug_name.get());
|
||||
|
||||
Run<MeetRegisterConstraintsPhase>();
|
||||
Run<ResolvePhisPhase>();
|
||||
Run<BuildLiveRangesPhase>();
|
||||
if (FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
PrintableInstructionSequence printable = {config, data->sequence()};
|
||||
os << "----- Instruction sequence before register allocation -----\n"
|
||||
<< printable;
|
||||
}
|
||||
DCHECK(!data->register_allocator()->ExistsUseWithoutDefinition());
|
||||
Run<AllocateGeneralRegistersPhase>();
|
||||
if (!data->register_allocator()->AllocationOk()) {
|
||||
data->set_compilation_failed();
|
||||
return;
|
||||
}
|
||||
Run<AllocateDoubleRegistersPhase>();
|
||||
if (!data->register_allocator()->AllocationOk()) {
|
||||
data->set_compilation_failed();
|
||||
return;
|
||||
}
|
||||
Run<PopulatePointerMapsPhase>();
|
||||
Run<ConnectRangesPhase>();
|
||||
Run<ResolveControlFlowPhase>();
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
PrintableInstructionSequence printable = {config, data->sequence()};
|
||||
os << "----- Instruction sequence after register allocation -----\n"
|
||||
<< printable;
|
||||
}
|
||||
|
||||
if (verifier != nullptr) {
|
||||
verifier->VerifyAssignment();
|
||||
verifier->VerifyGapMoves();
|
||||
}
|
||||
|
||||
if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) {
|
||||
TurboCfgFile tcf(data->isolate());
|
||||
tcf << AsC1VAllocator("CodeGen", data->register_allocator());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Pipeline::SetUp() {
|
||||
InstructionOperand::SetUpCaches();
|
||||
}
|
||||
|
@ -18,8 +18,10 @@ namespace compiler {
|
||||
|
||||
// Clients of this interface shouldn't depend on lots of compiler internals.
|
||||
class Graph;
|
||||
class InstructionSequence;
|
||||
class Linkage;
|
||||
class PipelineData;
|
||||
class RegisterConfiguration;
|
||||
class Schedule;
|
||||
|
||||
class Pipeline {
|
||||
@ -34,6 +36,10 @@ class Pipeline {
|
||||
Handle<Code> GenerateCodeForMachineGraph(Linkage* linkage, Graph* graph,
|
||||
Schedule* schedule = NULL);
|
||||
|
||||
static bool AllocateRegisters(const RegisterConfiguration* config,
|
||||
InstructionSequence* sequence,
|
||||
bool run_verifier);
|
||||
|
||||
static inline bool SupportedBackend() { return V8_TURBOFAN_BACKEND != 0; }
|
||||
static inline bool SupportedTarget() { return V8_TURBOFAN_TARGET != 0; }
|
||||
|
||||
@ -49,14 +55,15 @@ class Pipeline {
|
||||
void Run();
|
||||
template <typename Phase, typename Arg0>
|
||||
void Run(Arg0 arg_0);
|
||||
template <typename Phase, typename Arg0, typename Arg1>
|
||||
void Run(Arg0 arg_0, Arg1 arg_1);
|
||||
|
||||
CompilationInfo* info() const { return info_; }
|
||||
Isolate* isolate() { return info_->isolate(); }
|
||||
|
||||
void BeginPhaseKind(const char* phase_kind);
|
||||
void RunPrintAndVerify(const char* phase, bool untyped = false);
|
||||
void GenerateCode(Linkage* linkage);
|
||||
void AllocateRegisters(const RegisterConfiguration* config,
|
||||
bool run_verifier);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -3,7 +3,6 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/pipeline-statistics.h"
|
||||
#include "src/compiler/register-allocator.h"
|
||||
#include "src/string-stream.h"
|
||||
|
||||
@ -536,6 +535,12 @@ RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config,
|
||||
// when allocating local arrays.
|
||||
DCHECK(this->config()->num_double_registers() >=
|
||||
this->config()->num_general_registers());
|
||||
assigned_registers_ =
|
||||
new (code_zone()) BitVector(config->num_general_registers(), code_zone());
|
||||
assigned_double_registers_ = new (code_zone())
|
||||
BitVector(config->num_aliased_double_registers(), code_zone());
|
||||
frame->SetAllocatedRegisters(assigned_registers_);
|
||||
frame->SetAllocatedDoubleRegisters(assigned_double_registers_);
|
||||
}
|
||||
|
||||
|
||||
@ -1116,59 +1121,6 @@ void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
|
||||
}
|
||||
|
||||
|
||||
bool RegisterAllocator::Allocate(PipelineStatistics* stats) {
|
||||
assigned_registers_ = new (code_zone())
|
||||
BitVector(config()->num_general_registers(), code_zone());
|
||||
assigned_double_registers_ = new (code_zone())
|
||||
BitVector(config()->num_aliased_double_registers(), code_zone());
|
||||
{
|
||||
PhaseScope phase_scope(stats, "meet register constraints");
|
||||
MeetRegisterConstraints();
|
||||
}
|
||||
{
|
||||
PhaseScope phase_scope(stats, "resolve phis");
|
||||
ResolvePhis();
|
||||
}
|
||||
{
|
||||
PhaseScope phase_scope(stats, "build live ranges");
|
||||
BuildLiveRanges();
|
||||
}
|
||||
if (FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
PrintableInstructionSequence printable = {config(), code()};
|
||||
os << "----- Instruction sequence before register allocation -----\n"
|
||||
<< printable;
|
||||
}
|
||||
// This can be triggered in debug mode.
|
||||
DCHECK(!ExistsUseWithoutDefinition());
|
||||
{
|
||||
PhaseScope phase_scope(stats, "allocate general registers");
|
||||
AllocateGeneralRegisters();
|
||||
}
|
||||
if (!AllocationOk()) return false;
|
||||
{
|
||||
PhaseScope phase_scope(stats, "allocate double registers");
|
||||
AllocateDoubleRegisters();
|
||||
}
|
||||
if (!AllocationOk()) return false;
|
||||
{
|
||||
PhaseScope phase_scope(stats, "populate pointer maps");
|
||||
PopulatePointerMaps();
|
||||
}
|
||||
{
|
||||
PhaseScope phase_scope(stats, "connect ranges");
|
||||
ConnectRanges();
|
||||
}
|
||||
{
|
||||
PhaseScope phase_scope(stats, "resolve control flow");
|
||||
ResolveControlFlow();
|
||||
}
|
||||
frame()->SetAllocatedRegisters(assigned_registers_);
|
||||
frame()->SetAllocatedDoubleRegisters(assigned_double_registers_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocator::MeetRegisterConstraints() {
|
||||
for (auto block : code()->instruction_blocks()) {
|
||||
MeetRegisterConstraints(block);
|
||||
|
@ -12,8 +12,6 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class PipelineStatistics;
|
||||
|
||||
enum RegisterKind {
|
||||
UNALLOCATED_REGISTERS,
|
||||
GENERAL_REGISTERS,
|
||||
@ -320,17 +318,14 @@ class LiveRange FINAL : public ZoneObject {
|
||||
};
|
||||
|
||||
|
||||
class RegisterAllocator FINAL {
|
||||
class RegisterAllocator FINAL : public ZoneObject {
|
||||
public:
|
||||
explicit RegisterAllocator(const RegisterConfiguration* config,
|
||||
Zone* local_zone, Frame* frame,
|
||||
InstructionSequence* code,
|
||||
const char* debug_name = nullptr);
|
||||
|
||||
bool Allocate(PipelineStatistics* stats = NULL);
|
||||
bool AllocationOk() { return allocation_ok_; }
|
||||
BitVector* assigned_registers() { return assigned_registers_; }
|
||||
BitVector* assigned_double_registers() { return assigned_double_registers_; }
|
||||
|
||||
const ZoneList<LiveRange*>& live_ranges() const { return live_ranges_; }
|
||||
const ZoneVector<LiveRange*>& fixed_live_ranges() const {
|
||||
@ -343,6 +338,30 @@ class RegisterAllocator FINAL {
|
||||
// This zone is for datastructures only needed during register allocation.
|
||||
Zone* local_zone() const { return local_zone_; }
|
||||
|
||||
// Phase 1 : insert moves to account for fixed register operands.
|
||||
void MeetRegisterConstraints();
|
||||
|
||||
// Phase 2: deconstruct SSA by inserting moves in successors and the headers
|
||||
// of blocks containing phis.
|
||||
void ResolvePhis();
|
||||
|
||||
// Phase 3: compute liveness of all virtual register.
|
||||
void BuildLiveRanges();
|
||||
bool ExistsUseWithoutDefinition();
|
||||
|
||||
// Phase 4: compute register assignments.
|
||||
void AllocateGeneralRegisters();
|
||||
void AllocateDoubleRegisters();
|
||||
|
||||
// Phase 5: compute values for pointer maps.
|
||||
void PopulatePointerMaps(); // TODO(titzer): rename to PopulateReferenceMaps.
|
||||
|
||||
// Phase 6: reconnect split ranges with moves.
|
||||
void ConnectRanges();
|
||||
|
||||
// Phase 7: insert moves to connect ranges across basic blocks.
|
||||
void ResolveControlFlow();
|
||||
|
||||
private:
|
||||
int GetVirtualRegister() {
|
||||
int vreg = code()->NextVirtualRegister();
|
||||
@ -365,18 +384,13 @@ class RegisterAllocator FINAL {
|
||||
// allocation.
|
||||
Zone* code_zone() const { return code()->zone(); }
|
||||
|
||||
BitVector* assigned_registers() { return assigned_registers_; }
|
||||
BitVector* assigned_double_registers() { return assigned_double_registers_; }
|
||||
|
||||
#ifdef DEBUG
|
||||
void Verify() const;
|
||||
#endif
|
||||
|
||||
void MeetRegisterConstraints();
|
||||
void ResolvePhis();
|
||||
void BuildLiveRanges();
|
||||
void AllocateGeneralRegisters();
|
||||
void AllocateDoubleRegisters();
|
||||
void ConnectRanges();
|
||||
void ResolveControlFlow();
|
||||
void PopulatePointerMaps(); // TODO(titzer): rename to PopulateReferenceMaps.
|
||||
void AllocateRegisters();
|
||||
bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const;
|
||||
bool SafePointsAreInOrder() const;
|
||||
@ -388,7 +402,6 @@ class RegisterAllocator FINAL {
|
||||
bool IsOutputRegisterOf(Instruction* instr, int index);
|
||||
bool IsOutputDoubleRegisterOf(Instruction* instr, int index);
|
||||
void ProcessInstructions(const InstructionBlock* block, BitVector* live);
|
||||
bool ExistsUseWithoutDefinition();
|
||||
void MeetRegisterConstraints(const InstructionBlock* block);
|
||||
void MeetConstraintsBetween(Instruction* first, Instruction* second,
|
||||
int gap_index);
|
||||
|
@ -64,38 +64,10 @@ class DeoptCodegenTester {
|
||||
os << *schedule;
|
||||
}
|
||||
|
||||
// Initialize the codegen and generate code.
|
||||
Linkage* linkage = new (scope_->main_zone()) Linkage(info.zone(), &info);
|
||||
InstructionBlocks* instruction_blocks =
|
||||
TestInstrSeq::InstructionBlocksFor(scope_->main_zone(), schedule);
|
||||
code = new (scope_->main_zone())
|
||||
TestInstrSeq(scope_->main_zone(), instruction_blocks);
|
||||
SourcePositionTable source_positions(graph);
|
||||
InstructionSelector selector(scope_->main_zone(), graph, linkage, code,
|
||||
schedule, &source_positions);
|
||||
selector.SelectInstructions();
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
PrintableInstructionSequence printable = {
|
||||
RegisterConfiguration::ArchDefault(), code};
|
||||
os << "----- Instruction sequence before register allocation -----\n"
|
||||
<< printable;
|
||||
}
|
||||
|
||||
Frame frame;
|
||||
RegisterAllocator allocator(RegisterConfiguration::ArchDefault(),
|
||||
scope_->main_zone(), &frame, code);
|
||||
CHECK(allocator.Allocate());
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
PrintableInstructionSequence printable = {
|
||||
RegisterConfiguration::ArchDefault(), code};
|
||||
os << "----- Instruction sequence after register allocation -----\n"
|
||||
<< printable;
|
||||
}
|
||||
|
||||
compiler::CodeGenerator generator(&frame, linkage, code, &info);
|
||||
result_code = generator.GenerateCode();
|
||||
Pipeline pipeline(&info);
|
||||
result_code =
|
||||
pipeline.GenerateCodeForMachineGraph(linkage, graph, schedule);
|
||||
|
||||
#ifdef OBJECT_PRINT
|
||||
if (FLAG_print_opt_code || FLAG_trace_turbo) {
|
||||
|
@ -3,8 +3,8 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/base/utils/random-number-generator.h"
|
||||
#include "src/compiler/register-allocator.h"
|
||||
#include "src/compiler/register-allocator-verifier.h"
|
||||
#include "src/compiler/instruction.h"
|
||||
#include "src/compiler/pipeline.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
|
||||
@ -167,14 +167,6 @@ class RegisterAllocatorTest : public TestWithZone {
|
||||
return sequence_;
|
||||
}
|
||||
|
||||
RegisterAllocator* allocator() {
|
||||
if (allocator_.is_empty()) {
|
||||
allocator_.Reset(
|
||||
new RegisterAllocator(config(), zone(), frame(), sequence()));
|
||||
}
|
||||
return allocator_.get();
|
||||
}
|
||||
|
||||
void StartLoop(int loop_blocks) {
|
||||
CHECK(current_block_ == nullptr);
|
||||
if (!loop_blocks_.empty()) {
|
||||
@ -227,20 +219,7 @@ class RegisterAllocatorTest : public TestWithZone {
|
||||
void Allocate() {
|
||||
CHECK_EQ(nullptr, current_block_);
|
||||
WireBlocks();
|
||||
RegisterAllocatorVerifier verifier(zone(), config(), sequence());
|
||||
if (FLAG_trace_alloc || FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
PrintableInstructionSequence printable = {config(), sequence()};
|
||||
os << "Before: " << std::endl << printable << std::endl;
|
||||
}
|
||||
allocator()->Allocate();
|
||||
if (FLAG_trace_alloc || FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
PrintableInstructionSequence printable = {config(), sequence()};
|
||||
os << "After: " << std::endl << printable << std::endl;
|
||||
}
|
||||
verifier.VerifyAssignment();
|
||||
verifier.VerifyGapMoves();
|
||||
Pipeline::AllocateRegisters(config(), sequence(), true);
|
||||
}
|
||||
|
||||
TestOperand Imm(int32_t imm = 0) {
|
||||
@ -520,7 +499,6 @@ class RegisterAllocatorTest : public TestWithZone {
|
||||
|
||||
SmartPointer<RegisterConfiguration> config_;
|
||||
Frame* frame_;
|
||||
SmartPointer<RegisterAllocator> allocator_;
|
||||
InstructionSequence* sequence_;
|
||||
int num_general_registers_;
|
||||
int num_double_registers_;
|
||||
|
Loading…
Reference in New Issue
Block a user