| /* | 
 |  * Copyright (C) 2014 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #ifndef ART_COMPILER_OPTIMIZING_LOCATIONS_H_ | 
 | #define ART_COMPILER_OPTIMIZING_LOCATIONS_H_ | 
 |  | 
 | #include "base/arena_containers.h" | 
 | #include "base/arena_object.h" | 
 | #include "base/bit_field.h" | 
 | #include "base/bit_utils.h" | 
 | #include "base/bit_vector.h" | 
 | #include "base/value_object.h" | 
 |  | 
 | namespace art { | 
 |  | 
 | class HConstant; | 
 | class HInstruction; | 
 | class Location; | 
 |  | 
 | std::ostream& operator<<(std::ostream& os, const Location& location); | 
 |  | 
 | /** | 
 |  * A Location is an abstraction over the potential location | 
 |  * of an instruction. It could be in register or stack. | 
 |  */ | 
 | class Location : public ValueObject { | 
 |  public: | 
 |   enum OutputOverlap { | 
 |     // The liveness of the output overlaps the liveness of one or | 
 |     // several input(s); the register allocator cannot reuse an | 
 |     // input's location for the output's location. | 
 |     kOutputOverlap, | 
 |     // The liveness of the output does not overlap the liveness of any | 
 |     // input; the register allocator is allowed to reuse an input's | 
 |     // location for the output's location. | 
 |     kNoOutputOverlap | 
 |   }; | 
 |  | 
 |   enum Kind { | 
 |     kInvalid = 0, | 
 |     kConstant = 1, | 
 |     kStackSlot = 2,  // 32bit stack slot. | 
 |     kDoubleStackSlot = 3,  // 64bit stack slot. | 
 |  | 
 |     kRegister = 4,  // Core register. | 
 |  | 
 |     // We do not use the value 5 because it conflicts with kLocationConstantMask. | 
 |     kDoNotUse5 = 5, | 
 |  | 
 |     kFpuRegister = 6,  // Float register. | 
 |  | 
 |     kRegisterPair = 7,  // Long register. | 
 |  | 
 |     kFpuRegisterPair = 8,  // Double register. | 
 |  | 
 |     // We do not use the value 9 because it conflicts with kLocationConstantMask. | 
 |     kDoNotUse9 = 9, | 
 |  | 
 |     kSIMDStackSlot = 10,  // 128bit stack slot. TODO: generalize with encoded #bytes? | 
 |  | 
 |     // Unallocated location represents a location that is not fixed and can be | 
 |     // allocated by a register allocator.  Each unallocated location has | 
 |     // a policy that specifies what kind of location is suitable. Payload | 
 |     // contains register allocation policy. | 
 |     kUnallocated = 11, | 
 |   }; | 
 |  | 
 |   Location() : ValueObject(), value_(kInvalid) { | 
 |     // Verify that non-constant location kinds do not interfere with kConstant. | 
 |     static_assert((kInvalid & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kUnallocated & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kStackSlot & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kDoubleStackSlot & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kSIMDStackSlot & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kRegister & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kFpuRegister & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kRegisterPair & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kFpuRegisterPair & kLocationConstantMask) != kConstant, "TagError"); | 
 |     static_assert((kConstant & kLocationConstantMask) == kConstant, "TagError"); | 
 |  | 
 |     DCHECK(!IsValid()); | 
 |   } | 
 |  | 
 |   Location(const Location& other) = default; | 
 |  | 
 |   Location& operator=(const Location& other) = default; | 
 |  | 
 |   bool IsConstant() const { | 
 |     return (value_ & kLocationConstantMask) == kConstant; | 
 |   } | 
 |  | 
 |   static Location ConstantLocation(HConstant* constant) { | 
 |     DCHECK(constant != nullptr); | 
 |     return Location(kConstant | reinterpret_cast<uintptr_t>(constant)); | 
 |   } | 
 |  | 
 |   HConstant* GetConstant() const { | 
 |     DCHECK(IsConstant()); | 
 |     return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask); | 
 |   } | 
 |  | 
 |   bool IsValid() const { | 
 |     return value_ != kInvalid; | 
 |   } | 
 |  | 
 |   bool IsInvalid() const { | 
 |     return !IsValid(); | 
 |   } | 
 |  | 
 |   // Empty location. Used if there the location should be ignored. | 
 |   static Location NoLocation() { | 
 |     return Location(); | 
 |   } | 
 |  | 
 |   // Register locations. | 
 |   static Location RegisterLocation(int reg) { | 
 |     return Location(kRegister, reg); | 
 |   } | 
 |  | 
 |   static Location FpuRegisterLocation(int reg) { | 
 |     return Location(kFpuRegister, reg); | 
 |   } | 
 |  | 
 |   static Location RegisterPairLocation(int low, int high) { | 
 |     return Location(kRegisterPair, low << 16 | high); | 
 |   } | 
 |  | 
 |   static Location FpuRegisterPairLocation(int low, int high) { | 
 |     return Location(kFpuRegisterPair, low << 16 | high); | 
 |   } | 
 |  | 
 |   bool IsRegister() const { | 
 |     return GetKind() == kRegister; | 
 |   } | 
 |  | 
 |   bool IsFpuRegister() const { | 
 |     return GetKind() == kFpuRegister; | 
 |   } | 
 |  | 
 |   bool IsRegisterPair() const { | 
 |     return GetKind() == kRegisterPair; | 
 |   } | 
 |  | 
 |   bool IsFpuRegisterPair() const { | 
 |     return GetKind() == kFpuRegisterPair; | 
 |   } | 
 |  | 
 |   bool IsRegisterKind() const { | 
 |     return IsRegister() || IsFpuRegister() || IsRegisterPair() || IsFpuRegisterPair(); | 
 |   } | 
 |  | 
 |   int reg() const { | 
 |     DCHECK(IsRegister() || IsFpuRegister()); | 
 |     return GetPayload(); | 
 |   } | 
 |  | 
 |   int low() const { | 
 |     DCHECK(IsPair()); | 
 |     return GetPayload() >> 16; | 
 |   } | 
 |  | 
 |   int high() const { | 
 |     DCHECK(IsPair()); | 
 |     return GetPayload() & 0xFFFF; | 
 |   } | 
 |  | 
 |   template <typename T> | 
 |   T AsRegister() const { | 
 |     DCHECK(IsRegister()); | 
 |     return static_cast<T>(reg()); | 
 |   } | 
 |  | 
 |   template <typename T> | 
 |   T AsFpuRegister() const { | 
 |     DCHECK(IsFpuRegister()); | 
 |     return static_cast<T>(reg()); | 
 |   } | 
 |  | 
 |   template <typename T> | 
 |   T AsRegisterPairLow() const { | 
 |     DCHECK(IsRegisterPair()); | 
 |     return static_cast<T>(low()); | 
 |   } | 
 |  | 
 |   template <typename T> | 
 |   T AsRegisterPairHigh() const { | 
 |     DCHECK(IsRegisterPair()); | 
 |     return static_cast<T>(high()); | 
 |   } | 
 |  | 
 |   template <typename T> | 
 |   T AsFpuRegisterPairLow() const { | 
 |     DCHECK(IsFpuRegisterPair()); | 
 |     return static_cast<T>(low()); | 
 |   } | 
 |  | 
 |   template <typename T> | 
 |   T AsFpuRegisterPairHigh() const { | 
 |     DCHECK(IsFpuRegisterPair()); | 
 |     return static_cast<T>(high()); | 
 |   } | 
 |  | 
 |   bool IsPair() const { | 
 |     return IsRegisterPair() || IsFpuRegisterPair(); | 
 |   } | 
 |  | 
 |   Location ToLow() const { | 
 |     if (IsRegisterPair()) { | 
 |       return Location::RegisterLocation(low()); | 
 |     } else if (IsFpuRegisterPair()) { | 
 |       return Location::FpuRegisterLocation(low()); | 
 |     } else { | 
 |       DCHECK(IsDoubleStackSlot()); | 
 |       return Location::StackSlot(GetStackIndex()); | 
 |     } | 
 |   } | 
 |  | 
 |   Location ToHigh() const { | 
 |     if (IsRegisterPair()) { | 
 |       return Location::RegisterLocation(high()); | 
 |     } else if (IsFpuRegisterPair()) { | 
 |       return Location::FpuRegisterLocation(high()); | 
 |     } else { | 
 |       DCHECK(IsDoubleStackSlot()); | 
 |       return Location::StackSlot(GetHighStackIndex(4)); | 
 |     } | 
 |   } | 
 |  | 
 |   static uintptr_t EncodeStackIndex(intptr_t stack_index) { | 
 |     DCHECK(-kStackIndexBias <= stack_index); | 
 |     DCHECK(stack_index < kStackIndexBias); | 
 |     return static_cast<uintptr_t>(kStackIndexBias + stack_index); | 
 |   } | 
 |  | 
 |   static Location StackSlot(intptr_t stack_index) { | 
 |     uintptr_t payload = EncodeStackIndex(stack_index); | 
 |     Location loc(kStackSlot, payload); | 
 |     // Ensure that sign is preserved. | 
 |     DCHECK_EQ(loc.GetStackIndex(), stack_index); | 
 |     return loc; | 
 |   } | 
 |  | 
 |   bool IsStackSlot() const { | 
 |     return GetKind() == kStackSlot; | 
 |   } | 
 |  | 
 |   static Location DoubleStackSlot(intptr_t stack_index) { | 
 |     uintptr_t payload = EncodeStackIndex(stack_index); | 
 |     Location loc(kDoubleStackSlot, payload); | 
 |     // Ensure that sign is preserved. | 
 |     DCHECK_EQ(loc.GetStackIndex(), stack_index); | 
 |     return loc; | 
 |   } | 
 |  | 
 |   bool IsDoubleStackSlot() const { | 
 |     return GetKind() == kDoubleStackSlot; | 
 |   } | 
 |  | 
 |   static Location SIMDStackSlot(intptr_t stack_index) { | 
 |     uintptr_t payload = EncodeStackIndex(stack_index); | 
 |     Location loc(kSIMDStackSlot, payload); | 
 |     // Ensure that sign is preserved. | 
 |     DCHECK_EQ(loc.GetStackIndex(), stack_index); | 
 |     return loc; | 
 |   } | 
 |  | 
 |   bool IsSIMDStackSlot() const { | 
 |     return GetKind() == kSIMDStackSlot; | 
 |   } | 
 |  | 
 |   intptr_t GetStackIndex() const { | 
 |     DCHECK(IsStackSlot() || IsDoubleStackSlot() || IsSIMDStackSlot()); | 
 |     // Decode stack index manually to preserve sign. | 
 |     return GetPayload() - kStackIndexBias; | 
 |   } | 
 |  | 
 |   intptr_t GetHighStackIndex(uintptr_t word_size) const { | 
 |     DCHECK(IsDoubleStackSlot()); | 
 |     // Decode stack index manually to preserve sign. | 
 |     return GetPayload() - kStackIndexBias + word_size; | 
 |   } | 
 |  | 
 |   Kind GetKind() const { | 
 |     return IsConstant() ? kConstant : KindField::Decode(value_); | 
 |   } | 
 |  | 
 |   bool Equals(Location other) const { | 
 |     return value_ == other.value_; | 
 |   } | 
 |  | 
 |   bool Contains(Location other) const { | 
 |     if (Equals(other)) { | 
 |       return true; | 
 |     } else if (IsPair() || IsDoubleStackSlot()) { | 
 |       return ToLow().Equals(other) || ToHigh().Equals(other); | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |   bool OverlapsWith(Location other) const { | 
 |     // Only check the overlapping case that can happen with our register allocation algorithm. | 
 |     bool overlap = Contains(other) || other.Contains(*this); | 
 |     if (kIsDebugBuild && !overlap) { | 
 |       // Note: These are also overlapping cases. But we are not able to handle them in | 
 |       // ParallelMoveResolverWithSwap. Make sure that we do not meet such case with our compiler. | 
 |       if ((IsPair() && other.IsPair()) || (IsDoubleStackSlot() && other.IsDoubleStackSlot())) { | 
 |         DCHECK(!Contains(other.ToLow())); | 
 |         DCHECK(!Contains(other.ToHigh())); | 
 |       } | 
 |     } | 
 |     return overlap; | 
 |   } | 
 |  | 
 |   const char* DebugString() const { | 
 |     switch (GetKind()) { | 
 |       case kInvalid: return "I"; | 
 |       case kRegister: return "R"; | 
 |       case kStackSlot: return "S"; | 
 |       case kDoubleStackSlot: return "DS"; | 
 |       case kSIMDStackSlot: return "SIMD"; | 
 |       case kUnallocated: return "U"; | 
 |       case kConstant: return "C"; | 
 |       case kFpuRegister: return "F"; | 
 |       case kRegisterPair: return "RP"; | 
 |       case kFpuRegisterPair: return "FP"; | 
 |       case kDoNotUse5:  // fall-through | 
 |       case kDoNotUse9: | 
 |         LOG(FATAL) << "Should not use this location kind"; | 
 |     } | 
 |     UNREACHABLE(); | 
 |   } | 
 |  | 
 |   // Unallocated locations. | 
 |   enum Policy { | 
 |     kAny, | 
 |     kRequiresRegister, | 
 |     kRequiresFpuRegister, | 
 |     kSameAsFirstInput, | 
 |   }; | 
 |  | 
 |   bool IsUnallocated() const { | 
 |     return GetKind() == kUnallocated; | 
 |   } | 
 |  | 
 |   static Location UnallocatedLocation(Policy policy) { | 
 |     return Location(kUnallocated, PolicyField::Encode(policy)); | 
 |   } | 
 |  | 
 |   // Any free register is suitable to replace this unallocated location. | 
 |   static Location Any() { | 
 |     return UnallocatedLocation(kAny); | 
 |   } | 
 |  | 
 |   static Location RequiresRegister() { | 
 |     return UnallocatedLocation(kRequiresRegister); | 
 |   } | 
 |  | 
 |   static Location RequiresFpuRegister() { | 
 |     return UnallocatedLocation(kRequiresFpuRegister); | 
 |   } | 
 |  | 
 |   static Location RegisterOrConstant(HInstruction* instruction); | 
 |   static Location RegisterOrInt32Constant(HInstruction* instruction); | 
 |   static Location ByteRegisterOrConstant(int reg, HInstruction* instruction); | 
 |   static Location FpuRegisterOrConstant(HInstruction* instruction); | 
 |   static Location FpuRegisterOrInt32Constant(HInstruction* instruction); | 
 |  | 
 |   // The location of the first input to the instruction will be | 
 |   // used to replace this unallocated location. | 
 |   static Location SameAsFirstInput() { | 
 |     return UnallocatedLocation(kSameAsFirstInput); | 
 |   } | 
 |  | 
 |   Policy GetPolicy() const { | 
 |     DCHECK(IsUnallocated()); | 
 |     return PolicyField::Decode(GetPayload()); | 
 |   } | 
 |  | 
 |   bool RequiresRegisterKind() const { | 
 |     return GetPolicy() == kRequiresRegister || GetPolicy() == kRequiresFpuRegister; | 
 |   } | 
 |  | 
 |   uintptr_t GetEncoding() const { | 
 |     return GetPayload(); | 
 |   } | 
 |  | 
 |  private: | 
 |   // Number of bits required to encode Kind value. | 
 |   static constexpr uint32_t kBitsForKind = 4; | 
 |   static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind; | 
 |   static constexpr uintptr_t kLocationConstantMask = 0x3; | 
 |  | 
 |   explicit Location(uintptr_t value) : value_(value) {} | 
 |  | 
 |   Location(Kind kind, uintptr_t payload) | 
 |       : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {} | 
 |  | 
 |   uintptr_t GetPayload() const { | 
 |     return PayloadField::Decode(value_); | 
 |   } | 
 |  | 
 |   typedef BitField<Kind, 0, kBitsForKind> KindField; | 
 |   typedef BitField<uintptr_t, kBitsForKind, kBitsForPayload> PayloadField; | 
 |  | 
 |   // Layout for kUnallocated locations payload. | 
 |   typedef BitField<Policy, 0, 3> PolicyField; | 
 |  | 
 |   // Layout for stack slots. | 
 |   static const intptr_t kStackIndexBias = | 
 |       static_cast<intptr_t>(1) << (kBitsForPayload - 1); | 
 |  | 
 |   // Location either contains kind and payload fields or a tagged handle for | 
 |   // a constant locations. Values of enumeration Kind are selected in such a | 
 |   // way that none of them can be interpreted as a kConstant tag. | 
 |   uintptr_t value_; | 
 | }; | 
 | std::ostream& operator<<(std::ostream& os, const Location::Kind& rhs); | 
 | std::ostream& operator<<(std::ostream& os, const Location::Policy& rhs); | 
 |  | 
 | class RegisterSet : public ValueObject { | 
 |  public: | 
 |   static RegisterSet Empty() { return RegisterSet(); } | 
 |   static RegisterSet AllFpu() { return RegisterSet(0, -1); } | 
 |  | 
 |   void Add(Location loc) { | 
 |     if (loc.IsRegister()) { | 
 |       core_registers_ |= (1 << loc.reg()); | 
 |     } else { | 
 |       DCHECK(loc.IsFpuRegister()); | 
 |       floating_point_registers_ |= (1 << loc.reg()); | 
 |     } | 
 |   } | 
 |  | 
 |   void Remove(Location loc) { | 
 |     if (loc.IsRegister()) { | 
 |       core_registers_ &= ~(1 << loc.reg()); | 
 |     } else { | 
 |       DCHECK(loc.IsFpuRegister()) << loc; | 
 |       floating_point_registers_ &= ~(1 << loc.reg()); | 
 |     } | 
 |   } | 
 |  | 
 |   bool ContainsCoreRegister(uint32_t id) const { | 
 |     return Contains(core_registers_, id); | 
 |   } | 
 |  | 
 |   bool ContainsFloatingPointRegister(uint32_t id) const { | 
 |     return Contains(floating_point_registers_, id); | 
 |   } | 
 |  | 
 |   static bool Contains(uint32_t register_set, uint32_t reg) { | 
 |     return (register_set & (1 << reg)) != 0; | 
 |   } | 
 |  | 
 |   size_t GetNumberOfRegisters() const { | 
 |     return POPCOUNT(core_registers_) + POPCOUNT(floating_point_registers_); | 
 |   } | 
 |  | 
 |   uint32_t GetCoreRegisters() const { | 
 |     return core_registers_; | 
 |   } | 
 |  | 
 |   uint32_t GetFloatingPointRegisters() const { | 
 |     return floating_point_registers_; | 
 |   } | 
 |  | 
 |  private: | 
 |   RegisterSet() : core_registers_(0), floating_point_registers_(0) {} | 
 |   RegisterSet(uint32_t core, uint32_t fp) : core_registers_(core), floating_point_registers_(fp) {} | 
 |  | 
 |   uint32_t core_registers_; | 
 |   uint32_t floating_point_registers_; | 
 | }; | 
 |  | 
 | static constexpr bool kIntrinsified = true; | 
 |  | 
 | /** | 
 |  * The code generator computes LocationSummary for each instruction so that | 
 |  * the instruction itself knows what code to generate: where to find the inputs | 
 |  * and where to place the result. | 
 |  * | 
 |  * The intent is to have the code for generating the instruction independent of | 
 |  * register allocation. A register allocator just has to provide a LocationSummary. | 
 |  */ | 
 | class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { | 
 |  public: | 
 |   enum CallKind { | 
 |     kNoCall, | 
 |     kCallOnMainAndSlowPath, | 
 |     kCallOnSlowPath, | 
 |     kCallOnMainOnly | 
 |   }; | 
 |  | 
 |   explicit LocationSummary(HInstruction* instruction, | 
 |                            CallKind call_kind = kNoCall, | 
 |                            bool intrinsified = false); | 
 |  | 
 |   void SetInAt(uint32_t at, Location location) { | 
 |     inputs_[at] = location; | 
 |   } | 
 |  | 
 |   Location InAt(uint32_t at) const { | 
 |     return inputs_[at]; | 
 |   } | 
 |  | 
 |   size_t GetInputCount() const { | 
 |     return inputs_.size(); | 
 |   } | 
 |  | 
 |   // Set the output location.  Argument `overlaps` tells whether the | 
 |   // output overlaps any of the inputs (if so, it cannot share the | 
 |   // same register as one of the inputs); it is set to | 
 |   // `Location::kOutputOverlap` by default for safety. | 
 |   void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) { | 
 |     DCHECK(output_.IsInvalid()); | 
 |     output_overlaps_ = overlaps; | 
 |     output_ = location; | 
 |   } | 
 |  | 
 |   void UpdateOut(Location location) { | 
 |     // There are two reasons for updating an output: | 
 |     // 1) Parameters, where we only know the exact stack slot after | 
 |     //    doing full register allocation. | 
 |     // 2) Unallocated location. | 
 |     DCHECK(output_.IsStackSlot() || output_.IsDoubleStackSlot() || output_.IsUnallocated()); | 
 |     output_ = location; | 
 |   } | 
 |  | 
 |   void AddTemp(Location location) { | 
 |     temps_.push_back(location); | 
 |   } | 
 |  | 
 |   void AddRegisterTemps(size_t count) { | 
 |     for (size_t i = 0; i < count; ++i) { | 
 |       AddTemp(Location::RequiresRegister()); | 
 |     } | 
 |   } | 
 |  | 
 |   Location GetTemp(uint32_t at) const { | 
 |     return temps_[at]; | 
 |   } | 
 |  | 
 |   void SetTempAt(uint32_t at, Location location) { | 
 |     DCHECK(temps_[at].IsUnallocated() || temps_[at].IsInvalid()); | 
 |     temps_[at] = location; | 
 |   } | 
 |  | 
 |   size_t GetTempCount() const { | 
 |     return temps_.size(); | 
 |   } | 
 |  | 
 |   bool HasTemps() const { return !temps_.empty(); } | 
 |  | 
 |   Location Out() const { return output_; } | 
 |  | 
 |   bool CanCall() const { | 
 |     return call_kind_ != kNoCall; | 
 |   } | 
 |  | 
 |   bool WillCall() const { | 
 |     return call_kind_ == kCallOnMainOnly || call_kind_ == kCallOnMainAndSlowPath; | 
 |   } | 
 |  | 
 |   bool CallsOnSlowPath() const { | 
 |     return call_kind_ == kCallOnSlowPath || call_kind_ == kCallOnMainAndSlowPath; | 
 |   } | 
 |  | 
 |   bool OnlyCallsOnSlowPath() const { | 
 |     return call_kind_ == kCallOnSlowPath; | 
 |   } | 
 |  | 
 |   bool CallsOnMainAndSlowPath() const { | 
 |     return call_kind_ == kCallOnMainAndSlowPath; | 
 |   } | 
 |  | 
 |   bool NeedsSafepoint() const { | 
 |     return CanCall(); | 
 |   } | 
 |  | 
 |   void SetCustomSlowPathCallerSaves(const RegisterSet& caller_saves) { | 
 |     DCHECK(OnlyCallsOnSlowPath()); | 
 |     has_custom_slow_path_calling_convention_ = true; | 
 |     custom_slow_path_caller_saves_ = caller_saves; | 
 |   } | 
 |  | 
 |   bool HasCustomSlowPathCallingConvention() const { | 
 |     return has_custom_slow_path_calling_convention_; | 
 |   } | 
 |  | 
 |   const RegisterSet& GetCustomSlowPathCallerSaves() const { | 
 |     DCHECK(HasCustomSlowPathCallingConvention()); | 
 |     return custom_slow_path_caller_saves_; | 
 |   } | 
 |  | 
 |   void SetStackBit(uint32_t index) { | 
 |     stack_mask_->SetBit(index); | 
 |   } | 
 |  | 
 |   void ClearStackBit(uint32_t index) { | 
 |     stack_mask_->ClearBit(index); | 
 |   } | 
 |  | 
 |   void SetRegisterBit(uint32_t reg_id) { | 
 |     register_mask_ |= (1 << reg_id); | 
 |   } | 
 |  | 
 |   uint32_t GetRegisterMask() const { | 
 |     return register_mask_; | 
 |   } | 
 |  | 
 |   bool RegisterContainsObject(uint32_t reg_id) { | 
 |     return RegisterSet::Contains(register_mask_, reg_id); | 
 |   } | 
 |  | 
 |   void AddLiveRegister(Location location) { | 
 |     live_registers_.Add(location); | 
 |   } | 
 |  | 
 |   BitVector* GetStackMask() const { | 
 |     return stack_mask_; | 
 |   } | 
 |  | 
 |   RegisterSet* GetLiveRegisters() { | 
 |     return &live_registers_; | 
 |   } | 
 |  | 
 |   size_t GetNumberOfLiveRegisters() const { | 
 |     return live_registers_.GetNumberOfRegisters(); | 
 |   } | 
 |  | 
 |   bool OutputUsesSameAs(uint32_t input_index) const { | 
 |     return (input_index == 0) | 
 |         && output_.IsUnallocated() | 
 |         && (output_.GetPolicy() == Location::kSameAsFirstInput); | 
 |   } | 
 |  | 
 |   bool IsFixedInput(uint32_t input_index) const { | 
 |     Location input = inputs_[input_index]; | 
 |     return input.IsRegister() | 
 |         || input.IsFpuRegister() | 
 |         || input.IsPair() | 
 |         || input.IsStackSlot() | 
 |         || input.IsDoubleStackSlot(); | 
 |   } | 
 |  | 
 |   bool OutputCanOverlapWithInputs() const { | 
 |     return output_overlaps_ == Location::kOutputOverlap; | 
 |   } | 
 |  | 
 |   bool Intrinsified() const { | 
 |     return intrinsified_; | 
 |   } | 
 |  | 
 |  private: | 
 |   LocationSummary(HInstruction* instruction, | 
 |                   CallKind call_kind, | 
 |                   bool intrinsified, | 
 |                   ArenaAllocator* allocator); | 
 |  | 
 |   ArenaVector<Location> inputs_; | 
 |   ArenaVector<Location> temps_; | 
 |   const CallKind call_kind_; | 
 |   // Whether these are locations for an intrinsified call. | 
 |   const bool intrinsified_; | 
 |   // Whether the slow path has default or custom calling convention. | 
 |   bool has_custom_slow_path_calling_convention_; | 
 |   // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot | 
 |   // share the same register as the inputs. | 
 |   Location::OutputOverlap output_overlaps_; | 
 |   Location output_; | 
 |  | 
 |   // Mask of objects that live in the stack. | 
 |   BitVector* stack_mask_; | 
 |  | 
 |   // Mask of objects that live in register. | 
 |   uint32_t register_mask_; | 
 |  | 
 |   // Registers that are in use at this position. | 
 |   RegisterSet live_registers_; | 
 |  | 
 |   // Custom slow path caller saves. Valid only if indicated by slow_path_calling_convention_. | 
 |   RegisterSet custom_slow_path_caller_saves_; | 
 |  | 
 |   friend class RegisterAllocatorTest; | 
 |   DISALLOW_COPY_AND_ASSIGN(LocationSummary); | 
 | }; | 
 |  | 
 | }  // namespace art | 
 |  | 
 | #endif  // ART_COMPILER_OPTIMIZING_LOCATIONS_H_ |