blob: 8d0715a45a881505adf86e929f3b51780c1ed98e [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);
224
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100225 // The location of the first input to the instruction will be
226 // used to replace this unallocated location.
227 static Location SameAsFirstInput() {
228 return UnallocatedLocation(kSameAsFirstInput);
229 }
230
231 Policy GetPolicy() const {
232 DCHECK(IsUnallocated());
233 return PolicyField::Decode(GetPayload());
234 }
235
236 uword GetEncoding() const {
237 return GetPayload();
238 }
239
240 private:
241 // Number of bits required to encode Kind value.
242 static constexpr uint32_t kBitsForKind = 4;
243 static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100244 static constexpr uword kLocationTagMask = 0x3;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100245
246 explicit Location(uword value) : value_(value) {}
247
248 Location(Kind kind, uword payload)
249 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
250
251 uword GetPayload() const {
252 return PayloadField::Decode(value_);
253 }
254
255 typedef BitField<Kind, 0, kBitsForKind> KindField;
256 typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
257
258 // Layout for kUnallocated locations payload.
259 typedef BitField<Policy, 0, 3> PolicyField;
260
261 // Layout for stack slots.
262 static const intptr_t kStackIndexBias =
263 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
264
265 // Location either contains kind and payload fields or a tagged handle for
266 // a constant locations. Values of enumeration Kind are selected in such a
267 // way that none of them can be interpreted as a kConstant tag.
268 uword value_;
269};
270
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100271class RegisterSet : public ValueObject {
272 public:
273 RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
274
275 void Add(Location loc) {
276 // TODO: floating point registers.
277 core_registers_ |= (1 << loc.reg().RegId());
278 }
279
280 bool ContainsCoreRegister(uint32_t id) {
281 return Contains(core_registers_, id);
282 }
283
284 bool ContainsFloatingPointRegister(uint32_t id) {
285 return Contains(floating_point_registers_, id);
286 }
287
288 static bool Contains(uint32_t register_set, uint32_t reg) {
289 return (register_set & (1 << reg)) != 0;
290 }
291
292 private:
293 uint32_t core_registers_;
294 uint32_t floating_point_registers_;
295
296 DISALLOW_COPY_AND_ASSIGN(RegisterSet);
297};
298
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100299/**
300 * The code generator computes LocationSummary for each instruction so that
301 * the instruction itself knows what code to generate: where to find the inputs
302 * and where to place the result.
303 *
304 * The intent is to have the code for generating the instruction independent of
305 * register allocation. A register allocator just has to provide a LocationSummary.
306 */
307class LocationSummary : public ArenaObject {
308 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100309 enum CallKind {
310 kNoCall,
311 kCallOnSlowPath,
312 kCall
313 };
314
Roland Levillain5799fc02014-09-25 12:15:20 +0100315 LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100316
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100317 void SetInAt(uint32_t at, Location location, bool dies_at_entry = false) {
318 dies_at_entry_.Put(at, dies_at_entry);
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100319 inputs_.Put(at, location);
320 }
321
322 Location InAt(uint32_t at) const {
323 return inputs_.Get(at);
324 }
325
326 size_t GetInputCount() const {
327 return inputs_.Size();
328 }
329
330 void SetOut(Location location) {
331 output_ = Location(location);
332 }
333
334 void AddTemp(Location location) {
335 temps_.Add(location);
336 }
337
338 Location GetTemp(uint32_t at) const {
339 return temps_.Get(at);
340 }
341
342 void SetTempAt(uint32_t at, Location location) {
343 temps_.Put(at, location);
344 }
345
346 size_t GetTempCount() const {
347 return temps_.Size();
348 }
349
Nicolas Geoffray39468442014-09-02 15:17:15 +0100350 void SetEnvironmentAt(uint32_t at, Location location) {
351 environment_.Put(at, location);
352 }
353
354 Location GetEnvironmentAt(uint32_t at) const {
355 return environment_.Get(at);
356 }
357
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100358 Location Out() const { return output_; }
359
Nicolas Geoffray39468442014-09-02 15:17:15 +0100360 bool CanCall() const { return call_kind_ != kNoCall; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100361 bool WillCall() const { return call_kind_ == kCall; }
362 bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100363 bool NeedsSafepoint() const { return CanCall(); }
364
365 void SetStackBit(uint32_t index) {
366 stack_mask_->SetBit(index);
367 }
368
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100369 void ClearStackBit(uint32_t index) {
370 stack_mask_->ClearBit(index);
371 }
372
Nicolas Geoffray39468442014-09-02 15:17:15 +0100373 void SetRegisterBit(uint32_t reg_id) {
374 register_mask_ |= (1 << reg_id);
375 }
376
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100377 bool RegisterContainsObject(uint32_t reg_id) {
378 return RegisterSet::Contains(register_mask_, reg_id);
379 }
380
381 void AddLiveRegister(Location location) {
382 live_registers_.Add(location);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100383 }
384
385 BitVector* GetStackMask() const {
386 return stack_mask_;
387 }
388
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100389 RegisterSet* GetLiveRegisters() {
390 return &live_registers_;
391 }
392
Nicolas Geoffray76905622014-09-25 14:39:26 +0100393 bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const {
394 if (is_environment) return true;
395 Location location = Out();
Nicolas Geoffray76905622014-09-25 14:39:26 +0100396 if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) {
397 return false;
398 }
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100399 if (dies_at_entry_.Get(input)) {
400 return false;
401 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100402 return true;
403 }
404
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100405 private:
406 GrowableArray<Location> inputs_;
407 GrowableArray<Location> temps_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100408 GrowableArray<Location> environment_;
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100409 GrowableArray<bool> dies_at_entry_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100410 Location output_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100411 const CallKind call_kind_;
412
413 // Mask of objects that live in the stack.
414 BitVector* stack_mask_;
415
416 // Mask of objects that live in register.
417 uint32_t register_mask_;
418
419 // Registers that are in use at this position.
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100420 RegisterSet live_registers_;
Nicolas Geoffray76716a62014-05-23 10:14:19 +0100421
422 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
423};
424
425} // namespace art
426
427#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_