blob: e6b55c72a194e4985563b31f61e6c3ce72d661c1 [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"
25#include "utils/managed_register.h"
26
27namespace art {
28
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010029class HConstant;
Nicolas Geoffray76716a62014-05-23 10:14:19 +010030class HInstruction;
31
32/**
33 * A Location is an abstraction over the potential location
34 * of an instruction. It could be in register or stack.
35 */
36class Location : public ValueObject {
37 public:
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +010038 static constexpr bool kDiesAtEntry = true;
39
Nicolas Geoffray76716a62014-05-23 10:14:19 +010040 enum Kind {
41 kInvalid = 0,
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010042 kConstant = 1,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010043 kStackSlot = 2, // 32bit stack slot.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010044 kDoubleStackSlot = 3, // 64bit stack slot.
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010045
46 kRegister = 4, // Core register.
47
48 // We do not use the value 5 because it conflicts with kLocationConstantMask.
49 kDoNotUse = 5,
50
51 kFpuRegister = 6, // Floating point processor.
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 Geoffray7fb49da2014-10-06 09:12:41 +010057 kQuickParameter = 7,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010058
59 // Unallocated location represents a location that is not fixed and can be
60 // allocated by a register allocator. Each unallocated location has
61 // a policy that specifies what kind of location is suitable. Payload
62 // contains register allocation policy.
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010063 kUnallocated = 8,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010064 };
65
66 Location() : value_(kInvalid) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010067 // Verify that non-constant location kinds do not interfere with kConstant.
68 COMPILE_ASSERT((kInvalid & kLocationConstantMask) != kConstant, TagError);
69 COMPILE_ASSERT((kUnallocated & kLocationConstantMask) != kConstant, TagError);
70 COMPILE_ASSERT((kStackSlot & kLocationConstantMask) != kConstant, TagError);
71 COMPILE_ASSERT((kDoubleStackSlot & kLocationConstantMask) != kConstant, TagError);
72 COMPILE_ASSERT((kRegister & kLocationConstantMask) != kConstant, TagError);
73 COMPILE_ASSERT((kQuickParameter & kLocationConstantMask) != kConstant, TagError);
74 COMPILE_ASSERT((kFpuRegister & kLocationConstantMask) != kConstant, TagError);
75 COMPILE_ASSERT((kConstant & kLocationConstantMask) == kConstant, TagError);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010076
Nicolas Geoffray76716a62014-05-23 10:14:19 +010077 DCHECK(!IsValid());
78 }
79
80 Location(const Location& other) : ValueObject(), value_(other.value_) {}
81
82 Location& operator=(const Location& other) {
83 value_ = other.value_;
84 return *this;
85 }
86
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010087 bool IsConstant() const {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010088 return (value_ & kLocationConstantMask) == kConstant;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010089 }
90
91 static Location ConstantLocation(HConstant* constant) {
92 DCHECK(constant != nullptr);
93 return Location(kConstant | reinterpret_cast<uword>(constant));
94 }
95
96 HConstant* GetConstant() const {
97 DCHECK(IsConstant());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010098 return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010099 }
100
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100101 bool IsValid() const {
102 return value_ != kInvalid;
103 }
104
105 bool IsInvalid() const {
106 return !IsValid();
107 }
108
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100109 // Empty location. Used if there the location should be ignored.
110 static Location NoLocation() {
111 return Location();
112 }
113
114 // Register locations.
115 static Location RegisterLocation(ManagedRegister reg) {
116 return Location(kRegister, reg.RegId());
117 }
118
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100119 static Location FpuRegisterLocation(ManagedRegister reg) {
120 return Location(kFpuRegister, reg.RegId());
121 }
122
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100123 bool IsRegister() const {
124 return GetKind() == kRegister;
125 }
126
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100127 bool IsFpuRegister() const {
128 return GetKind() == kFpuRegister;
129 }
130
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100131 ManagedRegister reg() const {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100132 DCHECK(IsRegister() || IsFpuRegister());
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100133 return static_cast<ManagedRegister>(GetPayload());
134 }
135
136 static uword EncodeStackIndex(intptr_t stack_index) {
137 DCHECK(-kStackIndexBias <= stack_index);
138 DCHECK(stack_index < kStackIndexBias);
139 return static_cast<uword>(kStackIndexBias + stack_index);
140 }
141
142 static Location StackSlot(intptr_t stack_index) {
143 uword payload = EncodeStackIndex(stack_index);
144 Location loc(kStackSlot, payload);
145 // Ensure that sign is preserved.
146 DCHECK_EQ(loc.GetStackIndex(), stack_index);
147 return loc;
148 }
149
150 bool IsStackSlot() const {
151 return GetKind() == kStackSlot;
152 }
153
154 static Location DoubleStackSlot(intptr_t stack_index) {
155 uword payload = EncodeStackIndex(stack_index);
156 Location loc(kDoubleStackSlot, payload);
157 // Ensure that sign is preserved.
158 DCHECK_EQ(loc.GetStackIndex(), stack_index);
159 return loc;
160 }
161
162 bool IsDoubleStackSlot() const {
163 return GetKind() == kDoubleStackSlot;
164 }
165
166 intptr_t GetStackIndex() const {
167 DCHECK(IsStackSlot() || IsDoubleStackSlot());
168 // Decode stack index manually to preserve sign.
169 return GetPayload() - kStackIndexBias;
170 }
171
172 intptr_t GetHighStackIndex(uintptr_t word_size) const {
173 DCHECK(IsDoubleStackSlot());
174 // Decode stack index manually to preserve sign.
175 return GetPayload() - kStackIndexBias + word_size;
176 }
177
178 static Location QuickParameter(uint32_t parameter_index) {
179 return Location(kQuickParameter, parameter_index);
180 }
181
182 uint32_t GetQuickParameterIndex() const {
183 DCHECK(IsQuickParameter());
184 return GetPayload();
185 }
186
187 bool IsQuickParameter() const {
188 return GetKind() == kQuickParameter;
189 }
190
191 arm::ArmManagedRegister AsArm() const;
192 x86::X86ManagedRegister AsX86() const;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100193 x86_64::X86_64ManagedRegister AsX86_64() const;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100194
195 Kind GetKind() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100196 return IsConstant() ? kConstant : KindField::Decode(value_);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100197 }
198
199 bool Equals(Location other) const {
200 return value_ == other.value_;
201 }
202
203 const char* DebugString() const {
204 switch (GetKind()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100205 case kInvalid: return "I";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100206 case kRegister: return "R";
207 case kStackSlot: return "S";
208 case kDoubleStackSlot: return "DS";
209 case kQuickParameter: return "Q";
210 case kUnallocated: return "U";
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100211 case kConstant: return "C";
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100212 case kFpuRegister: return "F";
213 case kDoNotUse:
214 LOG(FATAL) << "Should not use this location kind";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100215 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100216 UNREACHABLE();
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100217 return "?";
218 }
219
220 // Unallocated locations.
221 enum Policy {
222 kAny,
223 kRequiresRegister,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100224 kRequiresFpuRegister,
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100225 kSameAsFirstInput,
226 };
227
228 bool IsUnallocated() const {
229 return GetKind() == kUnallocated;
230 }
231
232 static Location UnallocatedLocation(Policy policy) {
233 return Location(kUnallocated, PolicyField::Encode(policy));
234 }
235
236 // Any free register is suitable to replace this unallocated location.
237 static Location Any() {
238 return UnallocatedLocation(kAny);
239 }
240
241 static Location RequiresRegister() {
242 return UnallocatedLocation(kRequiresRegister);
243 }
244
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100245 static Location RequiresFpuRegister() {
246 return UnallocatedLocation(kRequiresFpuRegister);
247 }
248
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100249 static Location RegisterOrConstant(HInstruction* instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100250 static Location ByteRegisterOrConstant(ManagedRegister reg, HInstruction* instruction);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100251
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100252 // The location of the first input to the instruction will be
253 // used to replace this unallocated location.
254 static Location SameAsFirstInput() {
255 return UnallocatedLocation(kSameAsFirstInput);
256 }
257
258 Policy GetPolicy() const {
259 DCHECK(IsUnallocated());
260 return PolicyField::Decode(GetPayload());
261 }
262
263 uword GetEncoding() const {
264 return GetPayload();
265 }
266
267 private:
268 // Number of bits required to encode Kind value.
269 static constexpr uint32_t kBitsForKind = 4;
270 static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100271 static constexpr uword kLocationConstantMask = 0x3;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100272
273 explicit Location(uword value) : value_(value) {}
274
275 Location(Kind kind, uword payload)
276 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
277
278 uword GetPayload() const {
279 return PayloadField::Decode(value_);
280 }
281
282 typedef BitField<Kind, 0, kBitsForKind> KindField;
283 typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
284
285 // Layout for kUnallocated locations payload.
286 typedef BitField<Policy, 0, 3> PolicyField;
287
288 // Layout for stack slots.
289 static const intptr_t kStackIndexBias =
290 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
291
292 // Location either contains kind and payload fields or a tagged handle for
293 // a constant locations. Values of enumeration Kind are selected in such a
294 // way that none of them can be interpreted as a kConstant tag.
295 uword value_;
296};
297
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100298class RegisterSet : public ValueObject {
299 public:
300 RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
301
302 void Add(Location loc) {
303 // TODO: floating point registers.
304 core_registers_ |= (1 << loc.reg().RegId());
305 }
306
307 bool ContainsCoreRegister(uint32_t id) {
308 return Contains(core_registers_, id);
309 }
310
311 bool ContainsFloatingPointRegister(uint32_t id) {
312 return Contains(floating_point_registers_, id);
313 }
314
315 static bool Contains(uint32_t register_set, uint32_t reg) {
316 return (register_set & (1 << reg)) != 0;
317 }
318
319 private:
320 uint32_t core_registers_;
321 uint32_t floating_point_registers_;
322
323 DISALLOW_COPY_AND_ASSIGN(RegisterSet);
324};
325
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100326/**
327 * The code generator computes LocationSummary for each instruction so that
328 * the instruction itself knows what code to generate: where to find the inputs
329 * and where to place the result.
330 *
331 * The intent is to have the code for generating the instruction independent of
332 * register allocation. A register allocator just has to provide a LocationSummary.
333 */
334class LocationSummary : public ArenaObject {
335 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100336 enum CallKind {
337 kNoCall,
338 kCallOnSlowPath,
339 kCall
340 };
341
Roland Levillain5799fc02014-09-25 12:15:20 +0100342 LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100343
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100344 void SetInAt(uint32_t at, Location location, bool dies_at_entry = false) {
345 dies_at_entry_.Put(at, dies_at_entry);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100346 inputs_.Put(at, location);
347 }
348
349 Location InAt(uint32_t at) const {
350 return inputs_.Get(at);
351 }
352
353 size_t GetInputCount() const {
354 return inputs_.Size();
355 }
356
357 void SetOut(Location location) {
358 output_ = Location(location);
359 }
360
361 void AddTemp(Location location) {
362 temps_.Add(location);
363 }
364
365 Location GetTemp(uint32_t at) const {
366 return temps_.Get(at);
367 }
368
369 void SetTempAt(uint32_t at, Location location) {
370 temps_.Put(at, location);
371 }
372
373 size_t GetTempCount() const {
374 return temps_.Size();
375 }
376
Nicolas Geoffray39468442014-09-02 15:17:15 +0100377 void SetEnvironmentAt(uint32_t at, Location location) {
378 environment_.Put(at, location);
379 }
380
381 Location GetEnvironmentAt(uint32_t at) const {
382 return environment_.Get(at);
383 }
384
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100385 Location Out() const { return output_; }
386
Nicolas Geoffray39468442014-09-02 15:17:15 +0100387 bool CanCall() const { return call_kind_ != kNoCall; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100388 bool WillCall() const { return call_kind_ == kCall; }
389 bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100390 bool NeedsSafepoint() const { return CanCall(); }
391
392 void SetStackBit(uint32_t index) {
393 stack_mask_->SetBit(index);
394 }
395
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100396 void ClearStackBit(uint32_t index) {
397 stack_mask_->ClearBit(index);
398 }
399
Nicolas Geoffray39468442014-09-02 15:17:15 +0100400 void SetRegisterBit(uint32_t reg_id) {
401 register_mask_ |= (1 << reg_id);
402 }
403
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100404 bool RegisterContainsObject(uint32_t reg_id) {
405 return RegisterSet::Contains(register_mask_, reg_id);
406 }
407
408 void AddLiveRegister(Location location) {
409 live_registers_.Add(location);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100410 }
411
412 BitVector* GetStackMask() const {
413 return stack_mask_;
414 }
415
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100416 RegisterSet* GetLiveRegisters() {
417 return &live_registers_;
418 }
419
Nicolas Geoffray76905622014-09-25 14:39:26 +0100420 bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const {
421 if (is_environment) return true;
422 Location location = Out();
Nicolas Geoffray76905622014-09-25 14:39:26 +0100423 if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) {
424 return false;
425 }
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100426 if (dies_at_entry_.Get(input)) {
427 return false;
428 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100429 return true;
430 }
431
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100432 private:
433 GrowableArray<Location> inputs_;
434 GrowableArray<Location> temps_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100435 GrowableArray<Location> environment_;
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100436 GrowableArray<bool> dies_at_entry_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100437 Location output_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100438 const CallKind call_kind_;
439
440 // Mask of objects that live in the stack.
441 BitVector* stack_mask_;
442
443 // Mask of objects that live in register.
444 uint32_t register_mask_;
445
446 // Registers that are in use at this position.
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100447 RegisterSet live_registers_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100448
449 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
450};
451
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100452std::ostream& operator<<(std::ostream& os, const Location& location);
453
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100454} // namespace art
455
456#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_