blob: d56c15174834dd006551063e7f4b7b0dfddb2b55 [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"
Ian Rogers0279ebb2014-10-08 17:27:48 -070025#include "base/value_object.h"
Nicolas Geoffray76716a62014-05-23 10:14:19 +010026
27namespace art {
28
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010029class HConstant;
Nicolas Geoffray76716a62014-05-23 10:14:19 +010030class HInstruction;
Nicolas Geoffray424f6762014-11-03 14:51:25 +000031class Location;
32
33std::ostream& operator<<(std::ostream& os, const Location& location);
Nicolas Geoffray76716a62014-05-23 10:14:19 +010034
35/**
36 * A Location is an abstraction over the potential location
37 * of an instruction. It could be in register or stack.
38 */
Vladimir Marko76c92ac2015-09-17 15:39:16 +010039class Location : public ValueObject {
Nicolas Geoffray76716a62014-05-23 10:14:19 +010040 public:
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000041 enum OutputOverlap {
Roland Levillain3d312422016-06-23 13:53:42 +010042 // The liveness of the output overlaps the liveness of one or
43 // several input(s); the register allocator cannot reuse an
44 // input's location for the output's location.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000045 kOutputOverlap,
Roland Levillain3d312422016-06-23 13:53:42 +010046 // The liveness of the output does not overlap the liveness of any
47 // input; the register allocator is allowed to reuse an input's
48 // location for the output's location.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000049 kNoOutputOverlap
50 };
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +010051
Nicolas Geoffray76716a62014-05-23 10:14:19 +010052 enum Kind {
53 kInvalid = 0,
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010054 kConstant = 1,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010055 kStackSlot = 2, // 32bit stack slot.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010056 kDoubleStackSlot = 3, // 64bit stack slot.
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010057
58 kRegister = 4, // Core register.
59
60 // We do not use the value 5 because it conflicts with kLocationConstantMask.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010061 kDoNotUse5 = 5,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010062
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000063 kFpuRegister = 6, // Float register.
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010064
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000065 kRegisterPair = 7, // Long register.
66
67 kFpuRegisterPair = 8, // Double register.
68
69 // We do not use the value 9 because it conflicts with kLocationConstantMask.
70 kDoNotUse9 = 9,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010071
Aart Bik5576f372017-03-23 16:17:37 -070072 kSIMDStackSlot = 10, // 128bit stack slot. TODO: generalize with encoded #bytes?
73
Nicolas Geoffray76716a62014-05-23 10:14:19 +010074 // Unallocated location represents a location that is not fixed and can be
75 // allocated by a register allocator. Each unallocated location has
76 // a policy that specifies what kind of location is suitable. Payload
77 // contains register allocation policy.
Aart Bik5576f372017-03-23 16:17:37 -070078 kUnallocated = 11,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010079 };
80
Vladimir Marko76c92ac2015-09-17 15:39:16 +010081 Location() : ValueObject(), value_(kInvalid) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010082 // Verify that non-constant location kinds do not interfere with kConstant.
Andreas Gampe785d2f22014-11-03 22:57:30 -080083 static_assert((kInvalid & kLocationConstantMask) != kConstant, "TagError");
84 static_assert((kUnallocated & kLocationConstantMask) != kConstant, "TagError");
85 static_assert((kStackSlot & kLocationConstantMask) != kConstant, "TagError");
86 static_assert((kDoubleStackSlot & kLocationConstantMask) != kConstant, "TagError");
Aart Bik5576f372017-03-23 16:17:37 -070087 static_assert((kSIMDStackSlot & kLocationConstantMask) != kConstant, "TagError");
Andreas Gampe785d2f22014-11-03 22:57:30 -080088 static_assert((kRegister & kLocationConstantMask) != kConstant, "TagError");
Andreas Gampe785d2f22014-11-03 22:57:30 -080089 static_assert((kFpuRegister & kLocationConstantMask) != kConstant, "TagError");
90 static_assert((kRegisterPair & kLocationConstantMask) != kConstant, "TagError");
91 static_assert((kFpuRegisterPair & kLocationConstantMask) != kConstant, "TagError");
92 static_assert((kConstant & kLocationConstantMask) == kConstant, "TagError");
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010093
Nicolas Geoffray76716a62014-05-23 10:14:19 +010094 DCHECK(!IsValid());
95 }
96
Andreas Gampe2e6f38a2016-11-03 14:06:20 -070097 Location(const Location& other) = default;
Nicolas Geoffray76716a62014-05-23 10:14:19 +010098
Andreas Gampe2e6f38a2016-11-03 14:06:20 -070099 Location& operator=(const Location& other) = default;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100100
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100101 bool IsConstant() const {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100102 return (value_ & kLocationConstantMask) == kConstant;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100103 }
104
105 static Location ConstantLocation(HConstant* constant) {
106 DCHECK(constant != nullptr);
Ian Rogers13735952014-10-08 12:43:28 -0700107 return Location(kConstant | reinterpret_cast<uintptr_t>(constant));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100108 }
109
110 HConstant* GetConstant() const {
111 DCHECK(IsConstant());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100112 return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100113 }
114
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100115 bool IsValid() const {
116 return value_ != kInvalid;
117 }
118
119 bool IsInvalid() const {
120 return !IsValid();
121 }
122
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100123 // Empty location. Used if there the location should be ignored.
124 static Location NoLocation() {
125 return Location();
126 }
127
128 // Register locations.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100129 static Location RegisterLocation(int reg) {
130 return Location(kRegister, reg);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100131 }
132
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100133 static Location FpuRegisterLocation(int reg) {
134 return Location(kFpuRegister, reg);
135 }
136
137 static Location RegisterPairLocation(int low, int high) {
138 return Location(kRegisterPair, low << 16 | high);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100139 }
140
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000141 static Location FpuRegisterPairLocation(int low, int high) {
142 return Location(kFpuRegisterPair, low << 16 | high);
143 }
144
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100145 bool IsRegister() const {
146 return GetKind() == kRegister;
147 }
148
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100149 bool IsFpuRegister() const {
150 return GetKind() == kFpuRegister;
151 }
152
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100153 bool IsRegisterPair() const {
154 return GetKind() == kRegisterPair;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100155 }
156
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000157 bool IsFpuRegisterPair() const {
158 return GetKind() == kFpuRegisterPair;
159 }
160
Nicolas Geoffrayda02afe2015-02-11 02:29:42 +0000161 bool IsRegisterKind() const {
162 return IsRegister() || IsFpuRegister() || IsRegisterPair() || IsFpuRegisterPair();
163 }
164
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100165 int reg() const {
166 DCHECK(IsRegister() || IsFpuRegister());
167 return GetPayload();
168 }
169
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000170 int low() const {
171 DCHECK(IsPair());
172 return GetPayload() >> 16;
173 }
174
175 int high() const {
176 DCHECK(IsPair());
177 return GetPayload() & 0xFFFF;
178 }
179
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100180 template <typename T>
Roland Levillain271ab9c2014-11-27 15:23:57 +0000181 T AsRegister() const {
182 DCHECK(IsRegister());
183 return static_cast<T>(reg());
184 }
185
186 template <typename T>
187 T AsFpuRegister() const {
188 DCHECK(IsFpuRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100189 return static_cast<T>(reg());
190 }
191
192 template <typename T>
193 T AsRegisterPairLow() const {
194 DCHECK(IsRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000195 return static_cast<T>(low());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100196 }
197
198 template <typename T>
199 T AsRegisterPairHigh() const {
200 DCHECK(IsRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000201 return static_cast<T>(high());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100202 }
203
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000204 template <typename T>
205 T AsFpuRegisterPairLow() const {
206 DCHECK(IsFpuRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000207 return static_cast<T>(low());
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000208 }
209
210 template <typename T>
211 T AsFpuRegisterPairHigh() const {
212 DCHECK(IsFpuRegisterPair());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000213 return static_cast<T>(high());
214 }
215
216 bool IsPair() const {
217 return IsRegisterPair() || IsFpuRegisterPair();
218 }
219
220 Location ToLow() const {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000221 if (IsRegisterPair()) {
222 return Location::RegisterLocation(low());
223 } else if (IsFpuRegisterPair()) {
224 return Location::FpuRegisterLocation(low());
225 } else {
226 DCHECK(IsDoubleStackSlot());
227 return Location::StackSlot(GetStackIndex());
228 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000229 }
230
231 Location ToHigh() const {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000232 if (IsRegisterPair()) {
233 return Location::RegisterLocation(high());
234 } else if (IsFpuRegisterPair()) {
235 return Location::FpuRegisterLocation(high());
236 } else {
237 DCHECK(IsDoubleStackSlot());
238 return Location::StackSlot(GetHighStackIndex(4));
239 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000240 }
241
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100242 static uintptr_t EncodeStackIndex(intptr_t stack_index) {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100243 DCHECK(-kStackIndexBias <= stack_index);
244 DCHECK(stack_index < kStackIndexBias);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100245 return static_cast<uintptr_t>(kStackIndexBias + stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100246 }
247
248 static Location StackSlot(intptr_t stack_index) {
Ian Rogers13735952014-10-08 12:43:28 -0700249 uintptr_t payload = EncodeStackIndex(stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100250 Location loc(kStackSlot, payload);
251 // Ensure that sign is preserved.
252 DCHECK_EQ(loc.GetStackIndex(), stack_index);
253 return loc;
254 }
255
256 bool IsStackSlot() const {
257 return GetKind() == kStackSlot;
258 }
259
260 static Location DoubleStackSlot(intptr_t stack_index) {
Ian Rogers13735952014-10-08 12:43:28 -0700261 uintptr_t payload = EncodeStackIndex(stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100262 Location loc(kDoubleStackSlot, payload);
263 // Ensure that sign is preserved.
264 DCHECK_EQ(loc.GetStackIndex(), stack_index);
265 return loc;
266 }
267
268 bool IsDoubleStackSlot() const {
269 return GetKind() == kDoubleStackSlot;
270 }
271
Aart Bik5576f372017-03-23 16:17:37 -0700272 static Location SIMDStackSlot(intptr_t stack_index) {
273 uintptr_t payload = EncodeStackIndex(stack_index);
274 Location loc(kSIMDStackSlot, payload);
275 // Ensure that sign is preserved.
276 DCHECK_EQ(loc.GetStackIndex(), stack_index);
277 return loc;
278 }
279
280 bool IsSIMDStackSlot() const {
281 return GetKind() == kSIMDStackSlot;
282 }
283
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100284 intptr_t GetStackIndex() const {
Aart Bik5576f372017-03-23 16:17:37 -0700285 DCHECK(IsStackSlot() || IsDoubleStackSlot() || IsSIMDStackSlot());
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100286 // Decode stack index manually to preserve sign.
287 return GetPayload() - kStackIndexBias;
288 }
289
290 intptr_t GetHighStackIndex(uintptr_t word_size) const {
291 DCHECK(IsDoubleStackSlot());
292 // Decode stack index manually to preserve sign.
293 return GetPayload() - kStackIndexBias + word_size;
294 }
295
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100296 Kind GetKind() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100297 return IsConstant() ? kConstant : KindField::Decode(value_);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100298 }
299
300 bool Equals(Location other) const {
301 return value_ == other.value_;
302 }
303
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000304 bool Contains(Location other) const {
305 if (Equals(other)) {
306 return true;
Zheng Xuad4450e2015-04-17 18:48:56 +0800307 } else if (IsPair() || IsDoubleStackSlot()) {
308 return ToLow().Equals(other) || ToHigh().Equals(other);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000309 }
310 return false;
311 }
312
Zheng Xuad4450e2015-04-17 18:48:56 +0800313 bool OverlapsWith(Location other) const {
314 // Only check the overlapping case that can happen with our register allocation algorithm.
315 bool overlap = Contains(other) || other.Contains(*this);
316 if (kIsDebugBuild && !overlap) {
317 // Note: These are also overlapping cases. But we are not able to handle them in
318 // ParallelMoveResolverWithSwap. Make sure that we do not meet such case with our compiler.
319 if ((IsPair() && other.IsPair()) || (IsDoubleStackSlot() && other.IsDoubleStackSlot())) {
320 DCHECK(!Contains(other.ToLow()));
321 DCHECK(!Contains(other.ToHigh()));
322 }
323 }
324 return overlap;
325 }
326
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100327 const char* DebugString() const {
328 switch (GetKind()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100329 case kInvalid: return "I";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100330 case kRegister: return "R";
331 case kStackSlot: return "S";
332 case kDoubleStackSlot: return "DS";
Aart Bik5576f372017-03-23 16:17:37 -0700333 case kSIMDStackSlot: return "SIMD";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100334 case kUnallocated: return "U";
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100335 case kConstant: return "C";
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100336 case kFpuRegister: return "F";
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100337 case kRegisterPair: return "RP";
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000338 case kFpuRegisterPair: return "FP";
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100339 case kDoNotUse5: // fall-through
340 case kDoNotUse9:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100341 LOG(FATAL) << "Should not use this location kind";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100342 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100343 UNREACHABLE();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100344 }
345
346 // Unallocated locations.
347 enum Policy {
348 kAny,
349 kRequiresRegister,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100350 kRequiresFpuRegister,
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100351 kSameAsFirstInput,
352 };
353
354 bool IsUnallocated() const {
355 return GetKind() == kUnallocated;
356 }
357
358 static Location UnallocatedLocation(Policy policy) {
359 return Location(kUnallocated, PolicyField::Encode(policy));
360 }
361
362 // Any free register is suitable to replace this unallocated location.
363 static Location Any() {
364 return UnallocatedLocation(kAny);
365 }
366
367 static Location RequiresRegister() {
368 return UnallocatedLocation(kRequiresRegister);
369 }
370
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100371 static Location RequiresFpuRegister() {
372 return UnallocatedLocation(kRequiresFpuRegister);
373 }
374
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100375 static Location RegisterOrConstant(HInstruction* instruction);
Mark Mendellea5af682015-10-22 17:35:49 -0400376 static Location RegisterOrInt32Constant(HInstruction* instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100377 static Location ByteRegisterOrConstant(int reg, HInstruction* instruction);
Mark Mendellea5af682015-10-22 17:35:49 -0400378 static Location FpuRegisterOrConstant(HInstruction* instruction);
379 static Location FpuRegisterOrInt32Constant(HInstruction* instruction);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100380
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100381 // The location of the first input to the instruction will be
382 // used to replace this unallocated location.
383 static Location SameAsFirstInput() {
384 return UnallocatedLocation(kSameAsFirstInput);
385 }
386
387 Policy GetPolicy() const {
388 DCHECK(IsUnallocated());
389 return PolicyField::Decode(GetPayload());
390 }
391
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700392 bool RequiresRegisterKind() const {
393 return GetPolicy() == kRequiresRegister || GetPolicy() == kRequiresFpuRegister;
394 }
395
Ian Rogers13735952014-10-08 12:43:28 -0700396 uintptr_t GetEncoding() const {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100397 return GetPayload();
398 }
399
400 private:
401 // Number of bits required to encode Kind value.
402 static constexpr uint32_t kBitsForKind = 4;
Ian Rogers13735952014-10-08 12:43:28 -0700403 static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind;
404 static constexpr uintptr_t kLocationConstantMask = 0x3;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100405
Ian Rogers13735952014-10-08 12:43:28 -0700406 explicit Location(uintptr_t value) : value_(value) {}
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100407
Ian Rogers13735952014-10-08 12:43:28 -0700408 Location(Kind kind, uintptr_t payload)
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100409 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
410
Ian Rogers13735952014-10-08 12:43:28 -0700411 uintptr_t GetPayload() const {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100412 return PayloadField::Decode(value_);
413 }
414
415 typedef BitField<Kind, 0, kBitsForKind> KindField;
Ian Rogers13735952014-10-08 12:43:28 -0700416 typedef BitField<uintptr_t, kBitsForKind, kBitsForPayload> PayloadField;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100417
418 // Layout for kUnallocated locations payload.
419 typedef BitField<Policy, 0, 3> PolicyField;
420
421 // Layout for stack slots.
422 static const intptr_t kStackIndexBias =
423 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
424
425 // Location either contains kind and payload fields or a tagged handle for
426 // a constant locations. Values of enumeration Kind are selected in such a
427 // way that none of them can be interpreted as a kConstant tag.
Ian Rogers13735952014-10-08 12:43:28 -0700428 uintptr_t value_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100429};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700430std::ostream& operator<<(std::ostream& os, const Location::Kind& rhs);
431std::ostream& operator<<(std::ostream& os, const Location::Policy& rhs);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100432
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100433class RegisterSet : public ValueObject {
434 public:
Vladimir Marko804b03f2016-09-14 16:26:36 +0100435 static RegisterSet Empty() { return RegisterSet(); }
Aart Bikb13c65b2017-03-21 20:14:07 -0700436 static RegisterSet AllFpu() { return RegisterSet(0, -1); }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100437
438 void Add(Location loc) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100439 if (loc.IsRegister()) {
440 core_registers_ |= (1 << loc.reg());
441 } else {
442 DCHECK(loc.IsFpuRegister());
443 floating_point_registers_ |= (1 << loc.reg());
444 }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100445 }
446
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100447 void Remove(Location loc) {
448 if (loc.IsRegister()) {
449 core_registers_ &= ~(1 << loc.reg());
450 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000451 DCHECK(loc.IsFpuRegister()) << loc;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100452 floating_point_registers_ &= ~(1 << loc.reg());
453 }
454 }
455
Nicolas Geoffray45b83af2015-07-06 15:12:53 +0000456 bool ContainsCoreRegister(uint32_t id) const {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100457 return Contains(core_registers_, id);
458 }
459
Nicolas Geoffray45b83af2015-07-06 15:12:53 +0000460 bool ContainsFloatingPointRegister(uint32_t id) const {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100461 return Contains(floating_point_registers_, id);
462 }
463
464 static bool Contains(uint32_t register_set, uint32_t reg) {
465 return (register_set & (1 << reg)) != 0;
466 }
467
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000468 size_t GetNumberOfRegisters() const {
Vladimir Marko70e97462016-08-09 11:04:26 +0100469 return POPCOUNT(core_registers_) + POPCOUNT(floating_point_registers_);
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000470 }
471
Nicolas Geoffray98893962015-01-21 12:32:32 +0000472 uint32_t GetCoreRegisters() const {
473 return core_registers_;
474 }
475
476 uint32_t GetFloatingPointRegisters() const {
477 return floating_point_registers_;
478 }
479
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100480 private:
Vladimir Marko804b03f2016-09-14 16:26:36 +0100481 RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
Aart Bikb13c65b2017-03-21 20:14:07 -0700482 RegisterSet(uint32_t core, uint32_t fp) : core_registers_(core), floating_point_registers_(fp) {}
Vladimir Marko804b03f2016-09-14 16:26:36 +0100483
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100484 uint32_t core_registers_;
485 uint32_t floating_point_registers_;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100486};
487
Andreas Gampe878d58c2015-01-15 23:24:00 -0800488static constexpr bool kIntrinsified = true;
489
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100490/**
491 * The code generator computes LocationSummary for each instruction so that
492 * the instruction itself knows what code to generate: where to find the inputs
493 * and where to place the result.
494 *
495 * The intent is to have the code for generating the instruction independent of
496 * register allocation. A register allocator just has to provide a LocationSummary.
497 */
Vladimir Marko5233f932015-09-29 19:01:15 +0100498class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100499 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100500 enum CallKind {
501 kNoCall,
Serban Constantinescu806f0122016-03-09 11:10:16 +0000502 kCallOnMainAndSlowPath,
Nicolas Geoffray39468442014-09-02 15:17:15 +0100503 kCallOnSlowPath,
Serban Constantinescu54ff4822016-07-07 18:03:19 +0100504 kCallOnMainOnly
Nicolas Geoffray39468442014-09-02 15:17:15 +0100505 };
506
Chih-Hung Hsieha5931182016-09-01 15:08:13 -0700507 explicit LocationSummary(HInstruction* instruction,
508 CallKind call_kind = kNoCall,
509 bool intrinsified = false);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100510
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100511 void SetInAt(uint32_t at, Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100512 inputs_[at] = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100513 }
514
515 Location InAt(uint32_t at) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100516 return inputs_[at];
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100517 }
518
519 size_t GetInputCount() const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100520 return inputs_.size();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100521 }
522
Roland Levillain3d312422016-06-23 13:53:42 +0100523 // Set the output location. Argument `overlaps` tells whether the
524 // output overlaps any of the inputs (if so, it cannot share the
525 // same register as one of the inputs); it is set to
526 // `Location::kOutputOverlap` by default for safety.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000527 void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000528 DCHECK(output_.IsInvalid());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100529 output_overlaps_ = overlaps;
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000530 output_ = location;
531 }
532
533 void UpdateOut(Location location) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000534 // There are two reasons for updating an output:
535 // 1) Parameters, where we only know the exact stack slot after
536 // doing full register allocation.
537 // 2) Unallocated location.
538 DCHECK(output_.IsStackSlot() || output_.IsDoubleStackSlot() || output_.IsUnallocated());
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000539 output_ = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100540 }
541
542 void AddTemp(Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100543 temps_.push_back(location);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100544 }
545
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -0700546 void AddRegisterTemps(size_t count) {
547 for (size_t i = 0; i < count; ++i) {
548 AddTemp(Location::RequiresRegister());
549 }
550 }
551
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100552 Location GetTemp(uint32_t at) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100553 return temps_[at];
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100554 }
555
556 void SetTempAt(uint32_t at, Location location) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100557 DCHECK(temps_[at].IsUnallocated() || temps_[at].IsInvalid());
558 temps_[at] = location;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100559 }
560
561 size_t GetTempCount() const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100562 return temps_.size();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100563 }
564
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100565 bool HasTemps() const { return !temps_.empty(); }
Nicolas Geoffray94015b92015-06-04 18:21:04 +0100566
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100567 Location Out() const { return output_; }
568
Serban Constantinescu806f0122016-03-09 11:10:16 +0000569 bool CanCall() const {
570 return call_kind_ != kNoCall;
571 }
572
573 bool WillCall() const {
574 return call_kind_ == kCallOnMainOnly || call_kind_ == kCallOnMainAndSlowPath;
575 }
576
577 bool CallsOnSlowPath() const {
578 return call_kind_ == kCallOnSlowPath || call_kind_ == kCallOnMainAndSlowPath;
579 }
580
581 bool OnlyCallsOnSlowPath() const {
582 return call_kind_ == kCallOnSlowPath;
583 }
584
585 bool CallsOnMainAndSlowPath() const {
586 return call_kind_ == kCallOnMainAndSlowPath;
587 }
588
589 bool NeedsSafepoint() const {
590 return CanCall();
591 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100592
Vladimir Marko70e97462016-08-09 11:04:26 +0100593 void SetCustomSlowPathCallerSaves(const RegisterSet& caller_saves) {
594 DCHECK(OnlyCallsOnSlowPath());
595 has_custom_slow_path_calling_convention_ = true;
596 custom_slow_path_caller_saves_ = caller_saves;
597 }
598
599 bool HasCustomSlowPathCallingConvention() const {
600 return has_custom_slow_path_calling_convention_;
601 }
602
603 const RegisterSet& GetCustomSlowPathCallerSaves() const {
604 DCHECK(HasCustomSlowPathCallingConvention());
605 return custom_slow_path_caller_saves_;
606 }
607
Nicolas Geoffray39468442014-09-02 15:17:15 +0100608 void SetStackBit(uint32_t index) {
609 stack_mask_->SetBit(index);
610 }
611
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100612 void ClearStackBit(uint32_t index) {
613 stack_mask_->ClearBit(index);
614 }
615
Nicolas Geoffray39468442014-09-02 15:17:15 +0100616 void SetRegisterBit(uint32_t reg_id) {
617 register_mask_ |= (1 << reg_id);
618 }
619
Nicolas Geoffray98893962015-01-21 12:32:32 +0000620 uint32_t GetRegisterMask() const {
621 return register_mask_;
622 }
623
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100624 bool RegisterContainsObject(uint32_t reg_id) {
625 return RegisterSet::Contains(register_mask_, reg_id);
626 }
627
628 void AddLiveRegister(Location location) {
629 live_registers_.Add(location);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100630 }
631
632 BitVector* GetStackMask() const {
633 return stack_mask_;
634 }
635
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100636 RegisterSet* GetLiveRegisters() {
637 return &live_registers_;
638 }
639
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000640 size_t GetNumberOfLiveRegisters() const {
641 return live_registers_.GetNumberOfRegisters();
642 }
643
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000644 bool OutputUsesSameAs(uint32_t input_index) const {
645 return (input_index == 0)
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100646 && output_.IsUnallocated()
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000647 && (output_.GetPolicy() == Location::kSameAsFirstInput);
648 }
649
650 bool IsFixedInput(uint32_t input_index) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100651 Location input = inputs_[input_index];
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000652 return input.IsRegister()
Nicolas Geoffray98893962015-01-21 12:32:32 +0000653 || input.IsFpuRegister()
654 || input.IsPair()
655 || input.IsStackSlot()
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000656 || input.IsDoubleStackSlot();
Nicolas Geoffray76905622014-09-25 14:39:26 +0100657 }
658
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000659 bool OutputCanOverlapWithInputs() const {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000660 return output_overlaps_ == Location::kOutputOverlap;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100661 }
662
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800663 bool Intrinsified() const {
664 return intrinsified_;
665 }
666
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100667 private:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100668 LocationSummary(HInstruction* instruction,
669 CallKind call_kind,
670 bool intrinsified,
671 ArenaAllocator* allocator);
672
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100673 ArenaVector<Location> inputs_;
674 ArenaVector<Location> temps_;
Vladimir Marko70e97462016-08-09 11:04:26 +0100675 const CallKind call_kind_;
676 // Whether these are locations for an intrinsified call.
677 const bool intrinsified_;
678 // Whether the slow path has default or custom calling convention.
679 bool has_custom_slow_path_calling_convention_;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100680 // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot
681 // share the same register as the inputs.
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000682 Location::OutputOverlap output_overlaps_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100683 Location output_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100684
685 // Mask of objects that live in the stack.
686 BitVector* stack_mask_;
687
688 // Mask of objects that live in register.
689 uint32_t register_mask_;
690
691 // Registers that are in use at this position.
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100692 RegisterSet live_registers_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100693
Vladimir Marko70e97462016-08-09 11:04:26 +0100694 // Custom slow path caller saves. Valid only if indicated by slow_path_calling_convention_.
695 RegisterSet custom_slow_path_caller_saves_;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800696
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700697 friend class RegisterAllocatorTest;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100698 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
699};
700
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100701} // namespace art
702
703#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_