| 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();
|
| + }
|
| }
|
| }
|
| }
|
|
|