[turbofan] add RegisterConfiguration to decouple arch specific register layouts from compiler
R=bmeurer@chromium.org BUG= Review URL: https://codereview.chromium.org/694313002 Cr-Commit-Position: refs/heads/master@{#25097} git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25097 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
470be4ac0c
commit
7cb25f5020
2
BUILD.gn
2
BUILD.gn
@ -571,6 +571,8 @@ source_set("v8_base") {
|
||||
"src/compiler/raw-machine-assembler.h",
|
||||
"src/compiler/register-allocator.cc",
|
||||
"src/compiler/register-allocator.h",
|
||||
"src/compiler/register-configuration.cc",
|
||||
"src/compiler/register-configuration.h",
|
||||
"src/compiler/representation-change.h",
|
||||
"src/compiler/schedule.cc",
|
||||
"src/compiler/schedule.h",
|
||||
|
@ -680,7 +680,9 @@ void GraphC1Visualizer::PrintSchedule(const char* phase,
|
||||
for (int j = instruction_block->first_instruction_index();
|
||||
j <= instruction_block->last_instruction_index(); j++) {
|
||||
PrintIndent();
|
||||
os_ << j << " " << *instructions->InstructionAt(j) << " <|@\n";
|
||||
PrintableInstruction printable = {RegisterConfiguration::ArchDefault(),
|
||||
instructions->InstructionAt(j)};
|
||||
os_ << j << " " << printable << " <|@\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,17 +6,15 @@
|
||||
#include "src/compiler/generic-node-inl.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/instruction.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
STATIC_ASSERT(kMaxGeneralRegisters >= Register::kNumRegisters);
|
||||
STATIC_ASSERT(kMaxDoubleRegisters >= DoubleRegister::kMaxNumRegisters);
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) {
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableInstructionOperand& printable) {
|
||||
const InstructionOperand& op = *printable.op_;
|
||||
const RegisterConfiguration* conf = printable.register_configuration_;
|
||||
switch (op.kind()) {
|
||||
case InstructionOperand::INVALID:
|
||||
return os << "(0)";
|
||||
@ -30,10 +28,10 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) {
|
||||
case UnallocatedOperand::NONE:
|
||||
return os;
|
||||
case UnallocatedOperand::FIXED_REGISTER:
|
||||
return os << "(=" << Register::AllocationIndexToString(
|
||||
return os << "(=" << conf->general_register_name(
|
||||
unalloc->fixed_register_index()) << ")";
|
||||
case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
|
||||
return os << "(=" << DoubleRegister::AllocationIndexToString(
|
||||
return os << "(=" << conf->double_register_name(
|
||||
unalloc->fixed_register_index()) << ")";
|
||||
case UnallocatedOperand::MUST_HAVE_REGISTER:
|
||||
return os << "(R)";
|
||||
@ -52,11 +50,9 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) {
|
||||
case InstructionOperand::DOUBLE_STACK_SLOT:
|
||||
return os << "[double_stack:" << op.index() << "]";
|
||||
case InstructionOperand::REGISTER:
|
||||
return os << "[" << Register::AllocationIndexToString(op.index())
|
||||
<< "|R]";
|
||||
return os << "[" << conf->general_register_name(op.index()) << "|R]";
|
||||
case InstructionOperand::DOUBLE_REGISTER:
|
||||
return os << "[" << DoubleRegister::AllocationIndexToString(op.index())
|
||||
<< "|R]";
|
||||
return os << "[" << conf->double_register_name(op.index()) << "|R]";
|
||||
}
|
||||
UNREACHABLE();
|
||||
return os;
|
||||
@ -101,9 +97,17 @@ void InstructionOperand::TearDownCaches() {
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const MoveOperands& mo) {
|
||||
os << *mo.destination();
|
||||
if (!mo.source()->Equals(mo.destination())) os << " = " << *mo.source();
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableMoveOperands& printable) {
|
||||
const MoveOperands& mo = *printable.move_operands_;
|
||||
PrintableInstructionOperand printable_op = {printable.register_configuration_,
|
||||
mo.destination()};
|
||||
|
||||
os << printable_op;
|
||||
if (!mo.source()->Equals(mo.destination())) {
|
||||
printable_op.op_ = mo.source();
|
||||
os << " = " << printable_op;
|
||||
}
|
||||
return os << ";";
|
||||
}
|
||||
|
||||
@ -116,14 +120,17 @@ bool ParallelMove::IsRedundant() const {
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const ParallelMove& pm) {
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableParallelMove& printable) {
|
||||
const ParallelMove& pm = *printable.parallel_move_;
|
||||
bool first = true;
|
||||
for (ZoneList<MoveOperands>::iterator move = pm.move_operands()->begin();
|
||||
move != pm.move_operands()->end(); ++move) {
|
||||
if (move->IsEliminated()) continue;
|
||||
if (!first) os << " ";
|
||||
first = false;
|
||||
os << *move;
|
||||
PrintableMoveOperands pmo = {printable.register_configuration_, move};
|
||||
os << pmo;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
@ -256,11 +263,16 @@ std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Instruction& instr) {
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableInstruction& printable) {
|
||||
const Instruction& instr = *printable.instr_;
|
||||
PrintableInstructionOperand printable_op = {printable.register_configuration_,
|
||||
NULL};
|
||||
if (instr.OutputCount() > 1) os << "(";
|
||||
for (size_t i = 0; i < instr.OutputCount(); i++) {
|
||||
if (i > 0) os << ", ";
|
||||
os << *instr.OutputAt(i);
|
||||
printable_op.op_ = instr.OutputAt(i);
|
||||
os << printable_op;
|
||||
}
|
||||
|
||||
if (instr.OutputCount() > 1) os << ") = ";
|
||||
@ -272,7 +284,11 @@ std::ostream& operator<<(std::ostream& os, const Instruction& instr) {
|
||||
for (int i = GapInstruction::FIRST_INNER_POSITION;
|
||||
i <= GapInstruction::LAST_INNER_POSITION; i++) {
|
||||
os << "(";
|
||||
if (gap->parallel_moves_[i] != NULL) os << *gap->parallel_moves_[i];
|
||||
if (gap->parallel_moves_[i] != NULL) {
|
||||
PrintableParallelMove ppm = {printable.register_configuration_,
|
||||
gap->parallel_moves_[i]};
|
||||
os << ppm;
|
||||
}
|
||||
os << ") ";
|
||||
}
|
||||
} else if (instr.IsSourcePosition()) {
|
||||
@ -293,7 +309,8 @@ std::ostream& operator<<(std::ostream& os, const Instruction& instr) {
|
||||
}
|
||||
if (instr.InputCount() > 0) {
|
||||
for (size_t i = 0; i < instr.InputCount(); i++) {
|
||||
os << " " << *instr.InputAt(i);
|
||||
printable_op.op_ = instr.InputAt(i);
|
||||
os << " " << printable_op;
|
||||
}
|
||||
}
|
||||
return os;
|
||||
@ -585,7 +602,9 @@ void FrameStateDescriptor::SetType(size_t index, MachineType type) {
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const InstructionSequence& code) {
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableInstructionSequence& printable) {
|
||||
const InstructionSequence& code = *printable.sequence_;
|
||||
for (size_t i = 0; i < code.immediates_.size(); ++i) {
|
||||
Constant constant = code.immediates_[i];
|
||||
os << "IMM#" << i << ": " << constant << "\n";
|
||||
@ -626,20 +645,16 @@ std::ostream& operator<<(std::ostream& os, const InstructionSequence& code) {
|
||||
}
|
||||
|
||||
ScopedVector<char> buf(32);
|
||||
PrintableInstruction printable_instr;
|
||||
printable_instr.register_configuration_ = printable.register_configuration_;
|
||||
for (int j = block->first_instruction_index();
|
||||
j <= block->last_instruction_index(); j++) {
|
||||
// TODO(svenpanne) Add some basic formatting to our streams.
|
||||
SNPrintF(buf, "%5d", j);
|
||||
os << " " << buf.start() << ": " << *code.InstructionAt(j) << "\n";
|
||||
printable_instr.instr_ = code.InstructionAt(j);
|
||||
os << " " << buf.start() << ": " << printable_instr << "\n";
|
||||
}
|
||||
|
||||
// TODO(dcarney): add this back somehow?
|
||||
// os << " " << block->control();
|
||||
|
||||
// if (block->control_input() != NULL) {
|
||||
// os << " v" << block->control_input()->id();
|
||||
// }
|
||||
|
||||
for (auto succ : block->successors()) {
|
||||
const InstructionBlock* succ_block = code.InstructionBlockAt(succ);
|
||||
os << " B" << succ_block->id();
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "src/compiler/frame.h"
|
||||
#include "src/compiler/instruction-codes.h"
|
||||
#include "src/compiler/opcodes.h"
|
||||
#include "src/compiler/register-configuration.h"
|
||||
#include "src/compiler/schedule.h"
|
||||
#include "src/compiler/source-position.h"
|
||||
#include "src/zone-allocator.h"
|
||||
@ -27,18 +28,13 @@ const InstructionCode kGapInstruction = -1;
|
||||
const InstructionCode kBlockStartInstruction = -2;
|
||||
const InstructionCode kSourcePositionInstruction = -3;
|
||||
|
||||
// Platform independent maxes.
|
||||
static const int kMaxGeneralRegisters = 32;
|
||||
static const int kMaxDoubleRegisters = 32;
|
||||
|
||||
|
||||
#define INSTRUCTION_OPERAND_LIST(V) \
|
||||
V(Constant, CONSTANT, 0) \
|
||||
V(Immediate, IMMEDIATE, 0) \
|
||||
V(StackSlot, STACK_SLOT, 128) \
|
||||
V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \
|
||||
V(Register, REGISTER, kMaxGeneralRegisters) \
|
||||
V(DoubleRegister, DOUBLE_REGISTER, kMaxDoubleRegisters)
|
||||
#define INSTRUCTION_OPERAND_LIST(V) \
|
||||
V(Constant, CONSTANT, 0) \
|
||||
V(Immediate, IMMEDIATE, 0) \
|
||||
V(StackSlot, STACK_SLOT, 128) \
|
||||
V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \
|
||||
V(Register, REGISTER, RegisterConfiguration::kMaxGeneralRegisters) \
|
||||
V(DoubleRegister, DOUBLE_REGISTER, RegisterConfiguration::kMaxDoubleRegisters)
|
||||
|
||||
class InstructionOperand : public ZoneObject {
|
||||
public:
|
||||
@ -87,7 +83,13 @@ class InstructionOperand : public ZoneObject {
|
||||
|
||||
typedef ZoneVector<InstructionOperand*> InstructionOperandVector;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const InstructionOperand& op);
|
||||
struct PrintableInstructionOperand {
|
||||
const RegisterConfiguration* register_configuration_;
|
||||
const InstructionOperand* op_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableInstructionOperand& op);
|
||||
|
||||
class UnallocatedOperand : public InstructionOperand {
|
||||
public:
|
||||
@ -306,7 +308,15 @@ class MoveOperands FINAL {
|
||||
InstructionOperand* destination_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const MoveOperands& mo);
|
||||
|
||||
struct PrintableMoveOperands {
|
||||
const RegisterConfiguration* register_configuration_;
|
||||
const MoveOperands* move_operands_;
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo);
|
||||
|
||||
|
||||
template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
|
||||
class SubKindOperand FINAL : public InstructionOperand {
|
||||
@ -359,7 +369,15 @@ class ParallelMove FINAL : public ZoneObject {
|
||||
ZoneList<MoveOperands> move_operands_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const ParallelMove& pm);
|
||||
|
||||
struct PrintableParallelMove {
|
||||
const RegisterConfiguration* register_configuration_;
|
||||
const ParallelMove* parallel_move_;
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm);
|
||||
|
||||
|
||||
class PointerMap FINAL : public ZoneObject {
|
||||
public:
|
||||
@ -534,7 +552,13 @@ class Instruction : public ZoneObject {
|
||||
InstructionOperand* operands_[1];
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Instruction& instr);
|
||||
|
||||
struct PrintableInstruction {
|
||||
const RegisterConfiguration* register_configuration_;
|
||||
const Instruction* instr_;
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr);
|
||||
|
||||
|
||||
// Represents moves inserted before an instruction due to register allocation.
|
||||
// TODO(titzer): squash GapInstruction back into Instruction, since essentially
|
||||
@ -585,7 +609,8 @@ class GapInstruction : public Instruction {
|
||||
}
|
||||
|
||||
private:
|
||||
friend std::ostream& operator<<(std::ostream& os, const Instruction& instr);
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableInstruction& instr);
|
||||
ParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
|
||||
};
|
||||
|
||||
@ -847,6 +872,9 @@ typedef ZoneDeque<PointerMap*> PointerMapDeque;
|
||||
typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector;
|
||||
typedef ZoneVector<InstructionBlock*> InstructionBlocks;
|
||||
|
||||
struct PrintableInstructionSequence;
|
||||
|
||||
|
||||
// Represents architecture-specific generated code before, during, and after
|
||||
// register allocation.
|
||||
// TODO(titzer): s/IsDouble/IsFloat64/
|
||||
@ -961,7 +989,7 @@ class InstructionSequence FINAL {
|
||||
|
||||
private:
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
const InstructionSequence& code);
|
||||
const PrintableInstructionSequence& code);
|
||||
|
||||
typedef std::set<int, std::less<int>, ZoneIntAllocator> VirtualRegisterSet;
|
||||
|
||||
@ -977,7 +1005,15 @@ class InstructionSequence FINAL {
|
||||
DeoptimizationVector deoptimization_entries_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const InstructionSequence& code);
|
||||
|
||||
struct PrintableInstructionSequence {
|
||||
const RegisterConfiguration* register_configuration_;
|
||||
const InstructionSequence* sequence_;
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableInstructionSequence& code);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
|
@ -558,8 +558,10 @@ Handle<Code> Pipeline::GenerateCode(Linkage* linkage, PipelineData* data) {
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
PrintableInstructionSequence printable = {
|
||||
RegisterConfiguration::ArchDefault(), &sequence};
|
||||
os << "----- Instruction sequence before register allocation -----\n"
|
||||
<< sequence;
|
||||
<< printable;
|
||||
TurboCfgFile tcf(isolate());
|
||||
tcf << AsC1V("CodeGen", data->schedule(), data->source_positions(),
|
||||
&sequence);
|
||||
@ -587,7 +589,7 @@ Handle<Code> Pipeline::GenerateCode(Linkage* linkage, PipelineData* data) {
|
||||
#endif
|
||||
|
||||
|
||||
RegisterAllocator allocator(RegisterAllocator::PlatformConfig(),
|
||||
RegisterAllocator allocator(RegisterConfiguration::ArchDefault(),
|
||||
zone_scope.zone(), &frame, &sequence,
|
||||
debug_name.get());
|
||||
if (!allocator.Allocate(data->pipeline_statistics())) {
|
||||
@ -602,8 +604,10 @@ Handle<Code> Pipeline::GenerateCode(Linkage* linkage, PipelineData* data) {
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
OFStream os(stdout);
|
||||
PrintableInstructionSequence printable = {
|
||||
RegisterConfiguration::ArchDefault(), &sequence};
|
||||
os << "----- Instruction sequence after register allocation -----\n"
|
||||
<< sequence;
|
||||
<< printable;
|
||||
}
|
||||
|
||||
if (data->pipeline_statistics() != NULL) {
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/pipeline-statistics.h"
|
||||
#include "src/compiler/register-allocator.h"
|
||||
#include "src/macro-assembler.h" // TODO(dcarney): remove this.
|
||||
#include "src/string-stream.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -507,22 +506,9 @@ LifetimePosition LiveRange::FirstIntersection(LiveRange* other) {
|
||||
}
|
||||
|
||||
|
||||
RegisterAllocator::Config RegisterAllocator::PlatformConfig() {
|
||||
DCHECK_EQ(Register::kMaxNumAllocatableRegisters,
|
||||
Register::NumAllocatableRegisters());
|
||||
Config config;
|
||||
config.num_general_registers_ = Register::kMaxNumAllocatableRegisters;
|
||||
config.num_double_registers_ = DoubleRegister::kMaxNumAllocatableRegisters;
|
||||
config.num_aliased_double_registers_ =
|
||||
DoubleRegister::NumAllocatableAliasedRegisters();
|
||||
config.GeneralRegisterName = Register::AllocationIndexToString;
|
||||
config.DoubleRegisterName = DoubleRegister::AllocationIndexToString;
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
RegisterAllocator::RegisterAllocator(const Config& config, Zone* local_zone,
|
||||
Frame* frame, InstructionSequence* code,
|
||||
RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config,
|
||||
Zone* local_zone, Frame* frame,
|
||||
InstructionSequence* code,
|
||||
const char* debug_name)
|
||||
: zone_(local_zone),
|
||||
frame_(frame),
|
||||
@ -531,8 +517,8 @@ RegisterAllocator::RegisterAllocator(const Config& config, Zone* local_zone,
|
||||
config_(config),
|
||||
live_in_sets_(code->InstructionBlockCount(), zone()),
|
||||
live_ranges_(code->VirtualRegisterCount() * 2, zone()),
|
||||
fixed_live_ranges_(this->config().num_general_registers_, NULL, zone()),
|
||||
fixed_double_live_ranges_(this->config().num_double_registers_, NULL,
|
||||
fixed_live_ranges_(this->config()->num_general_registers(), NULL, zone()),
|
||||
fixed_double_live_ranges_(this->config()->num_double_registers(), NULL,
|
||||
zone()),
|
||||
unhandled_live_ranges_(code->VirtualRegisterCount() * 2, zone()),
|
||||
active_live_ranges_(8, zone()),
|
||||
@ -541,12 +527,14 @@ RegisterAllocator::RegisterAllocator(const Config& config, Zone* local_zone,
|
||||
mode_(UNALLOCATED_REGISTERS),
|
||||
num_registers_(-1),
|
||||
allocation_ok_(true) {
|
||||
DCHECK(this->config().num_general_registers_ <= kMaxGeneralRegisters);
|
||||
DCHECK(this->config().num_double_registers_ <= kMaxDoubleRegisters);
|
||||
DCHECK(this->config()->num_general_registers() <=
|
||||
RegisterConfiguration::kMaxGeneralRegisters);
|
||||
DCHECK(this->config()->num_double_registers() <=
|
||||
RegisterConfiguration::kMaxDoubleRegisters);
|
||||
// TryAllocateFreeReg and AllocateBlockedReg assume this
|
||||
// when allocating local arrays.
|
||||
DCHECK(this->config().num_double_registers_ >=
|
||||
this->config().num_general_registers_);
|
||||
DCHECK(this->config()->num_double_registers() >=
|
||||
this->config()->num_general_registers());
|
||||
}
|
||||
|
||||
|
||||
@ -603,7 +591,7 @@ void RegisterAllocator::AddInitialIntervals(const InstructionBlock* block,
|
||||
|
||||
|
||||
int RegisterAllocator::FixedDoubleLiveRangeID(int index) {
|
||||
return -index - 1 - config().num_general_registers_;
|
||||
return -index - 1 - config()->num_general_registers();
|
||||
}
|
||||
|
||||
|
||||
@ -635,7 +623,7 @@ InstructionOperand* RegisterAllocator::AllocateFixed(
|
||||
|
||||
|
||||
LiveRange* RegisterAllocator::FixedLiveRangeFor(int index) {
|
||||
DCHECK(index < config().num_general_registers_);
|
||||
DCHECK(index < config()->num_general_registers());
|
||||
LiveRange* result = fixed_live_ranges_[index];
|
||||
if (result == NULL) {
|
||||
// TODO(titzer): add a utility method to allocate a new LiveRange:
|
||||
@ -653,7 +641,7 @@ LiveRange* RegisterAllocator::FixedLiveRangeFor(int index) {
|
||||
|
||||
|
||||
LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) {
|
||||
DCHECK(index < config().num_aliased_double_registers_);
|
||||
DCHECK(index < config()->num_aliased_double_registers());
|
||||
LiveRange* result = fixed_double_live_ranges_[index];
|
||||
if (result == NULL) {
|
||||
result = new (zone()) LiveRange(FixedDoubleLiveRangeID(index), code_zone());
|
||||
@ -1031,7 +1019,7 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
|
||||
}
|
||||
|
||||
if (instr->ClobbersRegisters()) {
|
||||
for (int i = 0; i < config().num_general_registers_; ++i) {
|
||||
for (int i = 0; i < config()->num_general_registers(); ++i) {
|
||||
if (!IsOutputRegisterOf(instr, i)) {
|
||||
LiveRange* range = FixedLiveRangeFor(i);
|
||||
range->AddUseInterval(curr_position, curr_position.InstructionEnd(),
|
||||
@ -1041,7 +1029,7 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
|
||||
}
|
||||
|
||||
if (instr->ClobbersDoubleRegisters()) {
|
||||
for (int i = 0; i < config().num_aliased_double_registers_; ++i) {
|
||||
for (int i = 0; i < config()->num_aliased_double_registers(); ++i) {
|
||||
if (!IsOutputDoubleRegisterOf(instr, i)) {
|
||||
LiveRange* range = FixedDoubleLiveRangeFor(i);
|
||||
range->AddUseInterval(curr_position, curr_position.InstructionEnd(),
|
||||
@ -1126,10 +1114,10 @@ void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
|
||||
|
||||
|
||||
bool RegisterAllocator::Allocate(PipelineStatistics* stats) {
|
||||
assigned_registers_ =
|
||||
new (code_zone()) BitVector(config().num_general_registers_, code_zone());
|
||||
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());
|
||||
BitVector(config()->num_aliased_double_registers(), code_zone());
|
||||
{
|
||||
PhaseScope phase_scope(stats, "meet register constraints");
|
||||
MeetRegisterConstraints();
|
||||
@ -1535,14 +1523,14 @@ void RegisterAllocator::PopulatePointerMaps() {
|
||||
|
||||
|
||||
void RegisterAllocator::AllocateGeneralRegisters() {
|
||||
num_registers_ = config().num_general_registers_;
|
||||
num_registers_ = config()->num_general_registers();
|
||||
mode_ = GENERAL_REGISTERS;
|
||||
AllocateRegisters();
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocator::AllocateDoubleRegisters() {
|
||||
num_registers_ = config().num_aliased_double_registers_;
|
||||
num_registers_ = config()->num_aliased_double_registers();
|
||||
mode_ = DOUBLE_REGISTERS;
|
||||
AllocateRegisters();
|
||||
}
|
||||
@ -1566,7 +1554,7 @@ void RegisterAllocator::AllocateRegisters() {
|
||||
DCHECK(inactive_live_ranges_.is_empty());
|
||||
|
||||
if (mode_ == DOUBLE_REGISTERS) {
|
||||
for (int i = 0; i < config().num_aliased_double_registers_; ++i) {
|
||||
for (int i = 0; i < config()->num_aliased_double_registers(); ++i) {
|
||||
LiveRange* current = fixed_double_live_ranges_.at(i);
|
||||
if (current != NULL) {
|
||||
AddToInactive(current);
|
||||
@ -1658,9 +1646,9 @@ void RegisterAllocator::AllocateRegisters() {
|
||||
|
||||
const char* RegisterAllocator::RegisterName(int allocation_index) {
|
||||
if (mode_ == GENERAL_REGISTERS) {
|
||||
return config().GeneralRegisterName(allocation_index);
|
||||
return config()->general_register_name(allocation_index);
|
||||
} else {
|
||||
return config().DoubleRegisterName(allocation_index);
|
||||
return config()->double_register_name(allocation_index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1805,7 +1793,7 @@ void RegisterAllocator::InactiveToActive(LiveRange* range) {
|
||||
|
||||
|
||||
bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) {
|
||||
LifetimePosition free_until_pos[kMaxDoubleRegisters];
|
||||
LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters];
|
||||
|
||||
for (int i = 0; i < num_registers_; i++) {
|
||||
free_until_pos[i] = LifetimePosition::MaxPosition();
|
||||
@ -1888,8 +1876,8 @@ void RegisterAllocator::AllocateBlockedReg(LiveRange* current) {
|
||||
return;
|
||||
}
|
||||
|
||||
LifetimePosition use_pos[kMaxGeneralRegisters];
|
||||
LifetimePosition block_pos[kMaxDoubleRegisters];
|
||||
LifetimePosition use_pos[RegisterConfiguration::kMaxGeneralRegisters];
|
||||
LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters];
|
||||
|
||||
for (int i = 0; i < num_registers_; i++) {
|
||||
use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
|
||||
|
@ -319,19 +319,9 @@ class LiveRange FINAL : public ZoneObject {
|
||||
|
||||
class RegisterAllocator FINAL {
|
||||
public:
|
||||
class Config {
|
||||
public:
|
||||
int num_general_registers_;
|
||||
int num_double_registers_;
|
||||
int num_aliased_double_registers_;
|
||||
const char* (*GeneralRegisterName)(int allocation_index);
|
||||
const char* (*DoubleRegisterName)(int allocation_index);
|
||||
};
|
||||
|
||||
static Config PlatformConfig();
|
||||
|
||||
explicit RegisterAllocator(const Config& config, Zone* local_zone,
|
||||
Frame* frame, InstructionSequence* code,
|
||||
explicit RegisterAllocator(const RegisterConfiguration* config,
|
||||
Zone* local_zone, Frame* frame,
|
||||
InstructionSequence* code,
|
||||
const char* debug_name = nullptr);
|
||||
|
||||
bool Allocate(PipelineStatistics* stats = NULL);
|
||||
@ -502,14 +492,14 @@ class RegisterAllocator FINAL {
|
||||
|
||||
Frame* frame() const { return frame_; }
|
||||
const char* debug_name() const { return debug_name_; }
|
||||
const Config& config() const { return config_; }
|
||||
const RegisterConfiguration* config() const { return config_; }
|
||||
|
||||
Zone* const zone_;
|
||||
Frame* const frame_;
|
||||
InstructionSequence* const code_;
|
||||
const char* const debug_name_;
|
||||
|
||||
const Config config_;
|
||||
const RegisterConfiguration* config_;
|
||||
|
||||
// During liveness analysis keep a mapping from block id to live_in sets
|
||||
// for blocks already analyzed.
|
||||
|
68
src/compiler/register-configuration.cc
Normal file
68
src/compiler/register-configuration.cc
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/register-configuration.h"
|
||||
#include "src/macro-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
namespace {
|
||||
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
|
||||
Register::kNumRegisters);
|
||||
STATIC_ASSERT(RegisterConfiguration::kMaxDoubleRegisters >=
|
||||
DoubleRegister::kMaxNumRegisters);
|
||||
|
||||
class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
|
||||
public:
|
||||
ArchDefaultRegisterConfiguration()
|
||||
: RegisterConfiguration(Register::kMaxNumAllocatableRegisters,
|
||||
DoubleRegister::kMaxNumAllocatableRegisters,
|
||||
DoubleRegister::NumAllocatableAliasedRegisters(),
|
||||
general_register_name_table_,
|
||||
double_register_name_table_) {
|
||||
DCHECK_EQ(Register::kMaxNumAllocatableRegisters,
|
||||
Register::NumAllocatableRegisters());
|
||||
for (int i = 0; i < Register::kMaxNumAllocatableRegisters; ++i) {
|
||||
general_register_name_table_[i] = Register::AllocationIndexToString(i);
|
||||
}
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; ++i) {
|
||||
double_register_name_table_[i] =
|
||||
DoubleRegister::AllocationIndexToString(i);
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
general_register_name_table_[Register::kMaxNumAllocatableRegisters];
|
||||
const char*
|
||||
double_register_name_table_[DoubleRegister::kMaxNumAllocatableRegisters];
|
||||
};
|
||||
|
||||
|
||||
static base::LazyInstance<ArchDefaultRegisterConfiguration>::type
|
||||
kDefaultRegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
} // namepace
|
||||
|
||||
|
||||
const RegisterConfiguration* RegisterConfiguration::ArchDefault() {
|
||||
return &kDefaultRegisterConfiguration.Get();
|
||||
}
|
||||
|
||||
RegisterConfiguration::RegisterConfiguration(
|
||||
int num_general_registers, int num_double_registers,
|
||||
int num_aliased_double_registers, const char* const* general_register_names,
|
||||
const char* const* double_register_names)
|
||||
: num_general_registers_(num_general_registers),
|
||||
num_double_registers_(num_double_registers),
|
||||
num_aliased_double_registers_(num_aliased_double_registers),
|
||||
general_register_names_(general_register_names),
|
||||
double_register_names_(double_register_names) {}
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
56
src/compiler/register-configuration.h
Normal file
56
src/compiler/register-configuration.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_COMPILER_REGISTER_CONFIGURATION_H_
|
||||
#define V8_COMPILER_REGISTER_CONFIGURATION_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// An architecture independent representation of the sets of registers available
|
||||
// for instruction creation.
|
||||
class RegisterConfiguration {
|
||||
public:
|
||||
// Architecture independent maxes.
|
||||
static const int kMaxGeneralRegisters = 32;
|
||||
static const int kMaxDoubleRegisters = 32;
|
||||
|
||||
static const RegisterConfiguration* ArchDefault();
|
||||
|
||||
RegisterConfiguration(int num_general_registers, int num_double_registers,
|
||||
int num_aliased_double_registers,
|
||||
const char* const* general_register_name,
|
||||
const char* const* double_register_name);
|
||||
|
||||
int num_general_registers() const { return num_general_registers_; }
|
||||
int num_double_registers() const { return num_double_registers_; }
|
||||
int num_aliased_double_registers() const {
|
||||
return num_aliased_double_registers_;
|
||||
}
|
||||
|
||||
const char* general_register_name(int offset) const {
|
||||
DCHECK(offset >= 0 && offset < kMaxGeneralRegisters);
|
||||
return general_register_names_[offset];
|
||||
}
|
||||
const char* double_register_name(int offset) const {
|
||||
DCHECK(offset >= 0 && offset < kMaxDoubleRegisters);
|
||||
return double_register_names_[offset];
|
||||
}
|
||||
|
||||
private:
|
||||
const int num_general_registers_;
|
||||
const int num_double_registers_;
|
||||
const int num_aliased_double_registers_;
|
||||
const char* const* general_register_names_;
|
||||
const char* const* double_register_names_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_REGISTER_CONFIGURATION_H_
|
@ -75,18 +75,22 @@ class DeoptCodegenTester {
|
||||
selector.SelectInstructions();
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
PrintableInstructionSequence printable = {
|
||||
RegisterConfiguration::ArchDefault(), code};
|
||||
os << "----- Instruction sequence before register allocation -----\n"
|
||||
<< *code;
|
||||
<< printable;
|
||||
}
|
||||
|
||||
Frame frame;
|
||||
RegisterAllocator allocator(RegisterAllocator::PlatformConfig(),
|
||||
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"
|
||||
<< *code;
|
||||
<< printable;
|
||||
}
|
||||
|
||||
compiler::CodeGenerator generator(&frame, linkage, code, &info);
|
||||
|
@ -65,7 +65,9 @@ class InterpreterState {
|
||||
if (it != is.values_.begin()) os << " ";
|
||||
InstructionOperand source(it->first.first, it->first.second);
|
||||
InstructionOperand destination(it->second.first, it->second.second);
|
||||
os << MoveOperands(&source, &destination);
|
||||
MoveOperands mo(&source, &destination);
|
||||
PrintableMoveOperands pmo = {RegisterConfiguration::ArchDefault(), &mo};
|
||||
os << pmo;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
@ -46,8 +46,10 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
|
||||
selector.SelectInstructions();
|
||||
if (FLAG_trace_turbo) {
|
||||
OFStream out(stdout);
|
||||
PrintableInstructionSequence printable = {
|
||||
RegisterConfiguration::ArchDefault(), &sequence};
|
||||
out << "=== Code sequence after instruction selection ===" << std::endl
|
||||
<< sequence;
|
||||
<< printable;
|
||||
}
|
||||
Stream s;
|
||||
// Map virtual registers.
|
||||
|
@ -15,29 +15,22 @@ typedef BasicBlock::RpoNumber Rpo;
|
||||
|
||||
namespace {
|
||||
|
||||
static const char* general_register_names_[kMaxGeneralRegisters];
|
||||
static const char* double_register_names_[kMaxDoubleRegisters];
|
||||
static char register_names_[10 * (kMaxGeneralRegisters + kMaxDoubleRegisters)];
|
||||
|
||||
|
||||
static const char* GeneralRegisterName(int allocation_index) {
|
||||
return general_register_names_[allocation_index];
|
||||
}
|
||||
|
||||
|
||||
static const char* DoubleRegisterName(int allocation_index) {
|
||||
return double_register_names_[allocation_index];
|
||||
}
|
||||
static const char*
|
||||
general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
|
||||
static const char*
|
||||
double_register_names_[RegisterConfiguration::kMaxDoubleRegisters];
|
||||
static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
|
||||
RegisterConfiguration::kMaxDoubleRegisters)];
|
||||
|
||||
|
||||
static void InitializeRegisterNames() {
|
||||
char* loc = register_names_;
|
||||
for (int i = 0; i < kMaxGeneralRegisters; ++i) {
|
||||
for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
|
||||
general_register_names_[i] = loc;
|
||||
loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
|
||||
*loc++ = 0;
|
||||
}
|
||||
for (int i = 0; i < kMaxDoubleRegisters; ++i) {
|
||||
for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) {
|
||||
double_register_names_[i] = loc;
|
||||
loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
|
||||
*loc++ = 0;
|
||||
@ -54,15 +47,21 @@ class RegisterAllocatorTest : public TestWithZone {
|
||||
static const int kDefaultNRegs = 4;
|
||||
|
||||
RegisterAllocatorTest()
|
||||
: basic_blocks_(zone()),
|
||||
: num_general_registers_(kDefaultNRegs),
|
||||
num_double_registers_(kDefaultNRegs),
|
||||
basic_blocks_(zone()),
|
||||
instruction_blocks_(zone()),
|
||||
current_block_(NULL) {
|
||||
InitializeRegisterNames();
|
||||
config_.num_general_registers_ = kDefaultNRegs;
|
||||
config_.num_double_registers_ = kDefaultNRegs;
|
||||
config_.num_aliased_double_registers_ = kDefaultNRegs;
|
||||
config_.GeneralRegisterName = GeneralRegisterName;
|
||||
config_.DoubleRegisterName = DoubleRegisterName;
|
||||
}
|
||||
|
||||
RegisterConfiguration* config() {
|
||||
if (config_.is_empty()) {
|
||||
config_.Reset(new RegisterConfiguration(
|
||||
num_general_registers_, num_double_registers_, num_double_registers_,
|
||||
general_register_names_, double_register_names_));
|
||||
}
|
||||
return config_.get();
|
||||
}
|
||||
|
||||
Frame* frame() {
|
||||
@ -82,7 +81,7 @@ class RegisterAllocatorTest : public TestWithZone {
|
||||
RegisterAllocator* allocator() {
|
||||
if (allocator_.is_empty()) {
|
||||
allocator_.Reset(
|
||||
new RegisterAllocator(config_, zone(), frame(), sequence()));
|
||||
new RegisterAllocator(config(), zone(), frame(), sequence()));
|
||||
}
|
||||
return allocator_.get();
|
||||
}
|
||||
@ -118,12 +117,14 @@ class RegisterAllocatorTest : public TestWithZone {
|
||||
void Allocate() {
|
||||
if (FLAG_trace_alloc) {
|
||||
OFStream os(stdout);
|
||||
os << "Before: " << std::endl << *sequence() << std::endl;
|
||||
PrintableInstructionSequence printable = {config(), sequence()};
|
||||
os << "Before: " << std::endl << printable << std::endl;
|
||||
}
|
||||
allocator()->Allocate();
|
||||
if (FLAG_trace_alloc) {
|
||||
OFStream os(stdout);
|
||||
os << "After: " << std::endl << *sequence() << std::endl;
|
||||
PrintableInstructionSequence printable = {config(), sequence()};
|
||||
os << "After: " << std::endl << printable << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,7 +168,9 @@ class RegisterAllocatorTest : public TestWithZone {
|
||||
return op;
|
||||
}
|
||||
|
||||
RegisterAllocator::Config config_;
|
||||
int num_general_registers_;
|
||||
int num_double_registers_;
|
||||
SmartPointer<RegisterConfiguration> config_;
|
||||
ZoneVector<BasicBlock*> basic_blocks_;
|
||||
InstructionBlocks instruction_blocks_;
|
||||
InstructionBlock* current_block_;
|
||||
|
@ -484,6 +484,8 @@
|
||||
'../../src/compiler/raw-machine-assembler.h',
|
||||
'../../src/compiler/register-allocator.cc',
|
||||
'../../src/compiler/register-allocator.h',
|
||||
'../../src/compiler/register-configuration.cc',
|
||||
'../../src/compiler/register-configuration.h',
|
||||
'../../src/compiler/representation-change.h',
|
||||
'../../src/compiler/schedule.cc',
|
||||
'../../src/compiler/schedule.h',
|
||||
|
Loading…
Reference in New Issue
Block a user