locations.h revision 9cf35523764d829ae0470dae2d5dd99be469c841
1/*
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"
21#include "utils/allocation.h"
22#include "utils/growable_array.h"
23#include "utils/managed_register.h"
24
25namespace art {
26
27class HInstruction;
28
29/**
30 * A Location is an abstraction over the potential location
31 * of an instruction. It could be in register or stack.
32 */
33class Location : public ValueObject {
34 public:
35  enum Kind {
36    kInvalid = 0,
37    kStackSlot = 1,  // Word size slot.
38    kDoubleStackSlot = 2,  // 64bit stack slot.
39    kRegister = 3,
40    // On 32bits architectures, quick can pass a long where the
41    // low bits are in the last parameter register, and the high
42    // bits are in a stack slot. The kQuickParameter kind is for
43    // handling this special case.
44    kQuickParameter = 4,
45
46    // Unallocated location represents a location that is not fixed and can be
47    // allocated by a register allocator.  Each unallocated location has
48    // a policy that specifies what kind of location is suitable. Payload
49    // contains register allocation policy.
50    kUnallocated = 5,
51  };
52
53  Location() : value_(kInvalid) {
54    DCHECK(!IsValid());
55  }
56
57  Location(const Location& other) : ValueObject(), value_(other.value_) {}
58
59  Location& operator=(const Location& other) {
60    value_ = other.value_;
61    return *this;
62  }
63
64  bool IsValid() const {
65    return value_ != kInvalid;
66  }
67
68  bool IsInvalid() const {
69    return !IsValid();
70  }
71
72  bool IsConstant() const {
73    // TODO: support constants.
74    return false;
75  }
76
77  // Empty location. Used if there the location should be ignored.
78  static Location NoLocation() {
79    return Location();
80  }
81
82  // Register locations.
83  static Location RegisterLocation(ManagedRegister reg) {
84    return Location(kRegister, reg.RegId());
85  }
86
87  bool IsRegister() const {
88    return GetKind() == kRegister;
89  }
90
91  ManagedRegister reg() const {
92    DCHECK(IsRegister());
93    return static_cast<ManagedRegister>(GetPayload());
94  }
95
96  static uword EncodeStackIndex(intptr_t stack_index) {
97    DCHECK(-kStackIndexBias <= stack_index);
98    DCHECK(stack_index < kStackIndexBias);
99    return static_cast<uword>(kStackIndexBias + stack_index);
100  }
101
102  static Location StackSlot(intptr_t stack_index) {
103    uword payload = EncodeStackIndex(stack_index);
104    Location loc(kStackSlot, payload);
105    // Ensure that sign is preserved.
106    DCHECK_EQ(loc.GetStackIndex(), stack_index);
107    return loc;
108  }
109
110  bool IsStackSlot() const {
111    return GetKind() == kStackSlot;
112  }
113
114  static Location DoubleStackSlot(intptr_t stack_index) {
115    uword payload = EncodeStackIndex(stack_index);
116    Location loc(kDoubleStackSlot, payload);
117    // Ensure that sign is preserved.
118    DCHECK_EQ(loc.GetStackIndex(), stack_index);
119    return loc;
120  }
121
122  bool IsDoubleStackSlot() const {
123    return GetKind() == kDoubleStackSlot;
124  }
125
126  intptr_t GetStackIndex() const {
127    DCHECK(IsStackSlot() || IsDoubleStackSlot());
128    // Decode stack index manually to preserve sign.
129    return GetPayload() - kStackIndexBias;
130  }
131
132  intptr_t GetHighStackIndex(uintptr_t word_size) const {
133    DCHECK(IsDoubleStackSlot());
134    // Decode stack index manually to preserve sign.
135    return GetPayload() - kStackIndexBias + word_size;
136  }
137
138  static Location QuickParameter(uint32_t parameter_index) {
139    return Location(kQuickParameter, parameter_index);
140  }
141
142  uint32_t GetQuickParameterIndex() const {
143    DCHECK(IsQuickParameter());
144    return GetPayload();
145  }
146
147  bool IsQuickParameter() const {
148    return GetKind() == kQuickParameter;
149  }
150
151  arm::ArmManagedRegister AsArm() const;
152  x86::X86ManagedRegister AsX86() const;
153  x86_64::X86_64ManagedRegister AsX86_64() const;
154
155  Kind GetKind() const {
156    return KindField::Decode(value_);
157  }
158
159  bool Equals(Location other) const {
160    return value_ == other.value_;
161  }
162
163  const char* DebugString() const {
164    switch (GetKind()) {
165      case kInvalid: return "?";
166      case kRegister: return "R";
167      case kStackSlot: return "S";
168      case kDoubleStackSlot: return "DS";
169      case kQuickParameter: return "Q";
170      case kUnallocated: return "U";
171    }
172    return "?";
173  }
174
175  // Unallocated locations.
176  enum Policy {
177    kAny,
178    kRequiresRegister,
179    kSameAsFirstInput,
180  };
181
182  bool IsUnallocated() const {
183    return GetKind() == kUnallocated;
184  }
185
186  static Location UnallocatedLocation(Policy policy) {
187    return Location(kUnallocated, PolicyField::Encode(policy));
188  }
189
190  // Any free register is suitable to replace this unallocated location.
191  static Location Any() {
192    return UnallocatedLocation(kAny);
193  }
194
195  static Location RequiresRegister() {
196    return UnallocatedLocation(kRequiresRegister);
197  }
198
199  // The location of the first input to the instruction will be
200  // used to replace this unallocated location.
201  static Location SameAsFirstInput() {
202    return UnallocatedLocation(kSameAsFirstInput);
203  }
204
205  Policy GetPolicy() const {
206    DCHECK(IsUnallocated());
207    return PolicyField::Decode(GetPayload());
208  }
209
210  uword GetEncoding() const {
211    return GetPayload();
212  }
213
214 private:
215  // Number of bits required to encode Kind value.
216  static constexpr uint32_t kBitsForKind = 4;
217  static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
218
219  explicit Location(uword value) : value_(value) {}
220
221  Location(Kind kind, uword payload)
222      : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
223
224  uword GetPayload() const {
225    return PayloadField::Decode(value_);
226  }
227
228  typedef BitField<Kind, 0, kBitsForKind> KindField;
229  typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
230
231  // Layout for kUnallocated locations payload.
232  typedef BitField<Policy, 0, 3> PolicyField;
233
234  // Layout for stack slots.
235  static const intptr_t kStackIndexBias =
236      static_cast<intptr_t>(1) << (kBitsForPayload - 1);
237
238  // Location either contains kind and payload fields or a tagged handle for
239  // a constant locations. Values of enumeration Kind are selected in such a
240  // way that none of them can be interpreted as a kConstant tag.
241  uword value_;
242};
243
244/**
245 * The code generator computes LocationSummary for each instruction so that
246 * the instruction itself knows what code to generate: where to find the inputs
247 * and where to place the result.
248 *
249 * The intent is to have the code for generating the instruction independent of
250 * register allocation. A register allocator just has to provide a LocationSummary.
251 */
252class LocationSummary : public ArenaObject {
253 public:
254  explicit LocationSummary(HInstruction* instruction);
255
256  void SetInAt(uint32_t at, Location location) {
257    inputs_.Put(at, location);
258  }
259
260  Location InAt(uint32_t at) const {
261    return inputs_.Get(at);
262  }
263
264  size_t GetInputCount() const {
265    return inputs_.Size();
266  }
267
268  void SetOut(Location location) {
269    output_ = Location(location);
270  }
271
272  void AddTemp(Location location) {
273    temps_.Add(location);
274  }
275
276  Location GetTemp(uint32_t at) const {
277    return temps_.Get(at);
278  }
279
280  void SetTempAt(uint32_t at, Location location) {
281    temps_.Put(at, location);
282  }
283
284  size_t GetTempCount() const {
285    return temps_.Size();
286  }
287
288  Location Out() const { return output_; }
289
290 private:
291  GrowableArray<Location> inputs_;
292  GrowableArray<Location> temps_;
293  Location output_;
294
295  DISALLOW_COPY_AND_ASSIGN(LocationSummary);
296};
297
298}  // namespace art
299
300#endif  // ART_COMPILER_OPTIMIZING_LOCATIONS_H_
301