Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(514)

Unified Diff: src/compiler/register-allocator.h

Issue 1157663007: Greedy allocator: perf work (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | src/compiler/register-allocator.cc » ('j') | src/compiler/register-allocator.cc » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/register-allocator.h
diff --git a/src/compiler/register-allocator.h b/src/compiler/register-allocator.h
index baffedd919292c93e68b263793f3424c30aa0aaa..6479ef75f3a1c51b59cd5ee393ea16c58be1d36a 100644
--- a/src/compiler/register-allocator.h
+++ b/src/compiler/register-allocator.h
@@ -251,6 +251,7 @@ class UsePosition final : public ZoneObject {
return hint_type() != UsePositionHintType::kUnresolved;
}
static UsePositionHintType HintTypeForOperand(const InstructionOperand& op);
+ void dump_hint(std::ostream& os, const RegisterConfiguration* config);
private:
typedef BitField<UsePositionType, 0, 2> TypeField;
@@ -269,6 +270,7 @@ class UsePosition final : public ZoneObject {
class SpillRange;
+class LiveRangeGroup;
// Representation of SSA values' live ranges as a collection of (continuous)
@@ -341,7 +343,10 @@ class LiveRange final : public ZoneObject {
LifetimePosition start) const;
// Can this live range be spilled at this position.
- bool CanBeSpilled(LifetimePosition pos) const;
+ bool CanBeSpilled(LifetimePosition pos) const { return CanBeSplit(pos); }
+
+ // Can this live range be split at this position.
+ bool CanBeSplit(LifetimePosition pos) const;
// Split this live range at the given position which must follow the start of
// the range.
@@ -428,7 +433,36 @@ class LiveRange final : public ZoneObject {
return spills_at_definition_;
}
+ LiveRangeGroup* group() const { return group_; }
+ void SetGroup(LiveRangeGroup* grp) { group_ = grp; }
+
+ float GetWeight() const {
+ DCHECK(weight_ >= 0.0f);
+ return weight_;
+ }
+
+ unsigned GetSize() {
+ if (size_ < 0) RecalculateSize();
+ DCHECK(size_ > 0);
+ return static_cast<unsigned>(size_);
+ }
+
+ void InvalidateWeightAndSize() {
+ weight_ = kInvalidWeight;
+ size_ = kInvalidSize;
+ }
+ void RecalculateWeight(InstructionSequence* code);
+ LifetimePosition GetFirstSplittablePosition();
+
+ static const float kMaxWeight;
+
private:
+ static const float kUseInLoopWeightMultiplier;
+ static const float kPreferredRegisterWeightMultiplier;
+ static const float kInvalidWeight;
+ static const int kInvalidSize = -1;
+
+ void RecalculateSize();
void set_spill_type(SpillType value) {
bits_ = SpillTypeField::update(bits_, value);
}
@@ -468,10 +502,27 @@ class LiveRange final : public ZoneObject {
// This is used as a cache, it's invalid outside of BuildLiveRanges.
mutable UsePosition* current_hint_position_;
+ // Used only by the greedy allocator.
+ float weight_;
+ int size_;
+ LiveRangeGroup* group_;
DISALLOW_COPY_AND_ASSIGN(LiveRange);
};
+class LiveRangeGroup final : public ZoneObject {
+ public:
+ explicit LiveRangeGroup(Zone* zone) : ranges_(zone) {}
+ ZoneSet<LiveRange*>& ranges() { return ranges_; }
+ bool CanAdd(LiveRange* r);
+ void TryMerge(LiveRangeGroup* other);
+
+ private:
+ ZoneSet<LiveRange*> ranges_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiveRangeGroup);
+};
+
struct PrintableLiveRange {
const RegisterConfiguration* register_configuration_;
const LiveRange* range_;
@@ -497,6 +548,7 @@ class SpillRange final : public ZoneObject {
DCHECK_EQ(kUnassignedSlot, assigned_slot_);
assigned_slot_ = index;
}
+ bool IsSlotAssigned() const { return assigned_slot_ != kUnassignedSlot; }
int assigned_slot() {
DCHECK_NE(kUnassignedSlot, assigned_slot_);
return assigned_slot_;
@@ -518,6 +570,9 @@ class SpillRange final : public ZoneObject {
};
+std::ostream& operator<<(std::ostream& os, SpillRange* range);
+
+
class RegisterAllocationData final : public ZoneObject {
public:
class PhiMapValue : public ZoneObject {
@@ -728,12 +783,33 @@ class LiveRangeBuilder final : public ZoneObject {
DISALLOW_COPY_AND_ASSIGN(LiveRangeBuilder);
};
+struct AllocatorStats {
+ unsigned spills;
+ unsigned wins;
+ unsigned losses_no_eviction;
+ unsigned losses_after_eviction;
+ unsigned good_split_attempts;
+ unsigned good_split_successes;
+ unsigned good_split_smart_above;
+ unsigned good_split_smart_below;
+ unsigned good_split_above;
+ unsigned good_split_below;
+ unsigned groups_attempted;
+ unsigned groups_succeeded;
+ unsigned groups_allocated;
+ void reset() { *this = {0}; }
+};
+
+
+std::ostream& operator<<(std::ostream& os, const AllocatorStats& stats);
+
class RegisterAllocator : public ZoneObject {
public:
explicit RegisterAllocator(RegisterAllocationData* data, RegisterKind kind);
protected:
+ AllocatorStats stats_;
RegisterAllocationData* data() const { return data_; }
InstructionSequence* code() const { return data()->code(); }
RegisterKind mode() const { return mode_; }
@@ -767,6 +843,7 @@ class RegisterAllocator : public ZoneObject {
// hoist spill position out to the point just before the loop.
LifetimePosition FindOptimalSpillingPos(LiveRange* range,
LifetimePosition pos);
+ const char* RegisterName(int allocation_index) const;
private:
RegisterAllocationData* const data_;
@@ -786,8 +863,6 @@ class LinearScanAllocator final : public RegisterAllocator {
void AllocateRegisters();
private:
- const char* RegisterName(int allocation_index) const;
-
ZoneVector<LiveRange*>& unhandled_live_ranges() {
return unhandled_live_ranges_;
}
@@ -840,9 +915,104 @@ class LinearScanAllocator final : public RegisterAllocator {
DISALLOW_COPY_AND_ASSIGN(LinearScanAllocator);
};
+
+// Storage detail for CoalescedLiveRanges.
+struct AllocatedInterval {
+ LifetimePosition start;
+ LifetimePosition end;
+ LiveRange* range;
+ struct Comparer : public std::binary_function<AllocatedInterval,
+ AllocatedInterval, bool> {
+ bool operator()(const AllocatedInterval& x,
+ const AllocatedInterval& y) const {
+ return x.start < y.start;
+ }
+ };
+};
+
+
class CoalescedLiveRanges;
+// Iterator over allocated live ranges (CoalescedLiveRanges) that conflict with
+// a given one. See CoalescedLiveRanges::first_conflict.
+// Note that iterating may produce non-consecutively repeating live ranges.
+struct conflict_iterator {
+ conflict_iterator() : storage_(nullptr) {}
Jarin 2015/06/12 04:09:12 Initialize all fields here.
+ const LiveRange* operator->() const { return pos_->range; }
+
+ LiveRange* operator*() const { return pos_->range; }
+
+ conflict_iterator& operator++();
+ bool IsEnd() const {
+ DCHECK(storage_ != nullptr);
+ return pos_ == storage_->end();
+ }
+
+ private:
+ friend class CoalescedLiveRanges;
+ friend bool operator==(const conflict_iterator& first,
+ const conflict_iterator& second);
+
+ typedef ZoneSet<AllocatedInterval, AllocatedInterval::Comparer> IntervalStore;
+ typedef IntervalStore::const_iterator interval_iterator;
+
+ void Invalidate() {
+ DCHECK(storage_ != nullptr);
+ pos_ = storage_->end();
+ query_ = nullptr;
+ }
+
+ static bool Intersects(LifetimePosition a_start, LifetimePosition a_end,
+ LifetimePosition b_start, LifetimePosition b_end) {
+ if (a_start == b_start) return true;
+ if (a_start < b_start) return a_end > b_start;
Jarin 2015/06/12 04:09:12 Out of curiosity, cannot you just leave out the "i
Sven Panne 2015/06/12 07:36:37 Hmmm, this looks still too complicated, normally j
+ return Intersects(b_start, b_end, a_start, a_end);
+ }
+
+ bool QueryIntersectsAllocatedInterval() {
+ DCHECK(query_ != nullptr);
+ return Intersects(query_->start(), query_->end(), pos_->start, pos_->end);
+ }
+
+ bool NextQueryIntersectsAllocatedInterval() {
+ DCHECK(query_->next() != nullptr);
+ return Intersects(query_->next()->start(), query_->next()->end(),
+ pos_->start, pos_->end);
+ }
+
+ conflict_iterator(UseInterval* query, IntervalStore* storage)
+ : query_(query), storage_(storage) {
+ InitializeForNewQuery();
+ }
+
+ explicit conflict_iterator(IntervalStore* storage) : storage_(storage) {
+ Invalidate();
+ }
+
+ static conflict_iterator EndIteratorForStorage(IntervalStore* storage) {
+ conflict_iterator ret(storage);
+ return ret;
+ }
+
+ void InitializeForNewQuery();
+ void SkipMatchedQueries();
+
+ AllocatedInterval AsAllocatedInterval(LifetimePosition pos) {
+ return {pos, LifetimePosition::Invalid(), nullptr};
+ }
+
+ UseInterval* query_;
+ IntervalStore* storage_;
+ interval_iterator pos_;
+};
+
+bool operator==(const conflict_iterator& first,
+ const conflict_iterator& second);
+bool operator!=(const conflict_iterator& first,
+ const conflict_iterator& second);
+
+
// A variant of the LLVM Greedy Register Allocator. See
// http://blog.llvm.org/2011/09/greedy-register-allocation-in-llvm-30.html
class GreedyAllocator final : public RegisterAllocator {
@@ -853,36 +1023,86 @@ class GreedyAllocator final : public RegisterAllocator {
void AllocateRegisters();
private:
- LifetimePosition GetSplittablePos(LifetimePosition pos);
+ void AllocateRange(LiveRange* current);
+ void AllocateGroup(LiveRangeGroup* grp);
+ bool TryAllocateGroup(LiveRangeGroup* grp);
+ bool TryAllocateGroupAtRegister(unsigned reg, LiveRangeGroup* grp);
+
+ struct PQueueElem {
Jarin 2015/06/12 04:09:12 PQueueElem -> QueueElement (or PriorityQueueElemen
+ bool IsGroup() { return is_grp_; }
+ explicit PQueueElem(LiveRange* range) : is_grp_(false) {
+ storage_.range_ = range;
+ }
+
+ explicit PQueueElem(LiveRangeGroup* grp) : is_grp_(true) {
+ storage_.grp_ = grp;
+ }
+
+
+ LiveRange* get_range() {
+ if (is_grp_) return nullptr;
Jarin 2015/06/12 04:09:12 The callers should (and do) always consult IsGroup
+ return storage_.range_;
+ }
+
+
+ LiveRangeGroup* get_group() {
+ if (is_grp_) return storage_.grp_;
Jarin 2015/06/12 04:09:12 Similarly, "DCHECK(IsGroup()); return storage_.grp
+ return nullptr;
+ }
+
+ private:
+ bool is_grp_;
+ union {
+ LiveRange* range_;
+ LiveRangeGroup* grp_;
+ } storage_;
+ };
+
+ void GroupAndEnqueue();
Jarin 2015/06/12 04:09:12 GroupAndEnqueue -> EnqueuePhiGroups?
const RegisterConfiguration* config() const { return data()->config(); }
Zone* local_zone() const { return local_zone_; }
- bool TryReuseSpillForPhi(LiveRange* range);
- int GetHintedRegister(LiveRange* range);
- typedef ZonePriorityQueue<std::pair<unsigned, LiveRange*>> PQueue;
+ struct PQueueElemComparer
+ : public std::binary_function<std::pair<unsigned, PQueueElem>,
+ std::pair<unsigned, PQueueElem>, bool> {
+ bool operator()(const std::pair<unsigned, PQueueElem>& x,
+ const std::pair<unsigned, PQueueElem>& y) const {
+ return x.first < y.first;
+ }
+ };
+
+ typedef ZonePriorityQueue<std::pair<unsigned, PQueueElem>, PQueueElemComparer>
+ PQueue;
Jarin 2015/06/12 04:09:12 PQueue -> PriorityQueue
- unsigned GetLiveRangeSize(LiveRange* range);
void Enqueue(LiveRange* range);
+ void Enqueue(LiveRangeGroup* group);
void Evict(LiveRange* range);
- float CalculateSpillWeight(LiveRange* range);
- float CalculateMaxSpillWeight(const ZoneSet<LiveRange*>& ranges);
+ void EvictAll(int reg, const conflict_iterator& first_conflict);
+
+ // Find the register with the minimum spill weight. If that is still higher
+ // or equal to competing, return -1.
+ int FindRegisterToEvictForRange(
+ conflict_iterator
+ all_conflicts[RegisterConfiguration::kMaxDoubleRegisters],
+ float competing);
+ // Same as above, for all the registers in a group.
+ int FindRegisterToEvictForGroup(LiveRangeGroup* grp, float competing);
- bool TryAllocate(LiveRange* current, ZoneSet<LiveRange*>* conflicting);
- bool TryAllocatePhysicalRegister(unsigned reg_id, LiveRange* range,
- ZoneSet<LiveRange*>* conflicting);
- bool HandleSpillOperands(LiveRange* range);
- void AllocateBlockedRange(LiveRange* current, LifetimePosition pos,
- bool spill);
+ template <typename TIter>
+ float CalculateMaxSpillWeight(const TIter& begin, const TIter& end);
Jarin 2015/06/12 04:09:12 Static?
+
+ bool HandleSpillOperands(LiveRange* range, LiveRange** remaining);
+ void HandleBlockedRange(LiveRange* current);
+ bool TrySplitBeforeLoops(LiveRange* current);
+ bool TrySplitAfterLoops(LiveRange* current);
+ bool TrySplitAroundCalls(LiveRange* range);
LiveRange* SpillBetweenUntil(LiveRange* range, LifetimePosition start,
LifetimePosition until, LifetimePosition end);
void AssignRangeToRegister(int reg_id, LiveRange* range);
- LifetimePosition FindProgressingSplitPosition(LiveRange* range,
- bool* is_spill_pos);
-
Zone* local_zone_;
ZoneVector<CoalescedLiveRanges*> allocations_;
PQueue queue_;
« no previous file with comments | « no previous file | src/compiler/register-allocator.cc » ('j') | src/compiler/register-allocator.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698