[turbofan] decouple register allocation from schedule and graph
R=bmeurer@chromium.org, jarin@chromium.org BUG= Review URL: https://codereview.chromium.org/664683002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24717 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d029d76120
commit
b3f2277ea4
@ -853,8 +853,17 @@ void InstructionSelector::VisitParameter(Node* node) {
|
|||||||
|
|
||||||
void InstructionSelector::VisitPhi(Node* node) {
|
void InstructionSelector::VisitPhi(Node* node) {
|
||||||
// TODO(bmeurer): Emit a PhiInstruction here.
|
// TODO(bmeurer): Emit a PhiInstruction here.
|
||||||
for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
|
PhiInstruction* phi = new (instruction_zone())
|
||||||
MarkAsUsed(*i);
|
PhiInstruction(instruction_zone(), sequence()->GetVirtualRegister(node));
|
||||||
|
sequence()->InstructionBlockAt(current_block_->GetRpoNumber())->AddPhi(phi);
|
||||||
|
Node::Inputs inputs = node->inputs();
|
||||||
|
size_t j = 0;
|
||||||
|
for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
|
||||||
|
++iter, ++j) {
|
||||||
|
MarkAsUsed(*iter);
|
||||||
|
// TODO(mstarzinger): Use a ValueInputIterator instead.
|
||||||
|
if (j >= current_block_->PredecessorCount()) continue;
|
||||||
|
phi->operands().push_back(sequence()->GetVirtualRegister(*iter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,12 +317,75 @@ std::ostream& operator<<(std::ostream& os, const Constant& constant) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BasicBlock::RpoNumber GetRpo(BasicBlock* block) {
|
||||||
|
if (block == NULL) return BasicBlock::RpoNumber::Invalid();
|
||||||
|
return block->GetRpoNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BasicBlock::RpoNumber GetLoopEndRpo(const BasicBlock* block) {
|
||||||
|
if (!block->IsLoopHeader()) return BasicBlock::RpoNumber::Invalid();
|
||||||
|
return BasicBlock::RpoNumber::FromInt(block->loop_end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
InstructionBlock::InstructionBlock(Zone* zone, const BasicBlock* block)
|
||||||
|
: successors_(block->SuccessorCount(), BasicBlock::RpoNumber::Invalid(),
|
||||||
|
zone),
|
||||||
|
predecessors_(block->PredecessorCount(), BasicBlock::RpoNumber::Invalid(),
|
||||||
|
zone),
|
||||||
|
phis_(zone),
|
||||||
|
rpo_number_(block->GetRpoNumber()),
|
||||||
|
loop_header_(GetRpo(block->loop_header())),
|
||||||
|
loop_end_(GetLoopEndRpo(block)),
|
||||||
|
code_start_(-1),
|
||||||
|
code_end_(-1) {
|
||||||
|
// Map successors and precessors
|
||||||
|
size_t index = 0;
|
||||||
|
for (BasicBlock::Successors::const_iterator it = block->successors_begin();
|
||||||
|
it != block->successors_end(); ++it, ++index) {
|
||||||
|
successors_[index] = (*it)->GetRpoNumber();
|
||||||
|
}
|
||||||
|
index = 0;
|
||||||
|
for (BasicBlock::Predecessors::const_iterator
|
||||||
|
it = block->predecessors_begin();
|
||||||
|
it != block->predecessors_end(); ++it, ++index) {
|
||||||
|
predecessors_[index] = (*it)->GetRpoNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t InstructionBlock::PredecessorIndexOf(
|
||||||
|
BasicBlock::RpoNumber rpo_number) const {
|
||||||
|
size_t j = 0;
|
||||||
|
for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
|
||||||
|
i != predecessors_.end(); ++i, ++j) {
|
||||||
|
if (*i == rpo_number) break;
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void InitializeInstructionBlocks(Zone* zone, const Schedule* schedule,
|
||||||
|
InstructionBlocks* blocks) {
|
||||||
|
DCHECK(blocks->size() == schedule->rpo_order()->size());
|
||||||
|
size_t rpo_number = 0;
|
||||||
|
for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
|
||||||
|
it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
|
||||||
|
DCHECK_EQ(NULL, (*blocks)[rpo_number]);
|
||||||
|
DCHECK((*it)->GetRpoNumber().ToSize() == rpo_number);
|
||||||
|
(*blocks)[rpo_number] = new (zone) InstructionBlock(zone, *it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
InstructionSequence::InstructionSequence(Linkage* linkage, Graph* graph,
|
InstructionSequence::InstructionSequence(Linkage* linkage, Graph* graph,
|
||||||
Schedule* schedule)
|
Schedule* schedule)
|
||||||
: zone_(schedule->zone()),
|
: zone_(schedule->zone()), // TODO(dcarney): new zone.
|
||||||
node_count_(graph->NodeCount()),
|
node_count_(graph->NodeCount()),
|
||||||
node_map_(zone()->NewArray<int>(node_count_)),
|
node_map_(zone()->NewArray<int>(node_count_)),
|
||||||
block_data_(static_cast<int>(schedule->BasicBlockCount()), zone()),
|
instruction_blocks_(static_cast<int>(schedule->rpo_order()->size()), NULL,
|
||||||
|
zone()),
|
||||||
linkage_(linkage),
|
linkage_(linkage),
|
||||||
schedule_(schedule),
|
schedule_(schedule),
|
||||||
constants_(ConstantMap::key_compare(),
|
constants_(ConstantMap::key_compare(),
|
||||||
@ -337,6 +400,7 @@ InstructionSequence::InstructionSequence(Linkage* linkage, Graph* graph,
|
|||||||
for (int i = 0; i < node_count_; ++i) {
|
for (int i = 0; i < node_count_; ++i) {
|
||||||
node_map_[i] = -1;
|
node_map_[i] = -1;
|
||||||
}
|
}
|
||||||
|
InitializeInstructionBlocks(zone(), schedule, &instruction_blocks_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -408,6 +472,20 @@ BasicBlock* InstructionSequence::GetBasicBlock(int instruction_index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const InstructionBlock* InstructionSequence::GetInstructionBlock(
|
||||||
|
int instruction_index) const {
|
||||||
|
// TODO(turbofan): Optimize this.
|
||||||
|
for (;;) {
|
||||||
|
DCHECK_LE(0, instruction_index);
|
||||||
|
Instruction* instruction = InstructionAt(instruction_index--);
|
||||||
|
if (instruction->IsBlockStart()) {
|
||||||
|
return instruction_blocks_
|
||||||
|
[BlockStartInstruction::cast(instruction)->rpo_number().ToSize()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool InstructionSequence::IsReference(int virtual_register) const {
|
bool InstructionSequence::IsReference(int virtual_register) const {
|
||||||
return references_.find(virtual_register) != references_.end();
|
return references_.find(virtual_register) != references_.end();
|
||||||
}
|
}
|
||||||
|
@ -753,6 +753,81 @@ class FrameStateDescriptor : public ZoneObject {
|
|||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Constant& constant);
|
std::ostream& operator<<(std::ostream& os, const Constant& constant);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(dcarney): this is a temporary hack. turn into an actual instruction.
|
||||||
|
class PhiInstruction : public ZoneObject {
|
||||||
|
public:
|
||||||
|
PhiInstruction(Zone* zone, int virtual_register)
|
||||||
|
: virtual_register_(virtual_register), operands_(zone) {}
|
||||||
|
|
||||||
|
int virtual_register() const { return virtual_register_; }
|
||||||
|
const IntVector& operands() const { return operands_; }
|
||||||
|
IntVector& operands() { return operands_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int virtual_register_;
|
||||||
|
IntVector operands_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Analogue of BasicBlock for Instructions instead of Nodes.
|
||||||
|
class InstructionBlock : public ZoneObject {
|
||||||
|
public:
|
||||||
|
explicit InstructionBlock(Zone* zone, const BasicBlock* block);
|
||||||
|
|
||||||
|
// Instruction indexes (used by the register allocator).
|
||||||
|
int first_instruction_index() const {
|
||||||
|
DCHECK(code_start_ >= 0);
|
||||||
|
DCHECK(code_end_ > 0);
|
||||||
|
DCHECK(code_end_ >= code_start_);
|
||||||
|
return code_start_;
|
||||||
|
}
|
||||||
|
int last_instruction_index() const {
|
||||||
|
DCHECK(code_start_ >= 0);
|
||||||
|
DCHECK(code_end_ > 0);
|
||||||
|
DCHECK(code_end_ >= code_start_);
|
||||||
|
return code_end_ - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t code_start() const { return code_start_; }
|
||||||
|
void set_code_start(int32_t start) { code_start_ = start; }
|
||||||
|
|
||||||
|
int32_t code_end() const { return code_end_; }
|
||||||
|
void set_code_end(int32_t end) { code_end_ = end; }
|
||||||
|
|
||||||
|
BasicBlock::RpoNumber rpo_number() const { return rpo_number_; }
|
||||||
|
BasicBlock::RpoNumber loop_header() const { return loop_header_; }
|
||||||
|
BasicBlock::RpoNumber loop_end() const {
|
||||||
|
DCHECK(IsLoopHeader());
|
||||||
|
return loop_end_;
|
||||||
|
}
|
||||||
|
inline bool IsLoopHeader() const { return loop_end_.IsValid(); }
|
||||||
|
|
||||||
|
typedef ZoneVector<BasicBlock::RpoNumber> Predecessors;
|
||||||
|
const Predecessors& predecessors() const { return predecessors_; }
|
||||||
|
size_t PredecessorCount() const { return predecessors_.size(); }
|
||||||
|
size_t PredecessorIndexOf(BasicBlock::RpoNumber rpo_number) const;
|
||||||
|
|
||||||
|
typedef ZoneVector<BasicBlock::RpoNumber> Successors;
|
||||||
|
const Successors& successors() const { return successors_; }
|
||||||
|
size_t SuccessorCount() const { return successors_.size(); }
|
||||||
|
|
||||||
|
typedef ZoneVector<PhiInstruction*> PhiInstructions;
|
||||||
|
const PhiInstructions& phis() const { return phis_; }
|
||||||
|
void AddPhi(PhiInstruction* phi) { phis_.push_back(phi); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Successors successors_;
|
||||||
|
Predecessors predecessors_;
|
||||||
|
PhiInstructions phis_;
|
||||||
|
// TODO(dcarney): probably dont't need this.
|
||||||
|
BasicBlock::RpoNumber rpo_number_;
|
||||||
|
BasicBlock::RpoNumber loop_header_;
|
||||||
|
BasicBlock::RpoNumber loop_end_;
|
||||||
|
int32_t code_start_; // start index of arch-specific code.
|
||||||
|
int32_t code_end_; // end index of arch-specific code.
|
||||||
|
};
|
||||||
|
|
||||||
typedef ZoneDeque<Constant> ConstantDeque;
|
typedef ZoneDeque<Constant> ConstantDeque;
|
||||||
typedef std::map<int, Constant, std::less<int>,
|
typedef std::map<int, Constant, std::less<int>,
|
||||||
zone_allocator<std::pair<int, Constant> > > ConstantMap;
|
zone_allocator<std::pair<int, Constant> > > ConstantMap;
|
||||||
@ -760,6 +835,7 @@ typedef std::map<int, Constant, std::less<int>,
|
|||||||
typedef ZoneDeque<Instruction*> InstructionDeque;
|
typedef ZoneDeque<Instruction*> InstructionDeque;
|
||||||
typedef ZoneDeque<PointerMap*> PointerMapDeque;
|
typedef ZoneDeque<PointerMap*> PointerMapDeque;
|
||||||
typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector;
|
typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector;
|
||||||
|
typedef ZoneVector<InstructionBlock*> InstructionBlocks;
|
||||||
|
|
||||||
// Represents architecture-specific generated code before, during, and after
|
// Represents architecture-specific generated code before, during, and after
|
||||||
// register allocation.
|
// register allocation.
|
||||||
@ -774,18 +850,32 @@ class InstructionSequence FINAL {
|
|||||||
int node_count() const { return node_count_; }
|
int node_count() const { return node_count_; }
|
||||||
|
|
||||||
int BasicBlockCount() const {
|
int BasicBlockCount() const {
|
||||||
return static_cast<int>(schedule_->rpo_order()->size());
|
return static_cast<int>(instruction_blocks_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock* BlockAt(int rpo_number) const {
|
BasicBlock* BlockAt(int rpo_number) const {
|
||||||
return (*schedule_->rpo_order())[rpo_number];
|
return (*schedule_->rpo_order())[rpo_number];
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock* GetContainingLoop(BasicBlock* block) {
|
InstructionBlock* InstructionBlockAt(BasicBlock::RpoNumber rpo_number) {
|
||||||
return block->loop_header();
|
return GetBlock(rpo_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const InstructionBlock* InstructionBlockAt(
|
||||||
|
BasicBlock::RpoNumber rpo_number) const {
|
||||||
|
return GetBlock(rpo_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(dcarney): move to register allocator.
|
||||||
|
const InstructionBlock* GetContainingLoop(
|
||||||
|
const InstructionBlock* block) const {
|
||||||
|
BasicBlock::RpoNumber index = block->loop_header();
|
||||||
|
if (!index.IsValid()) return NULL;
|
||||||
|
return instruction_blocks_[index.ToInt()];
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock* GetBasicBlock(int instruction_index);
|
BasicBlock* GetBasicBlock(int instruction_index);
|
||||||
|
const InstructionBlock* GetInstructionBlock(int instruction_index) const;
|
||||||
|
|
||||||
int GetVirtualRegister(const Node* node);
|
int GetVirtualRegister(const Node* node);
|
||||||
// TODO(dcarney): find a way to remove this.
|
// TODO(dcarney): find a way to remove this.
|
||||||
@ -828,26 +918,32 @@ class InstructionSequence FINAL {
|
|||||||
void StartBlock(BasicBlock* block);
|
void StartBlock(BasicBlock* block);
|
||||||
void EndBlock(BasicBlock* block);
|
void EndBlock(BasicBlock* block);
|
||||||
void set_code_start(BasicBlock* block, int start) {
|
void set_code_start(BasicBlock* block, int start) {
|
||||||
return GetBlockData(block->GetRpoNumber()).set_code_start(start);
|
return GetBlock(block->GetRpoNumber())->set_code_start(start);
|
||||||
}
|
}
|
||||||
void set_code_end(BasicBlock* block, int end) {
|
void set_code_end(BasicBlock* block, int end) {
|
||||||
return GetBlockData(block->GetRpoNumber()).set_code_end(end);
|
return GetBlock(block->GetRpoNumber())->set_code_end(end);
|
||||||
}
|
}
|
||||||
// TODO(dcarney): use RpoNumber for all of the below.
|
// TODO(dcarney): use RpoNumber for all of the below.
|
||||||
int code_start(BasicBlock::RpoNumber rpo_number) const {
|
int code_start(BasicBlock::RpoNumber rpo_number) const {
|
||||||
return GetBlockData(rpo_number).code_start();
|
return GetBlock(rpo_number)->code_start();
|
||||||
}
|
}
|
||||||
int code_start(BasicBlock* block) const {
|
int code_start(BasicBlock* block) const {
|
||||||
return GetBlockData(block->GetRpoNumber()).code_start();
|
return GetBlock(block->GetRpoNumber())->code_start();
|
||||||
}
|
}
|
||||||
int code_end(BasicBlock* block) const {
|
int code_end(BasicBlock* block) const {
|
||||||
return GetBlockData(block->GetRpoNumber()).code_end();
|
return GetBlock(block->GetRpoNumber())->code_end();
|
||||||
}
|
}
|
||||||
int first_instruction_index(BasicBlock* block) const {
|
int first_instruction_index(BasicBlock* block) const {
|
||||||
return GetBlockData(block->GetRpoNumber()).first_instruction_index();
|
return GetBlock(block->GetRpoNumber())->first_instruction_index();
|
||||||
}
|
}
|
||||||
int last_instruction_index(BasicBlock* block) const {
|
int last_instruction_index(BasicBlock* block) const {
|
||||||
return GetBlockData(block->GetRpoNumber()).last_instruction_index();
|
return GetBlock(block->GetRpoNumber())->last_instruction_index();
|
||||||
|
}
|
||||||
|
int first_instruction_index(InstructionBlock* block) const {
|
||||||
|
return GetBlock(block->rpo_number())->first_instruction_index();
|
||||||
|
}
|
||||||
|
int last_instruction_index(InstructionBlock* block) const {
|
||||||
|
return GetBlock(block->rpo_number())->last_instruction_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AddConstant(Node* node, Constant constant) {
|
int AddConstant(Node* node, Constant constant) {
|
||||||
@ -892,51 +988,19 @@ class InstructionSequence FINAL {
|
|||||||
int GetFrameStateDescriptorCount();
|
int GetFrameStateDescriptorCount();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class BlockData {
|
InstructionBlock* GetBlock(BasicBlock::RpoNumber rpo_number) const {
|
||||||
public:
|
return instruction_blocks_[rpo_number.ToSize()];
|
||||||
BlockData() : code_start_(-1), code_end_(-1) {}
|
|
||||||
// Instruction indexes (used by the register allocator).
|
|
||||||
int first_instruction_index() const {
|
|
||||||
DCHECK(code_start_ >= 0);
|
|
||||||
DCHECK(code_end_ > 0);
|
|
||||||
DCHECK(code_end_ >= code_start_);
|
|
||||||
return code_start_;
|
|
||||||
}
|
|
||||||
int last_instruction_index() const {
|
|
||||||
DCHECK(code_start_ >= 0);
|
|
||||||
DCHECK(code_end_ > 0);
|
|
||||||
DCHECK(code_end_ >= code_start_);
|
|
||||||
return code_end_ - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t code_start() const { return code_start_; }
|
|
||||||
void set_code_start(int32_t start) { code_start_ = start; }
|
|
||||||
|
|
||||||
int32_t code_end() const { return code_end_; }
|
|
||||||
void set_code_end(int32_t end) { code_end_ = end; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int32_t code_start_; // start index of arch-specific code.
|
|
||||||
int32_t code_end_; // end index of arch-specific code.
|
|
||||||
};
|
|
||||||
|
|
||||||
const BlockData& GetBlockData(BasicBlock::RpoNumber rpo_number) const {
|
|
||||||
return block_data_[rpo_number.ToSize()];
|
|
||||||
}
|
|
||||||
BlockData& GetBlockData(BasicBlock::RpoNumber rpo_number) {
|
|
||||||
return block_data_[rpo_number.ToSize()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os,
|
friend std::ostream& operator<<(std::ostream& os,
|
||||||
const InstructionSequence& code);
|
const InstructionSequence& code);
|
||||||
|
|
||||||
typedef std::set<int, std::less<int>, ZoneIntAllocator> VirtualRegisterSet;
|
typedef std::set<int, std::less<int>, ZoneIntAllocator> VirtualRegisterSet;
|
||||||
typedef ZoneVector<BlockData> BlockDataVector;
|
|
||||||
|
|
||||||
Zone* zone_;
|
Zone* zone_;
|
||||||
int node_count_;
|
int node_count_;
|
||||||
int* node_map_;
|
int* node_map_;
|
||||||
BlockDataVector block_data_;
|
InstructionBlocks instruction_blocks_;
|
||||||
Linkage* linkage_;
|
Linkage* linkage_;
|
||||||
Schedule* schedule_;
|
Schedule* schedule_;
|
||||||
ConstantMap constants_;
|
ConstantMap constants_;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "src/compiler/register-allocator.h"
|
#include "src/compiler/register-allocator.h"
|
||||||
|
|
||||||
#include "src/compiler/generic-node-inl.h"
|
|
||||||
#include "src/compiler/linkage.h"
|
#include "src/compiler/linkage.h"
|
||||||
#include "src/hydrogen.h"
|
#include "src/hydrogen.h"
|
||||||
#include "src/string-stream.h"
|
#include "src/string-stream.h"
|
||||||
@ -524,46 +523,40 @@ void RegisterAllocator::InitializeLivenessAnalysis() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BitVector* RegisterAllocator::ComputeLiveOut(BasicBlock* block) {
|
BitVector* RegisterAllocator::ComputeLiveOut(const InstructionBlock* block) {
|
||||||
// Compute live out for the given block, except not including backward
|
// Compute live out for the given block, except not including backward
|
||||||
// successor edges.
|
// successor edges.
|
||||||
BitVector* live_out =
|
BitVector* live_out =
|
||||||
new (zone()) BitVector(code()->VirtualRegisterCount(), zone());
|
new (zone()) BitVector(code()->VirtualRegisterCount(), zone());
|
||||||
|
|
||||||
// Process all successor blocks.
|
// Process all successor blocks.
|
||||||
for (BasicBlock::Successors::iterator i = block->successors_begin();
|
for (auto succ : block->successors()) {
|
||||||
i != block->successors_end(); ++i) {
|
|
||||||
// Add values live on entry to the successor. Note the successor's
|
// Add values live on entry to the successor. Note the successor's
|
||||||
// live_in will not be computed yet for backwards edges.
|
// live_in will not be computed yet for backwards edges.
|
||||||
BasicBlock* successor = *i;
|
BitVector* live_in = live_in_sets_[succ.ToSize()];
|
||||||
BitVector* live_in = live_in_sets_[successor->rpo_number()];
|
|
||||||
if (live_in != NULL) live_out->Union(*live_in);
|
if (live_in != NULL) live_out->Union(*live_in);
|
||||||
|
|
||||||
// All phi input operands corresponding to this successor edge are live
|
// All phi input operands corresponding to this successor edge are live
|
||||||
// out from this block.
|
// out from this block.
|
||||||
size_t index = successor->PredecessorIndexOf(block);
|
const InstructionBlock* successor = code()->InstructionBlockAt(succ);
|
||||||
|
size_t index = successor->PredecessorIndexOf(block->rpo_number());
|
||||||
DCHECK(index < successor->PredecessorCount());
|
DCHECK(index < successor->PredecessorCount());
|
||||||
for (BasicBlock::const_iterator j = successor->begin();
|
for (auto phi : successor->phis()) {
|
||||||
j != successor->end(); ++j) {
|
live_out->Add(phi->operands()[index]);
|
||||||
Node* phi = *j;
|
|
||||||
if (phi->opcode() != IrOpcode::kPhi) continue;
|
|
||||||
Node* input = phi->InputAt(static_cast<int>(index));
|
|
||||||
live_out->Add(code()->GetVirtualRegister(input));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return live_out;
|
return live_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RegisterAllocator::AddInitialIntervals(BasicBlock* block,
|
void RegisterAllocator::AddInitialIntervals(const InstructionBlock* block,
|
||||||
BitVector* live_out) {
|
BitVector* live_out) {
|
||||||
// Add an interval that includes the entire block to the live range for
|
// Add an interval that includes the entire block to the live range for
|
||||||
// each live_out value.
|
// each live_out value.
|
||||||
LifetimePosition start = LifetimePosition::FromInstructionIndex(
|
LifetimePosition start =
|
||||||
code()->first_instruction_index(block));
|
LifetimePosition::FromInstructionIndex(block->first_instruction_index());
|
||||||
LifetimePosition end =
|
LifetimePosition end = LifetimePosition::FromInstructionIndex(
|
||||||
LifetimePosition::FromInstructionIndex(
|
block->last_instruction_index()).NextInstruction();
|
||||||
code()->last_instruction_index(block)).NextInstruction();
|
|
||||||
BitVector::Iterator iterator(live_out);
|
BitVector::Iterator iterator(live_out);
|
||||||
while (!iterator.Done()) {
|
while (!iterator.Done()) {
|
||||||
int operand_index = iterator.Current();
|
int operand_index = iterator.Current();
|
||||||
@ -651,8 +644,8 @@ LiveRange* RegisterAllocator::LiveRangeFor(int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GapInstruction* RegisterAllocator::GetLastGap(BasicBlock* block) {
|
GapInstruction* RegisterAllocator::GetLastGap(const InstructionBlock* block) {
|
||||||
int last_instruction = code()->last_instruction_index(block);
|
int last_instruction = block->last_instruction_index();
|
||||||
return code()->GapAt(last_instruction - 1);
|
return code()->GapAt(last_instruction - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,9 +722,9 @@ void RegisterAllocator::AddConstraintsGapMove(int index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RegisterAllocator::MeetRegisterConstraints(BasicBlock* block) {
|
void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) {
|
||||||
int start = code()->first_instruction_index(block);
|
int start = block->first_instruction_index();
|
||||||
int end = code()->last_instruction_index(block);
|
int end = block->last_instruction_index();
|
||||||
DCHECK_NE(-1, start);
|
DCHECK_NE(-1, start);
|
||||||
for (int i = start; i <= end; ++i) {
|
for (int i = start; i <= end; ++i) {
|
||||||
if (code()->IsGapAt(i)) {
|
if (code()->IsGapAt(i)) {
|
||||||
@ -752,8 +745,8 @@ void RegisterAllocator::MeetRegisterConstraints(BasicBlock* block) {
|
|||||||
|
|
||||||
|
|
||||||
void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock(
|
void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock(
|
||||||
BasicBlock* block) {
|
const InstructionBlock* block) {
|
||||||
int end = code()->last_instruction_index(block);
|
int end = block->last_instruction_index();
|
||||||
Instruction* last_instruction = InstructionAt(end);
|
Instruction* last_instruction = InstructionAt(end);
|
||||||
for (size_t i = 0; i < last_instruction->OutputCount(); i++) {
|
for (size_t i = 0; i < last_instruction->OutputCount(); i++) {
|
||||||
InstructionOperand* output_operand = last_instruction->OutputAt(i);
|
InstructionOperand* output_operand = last_instruction->OutputAt(i);
|
||||||
@ -771,10 +764,10 @@ void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock(
|
|||||||
assigned = true;
|
assigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (BasicBlock::Successors::iterator succ = block->successors_begin();
|
for (auto succ : block->successors()) {
|
||||||
succ != block->successors_end(); ++succ) {
|
const InstructionBlock* successor = code()->InstructionBlockAt(succ);
|
||||||
DCHECK((*succ)->PredecessorCount() == 1);
|
DCHECK(successor->PredecessorCount() == 1);
|
||||||
int gap_index = code()->first_instruction_index(*succ) + 1;
|
int gap_index = successor->first_instruction_index() + 1;
|
||||||
DCHECK(code()->IsGapAt(gap_index));
|
DCHECK(code()->IsGapAt(gap_index));
|
||||||
|
|
||||||
// Create an unconstrained operand for the same virtual register
|
// Create an unconstrained operand for the same virtual register
|
||||||
@ -788,10 +781,10 @@ void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!assigned) {
|
if (!assigned) {
|
||||||
for (BasicBlock::Successors::iterator succ = block->successors_begin();
|
for (auto succ : block->successors()) {
|
||||||
succ != block->successors_end(); ++succ) {
|
const InstructionBlock* successor = code()->InstructionBlockAt(succ);
|
||||||
DCHECK((*succ)->PredecessorCount() == 1);
|
DCHECK(successor->PredecessorCount() == 1);
|
||||||
int gap_index = code()->first_instruction_index(*succ) + 1;
|
int gap_index = successor->first_instruction_index() + 1;
|
||||||
range->SetSpillStartIndex(gap_index);
|
range->SetSpillStartIndex(gap_index);
|
||||||
|
|
||||||
// This move to spill operand is not a real use. Liveness analysis
|
// This move to spill operand is not a real use. Liveness analysis
|
||||||
@ -936,14 +929,14 @@ bool RegisterAllocator::IsOutputDoubleRegisterOf(Instruction* instr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RegisterAllocator::ProcessInstructions(BasicBlock* block,
|
void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
|
||||||
BitVector* live) {
|
BitVector* live) {
|
||||||
int block_start = code()->first_instruction_index(block);
|
int block_start = block->first_instruction_index();
|
||||||
|
|
||||||
LifetimePosition block_start_position =
|
LifetimePosition block_start_position =
|
||||||
LifetimePosition::FromInstructionIndex(block_start);
|
LifetimePosition::FromInstructionIndex(block_start);
|
||||||
|
|
||||||
for (int index = code()->last_instruction_index(block); index >= block_start;
|
for (int index = block->last_instruction_index(); index >= block_start;
|
||||||
index--) {
|
index--) {
|
||||||
LifetimePosition curr_position =
|
LifetimePosition curr_position =
|
||||||
LifetimePosition::FromInstructionIndex(index);
|
LifetimePosition::FromInstructionIndex(index);
|
||||||
@ -1059,44 +1052,35 @@ void RegisterAllocator::ProcessInstructions(BasicBlock* block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RegisterAllocator::ResolvePhis(BasicBlock* block) {
|
void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
|
||||||
for (BasicBlock::const_iterator i = block->begin(); i != block->end(); ++i) {
|
for (auto phi : block->phis()) {
|
||||||
Node* phi = *i;
|
|
||||||
if (phi->opcode() != IrOpcode::kPhi) continue;
|
|
||||||
|
|
||||||
UnallocatedOperand* phi_operand =
|
UnallocatedOperand* phi_operand =
|
||||||
new (code_zone()) UnallocatedOperand(UnallocatedOperand::NONE);
|
new (code_zone()) UnallocatedOperand(UnallocatedOperand::NONE);
|
||||||
int phi_vreg = code()->GetVirtualRegister(phi);
|
int phi_vreg = phi->virtual_register();
|
||||||
phi_operand->set_virtual_register(phi_vreg);
|
phi_operand->set_virtual_register(phi_vreg);
|
||||||
|
|
||||||
size_t j = 0;
|
for (size_t i = 0; i < phi->operands().size(); ++i) {
|
||||||
Node::Inputs inputs = phi->inputs();
|
|
||||||
for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
|
|
||||||
++iter, ++j) {
|
|
||||||
Node* op = *iter;
|
|
||||||
// TODO(mstarzinger): Use a ValueInputIterator instead.
|
|
||||||
if (j >= block->PredecessorCount()) continue;
|
|
||||||
UnallocatedOperand* operand =
|
UnallocatedOperand* operand =
|
||||||
new (code_zone()) UnallocatedOperand(UnallocatedOperand::ANY);
|
new (code_zone()) UnallocatedOperand(UnallocatedOperand::ANY);
|
||||||
operand->set_virtual_register(code()->GetVirtualRegister(op));
|
operand->set_virtual_register(phi->operands()[i]);
|
||||||
BasicBlock* cur_block = block->PredecessorAt(j);
|
InstructionBlock* cur_block =
|
||||||
|
code()->InstructionBlockAt(block->predecessors()[i]);
|
||||||
// The gap move must be added without any special processing as in
|
// The gap move must be added without any special processing as in
|
||||||
// the AddConstraintsGapMove.
|
// the AddConstraintsGapMove.
|
||||||
code()->AddGapMove(code()->last_instruction_index(cur_block) - 1, operand,
|
code()->AddGapMove(cur_block->last_instruction_index() - 1, operand,
|
||||||
phi_operand);
|
phi_operand);
|
||||||
|
|
||||||
Instruction* branch =
|
Instruction* branch = InstructionAt(cur_block->last_instruction_index());
|
||||||
InstructionAt(code()->last_instruction_index(cur_block));
|
|
||||||
DCHECK(!branch->HasPointerMap());
|
DCHECK(!branch->HasPointerMap());
|
||||||
USE(branch);
|
USE(branch);
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveRange* live_range = LiveRangeFor(phi_vreg);
|
LiveRange* live_range = LiveRangeFor(phi_vreg);
|
||||||
BlockStartInstruction* block_start =
|
BlockStartInstruction* block_start =
|
||||||
code()->GetBlockStart(block->GetRpoNumber());
|
code()->GetBlockStart(block->rpo_number());
|
||||||
block_start->GetOrCreateParallelMove(GapInstruction::START, code_zone())
|
block_start->GetOrCreateParallelMove(GapInstruction::START, code_zone())
|
||||||
->AddMove(phi_operand, live_range->GetSpillOperand(), code_zone());
|
->AddMove(phi_operand, live_range->GetSpillOperand(), code_zone());
|
||||||
live_range->SetSpillStartIndex(code()->first_instruction_index(block));
|
live_range->SetSpillStartIndex(block->first_instruction_index());
|
||||||
|
|
||||||
// We use the phi-ness of some nodes in some later heuristics.
|
// We use the phi-ness of some nodes in some later heuristics.
|
||||||
live_range->set_is_phi(true);
|
live_range->set_is_phi(true);
|
||||||
@ -1132,7 +1116,8 @@ bool RegisterAllocator::Allocate() {
|
|||||||
void RegisterAllocator::MeetRegisterConstraints() {
|
void RegisterAllocator::MeetRegisterConstraints() {
|
||||||
RegisterAllocatorPhase phase("L_Register constraints", this);
|
RegisterAllocatorPhase phase("L_Register constraints", this);
|
||||||
for (int i = 0; i < code()->BasicBlockCount(); ++i) {
|
for (int i = 0; i < code()->BasicBlockCount(); ++i) {
|
||||||
MeetRegisterConstraints(code()->BlockAt(i));
|
MeetRegisterConstraints(
|
||||||
|
code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(i)));
|
||||||
if (!AllocationOk()) return;
|
if (!AllocationOk()) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1143,17 +1128,18 @@ void RegisterAllocator::ResolvePhis() {
|
|||||||
|
|
||||||
// Process the blocks in reverse order.
|
// Process the blocks in reverse order.
|
||||||
for (int i = code()->BasicBlockCount() - 1; i >= 0; --i) {
|
for (int i = code()->BasicBlockCount() - 1; i >= 0; --i) {
|
||||||
ResolvePhis(code()->BlockAt(i));
|
ResolvePhis(code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RegisterAllocator::ResolveControlFlow(LiveRange* range, BasicBlock* block,
|
void RegisterAllocator::ResolveControlFlow(LiveRange* range,
|
||||||
BasicBlock* pred) {
|
const InstructionBlock* block,
|
||||||
LifetimePosition pred_end = LifetimePosition::FromInstructionIndex(
|
const InstructionBlock* pred) {
|
||||||
code()->last_instruction_index(pred));
|
LifetimePosition pred_end =
|
||||||
LifetimePosition cur_start = LifetimePosition::FromInstructionIndex(
|
LifetimePosition::FromInstructionIndex(pred->last_instruction_index());
|
||||||
code()->first_instruction_index(block));
|
LifetimePosition cur_start =
|
||||||
|
LifetimePosition::FromInstructionIndex(block->first_instruction_index());
|
||||||
LiveRange* pred_cover = NULL;
|
LiveRange* pred_cover = NULL;
|
||||||
LiveRange* cur_cover = NULL;
|
LiveRange* cur_cover = NULL;
|
||||||
LiveRange* cur_range = range;
|
LiveRange* cur_range = range;
|
||||||
@ -1178,13 +1164,12 @@ void RegisterAllocator::ResolveControlFlow(LiveRange* range, BasicBlock* block,
|
|||||||
if (!pred_op->Equals(cur_op)) {
|
if (!pred_op->Equals(cur_op)) {
|
||||||
GapInstruction* gap = NULL;
|
GapInstruction* gap = NULL;
|
||||||
if (block->PredecessorCount() == 1) {
|
if (block->PredecessorCount() == 1) {
|
||||||
gap = code()->GapAt(code()->first_instruction_index(block));
|
gap = code()->GapAt(block->first_instruction_index());
|
||||||
} else {
|
} else {
|
||||||
DCHECK(pred->SuccessorCount() == 1);
|
DCHECK(pred->SuccessorCount() == 1);
|
||||||
gap = GetLastGap(pred);
|
gap = GetLastGap(pred);
|
||||||
|
|
||||||
Instruction* branch =
|
Instruction* branch = InstructionAt(pred->last_instruction_index());
|
||||||
InstructionAt(code()->last_instruction_index(pred));
|
|
||||||
DCHECK(!branch->HasPointerMap());
|
DCHECK(!branch->HasPointerMap());
|
||||||
USE(branch);
|
USE(branch);
|
||||||
}
|
}
|
||||||
@ -1211,8 +1196,9 @@ ParallelMove* RegisterAllocator::GetConnectingParallelMove(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BasicBlock* RegisterAllocator::GetBlock(LifetimePosition pos) {
|
const InstructionBlock* RegisterAllocator::GetInstructionBlock(
|
||||||
return code()->GetBasicBlock(pos.InstructionIndex());
|
LifetimePosition pos) {
|
||||||
|
return code()->GetInstructionBlock(pos.InstructionIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1232,7 +1218,8 @@ void RegisterAllocator::ConnectRanges() {
|
|||||||
if (first_range->End().Value() == pos.Value()) {
|
if (first_range->End().Value() == pos.Value()) {
|
||||||
bool should_insert = true;
|
bool should_insert = true;
|
||||||
if (IsBlockBoundary(pos)) {
|
if (IsBlockBoundary(pos)) {
|
||||||
should_insert = CanEagerlyResolveControlFlow(GetBlock(pos));
|
should_insert =
|
||||||
|
CanEagerlyResolveControlFlow(GetInstructionBlock(pos));
|
||||||
}
|
}
|
||||||
if (should_insert) {
|
if (should_insert) {
|
||||||
ParallelMove* move = GetConnectingParallelMove(pos);
|
ParallelMove* move = GetConnectingParallelMove(pos);
|
||||||
@ -1252,24 +1239,25 @@ void RegisterAllocator::ConnectRanges() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool RegisterAllocator::CanEagerlyResolveControlFlow(BasicBlock* block) const {
|
bool RegisterAllocator::CanEagerlyResolveControlFlow(
|
||||||
|
const InstructionBlock* block) const {
|
||||||
if (block->PredecessorCount() != 1) return false;
|
if (block->PredecessorCount() != 1) return false;
|
||||||
return block->PredecessorAt(0)->rpo_number() == block->rpo_number() - 1;
|
return block->predecessors()[0].IsNext(block->rpo_number());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RegisterAllocator::ResolveControlFlow() {
|
void RegisterAllocator::ResolveControlFlow() {
|
||||||
RegisterAllocatorPhase phase("L_Resolve control flow", this);
|
RegisterAllocatorPhase phase("L_Resolve control flow", this);
|
||||||
for (int block_id = 1; block_id < code()->BasicBlockCount(); ++block_id) {
|
for (int block_id = 1; block_id < code()->BasicBlockCount(); ++block_id) {
|
||||||
BasicBlock* block = code()->BlockAt(block_id);
|
const InstructionBlock* block =
|
||||||
|
code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(block_id));
|
||||||
if (CanEagerlyResolveControlFlow(block)) continue;
|
if (CanEagerlyResolveControlFlow(block)) continue;
|
||||||
BitVector* live = live_in_sets_[block->rpo_number()];
|
BitVector* live = live_in_sets_[block->rpo_number().ToInt()];
|
||||||
BitVector::Iterator iterator(live);
|
BitVector::Iterator iterator(live);
|
||||||
while (!iterator.Done()) {
|
while (!iterator.Done()) {
|
||||||
int operand_index = iterator.Current();
|
int operand_index = iterator.Current();
|
||||||
for (BasicBlock::Predecessors::iterator i = block->predecessors_begin();
|
for (auto pred : block->predecessors()) {
|
||||||
i != block->predecessors_end(); ++i) {
|
const InstructionBlock* cur = code()->InstructionBlockAt(pred);
|
||||||
BasicBlock* cur = *i;
|
|
||||||
LiveRange* cur_range = LiveRangeFor(operand_index);
|
LiveRange* cur_range = LiveRangeFor(operand_index);
|
||||||
ResolveControlFlow(cur_range, block, cur);
|
ResolveControlFlow(cur_range, block, cur);
|
||||||
}
|
}
|
||||||
@ -1285,7 +1273,8 @@ void RegisterAllocator::BuildLiveRanges() {
|
|||||||
// Process the blocks in reverse order.
|
// Process the blocks in reverse order.
|
||||||
for (int block_id = code()->BasicBlockCount() - 1; block_id >= 0;
|
for (int block_id = code()->BasicBlockCount() - 1; block_id >= 0;
|
||||||
--block_id) {
|
--block_id) {
|
||||||
BasicBlock* block = code()->BlockAt(block_id);
|
const InstructionBlock* block =
|
||||||
|
code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(block_id));
|
||||||
BitVector* live = ComputeLiveOut(block);
|
BitVector* live = ComputeLiveOut(block);
|
||||||
// Initially consider all live_out values live for the entire block. We
|
// Initially consider all live_out values live for the entire block. We
|
||||||
// will shorten these intervals if necessary.
|
// will shorten these intervals if necessary.
|
||||||
@ -1295,19 +1284,16 @@ void RegisterAllocator::BuildLiveRanges() {
|
|||||||
// live values.
|
// live values.
|
||||||
ProcessInstructions(block, live);
|
ProcessInstructions(block, live);
|
||||||
// All phi output operands are killed by this block.
|
// All phi output operands are killed by this block.
|
||||||
for (BasicBlock::const_iterator i = block->begin(); i != block->end();
|
for (auto phi : block->phis()) {
|
||||||
++i) {
|
|
||||||
Node* phi = *i;
|
|
||||||
if (phi->opcode() != IrOpcode::kPhi) continue;
|
|
||||||
|
|
||||||
// The live range interval already ends at the first instruction of the
|
// The live range interval already ends at the first instruction of the
|
||||||
// block.
|
// block.
|
||||||
int phi_vreg = code()->GetVirtualRegister(phi);
|
int phi_vreg = phi->virtual_register();
|
||||||
live->Remove(phi_vreg);
|
live->Remove(phi_vreg);
|
||||||
|
|
||||||
InstructionOperand* hint = NULL;
|
InstructionOperand* hint = NULL;
|
||||||
InstructionOperand* phi_operand = NULL;
|
InstructionOperand* phi_operand = NULL;
|
||||||
GapInstruction* gap = GetLastGap(block->PredecessorAt(0));
|
GapInstruction* gap =
|
||||||
|
GetLastGap(code()->InstructionBlockAt(block->predecessors()[0]));
|
||||||
|
|
||||||
// TODO(titzer): no need to create the parallel move if it doesn't exit.
|
// TODO(titzer): no need to create the parallel move if it doesn't exit.
|
||||||
ParallelMove* move =
|
ParallelMove* move =
|
||||||
@ -1324,7 +1310,7 @@ void RegisterAllocator::BuildLiveRanges() {
|
|||||||
DCHECK(hint != NULL);
|
DCHECK(hint != NULL);
|
||||||
|
|
||||||
LifetimePosition block_start = LifetimePosition::FromInstructionIndex(
|
LifetimePosition block_start = LifetimePosition::FromInstructionIndex(
|
||||||
code()->first_instruction_index(block));
|
block->first_instruction_index());
|
||||||
Define(block_start, phi_operand, hint);
|
Define(block_start, phi_operand, hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1337,9 +1323,10 @@ void RegisterAllocator::BuildLiveRanges() {
|
|||||||
// for each value live on entry to the header.
|
// for each value live on entry to the header.
|
||||||
BitVector::Iterator iterator(live);
|
BitVector::Iterator iterator(live);
|
||||||
LifetimePosition start = LifetimePosition::FromInstructionIndex(
|
LifetimePosition start = LifetimePosition::FromInstructionIndex(
|
||||||
code()->first_instruction_index(block));
|
block->first_instruction_index());
|
||||||
int end_index =
|
int end_index = code()
|
||||||
code()->last_instruction_index(code()->BlockAt(block->loop_end()));
|
->InstructionBlockAt(block->loop_end())
|
||||||
|
->last_instruction_index();
|
||||||
LifetimePosition end =
|
LifetimePosition end =
|
||||||
LifetimePosition::FromInstructionIndex(end_index).NextInstruction();
|
LifetimePosition::FromInstructionIndex(end_index).NextInstruction();
|
||||||
while (!iterator.Done()) {
|
while (!iterator.Done()) {
|
||||||
@ -1350,7 +1337,8 @@ void RegisterAllocator::BuildLiveRanges() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert all values into the live in sets of all blocks in the loop.
|
// Insert all values into the live in sets of all blocks in the loop.
|
||||||
for (int i = block->rpo_number() + 1; i < block->loop_end(); ++i) {
|
for (int i = block->rpo_number().ToInt() + 1;
|
||||||
|
i < block->loop_end().ToInt(); ++i) {
|
||||||
live_in_sets_[i]->Union(*live);
|
live_in_sets_[i]->Union(*live);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1958,8 +1946,8 @@ void RegisterAllocator::AllocateBlockedReg(LiveRange* current) {
|
|||||||
|
|
||||||
LifetimePosition RegisterAllocator::FindOptimalSpillingPos(
|
LifetimePosition RegisterAllocator::FindOptimalSpillingPos(
|
||||||
LiveRange* range, LifetimePosition pos) {
|
LiveRange* range, LifetimePosition pos) {
|
||||||
BasicBlock* block = GetBlock(pos.InstructionStart());
|
const InstructionBlock* block = GetInstructionBlock(pos.InstructionStart());
|
||||||
BasicBlock* loop_header =
|
const InstructionBlock* loop_header =
|
||||||
block->IsLoopHeader() ? block : code()->GetContainingLoop(block);
|
block->IsLoopHeader() ? block : code()->GetContainingLoop(block);
|
||||||
|
|
||||||
if (loop_header == NULL) return pos;
|
if (loop_header == NULL) return pos;
|
||||||
@ -1971,7 +1959,7 @@ LifetimePosition RegisterAllocator::FindOptimalSpillingPos(
|
|||||||
// If possible try to move spilling position backwards to loop header.
|
// If possible try to move spilling position backwards to loop header.
|
||||||
// This will reduce number of memory moves on the back edge.
|
// This will reduce number of memory moves on the back edge.
|
||||||
LifetimePosition loop_start = LifetimePosition::FromInstructionIndex(
|
LifetimePosition loop_start = LifetimePosition::FromInstructionIndex(
|
||||||
code()->first_instruction_index(loop_header));
|
loop_header->first_instruction_index());
|
||||||
|
|
||||||
if (range->Covers(loop_start)) {
|
if (range->Covers(loop_start)) {
|
||||||
if (prev_use == NULL || prev_use->pos().Value() < loop_start.Value()) {
|
if (prev_use == NULL || prev_use->pos().Value() < loop_start.Value()) {
|
||||||
@ -2086,8 +2074,8 @@ LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start,
|
|||||||
// We have no choice
|
// We have no choice
|
||||||
if (start_instr == end_instr) return end;
|
if (start_instr == end_instr) return end;
|
||||||
|
|
||||||
BasicBlock* start_block = GetBlock(start);
|
const InstructionBlock* start_block = GetInstructionBlock(start);
|
||||||
BasicBlock* end_block = GetBlock(end);
|
const InstructionBlock* end_block = GetInstructionBlock(end);
|
||||||
|
|
||||||
if (end_block == start_block) {
|
if (end_block == start_block) {
|
||||||
// The interval is split in the same basic block. Split at the latest
|
// The interval is split in the same basic block. Split at the latest
|
||||||
@ -2095,12 +2083,12 @@ LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start,
|
|||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock* block = end_block;
|
const InstructionBlock* block = end_block;
|
||||||
// Find header of outermost loop.
|
// Find header of outermost loop.
|
||||||
// TODO(titzer): fix redundancy below.
|
// TODO(titzer): fix redundancy below.
|
||||||
while (code()->GetContainingLoop(block) != NULL &&
|
while (code()->GetContainingLoop(block) != NULL &&
|
||||||
code()->GetContainingLoop(block)->rpo_number() >
|
code()->GetContainingLoop(block)->rpo_number().ToInt() >
|
||||||
start_block->rpo_number()) {
|
start_block->rpo_number().ToInt()) {
|
||||||
block = code()->GetContainingLoop(block);
|
block = code()->GetContainingLoop(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2109,7 +2097,7 @@ LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start,
|
|||||||
if (block == end_block && !end_block->IsLoopHeader()) return end;
|
if (block == end_block && !end_block->IsLoopHeader()) return end;
|
||||||
|
|
||||||
return LifetimePosition::FromInstructionIndex(
|
return LifetimePosition::FromInstructionIndex(
|
||||||
code()->first_instruction_index(block));
|
block->first_instruction_index());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
#include "src/allocation.h"
|
#include "src/allocation.h"
|
||||||
#include "src/compiler/instruction.h"
|
#include "src/compiler/instruction.h"
|
||||||
#include "src/compiler/node.h"
|
|
||||||
#include "src/compiler/schedule.h"
|
|
||||||
#include "src/macro-assembler.h"
|
#include "src/macro-assembler.h"
|
||||||
#include "src/zone.h"
|
#include "src/zone.h"
|
||||||
|
|
||||||
@ -378,21 +376,22 @@ class RegisterAllocator BASE_EMBEDDED {
|
|||||||
void ResolveControlFlow();
|
void ResolveControlFlow();
|
||||||
void PopulatePointerMaps(); // TODO(titzer): rename to PopulateReferenceMaps.
|
void PopulatePointerMaps(); // TODO(titzer): rename to PopulateReferenceMaps.
|
||||||
void AllocateRegisters();
|
void AllocateRegisters();
|
||||||
bool CanEagerlyResolveControlFlow(BasicBlock* block) const;
|
bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const;
|
||||||
inline bool SafePointsAreInOrder() const;
|
inline bool SafePointsAreInOrder() const;
|
||||||
|
|
||||||
// Liveness analysis support.
|
// Liveness analysis support.
|
||||||
void InitializeLivenessAnalysis();
|
void InitializeLivenessAnalysis();
|
||||||
BitVector* ComputeLiveOut(BasicBlock* block);
|
BitVector* ComputeLiveOut(const InstructionBlock* block);
|
||||||
void AddInitialIntervals(BasicBlock* block, BitVector* live_out);
|
void AddInitialIntervals(const InstructionBlock* block, BitVector* live_out);
|
||||||
bool IsOutputRegisterOf(Instruction* instr, int index);
|
bool IsOutputRegisterOf(Instruction* instr, int index);
|
||||||
bool IsOutputDoubleRegisterOf(Instruction* instr, int index);
|
bool IsOutputDoubleRegisterOf(Instruction* instr, int index);
|
||||||
void ProcessInstructions(BasicBlock* block, BitVector* live);
|
void ProcessInstructions(const InstructionBlock* block, BitVector* live);
|
||||||
void MeetRegisterConstraints(BasicBlock* block);
|
void MeetRegisterConstraints(const InstructionBlock* block);
|
||||||
void MeetConstraintsBetween(Instruction* first, Instruction* second,
|
void MeetConstraintsBetween(Instruction* first, Instruction* second,
|
||||||
int gap_index);
|
int gap_index);
|
||||||
void MeetRegisterConstraintsForLastInstructionInBlock(BasicBlock* block);
|
void MeetRegisterConstraintsForLastInstructionInBlock(
|
||||||
void ResolvePhis(BasicBlock* block);
|
const InstructionBlock* block);
|
||||||
|
void ResolvePhis(const InstructionBlock* block);
|
||||||
|
|
||||||
// Helper methods for building intervals.
|
// Helper methods for building intervals.
|
||||||
InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos,
|
InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos,
|
||||||
@ -466,8 +465,8 @@ class RegisterAllocator BASE_EMBEDDED {
|
|||||||
bool IsBlockBoundary(LifetimePosition pos);
|
bool IsBlockBoundary(LifetimePosition pos);
|
||||||
|
|
||||||
// Helper methods for resolving control flow.
|
// Helper methods for resolving control flow.
|
||||||
void ResolveControlFlow(LiveRange* range, BasicBlock* block,
|
void ResolveControlFlow(LiveRange* range, const InstructionBlock* block,
|
||||||
BasicBlock* pred);
|
const InstructionBlock* pred);
|
||||||
|
|
||||||
inline void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
|
inline void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
|
||||||
|
|
||||||
@ -476,7 +475,7 @@ class RegisterAllocator BASE_EMBEDDED {
|
|||||||
ParallelMove* GetConnectingParallelMove(LifetimePosition pos);
|
ParallelMove* GetConnectingParallelMove(LifetimePosition pos);
|
||||||
|
|
||||||
// Return the block which contains give lifetime position.
|
// Return the block which contains give lifetime position.
|
||||||
BasicBlock* GetBlock(LifetimePosition pos);
|
const InstructionBlock* GetInstructionBlock(LifetimePosition pos);
|
||||||
|
|
||||||
// Helper methods for the fixed registers.
|
// Helper methods for the fixed registers.
|
||||||
int RegisterCount() const;
|
int RegisterCount() const;
|
||||||
@ -485,7 +484,7 @@ class RegisterAllocator BASE_EMBEDDED {
|
|||||||
LiveRange* FixedLiveRangeFor(int index);
|
LiveRange* FixedLiveRangeFor(int index);
|
||||||
LiveRange* FixedDoubleLiveRangeFor(int index);
|
LiveRange* FixedDoubleLiveRangeFor(int index);
|
||||||
LiveRange* LiveRangeFor(int index);
|
LiveRange* LiveRangeFor(int index);
|
||||||
GapInstruction* GetLastGap(BasicBlock* block);
|
GapInstruction* GetLastGap(const InstructionBlock* block);
|
||||||
|
|
||||||
const char* RegisterName(int allocation_index);
|
const char* RegisterName(int allocation_index);
|
||||||
|
|
||||||
|
@ -35,12 +35,6 @@ bool BasicBlock::LoopContains(BasicBlock* block) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BasicBlock* BasicBlock::ContainingLoop() {
|
|
||||||
if (IsLoopHeader()) return this;
|
|
||||||
return loop_header();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BasicBlock::AddSuccessor(BasicBlock* successor) {
|
void BasicBlock::AddSuccessor(BasicBlock* successor) {
|
||||||
successors_.push_back(successor);
|
successors_.push_back(successor);
|
||||||
}
|
}
|
||||||
@ -88,16 +82,6 @@ void BasicBlock::set_loop_header(BasicBlock* loop_header) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t BasicBlock::PredecessorIndexOf(BasicBlock* predecessor) {
|
|
||||||
size_t j = 0;
|
|
||||||
for (BasicBlock::Predecessors::iterator i = predecessors_.begin();
|
|
||||||
i != predecessors_.end(); ++i, ++j) {
|
|
||||||
if (*i == predecessor) break;
|
|
||||||
}
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const BasicBlock::Control& c) {
|
std::ostream& operator<<(std::ostream& os, const BasicBlock::Control& c) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case BasicBlock::kNone:
|
case BasicBlock::kNone:
|
||||||
|
@ -50,22 +50,33 @@ class BasicBlock FINAL : public ZoneObject {
|
|||||||
size_t index_;
|
size_t index_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const int kInvalidRpoNumber = -1;
|
||||||
class RpoNumber FINAL {
|
class RpoNumber FINAL {
|
||||||
public:
|
public:
|
||||||
int ToInt() const { return static_cast<int>(index_); }
|
int ToInt() const {
|
||||||
size_t ToSize() const { return index_; }
|
DCHECK(IsValid());
|
||||||
static RpoNumber FromInt(int index) {
|
return index_;
|
||||||
return RpoNumber(static_cast<size_t>(index));
|
|
||||||
}
|
}
|
||||||
static RpoNumber Invalid() { return RpoNumber(static_cast<size_t>(-1)); }
|
size_t ToSize() const {
|
||||||
|
DCHECK(IsValid());
|
||||||
|
return static_cast<size_t>(index_);
|
||||||
|
}
|
||||||
|
bool IsValid() const { return index_ != kInvalidRpoNumber; }
|
||||||
|
static RpoNumber FromInt(int index) { return RpoNumber(index); }
|
||||||
|
static RpoNumber Invalid() { return RpoNumber(kInvalidRpoNumber); }
|
||||||
|
|
||||||
bool IsNext(const RpoNumber other) const {
|
bool IsNext(const RpoNumber other) const {
|
||||||
|
DCHECK(IsValid());
|
||||||
return other.index_ == this->index_ + 1;
|
return other.index_ == this->index_ + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(RpoNumber other) const {
|
||||||
|
return this->index_ == other.index_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit RpoNumber(size_t index) : index_(index) {}
|
explicit RpoNumber(int32_t index) : index_(index) {}
|
||||||
size_t index_;
|
int32_t index_;
|
||||||
};
|
};
|
||||||
|
|
||||||
BasicBlock(Zone* zone, Id id);
|
BasicBlock(Zone* zone, Id id);
|
||||||
@ -76,14 +87,25 @@ class BasicBlock FINAL : public ZoneObject {
|
|||||||
typedef ZoneVector<BasicBlock*> Predecessors;
|
typedef ZoneVector<BasicBlock*> Predecessors;
|
||||||
Predecessors::iterator predecessors_begin() { return predecessors_.begin(); }
|
Predecessors::iterator predecessors_begin() { return predecessors_.begin(); }
|
||||||
Predecessors::iterator predecessors_end() { return predecessors_.end(); }
|
Predecessors::iterator predecessors_end() { return predecessors_.end(); }
|
||||||
|
Predecessors::const_iterator predecessors_begin() const {
|
||||||
|
return predecessors_.begin();
|
||||||
|
}
|
||||||
|
Predecessors::const_iterator predecessors_end() const {
|
||||||
|
return predecessors_.end();
|
||||||
|
}
|
||||||
size_t PredecessorCount() const { return predecessors_.size(); }
|
size_t PredecessorCount() const { return predecessors_.size(); }
|
||||||
BasicBlock* PredecessorAt(size_t index) { return predecessors_[index]; }
|
BasicBlock* PredecessorAt(size_t index) { return predecessors_[index]; }
|
||||||
size_t PredecessorIndexOf(BasicBlock* predecessor);
|
|
||||||
void AddPredecessor(BasicBlock* predecessor);
|
void AddPredecessor(BasicBlock* predecessor);
|
||||||
|
|
||||||
typedef ZoneVector<BasicBlock*> Successors;
|
typedef ZoneVector<BasicBlock*> Successors;
|
||||||
Successors::iterator successors_begin() { return successors_.begin(); }
|
Successors::iterator successors_begin() { return successors_.begin(); }
|
||||||
Successors::iterator successors_end() { return successors_.end(); }
|
Successors::iterator successors_end() { return successors_.end(); }
|
||||||
|
Successors::const_iterator successors_begin() const {
|
||||||
|
return successors_.begin();
|
||||||
|
}
|
||||||
|
Successors::const_iterator successors_end() const {
|
||||||
|
return successors_.end();
|
||||||
|
}
|
||||||
size_t SuccessorCount() const { return successors_.size(); }
|
size_t SuccessorCount() const { return successors_.size(); }
|
||||||
BasicBlock* SuccessorAt(size_t index) { return successors_[index]; }
|
BasicBlock* SuccessorAt(size_t index) { return successors_[index]; }
|
||||||
void AddSuccessor(BasicBlock* successor);
|
void AddSuccessor(BasicBlock* successor);
|
||||||
@ -137,7 +159,6 @@ class BasicBlock FINAL : public ZoneObject {
|
|||||||
// Loop membership helpers.
|
// Loop membership helpers.
|
||||||
inline bool IsLoopHeader() const { return loop_end_ >= 0; }
|
inline bool IsLoopHeader() const { return loop_end_ >= 0; }
|
||||||
bool LoopContains(BasicBlock* block) const;
|
bool LoopContains(BasicBlock* block) const;
|
||||||
BasicBlock* ContainingLoop();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32_t rpo_number_; // special RPO number of the block.
|
int32_t rpo_number_; // special RPO number of the block.
|
||||||
|
Loading…
Reference in New Issue
Block a user