| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 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" | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 21 | #include "base/bit_vector.h" | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 22 | #include "utils/allocation.h" | 
 | 23 | #include "utils/growable_array.h" | 
 | 24 | #include "utils/managed_register.h" | 
 | 25 |  | 
 | 26 | namespace art { | 
 | 27 |  | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 28 | class HConstant; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 29 | class 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 |  */ | 
 | 35 | class Location : public ValueObject { | 
 | 36 |  public: | 
 | 37 |   enum Kind { | 
 | 38 |     kInvalid = 0, | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 39 |     kConstant = 1, | 
 | 40 |     kStackSlot = 2,  // Word size slot. | 
 | 41 |     kDoubleStackSlot = 3,  // 64bit stack slot. | 
 | 42 |     kRegister = 4, | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 43 |     // On 32bits architectures, quick can pass a long where the | 
 | 44 |     // low bits are in the last parameter register, and the high | 
 | 45 |     // bits are in a stack slot. The kQuickParameter kind is for | 
 | 46 |     // handling this special case. | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 47 |     kQuickParameter = 6, | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 48 |  | 
 | 49 |     // Unallocated location represents a location that is not fixed and can be | 
 | 50 |     // allocated by a register allocator.  Each unallocated location has | 
 | 51 |     // a policy that specifies what kind of location is suitable. Payload | 
 | 52 |     // contains register allocation policy. | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 53 |     kUnallocated = 7, | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 54 |   }; | 
 | 55 |  | 
 | 56 |   Location() : value_(kInvalid) { | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 57 |     // Verify that non-tagged location kinds do not interfere with kConstantTag. | 
 | 58 |     COMPILE_ASSERT((kInvalid & kLocationTagMask) != kConstant, TagError); | 
 | 59 |     COMPILE_ASSERT((kUnallocated & kLocationTagMask) != kConstant, TagError); | 
 | 60 |     COMPILE_ASSERT((kStackSlot & kLocationTagMask) != kConstant, TagError); | 
 | 61 |     COMPILE_ASSERT((kDoubleStackSlot & kLocationTagMask) != kConstant, TagError); | 
 | 62 |     COMPILE_ASSERT((kRegister & kLocationTagMask) != kConstant, TagError); | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 63 |     COMPILE_ASSERT((kQuickParameter & kLocationTagMask) != kConstant, TagError); | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 64 |     COMPILE_ASSERT((kConstant & kLocationTagMask) == kConstant, TagError); | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 65 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 66 |     DCHECK(!IsValid()); | 
 | 67 |   } | 
 | 68 |  | 
 | 69 |   Location(const Location& other) : ValueObject(), value_(other.value_) {} | 
 | 70 |  | 
 | 71 |   Location& operator=(const Location& other) { | 
 | 72 |     value_ = other.value_; | 
 | 73 |     return *this; | 
 | 74 |   } | 
 | 75 |  | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 76 |   bool IsConstant() const { | 
 | 77 |     return (value_ & kLocationTagMask) == kConstant; | 
 | 78 |   } | 
 | 79 |  | 
 | 80 |   static Location ConstantLocation(HConstant* constant) { | 
 | 81 |     DCHECK(constant != nullptr); | 
 | 82 |     return Location(kConstant | reinterpret_cast<uword>(constant)); | 
 | 83 |   } | 
 | 84 |  | 
 | 85 |   HConstant* GetConstant() const { | 
 | 86 |     DCHECK(IsConstant()); | 
 | 87 |     return reinterpret_cast<HConstant*>(value_ & ~kLocationTagMask); | 
 | 88 |   } | 
 | 89 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 90 |   bool IsValid() const { | 
 | 91 |     return value_ != kInvalid; | 
 | 92 |   } | 
 | 93 |  | 
 | 94 |   bool IsInvalid() const { | 
 | 95 |     return !IsValid(); | 
 | 96 |   } | 
 | 97 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 98 |   // Empty location. Used if there the location should be ignored. | 
 | 99 |   static Location NoLocation() { | 
 | 100 |     return Location(); | 
 | 101 |   } | 
 | 102 |  | 
 | 103 |   // Register locations. | 
 | 104 |   static Location RegisterLocation(ManagedRegister reg) { | 
 | 105 |     return Location(kRegister, reg.RegId()); | 
 | 106 |   } | 
 | 107 |  | 
 | 108 |   bool IsRegister() const { | 
 | 109 |     return GetKind() == kRegister; | 
 | 110 |   } | 
 | 111 |  | 
 | 112 |   ManagedRegister reg() const { | 
 | 113 |     DCHECK(IsRegister()); | 
 | 114 |     return static_cast<ManagedRegister>(GetPayload()); | 
 | 115 |   } | 
 | 116 |  | 
 | 117 |   static uword EncodeStackIndex(intptr_t stack_index) { | 
 | 118 |     DCHECK(-kStackIndexBias <= stack_index); | 
 | 119 |     DCHECK(stack_index < kStackIndexBias); | 
 | 120 |     return static_cast<uword>(kStackIndexBias + stack_index); | 
 | 121 |   } | 
 | 122 |  | 
 | 123 |   static Location StackSlot(intptr_t stack_index) { | 
 | 124 |     uword payload = EncodeStackIndex(stack_index); | 
 | 125 |     Location loc(kStackSlot, payload); | 
 | 126 |     // Ensure that sign is preserved. | 
 | 127 |     DCHECK_EQ(loc.GetStackIndex(), stack_index); | 
 | 128 |     return loc; | 
 | 129 |   } | 
 | 130 |  | 
 | 131 |   bool IsStackSlot() const { | 
 | 132 |     return GetKind() == kStackSlot; | 
 | 133 |   } | 
 | 134 |  | 
 | 135 |   static Location DoubleStackSlot(intptr_t stack_index) { | 
 | 136 |     uword payload = EncodeStackIndex(stack_index); | 
 | 137 |     Location loc(kDoubleStackSlot, payload); | 
 | 138 |     // Ensure that sign is preserved. | 
 | 139 |     DCHECK_EQ(loc.GetStackIndex(), stack_index); | 
 | 140 |     return loc; | 
 | 141 |   } | 
 | 142 |  | 
 | 143 |   bool IsDoubleStackSlot() const { | 
 | 144 |     return GetKind() == kDoubleStackSlot; | 
 | 145 |   } | 
 | 146 |  | 
 | 147 |   intptr_t GetStackIndex() const { | 
 | 148 |     DCHECK(IsStackSlot() || IsDoubleStackSlot()); | 
 | 149 |     // Decode stack index manually to preserve sign. | 
 | 150 |     return GetPayload() - kStackIndexBias; | 
 | 151 |   } | 
 | 152 |  | 
 | 153 |   intptr_t GetHighStackIndex(uintptr_t word_size) const { | 
 | 154 |     DCHECK(IsDoubleStackSlot()); | 
 | 155 |     // Decode stack index manually to preserve sign. | 
 | 156 |     return GetPayload() - kStackIndexBias + word_size; | 
 | 157 |   } | 
 | 158 |  | 
 | 159 |   static Location QuickParameter(uint32_t parameter_index) { | 
 | 160 |     return Location(kQuickParameter, parameter_index); | 
 | 161 |   } | 
 | 162 |  | 
 | 163 |   uint32_t GetQuickParameterIndex() const { | 
 | 164 |     DCHECK(IsQuickParameter()); | 
 | 165 |     return GetPayload(); | 
 | 166 |   } | 
 | 167 |  | 
 | 168 |   bool IsQuickParameter() const { | 
 | 169 |     return GetKind() == kQuickParameter; | 
 | 170 |   } | 
 | 171 |  | 
 | 172 |   arm::ArmManagedRegister AsArm() const; | 
 | 173 |   x86::X86ManagedRegister AsX86() const; | 
| Nicolas Geoffray | 9cf3552 | 2014-06-09 18:40:10 +0100 | [diff] [blame] | 174 |   x86_64::X86_64ManagedRegister AsX86_64() const; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 175 |  | 
 | 176 |   Kind GetKind() const { | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 177 |     return IsConstant() ? kConstant : KindField::Decode(value_); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 178 |   } | 
 | 179 |  | 
 | 180 |   bool Equals(Location other) const { | 
 | 181 |     return value_ == other.value_; | 
 | 182 |   } | 
 | 183 |  | 
 | 184 |   const char* DebugString() const { | 
 | 185 |     switch (GetKind()) { | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 186 |       case kInvalid: return "I"; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 187 |       case kRegister: return "R"; | 
 | 188 |       case kStackSlot: return "S"; | 
 | 189 |       case kDoubleStackSlot: return "DS"; | 
 | 190 |       case kQuickParameter: return "Q"; | 
 | 191 |       case kUnallocated: return "U"; | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 192 |       case kConstant: return "C"; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 193 |     } | 
 | 194 |     return "?"; | 
 | 195 |   } | 
 | 196 |  | 
 | 197 |   // Unallocated locations. | 
 | 198 |   enum Policy { | 
 | 199 |     kAny, | 
 | 200 |     kRequiresRegister, | 
 | 201 |     kSameAsFirstInput, | 
 | 202 |   }; | 
 | 203 |  | 
 | 204 |   bool IsUnallocated() const { | 
 | 205 |     return GetKind() == kUnallocated; | 
 | 206 |   } | 
 | 207 |  | 
 | 208 |   static Location UnallocatedLocation(Policy policy) { | 
 | 209 |     return Location(kUnallocated, PolicyField::Encode(policy)); | 
 | 210 |   } | 
 | 211 |  | 
 | 212 |   // Any free register is suitable to replace this unallocated location. | 
 | 213 |   static Location Any() { | 
 | 214 |     return UnallocatedLocation(kAny); | 
 | 215 |   } | 
 | 216 |  | 
 | 217 |   static Location RequiresRegister() { | 
 | 218 |     return UnallocatedLocation(kRequiresRegister); | 
 | 219 |   } | 
 | 220 |  | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 221 |   static Location RegisterOrConstant(HInstruction* instruction); | 
 | 222 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 223 |   // The location of the first input to the instruction will be | 
 | 224 |   // used to replace this unallocated location. | 
 | 225 |   static Location SameAsFirstInput() { | 
 | 226 |     return UnallocatedLocation(kSameAsFirstInput); | 
 | 227 |   } | 
 | 228 |  | 
 | 229 |   Policy GetPolicy() const { | 
 | 230 |     DCHECK(IsUnallocated()); | 
 | 231 |     return PolicyField::Decode(GetPayload()); | 
 | 232 |   } | 
 | 233 |  | 
 | 234 |   uword GetEncoding() const { | 
 | 235 |     return GetPayload(); | 
 | 236 |   } | 
 | 237 |  | 
 | 238 |  private: | 
 | 239 |   // Number of bits required to encode Kind value. | 
 | 240 |   static constexpr uint32_t kBitsForKind = 4; | 
 | 241 |   static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind; | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 242 |   static constexpr uword kLocationTagMask = 0x3; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 243 |  | 
 | 244 |   explicit Location(uword value) : value_(value) {} | 
 | 245 |  | 
 | 246 |   Location(Kind kind, uword payload) | 
 | 247 |       : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {} | 
 | 248 |  | 
 | 249 |   uword GetPayload() const { | 
 | 250 |     return PayloadField::Decode(value_); | 
 | 251 |   } | 
 | 252 |  | 
 | 253 |   typedef BitField<Kind, 0, kBitsForKind> KindField; | 
 | 254 |   typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField; | 
 | 255 |  | 
 | 256 |   // Layout for kUnallocated locations payload. | 
 | 257 |   typedef BitField<Policy, 0, 3> PolicyField; | 
 | 258 |  | 
 | 259 |   // Layout for stack slots. | 
 | 260 |   static const intptr_t kStackIndexBias = | 
 | 261 |       static_cast<intptr_t>(1) << (kBitsForPayload - 1); | 
 | 262 |  | 
 | 263 |   // Location either contains kind and payload fields or a tagged handle for | 
 | 264 |   // a constant locations. Values of enumeration Kind are selected in such a | 
 | 265 |   // way that none of them can be interpreted as a kConstant tag. | 
 | 266 |   uword value_; | 
 | 267 | }; | 
 | 268 |  | 
 | 269 | /** | 
 | 270 |  * The code generator computes LocationSummary for each instruction so that | 
 | 271 |  * the instruction itself knows what code to generate: where to find the inputs | 
 | 272 |  * and where to place the result. | 
 | 273 |  * | 
 | 274 |  * The intent is to have the code for generating the instruction independent of | 
 | 275 |  * register allocation. A register allocator just has to provide a LocationSummary. | 
 | 276 |  */ | 
 | 277 | class LocationSummary : public ArenaObject { | 
 | 278 |  public: | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 279 |   enum CallKind { | 
 | 280 |     kNoCall, | 
 | 281 |     kCallOnSlowPath, | 
 | 282 |     kCall | 
 | 283 |   }; | 
 | 284 |  | 
 | 285 |   explicit LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 286 |  | 
 | 287 |   void SetInAt(uint32_t at, Location location) { | 
 | 288 |     inputs_.Put(at, location); | 
 | 289 |   } | 
 | 290 |  | 
 | 291 |   Location InAt(uint32_t at) const { | 
 | 292 |     return inputs_.Get(at); | 
 | 293 |   } | 
 | 294 |  | 
 | 295 |   size_t GetInputCount() const { | 
 | 296 |     return inputs_.Size(); | 
 | 297 |   } | 
 | 298 |  | 
 | 299 |   void SetOut(Location location) { | 
 | 300 |     output_ = Location(location); | 
 | 301 |   } | 
 | 302 |  | 
 | 303 |   void AddTemp(Location location) { | 
 | 304 |     temps_.Add(location); | 
 | 305 |   } | 
 | 306 |  | 
 | 307 |   Location GetTemp(uint32_t at) const { | 
 | 308 |     return temps_.Get(at); | 
 | 309 |   } | 
 | 310 |  | 
 | 311 |   void SetTempAt(uint32_t at, Location location) { | 
 | 312 |     temps_.Put(at, location); | 
 | 313 |   } | 
 | 314 |  | 
 | 315 |   size_t GetTempCount() const { | 
 | 316 |     return temps_.Size(); | 
 | 317 |   } | 
 | 318 |  | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 319 |   void SetEnvironmentAt(uint32_t at, Location location) { | 
 | 320 |     environment_.Put(at, location); | 
 | 321 |   } | 
 | 322 |  | 
 | 323 |   Location GetEnvironmentAt(uint32_t at) const { | 
 | 324 |     return environment_.Get(at); | 
 | 325 |   } | 
 | 326 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 327 |   Location Out() const { return output_; } | 
 | 328 |  | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 329 |   bool CanCall() const { return call_kind_ != kNoCall; } | 
 | 330 |   bool NeedsSafepoint() const { return CanCall(); } | 
 | 331 |  | 
 | 332 |   void SetStackBit(uint32_t index) { | 
 | 333 |     stack_mask_->SetBit(index); | 
 | 334 |   } | 
 | 335 |  | 
 | 336 |   void SetRegisterBit(uint32_t reg_id) { | 
 | 337 |     register_mask_ |= (1 << reg_id); | 
 | 338 |   } | 
 | 339 |  | 
 | 340 |   void SetLiveRegister(uint32_t reg_id) { | 
 | 341 |     live_registers_ |= (1 << reg_id); | 
 | 342 |   } | 
 | 343 |  | 
 | 344 |   BitVector* GetStackMask() const { | 
 | 345 |     return stack_mask_; | 
 | 346 |   } | 
 | 347 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 348 |  private: | 
 | 349 |   GrowableArray<Location> inputs_; | 
 | 350 |   GrowableArray<Location> temps_; | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 351 |   GrowableArray<Location> environment_; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 352 |   Location output_; | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame^] | 353 |   const CallKind call_kind_; | 
 | 354 |  | 
 | 355 |   // Mask of objects that live in the stack. | 
 | 356 |   BitVector* stack_mask_; | 
 | 357 |  | 
 | 358 |   // Mask of objects that live in register. | 
 | 359 |   uint32_t register_mask_; | 
 | 360 |  | 
 | 361 |   // Registers that are in use at this position. | 
 | 362 |   uint32_t live_registers_; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 363 |  | 
 | 364 |   DISALLOW_COPY_AND_ASSIGN(LocationSummary); | 
 | 365 | }; | 
 | 366 |  | 
 | 367 | }  // namespace art | 
 | 368 |  | 
 | 369 | #endif  // ART_COMPILER_OPTIMIZING_LOCATIONS_H_ |