blob: 20099ebbc2901ad06b9ef8153eb42f7aa2a22f66 [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"
Vladimír Marko434d9682022-11-04 14:04:17 +000025#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
Vladimír Marko434d9682022-11-04 14:04:17 +000028namespace 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 Markoaf06af42023-10-31 10:02:46 +000082 constexpr 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
Vladimir Markoaf06af42023-10-31 10:02:46 +000098 constexpr 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
Vladimir Markof76ca8c2023-04-05 15:24:41 +0000106 static Location ConstantLocation(HInstruction* constant) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100107 DCHECK(constant != nullptr);
Vladimir Markof76ca8c2023-04-05 15:24:41 +0000108 if (kIsDebugBuild) {
109 // Call out-of-line helper to avoid circular dependency with `nodes.h`.
110 DCheckInstructionIsConstant(constant);
111 }
Ian Rogers13735952014-10-08 12:43:28 -0700112 return Location(kConstant | reinterpret_cast<uintptr_t>(constant));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100113 }
114
115 HConstant* GetConstant() const {
116 DCHECK(IsConstant());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100117 return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100118 }
119
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100120 bool IsValid() const {
121 return value_ != kInvalid;
122 }
123
124 bool IsInvalid() const {
125 return !IsValid();
126 }
127
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100128 // Empty location. Used if there the location should be ignored.
Vladimir Markoaf06af42023-10-31 10:02:46 +0000129 static constexpr Location NoLocation() {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100130 return Location();
131 }
132
133 // Register locations.
Vladimir Markoaf06af42023-10-31 10:02:46 +0000134 static constexpr Location RegisterLocation(int reg) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100135 return Location(kRegister, reg);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100136 }
137
Vladimir Markoaf06af42023-10-31 10:02:46 +0000138 static constexpr Location FpuRegisterLocation(int reg) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100139 return Location(kFpuRegister, reg);
140 }
141
Vladimir Markoaf06af42023-10-31 10:02:46 +0000142 static constexpr Location RegisterPairLocation(int low, int high) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100143 return Location(kRegisterPair, low << 16 | high);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100144 }
145
Vladimir Markoaf06af42023-10-31 10:02:46 +0000146 static constexpr Location FpuRegisterPairLocation(int low, int high) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000147 return Location(kFpuRegisterPair, low << 16 | high);
148 }
149
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100150 bool IsRegister() const {
151 return GetKind() == kRegister;
152 }
153
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100154 bool IsFpuRegister() const {
155 return GetKind() == kFpuRegister;
156 }
157
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100158 bool IsRegisterPair() const {
159 return GetKind() == kRegisterPair;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100160 }
161
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000162 bool IsFpuRegisterPair() const {
163 return GetKind() == kFpuRegisterPair;
164 }
165
Nicolas Geoffrayda02afe2015-02-11 02:29:42 +0000166 bool IsRegisterKind() const {
167 return IsRegister() || IsFpuRegister() || IsRegisterPair() || IsFpuRegisterPair();
168 }
169
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100170 int reg() const {
171 DCHECK(IsRegister() || IsFpuRegister());
172 return GetPayload();
173 }
174
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000175 int low() const {
176 DCHECK(IsPair());
177 return GetPayload() >> 16;
178 }
179
180 int high() const {
181 DCHECK(IsPair());
182 return GetPayload() & 0xFFFF;
183 }
184
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100185 template <typename T>
Roland Levillain271ab9c2014-11-27 15:23:57 +0000186 T AsRegister() const {
187 DCHECK(IsRegister());
188 return static_cast<T>(reg());
189 }
190
191 template <typename T>
192 T AsFpuRegister() const {
193 DCHECK(IsFpuRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100194 return static_cast<T>(reg());
195 }
196
197 template <typename T>
198 T AsRegisterPairLow() const {
199 DCHECK(IsRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000200 return static_cast<T>(low());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100201 }
202
203 template <typename T>
204 T AsRegisterPairHigh() const {
205 DCHECK(IsRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000206 return static_cast<T>(high());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100207 }
208
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000209 template <typename T>
210 T AsFpuRegisterPairLow() const {
211 DCHECK(IsFpuRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000212 return static_cast<T>(low());
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000213 }
214
215 template <typename T>
216 T AsFpuRegisterPairHigh() const {
217 DCHECK(IsFpuRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000218 return static_cast<T>(high());
219 }
220
221 bool IsPair() const {
222 return IsRegisterPair() || IsFpuRegisterPair();
223 }
224
225 Location ToLow() const {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000226 if (IsRegisterPair()) {
227 return Location::RegisterLocation(low());
228 } else if (IsFpuRegisterPair()) {
229 return Location::FpuRegisterLocation(low());
230 } else {
231 DCHECK(IsDoubleStackSlot());
232 return Location::StackSlot(GetStackIndex());
233 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000234 }
235
236 Location ToHigh() const {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000237 if (IsRegisterPair()) {
238 return Location::RegisterLocation(high());
239 } else if (IsFpuRegisterPair()) {
240 return Location::FpuRegisterLocation(high());
241 } else {
242 DCHECK(IsDoubleStackSlot());
243 return Location::StackSlot(GetHighStackIndex(4));
244 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000245 }
246
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100247 static uintptr_t EncodeStackIndex(intptr_t stack_index) {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100248 DCHECK(-kStackIndexBias <= stack_index);
249 DCHECK(stack_index < kStackIndexBias);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100250 return static_cast<uintptr_t>(kStackIndexBias + stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100251 }
252
253 static Location StackSlot(intptr_t stack_index) {
Ian Rogers13735952014-10-08 12:43:28 -0700254 uintptr_t payload = EncodeStackIndex(stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100255 Location loc(kStackSlot, payload);
256 // Ensure that sign is preserved.
257 DCHECK_EQ(loc.GetStackIndex(), stack_index);
258 return loc;
259 }
260
261 bool IsStackSlot() const {
262 return GetKind() == kStackSlot;
263 }
264
265 static Location DoubleStackSlot(intptr_t stack_index) {
Ian Rogers13735952014-10-08 12:43:28 -0700266 uintptr_t payload = EncodeStackIndex(stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100267 Location loc(kDoubleStackSlot, payload);
268 // Ensure that sign is preserved.
269 DCHECK_EQ(loc.GetStackIndex(), stack_index);
270 return loc;
271 }
272
273 bool IsDoubleStackSlot() const {
274 return GetKind() == kDoubleStackSlot;
275 }
276
Aart Bik5576f372017-03-23 16:17:37 -0700277 static Location SIMDStackSlot(intptr_t stack_index) {
278 uintptr_t payload = EncodeStackIndex(stack_index);
279 Location loc(kSIMDStackSlot, payload);
280 // Ensure that sign is preserved.
281 DCHECK_EQ(loc.GetStackIndex(), stack_index);
282 return loc;
283 }
284
285 bool IsSIMDStackSlot() const {
286 return GetKind() == kSIMDStackSlot;
287 }
288
Artem Serovc8150b52019-07-31 18:28:00 +0100289 static Location StackSlotByNumOfSlots(size_t num_of_slots, int spill_slot) {
290 DCHECK_NE(num_of_slots, 0u);
291 switch (num_of_slots) {
292 case 1u:
293 return Location::StackSlot(spill_slot);
294 case 2u:
295 return Location::DoubleStackSlot(spill_slot);
296 default:
297 // Assume all other stack slot sizes correspond to SIMD slot size.
298 return Location::SIMDStackSlot(spill_slot);
299 }
300 }
301
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100302 intptr_t GetStackIndex() const {
Aart Bik5576f372017-03-23 16:17:37 -0700303 DCHECK(IsStackSlot() || IsDoubleStackSlot() || IsSIMDStackSlot());
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100304 // Decode stack index manually to preserve sign.
305 return GetPayload() - kStackIndexBias;
306 }
307
308 intptr_t GetHighStackIndex(uintptr_t word_size) const {
309 DCHECK(IsDoubleStackSlot());
310 // Decode stack index manually to preserve sign.
311 return GetPayload() - kStackIndexBias + word_size;
312 }
313
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100314 Kind GetKind() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100315 return IsConstant() ? kConstant : KindField::Decode(value_);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100316 }
317
318 bool Equals(Location other) const {
319 return value_ == other.value_;
320 }
321
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000322 bool Contains(Location other) const {
323 if (Equals(other)) {
324 return true;
Zheng Xuad4450e2015-04-17 18:48:56 +0800325 } else if (IsPair() || IsDoubleStackSlot()) {
326 return ToLow().Equals(other) || ToHigh().Equals(other);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000327 }
328 return false;
329 }
330
Zheng Xuad4450e2015-04-17 18:48:56 +0800331 bool OverlapsWith(Location other) const {
332 // Only check the overlapping case that can happen with our register allocation algorithm.
333 bool overlap = Contains(other) || other.Contains(*this);
334 if (kIsDebugBuild && !overlap) {
335 // Note: These are also overlapping cases. But we are not able to handle them in
336 // ParallelMoveResolverWithSwap. Make sure that we do not meet such case with our compiler.
337 if ((IsPair() && other.IsPair()) || (IsDoubleStackSlot() && other.IsDoubleStackSlot())) {
338 DCHECK(!Contains(other.ToLow()));
339 DCHECK(!Contains(other.ToHigh()));
340 }
341 }
342 return overlap;
343 }
344
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100345 const char* DebugString() const {
346 switch (GetKind()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100347 case kInvalid: return "I";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100348 case kRegister: return "R";
349 case kStackSlot: return "S";
350 case kDoubleStackSlot: return "DS";
Aart Bik5576f372017-03-23 16:17:37 -0700351 case kSIMDStackSlot: return "SIMD";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100352 case kUnallocated: return "U";
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100353 case kConstant: return "C";
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100354 case kFpuRegister: return "F";
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100355 case kRegisterPair: return "RP";
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000356 case kFpuRegisterPair: return "FP";
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100357 case kDoNotUse5: // fall-through
358 case kDoNotUse9:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100359 LOG(FATAL) << "Should not use this location kind";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100360 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100361 UNREACHABLE();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100362 }
363
364 // Unallocated locations.
365 enum Policy {
366 kAny,
367 kRequiresRegister,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100368 kRequiresFpuRegister,
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100369 kSameAsFirstInput,
370 };
371
372 bool IsUnallocated() const {
373 return GetKind() == kUnallocated;
374 }
375
376 static Location UnallocatedLocation(Policy policy) {
377 return Location(kUnallocated, PolicyField::Encode(policy));
378 }
379
380 // Any free register is suitable to replace this unallocated location.
381 static Location Any() {
382 return UnallocatedLocation(kAny);
383 }
384
385 static Location RequiresRegister() {
386 return UnallocatedLocation(kRequiresRegister);
387 }
388
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100389 static Location RequiresFpuRegister() {
390 return UnallocatedLocation(kRequiresFpuRegister);
391 }
392
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100393 static Location RegisterOrConstant(HInstruction* instruction);
Mark Mendellea5af682015-10-22 17:35:49 -0400394 static Location RegisterOrInt32Constant(HInstruction* instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100395 static Location ByteRegisterOrConstant(int reg, HInstruction* instruction);
Mark Mendellea5af682015-10-22 17:35:49 -0400396 static Location FpuRegisterOrConstant(HInstruction* instruction);
397 static Location FpuRegisterOrInt32Constant(HInstruction* instruction);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100398
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100399 // The location of the first input to the instruction will be
400 // used to replace this unallocated location.
401 static Location SameAsFirstInput() {
402 return UnallocatedLocation(kSameAsFirstInput);
403 }
404
405 Policy GetPolicy() const {
406 DCHECK(IsUnallocated());
407 return PolicyField::Decode(GetPayload());
408 }
409
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700410 bool RequiresRegisterKind() const {
411 return GetPolicy() == kRequiresRegister || GetPolicy() == kRequiresFpuRegister;
412 }
413
Ian Rogers13735952014-10-08 12:43:28 -0700414 uintptr_t GetEncoding() const {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100415 return GetPayload();
416 }
417
418 private:
419 // Number of bits required to encode Kind value.
420 static constexpr uint32_t kBitsForKind = 4;
Ian Rogers13735952014-10-08 12:43:28 -0700421 static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind;
422 static constexpr uintptr_t kLocationConstantMask = 0x3;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100423
Ian Rogers13735952014-10-08 12:43:28 -0700424 explicit Location(uintptr_t value) : value_(value) {}
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100425
Vladimir Markoaf06af42023-10-31 10:02:46 +0000426 constexpr Location(Kind kind, uintptr_t payload)
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100427 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
428
Ian Rogers13735952014-10-08 12:43:28 -0700429 uintptr_t GetPayload() const {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100430 return PayloadField::Decode(value_);
431 }
432
Vladimir Markof76ca8c2023-04-05 15:24:41 +0000433 static void DCheckInstructionIsConstant(HInstruction* instruction);
434
Vladimir Marko4f990712021-07-14 12:45:13 +0100435 using KindField = BitField<Kind, 0, kBitsForKind>;
436 using PayloadField = BitField<uintptr_t, kBitsForKind, kBitsForPayload>;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100437
438 // Layout for kUnallocated locations payload.
Vladimir Marko4f990712021-07-14 12:45:13 +0100439 using PolicyField = BitField<Policy, 0, 3>;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100440
441 // Layout for stack slots.
442 static const intptr_t kStackIndexBias =
443 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
444
445 // Location either contains kind and payload fields or a tagged handle for
446 // a constant locations. Values of enumeration Kind are selected in such a
447 // way that none of them can be interpreted as a kConstant tag.
Ian Rogers13735952014-10-08 12:43:28 -0700448 uintptr_t value_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100449};
Vladimir Marko9974e3c2020-06-10 16:27:06 +0100450std::ostream& operator<<(std::ostream& os, Location::Kind rhs);
451std::ostream& operator<<(std::ostream& os, Location::Policy rhs);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100452
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100453class RegisterSet : public ValueObject {
454 public:
Vladimir Marko804b03f2016-09-14 16:26:36 +0100455 static RegisterSet Empty() { return RegisterSet(); }
Aart Bikb13c65b2017-03-21 20:14:07 -0700456 static RegisterSet AllFpu() { return RegisterSet(0, -1); }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100457
458 void Add(Location loc) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100459 if (loc.IsRegister()) {
460 core_registers_ |= (1 << loc.reg());
461 } else {
462 DCHECK(loc.IsFpuRegister());
463 floating_point_registers_ |= (1 << loc.reg());
464 }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100465 }
466
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100467 void Remove(Location loc) {
468 if (loc.IsRegister()) {
469 core_registers_ &= ~(1 << loc.reg());
470 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000471 DCHECK(loc.IsFpuRegister()) << loc;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100472 floating_point_registers_ &= ~(1 << loc.reg());
473 }
474 }
475
Nicolas Geoffray45b83af2015-07-06 15:12:53 +0000476 bool ContainsCoreRegister(uint32_t id) const {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100477 return Contains(core_registers_, id);
478 }
479
Nicolas Geoffray45b83af2015-07-06 15:12:53 +0000480 bool ContainsFloatingPointRegister(uint32_t id) const {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100481 return Contains(floating_point_registers_, id);
482 }
483
484 static bool Contains(uint32_t register_set, uint32_t reg) {
485 return (register_set & (1 << reg)) != 0;
486 }
487
Andra Danciue3e187f2020-07-30 12:19:31 +0000488 bool OverlapsRegisters(Location out) {
489 DCHECK(out.IsRegisterKind());
490 switch (out.GetKind()) {
491 case Location::Kind::kRegister:
492 return ContainsCoreRegister(out.reg());
493 case Location::Kind::kFpuRegister:
494 return ContainsFloatingPointRegister(out.reg());
495 case Location::Kind::kRegisterPair:
496 return ContainsCoreRegister(out.low()) || ContainsCoreRegister(out.high());
497 case Location::Kind::kFpuRegisterPair:
498 return ContainsFloatingPointRegister(out.low()) ||
499 ContainsFloatingPointRegister(out.high());
500 default:
501 return false;
502 }
503 }
504
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000505 size_t GetNumberOfRegisters() const {
Vladimir Marko70e97462016-08-09 11:04:26 +0100506 return POPCOUNT(core_registers_) + POPCOUNT(floating_point_registers_);
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000507 }
508
Nicolas Geoffray98893962015-01-21 12:32:32 +0000509 uint32_t GetCoreRegisters() const {
510 return core_registers_;
511 }
512
513 uint32_t GetFloatingPointRegisters() const {
514 return floating_point_registers_;
515 }
516
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100517 private:
Vladimir Marko804b03f2016-09-14 16:26:36 +0100518 RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
Aart Bikb13c65b2017-03-21 20:14:07 -0700519 RegisterSet(uint32_t core, uint32_t fp) : core_registers_(core), floating_point_registers_(fp) {}
Vladimir Marko804b03f2016-09-14 16:26:36 +0100520
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100521 uint32_t core_registers_;
522 uint32_t floating_point_registers_;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100523};
524
Andreas Gampe878d58c2015-01-15 23:24:00 -0800525static constexpr bool kIntrinsified = true;
526
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100527/**
528 * The code generator computes LocationSummary for each instruction so that
529 * the instruction itself knows what code to generate: where to find the inputs
530 * and where to place the result.
531 *
532 * The intent is to have the code for generating the instruction independent of
533 * register allocation. A register allocator just has to provide a LocationSummary.
534 */
Vladimir Marko5233f932015-09-29 19:01:15 +0100535class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100536 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100537 enum CallKind {
538 kNoCall,
Serban Constantinescu806f0122016-03-09 11:10:16 +0000539 kCallOnMainAndSlowPath,
Nicolas Geoffray39468442014-09-02 15:17:15 +0100540 kCallOnSlowPath,
Serban Constantinescu54ff4822016-07-07 18:03:19 +0100541 kCallOnMainOnly
Nicolas Geoffray39468442014-09-02 15:17:15 +0100542 };
543
Chih-Hung Hsieha5931182016-09-01 15:08:13 -0700544 explicit LocationSummary(HInstruction* instruction,
545 CallKind call_kind = kNoCall,
546 bool intrinsified = false);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100547
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100548 void SetInAt(uint32_t at, Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100549 inputs_[at] = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100550 }
551
552 Location InAt(uint32_t at) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100553 return inputs_[at];
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100554 }
555
556 size_t GetInputCount() const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100557 return inputs_.size();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100558 }
559
Roland Levillain3d312422016-06-23 13:53:42 +0100560 // Set the output location. Argument `overlaps` tells whether the
561 // output overlaps any of the inputs (if so, it cannot share the
562 // same register as one of the inputs); it is set to
563 // `Location::kOutputOverlap` by default for safety.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000564 void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000565 DCHECK(output_.IsInvalid());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100566 output_overlaps_ = overlaps;
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000567 output_ = location;
568 }
569
570 void UpdateOut(Location location) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000571 // There are two reasons for updating an output:
572 // 1) Parameters, where we only know the exact stack slot after
573 // doing full register allocation.
574 // 2) Unallocated location.
575 DCHECK(output_.IsStackSlot() || output_.IsDoubleStackSlot() || output_.IsUnallocated());
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000576 output_ = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100577 }
578
579 void AddTemp(Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100580 temps_.push_back(location);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100581 }
582
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -0700583 void AddRegisterTemps(size_t count) {
584 for (size_t i = 0; i < count; ++i) {
585 AddTemp(Location::RequiresRegister());
586 }
587 }
588
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100589 Location GetTemp(uint32_t at) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100590 return temps_[at];
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100591 }
592
593 void SetTempAt(uint32_t at, Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100594 DCHECK(temps_[at].IsUnallocated() || temps_[at].IsInvalid());
595 temps_[at] = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100596 }
597
598 size_t GetTempCount() const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100599 return temps_.size();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100600 }
601
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100602 bool HasTemps() const { return !temps_.empty(); }
Nicolas Geoffray94015b92015-06-04 18:21:04 +0100603
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100604 Location Out() const { return output_; }
605
Serban Constantinescu806f0122016-03-09 11:10:16 +0000606 bool CanCall() const {
607 return call_kind_ != kNoCall;
608 }
609
610 bool WillCall() const {
611 return call_kind_ == kCallOnMainOnly || call_kind_ == kCallOnMainAndSlowPath;
612 }
613
614 bool CallsOnSlowPath() const {
Santiago Aboy Solanese8a822d2021-09-13 14:40:53 +0100615 return OnlyCallsOnSlowPath() || CallsOnMainAndSlowPath();
Serban Constantinescu806f0122016-03-09 11:10:16 +0000616 }
617
618 bool OnlyCallsOnSlowPath() const {
619 return call_kind_ == kCallOnSlowPath;
620 }
621
Santiago Aboy Solanese8a822d2021-09-13 14:40:53 +0100622 bool NeedsSuspendCheckEntry() const {
623 // Slow path calls do not need a SuspendCheck at method entry since they go into the runtime,
624 // which we expect to either do a suspend check or return quickly.
625 return WillCall();
626 }
627
Serban Constantinescu806f0122016-03-09 11:10:16 +0000628 bool CallsOnMainAndSlowPath() const {
629 return call_kind_ == kCallOnMainAndSlowPath;
630 }
631
632 bool NeedsSafepoint() const {
633 return CanCall();
634 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100635
Vladimir Marko70e97462016-08-09 11:04:26 +0100636 void SetCustomSlowPathCallerSaves(const RegisterSet& caller_saves) {
637 DCHECK(OnlyCallsOnSlowPath());
638 has_custom_slow_path_calling_convention_ = true;
639 custom_slow_path_caller_saves_ = caller_saves;
640 }
641
642 bool HasCustomSlowPathCallingConvention() const {
643 return has_custom_slow_path_calling_convention_;
644 }
645
646 const RegisterSet& GetCustomSlowPathCallerSaves() const {
647 DCHECK(HasCustomSlowPathCallingConvention());
648 return custom_slow_path_caller_saves_;
649 }
650
Nicolas Geoffray39468442014-09-02 15:17:15 +0100651 void SetStackBit(uint32_t index) {
652 stack_mask_->SetBit(index);
653 }
654
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100655 void ClearStackBit(uint32_t index) {
656 stack_mask_->ClearBit(index);
657 }
658
Nicolas Geoffray39468442014-09-02 15:17:15 +0100659 void SetRegisterBit(uint32_t reg_id) {
660 register_mask_ |= (1 << reg_id);
661 }
662
Nicolas Geoffray98893962015-01-21 12:32:32 +0000663 uint32_t GetRegisterMask() const {
664 return register_mask_;
665 }
666
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100667 bool RegisterContainsObject(uint32_t reg_id) {
668 return RegisterSet::Contains(register_mask_, reg_id);
669 }
670
671 void AddLiveRegister(Location location) {
672 live_registers_.Add(location);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100673 }
674
675 BitVector* GetStackMask() const {
676 return stack_mask_;
677 }
678
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100679 RegisterSet* GetLiveRegisters() {
680 return &live_registers_;
681 }
682
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000683 size_t GetNumberOfLiveRegisters() const {
684 return live_registers_.GetNumberOfRegisters();
685 }
686
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000687 bool OutputUsesSameAs(uint32_t input_index) const {
688 return (input_index == 0)
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100689 && output_.IsUnallocated()
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000690 && (output_.GetPolicy() == Location::kSameAsFirstInput);
691 }
692
693 bool IsFixedInput(uint32_t input_index) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100694 Location input = inputs_[input_index];
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000695 return input.IsRegister()
Nicolas Geoffray98893962015-01-21 12:32:32 +0000696 || input.IsFpuRegister()
697 || input.IsPair()
698 || input.IsStackSlot()
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000699 || input.IsDoubleStackSlot();
Nicolas Geoffray76905622014-09-25 14:39:26 +0100700 }
701
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000702 bool OutputCanOverlapWithInputs() const {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000703 return output_overlaps_ == Location::kOutputOverlap;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100704 }
705
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800706 bool Intrinsified() const {
707 return intrinsified_;
708 }
709
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100710 private:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100711 LocationSummary(HInstruction* instruction,
712 CallKind call_kind,
713 bool intrinsified,
714 ArenaAllocator* allocator);
715
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100716 ArenaVector<Location> inputs_;
717 ArenaVector<Location> temps_;
Vladimir Marko70e97462016-08-09 11:04:26 +0100718 const CallKind call_kind_;
719 // Whether these are locations for an intrinsified call.
720 const bool intrinsified_;
721 // Whether the slow path has default or custom calling convention.
722 bool has_custom_slow_path_calling_convention_;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100723 // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot
724 // share the same register as the inputs.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000725 Location::OutputOverlap output_overlaps_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100726 Location output_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100727
728 // Mask of objects that live in the stack.
729 BitVector* stack_mask_;
730
731 // Mask of objects that live in register.
732 uint32_t register_mask_;
733
734 // Registers that are in use at this position.
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100735 RegisterSet live_registers_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100736
Vladimir Marko70e97462016-08-09 11:04:26 +0100737 // Custom slow path caller saves. Valid only if indicated by slow_path_calling_convention_.
738 RegisterSet custom_slow_path_caller_saves_;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800739
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700740 friend class RegisterAllocatorTest;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100741 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
742};
743
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100744} // namespace art
745
746#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_