Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(684)

Unified Diff: runtime/vm/flow_graph_allocator.cc

Issue 215363004: Support for multiple register values (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/flow_graph_allocator.h ('k') | runtime/vm/flow_graph_optimizer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/flow_graph_allocator.cc
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index 86c54fd40fe925973979e75e189f5a6bc768d90d..f17badf3b0e7fb7e43eabb983c87fb88eeb0ce59 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -34,6 +34,18 @@ static const intptr_t kNoVirtualRegister = -1;
static const intptr_t kTempVirtualRegister = -2;
static const intptr_t kIllegalPosition = -1;
static const intptr_t kMaxPosition = 0x7FFFFFFF;
+static const intptr_t kPairVirtualRegisterOffset = 1;
+
+// Definitions which have pair representations
+// (kPairOfTagged or kPairOfUnboxedDouble) use two virtual register names.
+// At SSA index allocation time each definition reserves two SSA indexes,
+// the second index is only used for pairs. This function maps from the first
+// SSA index to the second.
+static intptr_t ToSecondPairVreg(intptr_t vreg) {
+ // Map vreg to its pair vreg.
+ return vreg + kPairVirtualRegisterOffset;
+}
+
static intptr_t MinPosition(intptr_t a, intptr_t b) {
return (a < b) ? a : b;
@@ -74,7 +86,9 @@ FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph)
blocked_cpu_registers_(),
blocked_fpu_registers_(),
cpu_spill_slot_count_(0) {
- for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL);
+ for (intptr_t i = 0; i < vreg_count_; i++) {
+ live_ranges_.Add(NULL);
+ }
for (intptr_t i = 0; i < vreg_count_; i++) {
value_representations_.Add(kNoRepresentation);
}
@@ -114,25 +128,33 @@ void SSALivenessAnalysis::ComputeInitialSets() {
for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) {
Instruction* current = it.Current();
+ // Initialize location summary for instruction.
+ current->InitializeLocationSummary(true); // Optimizing.
+ LocationSummary* locs = current->locs();
+
// Handle definitions.
Definition* current_def = current->AsDefinition();
if ((current_def != NULL) && current_def->HasSSATemp()) {
kill->Add(current_def->ssa_temp_index());
live_in->Remove(current_def->ssa_temp_index());
+ if (current_def->HasPairRepresentation()) {
+ kill->Add(ToSecondPairVreg(current_def->ssa_temp_index()));
+ live_in->Remove(ToSecondPairVreg(current_def->ssa_temp_index()));
+ }
}
// Handle uses.
- current->InitializeLocationSummary(true); // Optimizing.
- LocationSummary* locs = current->locs();
ASSERT(locs->input_count() == current->InputCount());
for (intptr_t j = 0; j < current->InputCount(); j++) {
Value* input = current->InputAt(j);
- const intptr_t use = input->definition()->ssa_temp_index();
ASSERT(!locs->in(j).IsConstant() || input->BindsToConstant());
if (locs->in(j).IsConstant()) continue;
- live_in->Add(use);
+ live_in->Add(input->definition()->ssa_temp_index());
+ if (input->definition()->HasPairRepresentation()) {
+ live_in->Add(ToSecondPairVreg(input->definition()->ssa_temp_index()));
+ }
}
// Add non-argument uses from the deoptimization environment (pushed
@@ -147,11 +169,15 @@ void SSALivenessAnalysis::ComputeInitialSets() {
// Treat its inputs as part of the environment.
for (intptr_t i = 0; i < defn->InputCount(); i++) {
if (!defn->InputAt(i)->BindsToConstant()) {
- live_in->Add(defn->InputAt(i)->definition()->ssa_temp_index());
+ intptr_t idx = defn->InputAt(i)->definition()->ssa_temp_index();
+ live_in->Add(idx);
}
}
} else if (!defn->IsPushArgument() && !defn->IsConstant()) {
live_in->Add(defn->ssa_temp_index());
+ if (defn->HasPairRepresentation()) {
+ live_in->Add(ToSecondPairVreg(defn->ssa_temp_index()));
+ }
}
}
}
@@ -161,6 +187,7 @@ void SSALivenessAnalysis::ComputeInitialSets() {
if (block->IsJoinEntry()) {
JoinEntryInstr* join = block->AsJoinEntry();
for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
ASSERT(phi != NULL);
kill->Add(phi->ssa_temp_index());
@@ -185,8 +212,8 @@ void SSALivenessAnalysis::ComputeInitialSets() {
for (intptr_t i = 0;
i < catch_entry->initial_definitions()->length();
i++) {
- intptr_t vreg =
- (*catch_entry->initial_definitions())[i]->ssa_temp_index();
+ Definition* def = (*catch_entry->initial_definitions())[i];
+ const intptr_t vreg = def->ssa_temp_index();
kill_[catch_entry->postorder_number()]->Add(vreg);
live_in_[catch_entry->postorder_number()]->Remove(vreg);
}
@@ -195,7 +222,8 @@ void SSALivenessAnalysis::ComputeInitialSets() {
// Process initial definitions, ie, constants and incoming parameters.
for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) {
- intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index();
+ Definition* def = (*graph_entry_->initial_definitions())[i];
+ const intptr_t vreg = def->ssa_temp_index();
kill_[graph_entry_->postorder_number()]->Add(vreg);
live_in_[graph_entry_->postorder_number()]->Remove(vreg);
}
@@ -607,7 +635,8 @@ static Location::Kind RegisterKindForResult(Instruction* instr) {
(instr->representation() == kUnboxedMint) ||
(instr->representation() == kUnboxedFloat32x4) ||
(instr->representation() == kUnboxedInt32x4) ||
- (instr->representation() == kUnboxedFloat64x2)) {
+ (instr->representation() == kUnboxedFloat64x2) ||
+ (instr->representation() == kPairOfUnboxedDouble)) {
return Location::kFpuRegister;
} else {
return Location::kRegister;
@@ -666,6 +695,7 @@ Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves(
// Record the corresponding phi input use for each phi.
intptr_t move_idx = 0;
for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
Value* val = phi->InputAt(pred_idx);
MoveOperands* move = parallel_move->MoveOperandsAt(move_idx);
@@ -709,6 +739,7 @@ void FlowGraphAllocator::ConnectIncomingPhiMoves(JoinEntryInstr* join) {
const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header();
intptr_t move_idx = 0;
for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
ASSERT(phi != NULL);
const intptr_t vreg = phi->ssa_temp_index();
@@ -796,10 +827,16 @@ void FlowGraphAllocator::ProcessEnvironmentUses(BlockEntryInstr* block,
continue;
}
- const intptr_t vreg = def->ssa_temp_index();
- LiveRange* range = GetLiveRange(vreg);
+ LiveRange* range = GetLiveRange(def->ssa_temp_index());
range->AddUseInterval(block_start_pos, use_pos);
range->AddUse(use_pos, &locations[i]);
+
+ if (def->HasPairRepresentation()) {
+ LiveRange* range =
+ GetLiveRange(ToSecondPairVreg(def->ssa_temp_index()));
+ range->AddUseInterval(block_start_pos, use_pos);
+ range->AddUse(use_pos, &locations[i]);
+ }
}
env->set_locations(locations);
@@ -834,16 +871,197 @@ void FlowGraphAllocator::ProcessMaterializationUses(
locations[i] = Location::Any();
- const intptr_t vreg = def->ssa_temp_index();
- LiveRange* range = GetLiveRange(vreg);
+ LiveRange* range = GetLiveRange(def->ssa_temp_index());
range->AddUseInterval(block_start_pos, use_pos);
range->AddUse(use_pos, &locations[i]);
+ if (def->HasPairRepresentation()) {
+ LiveRange* range = GetLiveRange(ToSecondPairVreg(def->ssa_temp_index()));
+ range->AddUseInterval(block_start_pos, use_pos);
+ range->AddUse(use_pos, &locations[i]);
+ }
}
mat->set_locations(locations);
}
+void FlowGraphAllocator::ProcessOneInput(BlockEntryInstr* block,
+ intptr_t pos,
+ Location* in_ref,
+ Value* input,
+ intptr_t vreg) {
+ ASSERT(in_ref != NULL);
+ ASSERT(!in_ref->IsPairLocation());
+ ASSERT(input != NULL);
+ ASSERT(block != NULL);
+ LiveRange* range = GetLiveRange(vreg);
+ if (in_ref->IsMachineRegister()) {
+ // Input is expected in a fixed register. Expected shape of
+ // live ranges:
+ //
+ // j' i i'
+ // value --*
+ // register [-----)
+ //
+ MoveOperands* move =
+ AddMoveAt(pos - 1, *in_ref, Location::Any());
+ BlockLocation(*in_ref, pos - 1, pos + 1);
+ range->AddUseInterval(block->start_pos(), pos - 1);
+ range->AddHintedUse(pos - 1, move->src_slot(), in_ref);
+ } else if (in_ref->IsUnallocated()) {
+ if (in_ref->policy() == Location::kWritableRegister) {
+ // Writable unallocated input. Expected shape of
+ // live ranges:
+ //
+ // j' i i'
+ // value --*
+ // temp [------)
+ MoveOperands* move = AddMoveAt(pos - 1,
+ Location::RequiresRegister(),
+ Location::PrefersRegister());
+
+ // Add uses to the live range of the input.
+ range->AddUseInterval(block->start_pos(), pos - 1);
+ range->AddUse(pos - 1, move->src_slot());
+
+ // Create live range for the temporary.
+ LiveRange* temp = MakeLiveRangeForTemporary();
+ temp->AddUseInterval(pos - 1, pos + 1);
+ temp->AddHintedUse(pos - 1, in_ref, move->src_slot());
+ temp->AddUse(pos + 1, move->dest_slot());
+ *in_ref = Location::RequiresRegister();
+ CompleteRange(temp, RegisterKindFromPolicy(*in_ref));
+ } else {
+ // Normal unallocated input. Expected shape of
+ // live ranges:
+ //
+ // i i'
+ // value -----*
+ //
+ range->AddUseInterval(block->start_pos(), pos + 1);
+ range->AddUse(pos + 1, in_ref);
+ }
+ } else {
+ ASSERT(in_ref->IsConstant());
+ }
+}
+
+
+void FlowGraphAllocator::ProcessOneOutput(BlockEntryInstr* block,
+ Instruction* current,
+ intptr_t pos,
+ Location* out,
+ Definition* def,
+ intptr_t vreg,
+ bool output_same_as_first_input,
+ Location* in_ref,
+ Definition* input,
+ intptr_t input_vreg,
+ BitVector* interference_set) {
+ ASSERT(out != NULL);
+ ASSERT(!out->IsPairLocation());
+ ASSERT(def != NULL);
+ ASSERT(block != NULL);
+
+ LiveRange* range = vreg >= 0 ?
+ GetLiveRange(vreg) : MakeLiveRangeForTemporary();
+
+ // Process output and finalize its liverange.
+ if (out->IsMachineRegister()) {
+ // Fixed output location. Expected shape of live range:
+ //
+ // i i' j j'
+ // register [--)
+ // output [-------
+ //
+ BlockLocation(*out, pos, pos + 1);
+
+ if (range->vreg() == kTempVirtualRegister) return;
+
+ // We need to emit move connecting fixed register with another location
+ // that will be allocated for this output's live range.
+ // Special case: fixed output followed by a fixed input last use.
+ UsePosition* use = range->first_use();
+
+ // If the value has no uses we don't need to allocate it.
+ if (use == NULL) return;
+
+ if (use->pos() == (pos + 1)) {
+ ASSERT(use->location_slot()->IsUnallocated());
+ *(use->location_slot()) = *out;
+
+ // Remove first use. It was allocated.
+ range->set_first_use(range->first_use()->next());
+ }
+
+ // Shorten live range to the point of definition, this might make the range
+ // empty (if the only use immediately follows). If range is not empty add
+ // move from a fixed register to an unallocated location.
+ range->DefineAt(pos + 1);
+ if (range->Start() == range->End()) return;
+
+ MoveOperands* move = AddMoveAt(pos + 1, Location::Any(), *out);
+ range->AddHintedUse(pos + 1, move->dest_slot(), out);
+ } else if (output_same_as_first_input) {
+ ASSERT(in_ref != NULL);
+ ASSERT(input != NULL);
+ // Output register will contain a value of the first input at instruction's
+ // start. Expected shape of live ranges:
+ //
+ // i i'
+ // input #0 --*
+ // output [----
+ //
+ ASSERT(in_ref->Equals(Location::RequiresRegister()) ||
+ in_ref->Equals(Location::RequiresFpuRegister()));
+
+ // TODO(johnmccutchan): Without this I get allocated a register instead
+ // of an FPU register. Figure out why.
+
+ *out = *in_ref;
+ // Create move that will copy value between input and output.
+ MoveOperands* move = AddMoveAt(pos,
+ Location::RequiresRegister(),
+ Location::Any());
+
+ // Add uses to the live range of the input.
+ LiveRange* input_range = GetLiveRange(input_vreg);
+ input_range->AddUseInterval(block->start_pos(), pos);
+ input_range->AddUse(pos, move->src_slot());
+
+ // Shorten output live range to the point of definition and add both input
+ // and output uses slots to be filled by allocator.
+ range->DefineAt(pos);
+ range->AddHintedUse(pos, out, move->src_slot());
+ range->AddUse(pos, move->dest_slot());
+ range->AddUse(pos, in_ref);
+
+ if ((interference_set != NULL) &&
+ (range->vreg() >= 0) &&
+ interference_set->Contains(range->vreg())) {
+ interference_set->Add(input->ssa_temp_index());
+ }
+ } else {
+ // Normal unallocated location that requires a register. Expected shape of
+ // live range:
+ //
+ // i i'
+ // output [-------
+ //
+ ASSERT(out->Equals(Location::RequiresRegister()) ||
+ out->Equals(Location::RequiresFpuRegister()));
+
+ // Shorten live range to the point of definition and add use to be filled by
+ // allocator.
+ range->DefineAt(pos);
+ range->AddUse(pos, out);
+ }
+
+ AssignSafepoints(range);
+ CompleteRange(range, RegisterKindForResult(current));
+}
+
+
// Create and update live ranges corresponding to instruction's inputs,
// temporaries and output.
void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
@@ -853,6 +1071,7 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
Definition* def = current->AsDefinition();
if ((def != NULL) && (def->AsConstant() != NULL)) {
+ ASSERT(!def->HasPairRepresentation());
LiveRange* range = (def->ssa_temp_index() != -1) ?
GetLiveRange(def->ssa_temp_index()) : NULL;
@@ -881,7 +1100,6 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
const intptr_t pos = current->lifetime_position();
ASSERT(IsInstructionStartPosition(pos));
- // Number of input locations and number of input operands have to agree.
ASSERT(locs->input_count() == current->InputCount());
// Normalize same-as-first-input output if input is specified as
@@ -902,63 +1120,28 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
// Process inputs.
// Skip the first input if output is specified with kSameAsFirstInput policy,
// they will be processed together at the very end.
- for (intptr_t j = output_same_as_first_input ? 1 : 0;
- j < current->InputCount();
- j++) {
- Value* input = current->InputAt(j);
- const intptr_t vreg = input->definition()->ssa_temp_index();
- LiveRange* range = GetLiveRange(vreg);
-
- Location* in_ref = locs->in_slot(j);
-
- if (in_ref->IsMachineRegister()) {
- // Input is expected in a fixed register. Expected shape of
- // live ranges:
- //
- // j' i i'
- // value --*
- // register [-----)
- //
- MoveOperands* move =
- AddMoveAt(pos - 1, *in_ref, Location::Any());
- BlockLocation(*in_ref, pos - 1, pos + 1);
- range->AddUseInterval(block->start_pos(), pos - 1);
- range->AddHintedUse(pos - 1, move->src_slot(), in_ref);
- } else if (in_ref->IsUnallocated()) {
- if (in_ref->policy() == Location::kWritableRegister) {
- // Writable unallocated input. Expected shape of
- // live ranges:
- //
- // i i'
- // value --*
- // temp [--)
- MoveOperands* move = AddMoveAt(pos,
- Location::RequiresRegister(),
- Location::PrefersRegister());
-
- // Add uses to the live range of the input.
- range->AddUseInterval(block->start_pos(), pos);
- range->AddUse(pos, move->src_slot());
-
- // Create live range for the temporary.
- LiveRange* temp = MakeLiveRangeForTemporary();
- temp->AddUseInterval(pos, pos + 1);
- temp->AddHintedUse(pos, in_ref, move->src_slot());
- temp->AddUse(pos, move->dest_slot());
- *in_ref = Location::RequiresRegister();
- CompleteRange(temp, RegisterKindFromPolicy(*in_ref));
+ {
+ for (intptr_t j = output_same_as_first_input ? 1 : 0;
+ j < locs->input_count();
+ j++) {
+ // Determine if we are dealing with a value pair, and if so, whether
+ // the location is the first register or second register.
+ Value* input = current->InputAt(j);
+ Location* in_ref = locs->in_slot(j);
+ if (in_ref->IsPairLocation()) {
+ ASSERT(input->definition()->HasPairRepresentation());
+ PairLocation* pair = in_ref->AsPairLocation();
+ const intptr_t vreg = input->definition()->ssa_temp_index();
+ // Each element of the pair is assigned it's own virtual register number
+ // and is allocated its own LiveRange.
+ ProcessOneInput(block, pos, pair->SlotAt(0),
+ input, vreg);
+ ProcessOneInput(block, pos, pair->SlotAt(1), input,
+ ToSecondPairVreg(vreg));
} else {
- // Normal unallocated input. Expected shape of
- // live ranges:
- //
- // i i'
- // value -----*
- //
- range->AddUseInterval(block->start_pos(), pos + 1);
- range->AddUse(pos + 1, in_ref);
+ ProcessOneInput(block, pos, in_ref, input,
+ input->definition()->ssa_temp_index());
}
- } else {
- ASSERT(in_ref->IsConstant());
}
}
@@ -971,6 +1154,8 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
//
Location temp = locs->temp(j);
+ // We do not support pair locations for temporaries.
+ ASSERT(!temp.IsPairLocation());
if (temp.IsMachineRegister()) {
BlockLocation(temp, pos, pos + 1);
} else if (temp.IsUnallocated()) {
@@ -1010,14 +1195,27 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
// locations. Every register is blocked now so attempt to
// allocate will not succeed.
for (intptr_t j = 0; j < locs->temp_count(); j++) {
+ ASSERT(!locs->temp(j).IsPairLocation());
ASSERT(!locs->temp(j).IsUnallocated());
}
for (intptr_t j = 0; j < locs->input_count(); j++) {
- ASSERT(!locs->in(j).IsUnallocated());
+ if (locs->in(j).IsPairLocation()) {
+ PairLocation* pair = locs->in_slot(j)->AsPairLocation();
+ ASSERT(!pair->At(0).IsUnallocated());
+ ASSERT(!pair->At(1).IsUnallocated());
+ } else {
+ ASSERT(!locs->in(j).IsUnallocated());
+ }
}
- ASSERT(!locs->out(0).IsUnallocated());
+ if (locs->out(0).IsPairLocation()) {
+ PairLocation* pair = locs->out_slot(0)->AsPairLocation();
+ ASSERT(!pair->At(0).IsUnallocated());
+ ASSERT(!pair->At(1).IsUnallocated());
+ } else {
+ ASSERT(!locs->out(0).IsUnallocated());
+ }
#endif
}
@@ -1035,103 +1233,69 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
return;
}
- // We might have a definition without use. We do not assign SSA index to
- // such definitions.
- LiveRange* range = (def->ssa_temp_index() >= 0) ?
- GetLiveRange(def->ssa_temp_index()) :
- MakeLiveRangeForTemporary();
+ ASSERT(locs->output_count() == 1);
Location* out = locs->out_slot(0);
-
- // Process output and finalize its liverange.
- if (out->IsMachineRegister()) {
- // Fixed output location. Expected shape of live range:
- //
- // i i' j j'
- // register [--)
- // output [-------
- //
- BlockLocation(*out, pos, pos + 1);
-
- if (range->vreg() == kTempVirtualRegister) return;
-
- // We need to emit move connecting fixed register with another location
- // that will be allocated for this output's live range.
- // Special case: fixed output followed by a fixed input last use.
- UsePosition* use = range->first_use();
-
- // If the value has no uses we don't need to allocate it.
- if (use == NULL) return;
-
- if (use->pos() == (pos + 1)) {
- ASSERT(use->location_slot()->IsUnallocated());
- *(use->location_slot()) = *out;
-
- // Remove first use. It was allocated.
- range->set_first_use(range->first_use()->next());
- }
-
- // Shorten live range to the point of definition, this might make the range
- // empty (if the only use immediately follows). If range is not empty add
- // move from a fixed register to an unallocated location.
- range->DefineAt(pos + 1);
- if (range->Start() == range->End()) return;
-
- MoveOperands* move = AddMoveAt(pos + 1, Location::Any(), *out);
- range->AddHintedUse(pos + 1, move->dest_slot(), out);
- } else if (output_same_as_first_input) {
- // Output register will contain a value of the first input at instruction's
- // start. Expected shape of live ranges:
- //
- // i i'
- // input #0 --*
- // output [----
- //
- ASSERT(locs->in(0).Equals(Location::RequiresRegister()) ||
- locs->in(0).Equals(Location::RequiresFpuRegister()));
-
- // Create move that will copy value between input and output.
- locs->set_out(0, Location::RequiresRegister());
- MoveOperands* move = AddMoveAt(pos,
- Location::RequiresRegister(),
- Location::Any());
-
- // Add uses to the live range of the input.
- Definition* input = current->InputAt(0)->definition();
- LiveRange* input_range =
- GetLiveRange(input->ssa_temp_index());
- input_range->AddUseInterval(block->start_pos(), pos);
- input_range->AddUse(pos, move->src_slot());
-
- // Shorten output live range to the point of definition and add both input
- // and output uses slots to be filled by allocator.
- range->DefineAt(pos);
- range->AddHintedUse(pos, out, move->src_slot());
- range->AddUse(pos, move->dest_slot());
- range->AddUse(pos, locs->in_slot(0));
-
- if ((interference_set != NULL) &&
- (range->vreg() >= 0) &&
- interference_set->Contains(range->vreg())) {
- interference_set->Add(input->ssa_temp_index());
+ if (out->IsPairLocation()) {
+ ASSERT(def->HasPairRepresentation());
+ PairLocation* pair = out->AsPairLocation();
+ if (output_same_as_first_input) {
+ ASSERT(locs->in_slot(0)->IsPairLocation());
+ PairLocation* in_pair = locs->in_slot(0)->AsPairLocation();
+ Definition* input = current->InputAt(0)->definition();
+ ASSERT(input->HasPairRepresentation());
+ // Each element of the pair is assigned it's own virtual register number
+ // and is allocated its own LiveRange.
+ ProcessOneOutput(block, current, pos, // BlockEntry, Instruction, seq.
+ pair->SlotAt(0), def, // (output) Location, Definition.
+ def->ssa_temp_index(), // (output) virtual register.
+ true, // output mapped to first input.
+ in_pair->SlotAt(0), input, // (input) Location, Def.
+ input->ssa_temp_index(), // (input) virtual register.
+ interference_set);
+ ProcessOneOutput(block, current, pos,
+ pair->SlotAt(1), def,
+ ToSecondPairVreg(def->ssa_temp_index()),
+ true,
+ in_pair->SlotAt(1), input,
+ ToSecondPairVreg(input->ssa_temp_index()),
+ interference_set);
+ } else {
+ // Each element of the pair is assigned it's own virtual register number
+ // and is allocated its own LiveRange.
+ ProcessOneOutput(block, current, pos,
+ pair->SlotAt(0), def,
+ def->ssa_temp_index(),
+ false, // output is not mapped to first input.
+ NULL, NULL, -1, // First input not needed.
+ interference_set);
+ ProcessOneOutput(block, current, pos,
+ pair->SlotAt(1), def,
+ ToSecondPairVreg(def->ssa_temp_index()),
+ false,
+ NULL, NULL, -1,
+ interference_set);
}
} else {
- // Normal unallocated location that requires a register. Expected shape of
- // live range:
- //
- // i i'
- // output [-------
- //
- ASSERT(locs->out(0).Equals(Location::RequiresRegister()) ||
- locs->out(0).Equals(Location::RequiresFpuRegister()));
-
- // Shorten live range to the point of definition and add use to be filled by
- // allocator.
- range->DefineAt(pos);
- range->AddUse(pos, out);
+ if (output_same_as_first_input) {
+ Location* in_ref = locs->in_slot(0);
+ Definition* input = current->InputAt(0)->definition();
+ ASSERT(!in_ref->IsPairLocation());
+ ProcessOneOutput(block, current, pos, // BlockEntry, Instruction, seq.
+ out, def, // (output) Location, Definition.
+ def->ssa_temp_index(), // (output) virtual register.
+ true, // output mapped to first input.
+ in_ref, input, // (input) Location, Def.
+ input->ssa_temp_index(), // (input) virtual register.
+ interference_set);
+ } else {
+ ProcessOneOutput(block, current, pos,
+ out, def,
+ def->ssa_temp_index(),
+ false, // output is not mapped to first input.
+ NULL, NULL, -1, // First input not needed.
+ interference_set);
+ }
}
-
- AssignSafepoints(range);
- CompleteRange(range, RegisterKindForResult(current));
}
@@ -1718,6 +1882,7 @@ intptr_t FlowGraphAllocator::FirstIntersectionWithAllocated(
void ReachingDefs::AddPhi(PhiInstr* phi) {
+ // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
if (phi->reaching_defs() == NULL) {
phi->set_reaching_defs(
new BitVector(flow_graph_.max_virtual_register_number()));
@@ -1741,6 +1906,7 @@ void ReachingDefs::AddPhi(PhiInstr* phi) {
void ReachingDefs::Compute() {
// Transitively collect all phis that are used by the given phi.
for (intptr_t i = 0; i < phis_.length(); i++) {
+ // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = phis_[i];
// Add all phis that affect this phi to the list.
@@ -1844,6 +2010,7 @@ bool FlowGraphAllocator::AllocateFreeRegister(LiveRange* unallocated) {
for (PhiIterator it(loop_header->entry()->AsJoinEntry());
!it.Done();
it.Advance()) {
+ // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
ASSERT(phi->is_alive());
const intptr_t phi_vreg = phi->ssa_temp_index();
@@ -1908,7 +2075,8 @@ bool FlowGraphAllocator::AllocateFreeRegister(LiveRange* unallocated) {
bool FlowGraphAllocator::RangeHasOnlyUnconstrainedUsesInLoop(LiveRange* range,
intptr_t loop_id) {
if (range->vreg() >= 0) {
- return GetLiveRange(range->vreg())->HasOnlyUnconstrainedUsesInLoop(loop_id);
+ LiveRange* parent = GetLiveRange(range->vreg());
+ return parent->HasOnlyUnconstrainedUsesInLoop(loop_id);
}
return false;
}
@@ -1989,6 +2157,8 @@ void FlowGraphAllocator::AllocateAnyRegister(LiveRange* unallocated) {
return;
}
+ ASSERT(candidate != kNoRegister);
+
TRACE_ALLOC(OS::Print("assigning blocked register "));
TRACE_ALLOC(MakeRegisterLocation(candidate).Print());
TRACE_ALLOC(OS::Print(" to live range v%" Pd " until %" Pd "\n",
@@ -2499,6 +2669,7 @@ void FlowGraphAllocator::CollectRepresentations() {
for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) {
Definition* def = (*graph_entry->initial_definitions())[i];
value_representations_[def->ssa_temp_index()] = def->representation();
+ ASSERT(!def->HasPairRepresentation());
}
for (BlockIterator it = flow_graph_.reverse_postorder_iterator();
@@ -2520,6 +2691,7 @@ void FlowGraphAllocator::CollectRepresentations() {
if (block->IsJoinEntry()) {
JoinEntryInstr* join = block->AsJoinEntry();
for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) {
value_representations_[phi->ssa_temp_index()] = phi->representation();
@@ -2532,7 +2704,11 @@ void FlowGraphAllocator::CollectRepresentations() {
instr_it.Advance()) {
Definition* def = instr_it.Current()->AsDefinition();
if ((def != NULL) && (def->ssa_temp_index() >= 0)) {
- value_representations_[def->ssa_temp_index()] = def->representation();
+ const intptr_t vreg = def->ssa_temp_index();
+ value_representations_[vreg] = def->representation();
+ if (def->HasPairRepresentation()) {
+ value_representations_[ToSecondPairVreg(vreg)] = def->representation();
+ }
}
}
}
« no previous file with comments | « runtime/vm/flow_graph_allocator.h ('k') | runtime/vm/flow_graph_optimizer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698