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