diff options
Diffstat (limited to 'compiler/optimizing/locations.h')
| -rw-r--r-- | compiler/optimizing/locations.h | 127 |
1 files changed, 98 insertions, 29 deletions
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index 63bbc2cd0a..6f0dbce2df 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -20,6 +20,7 @@ #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" @@ -38,7 +39,13 @@ std::ostream& operator<<(std::ostream& os, const Location& location); 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 }; @@ -62,11 +69,13 @@ class Location : public ValueObject { // 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 = 10, + kUnallocated = 11, }; Location() : ValueObject(), value_(kInvalid) { @@ -75,6 +84,7 @@ class Location : public ValueObject { 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"); @@ -84,12 +94,9 @@ class Location : public ValueObject { DCHECK(!IsValid()); } - Location(const Location& other) : value_(other.value_) {} + Location(const Location& other) = default; - Location& operator=(const Location& other) { - value_ = other.value_; - return *this; - } + Location& operator=(const Location& other) = default; bool IsConstant() const { return (value_ & kLocationConstantMask) == kConstant; @@ -262,8 +269,20 @@ class Location : public ValueObject { 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()); + DCHECK(IsStackSlot() || IsDoubleStackSlot() || IsSIMDStackSlot()); // Decode stack index manually to preserve sign. return GetPayload() - kStackIndexBias; } @@ -311,6 +330,7 @@ class Location : public ValueObject { 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"; @@ -321,7 +341,6 @@ class Location : public ValueObject { LOG(FATAL) << "Should not use this location kind"; } UNREACHABLE(); - return "?"; } // Unallocated locations. @@ -370,6 +389,10 @@ class Location : public ValueObject { return PolicyField::Decode(GetPayload()); } + bool RequiresRegisterKind() const { + return GetPolicy() == kRequiresRegister || GetPolicy() == kRequiresFpuRegister; + } + uintptr_t GetEncoding() const { return GetPayload(); } @@ -409,7 +432,8 @@ std::ostream& operator<<(std::ostream& os, const Location::Policy& rhs); class RegisterSet : public ValueObject { public: - RegisterSet() : core_registers_(0), floating_point_registers_(0) {} + static RegisterSet Empty() { return RegisterSet(); } + static RegisterSet AllFpu() { return RegisterSet(0, -1); } void Add(Location loc) { if (loc.IsRegister()) { @@ -442,7 +466,7 @@ class RegisterSet : public ValueObject { } size_t GetNumberOfRegisters() const { - return __builtin_popcount(core_registers_) + __builtin_popcount(floating_point_registers_); + return POPCOUNT(core_registers_) + POPCOUNT(floating_point_registers_); } uint32_t GetCoreRegisters() const { @@ -454,10 +478,11 @@ class RegisterSet : public ValueObject { } 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_; - - DISALLOW_COPY_AND_ASSIGN(RegisterSet); }; static constexpr bool kIntrinsified = true; @@ -474,13 +499,14 @@ class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { public: enum CallKind { kNoCall, + kCallOnMainAndSlowPath, kCallOnSlowPath, - kCall + kCallOnMainOnly }; - LocationSummary(HInstruction* instruction, - CallKind call_kind = kNoCall, - bool intrinsified = false); + explicit LocationSummary(HInstruction* instruction, + CallKind call_kind = kNoCall, + bool intrinsified = false); void SetInAt(uint32_t at, Location location) { inputs_[at] = location; @@ -494,6 +520,10 @@ class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { 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; @@ -513,6 +543,12 @@ class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { 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]; } @@ -530,10 +566,44 @@ class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { Location Out() const { return output_; } - bool CanCall() const { return call_kind_ != kNoCall; } - bool WillCall() const { return call_kind_ == kCall; } - bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; } - bool NeedsSafepoint() const { return CanCall(); } + 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); @@ -594,18 +664,18 @@ class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { return intrinsified_; } - void SetIntrinsified(bool intrinsified) { - intrinsified_ = intrinsified; - } - private: 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_; - const CallKind call_kind_; // Mask of objects that live in the stack. BitVector* stack_mask_; @@ -616,11 +686,10 @@ class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { // Registers that are in use at this position. RegisterSet live_registers_; - // Whether these are locations for an intrinsified call. - bool intrinsified_; + // Custom slow path caller saves. Valid only if indicated by slow_path_calling_convention_. + RegisterSet custom_slow_path_caller_saves_; - ART_FRIEND_TEST(RegisterAllocatorTest, ExpectedInRegisterHint); - ART_FRIEND_TEST(RegisterAllocatorTest, SameAsFirstInputHint); + friend class RegisterAllocatorTest; DISALLOW_COPY_AND_ASSIGN(LocationSummary); }; |