| 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..163c4c8ebca0fb5c2c5bdfd8a6ee8482d9369d63 100644
|
| --- a/runtime/vm/flow_graph_allocator.cc
|
| +++ b/runtime/vm/flow_graph_allocator.cc
|
| @@ -74,7 +74,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 +116,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->RequiresTwoSSATempIndexes()) {
|
| + kill->Add(current_def->ssa_temp_index2());
|
| + live_in->Remove(current_def->ssa_temp_index2());
|
| + }
|
| }
|
|
|
| // 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()->RequiresTwoSSATempIndexes()) {
|
| + live_in->Add(input->definition()->ssa_temp_index2());
|
| + }
|
| }
|
|
|
| // Add non-argument uses from the deoptimization environment (pushed
|
| @@ -147,11 +157,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->RequiresTwoSSATempIndexes()) {
|
| + live_in->Add(defn->ssa_temp_index2());
|
| + }
|
| }
|
| }
|
| }
|
| @@ -161,6 +175,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 +200,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 +210,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 +623,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 +683,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 +727,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 +815,15 @@ 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->RequiresTwoSSATempIndexes()) {
|
| + LiveRange* range = GetLiveRange(def->ssa_temp_index2());
|
| + range->AddUseInterval(block_start_pos, use_pos);
|
| + range->AddUse(use_pos, &locations[i]);
|
| + }
|
| }
|
|
|
| env->set_locations(locations);
|
| @@ -834,16 +858,193 @@ 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->RequiresTwoSSATempIndexes()) {
|
| + LiveRange* range = GetLiveRange(def->ssa_temp_index2());
|
| + 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);
|
| + ASSERT(!in_ref->IsPairLocation());
|
| + ASSERT(input);
|
| + ASSERT(block);
|
| + 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);
|
| + ASSERT(!out->IsPairLocation());
|
| + ASSERT(def);
|
| + ASSERT(block);
|
| +
|
| + 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()));
|
| +
|
| + *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 +1054,7 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
|
|
|
| Definition* def = current->AsDefinition();
|
| if ((def != NULL) && (def->AsConstant() != NULL)) {
|
| + ASSERT(!def->RequiresTwoSSATempIndexes());
|
| LiveRange* range = (def->ssa_temp_index() != -1) ?
|
| GetLiveRange(def->ssa_temp_index()) : NULL;
|
|
|
| @@ -860,7 +1062,7 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
|
| if ((range == NULL) || (range->first_use() == NULL)) {
|
| locs->set_out(0, Location::NoLocation());
|
| return;
|
| - }
|
| + }
|
|
|
| // If this constant has only unconstrained uses convert them all
|
| // to use the constant directly and drop this definition.
|
| @@ -881,7 +1083,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,66 +1103,29 @@ 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()->RequiresTwoSSATempIndexes());
|
| + PairLocation* pair = in_ref->AsPairLocation();
|
| + ProcessOneInput(block, pos, pair->SlotAt(0),
|
| + input, input->definition()->ssa_temp_index());
|
| + ProcessOneInput(block, pos, pair->SlotAt(1), input,
|
| + input->definition()->ssa_temp_index2());
|
| } 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());
|
| }
|
| }
|
|
|
| +
|
| // Process temps.
|
| for (intptr_t j = 0; j < locs->temp_count(); j++) {
|
| // Expected shape of live range:
|
| @@ -971,6 +1135,7 @@ void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
|
| //
|
|
|
| Location temp = locs->temp(j);
|
| + ASSERT(!temp.IsPairLocation());
|
| if (temp.IsMachineRegister()) {
|
| BlockLocation(temp, pos, pos + 1);
|
| } else if (temp.IsUnallocated()) {
|
| @@ -1035,103 +1200,56 @@ 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->RequiresTwoSSATempIndexes());
|
| + 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->RequiresTwoSSATempIndexes());
|
| + ProcessOneOutput(block, current, pos,
|
| + pair->SlotAt(0), def, def->ssa_temp_index(),
|
| + true,
|
| + in_pair->SlotAt(0), input, input->ssa_temp_index(),
|
| + interference_set);
|
| + ProcessOneOutput(block, current, pos,
|
| + pair->SlotAt(1), def, def->ssa_temp_index2(),
|
| + true,
|
| + in_pair->SlotAt(1), input, input->ssa_temp_index2(),
|
| + interference_set);
|
| + } else {
|
| + ProcessOneOutput(block, current, pos,
|
| + pair->SlotAt(0), def, def->ssa_temp_index(),
|
| + false,
|
| + NULL, NULL, -1,
|
| + interference_set);
|
| + ProcessOneOutput(block, current, pos,
|
| + pair->SlotAt(1), def, def->ssa_temp_index2(),
|
| + 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,
|
| + out, def, def->ssa_temp_index(),
|
| + true,
|
| + in_ref, input, input->ssa_temp_index(),
|
| + interference_set);
|
| + } else {
|
| + ProcessOneOutput(block, current, pos,
|
| + out, def, def->ssa_temp_index(),
|
| + false,
|
| + NULL, NULL, -1,
|
| + interference_set);
|
| + }
|
| }
|
| -
|
| - AssignSafepoints(range);
|
| - CompleteRange(range, RegisterKindForResult(current));
|
| }
|
|
|
|
|
| @@ -1718,6 +1836,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 +1860,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 +1964,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 +2029,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 +2111,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",
|
| @@ -2354,7 +2478,8 @@ bool FlowGraphAllocator::TargetLocationIsSpillSlot(LiveRange* range,
|
| if (target.IsStackSlot() ||
|
| target.IsDoubleStackSlot() ||
|
| target.IsConstant()) {
|
| - ASSERT(GetLiveRange(range->vreg())->spill_slot().Equals(target));
|
| + LiveRange* parent = GetLiveRange(range->vreg());
|
| + ASSERT(parent->spill_slot().Equals(target));
|
| return true;
|
| }
|
| return false;
|
| @@ -2499,6 +2624,9 @@ 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();
|
| + if (def->RequiresTwoSSATempIndexes()) {
|
| + value_representations_[def->ssa_temp_index2()] = def->representation();
|
| + }
|
| }
|
|
|
| for (BlockIterator it = flow_graph_.reverse_postorder_iterator();
|
| @@ -2520,6 +2648,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();
|
| @@ -2533,6 +2662,9 @@ void FlowGraphAllocator::CollectRepresentations() {
|
| Definition* def = instr_it.Current()->AsDefinition();
|
| if ((def != NULL) && (def->ssa_temp_index() >= 0)) {
|
| value_representations_[def->ssa_temp_index()] = def->representation();
|
| + if (def->RequiresTwoSSATempIndexes()) {
|
| + value_representations_[def->ssa_temp_index2()] = def->representation();
|
| + }
|
| }
|
| }
|
| }
|
|
|