LLVM 22.0.0git
Interval.h
Go to the documentation of this file.
1//===- Interval.h -----------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The Interval class is a generic interval of ordered objects that implement:
10// - T * T::getPrevNode()
11// - T * T::getNextNode()
12// - bool T::comesBefore(const T *) const
13//
14// This is currently used for Instruction intervals.
15// It provides an API for some basic operations on the interval, including some
16// simple set operations, like union, intersection and others.
17//
18//===----------------------------------------------------------------------===//
19
20#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H
21#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H
22
23#include "llvm/ADT/ArrayRef.h"
27#include <iterator>
28#include <type_traits>
29
30namespace llvm::sandboxir {
31
32/// A simple iterator for iterating the interval.
33template <typename T, typename IntervalType> class IntervalIterator {
34 T *I;
35 IntervalType &R;
36
37public:
38 using difference_type = std::ptrdiff_t;
39 using value_type = T;
41 using reference = T &;
42 using iterator_category = std::bidirectional_iterator_tag;
43
44 IntervalIterator(T *I, IntervalType &R) : I(I), R(R) {}
45 bool operator==(const IntervalIterator &Other) const {
46 assert(&R == &Other.R && "Iterators belong to different regions!");
47 return Other.I == I;
48 }
49 bool operator!=(const IntervalIterator &Other) const {
50 return !(*this == Other);
51 }
53 assert(I != nullptr && "already at end()!");
54 I = I->getNextNode();
55 return *this;
56 }
58 auto ItCopy = *this;
59 ++*this;
60 return ItCopy;
61 }
63 // `I` is nullptr for end() when To is the BB terminator.
64 I = I != nullptr ? I->getPrevNode() : R.bottom();
65 return *this;
66 }
68 auto ItCopy = *this;
69 --*this;
70 return ItCopy;
71 }
72 template <typename HT = std::enable_if<std::is_same<T, T *&>::value>>
74 return *I;
75 }
76 T &operator*() const { return *I; }
77};
78
79template <typename T> class Interval {
80 T *Top;
81 T *Bottom;
82
83public:
84 Interval() : Top(nullptr), Bottom(nullptr) {}
85 Interval(T *Top, T *Bottom) : Top(Top), Bottom(Bottom) {
86 assert((Top == Bottom || Top->comesBefore(Bottom)) &&
87 "Top should come before Bottom!");
88 }
90 assert(!Elems.empty() && "Expected non-empty Elems!");
91 Top = Elems[0];
92 Bottom = Elems[0];
93 for (auto *I : drop_begin(Elems)) {
94 if (I->comesBefore(Top))
95 Top = I;
96 else if (Bottom->comesBefore(I))
97 Bottom = I;
98 }
99 }
100 bool empty() const {
101 assert(((Top == nullptr && Bottom == nullptr) ||
102 (Top != nullptr && Bottom != nullptr)) &&
103 "Either none or both should be null");
104 return Top == nullptr;
105 }
106 bool contains(T *I) const {
107 if (empty())
108 return false;
109 return (Top == I || Top->comesBefore(I)) &&
110 (I == Bottom || I->comesBefore(Bottom));
111 }
112 /// \Returns true if \p Elm is right before the top or right after the bottom.
113 bool touches(T *Elm) const {
114 return Top == Elm->getNextNode() || Bottom == Elm->getPrevNode();
115 }
116 T *top() const { return Top; }
117 T *bottom() const { return Bottom; }
118
120 iterator begin() { return iterator(Top, *this); }
122 return iterator(Bottom != nullptr ? Bottom->getNextNode() : nullptr, *this);
123 }
124 iterator begin() const {
125 return iterator(Top, const_cast<Interval &>(*this));
126 }
127 iterator end() const {
128 return iterator(Bottom != nullptr ? Bottom->getNextNode() : nullptr,
129 const_cast<Interval &>(*this));
130 }
131 /// Equality.
132 bool operator==(const Interval &Other) const {
133 return Top == Other.Top && Bottom == Other.Bottom;
134 }
135 /// Inequality.
136 bool operator!=(const Interval &Other) const { return !(*this == Other); }
137 /// \Returns true if this interval comes before \p Other in program order.
138 /// This expects disjoint intervals.
139 bool comesBefore(const Interval &Other) const {
140 assert(disjoint(Other) && "Expect disjoint intervals!");
141 return bottom()->comesBefore(Other.top());
142 }
143 /// \Returns true if this and \p Other have nothing in common.
144 bool disjoint(const Interval &Other) const;
145 /// \Returns the intersection between this and \p Other.
146 // Example:
147 // |----| this
148 // |---| Other
149 // |-| this->getIntersection(Other)
151 if (empty())
152 return *this;
153 if (Other.empty())
154 return Interval();
155 // 1. No overlap
156 // A---B this
157 // C--D Other
158 if (Bottom->comesBefore(Other.Top) || Other.Bottom->comesBefore(Top))
159 return Interval();
160 // 2. Overlap.
161 // A---B this
162 // C--D Other
163 auto NewTopI = Top->comesBefore(Other.Top) ? Other.Top : Top;
164 auto NewBottomI = Bottom->comesBefore(Other.Bottom) ? Bottom : Other.Bottom;
165 return Interval(NewTopI, NewBottomI);
166 }
167 /// Difference operation. This returns up to two intervals.
168 // Example:
169 // |--------| this
170 // |-| Other
171 // |-| |--| this - Other
173 if (disjoint(Other))
174 return {*this};
175 if (Other.empty())
176 return {*this};
177 if (*this == Other)
178 return {Interval()};
179 Interval Intersection = intersection(Other);
181 // Part 1, skip if empty.
182 if (Top != Intersection.Top)
183 Result.emplace_back(Top, Intersection.Top->getPrevNode());
184 // Part 2, skip if empty.
185 if (Intersection.Bottom != Bottom)
186 Result.emplace_back(Intersection.Bottom->getNextNode(), Bottom);
187 return Result;
188 }
189 /// \Returns the interval difference `this - Other`. This will crash in Debug
190 /// if the result is not a single interval.
192 auto Diff = *this - Other;
193 assert(Diff.size() == 1 && "Expected a single interval!");
194 return Diff[0];
195 }
196 /// \Returns a single interval that spans across both this and \p Other.
197 // For example:
198 // |---| this
199 // |---| Other
200 // |----------| this->getUnionInterval(Other)
202 if (empty())
203 return Other;
204 if (Other.empty())
205 return *this;
206 auto *NewTop = Top->comesBefore(Other.Top) ? Top : Other.Top;
207 auto *NewBottom = Bottom->comesBefore(Other.Bottom) ? Other.Bottom : Bottom;
208 return {NewTop, NewBottom};
209 }
210
211 /// Update the interval when \p I is about to be moved before \p Before.
212 // SFINAE disables this for non-Instructions.
213 template <typename HelperT = T>
214 std::enable_if_t<std::is_same<HelperT, Instruction>::value, void>
215 notifyMoveInstr(HelperT *I, decltype(I->getIterator()) BeforeIt) {
216 assert(contains(I) && "Expect `I` in interval!");
217 assert(I->getIterator() != BeforeIt && "Can't move `I` before itself!");
218
219 // Nothing to do if the instruction won't move.
220 if (std::next(I->getIterator()) == BeforeIt)
221 return;
222
223 T *NewTop = Top->getIterator() == BeforeIt ? I
224 : I == Top ? Top->getNextNode()
225 : Top;
226 T *NewBottom = std::next(Bottom->getIterator()) == BeforeIt ? I
227 : I == Bottom ? Bottom->getPrevNode()
228 : Bottom;
229 Top = NewTop;
230 Bottom = NewBottom;
231 }
232
233#ifndef NDEBUG
234 void print(raw_ostream &OS) const;
235 LLVM_DUMP_METHOD void dump() const;
236#endif
237};
238
239// Defined in Transforms/Vectorize/SandboxVectorizer/Interval.cpp
240extern template class LLVM_TEMPLATE_ABI Interval<Instruction>;
241
242} // namespace llvm::sandboxir
243
244#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_TEMPLATE_ABI
Definition: Compiler.h:214
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:638
#define I(x, y, z)
Definition: MD5.cpp:58
std::pair< uint64_t, uint64_t > Interval
#define T
raw_pwrite_stream & OS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:142
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
A simple iterator for iterating the interval.
Definition: Interval.h:33
bool operator!=(const IntervalIterator &Other) const
Definition: Interval.h:49
IntervalIterator & operator--()
Definition: Interval.h:62
IntervalIterator(T *I, IntervalType &R)
Definition: Interval.h:44
std::bidirectional_iterator_tag iterator_category
Definition: Interval.h:42
bool operator==(const IntervalIterator &Other) const
Definition: Interval.h:45
IntervalIterator operator++(int)
Definition: Interval.h:57
std::ptrdiff_t difference_type
Definition: Interval.h:38
IntervalIterator & operator++()
Definition: Interval.h:52
IntervalIterator operator--(int)
Definition: Interval.h:67
Interval(T *Top, T *Bottom)
Definition: Interval.h:85
SmallVector< Interval, 2 > operator-(const Interval &Other)
Difference operation. This returns up to two intervals.
Definition: Interval.h:172
bool operator==(const Interval &Other) const
Equality.
Definition: Interval.h:132
bool touches(T *Elm) const
\Returns true if Elm is right before the top or right after the bottom.
Definition: Interval.h:113
Interval getUnionInterval(const Interval &Other)
\Returns a single interval that spans across both this and Other.
Definition: Interval.h:201
LLVM_DUMP_METHOD void dump() const
Definition: Interval.cpp:43
bool contains(T *I) const
Definition: Interval.h:106
Interval getSingleDiff(const Interval &Other)
\Returns the interval difference this - Other.
Definition: Interval.h:191
bool operator!=(const Interval &Other) const
Inequality.
Definition: Interval.h:136
Interval(ArrayRef< T * > Elems)
Definition: Interval.h:89
IntervalIterator< T, Interval > iterator
Definition: Interval.h:119
iterator end() const
Definition: Interval.h:127
bool disjoint(const Interval &Other) const
\Returns true if this and Other have nothing in common.
Definition: Interval.cpp:17
bool comesBefore(const Interval &Other) const
\Returns true if this interval comes before Other in program order.
Definition: Interval.h:139
void print(raw_ostream &OS) const
Definition: Interval.cpp:26
iterator begin() const
Definition: Interval.h:124
Interval intersection(const Interval &Other) const
\Returns the intersection between this and Other.
Definition: Interval.h:150
std::enable_if_t< std::is_same< HelperT, Instruction >::value, void > notifyMoveInstr(HelperT *I, decltype(I->getIterator()) BeforeIt)
Update the interval when I is about to be moved before Before.
Definition: Interval.h:215
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:338
@ Other
Any other memory.