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