1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "register_allocation_resolver.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
21*795d594fSAndroid Build Coastguard Worker #include "linear_order.h"
22*795d594fSAndroid Build Coastguard Worker #include "ssa_liveness_analysis.h"
23*795d594fSAndroid Build Coastguard Worker
24*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
25*795d594fSAndroid Build Coastguard Worker
RegisterAllocationResolver(CodeGenerator * codegen,const SsaLivenessAnalysis & liveness)26*795d594fSAndroid Build Coastguard Worker RegisterAllocationResolver::RegisterAllocationResolver(CodeGenerator* codegen,
27*795d594fSAndroid Build Coastguard Worker const SsaLivenessAnalysis& liveness)
28*795d594fSAndroid Build Coastguard Worker : allocator_(codegen->GetGraph()->GetAllocator()),
29*795d594fSAndroid Build Coastguard Worker codegen_(codegen),
30*795d594fSAndroid Build Coastguard Worker liveness_(liveness) {}
31*795d594fSAndroid Build Coastguard Worker
Resolve(ArrayRef<HInstruction * const> safepoints,size_t reserved_out_slots,size_t int_spill_slots,size_t long_spill_slots,size_t float_spill_slots,size_t double_spill_slots,size_t catch_phi_spill_slots,ArrayRef<LiveInterval * const> temp_intervals)32*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::Resolve(ArrayRef<HInstruction* const> safepoints,
33*795d594fSAndroid Build Coastguard Worker size_t reserved_out_slots,
34*795d594fSAndroid Build Coastguard Worker size_t int_spill_slots,
35*795d594fSAndroid Build Coastguard Worker size_t long_spill_slots,
36*795d594fSAndroid Build Coastguard Worker size_t float_spill_slots,
37*795d594fSAndroid Build Coastguard Worker size_t double_spill_slots,
38*795d594fSAndroid Build Coastguard Worker size_t catch_phi_spill_slots,
39*795d594fSAndroid Build Coastguard Worker ArrayRef<LiveInterval* const> temp_intervals) {
40*795d594fSAndroid Build Coastguard Worker size_t spill_slots = int_spill_slots
41*795d594fSAndroid Build Coastguard Worker + long_spill_slots
42*795d594fSAndroid Build Coastguard Worker + float_spill_slots
43*795d594fSAndroid Build Coastguard Worker + double_spill_slots
44*795d594fSAndroid Build Coastguard Worker + catch_phi_spill_slots;
45*795d594fSAndroid Build Coastguard Worker
46*795d594fSAndroid Build Coastguard Worker // Update safepoints and calculate the size of the spills.
47*795d594fSAndroid Build Coastguard Worker UpdateSafepointLiveRegisters();
48*795d594fSAndroid Build Coastguard Worker size_t maximum_safepoint_spill_size = CalculateMaximumSafepointSpillSize(safepoints);
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker // Computes frame size and spill mask.
51*795d594fSAndroid Build Coastguard Worker codegen_->InitializeCodeGeneration(spill_slots,
52*795d594fSAndroid Build Coastguard Worker maximum_safepoint_spill_size,
53*795d594fSAndroid Build Coastguard Worker reserved_out_slots, // Includes slot(s) for the art method.
54*795d594fSAndroid Build Coastguard Worker codegen_->GetGraph()->GetLinearOrder());
55*795d594fSAndroid Build Coastguard Worker
56*795d594fSAndroid Build Coastguard Worker // Resolve outputs, including stack locations.
57*795d594fSAndroid Build Coastguard Worker // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
58*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
59*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
60*795d594fSAndroid Build Coastguard Worker LiveInterval* current = instruction->GetLiveInterval();
61*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
62*795d594fSAndroid Build Coastguard Worker Location location = locations->Out();
63*795d594fSAndroid Build Coastguard Worker if (instruction->IsParameterValue()) {
64*795d594fSAndroid Build Coastguard Worker // Now that we know the frame size, adjust the parameter's location.
65*795d594fSAndroid Build Coastguard Worker if (location.IsStackSlot()) {
66*795d594fSAndroid Build Coastguard Worker location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
67*795d594fSAndroid Build Coastguard Worker current->SetSpillSlot(location.GetStackIndex());
68*795d594fSAndroid Build Coastguard Worker locations->UpdateOut(location);
69*795d594fSAndroid Build Coastguard Worker } else if (location.IsDoubleStackSlot()) {
70*795d594fSAndroid Build Coastguard Worker location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
71*795d594fSAndroid Build Coastguard Worker current->SetSpillSlot(location.GetStackIndex());
72*795d594fSAndroid Build Coastguard Worker locations->UpdateOut(location);
73*795d594fSAndroid Build Coastguard Worker } else if (current->HasSpillSlot()) {
74*795d594fSAndroid Build Coastguard Worker current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
75*795d594fSAndroid Build Coastguard Worker }
76*795d594fSAndroid Build Coastguard Worker } else if (instruction->IsCurrentMethod()) {
77*795d594fSAndroid Build Coastguard Worker // The current method is always at offset 0.
78*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(current->HasSpillSlot(), (current->GetSpillSlot() == 0));
79*795d594fSAndroid Build Coastguard Worker } else if (instruction->IsPhi() && instruction->AsPhi()->IsCatchPhi()) {
80*795d594fSAndroid Build Coastguard Worker DCHECK(current->HasSpillSlot());
81*795d594fSAndroid Build Coastguard Worker size_t slot = current->GetSpillSlot()
82*795d594fSAndroid Build Coastguard Worker + spill_slots
83*795d594fSAndroid Build Coastguard Worker + reserved_out_slots
84*795d594fSAndroid Build Coastguard Worker - catch_phi_spill_slots;
85*795d594fSAndroid Build Coastguard Worker current->SetSpillSlot(slot * kVRegSize);
86*795d594fSAndroid Build Coastguard Worker } else if (current->HasSpillSlot()) {
87*795d594fSAndroid Build Coastguard Worker // Adjust the stack slot, now that we know the number of them for each type.
88*795d594fSAndroid Build Coastguard Worker // The way this implementation lays out the stack is the following:
89*795d594fSAndroid Build Coastguard Worker // [parameter slots ]
90*795d594fSAndroid Build Coastguard Worker // [art method (caller) ]
91*795d594fSAndroid Build Coastguard Worker // [entry spill (core) ]
92*795d594fSAndroid Build Coastguard Worker // [entry spill (float) ]
93*795d594fSAndroid Build Coastguard Worker // [should_deoptimize flag] (this is optional)
94*795d594fSAndroid Build Coastguard Worker // [catch phi spill slots ]
95*795d594fSAndroid Build Coastguard Worker // [double spill slots ]
96*795d594fSAndroid Build Coastguard Worker // [long spill slots ]
97*795d594fSAndroid Build Coastguard Worker // [float spill slots ]
98*795d594fSAndroid Build Coastguard Worker // [int/ref values ]
99*795d594fSAndroid Build Coastguard Worker // [maximum out values ] (number of arguments for calls)
100*795d594fSAndroid Build Coastguard Worker // [art method ].
101*795d594fSAndroid Build Coastguard Worker size_t slot = current->GetSpillSlot();
102*795d594fSAndroid Build Coastguard Worker switch (current->GetType()) {
103*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
104*795d594fSAndroid Build Coastguard Worker slot += long_spill_slots;
105*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
106*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint64:
107*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
108*795d594fSAndroid Build Coastguard Worker slot += float_spill_slots;
109*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
110*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
111*795d594fSAndroid Build Coastguard Worker slot += int_spill_slots;
112*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
113*795d594fSAndroid Build Coastguard Worker case DataType::Type::kReference:
114*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint32:
115*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
116*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
117*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
118*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
119*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
120*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
121*795d594fSAndroid Build Coastguard Worker slot += reserved_out_slots;
122*795d594fSAndroid Build Coastguard Worker break;
123*795d594fSAndroid Build Coastguard Worker case DataType::Type::kVoid:
124*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type for interval " << current->GetType();
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker current->SetSpillSlot(slot * kVRegSize);
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker
129*795d594fSAndroid Build Coastguard Worker Location source = current->ToLocation();
130*795d594fSAndroid Build Coastguard Worker
131*795d594fSAndroid Build Coastguard Worker if (location.IsUnallocated()) {
132*795d594fSAndroid Build Coastguard Worker if (location.GetPolicy() == Location::kSameAsFirstInput) {
133*795d594fSAndroid Build Coastguard Worker if (locations->InAt(0).IsUnallocated()) {
134*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, source);
135*795d594fSAndroid Build Coastguard Worker } else {
136*795d594fSAndroid Build Coastguard Worker DCHECK(locations->InAt(0).Equals(source));
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker locations->UpdateOut(source);
140*795d594fSAndroid Build Coastguard Worker } else {
141*795d594fSAndroid Build Coastguard Worker DCHECK(source.Equals(location));
142*795d594fSAndroid Build Coastguard Worker }
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker
145*795d594fSAndroid Build Coastguard Worker // Connect siblings and resolve inputs.
146*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
147*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
148*795d594fSAndroid Build Coastguard Worker ConnectSiblings(instruction->GetLiveInterval());
149*795d594fSAndroid Build Coastguard Worker }
150*795d594fSAndroid Build Coastguard Worker
151*795d594fSAndroid Build Coastguard Worker // Resolve non-linear control flow across branches. Order does not matter.
152*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : codegen_->GetGraph()->GetLinearOrder()) {
153*795d594fSAndroid Build Coastguard Worker if (block->IsCatchBlock() ||
154*795d594fSAndroid Build Coastguard Worker (block->IsLoopHeader() && block->GetLoopInformation()->IsIrreducible())) {
155*795d594fSAndroid Build Coastguard Worker // Instructions live at the top of catch blocks or irreducible loop header
156*795d594fSAndroid Build Coastguard Worker // were forced to spill.
157*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
158*795d594fSAndroid Build Coastguard Worker BitVector* live = liveness_.GetLiveInSet(*block);
159*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : live->Indexes()) {
160*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = liveness_.GetInstructionFromSsaIndex(idx)->GetLiveInterval();
161*795d594fSAndroid Build Coastguard Worker LiveInterval* sibling = interval->GetSiblingAt(block->GetLifetimeStart());
162*795d594fSAndroid Build Coastguard Worker // `GetSiblingAt` returns the sibling that contains a position, but there could be
163*795d594fSAndroid Build Coastguard Worker // a lifetime hole in it. `CoversSlow` returns whether the interval is live at that
164*795d594fSAndroid Build Coastguard Worker // position.
165*795d594fSAndroid Build Coastguard Worker if ((sibling != nullptr) && sibling->CoversSlow(block->GetLifetimeStart())) {
166*795d594fSAndroid Build Coastguard Worker DCHECK(!sibling->HasRegister());
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker }
169*795d594fSAndroid Build Coastguard Worker }
170*795d594fSAndroid Build Coastguard Worker } else {
171*795d594fSAndroid Build Coastguard Worker BitVector* live = liveness_.GetLiveInSet(*block);
172*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : live->Indexes()) {
173*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = liveness_.GetInstructionFromSsaIndex(idx)->GetLiveInterval();
174*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : block->GetPredecessors()) {
175*795d594fSAndroid Build Coastguard Worker ConnectSplitSiblings(interval, predecessor, block);
176*795d594fSAndroid Build Coastguard Worker }
177*795d594fSAndroid Build Coastguard Worker }
178*795d594fSAndroid Build Coastguard Worker }
179*795d594fSAndroid Build Coastguard Worker }
180*795d594fSAndroid Build Coastguard Worker
181*795d594fSAndroid Build Coastguard Worker // Resolve phi inputs. Order does not matter.
182*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : codegen_->GetGraph()->GetLinearOrder()) {
183*795d594fSAndroid Build Coastguard Worker if (block->IsCatchBlock()) {
184*795d594fSAndroid Build Coastguard Worker // Catch phi values are set at runtime by the exception delivery mechanism.
185*795d594fSAndroid Build Coastguard Worker } else {
186*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
187*795d594fSAndroid Build Coastguard Worker HInstruction* phi = inst_it.Current();
188*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = block->GetPredecessors().size(); i < e; ++i) {
189*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = block->GetPredecessors()[i];
190*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(predecessor->GetNormalSuccessors().size(), 1u);
191*795d594fSAndroid Build Coastguard Worker HInstruction* input = phi->InputAt(i);
192*795d594fSAndroid Build Coastguard Worker Location source = input->GetLiveInterval()->GetLocationAt(
193*795d594fSAndroid Build Coastguard Worker predecessor->GetLifetimeEnd() - 1);
194*795d594fSAndroid Build Coastguard Worker Location destination = phi->GetLiveInterval()->ToLocation();
195*795d594fSAndroid Build Coastguard Worker InsertParallelMoveAtExitOf(predecessor, phi, source, destination);
196*795d594fSAndroid Build Coastguard Worker }
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker }
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker
201*795d594fSAndroid Build Coastguard Worker // Resolve temp locations.
202*795d594fSAndroid Build Coastguard Worker for (LiveInterval* temp : temp_intervals) {
203*795d594fSAndroid Build Coastguard Worker if (temp->IsHighInterval()) {
204*795d594fSAndroid Build Coastguard Worker // High intervals can be skipped, they are already handled by the low interval.
205*795d594fSAndroid Build Coastguard Worker continue;
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker HInstruction* at = liveness_.GetTempUser(temp);
208*795d594fSAndroid Build Coastguard Worker size_t temp_index = liveness_.GetTempIndex(temp);
209*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = at->GetLocations();
210*795d594fSAndroid Build Coastguard Worker switch (temp->GetType()) {
211*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
212*795d594fSAndroid Build Coastguard Worker locations->SetTempAt(temp_index, Location::RegisterLocation(temp->GetRegister()));
213*795d594fSAndroid Build Coastguard Worker break;
214*795d594fSAndroid Build Coastguard Worker
215*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
216*795d594fSAndroid Build Coastguard Worker if (codegen_->NeedsTwoRegisters(DataType::Type::kFloat64)) {
217*795d594fSAndroid Build Coastguard Worker Location location = Location::FpuRegisterPairLocation(
218*795d594fSAndroid Build Coastguard Worker temp->GetRegister(), temp->GetHighInterval()->GetRegister());
219*795d594fSAndroid Build Coastguard Worker locations->SetTempAt(temp_index, location);
220*795d594fSAndroid Build Coastguard Worker } else {
221*795d594fSAndroid Build Coastguard Worker locations->SetTempAt(temp_index, Location::FpuRegisterLocation(temp->GetRegister()));
222*795d594fSAndroid Build Coastguard Worker }
223*795d594fSAndroid Build Coastguard Worker break;
224*795d594fSAndroid Build Coastguard Worker
225*795d594fSAndroid Build Coastguard Worker default:
226*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type for temporary location "
227*795d594fSAndroid Build Coastguard Worker << temp->GetType();
228*795d594fSAndroid Build Coastguard Worker }
229*795d594fSAndroid Build Coastguard Worker }
230*795d594fSAndroid Build Coastguard Worker }
231*795d594fSAndroid Build Coastguard Worker
UpdateSafepointLiveRegisters()232*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::UpdateSafepointLiveRegisters() {
233*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
234*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
235*795d594fSAndroid Build Coastguard Worker for (LiveInterval* current = instruction->GetLiveInterval();
236*795d594fSAndroid Build Coastguard Worker current != nullptr;
237*795d594fSAndroid Build Coastguard Worker current = current->GetNextSibling()) {
238*795d594fSAndroid Build Coastguard Worker if (!current->HasRegister()) {
239*795d594fSAndroid Build Coastguard Worker continue;
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker Location source = current->ToLocation();
242*795d594fSAndroid Build Coastguard Worker for (SafepointPosition* safepoint_position = current->GetFirstSafepoint();
243*795d594fSAndroid Build Coastguard Worker safepoint_position != nullptr;
244*795d594fSAndroid Build Coastguard Worker safepoint_position = safepoint_position->GetNext()) {
245*795d594fSAndroid Build Coastguard Worker DCHECK(current->CoversSlow(safepoint_position->GetPosition()));
246*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = safepoint_position->GetLocations();
247*795d594fSAndroid Build Coastguard Worker switch (source.GetKind()) {
248*795d594fSAndroid Build Coastguard Worker case Location::kRegister:
249*795d594fSAndroid Build Coastguard Worker case Location::kFpuRegister: {
250*795d594fSAndroid Build Coastguard Worker locations->AddLiveRegister(source);
251*795d594fSAndroid Build Coastguard Worker break;
252*795d594fSAndroid Build Coastguard Worker }
253*795d594fSAndroid Build Coastguard Worker case Location::kRegisterPair:
254*795d594fSAndroid Build Coastguard Worker case Location::kFpuRegisterPair: {
255*795d594fSAndroid Build Coastguard Worker locations->AddLiveRegister(source.ToLow());
256*795d594fSAndroid Build Coastguard Worker locations->AddLiveRegister(source.ToHigh());
257*795d594fSAndroid Build Coastguard Worker break;
258*795d594fSAndroid Build Coastguard Worker }
259*795d594fSAndroid Build Coastguard Worker case Location::kStackSlot: // Fall-through
260*795d594fSAndroid Build Coastguard Worker case Location::kDoubleStackSlot: // Fall-through
261*795d594fSAndroid Build Coastguard Worker case Location::kConstant: {
262*795d594fSAndroid Build Coastguard Worker // Nothing to do.
263*795d594fSAndroid Build Coastguard Worker break;
264*795d594fSAndroid Build Coastguard Worker }
265*795d594fSAndroid Build Coastguard Worker default: {
266*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected location for object";
267*795d594fSAndroid Build Coastguard Worker }
268*795d594fSAndroid Build Coastguard Worker }
269*795d594fSAndroid Build Coastguard Worker }
270*795d594fSAndroid Build Coastguard Worker }
271*795d594fSAndroid Build Coastguard Worker }
272*795d594fSAndroid Build Coastguard Worker }
273*795d594fSAndroid Build Coastguard Worker
CalculateMaximumSafepointSpillSize(ArrayRef<HInstruction * const> safepoints)274*795d594fSAndroid Build Coastguard Worker size_t RegisterAllocationResolver::CalculateMaximumSafepointSpillSize(
275*795d594fSAndroid Build Coastguard Worker ArrayRef<HInstruction* const> safepoints) {
276*795d594fSAndroid Build Coastguard Worker size_t core_register_spill_size = codegen_->GetWordSize();
277*795d594fSAndroid Build Coastguard Worker size_t fp_register_spill_size = codegen_->GetSlowPathFPWidth();
278*795d594fSAndroid Build Coastguard Worker size_t maximum_safepoint_spill_size = 0u;
279*795d594fSAndroid Build Coastguard Worker for (HInstruction* instruction : safepoints) {
280*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
281*795d594fSAndroid Build Coastguard Worker if (locations->OnlyCallsOnSlowPath()) {
282*795d594fSAndroid Build Coastguard Worker size_t core_spills =
283*795d594fSAndroid Build Coastguard Worker codegen_->GetNumberOfSlowPathSpills(locations, /* core_registers= */ true);
284*795d594fSAndroid Build Coastguard Worker size_t fp_spills =
285*795d594fSAndroid Build Coastguard Worker codegen_->GetNumberOfSlowPathSpills(locations, /* core_registers= */ false);
286*795d594fSAndroid Build Coastguard Worker size_t spill_size =
287*795d594fSAndroid Build Coastguard Worker core_register_spill_size * core_spills + fp_register_spill_size * fp_spills;
288*795d594fSAndroid Build Coastguard Worker maximum_safepoint_spill_size = std::max(maximum_safepoint_spill_size, spill_size);
289*795d594fSAndroid Build Coastguard Worker } else if (locations->CallsOnMainAndSlowPath()) {
290*795d594fSAndroid Build Coastguard Worker // Nothing to spill on the slow path if the main path already clobbers caller-saves.
291*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, codegen_->GetNumberOfSlowPathSpills(locations, /* core_registers= */ true));
292*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, codegen_->GetNumberOfSlowPathSpills(locations, /* core_registers= */ false));
293*795d594fSAndroid Build Coastguard Worker }
294*795d594fSAndroid Build Coastguard Worker }
295*795d594fSAndroid Build Coastguard Worker return maximum_safepoint_spill_size;
296*795d594fSAndroid Build Coastguard Worker }
297*795d594fSAndroid Build Coastguard Worker
ConnectSiblings(LiveInterval * interval)298*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::ConnectSiblings(LiveInterval* interval) {
299*795d594fSAndroid Build Coastguard Worker LiveInterval* current = interval;
300*795d594fSAndroid Build Coastguard Worker if (current->HasSpillSlot()
301*795d594fSAndroid Build Coastguard Worker && current->HasRegister()
302*795d594fSAndroid Build Coastguard Worker // Currently, we spill unconditionnally the current method in the code generators.
303*795d594fSAndroid Build Coastguard Worker && !interval->GetDefinedBy()->IsCurrentMethod()) {
304*795d594fSAndroid Build Coastguard Worker // We spill eagerly, so move must be at definition.
305*795d594fSAndroid Build Coastguard Worker Location loc;
306*795d594fSAndroid Build Coastguard Worker size_t num_of_slots = interval->NumberOfSpillSlotsNeeded();
307*795d594fSAndroid Build Coastguard Worker loc = Location::StackSlotByNumOfSlots(num_of_slots, interval->GetParent()->GetSpillSlot());
308*795d594fSAndroid Build Coastguard Worker
309*795d594fSAndroid Build Coastguard Worker CHECK_IMPLIES(loc.IsSIMDStackSlot(),
310*795d594fSAndroid Build Coastguard Worker (codegen_->GetSIMDRegisterWidth() / kVRegSize == num_of_slots))
311*795d594fSAndroid Build Coastguard Worker << "Unexpected number of spill slots";
312*795d594fSAndroid Build Coastguard Worker InsertMoveAfter(interval->GetDefinedBy(), interval->ToLocation(), loc);
313*795d594fSAndroid Build Coastguard Worker }
314*795d594fSAndroid Build Coastguard Worker UsePositionList::const_iterator use_it = current->GetUses().begin();
315*795d594fSAndroid Build Coastguard Worker const UsePositionList::const_iterator use_end = current->GetUses().end();
316*795d594fSAndroid Build Coastguard Worker EnvUsePositionList::const_iterator env_use_it = current->GetEnvironmentUses().begin();
317*795d594fSAndroid Build Coastguard Worker const EnvUsePositionList::const_iterator env_use_end = current->GetEnvironmentUses().end();
318*795d594fSAndroid Build Coastguard Worker
319*795d594fSAndroid Build Coastguard Worker // Walk over all siblings, updating locations of use positions, and
320*795d594fSAndroid Build Coastguard Worker // connecting them when they are adjacent.
321*795d594fSAndroid Build Coastguard Worker do {
322*795d594fSAndroid Build Coastguard Worker Location source = current->ToLocation();
323*795d594fSAndroid Build Coastguard Worker
324*795d594fSAndroid Build Coastguard Worker // Walk over all uses covered by this interval, and update the location
325*795d594fSAndroid Build Coastguard Worker // information.
326*795d594fSAndroid Build Coastguard Worker
327*795d594fSAndroid Build Coastguard Worker LiveRange* range = current->GetFirstRange();
328*795d594fSAndroid Build Coastguard Worker while (range != nullptr) {
329*795d594fSAndroid Build Coastguard Worker // Process uses in the closed interval [range->GetStart(), range->GetEnd()].
330*795d594fSAndroid Build Coastguard Worker // FindMatchingUseRange() expects a half-open interval, so pass `range->GetEnd() + 1u`.
331*795d594fSAndroid Build Coastguard Worker size_t range_begin = range->GetStart();
332*795d594fSAndroid Build Coastguard Worker size_t range_end = range->GetEnd() + 1u;
333*795d594fSAndroid Build Coastguard Worker auto matching_use_range =
334*795d594fSAndroid Build Coastguard Worker FindMatchingUseRange(use_it, use_end, range_begin, range_end);
335*795d594fSAndroid Build Coastguard Worker DCHECK(std::all_of(use_it,
336*795d594fSAndroid Build Coastguard Worker matching_use_range.begin(),
337*795d594fSAndroid Build Coastguard Worker [](const UsePosition& pos) { return pos.IsSynthesized(); }));
338*795d594fSAndroid Build Coastguard Worker for (const UsePosition& use : matching_use_range) {
339*795d594fSAndroid Build Coastguard Worker DCHECK(current->CoversSlow(use.GetPosition()) || (use.GetPosition() == range->GetEnd()));
340*795d594fSAndroid Build Coastguard Worker if (!use.IsSynthesized()) {
341*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = use.GetUser()->GetLocations();
342*795d594fSAndroid Build Coastguard Worker Location expected_location = locations->InAt(use.GetInputIndex());
343*795d594fSAndroid Build Coastguard Worker // The expected (actual) location may be invalid in case the input is unused. Currently
344*795d594fSAndroid Build Coastguard Worker // this only happens for intrinsics.
345*795d594fSAndroid Build Coastguard Worker if (expected_location.IsValid()) {
346*795d594fSAndroid Build Coastguard Worker if (expected_location.IsUnallocated()) {
347*795d594fSAndroid Build Coastguard Worker locations->SetInAt(use.GetInputIndex(), source);
348*795d594fSAndroid Build Coastguard Worker } else if (!expected_location.IsConstant()) {
349*795d594fSAndroid Build Coastguard Worker AddInputMoveFor(
350*795d594fSAndroid Build Coastguard Worker interval->GetDefinedBy(), use.GetUser(), source, expected_location);
351*795d594fSAndroid Build Coastguard Worker }
352*795d594fSAndroid Build Coastguard Worker } else {
353*795d594fSAndroid Build Coastguard Worker DCHECK(use.GetUser()->IsInvoke());
354*795d594fSAndroid Build Coastguard Worker DCHECK(use.GetUser()->AsInvoke()->GetIntrinsic() != Intrinsics::kNone);
355*795d594fSAndroid Build Coastguard Worker }
356*795d594fSAndroid Build Coastguard Worker }
357*795d594fSAndroid Build Coastguard Worker }
358*795d594fSAndroid Build Coastguard Worker use_it = matching_use_range.end();
359*795d594fSAndroid Build Coastguard Worker
360*795d594fSAndroid Build Coastguard Worker // Walk over the environment uses, and update their locations.
361*795d594fSAndroid Build Coastguard Worker auto matching_env_use_range =
362*795d594fSAndroid Build Coastguard Worker FindMatchingUseRange(env_use_it, env_use_end, range_begin, range_end);
363*795d594fSAndroid Build Coastguard Worker for (const EnvUsePosition& env_use : matching_env_use_range) {
364*795d594fSAndroid Build Coastguard Worker DCHECK(current->CoversSlow(env_use.GetPosition())
365*795d594fSAndroid Build Coastguard Worker || (env_use.GetPosition() == range->GetEnd()));
366*795d594fSAndroid Build Coastguard Worker HEnvironment* environment = env_use.GetEnvironment();
367*795d594fSAndroid Build Coastguard Worker environment->SetLocationAt(env_use.GetInputIndex(), source);
368*795d594fSAndroid Build Coastguard Worker }
369*795d594fSAndroid Build Coastguard Worker env_use_it = matching_env_use_range.end();
370*795d594fSAndroid Build Coastguard Worker
371*795d594fSAndroid Build Coastguard Worker range = range->GetNext();
372*795d594fSAndroid Build Coastguard Worker }
373*795d594fSAndroid Build Coastguard Worker
374*795d594fSAndroid Build Coastguard Worker // If the next interval starts just after this one, and has a register,
375*795d594fSAndroid Build Coastguard Worker // insert a move.
376*795d594fSAndroid Build Coastguard Worker LiveInterval* next_sibling = current->GetNextSibling();
377*795d594fSAndroid Build Coastguard Worker if (next_sibling != nullptr
378*795d594fSAndroid Build Coastguard Worker && next_sibling->HasRegister()
379*795d594fSAndroid Build Coastguard Worker && current->GetEnd() == next_sibling->GetStart()) {
380*795d594fSAndroid Build Coastguard Worker Location destination = next_sibling->ToLocation();
381*795d594fSAndroid Build Coastguard Worker InsertParallelMoveAt(current->GetEnd(), interval->GetDefinedBy(), source, destination);
382*795d594fSAndroid Build Coastguard Worker }
383*795d594fSAndroid Build Coastguard Worker
384*795d594fSAndroid Build Coastguard Worker for (SafepointPosition* safepoint_position = current->GetFirstSafepoint();
385*795d594fSAndroid Build Coastguard Worker safepoint_position != nullptr;
386*795d594fSAndroid Build Coastguard Worker safepoint_position = safepoint_position->GetNext()) {
387*795d594fSAndroid Build Coastguard Worker DCHECK(current->CoversSlow(safepoint_position->GetPosition()));
388*795d594fSAndroid Build Coastguard Worker
389*795d594fSAndroid Build Coastguard Worker if (current->GetType() == DataType::Type::kReference) {
390*795d594fSAndroid Build Coastguard Worker DCHECK(interval->GetDefinedBy()->IsActualObject())
391*795d594fSAndroid Build Coastguard Worker << interval->GetDefinedBy()->DebugName()
392*795d594fSAndroid Build Coastguard Worker << '(' << interval->GetDefinedBy()->GetId() << ')'
393*795d594fSAndroid Build Coastguard Worker << "@" << safepoint_position->GetInstruction()->DebugName()
394*795d594fSAndroid Build Coastguard Worker << '(' << safepoint_position->GetInstruction()->GetId() << ')';
395*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = safepoint_position->GetLocations();
396*795d594fSAndroid Build Coastguard Worker if (current->GetParent()->HasSpillSlot()) {
397*795d594fSAndroid Build Coastguard Worker locations->SetStackBit(current->GetParent()->GetSpillSlot() / kVRegSize);
398*795d594fSAndroid Build Coastguard Worker }
399*795d594fSAndroid Build Coastguard Worker if (source.GetKind() == Location::kRegister) {
400*795d594fSAndroid Build Coastguard Worker locations->SetRegisterBit(source.reg());
401*795d594fSAndroid Build Coastguard Worker }
402*795d594fSAndroid Build Coastguard Worker }
403*795d594fSAndroid Build Coastguard Worker }
404*795d594fSAndroid Build Coastguard Worker current = next_sibling;
405*795d594fSAndroid Build Coastguard Worker } while (current != nullptr);
406*795d594fSAndroid Build Coastguard Worker
407*795d594fSAndroid Build Coastguard Worker // Following uses can only be synthesized uses.
408*795d594fSAndroid Build Coastguard Worker DCHECK(std::all_of(use_it, use_end, [](const UsePosition& pos) { return pos.IsSynthesized(); }));
409*795d594fSAndroid Build Coastguard Worker }
410*795d594fSAndroid Build Coastguard Worker
IsMaterializableEntryBlockInstructionOfGraphWithIrreducibleLoop(HInstruction * instruction)411*795d594fSAndroid Build Coastguard Worker static bool IsMaterializableEntryBlockInstructionOfGraphWithIrreducibleLoop(
412*795d594fSAndroid Build Coastguard Worker HInstruction* instruction) {
413*795d594fSAndroid Build Coastguard Worker return instruction->GetBlock()->GetGraph()->HasIrreducibleLoops() &&
414*795d594fSAndroid Build Coastguard Worker (instruction->IsConstant() || instruction->IsCurrentMethod());
415*795d594fSAndroid Build Coastguard Worker }
416*795d594fSAndroid Build Coastguard Worker
ConnectSplitSiblings(LiveInterval * interval,HBasicBlock * from,HBasicBlock * to) const417*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::ConnectSplitSiblings(LiveInterval* interval,
418*795d594fSAndroid Build Coastguard Worker HBasicBlock* from,
419*795d594fSAndroid Build Coastguard Worker HBasicBlock* to) const {
420*795d594fSAndroid Build Coastguard Worker if (interval->GetNextSibling() == nullptr) {
421*795d594fSAndroid Build Coastguard Worker // Nothing to connect. The whole range was allocated to the same location.
422*795d594fSAndroid Build Coastguard Worker return;
423*795d594fSAndroid Build Coastguard Worker }
424*795d594fSAndroid Build Coastguard Worker
425*795d594fSAndroid Build Coastguard Worker // Find the intervals that cover `from` and `to`.
426*795d594fSAndroid Build Coastguard Worker size_t destination_position = to->GetLifetimeStart();
427*795d594fSAndroid Build Coastguard Worker size_t source_position = from->GetLifetimeEnd() - 1;
428*795d594fSAndroid Build Coastguard Worker LiveInterval* destination = interval->GetSiblingAt(destination_position);
429*795d594fSAndroid Build Coastguard Worker LiveInterval* source = interval->GetSiblingAt(source_position);
430*795d594fSAndroid Build Coastguard Worker
431*795d594fSAndroid Build Coastguard Worker if (destination == source) {
432*795d594fSAndroid Build Coastguard Worker // Interval was not split.
433*795d594fSAndroid Build Coastguard Worker return;
434*795d594fSAndroid Build Coastguard Worker }
435*795d594fSAndroid Build Coastguard Worker
436*795d594fSAndroid Build Coastguard Worker LiveInterval* parent = interval->GetParent();
437*795d594fSAndroid Build Coastguard Worker HInstruction* defined_by = parent->GetDefinedBy();
438*795d594fSAndroid Build Coastguard Worker if (codegen_->GetGraph()->HasIrreducibleLoops() &&
439*795d594fSAndroid Build Coastguard Worker (destination == nullptr || !destination->CoversSlow(destination_position))) {
440*795d594fSAndroid Build Coastguard Worker // Our live_in fixed point calculation has found that the instruction is live
441*795d594fSAndroid Build Coastguard Worker // in the `to` block because it will eventually enter an irreducible loop. Our
442*795d594fSAndroid Build Coastguard Worker // live interval computation however does not compute a fixed point, and
443*795d594fSAndroid Build Coastguard Worker // therefore will not have a location for that instruction for `to`.
444*795d594fSAndroid Build Coastguard Worker // Because the instruction is a constant or the ArtMethod, we don't need to
445*795d594fSAndroid Build Coastguard Worker // do anything: it will be materialized in the irreducible loop.
446*795d594fSAndroid Build Coastguard Worker DCHECK(IsMaterializableEntryBlockInstructionOfGraphWithIrreducibleLoop(defined_by))
447*795d594fSAndroid Build Coastguard Worker << defined_by->DebugName() << ":" << defined_by->GetId()
448*795d594fSAndroid Build Coastguard Worker << " " << from->GetBlockId() << " -> " << to->GetBlockId();
449*795d594fSAndroid Build Coastguard Worker return;
450*795d594fSAndroid Build Coastguard Worker }
451*795d594fSAndroid Build Coastguard Worker
452*795d594fSAndroid Build Coastguard Worker if (!destination->HasRegister()) {
453*795d594fSAndroid Build Coastguard Worker // Values are eagerly spilled. Spill slot already contains appropriate value.
454*795d594fSAndroid Build Coastguard Worker return;
455*795d594fSAndroid Build Coastguard Worker }
456*795d594fSAndroid Build Coastguard Worker
457*795d594fSAndroid Build Coastguard Worker Location location_source;
458*795d594fSAndroid Build Coastguard Worker // `GetSiblingAt` returns the interval whose start and end cover `position`,
459*795d594fSAndroid Build Coastguard Worker // but does not check whether the interval is inactive at that position.
460*795d594fSAndroid Build Coastguard Worker // The only situation where the interval is inactive at that position is in the
461*795d594fSAndroid Build Coastguard Worker // presence of irreducible loops for constants and ArtMethod.
462*795d594fSAndroid Build Coastguard Worker if (codegen_->GetGraph()->HasIrreducibleLoops() &&
463*795d594fSAndroid Build Coastguard Worker (source == nullptr || !source->CoversSlow(source_position))) {
464*795d594fSAndroid Build Coastguard Worker DCHECK(IsMaterializableEntryBlockInstructionOfGraphWithIrreducibleLoop(defined_by));
465*795d594fSAndroid Build Coastguard Worker if (defined_by->IsConstant()) {
466*795d594fSAndroid Build Coastguard Worker location_source = defined_by->GetLocations()->Out();
467*795d594fSAndroid Build Coastguard Worker } else {
468*795d594fSAndroid Build Coastguard Worker DCHECK(defined_by->IsCurrentMethod());
469*795d594fSAndroid Build Coastguard Worker size_t num_of_slots = parent->NumberOfSpillSlotsNeeded();
470*795d594fSAndroid Build Coastguard Worker location_source = Location::StackSlotByNumOfSlots(num_of_slots, parent->GetSpillSlot());
471*795d594fSAndroid Build Coastguard Worker CHECK_IMPLIES(location_source.IsSIMDStackSlot(),
472*795d594fSAndroid Build Coastguard Worker (codegen_->GetSIMDRegisterWidth() == num_of_slots * kVRegSize))
473*795d594fSAndroid Build Coastguard Worker << "Unexpected number of spill slots";
474*795d594fSAndroid Build Coastguard Worker }
475*795d594fSAndroid Build Coastguard Worker } else {
476*795d594fSAndroid Build Coastguard Worker DCHECK(source != nullptr);
477*795d594fSAndroid Build Coastguard Worker DCHECK(source->CoversSlow(source_position));
478*795d594fSAndroid Build Coastguard Worker DCHECK(destination->CoversSlow(destination_position));
479*795d594fSAndroid Build Coastguard Worker location_source = source->ToLocation();
480*795d594fSAndroid Build Coastguard Worker }
481*795d594fSAndroid Build Coastguard Worker
482*795d594fSAndroid Build Coastguard Worker // If `from` has only one successor, we can put the moves at the exit of it. Otherwise
483*795d594fSAndroid Build Coastguard Worker // we need to put the moves at the entry of `to`.
484*795d594fSAndroid Build Coastguard Worker if (from->GetNormalSuccessors().size() == 1) {
485*795d594fSAndroid Build Coastguard Worker InsertParallelMoveAtExitOf(from,
486*795d594fSAndroid Build Coastguard Worker defined_by,
487*795d594fSAndroid Build Coastguard Worker location_source,
488*795d594fSAndroid Build Coastguard Worker destination->ToLocation());
489*795d594fSAndroid Build Coastguard Worker } else {
490*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(to->GetPredecessors().size(), 1u);
491*795d594fSAndroid Build Coastguard Worker InsertParallelMoveAtEntryOf(to,
492*795d594fSAndroid Build Coastguard Worker defined_by,
493*795d594fSAndroid Build Coastguard Worker location_source,
494*795d594fSAndroid Build Coastguard Worker destination->ToLocation());
495*795d594fSAndroid Build Coastguard Worker }
496*795d594fSAndroid Build Coastguard Worker }
497*795d594fSAndroid Build Coastguard Worker
IsValidDestination(Location destination)498*795d594fSAndroid Build Coastguard Worker static bool IsValidDestination(Location destination) {
499*795d594fSAndroid Build Coastguard Worker return destination.IsRegister()
500*795d594fSAndroid Build Coastguard Worker || destination.IsRegisterPair()
501*795d594fSAndroid Build Coastguard Worker || destination.IsFpuRegister()
502*795d594fSAndroid Build Coastguard Worker || destination.IsFpuRegisterPair()
503*795d594fSAndroid Build Coastguard Worker || destination.IsStackSlot()
504*795d594fSAndroid Build Coastguard Worker || destination.IsDoubleStackSlot()
505*795d594fSAndroid Build Coastguard Worker || destination.IsSIMDStackSlot();
506*795d594fSAndroid Build Coastguard Worker }
507*795d594fSAndroid Build Coastguard Worker
AddMove(HParallelMove * move,Location source,Location destination,HInstruction * instruction,DataType::Type type) const508*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::AddMove(HParallelMove* move,
509*795d594fSAndroid Build Coastguard Worker Location source,
510*795d594fSAndroid Build Coastguard Worker Location destination,
511*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
512*795d594fSAndroid Build Coastguard Worker DataType::Type type) const {
513*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64
514*795d594fSAndroid Build Coastguard Worker && codegen_->ShouldSplitLongMoves()
515*795d594fSAndroid Build Coastguard Worker // The parallel move resolver knows how to deal with long constants.
516*795d594fSAndroid Build Coastguard Worker && !source.IsConstant()) {
517*795d594fSAndroid Build Coastguard Worker move->AddMove(source.ToLow(), destination.ToLow(), DataType::Type::kInt32, instruction);
518*795d594fSAndroid Build Coastguard Worker move->AddMove(source.ToHigh(), destination.ToHigh(), DataType::Type::kInt32, nullptr);
519*795d594fSAndroid Build Coastguard Worker } else {
520*795d594fSAndroid Build Coastguard Worker move->AddMove(source, destination, type, instruction);
521*795d594fSAndroid Build Coastguard Worker }
522*795d594fSAndroid Build Coastguard Worker }
523*795d594fSAndroid Build Coastguard Worker
AddInputMoveFor(HInstruction * input,HInstruction * user,Location source,Location destination) const524*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::AddInputMoveFor(HInstruction* input,
525*795d594fSAndroid Build Coastguard Worker HInstruction* user,
526*795d594fSAndroid Build Coastguard Worker Location source,
527*795d594fSAndroid Build Coastguard Worker Location destination) const {
528*795d594fSAndroid Build Coastguard Worker if (source.Equals(destination)) return;
529*795d594fSAndroid Build Coastguard Worker
530*795d594fSAndroid Build Coastguard Worker DCHECK(!user->IsPhi());
531*795d594fSAndroid Build Coastguard Worker
532*795d594fSAndroid Build Coastguard Worker HInstruction* previous = user->GetPrevious();
533*795d594fSAndroid Build Coastguard Worker HParallelMove* move = nullptr;
534*795d594fSAndroid Build Coastguard Worker if (previous == nullptr ||
535*795d594fSAndroid Build Coastguard Worker !previous->IsParallelMove() ||
536*795d594fSAndroid Build Coastguard Worker previous->GetLifetimePosition() < user->GetLifetimePosition()) {
537*795d594fSAndroid Build Coastguard Worker move = new (allocator_) HParallelMove(allocator_);
538*795d594fSAndroid Build Coastguard Worker move->SetLifetimePosition(user->GetLifetimePosition());
539*795d594fSAndroid Build Coastguard Worker user->GetBlock()->InsertInstructionBefore(move, user);
540*795d594fSAndroid Build Coastguard Worker } else {
541*795d594fSAndroid Build Coastguard Worker move = previous->AsParallelMove();
542*795d594fSAndroid Build Coastguard Worker }
543*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(move->GetLifetimePosition(), user->GetLifetimePosition());
544*795d594fSAndroid Build Coastguard Worker AddMove(move, source, destination, nullptr, input->GetType());
545*795d594fSAndroid Build Coastguard Worker }
546*795d594fSAndroid Build Coastguard Worker
IsInstructionStart(size_t position)547*795d594fSAndroid Build Coastguard Worker static bool IsInstructionStart(size_t position) {
548*795d594fSAndroid Build Coastguard Worker return (position & 1) == 0;
549*795d594fSAndroid Build Coastguard Worker }
550*795d594fSAndroid Build Coastguard Worker
IsInstructionEnd(size_t position)551*795d594fSAndroid Build Coastguard Worker static bool IsInstructionEnd(size_t position) {
552*795d594fSAndroid Build Coastguard Worker return (position & 1) == 1;
553*795d594fSAndroid Build Coastguard Worker }
554*795d594fSAndroid Build Coastguard Worker
InsertParallelMoveAt(size_t position,HInstruction * instruction,Location source,Location destination) const555*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::InsertParallelMoveAt(size_t position,
556*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
557*795d594fSAndroid Build Coastguard Worker Location source,
558*795d594fSAndroid Build Coastguard Worker Location destination) const {
559*795d594fSAndroid Build Coastguard Worker DCHECK(IsValidDestination(destination)) << destination;
560*795d594fSAndroid Build Coastguard Worker if (source.Equals(destination)) return;
561*795d594fSAndroid Build Coastguard Worker
562*795d594fSAndroid Build Coastguard Worker HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
563*795d594fSAndroid Build Coastguard Worker HParallelMove* move;
564*795d594fSAndroid Build Coastguard Worker if (at == nullptr) {
565*795d594fSAndroid Build Coastguard Worker if (IsInstructionStart(position)) {
566*795d594fSAndroid Build Coastguard Worker // Block boundary, don't do anything the connection of split siblings will handle it.
567*795d594fSAndroid Build Coastguard Worker return;
568*795d594fSAndroid Build Coastguard Worker } else {
569*795d594fSAndroid Build Coastguard Worker // Move must happen before the first instruction of the block.
570*795d594fSAndroid Build Coastguard Worker at = liveness_.GetInstructionFromPosition((position + 1) / 2);
571*795d594fSAndroid Build Coastguard Worker // Note that parallel moves may have already been inserted, so we explicitly
572*795d594fSAndroid Build Coastguard Worker // ask for the first instruction of the block: `GetInstructionFromPosition` does
573*795d594fSAndroid Build Coastguard Worker // not contain the `HParallelMove` instructions.
574*795d594fSAndroid Build Coastguard Worker at = at->GetBlock()->GetFirstInstruction();
575*795d594fSAndroid Build Coastguard Worker
576*795d594fSAndroid Build Coastguard Worker if (at->GetLifetimePosition() < position) {
577*795d594fSAndroid Build Coastguard Worker // We may insert moves for split siblings and phi spills at the beginning of the block.
578*795d594fSAndroid Build Coastguard Worker // Since this is a different lifetime position, we need to go to the next instruction.
579*795d594fSAndroid Build Coastguard Worker DCHECK(at->IsParallelMove());
580*795d594fSAndroid Build Coastguard Worker at = at->GetNext();
581*795d594fSAndroid Build Coastguard Worker }
582*795d594fSAndroid Build Coastguard Worker
583*795d594fSAndroid Build Coastguard Worker if (at->GetLifetimePosition() != position) {
584*795d594fSAndroid Build Coastguard Worker DCHECK_GT(at->GetLifetimePosition(), position);
585*795d594fSAndroid Build Coastguard Worker move = new (allocator_) HParallelMove(allocator_);
586*795d594fSAndroid Build Coastguard Worker move->SetLifetimePosition(position);
587*795d594fSAndroid Build Coastguard Worker at->GetBlock()->InsertInstructionBefore(move, at);
588*795d594fSAndroid Build Coastguard Worker } else {
589*795d594fSAndroid Build Coastguard Worker DCHECK(at->IsParallelMove());
590*795d594fSAndroid Build Coastguard Worker move = at->AsParallelMove();
591*795d594fSAndroid Build Coastguard Worker }
592*795d594fSAndroid Build Coastguard Worker }
593*795d594fSAndroid Build Coastguard Worker } else if (IsInstructionEnd(position)) {
594*795d594fSAndroid Build Coastguard Worker // Move must happen after the instruction.
595*795d594fSAndroid Build Coastguard Worker DCHECK(!at->IsControlFlow());
596*795d594fSAndroid Build Coastguard Worker move = at->GetNext()->AsParallelMoveOrNull();
597*795d594fSAndroid Build Coastguard Worker // This is a parallel move for connecting siblings in a same block. We need to
598*795d594fSAndroid Build Coastguard Worker // differentiate it with moves for connecting blocks, and input moves.
599*795d594fSAndroid Build Coastguard Worker if (move == nullptr || move->GetLifetimePosition() > position) {
600*795d594fSAndroid Build Coastguard Worker move = new (allocator_) HParallelMove(allocator_);
601*795d594fSAndroid Build Coastguard Worker move->SetLifetimePosition(position);
602*795d594fSAndroid Build Coastguard Worker at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
603*795d594fSAndroid Build Coastguard Worker }
604*795d594fSAndroid Build Coastguard Worker } else {
605*795d594fSAndroid Build Coastguard Worker // Move must happen before the instruction.
606*795d594fSAndroid Build Coastguard Worker HInstruction* previous = at->GetPrevious();
607*795d594fSAndroid Build Coastguard Worker if (previous == nullptr ||
608*795d594fSAndroid Build Coastguard Worker !previous->IsParallelMove() ||
609*795d594fSAndroid Build Coastguard Worker previous->GetLifetimePosition() != position) {
610*795d594fSAndroid Build Coastguard Worker // If the previous is a parallel move, then its position must be lower
611*795d594fSAndroid Build Coastguard Worker // than the given `position`: it was added just after the non-parallel
612*795d594fSAndroid Build Coastguard Worker // move instruction that precedes `instruction`.
613*795d594fSAndroid Build Coastguard Worker DCHECK(previous == nullptr ||
614*795d594fSAndroid Build Coastguard Worker !previous->IsParallelMove() ||
615*795d594fSAndroid Build Coastguard Worker previous->GetLifetimePosition() < position);
616*795d594fSAndroid Build Coastguard Worker move = new (allocator_) HParallelMove(allocator_);
617*795d594fSAndroid Build Coastguard Worker move->SetLifetimePosition(position);
618*795d594fSAndroid Build Coastguard Worker at->GetBlock()->InsertInstructionBefore(move, at);
619*795d594fSAndroid Build Coastguard Worker } else {
620*795d594fSAndroid Build Coastguard Worker move = previous->AsParallelMove();
621*795d594fSAndroid Build Coastguard Worker }
622*795d594fSAndroid Build Coastguard Worker }
623*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(move->GetLifetimePosition(), position);
624*795d594fSAndroid Build Coastguard Worker AddMove(move, source, destination, instruction, instruction->GetType());
625*795d594fSAndroid Build Coastguard Worker }
626*795d594fSAndroid Build Coastguard Worker
InsertParallelMoveAtExitOf(HBasicBlock * block,HInstruction * instruction,Location source,Location destination) const627*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::InsertParallelMoveAtExitOf(HBasicBlock* block,
628*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
629*795d594fSAndroid Build Coastguard Worker Location source,
630*795d594fSAndroid Build Coastguard Worker Location destination) const {
631*795d594fSAndroid Build Coastguard Worker DCHECK(IsValidDestination(destination)) << destination;
632*795d594fSAndroid Build Coastguard Worker if (source.Equals(destination)) return;
633*795d594fSAndroid Build Coastguard Worker
634*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(block->GetNormalSuccessors().size(), 1u);
635*795d594fSAndroid Build Coastguard Worker HInstruction* last = block->GetLastInstruction();
636*795d594fSAndroid Build Coastguard Worker // We insert moves at exit for phi predecessors and connecting blocks.
637*795d594fSAndroid Build Coastguard Worker // A block ending with an if or a packed switch cannot branch to a block
638*795d594fSAndroid Build Coastguard Worker // with phis because we do not allow critical edges. It can also not connect
639*795d594fSAndroid Build Coastguard Worker // a split interval between two blocks: the move has to happen in the successor.
640*795d594fSAndroid Build Coastguard Worker DCHECK(!last->IsIf() && !last->IsPackedSwitch());
641*795d594fSAndroid Build Coastguard Worker HInstruction* previous = last->GetPrevious();
642*795d594fSAndroid Build Coastguard Worker HParallelMove* move;
643*795d594fSAndroid Build Coastguard Worker // This is a parallel move for connecting blocks. We need to differentiate
644*795d594fSAndroid Build Coastguard Worker // it with moves for connecting siblings in a same block, and output moves.
645*795d594fSAndroid Build Coastguard Worker size_t position = last->GetLifetimePosition();
646*795d594fSAndroid Build Coastguard Worker if (previous == nullptr ||
647*795d594fSAndroid Build Coastguard Worker !previous->IsParallelMove() ||
648*795d594fSAndroid Build Coastguard Worker previous->AsParallelMove()->GetLifetimePosition() != position) {
649*795d594fSAndroid Build Coastguard Worker move = new (allocator_) HParallelMove(allocator_);
650*795d594fSAndroid Build Coastguard Worker move->SetLifetimePosition(position);
651*795d594fSAndroid Build Coastguard Worker block->InsertInstructionBefore(move, last);
652*795d594fSAndroid Build Coastguard Worker } else {
653*795d594fSAndroid Build Coastguard Worker move = previous->AsParallelMove();
654*795d594fSAndroid Build Coastguard Worker }
655*795d594fSAndroid Build Coastguard Worker AddMove(move, source, destination, instruction, instruction->GetType());
656*795d594fSAndroid Build Coastguard Worker }
657*795d594fSAndroid Build Coastguard Worker
InsertParallelMoveAtEntryOf(HBasicBlock * block,HInstruction * instruction,Location source,Location destination) const658*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::InsertParallelMoveAtEntryOf(HBasicBlock* block,
659*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
660*795d594fSAndroid Build Coastguard Worker Location source,
661*795d594fSAndroid Build Coastguard Worker Location destination) const {
662*795d594fSAndroid Build Coastguard Worker DCHECK(IsValidDestination(destination)) << destination;
663*795d594fSAndroid Build Coastguard Worker if (source.Equals(destination)) return;
664*795d594fSAndroid Build Coastguard Worker
665*795d594fSAndroid Build Coastguard Worker HInstruction* first = block->GetFirstInstruction();
666*795d594fSAndroid Build Coastguard Worker HParallelMove* move = first->AsParallelMoveOrNull();
667*795d594fSAndroid Build Coastguard Worker size_t position = block->GetLifetimeStart();
668*795d594fSAndroid Build Coastguard Worker // This is a parallel move for connecting blocks. We need to differentiate
669*795d594fSAndroid Build Coastguard Worker // it with moves for connecting siblings in a same block, and input moves.
670*795d594fSAndroid Build Coastguard Worker if (move == nullptr || move->GetLifetimePosition() != position) {
671*795d594fSAndroid Build Coastguard Worker move = new (allocator_) HParallelMove(allocator_);
672*795d594fSAndroid Build Coastguard Worker move->SetLifetimePosition(position);
673*795d594fSAndroid Build Coastguard Worker block->InsertInstructionBefore(move, first);
674*795d594fSAndroid Build Coastguard Worker }
675*795d594fSAndroid Build Coastguard Worker AddMove(move, source, destination, instruction, instruction->GetType());
676*795d594fSAndroid Build Coastguard Worker }
677*795d594fSAndroid Build Coastguard Worker
InsertMoveAfter(HInstruction * instruction,Location source,Location destination) const678*795d594fSAndroid Build Coastguard Worker void RegisterAllocationResolver::InsertMoveAfter(HInstruction* instruction,
679*795d594fSAndroid Build Coastguard Worker Location source,
680*795d594fSAndroid Build Coastguard Worker Location destination) const {
681*795d594fSAndroid Build Coastguard Worker DCHECK(IsValidDestination(destination)) << destination;
682*795d594fSAndroid Build Coastguard Worker if (source.Equals(destination)) return;
683*795d594fSAndroid Build Coastguard Worker
684*795d594fSAndroid Build Coastguard Worker if (instruction->IsPhi()) {
685*795d594fSAndroid Build Coastguard Worker InsertParallelMoveAtEntryOf(instruction->GetBlock(), instruction, source, destination);
686*795d594fSAndroid Build Coastguard Worker return;
687*795d594fSAndroid Build Coastguard Worker }
688*795d594fSAndroid Build Coastguard Worker
689*795d594fSAndroid Build Coastguard Worker size_t position = instruction->GetLifetimePosition() + 1;
690*795d594fSAndroid Build Coastguard Worker HParallelMove* move = instruction->GetNext()->AsParallelMoveOrNull();
691*795d594fSAndroid Build Coastguard Worker // This is a parallel move for moving the output of an instruction. We need
692*795d594fSAndroid Build Coastguard Worker // to differentiate with input moves, moves for connecting siblings in a
693*795d594fSAndroid Build Coastguard Worker // and moves for connecting blocks.
694*795d594fSAndroid Build Coastguard Worker if (move == nullptr || move->GetLifetimePosition() != position) {
695*795d594fSAndroid Build Coastguard Worker move = new (allocator_) HParallelMove(allocator_);
696*795d594fSAndroid Build Coastguard Worker move->SetLifetimePosition(position);
697*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
698*795d594fSAndroid Build Coastguard Worker }
699*795d594fSAndroid Build Coastguard Worker AddMove(move, source, destination, instruction, instruction->GetType());
700*795d594fSAndroid Build Coastguard Worker }
701*795d594fSAndroid Build Coastguard Worker
702*795d594fSAndroid Build Coastguard Worker } // namespace art
703