blob: dcf70f27b049afd99f2220c8a050fb9f82e23331 [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
20#include "base/bit_field.h"
Nicolas Geoffray39468442014-09-02 15:17:15 +010021#include "base/bit_vector.h"
Ian Rogers0279ebb2014-10-08 17:27:48 -070022#include "base/value_object.h"
23#include "utils/arena_object.h"
Nicolas Geoffray76716a62014-05-23 10:14:19 +010024#include "utils/growable_array.h"
Nicolas Geoffray76716a62014-05-23 10:14:19 +010025
26namespace art {
27
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010028class HConstant;
Nicolas Geoffray76716a62014-05-23 10:14:19 +010029class HInstruction;
30
31/**
32 * A Location is an abstraction over the potential location
33 * of an instruction. It could be in register or stack.
34 */
35class Location : public ValueObject {
36 public:
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +010037 static constexpr bool kDiesAtEntry = true;
38
Nicolas Geoffray76716a62014-05-23 10:14:19 +010039 enum Kind {
40 kInvalid = 0,
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010041 kConstant = 1,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010042 kStackSlot = 2, // 32bit stack slot.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010043 kDoubleStackSlot = 3, // 64bit stack slot.
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010044
45 kRegister = 4, // Core register.
46
47 // We do not use the value 5 because it conflicts with kLocationConstantMask.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010048 kDoNotUse5 = 5,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010049
50 kFpuRegister = 6, // Floating point processor.
51
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010052 kRegisterPair = 7,
53
Nicolas Geoffray76716a62014-05-23 10:14:19 +010054 // On 32bits architectures, quick can pass a long where the
55 // low bits are in the last parameter register, and the high
56 // bits are in a stack slot. The kQuickParameter kind is for
57 // handling this special case.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010058 kQuickParameter = 8,
59
60 // We do not use the value 9 because it conflicts with kLocationConstantMask.
61 kDoNotUse9 = 9,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010062
63 // Unallocated location represents a location that is not fixed and can be
64 // allocated by a register allocator. Each unallocated location has
65 // a policy that specifies what kind of location is suitable. Payload
66 // contains register allocation policy.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010067 kUnallocated = 10,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010068 };
69
70 Location() : value_(kInvalid) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010071 // Verify that non-constant location kinds do not interfere with kConstant.
72 COMPILE_ASSERT((kInvalid & kLocationConstantMask) != kConstant, TagError);
73 COMPILE_ASSERT((kUnallocated & kLocationConstantMask) != kConstant, TagError);
74 COMPILE_ASSERT((kStackSlot & kLocationConstantMask) != kConstant, TagError);
75 COMPILE_ASSERT((kDoubleStackSlot & kLocationConstantMask) != kConstant, TagError);
76 COMPILE_ASSERT((kRegister & kLocationConstantMask) != kConstant, TagError);
77 COMPILE_ASSERT((kQuickParameter & kLocationConstantMask) != kConstant, TagError);
78 COMPILE_ASSERT((kFpuRegister & kLocationConstantMask) != kConstant, TagError);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010079 COMPILE_ASSERT((kRegisterPair & kLocationConstantMask) != kConstant, TagError);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010080 COMPILE_ASSERT((kConstant & kLocationConstantMask) == kConstant, TagError);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010081
Nicolas Geoffray76716a62014-05-23 10:14:19 +010082 DCHECK(!IsValid());
83 }
84
85 Location(const Location& other) : ValueObject(), value_(other.value_) {}
86
87 Location& operator=(const Location& other) {
88 value_ = other.value_;
89 return *this;
90 }
91
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010092 bool IsConstant() const {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010093 return (value_ & kLocationConstantMask) == kConstant;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010094 }
95
96 static Location ConstantLocation(HConstant* constant) {
97 DCHECK(constant != nullptr);
Ian Rogers13735952014-10-08 12:43:28 -070098 return Location(kConstant | reinterpret_cast<uintptr_t>(constant));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010099 }
100
101 HConstant* GetConstant() const {
102 DCHECK(IsConstant());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100103 return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100104 }
105
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100106 bool IsValid() const {
107 return value_ != kInvalid;
108 }
109
110 bool IsInvalid() const {
111 return !IsValid();
112 }
113
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100114 // Empty location. Used if there the location should be ignored.
115 static Location NoLocation() {
116 return Location();
117 }
118
119 // Register locations.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100120 static Location RegisterLocation(int reg) {
121 return Location(kRegister, reg);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100122 }
123
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100124 static Location FpuRegisterLocation(int reg) {
125 return Location(kFpuRegister, reg);
126 }
127
128 static Location RegisterPairLocation(int low, int high) {
129 return Location(kRegisterPair, low << 16 | high);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100130 }
131
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100132 bool IsRegister() const {
133 return GetKind() == kRegister;
134 }
135
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100136 bool IsFpuRegister() const {
137 return GetKind() == kFpuRegister;
138 }
139
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100140 bool IsRegisterPair() const {
141 return GetKind() == kRegisterPair;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100142 }
143
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100144 int reg() const {
145 DCHECK(IsRegister() || IsFpuRegister());
146 return GetPayload();
147 }
148
149 template <typename T>
150 T As() const {
151 return static_cast<T>(reg());
152 }
153
154 template <typename T>
155 T AsRegisterPairLow() const {
156 DCHECK(IsRegisterPair());
157 return static_cast<T>(GetPayload() >> 16);
158 }
159
160 template <typename T>
161 T AsRegisterPairHigh() const {
162 DCHECK(IsRegisterPair());
163 return static_cast<T>(GetPayload() & 0xFFFF);
164 }
165
166 static uintptr_t EncodeStackIndex(intptr_t stack_index) {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100167 DCHECK(-kStackIndexBias <= stack_index);
168 DCHECK(stack_index < kStackIndexBias);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100169 return static_cast<uintptr_t>(kStackIndexBias + stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100170 }
171
172 static Location StackSlot(intptr_t stack_index) {
Ian Rogers13735952014-10-08 12:43:28 -0700173 uintptr_t payload = EncodeStackIndex(stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100174 Location loc(kStackSlot, payload);
175 // Ensure that sign is preserved.
176 DCHECK_EQ(loc.GetStackIndex(), stack_index);
177 return loc;
178 }
179
180 bool IsStackSlot() const {
181 return GetKind() == kStackSlot;
182 }
183
184 static Location DoubleStackSlot(intptr_t stack_index) {
Ian Rogers13735952014-10-08 12:43:28 -0700185 uintptr_t payload = EncodeStackIndex(stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100186 Location loc(kDoubleStackSlot, payload);
187 // Ensure that sign is preserved.
188 DCHECK_EQ(loc.GetStackIndex(), stack_index);
189 return loc;
190 }
191
192 bool IsDoubleStackSlot() const {
193 return GetKind() == kDoubleStackSlot;
194 }
195
196 intptr_t GetStackIndex() const {
197 DCHECK(IsStackSlot() || IsDoubleStackSlot());
198 // Decode stack index manually to preserve sign.
199 return GetPayload() - kStackIndexBias;
200 }
201
202 intptr_t GetHighStackIndex(uintptr_t word_size) const {
203 DCHECK(IsDoubleStackSlot());
204 // Decode stack index manually to preserve sign.
205 return GetPayload() - kStackIndexBias + word_size;
206 }
207
208 static Location QuickParameter(uint32_t parameter_index) {
209 return Location(kQuickParameter, parameter_index);
210 }
211
212 uint32_t GetQuickParameterIndex() const {
213 DCHECK(IsQuickParameter());
214 return GetPayload();
215 }
216
217 bool IsQuickParameter() const {
218 return GetKind() == kQuickParameter;
219 }
220
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100221 Kind GetKind() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100222 return IsConstant() ? kConstant : KindField::Decode(value_);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100223 }
224
225 bool Equals(Location other) const {
226 return value_ == other.value_;
227 }
228
229 const char* DebugString() const {
230 switch (GetKind()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100231 case kInvalid: return "I";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100232 case kRegister: return "R";
233 case kStackSlot: return "S";
234 case kDoubleStackSlot: return "DS";
235 case kQuickParameter: return "Q";
236 case kUnallocated: return "U";
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100237 case kConstant: return "C";
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100238 case kFpuRegister: return "F";
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100239 case kRegisterPair: return "RP";
240 case kDoNotUse5: // fall-through
241 case kDoNotUse9:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100242 LOG(FATAL) << "Should not use this location kind";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100243 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100244 UNREACHABLE();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100245 return "?";
246 }
247
248 // Unallocated locations.
249 enum Policy {
250 kAny,
251 kRequiresRegister,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100252 kRequiresFpuRegister,
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100253 kSameAsFirstInput,
254 };
255
256 bool IsUnallocated() const {
257 return GetKind() == kUnallocated;
258 }
259
260 static Location UnallocatedLocation(Policy policy) {
261 return Location(kUnallocated, PolicyField::Encode(policy));
262 }
263
264 // Any free register is suitable to replace this unallocated location.
265 static Location Any() {
266 return UnallocatedLocation(kAny);
267 }
268
269 static Location RequiresRegister() {
270 return UnallocatedLocation(kRequiresRegister);
271 }
272
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100273 static Location RequiresFpuRegister() {
274 return UnallocatedLocation(kRequiresFpuRegister);
275 }
276
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100277 static Location RegisterOrConstant(HInstruction* instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100278 static Location ByteRegisterOrConstant(int reg, HInstruction* instruction);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100279
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100280 // The location of the first input to the instruction will be
281 // used to replace this unallocated location.
282 static Location SameAsFirstInput() {
283 return UnallocatedLocation(kSameAsFirstInput);
284 }
285
286 Policy GetPolicy() const {
287 DCHECK(IsUnallocated());
288 return PolicyField::Decode(GetPayload());
289 }
290
Ian Rogers13735952014-10-08 12:43:28 -0700291 uintptr_t GetEncoding() const {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100292 return GetPayload();
293 }
294
295 private:
296 // Number of bits required to encode Kind value.
297 static constexpr uint32_t kBitsForKind = 4;
Ian Rogers13735952014-10-08 12:43:28 -0700298 static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind;
299 static constexpr uintptr_t kLocationConstantMask = 0x3;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100300
Ian Rogers13735952014-10-08 12:43:28 -0700301 explicit Location(uintptr_t value) : value_(value) {}
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100302
Ian Rogers13735952014-10-08 12:43:28 -0700303 Location(Kind kind, uintptr_t payload)
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100304 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
305
Ian Rogers13735952014-10-08 12:43:28 -0700306 uintptr_t GetPayload() const {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100307 return PayloadField::Decode(value_);
308 }
309
310 typedef BitField<Kind, 0, kBitsForKind> KindField;
Ian Rogers13735952014-10-08 12:43:28 -0700311 typedef BitField<uintptr_t, kBitsForKind, kBitsForPayload> PayloadField;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100312
313 // Layout for kUnallocated locations payload.
314 typedef BitField<Policy, 0, 3> PolicyField;
315
316 // Layout for stack slots.
317 static const intptr_t kStackIndexBias =
318 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
319
320 // Location either contains kind and payload fields or a tagged handle for
321 // a constant locations. Values of enumeration Kind are selected in such a
322 // way that none of them can be interpreted as a kConstant tag.
Ian Rogers13735952014-10-08 12:43:28 -0700323 uintptr_t value_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100324};
325
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100326class RegisterSet : public ValueObject {
327 public:
328 RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
329
330 void Add(Location loc) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100331 if (loc.IsRegister()) {
332 core_registers_ |= (1 << loc.reg());
333 } else {
334 DCHECK(loc.IsFpuRegister());
335 floating_point_registers_ |= (1 << loc.reg());
336 }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100337 }
338
339 bool ContainsCoreRegister(uint32_t id) {
340 return Contains(core_registers_, id);
341 }
342
343 bool ContainsFloatingPointRegister(uint32_t id) {
344 return Contains(floating_point_registers_, id);
345 }
346
347 static bool Contains(uint32_t register_set, uint32_t reg) {
348 return (register_set & (1 << reg)) != 0;
349 }
350
351 private:
352 uint32_t core_registers_;
353 uint32_t floating_point_registers_;
354
355 DISALLOW_COPY_AND_ASSIGN(RegisterSet);
356};
357
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100358/**
359 * The code generator computes LocationSummary for each instruction so that
360 * the instruction itself knows what code to generate: where to find the inputs
361 * and where to place the result.
362 *
363 * The intent is to have the code for generating the instruction independent of
364 * register allocation. A register allocator just has to provide a LocationSummary.
365 */
366class LocationSummary : public ArenaObject {
367 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100368 enum CallKind {
369 kNoCall,
370 kCallOnSlowPath,
371 kCall
372 };
373
Roland Levillain5799fc02014-09-25 12:15:20 +0100374 LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100375
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100376 void SetInAt(uint32_t at, Location location, bool dies_at_entry = false) {
377 dies_at_entry_.Put(at, dies_at_entry);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100378 inputs_.Put(at, location);
379 }
380
381 Location InAt(uint32_t at) const {
382 return inputs_.Get(at);
383 }
384
385 size_t GetInputCount() const {
386 return inputs_.Size();
387 }
388
389 void SetOut(Location location) {
390 output_ = Location(location);
391 }
392
393 void AddTemp(Location location) {
394 temps_.Add(location);
395 }
396
397 Location GetTemp(uint32_t at) const {
398 return temps_.Get(at);
399 }
400
401 void SetTempAt(uint32_t at, Location location) {
402 temps_.Put(at, location);
403 }
404
405 size_t GetTempCount() const {
406 return temps_.Size();
407 }
408
Nicolas Geoffray39468442014-09-02 15:17:15 +0100409 void SetEnvironmentAt(uint32_t at, Location location) {
410 environment_.Put(at, location);
411 }
412
413 Location GetEnvironmentAt(uint32_t at) const {
414 return environment_.Get(at);
415 }
416
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100417 Location Out() const { return output_; }
418
Nicolas Geoffray39468442014-09-02 15:17:15 +0100419 bool CanCall() const { return call_kind_ != kNoCall; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100420 bool WillCall() const { return call_kind_ == kCall; }
421 bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100422 bool NeedsSafepoint() const { return CanCall(); }
423
424 void SetStackBit(uint32_t index) {
425 stack_mask_->SetBit(index);
426 }
427
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100428 void ClearStackBit(uint32_t index) {
429 stack_mask_->ClearBit(index);
430 }
431
Nicolas Geoffray39468442014-09-02 15:17:15 +0100432 void SetRegisterBit(uint32_t reg_id) {
433 register_mask_ |= (1 << reg_id);
434 }
435
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100436 bool RegisterContainsObject(uint32_t reg_id) {
437 return RegisterSet::Contains(register_mask_, reg_id);
438 }
439
440 void AddLiveRegister(Location location) {
441 live_registers_.Add(location);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100442 }
443
444 BitVector* GetStackMask() const {
445 return stack_mask_;
446 }
447
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100448 RegisterSet* GetLiveRegisters() {
449 return &live_registers_;
450 }
451
Nicolas Geoffray76905622014-09-25 14:39:26 +0100452 bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const {
453 if (is_environment) return true;
454 Location location = Out();
Nicolas Geoffray76905622014-09-25 14:39:26 +0100455 if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) {
456 return false;
457 }
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100458 if (dies_at_entry_.Get(input)) {
459 return false;
460 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100461 return true;
462 }
463
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100464 private:
465 GrowableArray<Location> inputs_;
466 GrowableArray<Location> temps_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100467 GrowableArray<Location> environment_;
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100468 GrowableArray<bool> dies_at_entry_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100469 Location output_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100470 const CallKind call_kind_;
471
472 // Mask of objects that live in the stack.
473 BitVector* stack_mask_;
474
475 // Mask of objects that live in register.
476 uint32_t register_mask_;
477
478 // Registers that are in use at this position.
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100479 RegisterSet live_registers_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100480
481 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
482};
483
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100484std::ostream& operator<<(std::ostream& os, const Location& location);
485
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100486} // namespace art
487
488#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_