blob: 0e77deb9de266d1f912aedc5ea9471f70c177f37 [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"
24#include "utils/managed_register.h"
25
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,
42 kStackSlot = 2, // Word size slot.
43 kDoubleStackSlot = 3, // 64bit stack slot.
44 kRegister = 4,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010045 // On 32bits architectures, quick can pass a long where the
46 // low bits are in the last parameter register, and the high
47 // bits are in a stack slot. The kQuickParameter kind is for
48 // handling this special case.
Nicolas Geoffray39468442014-09-02 15:17:15 +010049 kQuickParameter = 6,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010050
51 // Unallocated location represents a location that is not fixed and can be
52 // allocated by a register allocator. Each unallocated location has
53 // a policy that specifies what kind of location is suitable. Payload
54 // contains register allocation policy.
Nicolas Geoffray39468442014-09-02 15:17:15 +010055 kUnallocated = 7,
Nicolas Geoffray76716a62014-05-23 10:14:19 +010056 };
57
58 Location() : value_(kInvalid) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010059 // Verify that non-tagged location kinds do not interfere with kConstantTag.
60 COMPILE_ASSERT((kInvalid & kLocationTagMask) != kConstant, TagError);
61 COMPILE_ASSERT((kUnallocated & kLocationTagMask) != kConstant, TagError);
62 COMPILE_ASSERT((kStackSlot & kLocationTagMask) != kConstant, TagError);
63 COMPILE_ASSERT((kDoubleStackSlot & kLocationTagMask) != kConstant, TagError);
64 COMPILE_ASSERT((kRegister & kLocationTagMask) != kConstant, TagError);
Nicolas Geoffray39468442014-09-02 15:17:15 +010065 COMPILE_ASSERT((kQuickParameter & kLocationTagMask) != kConstant, TagError);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010066 COMPILE_ASSERT((kConstant & kLocationTagMask) == kConstant, TagError);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010067
Nicolas Geoffray76716a62014-05-23 10:14:19 +010068 DCHECK(!IsValid());
69 }
70
71 Location(const Location& other) : ValueObject(), value_(other.value_) {}
72
73 Location& operator=(const Location& other) {
74 value_ = other.value_;
75 return *this;
76 }
77
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010078 bool IsConstant() const {
79 return (value_ & kLocationTagMask) == kConstant;
80 }
81
82 static Location ConstantLocation(HConstant* constant) {
83 DCHECK(constant != nullptr);
84 return Location(kConstant | reinterpret_cast<uword>(constant));
85 }
86
87 HConstant* GetConstant() const {
88 DCHECK(IsConstant());
89 return reinterpret_cast<HConstant*>(value_ & ~kLocationTagMask);
90 }
91
Nicolas Geoffray76716a62014-05-23 10:14:19 +010092 bool IsValid() const {
93 return value_ != kInvalid;
94 }
95
96 bool IsInvalid() const {
97 return !IsValid();
98 }
99
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100100 // Empty location. Used if there the location should be ignored.
101 static Location NoLocation() {
102 return Location();
103 }
104
105 // Register locations.
106 static Location RegisterLocation(ManagedRegister reg) {
107 return Location(kRegister, reg.RegId());
108 }
109
110 bool IsRegister() const {
111 return GetKind() == kRegister;
112 }
113
114 ManagedRegister reg() const {
115 DCHECK(IsRegister());
116 return static_cast<ManagedRegister>(GetPayload());
117 }
118
119 static uword EncodeStackIndex(intptr_t stack_index) {
120 DCHECK(-kStackIndexBias <= stack_index);
121 DCHECK(stack_index < kStackIndexBias);
122 return static_cast<uword>(kStackIndexBias + stack_index);
123 }
124
125 static Location StackSlot(intptr_t stack_index) {
126 uword payload = EncodeStackIndex(stack_index);
127 Location loc(kStackSlot, payload);
128 // Ensure that sign is preserved.
129 DCHECK_EQ(loc.GetStackIndex(), stack_index);
130 return loc;
131 }
132
133 bool IsStackSlot() const {
134 return GetKind() == kStackSlot;
135 }
136
137 static Location DoubleStackSlot(intptr_t stack_index) {
138 uword payload = EncodeStackIndex(stack_index);
139 Location loc(kDoubleStackSlot, payload);
140 // Ensure that sign is preserved.
141 DCHECK_EQ(loc.GetStackIndex(), stack_index);
142 return loc;
143 }
144
145 bool IsDoubleStackSlot() const {
146 return GetKind() == kDoubleStackSlot;
147 }
148
149 intptr_t GetStackIndex() const {
150 DCHECK(IsStackSlot() || IsDoubleStackSlot());
151 // Decode stack index manually to preserve sign.
152 return GetPayload() - kStackIndexBias;
153 }
154
155 intptr_t GetHighStackIndex(uintptr_t word_size) const {
156 DCHECK(IsDoubleStackSlot());
157 // Decode stack index manually to preserve sign.
158 return GetPayload() - kStackIndexBias + word_size;
159 }
160
161 static Location QuickParameter(uint32_t parameter_index) {
162 return Location(kQuickParameter, parameter_index);
163 }
164
165 uint32_t GetQuickParameterIndex() const {
166 DCHECK(IsQuickParameter());
167 return GetPayload();
168 }
169
170 bool IsQuickParameter() const {
171 return GetKind() == kQuickParameter;
172 }
173
174 arm::ArmManagedRegister AsArm() const;
175 x86::X86ManagedRegister AsX86() const;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100176 x86_64::X86_64ManagedRegister AsX86_64() const;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100177
178 Kind GetKind() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100179 return IsConstant() ? kConstant : KindField::Decode(value_);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100180 }
181
182 bool Equals(Location other) const {
183 return value_ == other.value_;
184 }
185
186 const char* DebugString() const {
187 switch (GetKind()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100188 case kInvalid: return "I";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100189 case kRegister: return "R";
190 case kStackSlot: return "S";
191 case kDoubleStackSlot: return "DS";
192 case kQuickParameter: return "Q";
193 case kUnallocated: return "U";
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100194 case kConstant: return "C";
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100195 }
196 return "?";
197 }
198
199 // Unallocated locations.
200 enum Policy {
201 kAny,
202 kRequiresRegister,
203 kSameAsFirstInput,
204 };
205
206 bool IsUnallocated() const {
207 return GetKind() == kUnallocated;
208 }
209
210 static Location UnallocatedLocation(Policy policy) {
211 return Location(kUnallocated, PolicyField::Encode(policy));
212 }
213
214 // Any free register is suitable to replace this unallocated location.
215 static Location Any() {
216 return UnallocatedLocation(kAny);
217 }
218
219 static Location RequiresRegister() {
220 return UnallocatedLocation(kRequiresRegister);
221 }
222
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100223 static Location RegisterOrConstant(HInstruction* instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100224 static Location ByteRegisterOrConstant(ManagedRegister reg, HInstruction* instruction);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100225
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100226 // The location of the first input to the instruction will be
227 // used to replace this unallocated location.
228 static Location SameAsFirstInput() {
229 return UnallocatedLocation(kSameAsFirstInput);
230 }
231
232 Policy GetPolicy() const {
233 DCHECK(IsUnallocated());
234 return PolicyField::Decode(GetPayload());
235 }
236
237 uword GetEncoding() const {
238 return GetPayload();
239 }
240
241 private:
242 // Number of bits required to encode Kind value.
243 static constexpr uint32_t kBitsForKind = 4;
244 static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100245 static constexpr uword kLocationTagMask = 0x3;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100246
247 explicit Location(uword value) : value_(value) {}
248
249 Location(Kind kind, uword payload)
250 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
251
252 uword GetPayload() const {
253 return PayloadField::Decode(value_);
254 }
255
256 typedef BitField<Kind, 0, kBitsForKind> KindField;
257 typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
258
259 // Layout for kUnallocated locations payload.
260 typedef BitField<Policy, 0, 3> PolicyField;
261
262 // Layout for stack slots.
263 static const intptr_t kStackIndexBias =
264 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
265
266 // Location either contains kind and payload fields or a tagged handle for
267 // a constant locations. Values of enumeration Kind are selected in such a
268 // way that none of them can be interpreted as a kConstant tag.
269 uword value_;
270};
271
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100272class RegisterSet : public ValueObject {
273 public:
274 RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
275
276 void Add(Location loc) {
277 // TODO: floating point registers.
278 core_registers_ |= (1 << loc.reg().RegId());
279 }
280
281 bool ContainsCoreRegister(uint32_t id) {
282 return Contains(core_registers_, id);
283 }
284
285 bool ContainsFloatingPointRegister(uint32_t id) {
286 return Contains(floating_point_registers_, id);
287 }
288
289 static bool Contains(uint32_t register_set, uint32_t reg) {
290 return (register_set & (1 << reg)) != 0;
291 }
292
293 private:
294 uint32_t core_registers_;
295 uint32_t floating_point_registers_;
296
297 DISALLOW_COPY_AND_ASSIGN(RegisterSet);
298};
299
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100300/**
301 * The code generator computes LocationSummary for each instruction so that
302 * the instruction itself knows what code to generate: where to find the inputs
303 * and where to place the result.
304 *
305 * The intent is to have the code for generating the instruction independent of
306 * register allocation. A register allocator just has to provide a LocationSummary.
307 */
308class LocationSummary : public ArenaObject {
309 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100310 enum CallKind {
311 kNoCall,
312 kCallOnSlowPath,
313 kCall
314 };
315
Roland Levillain5799fc02014-09-25 12:15:20 +0100316 LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100317
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100318 void SetInAt(uint32_t at, Location location, bool dies_at_entry = false) {
319 dies_at_entry_.Put(at, dies_at_entry);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100320 inputs_.Put(at, location);
321 }
322
323 Location InAt(uint32_t at) const {
324 return inputs_.Get(at);
325 }
326
327 size_t GetInputCount() const {
328 return inputs_.Size();
329 }
330
331 void SetOut(Location location) {
332 output_ = Location(location);
333 }
334
335 void AddTemp(Location location) {
336 temps_.Add(location);
337 }
338
339 Location GetTemp(uint32_t at) const {
340 return temps_.Get(at);
341 }
342
343 void SetTempAt(uint32_t at, Location location) {
344 temps_.Put(at, location);
345 }
346
347 size_t GetTempCount() const {
348 return temps_.Size();
349 }
350
Nicolas Geoffray39468442014-09-02 15:17:15 +0100351 void SetEnvironmentAt(uint32_t at, Location location) {
352 environment_.Put(at, location);
353 }
354
355 Location GetEnvironmentAt(uint32_t at) const {
356 return environment_.Get(at);
357 }
358
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100359 Location Out() const { return output_; }
360
Nicolas Geoffray39468442014-09-02 15:17:15 +0100361 bool CanCall() const { return call_kind_ != kNoCall; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100362 bool WillCall() const { return call_kind_ == kCall; }
363 bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100364 bool NeedsSafepoint() const { return CanCall(); }
365
366 void SetStackBit(uint32_t index) {
367 stack_mask_->SetBit(index);
368 }
369
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100370 void ClearStackBit(uint32_t index) {
371 stack_mask_->ClearBit(index);
372 }
373
Nicolas Geoffray39468442014-09-02 15:17:15 +0100374 void SetRegisterBit(uint32_t reg_id) {
375 register_mask_ |= (1 << reg_id);
376 }
377
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100378 bool RegisterContainsObject(uint32_t reg_id) {
379 return RegisterSet::Contains(register_mask_, reg_id);
380 }
381
382 void AddLiveRegister(Location location) {
383 live_registers_.Add(location);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100384 }
385
386 BitVector* GetStackMask() const {
387 return stack_mask_;
388 }
389
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100390 RegisterSet* GetLiveRegisters() {
391 return &live_registers_;
392 }
393
Nicolas Geoffray76905622014-09-25 14:39:26 +0100394 bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const {
395 if (is_environment) return true;
396 Location location = Out();
Nicolas Geoffray76905622014-09-25 14:39:26 +0100397 if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) {
398 return false;
399 }
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100400 if (dies_at_entry_.Get(input)) {
401 return false;
402 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100403 return true;
404 }
405
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100406 private:
407 GrowableArray<Location> inputs_;
408 GrowableArray<Location> temps_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100409 GrowableArray<Location> environment_;
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100410 GrowableArray<bool> dies_at_entry_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100411 Location output_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100412 const CallKind call_kind_;
413
414 // Mask of objects that live in the stack.
415 BitVector* stack_mask_;
416
417 // Mask of objects that live in register.
418 uint32_t register_mask_;
419
420 // Registers that are in use at this position.
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100421 RegisterSet live_registers_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100422
423 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
424};
425
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100426std::ostream& operator<<(std::ostream& os, const Location& location);
427
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100428} // namespace art
429
430#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_