LLVM 20.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"
26#include <iterator>
27#include <type_traits>
28
29namespace llvm::sandboxir {
30
31/// A simple iterator for iterating the interval.
32template <typename T, typename IntervalType> class IntervalIterator {
33 T *I;
34 IntervalType &R;
35
36public:
37 using difference_type = std::ptrdiff_t;
38 using value_type = T;
40 using reference = T &;
41 using iterator_category = std::bidirectional_iterator_tag;
42
43 IntervalIterator(T *I, IntervalType &R) : I(I), R(R) {}
44 bool operator==(const IntervalIterator &Other) const {
45 assert(&R == &Other.R && "Iterators belong to different regions!");
46 return Other.I == I;
47 }
48 bool operator!=(const IntervalIterator &Other) const {
49 return !(*this == Other);
50 }
52 assert(I != nullptr && "already at end()!");
53 I = I->getNextNode();
54 return *this;
55 }
57 auto ItCopy = *this;
58 ++*this;
59 return ItCopy;
60 }
62 // `I` is nullptr for end() when To is the BB terminator.
63 I = I != nullptr ? I->getPrevNode() : R.bottom();
64 return *this;
65 }
67 auto ItCopy = *this;
68 --*this;
69 return ItCopy;
70 }
71 template <typename HT = std::enable_if<std::is_same<T, T *&>::value>>
73 return *I;
74 }
75 T &operator*() const { return *I; }
76};
77
78template <typename T> class Interval {
79 T *Top;
80 T *Bottom;
81
82public:
83 Interval() : Top(nullptr), Bottom(nullptr) {}
84 Interval(T *Top, T *Bottom) : Top(Top), Bottom(Bottom) {
85 assert((Top == Bottom || Top->comesBefore(Bottom)) &&
86 "Top should come before Bottom!");
87 }
89 assert(!Elems.empty() && "Expected non-empty Elems!");
90 Top = Elems[0];
91 Bottom = Elems[0];
92 for (auto *I : drop_begin(Elems)) {
93 if (I->comesBefore(Top))
94 Top = I;
95 else if (Bottom->comesBefore(I))
96 Bottom = I;
97 }
98 }
99 bool empty() const {
100 assert(((Top == nullptr && Bottom == nullptr) ||
101 (Top != nullptr && Bottom != nullptr)) &&
102 "Either none or both should be null");
103 return Top == nullptr;
104 }
105 bool contains(T *I) const {
106 if (empty())
107 return false;
108 return (Top == I || Top->comesBefore(I)) &&
109 (I == Bottom || I->comesBefore(Bottom));
110 }
111 T *top() const { return Top; }
112 T *bottom() const { return Bottom; }
113
115 iterator begin() { return iterator(Top, *this); }
117 return iterator(Bottom != nullptr ? Bottom->getNextNode() : nullptr, *this);
118 }
119 iterator begin() const {
120 return iterator(Top, const_cast<Interval &>(*this));
121 }
122 iterator end() const {
123 return iterator(Bottom != nullptr ? Bottom->getNextNode() : nullptr,
124 const_cast<Interval &>(*this));
125 }
126 /// Equality.
127 bool operator==(const Interval &Other) const {
128 return Top == Other.Top && Bottom == Other.Bottom;
129 }
130 /// Inequality.
131 bool operator!=(const Interval &Other) const { return !(*this == Other); }
132 /// \Returns true if this interval comes before \p Other in program order.
133 /// This expects disjoint intervals.
134 bool comesBefore(const Interval &Other) const {
135 assert(disjoint(Other) && "Expect disjoint intervals!");
136 return bottom()->comesBefore(Other.top());
137 }
138 /// \Returns true if this and \p Other have nothing in common.
139 bool disjoint(const Interval &Other) const {
140 if (Other.empty())
141 return true;
142 if (empty())
143 return true;
144 return Other.Bottom->comesBefore(Top) || Bottom->comesBefore(Other.Top);
145 }
146 /// \Returns the intersection between this and \p Other.
147 // Example:
148 // |----| this
149 // |---| Other
150 // |-| this->getIntersection(Other)
152 if (empty())
153 return *this;
154 if (Other.empty())
155 return Interval();
156 // 1. No overlap
157 // A---B this
158 // C--D Other
159 if (Bottom->comesBefore(Other.Top) || Other.Bottom->comesBefore(Top))
160 return Interval();
161 // 2. Overlap.
162 // A---B this
163 // C--D Other
164 auto NewTopI = Top->comesBefore(Other.Top) ? Other.Top : Top;
165 auto NewBottomI = Bottom->comesBefore(Other.Bottom) ? Bottom : Other.Bottom;
166 return Interval(NewTopI, NewBottomI);
167 }
168 /// Difference operation. This returns up to two intervals.
169 // Example:
170 // |--------| this
171 // |-| Other
172 // |-| |--| this - Other
174 if (disjoint(Other))
175 return {*this};
176 if (Other.empty())
177 return {*this};
178 if (*this == Other)
179 return {Interval()};
180 Interval Intersection = intersection(Other);
182 // Part 1, skip if empty.
183 if (Top != Intersection.Top)
184 Result.emplace_back(Top, Intersection.Top->getPrevNode());
185 // Part 2, skip if empty.
186 if (Intersection.Bottom != Bottom)
187 Result.emplace_back(Intersection.Bottom->getNextNode(), Bottom);
188 return Result;
189 }
190 /// \Returns the interval difference `this - Other`. This will crash in Debug
191 /// if the result is not a single interval.
193 auto Diff = *this - Other;
194 assert(Diff.size() == 1 && "Expected a single interval!");
195 return Diff[0];
196 }
197 /// \Returns a single interval that spans across both this and \p Other.
198 // For example:
199 // |---| this
200 // |---| Other
201 // |----------| this->getUnionInterval(Other)
203 if (empty())
204 return Other;
205 if (Other.empty())
206 return *this;
207 auto *NewTop = Top->comesBefore(Other.Top) ? Top : Other.Top;
208 auto *NewBottom = Bottom->comesBefore(Other.Bottom) ? Other.Bottom : Bottom;
209 return {NewTop, NewBottom};
210 }
211
212 /// Update the interval when \p I is about to be moved before \p Before.
213 // SFINAE disables this for non-Instructions.
214 template <typename HelperT = T>
215 std::enable_if_t<std::is_same<HelperT, Instruction>::value, void>
216 notifyMoveInstr(HelperT *I, decltype(I->getIterator()) BeforeIt) {
217 assert(contains(I) && "Expect `I` in interval!");
218 assert(I->getIterator() != BeforeIt && "Can't move `I` before itself!");
219
220 // Nothing to do if the instruction won't move.
221 if (std::next(I->getIterator()) == BeforeIt)
222 return;
223
224 T *NewTop = Top->getIterator() == BeforeIt ? I
225 : I == Top ? Top->getNextNode()
226 : Top;
227 T *NewBottom = std::next(Bottom->getIterator()) == BeforeIt ? I
228 : I == Bottom ? Bottom->getPrevNode()
229 : Bottom;
230 Top = NewTop;
231 Bottom = NewBottom;
232 }
233
234#ifndef NDEBUG
235 void print(raw_ostream &OS) const {
236 auto *Top = top();
237 auto *Bot = bottom();
238 OS << "Top: ";
239 if (Top != nullptr)
240 OS << *Top;
241 else
242 OS << "nullptr";
243 OS << "\n";
244
245 OS << "Bot: ";
246 if (Bot != nullptr)
247 OS << *Bot;
248 else
249 OS << "nullptr";
250 OS << "\n";
251 }
252 LLVM_DUMP_METHOD void dump() const;
253#endif
254};
255
256} // namespace llvm::sandboxir
257
258#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:622
#define I(x, y, z)
Definition: MD5.cpp:58
#define T
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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:163
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A simple iterator for iterating the interval.
Definition: Interval.h:32
bool operator!=(const IntervalIterator &Other) const
Definition: Interval.h:48
IntervalIterator & operator--()
Definition: Interval.h:61
IntervalIterator(T *I, IntervalType &R)
Definition: Interval.h:43
std::bidirectional_iterator_tag iterator_category
Definition: Interval.h:41
bool operator==(const IntervalIterator &Other) const
Definition: Interval.h:44
IntervalIterator operator++(int)
Definition: Interval.h:56
std::ptrdiff_t difference_type
Definition: Interval.h:37
IntervalIterator & operator++()
Definition: Interval.h:51
IntervalIterator operator--(int)
Definition: Interval.h:66
Interval(T *Top, T *Bottom)
Definition: Interval.h:84
SmallVector< Interval, 2 > operator-(const Interval &Other)
Difference operation. This returns up to two intervals.
Definition: Interval.h:173
bool operator==(const Interval &Other) const
Equality.
Definition: Interval.h:127
Interval getUnionInterval(const Interval &Other)
\Returns a single interval that spans across both this and Other.
Definition: Interval.h:202
LLVM_DUMP_METHOD void dump() const
Definition: Interval.cpp:20
bool contains(T *I) const
Definition: Interval.h:105
Interval getSingleDiff(const Interval &Other)
\Returns the interval difference this - Other.
Definition: Interval.h:192
bool operator!=(const Interval &Other) const
Inequality.
Definition: Interval.h:131
Interval(ArrayRef< T * > Elems)
Definition: Interval.h:88
IntervalIterator< T, Interval > iterator
Definition: Interval.h:114
iterator end() const
Definition: Interval.h:122
bool empty() const
Definition: Interval.h:99
bool disjoint(const Interval &Other) const
\Returns true if this and Other have nothing in common.
Definition: Interval.h:139
bool comesBefore(const Interval &Other) const
\Returns true if this interval comes before Other in program order.
Definition: Interval.h:134
void print(raw_ostream &OS) const
Definition: Interval.h:235
iterator begin() const
Definition: Interval.h:119
Interval intersection(const Interval &Other) const
\Returns the intersection between this and Other.
Definition: Interval.h:151
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:216
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:329
@ Other
Any other memory.