blob: f4712425a0e189103d76b8156d4be4391de8682c [file] [log] [blame]
Nicolas Geoffray76716a62014-05-23 10:14:19 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_COMPILER_OPTIMIZING_LOCATIONS_H_
18#define ART_COMPILER_OPTIMIZING_LOCATIONS_H_
19
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010020#include "base/arena_containers.h"
Mathieu Chartierb666f482015-02-18 14:33:14 -080021#include "base/arena_object.h"
Nicolas Geoffray76716a62014-05-23 10:14:19 +010022#include "base/bit_field.h"
Vladimir Marko70e97462016-08-09 11:04:26 +010023#include "base/bit_utils.h"
Nicolas Geoffray39468442014-09-02 15:17:15 +010024#include "base/bit_vector.h"
Vladimir Markoe2727152019-10-10 10:46:42 +010025#include "base/macros.h"
Ian Rogers0279ebb2014-10-08 17:27:48 -070026#include "base/value_object.h"
Nicolas Geoffray76716a62014-05-23 10:14:19 +010027
Vladimir Markoe2727152019-10-10 10:46:42 +010028namespace art HIDDEN {
Nicolas Geoffray76716a62014-05-23 10:14:19 +010029
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010030class HConstant;
Nicolas Geoffray76716a62014-05-23 10:14:19 +010031class HInstruction;
Nicolas Geoffray424f6762014-11-03 14:51:25 +000032class Location;
33
34std::ostream& operator<<(std::ostream& os, const Location& location);
Nicolas Geoffray76716a62014-05-23 10:14:19 +010035
36/**
37 * A Location is an abstraction over the potential location
38 * of an instruction. It could be in register or stack.
39 */
Vladimir Marko76c92ac2015-09-17 15:39:16 +010040class Location : public ValueObject {
Nicolas Geoffray76716a62014-05-23 10:14:19 +010041 public:
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000042 enum OutputOverlap {
Roland Levillain3d312422016-06-23 13:53:42 +010043 // The liveness of the output overlaps the liveness of one or
44 // several input(s); the register allocator cannot reuse an
45 // input's location for the output's location.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000046 kOutputOverlap,
Roland Levillain3d312422016-06-23 13:53:42 +010047 // The liveness of the output does not overlap the liveness of any
48 // input; the register allocator is allowed to reuse an input's
49 // location for the output's location.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000050 kNoOutputOverlap
51 };
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +010052
Nicolas Geoffray76716a62014-05-23 10:14:19 +010053 enum Kind {
54 kInvalid = 0,
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010055 kConstant = 1,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010056 kStackSlot = 2, // 32bit stack slot.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010057 kDoubleStackSlot = 3, // 64bit stack slot.
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010058
59 kRegister = 4, // Core register.
60
61 // We do not use the value 5 because it conflicts with kLocationConstantMask.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010062 kDoNotUse5 = 5,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010063
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000064 kFpuRegister = 6, // Float register.
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010065
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000066 kRegisterPair = 7, // Long register.
67
68 kFpuRegisterPair = 8, // Double register.
69
70 // We do not use the value 9 because it conflicts with kLocationConstantMask.
71 kDoNotUse9 = 9,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010072
Aart Bik5576f372017-03-23 16:17:37 -070073 kSIMDStackSlot = 10, // 128bit stack slot. TODO: generalize with encoded #bytes?
74
Nicolas Geoffray76716a62014-05-23 10:14:19 +010075 // Unallocated location represents a location that is not fixed and can be
76 // allocated by a register allocator. Each unallocated location has
77 // a policy that specifies what kind of location is suitable. Payload
78 // contains register allocation policy.
Aart Bik5576f372017-03-23 16:17:37 -070079 kUnallocated = 11,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010080 };
81
Vladimir Marko76c92ac2015-09-17 15:39:16 +010082 Location() : ValueObject(), value_(kInvalid) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010083 // Verify that non-constant location kinds do not interfere with kConstant.
Andreas Gampe785d2f22014-11-03 22:57:30 -080084 static_assert((kInvalid & kLocationConstantMask) != kConstant, "TagError");
85 static_assert((kUnallocated & kLocationConstantMask) != kConstant, "TagError");
86 static_assert((kStackSlot & kLocationConstantMask) != kConstant, "TagError");
87 static_assert((kDoubleStackSlot & kLocationConstantMask) != kConstant, "TagError");
Aart Bik5576f372017-03-23 16:17:37 -070088 static_assert((kSIMDStackSlot & kLocationConstantMask) != kConstant, "TagError");
Andreas Gampe785d2f22014-11-03 22:57:30 -080089 static_assert((kRegister & kLocationConstantMask) != kConstant, "TagError");
Andreas Gampe785d2f22014-11-03 22:57:30 -080090 static_assert((kFpuRegister & kLocationConstantMask) != kConstant, "TagError");
91 static_assert((kRegisterPair & kLocationConstantMask) != kConstant, "TagError");
92 static_assert((kFpuRegisterPair & kLocationConstantMask) != kConstant, "TagError");
93 static_assert((kConstant & kLocationConstantMask) == kConstant, "TagError");
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010094
Nicolas Geoffray76716a62014-05-23 10:14:19 +010095 DCHECK(!IsValid());
96 }
97
Andreas Gampe2e6f38a2016-11-03 14:06:20 -070098 Location(const Location& other) = default;
Nicolas Geoffray76716a62014-05-23 10:14:19 +010099
Andreas Gampe2e6f38a2016-11-03 14:06:20 -0700100 Location& operator=(const Location& other) = default;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100101
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100102 bool IsConstant() const {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100103 return (value_ & kLocationConstantMask) == kConstant;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100104 }
105
106 static Location ConstantLocation(HConstant* constant) {
107 DCHECK(constant != nullptr);
Ian Rogers13735952014-10-08 12:43:28 -0700108 return Location(kConstant | reinterpret_cast<uintptr_t>(constant));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100109 }
110
111 HConstant* GetConstant() const {
112 DCHECK(IsConstant());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100113 return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100114 }
115
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100116 bool IsValid() const {
117 return value_ != kInvalid;
118 }
119
120 bool IsInvalid() const {
121 return !IsValid();
122 }
123
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100124 // Empty location. Used if there the location should be ignored.
125 static Location NoLocation() {
126 return Location();
127 }
128
129 // Register locations.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100130 static Location RegisterLocation(int reg) {
131 return Location(kRegister, reg);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100132 }
133
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100134 static Location FpuRegisterLocation(int reg) {
135 return Location(kFpuRegister, reg);
136 }
137
138 static Location RegisterPairLocation(int low, int high) {
139 return Location(kRegisterPair, low << 16 | high);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100140 }
141
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000142 static Location FpuRegisterPairLocation(int low, int high) {
143 return Location(kFpuRegisterPair, low << 16 | high);
144 }
145
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100146 bool IsRegister() const {
147 return GetKind() == kRegister;
148 }
149
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100150 bool IsFpuRegister() const {
151 return GetKind() == kFpuRegister;
152 }
153
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100154 bool IsRegisterPair() const {
155 return GetKind() == kRegisterPair;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100156 }
157
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000158 bool IsFpuRegisterPair() const {
159 return GetKind() == kFpuRegisterPair;
160 }
161
Nicolas Geoffrayda02afe2015-02-11 02:29:42 +0000162 bool IsRegisterKind() const {
163 return IsRegister() || IsFpuRegister() || IsRegisterPair() || IsFpuRegisterPair();
164 }
165
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100166 int reg() const {
167 DCHECK(IsRegister() || IsFpuRegister());
168 return GetPayload();
169 }
170
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000171 int low() const {
172 DCHECK(IsPair());
173 return GetPayload() >> 16;
174 }
175
176 int high() const {
177 DCHECK(IsPair());
178 return GetPayload() & 0xFFFF;
179 }
180
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100181 template <typename T>
Roland Levillain271ab9c2014-11-27 15:23:57 +0000182 T AsRegister() const {
183 DCHECK(IsRegister());
184 return static_cast<T>(reg());
185 }
186
187 template <typename T>
188 T AsFpuRegister() const {
189 DCHECK(IsFpuRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100190 return static_cast<T>(reg());
191 }
192
193 template <typename T>
194 T AsRegisterPairLow() const {
195 DCHECK(IsRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000196 return static_cast<T>(low());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100197 }
198
199 template <typename T>
200 T AsRegisterPairHigh() const {
201 DCHECK(IsRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000202 return static_cast<T>(high());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100203 }
204
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000205 template <typename T>
206 T AsFpuRegisterPairLow() const {
207 DCHECK(IsFpuRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000208 return static_cast<T>(low());
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000209 }
210
211 template <typename T>
212 T AsFpuRegisterPairHigh() const {
213 DCHECK(IsFpuRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000214 return static_cast<T>(high());
215 }
216
217 bool IsPair() const {
218 return IsRegisterPair() || IsFpuRegisterPair();
219 }
220
221 Location ToLow() const {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000222 if (IsRegisterPair()) {
223 return Location::RegisterLocation(low());
224 } else if (IsFpuRegisterPair()) {
225 return Location::FpuRegisterLocation(low());
226 } else {
227 DCHECK(IsDoubleStackSlot());
228 return Location::StackSlot(GetStackIndex());
229 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000230 }
231
232 Location ToHigh() const {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000233 if (IsRegisterPair()) {
234 return Location::RegisterLocation(high());
235 } else if (IsFpuRegisterPair()) {
236 return Location::FpuRegisterLocation(high());
237 } else {
238 DCHECK(IsDoubleStackSlot());
239 return Location::StackSlot(GetHighStackIndex(4));
240 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000241 }
242
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100243 static uintptr_t EncodeStackIndex(intptr_t stack_index) {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100244 DCHECK(-kStackIndexBias <= stack_index);
245 DCHECK(stack_index < kStackIndexBias);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100246 return static_cast<uintptr_t>(kStackIndexBias + stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100247 }
248
249 static Location StackSlot(intptr_t stack_index) {
Ian Rogers13735952014-10-08 12:43:28 -0700250 uintptr_t payload = EncodeStackIndex(stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100251 Location loc(kStackSlot, payload);
252 // Ensure that sign is preserved.
253 DCHECK_EQ(loc.GetStackIndex(), stack_index);
254 return loc;
255 }
256
257 bool IsStackSlot() const {
258 return GetKind() == kStackSlot;
259 }
260
261 static Location DoubleStackSlot(intptr_t stack_index) {
Ian Rogers13735952014-10-08 12:43:28 -0700262 uintptr_t payload = EncodeStackIndex(stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100263 Location loc(kDoubleStackSlot, payload);
264 // Ensure that sign is preserved.
265 DCHECK_EQ(loc.GetStackIndex(), stack_index);
266 return loc;
267 }
268
269 bool IsDoubleStackSlot() const {
270 return GetKind() == kDoubleStackSlot;
271 }
272
Aart Bik5576f372017-03-23 16:17:37 -0700273 static Location SIMDStackSlot(intptr_t stack_index) {
274 uintptr_t payload = EncodeStackIndex(stack_index);
275 Location loc(kSIMDStackSlot, payload);
276 // Ensure that sign is preserved.
277 DCHECK_EQ(loc.GetStackIndex(), stack_index);
278 return loc;
279 }
280
281 bool IsSIMDStackSlot() const {
282 return GetKind() == kSIMDStackSlot;
283 }
284
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100285 intptr_t GetStackIndex() const {
Aart Bik5576f372017-03-23 16:17:37 -0700286 DCHECK(IsStackSlot() || IsDoubleStackSlot() || IsSIMDStackSlot());
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100287 // Decode stack index manually to preserve sign.
288 return GetPayload() - kStackIndexBias;
289 }
290
291 intptr_t GetHighStackIndex(uintptr_t word_size) const {
292 DCHECK(IsDoubleStackSlot());
293 // Decode stack index manually to preserve sign.
294 return GetPayload() - kStackIndexBias + word_size;
295 }
296
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100297 Kind GetKind() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100298 return IsConstant() ? kConstant : KindField::Decode(value_);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100299 }
300
301 bool Equals(Location other) const {
302 return value_ == other.value_;
303 }
304
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000305 bool Contains(Location other) const {
306 if (Equals(other)) {
307 return true;
Zheng Xuad4450e2015-04-17 18:48:56 +0800308 } else if (IsPair() || IsDoubleStackSlot()) {
309 return ToLow().Equals(other) || ToHigh().Equals(other);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000310 }
311 return false;
312 }
313
Zheng Xuad4450e2015-04-17 18:48:56 +0800314 bool OverlapsWith(Location other) const {
315 // Only check the overlapping case that can happen with our register allocation algorithm.
316 bool overlap = Contains(other) || other.Contains(*this);
317 if (kIsDebugBuild && !overlap) {
318 // Note: These are also overlapping cases. But we are not able to handle them in
319 // ParallelMoveResolverWithSwap. Make sure that we do not meet such case with our compiler.
320 if ((IsPair() && other.IsPair()) || (IsDoubleStackSlot() && other.IsDoubleStackSlot())) {
321 DCHECK(!Contains(other.ToLow()));
322 DCHECK(!Contains(other.ToHigh()));
323 }
324 }
325 return overlap;
326 }
327
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100328 const char* DebugString() const {
329 switch (GetKind()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100330 case kInvalid: return "I";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100331 case kRegister: return "R";
332 case kStackSlot: return "S";
333 case kDoubleStackSlot: return "DS";
Aart Bik5576f372017-03-23 16:17:37 -0700334 case kSIMDStackSlot: return "SIMD";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100335 case kUnallocated: return "U";
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100336 case kConstant: return "C";
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100337 case kFpuRegister: return "F";
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100338 case kRegisterPair: return "RP";
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000339 case kFpuRegisterPair: return "FP";
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100340 case kDoNotUse5: // fall-through
341 case kDoNotUse9:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100342 LOG(FATAL) << "Should not use this location kind";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100343 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100344 UNREACHABLE();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100345 }
346
347 // Unallocated locations.
348 enum Policy {
349 kAny,
350 kRequiresRegister,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100351 kRequiresFpuRegister,
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100352 kSameAsFirstInput,
353 };
354
355 bool IsUnallocated() const {
356 return GetKind() == kUnallocated;
357 }
358
359 static Location UnallocatedLocation(Policy policy) {
360 return Location(kUnallocated, PolicyField::Encode(policy));
361 }
362
363 // Any free register is suitable to replace this unallocated location.
364 static Location Any() {
365 return UnallocatedLocation(kAny);
366 }
367
368 static Location RequiresRegister() {
369 return UnallocatedLocation(kRequiresRegister);
370 }
371
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100372 static Location RequiresFpuRegister() {
373 return UnallocatedLocation(kRequiresFpuRegister);
374 }
375
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100376 static Location RegisterOrConstant(HInstruction* instruction);
Mark Mendellea5af682015-10-22 17:35:49 -0400377 static Location RegisterOrInt32Constant(HInstruction* instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100378 static Location ByteRegisterOrConstant(int reg, HInstruction* instruction);
Mark Mendellea5af682015-10-22 17:35:49 -0400379 static Location FpuRegisterOrConstant(HInstruction* instruction);
380 static Location FpuRegisterOrInt32Constant(HInstruction* instruction);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100381
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100382 // The location of the first input to the instruction will be
383 // used to replace this unallocated location.
384 static Location SameAsFirstInput() {
385 return UnallocatedLocation(kSameAsFirstInput);
386 }
387
388 Policy GetPolicy() const {
389 DCHECK(IsUnallocated());
390 return PolicyField::Decode(GetPayload());
391 }
392
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700393 bool RequiresRegisterKind() const {
394 return GetPolicy() == kRequiresRegister || GetPolicy() == kRequiresFpuRegister;
395 }
396
Ian Rogers13735952014-10-08 12:43:28 -0700397 uintptr_t GetEncoding() const {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100398 return GetPayload();
399 }
400
401 private:
402 // Number of bits required to encode Kind value.
403 static constexpr uint32_t kBitsForKind = 4;
Ian Rogers13735952014-10-08 12:43:28 -0700404 static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind;
405 static constexpr uintptr_t kLocationConstantMask = 0x3;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100406
Ian Rogers13735952014-10-08 12:43:28 -0700407 explicit Location(uintptr_t value) : value_(value) {}
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100408
Ian Rogers13735952014-10-08 12:43:28 -0700409 Location(Kind kind, uintptr_t payload)
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100410 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
411
Ian Rogers13735952014-10-08 12:43:28 -0700412 uintptr_t GetPayload() const {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100413 return PayloadField::Decode(value_);
414 }
415
416 typedef BitField<Kind, 0, kBitsForKind> KindField;
Ian Rogers13735952014-10-08 12:43:28 -0700417 typedef BitField<uintptr_t, kBitsForKind, kBitsForPayload> PayloadField;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100418
419 // Layout for kUnallocated locations payload.
420 typedef BitField<Policy, 0, 3> PolicyField;
421
422 // Layout for stack slots.
423 static const intptr_t kStackIndexBias =
424 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
425
426 // Location either contains kind and payload fields or a tagged handle for
427 // a constant locations. Values of enumeration Kind are selected in such a
428 // way that none of them can be interpreted as a kConstant tag.
Ian Rogers13735952014-10-08 12:43:28 -0700429 uintptr_t value_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100430};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700431std::ostream& operator<<(std::ostream& os, const Location::Kind& rhs);
432std::ostream& operator<<(std::ostream& os, const Location::Policy& rhs);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100433
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100434class RegisterSet : public ValueObject {
435 public:
Vladimir Marko804b03f2016-09-14 16:26:36 +0100436 static RegisterSet Empty() { return RegisterSet(); }
Aart Bikb13c65b2017-03-21 20:14:07 -0700437 static RegisterSet AllFpu() { return RegisterSet(0, -1); }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100438
439 void Add(Location loc) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100440 if (loc.IsRegister()) {
441 core_registers_ |= (1 << loc.reg());
442 } else {
443 DCHECK(loc.IsFpuRegister());
444 floating_point_registers_ |= (1 << loc.reg());
445 }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100446 }
447
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100448 void Remove(Location loc) {
449 if (loc.IsRegister()) {
450 core_registers_ &= ~(1 << loc.reg());
451 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000452 DCHECK(loc.IsFpuRegister()) << loc;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100453 floating_point_registers_ &= ~(1 << loc.reg());
454 }
455 }
456
Nicolas Geoffray45b83af2015-07-06 15:12:53 +0000457 bool ContainsCoreRegister(uint32_t id) const {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100458 return Contains(core_registers_, id);
459 }
460
Nicolas Geoffray45b83af2015-07-06 15:12:53 +0000461 bool ContainsFloatingPointRegister(uint32_t id) const {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100462 return Contains(floating_point_registers_, id);
463 }
464
465 static bool Contains(uint32_t register_set, uint32_t reg) {
466 return (register_set & (1 << reg)) != 0;
467 }
468
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000469 size_t GetNumberOfRegisters() const {
Vladimir Marko70e97462016-08-09 11:04:26 +0100470 return POPCOUNT(core_registers_) + POPCOUNT(floating_point_registers_);
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000471 }
472
Nicolas Geoffray98893962015-01-21 12:32:32 +0000473 uint32_t GetCoreRegisters() const {
474 return core_registers_;
475 }
476
477 uint32_t GetFloatingPointRegisters() const {
478 return floating_point_registers_;
479 }
480
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100481 private:
Vladimir Marko804b03f2016-09-14 16:26:36 +0100482 RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
Aart Bikb13c65b2017-03-21 20:14:07 -0700483 RegisterSet(uint32_t core, uint32_t fp) : core_registers_(core), floating_point_registers_(fp) {}
Vladimir Marko804b03f2016-09-14 16:26:36 +0100484
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100485 uint32_t core_registers_;
486 uint32_t floating_point_registers_;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100487};
488
Andreas Gampe878d58c2015-01-15 23:24:00 -0800489static constexpr bool kIntrinsified = true;
490
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100491/**
492 * The code generator computes LocationSummary for each instruction so that
493 * the instruction itself knows what code to generate: where to find the inputs
494 * and where to place the result.
495 *
496 * The intent is to have the code for generating the instruction independent of
497 * register allocation. A register allocator just has to provide a LocationSummary.
498 */
Vladimir Marko5233f932015-09-29 19:01:15 +0100499class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100500 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100501 enum CallKind {
502 kNoCall,
Serban Constantinescu806f0122016-03-09 11:10:16 +0000503 kCallOnMainAndSlowPath,
Nicolas Geoffray39468442014-09-02 15:17:15 +0100504 kCallOnSlowPath,
Serban Constantinescu54ff4822016-07-07 18:03:19 +0100505 kCallOnMainOnly
Nicolas Geoffray39468442014-09-02 15:17:15 +0100506 };
507
Chih-Hung Hsieha5931182016-09-01 15:08:13 -0700508 explicit LocationSummary(HInstruction* instruction,
509 CallKind call_kind = kNoCall,
510 bool intrinsified = false);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100511
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100512 void SetInAt(uint32_t at, Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100513 inputs_[at] = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100514 }
515
516 Location InAt(uint32_t at) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100517 return inputs_[at];
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100518 }
519
520 size_t GetInputCount() const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100521 return inputs_.size();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100522 }
523
Roland Levillain3d312422016-06-23 13:53:42 +0100524 // Set the output location. Argument `overlaps` tells whether the
525 // output overlaps any of the inputs (if so, it cannot share the
526 // same register as one of the inputs); it is set to
527 // `Location::kOutputOverlap` by default for safety.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000528 void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000529 DCHECK(output_.IsInvalid());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100530 output_overlaps_ = overlaps;
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000531 output_ = location;
532 }
533
534 void UpdateOut(Location location) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000535 // There are two reasons for updating an output:
536 // 1) Parameters, where we only know the exact stack slot after
537 // doing full register allocation.
538 // 2) Unallocated location.
539 DCHECK(output_.IsStackSlot() || output_.IsDoubleStackSlot() || output_.IsUnallocated());
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000540 output_ = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100541 }
542
543 void AddTemp(Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100544 temps_.push_back(location);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100545 }
546
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -0700547 void AddRegisterTemps(size_t count) {
548 for (size_t i = 0; i < count; ++i) {
549 AddTemp(Location::RequiresRegister());
550 }
551 }
552
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100553 Location GetTemp(uint32_t at) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100554 return temps_[at];
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100555 }
556
557 void SetTempAt(uint32_t at, Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100558 DCHECK(temps_[at].IsUnallocated() || temps_[at].IsInvalid());
559 temps_[at] = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100560 }
561
562 size_t GetTempCount() const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100563 return temps_.size();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100564 }
565
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100566 bool HasTemps() const { return !temps_.empty(); }
Nicolas Geoffray94015b92015-06-04 18:21:04 +0100567
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100568 Location Out() const { return output_; }
569
Serban Constantinescu806f0122016-03-09 11:10:16 +0000570 bool CanCall() const {
571 return call_kind_ != kNoCall;
572 }
573
574 bool WillCall() const {
575 return call_kind_ == kCallOnMainOnly || call_kind_ == kCallOnMainAndSlowPath;
576 }
577
578 bool CallsOnSlowPath() const {
579 return call_kind_ == kCallOnSlowPath || call_kind_ == kCallOnMainAndSlowPath;
580 }
581
582 bool OnlyCallsOnSlowPath() const {
583 return call_kind_ == kCallOnSlowPath;
584 }
585
586 bool CallsOnMainAndSlowPath() const {
587 return call_kind_ == kCallOnMainAndSlowPath;
588 }
589
590 bool NeedsSafepoint() const {
591 return CanCall();
592 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100593
Vladimir Marko70e97462016-08-09 11:04:26 +0100594 void SetCustomSlowPathCallerSaves(const RegisterSet& caller_saves) {
595 DCHECK(OnlyCallsOnSlowPath());
596 has_custom_slow_path_calling_convention_ = true;
597 custom_slow_path_caller_saves_ = caller_saves;
598 }
599
600 bool HasCustomSlowPathCallingConvention() const {
601 return has_custom_slow_path_calling_convention_;
602 }
603
604 const RegisterSet& GetCustomSlowPathCallerSaves() const {
605 DCHECK(HasCustomSlowPathCallingConvention());
606 return custom_slow_path_caller_saves_;
607 }
608
Nicolas Geoffray39468442014-09-02 15:17:15 +0100609 void SetStackBit(uint32_t index) {
610 stack_mask_->SetBit(index);
611 }
612
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100613 void ClearStackBit(uint32_t index) {
614 stack_mask_->ClearBit(index);
615 }
616
Nicolas Geoffray39468442014-09-02 15:17:15 +0100617 void SetRegisterBit(uint32_t reg_id) {
618 register_mask_ |= (1 << reg_id);
619 }
620
Nicolas Geoffray98893962015-01-21 12:32:32 +0000621 uint32_t GetRegisterMask() const {
622 return register_mask_;
623 }
624
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100625 bool RegisterContainsObject(uint32_t reg_id) {
626 return RegisterSet::Contains(register_mask_, reg_id);
627 }
628
629 void AddLiveRegister(Location location) {
630 live_registers_.Add(location);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100631 }
632
633 BitVector* GetStackMask() const {
634 return stack_mask_;
635 }
636
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100637 RegisterSet* GetLiveRegisters() {
638 return &live_registers_;
639 }
640
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000641 size_t GetNumberOfLiveRegisters() const {
642 return live_registers_.GetNumberOfRegisters();
643 }
644
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000645 bool OutputUsesSameAs(uint32_t input_index) const {
646 return (input_index == 0)
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100647 && output_.IsUnallocated()
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000648 && (output_.GetPolicy() == Location::kSameAsFirstInput);
649 }
650
651 bool IsFixedInput(uint32_t input_index) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100652 Location input = inputs_[input_index];
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000653 return input.IsRegister()
Nicolas Geoffray98893962015-01-21 12:32:32 +0000654 || input.IsFpuRegister()
655 || input.IsPair()
656 || input.IsStackSlot()
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000657 || input.IsDoubleStackSlot();
Nicolas Geoffray76905622014-09-25 14:39:26 +0100658 }
659
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000660 bool OutputCanOverlapWithInputs() const {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000661 return output_overlaps_ == Location::kOutputOverlap;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100662 }
663
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800664 bool Intrinsified() const {
665 return intrinsified_;
666 }
667
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100668 private:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100669 LocationSummary(HInstruction* instruction,
670 CallKind call_kind,
671 bool intrinsified,
672 ArenaAllocator* allocator);
673
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100674 ArenaVector<Location> inputs_;
675 ArenaVector<Location> temps_;
Vladimir Marko70e97462016-08-09 11:04:26 +0100676 const CallKind call_kind_;
677 // Whether these are locations for an intrinsified call.
678 const bool intrinsified_;
679 // Whether the slow path has default or custom calling convention.
680 bool has_custom_slow_path_calling_convention_;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100681 // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot
682 // share the same register as the inputs.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000683 Location::OutputOverlap output_overlaps_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100684 Location output_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100685
686 // Mask of objects that live in the stack.
687 BitVector* stack_mask_;
688
689 // Mask of objects that live in register.
690 uint32_t register_mask_;
691
692 // Registers that are in use at this position.
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100693 RegisterSet live_registers_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100694
Vladimir Marko70e97462016-08-09 11:04:26 +0100695 // Custom slow path caller saves. Valid only if indicated by slow_path_calling_convention_.
696 RegisterSet custom_slow_path_caller_saves_;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800697
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700698 friend class RegisterAllocatorTest;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100699 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
700};
701
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100702} // namespace art
703
704#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_