[turbofan] Split ConstraintBuilder off of LiveRangeBuilder.

Plus some driveby cleanup.

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

Cr-Commit-Position: refs/heads/master@{#27961}
This commit is contained in:
dcarney 2015-04-21 05:01:45 -07:00 committed by Commit bot
parent 636cb4f365
commit 6a7cb78cbd
3 changed files with 293 additions and 303 deletions

View File

@ -716,7 +716,7 @@ struct MeetRegisterConstraintsPhase {
static const char* phase_name() { return "meet register constraints"; }
void Run(PipelineData* data, Zone* temp_zone) {
LiveRangeBuilder builder(data->register_allocation_data());
ConstraintBuilder builder(data->register_allocation_data());
builder.MeetRegisterConstraints();
}
};
@ -726,7 +726,7 @@ struct ResolvePhisPhase {
static const char* phase_name() { return "resolve phis"; }
void Run(PipelineData* data, Zone* temp_zone) {
LiveRangeBuilder builder(data->register_allocation_data());
ConstraintBuilder builder(data->register_allocation_data());
builder.ResolvePhis();
}
};

View File

@ -69,6 +69,11 @@ bool IsBlockBoundary(const InstructionSequence* code, LifetimePosition pos) {
}
Instruction* GetLastInstruction(InstructionSequence* code,
const InstructionBlock* block) {
return code->InstructionAt(block->last_instruction_index());
}
} // namespace
@ -833,6 +838,236 @@ void RegisterAllocationData::SetLiveRangeAssignedRegister(LiveRange* range,
}
ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data)
: data_(data) {}
InstructionOperand* ConstraintBuilder::AllocateFixed(
UnallocatedOperand* operand, int pos, bool is_tagged) {
TRACE("Allocating fixed reg for op %d\n", operand->virtual_register());
DCHECK(operand->HasFixedPolicy());
InstructionOperand allocated;
if (operand->HasFixedSlotPolicy()) {
allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT,
operand->fixed_slot_index());
} else if (operand->HasFixedRegisterPolicy()) {
allocated = AllocatedOperand(AllocatedOperand::REGISTER,
operand->fixed_register_index());
} else if (operand->HasFixedDoubleRegisterPolicy()) {
allocated = AllocatedOperand(AllocatedOperand::DOUBLE_REGISTER,
operand->fixed_register_index());
} else {
UNREACHABLE();
}
InstructionOperand::ReplaceWith(operand, &allocated);
if (is_tagged) {
TRACE("Fixed reg is tagged at %d\n", pos);
auto instr = InstructionAt(pos);
if (instr->HasReferenceMap()) {
instr->reference_map()->RecordReference(*operand);
}
}
return operand;
}
void ConstraintBuilder::MeetRegisterConstraints() {
for (auto block : code()->instruction_blocks()) {
MeetRegisterConstraints(block);
}
}
void ConstraintBuilder::MeetRegisterConstraints(const InstructionBlock* block) {
int start = block->first_instruction_index();
int end = block->last_instruction_index();
DCHECK_NE(-1, start);
for (int i = start; i <= end; ++i) {
MeetConstraintsBefore(i);
if (i != end) MeetConstraintsAfter(i);
}
// Meet register constraints for the instruction in the end.
MeetRegisterConstraintsForLastInstructionInBlock(block);
}
void ConstraintBuilder::MeetRegisterConstraintsForLastInstructionInBlock(
const InstructionBlock* block) {
int end = block->last_instruction_index();
auto last_instruction = InstructionAt(end);
for (size_t i = 0; i < last_instruction->OutputCount(); i++) {
auto output_operand = last_instruction->OutputAt(i);
DCHECK(!output_operand->IsConstant());
auto output = UnallocatedOperand::cast(output_operand);
int output_vreg = output->virtual_register();
auto range = LiveRangeFor(output_vreg);
bool assigned = false;
if (output->HasFixedPolicy()) {
AllocateFixed(output, -1, false);
// This value is produced on the stack, we never need to spill it.
if (output->IsStackSlot()) {
DCHECK(StackSlotOperand::cast(output)->index() <
data()->frame()->GetSpillSlotCount());
range->SetSpillOperand(StackSlotOperand::cast(output));
range->SetSpillStartIndex(end);
assigned = true;
}
for (auto succ : block->successors()) {
const InstructionBlock* successor = code()->InstructionBlockAt(succ);
DCHECK(successor->PredecessorCount() == 1);
int gap_index = successor->first_instruction_index();
// Create an unconstrained operand for the same virtual register
// and insert a gap move from the fixed output to the operand.
UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg);
data()->AddGapMove(gap_index, Instruction::START, *output, output_copy);
}
}
if (!assigned) {
for (auto succ : block->successors()) {
const InstructionBlock* successor = code()->InstructionBlockAt(succ);
DCHECK(successor->PredecessorCount() == 1);
int gap_index = successor->first_instruction_index();
range->SpillAtDefinition(allocation_zone(), gap_index, output);
range->SetSpillStartIndex(gap_index);
}
}
}
}
void ConstraintBuilder::MeetConstraintsAfter(int instr_index) {
auto first = InstructionAt(instr_index);
// Handle fixed temporaries.
for (size_t i = 0; i < first->TempCount(); i++) {
auto temp = UnallocatedOperand::cast(first->TempAt(i));
if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false);
}
// Handle constant/fixed output operands.
for (size_t i = 0; i < first->OutputCount(); i++) {
InstructionOperand* output = first->OutputAt(i);
if (output->IsConstant()) {
int output_vreg = ConstantOperand::cast(output)->virtual_register();
auto range = LiveRangeFor(output_vreg);
range->SetSpillStartIndex(instr_index + 1);
range->SetSpillOperand(output);
continue;
}
auto first_output = UnallocatedOperand::cast(output);
auto range = LiveRangeFor(first_output->virtual_register());
bool assigned = false;
if (first_output->HasFixedPolicy()) {
int output_vreg = first_output->virtual_register();
UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg);
bool is_tagged = IsReference(output_vreg);
AllocateFixed(first_output, instr_index, is_tagged);
// This value is produced on the stack, we never need to spill it.
if (first_output->IsStackSlot()) {
DCHECK(StackSlotOperand::cast(first_output)->index() <
data()->frame()->GetSpillSlotCount());
range->SetSpillOperand(StackSlotOperand::cast(first_output));
range->SetSpillStartIndex(instr_index + 1);
assigned = true;
}
data()->AddGapMove(instr_index + 1, Instruction::START, *first_output,
output_copy);
}
// Make sure we add a gap move for spilling (if we have not done
// so already).
if (!assigned) {
range->SpillAtDefinition(allocation_zone(), instr_index + 1,
first_output);
range->SetSpillStartIndex(instr_index + 1);
}
}
}
void ConstraintBuilder::MeetConstraintsBefore(int instr_index) {
auto second = InstructionAt(instr_index);
// Handle fixed input operands of second instruction.
for (size_t i = 0; i < second->InputCount(); i++) {
auto input = second->InputAt(i);
if (input->IsImmediate()) continue; // Ignore immediates.
auto cur_input = UnallocatedOperand::cast(input);
if (cur_input->HasFixedPolicy()) {
int input_vreg = cur_input->virtual_register();
UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
bool is_tagged = IsReference(input_vreg);
AllocateFixed(cur_input, instr_index, is_tagged);
data()->AddGapMove(instr_index, Instruction::END, input_copy, *cur_input);
}
}
// Handle "output same as input" for second instruction.
for (size_t i = 0; i < second->OutputCount(); i++) {
auto output = second->OutputAt(i);
if (!output->IsUnallocated()) continue;
auto second_output = UnallocatedOperand::cast(output);
if (!second_output->HasSameAsInputPolicy()) continue;
DCHECK(i == 0); // Only valid for first output.
UnallocatedOperand* cur_input =
UnallocatedOperand::cast(second->InputAt(0));
int output_vreg = second_output->virtual_register();
int input_vreg = cur_input->virtual_register();
UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
cur_input->set_virtual_register(second_output->virtual_register());
data()->AddGapMove(instr_index, Instruction::END, input_copy, *cur_input);
if (IsReference(input_vreg) && !IsReference(output_vreg)) {
if (second->HasReferenceMap()) {
second->reference_map()->RecordReference(input_copy);
}
} else if (!IsReference(input_vreg) && IsReference(output_vreg)) {
// The input is assumed to immediately have a tagged representation,
// before the pointer map can be used. I.e. the pointer map at the
// instruction will include the output operand (whose value at the
// beginning of the instruction is equal to the input operand). If
// this is not desired, then the pointer map at this instruction needs
// to be adjusted manually.
}
}
}
void ConstraintBuilder::ResolvePhis() {
// Process the blocks in reverse order.
for (InstructionBlock* block : base::Reversed(code()->instruction_blocks())) {
ResolvePhis(block);
}
}
void ConstraintBuilder::ResolvePhis(const InstructionBlock* block) {
for (auto phi : block->phis()) {
int phi_vreg = phi->virtual_register();
auto map_value = new (allocation_zone())
RegisterAllocationData::PhiMapValue(phi, block, allocation_zone());
auto res = data()->phi_map().insert(std::make_pair(phi_vreg, map_value));
DCHECK(res.second);
USE(res);
auto& output = phi->output();
for (size_t i = 0; i < phi->operands().size(); ++i) {
InstructionBlock* cur_block =
code()->InstructionBlockAt(block->predecessors()[i]);
UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]);
auto move = data()->AddGapMove(cur_block->last_instruction_index(),
Instruction::END, input, output);
map_value->incoming_moves.push_back(move);
DCHECK(!InstructionAt(cur_block->last_instruction_index())
->HasReferenceMap());
}
auto live_range = LiveRangeFor(phi_vreg);
int gap_index = block->first_instruction_index();
live_range->SpillAtDefinition(allocation_zone(), gap_index, &output);
live_range->SetSpillStartIndex(gap_index);
// We use the phi-ness of some nodes in some later heuristics.
live_range->set_is_phi(true);
live_range->set_is_non_loop_phi(!block->IsLoopHeader());
}
}
LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data)
: data_(data) {}
@ -881,55 +1116,20 @@ void LiveRangeBuilder::AddInitialIntervals(const InstructionBlock* block,
}
Instruction* LiveRangeBuilder::GetLastInstruction(
const InstructionBlock* block) {
return code()->InstructionAt(block->last_instruction_index());
}
int LiveRangeBuilder::FixedDoubleLiveRangeID(int index) {
return -index - 1 - config()->num_general_registers();
}
InstructionOperand* LiveRangeBuilder::AllocateFixed(UnallocatedOperand* operand,
int pos, bool is_tagged) {
TRACE("Allocating fixed reg for op %d\n", operand->virtual_register());
DCHECK(operand->HasFixedPolicy());
InstructionOperand allocated;
if (operand->HasFixedSlotPolicy()) {
allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT,
operand->fixed_slot_index());
} else if (operand->HasFixedRegisterPolicy()) {
allocated = AllocatedOperand(AllocatedOperand::REGISTER,
operand->fixed_register_index());
} else if (operand->HasFixedDoubleRegisterPolicy()) {
allocated = AllocatedOperand(AllocatedOperand::DOUBLE_REGISTER,
operand->fixed_register_index());
} else {
UNREACHABLE();
}
InstructionOperand::ReplaceWith(operand, &allocated);
if (is_tagged) {
TRACE("Fixed reg is tagged at %d\n", pos);
auto instr = InstructionAt(pos);
if (instr->HasReferenceMap()) {
instr->reference_map()->RecordReference(*operand);
}
}
return operand;
}
LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) {
DCHECK(index < config()->num_general_registers());
auto result = fixed_live_ranges()[index];
auto result = data()->fixed_live_ranges()[index];
if (result == nullptr) {
result = data()->NewLiveRange(FixedLiveRangeID(index));
DCHECK(result->IsFixed());
result->set_kind(GENERAL_REGISTERS);
data()->SetLiveRangeAssignedRegister(result, index);
fixed_live_ranges()[index] = result;
data()->fixed_live_ranges()[index] = result;
}
return result;
}
@ -937,13 +1137,13 @@ LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) {
LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) {
DCHECK(index < config()->num_aliased_double_registers());
auto result = fixed_double_live_ranges()[index];
auto result = data()->fixed_double_live_ranges()[index];
if (result == nullptr) {
result = data()->NewLiveRange(FixedDoubleLiveRangeID(index));
DCHECK(result->IsFixed());
result->set_kind(DOUBLE_REGISTERS);
data()->SetLiveRangeAssignedRegister(result, index);
fixed_double_live_ranges()[index] = result;
data()->fixed_double_live_ranges()[index] = result;
}
return result;
}
@ -1001,158 +1201,6 @@ void LiveRangeBuilder::Use(LifetimePosition block_start,
}
void LiveRangeBuilder::MeetRegisterConstraints(const InstructionBlock* block) {
int start = block->first_instruction_index();
int end = block->last_instruction_index();
DCHECK_NE(-1, start);
for (int i = start; i <= end; ++i) {
MeetConstraintsBefore(i);
if (i != end) MeetConstraintsAfter(i);
}
// Meet register constraints for the instruction in the end.
MeetRegisterConstraintsForLastInstructionInBlock(block);
}
void LiveRangeBuilder::MeetRegisterConstraintsForLastInstructionInBlock(
const InstructionBlock* block) {
int end = block->last_instruction_index();
auto last_instruction = InstructionAt(end);
for (size_t i = 0; i < last_instruction->OutputCount(); i++) {
auto output_operand = last_instruction->OutputAt(i);
DCHECK(!output_operand->IsConstant());
auto output = UnallocatedOperand::cast(output_operand);
int output_vreg = output->virtual_register();
auto range = LiveRangeFor(output_vreg);
bool assigned = false;
if (output->HasFixedPolicy()) {
AllocateFixed(output, -1, false);
// This value is produced on the stack, we never need to spill it.
if (output->IsStackSlot()) {
DCHECK(StackSlotOperand::cast(output)->index() <
data()->frame()->GetSpillSlotCount());
range->SetSpillOperand(StackSlotOperand::cast(output));
range->SetSpillStartIndex(end);
assigned = true;
}
for (auto succ : block->successors()) {
const InstructionBlock* successor = code()->InstructionBlockAt(succ);
DCHECK(successor->PredecessorCount() == 1);
int gap_index = successor->first_instruction_index();
// Create an unconstrained operand for the same virtual register
// and insert a gap move from the fixed output to the operand.
UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg);
data()->AddGapMove(gap_index, Instruction::START, *output, output_copy);
}
}
if (!assigned) {
for (auto succ : block->successors()) {
const InstructionBlock* successor = code()->InstructionBlockAt(succ);
DCHECK(successor->PredecessorCount() == 1);
int gap_index = successor->first_instruction_index();
range->SpillAtDefinition(allocation_zone(), gap_index, output);
range->SetSpillStartIndex(gap_index);
}
}
}
}
void LiveRangeBuilder::MeetConstraintsAfter(int instr_index) {
auto first = InstructionAt(instr_index);
// Handle fixed temporaries.
for (size_t i = 0; i < first->TempCount(); i++) {
auto temp = UnallocatedOperand::cast(first->TempAt(i));
if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false);
}
// Handle constant/fixed output operands.
for (size_t i = 0; i < first->OutputCount(); i++) {
InstructionOperand* output = first->OutputAt(i);
if (output->IsConstant()) {
int output_vreg = ConstantOperand::cast(output)->virtual_register();
auto range = LiveRangeFor(output_vreg);
range->SetSpillStartIndex(instr_index + 1);
range->SetSpillOperand(output);
continue;
}
auto first_output = UnallocatedOperand::cast(output);
auto range = LiveRangeFor(first_output->virtual_register());
bool assigned = false;
if (first_output->HasFixedPolicy()) {
int output_vreg = first_output->virtual_register();
UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg);
bool is_tagged = IsReference(output_vreg);
AllocateFixed(first_output, instr_index, is_tagged);
// This value is produced on the stack, we never need to spill it.
if (first_output->IsStackSlot()) {
DCHECK(StackSlotOperand::cast(first_output)->index() <
data()->frame()->GetSpillSlotCount());
range->SetSpillOperand(StackSlotOperand::cast(first_output));
range->SetSpillStartIndex(instr_index + 1);
assigned = true;
}
data()->AddGapMove(instr_index + 1, Instruction::START, *first_output,
output_copy);
}
// Make sure we add a gap move for spilling (if we have not done
// so already).
if (!assigned) {
range->SpillAtDefinition(allocation_zone(), instr_index + 1,
first_output);
range->SetSpillStartIndex(instr_index + 1);
}
}
}
void LiveRangeBuilder::MeetConstraintsBefore(int instr_index) {
auto second = InstructionAt(instr_index);
// Handle fixed input operands of second instruction.
for (size_t i = 0; i < second->InputCount(); i++) {
auto input = second->InputAt(i);
if (input->IsImmediate()) continue; // Ignore immediates.
auto cur_input = UnallocatedOperand::cast(input);
if (cur_input->HasFixedPolicy()) {
int input_vreg = cur_input->virtual_register();
UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
bool is_tagged = IsReference(input_vreg);
AllocateFixed(cur_input, instr_index, is_tagged);
data()->AddGapMove(instr_index, Instruction::END, input_copy, *cur_input);
}
}
// Handle "output same as input" for second instruction.
for (size_t i = 0; i < second->OutputCount(); i++) {
auto output = second->OutputAt(i);
if (!output->IsUnallocated()) continue;
auto second_output = UnallocatedOperand::cast(output);
if (!second_output->HasSameAsInputPolicy()) continue;
DCHECK(i == 0); // Only valid for first output.
UnallocatedOperand* cur_input =
UnallocatedOperand::cast(second->InputAt(0));
int output_vreg = second_output->virtual_register();
int input_vreg = cur_input->virtual_register();
UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
cur_input->set_virtual_register(second_output->virtual_register());
data()->AddGapMove(instr_index, Instruction::END, input_copy, *cur_input);
if (IsReference(input_vreg) && !IsReference(output_vreg)) {
if (second->HasReferenceMap()) {
second->reference_map()->RecordReference(input_copy);
}
} else if (!IsReference(input_vreg) && IsReference(output_vreg)) {
// The input is assumed to immediately have a tagged representation,
// before the pointer map can be used. I.e. the pointer map at the
// instruction will include the output operand (whose value at the
// beginning of the instruction is equal to the input operand). If
// this is not desired, then the pointer map at this instruction needs
// to be adjusted manually.
}
}
}
bool LiveRangeBuilder::IsOutputRegisterOf(Instruction* instr, int index) {
for (size_t i = 0; i < instr->OutputCount(); i++) {
auto output = instr->OutputAt(i);
@ -1184,7 +1232,7 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block,
index--) {
auto curr_position =
LifetimePosition::InstructionFromInstructionIndex(index);
auto instr = InstructionAt(index);
auto instr = code()->InstructionAt(index);
DCHECK(instr != nullptr);
DCHECK(curr_position.IsInstructionPosition());
// Process output, inputs, and temps of this instruction.
@ -1308,51 +1356,6 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block,
}
void LiveRangeBuilder::ResolvePhis(const InstructionBlock* block) {
for (auto phi : block->phis()) {
int phi_vreg = phi->virtual_register();
auto map_value = new (allocation_zone())
RegisterAllocationData::PhiMapValue(phi, block, allocation_zone());
auto res = phi_map().insert(std::make_pair(phi_vreg, map_value));
DCHECK(res.second);
USE(res);
auto& output = phi->output();
for (size_t i = 0; i < phi->operands().size(); ++i) {
InstructionBlock* cur_block =
code()->InstructionBlockAt(block->predecessors()[i]);
UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]);
auto move = data()->AddGapMove(cur_block->last_instruction_index(),
Instruction::END, input, output);
map_value->incoming_moves.push_back(move);
DCHECK(!InstructionAt(cur_block->last_instruction_index())
->HasReferenceMap());
}
auto live_range = LiveRangeFor(phi_vreg);
int gap_index = block->first_instruction_index();
live_range->SpillAtDefinition(allocation_zone(), gap_index, &output);
live_range->SetSpillStartIndex(gap_index);
// We use the phi-ness of some nodes in some later heuristics.
live_range->set_is_phi(true);
live_range->set_is_non_loop_phi(!block->IsLoopHeader());
}
}
void LiveRangeBuilder::MeetRegisterConstraints() {
for (auto block : code()->instruction_blocks()) {
MeetRegisterConstraints(block);
}
}
void LiveRangeBuilder::ResolvePhis() {
// Process the blocks in reverse order.
for (InstructionBlock* block : base::Reversed(code()->instruction_blocks())) {
ResolvePhis(block);
}
}
void LiveRangeBuilder::BuildLiveRanges() {
// Process the blocks in reverse order.
for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0;
@ -1374,7 +1377,7 @@ void LiveRangeBuilder::BuildLiveRanges() {
live->Remove(phi_vreg);
InstructionOperand* hint = nullptr;
auto instr = GetLastInstruction(
code()->InstructionBlockAt(block->predecessors()[0]));
code(), code()->InstructionBlockAt(block->predecessors()[0]));
for (auto move : *instr->GetParallelMove(Instruction::END)) {
auto& to = move->destination();
if (to.IsUnallocated() &&
@ -1415,7 +1418,7 @@ void LiveRangeBuilder::BuildLiveRanges() {
}
}
for (auto range : live_ranges()) {
for (auto range : data()->live_ranges()) {
if (range == nullptr) continue;
range->set_kind(RequiredRegisterKind(range->id()));
// Give slots to all ranges with a non fixed slot use.
@ -1474,14 +1477,16 @@ LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data,
// TryAllocateFreeReg and AllocateBlockedReg assume this
// when allocating local arrays.
DCHECK(RegisterConfiguration::kMaxDoubleRegisters >=
config()->num_general_registers());
this->data()->config()->num_general_registers());
}
void LinearScanAllocator::AllocateRegisters() {
DCHECK(unhandled_live_ranges().empty());
DCHECK(active_live_ranges().empty());
DCHECK(inactive_live_ranges().empty());
for (auto range : live_ranges()) {
for (auto range : data()->live_ranges()) {
if (range == nullptr) continue;
if (range->Kind() == mode_) {
AddToUnhandledUnsorted(range);
@ -1490,9 +1495,6 @@ void LinearScanAllocator::AllocateRegisters() {
SortUnhandled();
DCHECK(UnhandledIsSorted());
DCHECK(active_live_ranges().empty());
DCHECK(inactive_live_ranges().empty());
auto& fixed_ranges = GetFixedRegisters(data(), mode_);
for (auto current : fixed_ranges) {
if (current != nullptr) {
@ -1565,17 +1567,14 @@ void LinearScanAllocator::AllocateRegisters() {
AddToActive(current);
}
}
active_live_ranges().clear();
inactive_live_ranges().clear();
}
const char* LinearScanAllocator::RegisterName(int allocation_index) const {
if (mode_ == GENERAL_REGISTERS) {
return config()->general_register_name(allocation_index);
return data()->config()->general_register_name(allocation_index);
} else {
return config()->double_register_name(allocation_index);
return data()->config()->double_register_name(allocation_index);
}
}
@ -1910,8 +1909,8 @@ bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) {
if (range->IsChild() || !range->is_phi()) return false;
DCHECK(!range->HasSpillOperand());
auto lookup = phi_map().find(range->id());
DCHECK(lookup != phi_map().end());
auto lookup = data()->phi_map().find(range->id());
DCHECK(lookup != data()->phi_map().end());
auto phi = lookup->second->phi;
auto block = lookup->second->block;
// Count the number of spilled operands.
@ -2190,7 +2189,7 @@ void ReferenceMapPopulator::PopulateReferenceMaps() {
// Iterate over the first parts of multi-part live ranges.
if (range->IsChild()) continue;
// Skip non-reference values.
if (!IsReference(range->id())) continue;
if (!data()->IsReference(range->id())) continue;
// Skip empty live ranges.
if (range->IsEmpty()) continue;
@ -2444,7 +2443,7 @@ void LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block,
position = Instruction::START;
} else {
DCHECK(pred->SuccessorCount() == 1);
DCHECK(!data()
DCHECK(!code()
->InstructionAt(pred->last_instruction_index())
->HasReferenceMap());
gap_index = pred->last_instruction_index();

View File

@ -444,10 +444,8 @@ class RegisterAllocationData final : public ZoneObject {
const ZoneVector<LiveRange*>& fixed_double_live_ranges() const {
return fixed_double_live_ranges_;
}
const ZoneVector<BitVector*>& live_in_sets() const { return live_in_sets_; }
ZoneVector<BitVector*>& live_in_sets() { return live_in_sets_; }
ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; }
const ZoneVector<SpillRange*>& spill_ranges() const { return spill_ranges_; }
InstructionSequence* code() const { return code_; }
// This zone is for datastructures only needed during register allocation
// phases.
@ -463,9 +461,6 @@ class RegisterAllocationData final : public ZoneObject {
void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
LiveRange* LiveRangeFor(int index);
Instruction* InstructionAt(int index) const {
return code()->InstructionAt(index);
}
void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment);
SpillRange* AssignSpillRangeToLiveRange(LiveRange* range);
@ -502,9 +497,9 @@ class RegisterAllocationData final : public ZoneObject {
};
class LiveRangeBuilder final : public ZoneObject {
class ConstraintBuilder final : public ZoneObject {
public:
explicit LiveRangeBuilder(RegisterAllocationData* data);
explicit ConstraintBuilder(RegisterAllocationData* data);
// Phase 1 : insert moves to account for fixed register operands.
void MeetRegisterConstraints();
@ -513,6 +508,36 @@ class LiveRangeBuilder final : public ZoneObject {
// of blocks containing phis.
void ResolvePhis();
private:
RegisterAllocationData* data() const { return data_; }
InstructionSequence* code() const { return data()->code(); }
Zone* allocation_zone() const { return data()->allocation_zone(); }
Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
bool IsReference(int virtual_register) const {
return data()->IsReference(virtual_register);
}
LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos,
bool is_tagged);
void MeetRegisterConstraints(const InstructionBlock* block);
void MeetConstraintsBefore(int index);
void MeetConstraintsAfter(int index);
void MeetRegisterConstraintsForLastInstructionInBlock(
const InstructionBlock* block);
void ResolvePhis(const InstructionBlock* block);
RegisterAllocationData* const data_;
DISALLOW_COPY_AND_ASSIGN(ConstraintBuilder);
};
class LiveRangeBuilder final : public ZoneObject {
public:
explicit LiveRangeBuilder(RegisterAllocationData* data);
// Phase 3: compute liveness of all virtual register.
void BuildLiveRanges();
@ -525,20 +550,8 @@ class LiveRangeBuilder final : public ZoneObject {
ZoneVector<BitVector*>& live_in_sets() const {
return data()->live_in_sets();
}
ZoneVector<LiveRange*>& live_ranges() { return data()->live_ranges(); }
ZoneVector<LiveRange*>& fixed_live_ranges() {
return data()->fixed_live_ranges();
}
ZoneVector<LiveRange*>& fixed_double_live_ranges() {
return data()->fixed_double_live_ranges();
}
ZoneVector<SpillRange*>& spill_ranges() { return data()->spill_ranges(); }
RegisterAllocationData::PhiMap& phi_map() { return data()->phi_map(); }
Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
bool IsReference(int virtual_register) const {
return data()->IsReference(virtual_register);
}
LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
void Verify() const;
@ -548,26 +561,16 @@ class LiveRangeBuilder final : public ZoneObject {
bool IsOutputRegisterOf(Instruction* instr, int index);
bool IsOutputDoubleRegisterOf(Instruction* instr, int index);
void ProcessInstructions(const InstructionBlock* block, BitVector* live);
void MeetRegisterConstraints(const InstructionBlock* block);
void MeetConstraintsBefore(int index);
void MeetConstraintsAfter(int index);
void MeetRegisterConstraintsForLastInstructionInBlock(
const InstructionBlock* block);
void ResolvePhis(const InstructionBlock* block);
LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
static int FixedLiveRangeID(int index) { return -index - 1; }
int FixedDoubleLiveRangeID(int index);
LiveRange* FixedLiveRangeFor(int index);
LiveRange* FixedDoubleLiveRangeFor(int index);
Instruction* GetLastInstruction(const InstructionBlock* block);
// Returns the register kind required by the given virtual register.
RegisterKind RequiredRegisterKind(int virtual_register) const;
// Helper methods for building intervals.
InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos,
bool is_tagged);
LiveRange* LiveRangeFor(InstructionOperand* operand);
void Define(LifetimePosition position, InstructionOperand* operand,
InstructionOperand* hint);
@ -592,12 +595,9 @@ class LinearScanAllocator final : public ZoneObject {
RegisterAllocationData* data() const { return data_; }
InstructionSequence* code() const { return data()->code(); }
Zone* allocation_zone() const { return data()->allocation_zone(); }
Zone* code_zone() const { return code()->zone(); }
const RegisterConfiguration* config() const { return data()->config(); }
int num_registers() const { return num_registers_; }
const char* RegisterName(int allocation_index) const;
ZoneVector<LiveRange*>& live_ranges() { return data()->live_ranges(); }
ZoneVector<LiveRange*>& unhandled_live_ranges() {
return unhandled_live_ranges_;
}
@ -605,13 +605,7 @@ class LinearScanAllocator final : public ZoneObject {
ZoneVector<LiveRange*>& inactive_live_ranges() {
return inactive_live_ranges_;
}
ZoneVector<SpillRange*>& spill_ranges() { return data()->spill_ranges(); }
RegisterAllocationData::PhiMap& phi_map() { return data()->phi_map(); }
Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
bool IsReference(int virtual_register) const {
return data()->IsReference(virtual_register);
}
LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
// Helper methods for updating the life range lists.
@ -715,14 +709,10 @@ class ReferenceMapPopulator final : public ZoneObject {
void PopulateReferenceMaps();
private:
bool SafePointsAreInOrder() const;
bool IsReference(int virtual_register) const {
return data()->IsReference(virtual_register);
}
RegisterAllocationData* data() const { return data_; }
bool SafePointsAreInOrder() const;
RegisterAllocationData* const data_;
DISALLOW_COPY_AND_ASSIGN(ReferenceMapPopulator);
@ -740,14 +730,15 @@ class LiveRangeConnector final : public ZoneObject {
void ResolveControlFlow(Zone* local_zone);
private:
RegisterAllocationData* data() const { return data_; }
InstructionSequence* code() const { return data()->code(); }
Zone* code_zone() const { return code()->zone(); }
bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const;
void ResolveControlFlow(const InstructionBlock* block,
const InstructionOperand& cur_op,
const InstructionBlock* pred,
const InstructionOperand& pred_op);
InstructionSequence* code() const { return data()->code(); }
Zone* code_zone() const { return code()->zone(); }
RegisterAllocationData* data() const { return data_; }
RegisterAllocationData* const data_;