blob: ac44a42e768532d857c18323b8a5f472826ae0b3 [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"
Nicolas Geoffray76716a62014-05-23 10:14:19 +010022#include "utils/allocation.h"
23#include "utils/growable_array.h"
Nicolas Geoffray76716a62014-05-23 10:14:19 +010024
25namespace art {
26
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010027class HConstant;
Nicolas Geoffray76716a62014-05-23 10:14:19 +010028class HInstruction;
29
30/**
31 * A Location is an abstraction over the potential location
32 * of an instruction. It could be in register or stack.
33 */
34class Location : public ValueObject {
35 public:
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +010036 static constexpr bool kDiesAtEntry = true;
37
Nicolas Geoffray76716a62014-05-23 10:14:19 +010038 enum Kind {
39 kInvalid = 0,
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010040 kConstant = 1,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010041 kStackSlot = 2, // 32bit stack slot.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010042 kDoubleStackSlot = 3, // 64bit stack slot.
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010043
44 kRegister = 4, // Core register.
45
46 // We do not use the value 5 because it conflicts with kLocationConstantMask.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010047 kDoNotUse5 = 5,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010048
49 kFpuRegister = 6, // Floating point processor.
50
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010051 kRegisterPair = 7,
52
Nicolas Geoffray76716a62014-05-23 10:14:19 +010053 // On 32bits architectures, quick can pass a long where the
54 // low bits are in the last parameter register, and the high
55 // bits are in a stack slot. The kQuickParameter kind is for
56 // handling this special case.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010057 kQuickParameter = 8,
58
59 // We do not use the value 9 because it conflicts with kLocationConstantMask.
60 kDoNotUse9 = 9,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010061
62 // Unallocated location represents a location that is not fixed and can be
63 // allocated by a register allocator. Each unallocated location has
64 // a policy that specifies what kind of location is suitable. Payload
65 // contains register allocation policy.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010066 kUnallocated = 10,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010067 };
68
69 Location() : value_(kInvalid) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010070 // Verify that non-constant location kinds do not interfere with kConstant.
71 COMPILE_ASSERT((kInvalid & kLocationConstantMask) != kConstant, TagError);
72 COMPILE_ASSERT((kUnallocated & kLocationConstantMask) != kConstant, TagError);
73 COMPILE_ASSERT((kStackSlot & kLocationConstantMask) != kConstant, TagError);
74 COMPILE_ASSERT((kDoubleStackSlot & kLocationConstantMask) != kConstant, TagError);
75 COMPILE_ASSERT((kRegister & kLocationConstantMask) != kConstant, TagError);
76 COMPILE_ASSERT((kQuickParameter & kLocationConstantMask) != kConstant, TagError);
77 COMPILE_ASSERT((kFpuRegister & kLocationConstantMask) != kConstant, TagError);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010078 COMPILE_ASSERT((kRegisterPair & kLocationConstantMask) != kConstant, TagError);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010079 COMPILE_ASSERT((kConstant & kLocationConstantMask) == kConstant, TagError);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010080
Nicolas Geoffray76716a62014-05-23 10:14:19 +010081 DCHECK(!IsValid());
82 }
83
84 Location(const Location& other) : ValueObject(), value_(other.value_) {}
85
86 Location& operator=(const Location& other) {
87 value_ = other.value_;
88 return *this;
89 }
90
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010091 bool IsConstant() const {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010092 return (value_ & kLocationConstantMask) == kConstant;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010093 }
94
95 static Location ConstantLocation(HConstant* constant) {
96 DCHECK(constant != nullptr);
97 return Location(kConstant | reinterpret_cast<uword>(constant));
98 }
99
100 HConstant* GetConstant() const {
101 DCHECK(IsConstant());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100102 return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100103 }
104
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100105 bool IsValid() const {
106 return value_ != kInvalid;
107 }
108
109 bool IsInvalid() const {
110 return !IsValid();
111 }
112
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100113 // Empty location. Used if there the location should be ignored.
114 static Location NoLocation() {
115 return Location();
116 }
117
118 // Register locations.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100119 static Location RegisterLocation(int reg) {
120 return Location(kRegister, reg);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100121 }
122
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100123 static Location FpuRegisterLocation(int reg) {
124 return Location(kFpuRegister, reg);
125 }
126
127 static Location RegisterPairLocation(int low, int high) {
128 return Location(kRegisterPair, low << 16 | high);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100129 }
130
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100131 bool IsRegister() const {
132 return GetKind() == kRegister;
133 }
134
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100135 bool IsFpuRegister() const {
136 return GetKind() == kFpuRegister;
137 }
138
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100139 bool IsRegisterPair() const {
140 return GetKind() == kRegisterPair;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100141 }
142
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100143 int reg() const {
144 DCHECK(IsRegister() || IsFpuRegister());
145 return GetPayload();
146 }
147
148 template <typename T>
149 T As() const {
150 return static_cast<T>(reg());
151 }
152
153 template <typename T>
154 T AsRegisterPairLow() const {
155 DCHECK(IsRegisterPair());
156 return static_cast<T>(GetPayload() >> 16);
157 }
158
159 template <typename T>
160 T AsRegisterPairHigh() const {
161 DCHECK(IsRegisterPair());
162 return static_cast<T>(GetPayload() & 0xFFFF);
163 }
164
165 static uintptr_t EncodeStackIndex(intptr_t stack_index) {
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100166 DCHECK(-kStackIndexBias <= stack_index);
167 DCHECK(stack_index < kStackIndexBias);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100168 return static_cast<uintptr_t>(kStackIndexBias + stack_index);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100169 }
170
171 static Location StackSlot(intptr_t stack_index) {
172 uword payload = EncodeStackIndex(stack_index);
173 Location loc(kStackSlot, payload);
174 // Ensure that sign is preserved.
175 DCHECK_EQ(loc.GetStackIndex(), stack_index);
176 return loc;
177 }
178
179 bool IsStackSlot() const {
180 return GetKind() == kStackSlot;
181 }
182
183 static Location DoubleStackSlot(intptr_t stack_index) {
184 uword payload = EncodeStackIndex(stack_index);
185 Location loc(kDoubleStackSlot, payload);
186 // Ensure that sign is preserved.
187 DCHECK_EQ(loc.GetStackIndex(), stack_index);
188 return loc;
189 }
190
191 bool IsDoubleStackSlot() const {
192 return GetKind() == kDoubleStackSlot;
193 }
194
195 intptr_t GetStackIndex() const {
196 DCHECK(IsStackSlot() || IsDoubleStackSlot());
197 // Decode stack index manually to preserve sign.
198 return GetPayload() - kStackIndexBias;
199 }
200
201 intptr_t GetHighStackIndex(uintptr_t word_size) const {
202 DCHECK(IsDoubleStackSlot());
203 // Decode stack index manually to preserve sign.
204 return GetPayload() - kStackIndexBias + word_size;
205 }
206
207 static Location QuickParameter(uint32_t parameter_index) {
208 return Location(kQuickParameter, parameter_index);
209 }
210
211 uint32_t GetQuickParameterIndex() const {
212 DCHECK(IsQuickParameter());
213 return GetPayload();
214 }
215
216 bool IsQuickParameter() const {
217 return GetKind() == kQuickParameter;
218 }
219
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100220 Kind GetKind() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100221 return IsConstant() ? kConstant : KindField::Decode(value_);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100222 }
223
224 bool Equals(Location other) const {
225 return value_ == other.value_;
226 }
227
228 const char* DebugString() const {
229 switch (GetKind()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100230 case kInvalid: return "I";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100231 case kRegister: return "R";
232 case kStackSlot: return "S";
233 case kDoubleStackSlot: return "DS";
234 case kQuickParameter: return "Q";
235 case kUnallocated: return "U";
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100236 case kConstant: return "C";
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100237 case kFpuRegister: return "F";
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100238 case kRegisterPair: return "RP";
239 case kDoNotUse5: // fall-through
240 case kDoNotUse9:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100241 LOG(FATAL) << "Should not use this location kind";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100242 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100243 UNREACHABLE();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100244 return "?";
245 }
246
247 // Unallocated locations.
248 enum Policy {
249 kAny,
250 kRequiresRegister,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100251 kRequiresFpuRegister,
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100252 kSameAsFirstInput,
253 };
254
255 bool IsUnallocated() const {
256 return GetKind() == kUnallocated;
257 }
258
259 static Location UnallocatedLocation(Policy policy) {
260 return Location(kUnallocated, PolicyField::Encode(policy));
261 }
262
263 // Any free register is suitable to replace this unallocated location.
264 static Location Any() {
265 return UnallocatedLocation(kAny);
266 }
267
268 static Location RequiresRegister() {
269 return UnallocatedLocation(kRequiresRegister);
270 }
271
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100272 static Location RequiresFpuRegister() {
273 return UnallocatedLocation(kRequiresFpuRegister);
274 }
275
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100276 static Location RegisterOrConstant(HInstruction* instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100277 static Location ByteRegisterOrConstant(int reg, HInstruction* instruction);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100278
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100279 // The location of the first input to the instruction will be
280 // used to replace this unallocated location.
281 static Location SameAsFirstInput() {
282 return UnallocatedLocation(kSameAsFirstInput);
283 }
284
285 Policy GetPolicy() const {
286 DCHECK(IsUnallocated());
287 return PolicyField::Decode(GetPayload());
288 }
289
290 uword GetEncoding() const {
291 return GetPayload();
292 }
293
294 private:
295 // Number of bits required to encode Kind value.
296 static constexpr uint32_t kBitsForKind = 4;
297 static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100298 static constexpr uword kLocationConstantMask = 0x3;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100299
300 explicit Location(uword value) : value_(value) {}
301
302 Location(Kind kind, uword payload)
303 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
304
305 uword GetPayload() const {
306 return PayloadField::Decode(value_);
307 }
308
309 typedef BitField<Kind, 0, kBitsForKind> KindField;
310 typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
311
312 // Layout for kUnallocated locations payload.
313 typedef BitField<Policy, 0, 3> PolicyField;
314
315 // Layout for stack slots.
316 static const intptr_t kStackIndexBias =
317 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
318
319 // Location either contains kind and payload fields or a tagged handle for
320 // a constant locations. Values of enumeration Kind are selected in such a
321 // way that none of them can be interpreted as a kConstant tag.
322 uword value_;
323};
324
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100325class RegisterSet : public ValueObject {
326 public:
327 RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
328
329 void Add(Location loc) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100330 if (loc.IsRegister()) {
331 core_registers_ |= (1 << loc.reg());
332 } else {
333 DCHECK(loc.IsFpuRegister());
334 floating_point_registers_ |= (1 << loc.reg());
335 }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100336 }
337
338 bool ContainsCoreRegister(uint32_t id) {
339 return Contains(core_registers_, id);
340 }
341
342 bool ContainsFloatingPointRegister(uint32_t id) {
343 return Contains(floating_point_registers_, id);
344 }
345
346 static bool Contains(uint32_t register_set, uint32_t reg) {
347 return (register_set & (1 << reg)) != 0;
348 }
349
350 private:
351 uint32_t core_registers_;
352 uint32_t floating_point_registers_;
353
354 DISALLOW_COPY_AND_ASSIGN(RegisterSet);
355};
356
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100357/**
358 * The code generator computes LocationSummary for each instruction so that
359 * the instruction itself knows what code to generate: where to find the inputs
360 * and where to place the result.
361 *
362 * The intent is to have the code for generating the instruction independent of
363 * register allocation. A register allocator just has to provide a LocationSummary.
364 */
365class LocationSummary : public ArenaObject {
366 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100367 enum CallKind {
368 kNoCall,
369 kCallOnSlowPath,
370 kCall
371 };
372
Roland Levillain5799fc02014-09-25 12:15:20 +0100373 LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100374
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100375 void SetInAt(uint32_t at, Location location, bool dies_at_entry = false) {
376 dies_at_entry_.Put(at, dies_at_entry);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100377 inputs_.Put(at, location);
378 }
379
380 Location InAt(uint32_t at) const {
381 return inputs_.Get(at);
382 }
383
384 size_t GetInputCount() const {
385 return inputs_.Size();
386 }
387
388 void SetOut(Location location) {
389 output_ = Location(location);
390 }
391
392 void AddTemp(Location location) {
393 temps_.Add(location);
394 }
395
396 Location GetTemp(uint32_t at) const {
397 return temps_.Get(at);
398 }
399
400 void SetTempAt(uint32_t at, Location location) {
401 temps_.Put(at, location);
402 }
403
404 size_t GetTempCount() const {
405 return temps_.Size();
406 }
407
Nicolas Geoffray39468442014-09-02 15:17:15 +0100408 void SetEnvironmentAt(uint32_t at, Location location) {
409 environment_.Put(at, location);
410 }
411
412 Location GetEnvironmentAt(uint32_t at) const {
413 return environment_.Get(at);
414 }
415
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100416 Location Out() const { return output_; }
417
Nicolas Geoffray39468442014-09-02 15:17:15 +0100418 bool CanCall() const { return call_kind_ != kNoCall; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100419 bool WillCall() const { return call_kind_ == kCall; }
420 bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100421 bool NeedsSafepoint() const { return CanCall(); }
422
423 void SetStackBit(uint32_t index) {
424 stack_mask_->SetBit(index);
425 }
426
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100427 void ClearStackBit(uint32_t index) {
428 stack_mask_->ClearBit(index);
429 }
430
Nicolas Geoffray39468442014-09-02 15:17:15 +0100431 void SetRegisterBit(uint32_t reg_id) {
432 register_mask_ |= (1 << reg_id);
433 }
434
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100435 bool RegisterContainsObject(uint32_t reg_id) {
436 return RegisterSet::Contains(register_mask_, reg_id);
437 }
438
439 void AddLiveRegister(Location location) {
440 live_registers_.Add(location);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100441 }
442
443 BitVector* GetStackMask() const {
444 return stack_mask_;
445 }
446
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100447 RegisterSet* GetLiveRegisters() {
448 return &live_registers_;
449 }
450
Nicolas Geoffray76905622014-09-25 14:39:26 +0100451 bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const {
452 if (is_environment) return true;
453 Location location = Out();
Nicolas Geoffray76905622014-09-25 14:39:26 +0100454 if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) {
455 return false;
456 }
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100457 if (dies_at_entry_.Get(input)) {
458 return false;
459 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100460 return true;
461 }
462
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100463 private:
464 GrowableArray<Location> inputs_;
465 GrowableArray<Location> temps_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100466 GrowableArray<Location> environment_;
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100467 GrowableArray<bool> dies_at_entry_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100468 Location output_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100469 const CallKind call_kind_;
470
471 // Mask of objects that live in the stack.
472 BitVector* stack_mask_;
473
474 // Mask of objects that live in register.
475 uint32_t register_mask_;
476
477 // Registers that are in use at this position.
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100478 RegisterSet live_registers_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100479
480 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
481};
482
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100483std::ostream& operator<<(std::ostream& os, const Location& location);
484
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100485} // namespace art
486
487#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_