| 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 |  | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 20 | #include "base/arena_containers.h" | 
| Mathieu Chartier | b666f48 | 2015-02-18 14:33:14 -0800 | [diff] [blame] | 21 | #include "base/arena_object.h" | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 22 | #include "base/bit_field.h" | 
| Vladimir Marko | 70e9746 | 2016-08-09 11:04:26 +0100 | [diff] [blame] | 23 | #include "base/bit_utils.h" | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 24 | #include "base/bit_vector.h" | 
| Ian Rogers | 0279ebb | 2014-10-08 17:27:48 -0700 | [diff] [blame] | 25 | #include "base/value_object.h" | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 26 |  | 
 | 27 | namespace art { | 
 | 28 |  | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 29 | class HConstant; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 30 | class HInstruction; | 
| Nicolas Geoffray | 424f676 | 2014-11-03 14:51:25 +0000 | [diff] [blame] | 31 | class Location; | 
 | 32 |  | 
 | 33 | std::ostream& operator<<(std::ostream& os, const Location& location); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 34 |  | 
 | 35 | /** | 
 | 36 |  * A Location is an abstraction over the potential location | 
 | 37 |  * of an instruction. It could be in register or stack. | 
 | 38 |  */ | 
| Vladimir Marko | 76c92ac | 2015-09-17 15:39:16 +0100 | [diff] [blame] | 39 | class Location : public ValueObject { | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 40 |  public: | 
| Nicolas Geoffray | 6c2dff8 | 2015-01-21 14:56:54 +0000 | [diff] [blame] | 41 |   enum OutputOverlap { | 
| Roland Levillain | 3d31242 | 2016-06-23 13:53:42 +0100 | [diff] [blame] | 42 |     // The liveness of the output overlaps the liveness of one or | 
 | 43 |     // several input(s); the register allocator cannot reuse an | 
 | 44 |     // input's location for the output's location. | 
| Nicolas Geoffray | 6c2dff8 | 2015-01-21 14:56:54 +0000 | [diff] [blame] | 45 |     kOutputOverlap, | 
| Roland Levillain | 3d31242 | 2016-06-23 13:53:42 +0100 | [diff] [blame] | 46 |     // The liveness of the output does not overlap the liveness of any | 
 | 47 |     // input; the register allocator is allowed to reuse an input's | 
 | 48 |     // location for the output's location. | 
| Nicolas Geoffray | 6c2dff8 | 2015-01-21 14:56:54 +0000 | [diff] [blame] | 49 |     kNoOutputOverlap | 
 | 50 |   }; | 
| Nicolas Geoffray | 9ae0daa | 2014-09-30 22:40:23 +0100 | [diff] [blame] | 51 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 52 |   enum Kind { | 
 | 53 |     kInvalid = 0, | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 54 |     kConstant = 1, | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 55 |     kStackSlot = 2,  // 32bit stack slot. | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 56 |     kDoubleStackSlot = 3,  // 64bit stack slot. | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 57 |  | 
 | 58 |     kRegister = 4,  // Core register. | 
 | 59 |  | 
 | 60 |     // We do not use the value 5 because it conflicts with kLocationConstantMask. | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 61 |     kDoNotUse5 = 5, | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 62 |  | 
| Nicolas Geoffray | 1ba0f59 | 2014-10-27 15:14:55 +0000 | [diff] [blame] | 63 |     kFpuRegister = 6,  // Float register. | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 64 |  | 
| Nicolas Geoffray | 1ba0f59 | 2014-10-27 15:14:55 +0000 | [diff] [blame] | 65 |     kRegisterPair = 7,  // Long register. | 
 | 66 |  | 
 | 67 |     kFpuRegisterPair = 8,  // Double register. | 
 | 68 |  | 
 | 69 |     // We do not use the value 9 because it conflicts with kLocationConstantMask. | 
 | 70 |     kDoNotUse9 = 9, | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 71 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 72 |     // Unallocated location represents a location that is not fixed and can be | 
 | 73 |     // allocated by a register allocator.  Each unallocated location has | 
 | 74 |     // a policy that specifies what kind of location is suitable. Payload | 
 | 75 |     // contains register allocation policy. | 
| Mark Mendell | 3e6a3bf | 2015-01-19 14:09:22 -0500 | [diff] [blame] | 76 |     kUnallocated = 10, | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 77 |   }; | 
 | 78 |  | 
| Vladimir Marko | 76c92ac | 2015-09-17 15:39:16 +0100 | [diff] [blame] | 79 |   Location() : ValueObject(), value_(kInvalid) { | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 80 |     // Verify that non-constant location kinds do not interfere with kConstant. | 
| Andreas Gampe | 785d2f2 | 2014-11-03 22:57:30 -0800 | [diff] [blame] | 81 |     static_assert((kInvalid & kLocationConstantMask) != kConstant, "TagError"); | 
 | 82 |     static_assert((kUnallocated & kLocationConstantMask) != kConstant, "TagError"); | 
 | 83 |     static_assert((kStackSlot & kLocationConstantMask) != kConstant, "TagError"); | 
 | 84 |     static_assert((kDoubleStackSlot & kLocationConstantMask) != kConstant, "TagError"); | 
 | 85 |     static_assert((kRegister & kLocationConstantMask) != kConstant, "TagError"); | 
| Andreas Gampe | 785d2f2 | 2014-11-03 22:57:30 -0800 | [diff] [blame] | 86 |     static_assert((kFpuRegister & kLocationConstantMask) != kConstant, "TagError"); | 
 | 87 |     static_assert((kRegisterPair & kLocationConstantMask) != kConstant, "TagError"); | 
 | 88 |     static_assert((kFpuRegisterPair & kLocationConstantMask) != kConstant, "TagError"); | 
 | 89 |     static_assert((kConstant & kLocationConstantMask) == kConstant, "TagError"); | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 90 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 91 |     DCHECK(!IsValid()); | 
 | 92 |   } | 
 | 93 |  | 
| Andreas Gampe | 2e6f38a | 2016-11-03 14:06:20 -0700 | [diff] [blame] | 94 |   Location(const Location& other) = default; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 95 |  | 
| Andreas Gampe | 2e6f38a | 2016-11-03 14:06:20 -0700 | [diff] [blame] | 96 |   Location& operator=(const Location& other) = default; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 97 |  | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 98 |   bool IsConstant() const { | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 99 |     return (value_ & kLocationConstantMask) == kConstant; | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 100 |   } | 
 | 101 |  | 
 | 102 |   static Location ConstantLocation(HConstant* constant) { | 
 | 103 |     DCHECK(constant != nullptr); | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 104 |     return Location(kConstant | reinterpret_cast<uintptr_t>(constant)); | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 105 |   } | 
 | 106 |  | 
 | 107 |   HConstant* GetConstant() const { | 
 | 108 |     DCHECK(IsConstant()); | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 109 |     return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask); | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 110 |   } | 
 | 111 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 112 |   bool IsValid() const { | 
 | 113 |     return value_ != kInvalid; | 
 | 114 |   } | 
 | 115 |  | 
 | 116 |   bool IsInvalid() const { | 
 | 117 |     return !IsValid(); | 
 | 118 |   } | 
 | 119 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 120 |   // Empty location. Used if there the location should be ignored. | 
 | 121 |   static Location NoLocation() { | 
 | 122 |     return Location(); | 
 | 123 |   } | 
 | 124 |  | 
 | 125 |   // Register locations. | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 126 |   static Location RegisterLocation(int reg) { | 
 | 127 |     return Location(kRegister, reg); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 128 |   } | 
 | 129 |  | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 130 |   static Location FpuRegisterLocation(int reg) { | 
 | 131 |     return Location(kFpuRegister, reg); | 
 | 132 |   } | 
 | 133 |  | 
 | 134 |   static Location RegisterPairLocation(int low, int high) { | 
 | 135 |     return Location(kRegisterPair, low << 16 | high); | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 136 |   } | 
 | 137 |  | 
| Nicolas Geoffray | 1ba0f59 | 2014-10-27 15:14:55 +0000 | [diff] [blame] | 138 |   static Location FpuRegisterPairLocation(int low, int high) { | 
 | 139 |     return Location(kFpuRegisterPair, low << 16 | high); | 
 | 140 |   } | 
 | 141 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 142 |   bool IsRegister() const { | 
 | 143 |     return GetKind() == kRegister; | 
 | 144 |   } | 
 | 145 |  | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 146 |   bool IsFpuRegister() const { | 
 | 147 |     return GetKind() == kFpuRegister; | 
 | 148 |   } | 
 | 149 |  | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 150 |   bool IsRegisterPair() const { | 
 | 151 |     return GetKind() == kRegisterPair; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 152 |   } | 
 | 153 |  | 
| Nicolas Geoffray | 1ba0f59 | 2014-10-27 15:14:55 +0000 | [diff] [blame] | 154 |   bool IsFpuRegisterPair() const { | 
 | 155 |     return GetKind() == kFpuRegisterPair; | 
 | 156 |   } | 
 | 157 |  | 
| Nicolas Geoffray | da02afe | 2015-02-11 02:29:42 +0000 | [diff] [blame] | 158 |   bool IsRegisterKind() const { | 
 | 159 |     return IsRegister() || IsFpuRegister() || IsRegisterPair() || IsFpuRegisterPair(); | 
 | 160 |   } | 
 | 161 |  | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 162 |   int reg() const { | 
 | 163 |     DCHECK(IsRegister() || IsFpuRegister()); | 
 | 164 |     return GetPayload(); | 
 | 165 |   } | 
 | 166 |  | 
| Nicolas Geoffray | 840e546 | 2015-01-07 16:01:24 +0000 | [diff] [blame] | 167 |   int low() const { | 
 | 168 |     DCHECK(IsPair()); | 
 | 169 |     return GetPayload() >> 16; | 
 | 170 |   } | 
 | 171 |  | 
 | 172 |   int high() const { | 
 | 173 |     DCHECK(IsPair()); | 
 | 174 |     return GetPayload() & 0xFFFF; | 
 | 175 |   } | 
 | 176 |  | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 177 |   template <typename T> | 
| Roland Levillain | 271ab9c | 2014-11-27 15:23:57 +0000 | [diff] [blame] | 178 |   T AsRegister() const { | 
 | 179 |     DCHECK(IsRegister()); | 
 | 180 |     return static_cast<T>(reg()); | 
 | 181 |   } | 
 | 182 |  | 
 | 183 |   template <typename T> | 
 | 184 |   T AsFpuRegister() const { | 
 | 185 |     DCHECK(IsFpuRegister()); | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 186 |     return static_cast<T>(reg()); | 
 | 187 |   } | 
 | 188 |  | 
 | 189 |   template <typename T> | 
 | 190 |   T AsRegisterPairLow() const { | 
 | 191 |     DCHECK(IsRegisterPair()); | 
| Nicolas Geoffray | 840e546 | 2015-01-07 16:01:24 +0000 | [diff] [blame] | 192 |     return static_cast<T>(low()); | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 193 |   } | 
 | 194 |  | 
 | 195 |   template <typename T> | 
 | 196 |   T AsRegisterPairHigh() const { | 
 | 197 |     DCHECK(IsRegisterPair()); | 
| Nicolas Geoffray | 840e546 | 2015-01-07 16:01:24 +0000 | [diff] [blame] | 198 |     return static_cast<T>(high()); | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 199 |   } | 
 | 200 |  | 
| Nicolas Geoffray | 1ba0f59 | 2014-10-27 15:14:55 +0000 | [diff] [blame] | 201 |   template <typename T> | 
 | 202 |   T AsFpuRegisterPairLow() const { | 
 | 203 |     DCHECK(IsFpuRegisterPair()); | 
| Nicolas Geoffray | 840e546 | 2015-01-07 16:01:24 +0000 | [diff] [blame] | 204 |     return static_cast<T>(low()); | 
| Nicolas Geoffray | 1ba0f59 | 2014-10-27 15:14:55 +0000 | [diff] [blame] | 205 |   } | 
 | 206 |  | 
 | 207 |   template <typename T> | 
 | 208 |   T AsFpuRegisterPairHigh() const { | 
 | 209 |     DCHECK(IsFpuRegisterPair()); | 
| Nicolas Geoffray | 840e546 | 2015-01-07 16:01:24 +0000 | [diff] [blame] | 210 |     return static_cast<T>(high()); | 
 | 211 |   } | 
 | 212 |  | 
 | 213 |   bool IsPair() const { | 
 | 214 |     return IsRegisterPair() || IsFpuRegisterPair(); | 
 | 215 |   } | 
 | 216 |  | 
 | 217 |   Location ToLow() const { | 
| Nicolas Geoffray | 234d69d | 2015-03-09 10:28:50 +0000 | [diff] [blame] | 218 |     if (IsRegisterPair()) { | 
 | 219 |       return Location::RegisterLocation(low()); | 
 | 220 |     } else if (IsFpuRegisterPair()) { | 
 | 221 |       return Location::FpuRegisterLocation(low()); | 
 | 222 |     } else { | 
 | 223 |       DCHECK(IsDoubleStackSlot()); | 
 | 224 |       return Location::StackSlot(GetStackIndex()); | 
 | 225 |     } | 
| Nicolas Geoffray | 840e546 | 2015-01-07 16:01:24 +0000 | [diff] [blame] | 226 |   } | 
 | 227 |  | 
 | 228 |   Location ToHigh() const { | 
| Nicolas Geoffray | 234d69d | 2015-03-09 10:28:50 +0000 | [diff] [blame] | 229 |     if (IsRegisterPair()) { | 
 | 230 |       return Location::RegisterLocation(high()); | 
 | 231 |     } else if (IsFpuRegisterPair()) { | 
 | 232 |       return Location::FpuRegisterLocation(high()); | 
 | 233 |     } else { | 
 | 234 |       DCHECK(IsDoubleStackSlot()); | 
 | 235 |       return Location::StackSlot(GetHighStackIndex(4)); | 
 | 236 |     } | 
| Nicolas Geoffray | 1ba0f59 | 2014-10-27 15:14:55 +0000 | [diff] [blame] | 237 |   } | 
 | 238 |  | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 239 |   static uintptr_t EncodeStackIndex(intptr_t stack_index) { | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 240 |     DCHECK(-kStackIndexBias <= stack_index); | 
 | 241 |     DCHECK(stack_index < kStackIndexBias); | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 242 |     return static_cast<uintptr_t>(kStackIndexBias + stack_index); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 243 |   } | 
 | 244 |  | 
 | 245 |   static Location StackSlot(intptr_t stack_index) { | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 246 |     uintptr_t payload = EncodeStackIndex(stack_index); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 247 |     Location loc(kStackSlot, payload); | 
 | 248 |     // Ensure that sign is preserved. | 
 | 249 |     DCHECK_EQ(loc.GetStackIndex(), stack_index); | 
 | 250 |     return loc; | 
 | 251 |   } | 
 | 252 |  | 
 | 253 |   bool IsStackSlot() const { | 
 | 254 |     return GetKind() == kStackSlot; | 
 | 255 |   } | 
 | 256 |  | 
 | 257 |   static Location DoubleStackSlot(intptr_t stack_index) { | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 258 |     uintptr_t payload = EncodeStackIndex(stack_index); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 259 |     Location loc(kDoubleStackSlot, payload); | 
 | 260 |     // Ensure that sign is preserved. | 
 | 261 |     DCHECK_EQ(loc.GetStackIndex(), stack_index); | 
 | 262 |     return loc; | 
 | 263 |   } | 
 | 264 |  | 
 | 265 |   bool IsDoubleStackSlot() const { | 
 | 266 |     return GetKind() == kDoubleStackSlot; | 
 | 267 |   } | 
 | 268 |  | 
 | 269 |   intptr_t GetStackIndex() const { | 
 | 270 |     DCHECK(IsStackSlot() || IsDoubleStackSlot()); | 
 | 271 |     // Decode stack index manually to preserve sign. | 
 | 272 |     return GetPayload() - kStackIndexBias; | 
 | 273 |   } | 
 | 274 |  | 
 | 275 |   intptr_t GetHighStackIndex(uintptr_t word_size) const { | 
 | 276 |     DCHECK(IsDoubleStackSlot()); | 
 | 277 |     // Decode stack index manually to preserve sign. | 
 | 278 |     return GetPayload() - kStackIndexBias + word_size; | 
 | 279 |   } | 
 | 280 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 281 |   Kind GetKind() const { | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 282 |     return IsConstant() ? kConstant : KindField::Decode(value_); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 283 |   } | 
 | 284 |  | 
 | 285 |   bool Equals(Location other) const { | 
 | 286 |     return value_ == other.value_; | 
 | 287 |   } | 
 | 288 |  | 
| Nicolas Geoffray | f7a0c4e | 2015-02-10 17:08:47 +0000 | [diff] [blame] | 289 |   bool Contains(Location other) const { | 
 | 290 |     if (Equals(other)) { | 
 | 291 |       return true; | 
| Zheng Xu | ad4450e | 2015-04-17 18:48:56 +0800 | [diff] [blame] | 292 |     } else if (IsPair() || IsDoubleStackSlot()) { | 
 | 293 |       return ToLow().Equals(other) || ToHigh().Equals(other); | 
| Nicolas Geoffray | f7a0c4e | 2015-02-10 17:08:47 +0000 | [diff] [blame] | 294 |     } | 
 | 295 |     return false; | 
 | 296 |   } | 
 | 297 |  | 
| Zheng Xu | ad4450e | 2015-04-17 18:48:56 +0800 | [diff] [blame] | 298 |   bool OverlapsWith(Location other) const { | 
 | 299 |     // Only check the overlapping case that can happen with our register allocation algorithm. | 
 | 300 |     bool overlap = Contains(other) || other.Contains(*this); | 
 | 301 |     if (kIsDebugBuild && !overlap) { | 
 | 302 |       // Note: These are also overlapping cases. But we are not able to handle them in | 
 | 303 |       // ParallelMoveResolverWithSwap. Make sure that we do not meet such case with our compiler. | 
 | 304 |       if ((IsPair() && other.IsPair()) || (IsDoubleStackSlot() && other.IsDoubleStackSlot())) { | 
 | 305 |         DCHECK(!Contains(other.ToLow())); | 
 | 306 |         DCHECK(!Contains(other.ToHigh())); | 
 | 307 |       } | 
 | 308 |     } | 
 | 309 |     return overlap; | 
 | 310 |   } | 
 | 311 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 312 |   const char* DebugString() const { | 
 | 313 |     switch (GetKind()) { | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 314 |       case kInvalid: return "I"; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 315 |       case kRegister: return "R"; | 
 | 316 |       case kStackSlot: return "S"; | 
 | 317 |       case kDoubleStackSlot: return "DS"; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 318 |       case kUnallocated: return "U"; | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 319 |       case kConstant: return "C"; | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 320 |       case kFpuRegister: return "F"; | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 321 |       case kRegisterPair: return "RP"; | 
| Nicolas Geoffray | 1ba0f59 | 2014-10-27 15:14:55 +0000 | [diff] [blame] | 322 |       case kFpuRegisterPair: return "FP"; | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 323 |       case kDoNotUse5:  // fall-through | 
 | 324 |       case kDoNotUse9: | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 325 |         LOG(FATAL) << "Should not use this location kind"; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 326 |     } | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 327 |     UNREACHABLE(); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 328 |   } | 
 | 329 |  | 
 | 330 |   // Unallocated locations. | 
 | 331 |   enum Policy { | 
 | 332 |     kAny, | 
 | 333 |     kRequiresRegister, | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 334 |     kRequiresFpuRegister, | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 335 |     kSameAsFirstInput, | 
 | 336 |   }; | 
 | 337 |  | 
 | 338 |   bool IsUnallocated() const { | 
 | 339 |     return GetKind() == kUnallocated; | 
 | 340 |   } | 
 | 341 |  | 
 | 342 |   static Location UnallocatedLocation(Policy policy) { | 
 | 343 |     return Location(kUnallocated, PolicyField::Encode(policy)); | 
 | 344 |   } | 
 | 345 |  | 
 | 346 |   // Any free register is suitable to replace this unallocated location. | 
 | 347 |   static Location Any() { | 
 | 348 |     return UnallocatedLocation(kAny); | 
 | 349 |   } | 
 | 350 |  | 
 | 351 |   static Location RequiresRegister() { | 
 | 352 |     return UnallocatedLocation(kRequiresRegister); | 
 | 353 |   } | 
 | 354 |  | 
| Nicolas Geoffray | 7fb49da | 2014-10-06 09:12:41 +0100 | [diff] [blame] | 355 |   static Location RequiresFpuRegister() { | 
 | 356 |     return UnallocatedLocation(kRequiresFpuRegister); | 
 | 357 |   } | 
 | 358 |  | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 359 |   static Location RegisterOrConstant(HInstruction* instruction); | 
| Mark Mendell | ea5af68 | 2015-10-22 17:35:49 -0400 | [diff] [blame] | 360 |   static Location RegisterOrInt32Constant(HInstruction* instruction); | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 361 |   static Location ByteRegisterOrConstant(int reg, HInstruction* instruction); | 
| Mark Mendell | ea5af68 | 2015-10-22 17:35:49 -0400 | [diff] [blame] | 362 |   static Location FpuRegisterOrConstant(HInstruction* instruction); | 
 | 363 |   static Location FpuRegisterOrInt32Constant(HInstruction* instruction); | 
| Nicolas Geoffray | 96f89a2 | 2014-07-11 10:57:49 +0100 | [diff] [blame] | 364 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 365 |   // The location of the first input to the instruction will be | 
 | 366 |   // used to replace this unallocated location. | 
 | 367 |   static Location SameAsFirstInput() { | 
 | 368 |     return UnallocatedLocation(kSameAsFirstInput); | 
 | 369 |   } | 
 | 370 |  | 
 | 371 |   Policy GetPolicy() const { | 
 | 372 |     DCHECK(IsUnallocated()); | 
 | 373 |     return PolicyField::Decode(GetPayload()); | 
 | 374 |   } | 
 | 375 |  | 
| Matthew Gharrity | d9ffd0d | 2016-06-22 10:27:55 -0700 | [diff] [blame] | 376 |   bool RequiresRegisterKind() const { | 
 | 377 |     return GetPolicy() == kRequiresRegister || GetPolicy() == kRequiresFpuRegister; | 
 | 378 |   } | 
 | 379 |  | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 380 |   uintptr_t GetEncoding() const { | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 381 |     return GetPayload(); | 
 | 382 |   } | 
 | 383 |  | 
 | 384 |  private: | 
 | 385 |   // Number of bits required to encode Kind value. | 
 | 386 |   static constexpr uint32_t kBitsForKind = 4; | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 387 |   static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind; | 
 | 388 |   static constexpr uintptr_t kLocationConstantMask = 0x3; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 389 |  | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 390 |   explicit Location(uintptr_t value) : value_(value) {} | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 391 |  | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 392 |   Location(Kind kind, uintptr_t payload) | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 393 |       : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {} | 
 | 394 |  | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 395 |   uintptr_t GetPayload() const { | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 396 |     return PayloadField::Decode(value_); | 
 | 397 |   } | 
 | 398 |  | 
 | 399 |   typedef BitField<Kind, 0, kBitsForKind> KindField; | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 400 |   typedef BitField<uintptr_t, kBitsForKind, kBitsForPayload> PayloadField; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 401 |  | 
 | 402 |   // Layout for kUnallocated locations payload. | 
 | 403 |   typedef BitField<Policy, 0, 3> PolicyField; | 
 | 404 |  | 
 | 405 |   // Layout for stack slots. | 
 | 406 |   static const intptr_t kStackIndexBias = | 
 | 407 |       static_cast<intptr_t>(1) << (kBitsForPayload - 1); | 
 | 408 |  | 
 | 409 |   // Location either contains kind and payload fields or a tagged handle for | 
 | 410 |   // a constant locations. Values of enumeration Kind are selected in such a | 
 | 411 |   // way that none of them can be interpreted as a kConstant tag. | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 412 |   uintptr_t value_; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 413 | }; | 
| Ian Rogers | 6a3c1fc | 2014-10-31 00:33:20 -0700 | [diff] [blame] | 414 | std::ostream& operator<<(std::ostream& os, const Location::Kind& rhs); | 
 | 415 | std::ostream& operator<<(std::ostream& os, const Location::Policy& rhs); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 416 |  | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 417 | class RegisterSet : public ValueObject { | 
 | 418 |  public: | 
| Vladimir Marko | 804b03f | 2016-09-14 16:26:36 +0100 | [diff] [blame] | 419 |   static RegisterSet Empty() { return RegisterSet(); } | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 420 |  | 
 | 421 |   void Add(Location loc) { | 
| Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 422 |     if (loc.IsRegister()) { | 
 | 423 |       core_registers_ |= (1 << loc.reg()); | 
 | 424 |     } else { | 
 | 425 |       DCHECK(loc.IsFpuRegister()); | 
 | 426 |       floating_point_registers_ |= (1 << loc.reg()); | 
 | 427 |     } | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 428 |   } | 
 | 429 |  | 
| Nicolas Geoffray | 19a19cf | 2014-10-22 16:07:05 +0100 | [diff] [blame] | 430 |   void Remove(Location loc) { | 
 | 431 |     if (loc.IsRegister()) { | 
 | 432 |       core_registers_ &= ~(1 << loc.reg()); | 
 | 433 |     } else { | 
| Nicolas Geoffray | 424f676 | 2014-11-03 14:51:25 +0000 | [diff] [blame] | 434 |       DCHECK(loc.IsFpuRegister()) << loc; | 
| Nicolas Geoffray | 19a19cf | 2014-10-22 16:07:05 +0100 | [diff] [blame] | 435 |       floating_point_registers_ &= ~(1 << loc.reg()); | 
 | 436 |     } | 
 | 437 |   } | 
 | 438 |  | 
| Nicolas Geoffray | 45b83af | 2015-07-06 15:12:53 +0000 | [diff] [blame] | 439 |   bool ContainsCoreRegister(uint32_t id) const { | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 440 |     return Contains(core_registers_, id); | 
 | 441 |   } | 
 | 442 |  | 
| Nicolas Geoffray | 45b83af | 2015-07-06 15:12:53 +0000 | [diff] [blame] | 443 |   bool ContainsFloatingPointRegister(uint32_t id) const { | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 444 |     return Contains(floating_point_registers_, id); | 
 | 445 |   } | 
 | 446 |  | 
 | 447 |   static bool Contains(uint32_t register_set, uint32_t reg) { | 
 | 448 |     return (register_set & (1 << reg)) != 0; | 
 | 449 |   } | 
 | 450 |  | 
| Nicolas Geoffray | 87d0376 | 2014-11-19 15:17:56 +0000 | [diff] [blame] | 451 |   size_t GetNumberOfRegisters() const { | 
| Vladimir Marko | 70e9746 | 2016-08-09 11:04:26 +0100 | [diff] [blame] | 452 |     return POPCOUNT(core_registers_) + POPCOUNT(floating_point_registers_); | 
| Nicolas Geoffray | 87d0376 | 2014-11-19 15:17:56 +0000 | [diff] [blame] | 453 |   } | 
 | 454 |  | 
| Nicolas Geoffray | 9889396 | 2015-01-21 12:32:32 +0000 | [diff] [blame] | 455 |   uint32_t GetCoreRegisters() const { | 
 | 456 |     return core_registers_; | 
 | 457 |   } | 
 | 458 |  | 
 | 459 |   uint32_t GetFloatingPointRegisters() const { | 
 | 460 |     return floating_point_registers_; | 
 | 461 |   } | 
 | 462 |  | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 463 |  private: | 
| Vladimir Marko | 804b03f | 2016-09-14 16:26:36 +0100 | [diff] [blame] | 464 |   RegisterSet() : core_registers_(0), floating_point_registers_(0) {} | 
 | 465 |  | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 466 |   uint32_t core_registers_; | 
 | 467 |   uint32_t floating_point_registers_; | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 468 | }; | 
 | 469 |  | 
| Andreas Gampe | 878d58c | 2015-01-15 23:24:00 -0800 | [diff] [blame] | 470 | static constexpr bool kIntrinsified = true; | 
 | 471 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 472 | /** | 
 | 473 |  * The code generator computes LocationSummary for each instruction so that | 
 | 474 |  * the instruction itself knows what code to generate: where to find the inputs | 
 | 475 |  * and where to place the result. | 
 | 476 |  * | 
 | 477 |  * The intent is to have the code for generating the instruction independent of | 
 | 478 |  * register allocation. A register allocator just has to provide a LocationSummary. | 
 | 479 |  */ | 
| Vladimir Marko | 5233f93 | 2015-09-29 19:01:15 +0100 | [diff] [blame] | 480 | class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 481 |  public: | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 482 |   enum CallKind { | 
 | 483 |     kNoCall, | 
| Serban Constantinescu | 806f012 | 2016-03-09 11:10:16 +0000 | [diff] [blame] | 484 |     kCallOnMainAndSlowPath, | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 485 |     kCallOnSlowPath, | 
| Serban Constantinescu | 54ff482 | 2016-07-07 18:03:19 +0100 | [diff] [blame] | 486 |     kCallOnMainOnly | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 487 |   }; | 
 | 488 |  | 
| Chih-Hung Hsieh | a593118 | 2016-09-01 15:08:13 -0700 | [diff] [blame] | 489 |   explicit LocationSummary(HInstruction* instruction, | 
 | 490 |                            CallKind call_kind = kNoCall, | 
 | 491 |                            bool intrinsified = false); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 492 |  | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 493 |   void SetInAt(uint32_t at, Location location) { | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 494 |     inputs_[at] = location; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 495 |   } | 
 | 496 |  | 
 | 497 |   Location InAt(uint32_t at) const { | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 498 |     return inputs_[at]; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 499 |   } | 
 | 500 |  | 
 | 501 |   size_t GetInputCount() const { | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 502 |     return inputs_.size(); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 503 |   } | 
 | 504 |  | 
| Roland Levillain | 3d31242 | 2016-06-23 13:53:42 +0100 | [diff] [blame] | 505 |   // Set the output location.  Argument `overlaps` tells whether the | 
 | 506 |   // output overlaps any of the inputs (if so, it cannot share the | 
 | 507 |   // same register as one of the inputs); it is set to | 
 | 508 |   // `Location::kOutputOverlap` by default for safety. | 
| Nicolas Geoffray | 6c2dff8 | 2015-01-21 14:56:54 +0000 | [diff] [blame] | 509 |   void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) { | 
| Nicolas Geoffray | 829280c | 2015-01-28 10:20:37 +0000 | [diff] [blame] | 510 |     DCHECK(output_.IsInvalid()); | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 511 |     output_overlaps_ = overlaps; | 
| Nicolas Geoffray | f43083d | 2014-11-07 10:48:10 +0000 | [diff] [blame] | 512 |     output_ = location; | 
 | 513 |   } | 
 | 514 |  | 
 | 515 |   void UpdateOut(Location location) { | 
| Nicolas Geoffray | 829280c | 2015-01-28 10:20:37 +0000 | [diff] [blame] | 516 |     // There are two reasons for updating an output: | 
 | 517 |     // 1) Parameters, where we only know the exact stack slot after | 
 | 518 |     //    doing full register allocation. | 
 | 519 |     // 2) Unallocated location. | 
 | 520 |     DCHECK(output_.IsStackSlot() || output_.IsDoubleStackSlot() || output_.IsUnallocated()); | 
| Nicolas Geoffray | f43083d | 2014-11-07 10:48:10 +0000 | [diff] [blame] | 521 |     output_ = location; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 522 |   } | 
 | 523 |  | 
 | 524 |   void AddTemp(Location location) { | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 525 |     temps_.push_back(location); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 526 |   } | 
 | 527 |  | 
| Mathieu Chartier | 5c44c1b | 2016-11-04 18:13:04 -0700 | [diff] [blame] | 528 |   void AddRegisterTemps(size_t count) { | 
 | 529 |     for (size_t i = 0; i < count; ++i) { | 
 | 530 |       AddTemp(Location::RequiresRegister()); | 
 | 531 |     } | 
 | 532 |   } | 
 | 533 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 534 |   Location GetTemp(uint32_t at) const { | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 535 |     return temps_[at]; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 536 |   } | 
 | 537 |  | 
 | 538 |   void SetTempAt(uint32_t at, Location location) { | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 539 |     DCHECK(temps_[at].IsUnallocated() || temps_[at].IsInvalid()); | 
 | 540 |     temps_[at] = location; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 541 |   } | 
 | 542 |  | 
 | 543 |   size_t GetTempCount() const { | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 544 |     return temps_.size(); | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 545 |   } | 
 | 546 |  | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 547 |   bool HasTemps() const { return !temps_.empty(); } | 
| Nicolas Geoffray | 94015b9 | 2015-06-04 18:21:04 +0100 | [diff] [blame] | 548 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 549 |   Location Out() const { return output_; } | 
 | 550 |  | 
| Serban Constantinescu | 806f012 | 2016-03-09 11:10:16 +0000 | [diff] [blame] | 551 |   bool CanCall() const { | 
 | 552 |     return call_kind_ != kNoCall; | 
 | 553 |   } | 
 | 554 |  | 
 | 555 |   bool WillCall() const { | 
 | 556 |     return call_kind_ == kCallOnMainOnly || call_kind_ == kCallOnMainAndSlowPath; | 
 | 557 |   } | 
 | 558 |  | 
 | 559 |   bool CallsOnSlowPath() const { | 
 | 560 |     return call_kind_ == kCallOnSlowPath || call_kind_ == kCallOnMainAndSlowPath; | 
 | 561 |   } | 
 | 562 |  | 
 | 563 |   bool OnlyCallsOnSlowPath() const { | 
 | 564 |     return call_kind_ == kCallOnSlowPath; | 
 | 565 |   } | 
 | 566 |  | 
 | 567 |   bool CallsOnMainAndSlowPath() const { | 
 | 568 |     return call_kind_ == kCallOnMainAndSlowPath; | 
 | 569 |   } | 
 | 570 |  | 
 | 571 |   bool NeedsSafepoint() const { | 
 | 572 |     return CanCall(); | 
 | 573 |   } | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 574 |  | 
| Vladimir Marko | 70e9746 | 2016-08-09 11:04:26 +0100 | [diff] [blame] | 575 |   void SetCustomSlowPathCallerSaves(const RegisterSet& caller_saves) { | 
 | 576 |     DCHECK(OnlyCallsOnSlowPath()); | 
 | 577 |     has_custom_slow_path_calling_convention_ = true; | 
 | 578 |     custom_slow_path_caller_saves_ = caller_saves; | 
 | 579 |   } | 
 | 580 |  | 
 | 581 |   bool HasCustomSlowPathCallingConvention() const { | 
 | 582 |     return has_custom_slow_path_calling_convention_; | 
 | 583 |   } | 
 | 584 |  | 
 | 585 |   const RegisterSet& GetCustomSlowPathCallerSaves() const { | 
 | 586 |     DCHECK(HasCustomSlowPathCallingConvention()); | 
 | 587 |     return custom_slow_path_caller_saves_; | 
 | 588 |   } | 
 | 589 |  | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 590 |   void SetStackBit(uint32_t index) { | 
 | 591 |     stack_mask_->SetBit(index); | 
 | 592 |   } | 
 | 593 |  | 
| Nicolas Geoffray | 3c04974 | 2014-09-24 18:10:46 +0100 | [diff] [blame] | 594 |   void ClearStackBit(uint32_t index) { | 
 | 595 |     stack_mask_->ClearBit(index); | 
 | 596 |   } | 
 | 597 |  | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 598 |   void SetRegisterBit(uint32_t reg_id) { | 
 | 599 |     register_mask_ |= (1 << reg_id); | 
 | 600 |   } | 
 | 601 |  | 
| Nicolas Geoffray | 9889396 | 2015-01-21 12:32:32 +0000 | [diff] [blame] | 602 |   uint32_t GetRegisterMask() const { | 
 | 603 |     return register_mask_; | 
 | 604 |   } | 
 | 605 |  | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 606 |   bool RegisterContainsObject(uint32_t reg_id) { | 
 | 607 |     return RegisterSet::Contains(register_mask_, reg_id); | 
 | 608 |   } | 
 | 609 |  | 
 | 610 |   void AddLiveRegister(Location location) { | 
 | 611 |     live_registers_.Add(location); | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 612 |   } | 
 | 613 |  | 
 | 614 |   BitVector* GetStackMask() const { | 
 | 615 |     return stack_mask_; | 
 | 616 |   } | 
 | 617 |  | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 618 |   RegisterSet* GetLiveRegisters() { | 
 | 619 |     return &live_registers_; | 
 | 620 |   } | 
 | 621 |  | 
| Nicolas Geoffray | 87d0376 | 2014-11-19 15:17:56 +0000 | [diff] [blame] | 622 |   size_t GetNumberOfLiveRegisters() const { | 
 | 623 |     return live_registers_.GetNumberOfRegisters(); | 
 | 624 |   } | 
 | 625 |  | 
| Nicolas Geoffray | 829280c | 2015-01-28 10:20:37 +0000 | [diff] [blame] | 626 |   bool OutputUsesSameAs(uint32_t input_index) const { | 
 | 627 |     return (input_index == 0) | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 628 |         && output_.IsUnallocated() | 
| Nicolas Geoffray | 829280c | 2015-01-28 10:20:37 +0000 | [diff] [blame] | 629 |         && (output_.GetPolicy() == Location::kSameAsFirstInput); | 
 | 630 |   } | 
 | 631 |  | 
 | 632 |   bool IsFixedInput(uint32_t input_index) const { | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 633 |     Location input = inputs_[input_index]; | 
| Nicolas Geoffray | 829280c | 2015-01-28 10:20:37 +0000 | [diff] [blame] | 634 |     return input.IsRegister() | 
| Nicolas Geoffray | 9889396 | 2015-01-21 12:32:32 +0000 | [diff] [blame] | 635 |         || input.IsFpuRegister() | 
 | 636 |         || input.IsPair() | 
 | 637 |         || input.IsStackSlot() | 
| Nicolas Geoffray | 829280c | 2015-01-28 10:20:37 +0000 | [diff] [blame] | 638 |         || input.IsDoubleStackSlot(); | 
| Nicolas Geoffray | 7690562 | 2014-09-25 14:39:26 +0100 | [diff] [blame] | 639 |   } | 
 | 640 |  | 
| Nicolas Geoffray | 829280c | 2015-01-28 10:20:37 +0000 | [diff] [blame] | 641 |   bool OutputCanOverlapWithInputs() const { | 
| Nicolas Geoffray | 6c2dff8 | 2015-01-21 14:56:54 +0000 | [diff] [blame] | 642 |     return output_overlaps_ == Location::kOutputOverlap; | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 643 |   } | 
 | 644 |  | 
| Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 645 |   bool Intrinsified() const { | 
 | 646 |     return intrinsified_; | 
 | 647 |   } | 
 | 648 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 649 |  private: | 
| Vladimir Marko | 2aaa4b5 | 2015-09-17 17:03:26 +0100 | [diff] [blame] | 650 |   ArenaVector<Location> inputs_; | 
 | 651 |   ArenaVector<Location> temps_; | 
| Vladimir Marko | 70e9746 | 2016-08-09 11:04:26 +0100 | [diff] [blame] | 652 |   const CallKind call_kind_; | 
 | 653 |   // Whether these are locations for an intrinsified call. | 
 | 654 |   const bool intrinsified_; | 
 | 655 |   // Whether the slow path has default or custom calling convention. | 
 | 656 |   bool has_custom_slow_path_calling_convention_; | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 657 |   // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot | 
 | 658 |   // share the same register as the inputs. | 
| Nicolas Geoffray | 6c2dff8 | 2015-01-21 14:56:54 +0000 | [diff] [blame] | 659 |   Location::OutputOverlap output_overlaps_; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 660 |   Location output_; | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 661 |  | 
 | 662 |   // Mask of objects that live in the stack. | 
 | 663 |   BitVector* stack_mask_; | 
 | 664 |  | 
 | 665 |   // Mask of objects that live in register. | 
 | 666 |   uint32_t register_mask_; | 
 | 667 |  | 
 | 668 |   // Registers that are in use at this position. | 
| Nicolas Geoffray | 3bca0df | 2014-09-19 11:01:00 +0100 | [diff] [blame] | 669 |   RegisterSet live_registers_; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 670 |  | 
| Vladimir Marko | 70e9746 | 2016-08-09 11:04:26 +0100 | [diff] [blame] | 671 |   // Custom slow path caller saves. Valid only if indicated by slow_path_calling_convention_. | 
 | 672 |   RegisterSet custom_slow_path_caller_saves_; | 
| Andreas Gampe | 71fb52f | 2014-12-29 17:43:08 -0800 | [diff] [blame] | 673 |  | 
| Matthew Gharrity | 2ac06bc | 2016-08-05 09:34:52 -0700 | [diff] [blame] | 674 |   friend class RegisterAllocatorTest; | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 675 |   DISALLOW_COPY_AND_ASSIGN(LocationSummary); | 
 | 676 | }; | 
 | 677 |  | 
| Nicolas Geoffray | 76716a6 | 2014-05-23 10:14:19 +0100 | [diff] [blame] | 678 | }  // namespace art | 
 | 679 |  | 
 | 680 | #endif  // ART_COMPILER_OPTIMIZING_LOCATIONS_H_ |