Jlm
Loading...
Searching...
No Matches
Worklist.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2024 HÃ¥vard Krogstie <krogstie.havard@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5#ifndef JLM_UTIL_WORKLIST_HPP
6#define JLM_UTIL_WORKLIST_HPP
7
8#include <jlm/util/common.hpp>
10
11#include <algorithm>
12#include <limits>
13#include <queue>
14#include <stack>
15#include <unordered_map>
16#include <vector>
17
18namespace jlm::util
19{
20
26template<typename T>
28{
29public:
30 virtual ~Worklist() = default;
31
32 Worklist() = default;
33
34 Worklist(const Worklist & other) = delete;
35
36 Worklist(Worklist && other) = default;
37
38 Worklist &
39 operator=(const Worklist & other) = delete;
40
41 Worklist &
42 operator=(Worklist && other) = default;
43
47 [[nodiscard]] virtual bool
48 HasMoreWorkItems() const noexcept = 0;
49
55 [[nodiscard]] virtual T
57
63 virtual void
64 PushWorkItem(T item) = 0;
65};
66
73template<typename T>
74class LifoWorklist final : public Worklist<T>
75{
76public:
77 ~LifoWorklist() override = default;
78
79 LifoWorklist() = default;
80
81 [[nodiscard]] bool
82 HasMoreWorkItems() const noexcept override
83 {
84 return !WorkItems_.empty();
85 }
86
87 T
88 PopWorkItem() override
89 {
91 T item = WorkItems_.top();
92 WorkItems_.pop();
93 OnList_.Remove(item);
94 return item;
95 }
96
97 void
98 PushWorkItem(T item) override
99 {
100 if (OnList_.insert(item))
101 WorkItems_.push(item);
102 }
103
104private:
105 // Tracking which work items are already on the list
107
108 // The stack used to order the work items
109 std::stack<T> WorkItems_;
110};
111
118template<typename T>
119class FifoWorklist final : public Worklist<T>
120{
121public:
122 ~FifoWorklist() override = default;
123
124 FifoWorklist() = default;
125
126 [[nodiscard]] bool
127 HasMoreWorkItems() const noexcept override
128 {
129 return !WorkItems_.empty();
130 }
131
132 T
133 PopWorkItem() override
134 {
135 JLM_ASSERT(HasMoreWorkItems());
136 T item = WorkItems_.front();
137 WorkItems_.pop();
138 OnList_.Remove(item);
139 return item;
140 }
141
142 void
143 PushWorkItem(T item) override
144 {
145 if (OnList_.insert(item))
146 WorkItems_.push(item);
147 }
148
149private:
150 // Tracking which work items are already on the list
152
153 // The queue used to order the items
154 std::queue<T> WorkItems_;
155};
156
168template<typename T>
169class LrfWorklist final : public Worklist<T>
170{
171public:
172 ~LrfWorklist() override = default;
173
174 LrfWorklist() = default;
175
176 [[nodiscard]] bool
177 HasMoreWorkItems() const noexcept override
178 {
179 return !WorkItems_.empty();
180 }
181
182 T
183 PopWorkItem() override
184 {
185 JLM_ASSERT(HasMoreWorkItems());
186 auto [_, item] = WorkItems_.top();
187 WorkItems_.pop();
188 // Note down the moment this item fired
189 LastFire_[item] = ++FireCounter_;
190 return item;
191 }
192
193 void
194 PushWorkItem(T item) override
195 {
196 size_t & lastFire = LastFire_[item];
197 if (lastFire == InQueueSentinelValue)
198 return;
199
200 // Add the work item to the priority queue based on when it was last fired
201 WorkItems_.push({ lastFire, item });
202 lastFire = InQueueSentinelValue;
203 }
204
205private:
206 // If a work item is currently in the queue, its "last fire" is set to this value
207 static inline const size_t InQueueSentinelValue = std::numeric_limits<size_t>::max();
208
209 // The type of a priority queue giving the highest priority to the lowest value
210 template<typename U>
211 using MinPriorityQueue = std::priority_queue<U, std::vector<U>, std::greater<U>>;
212
213 // The priority queue used to order the items
215
216 // Counter used to order fire events (work items being popped)
217 size_t FireCounter_ = 0;
218
219 // For each work item, when the item was last fired.
220 // If the work item is currently in the queue, InQueueSentinelValue is used instead
221 std::unordered_map<T, size_t> LastFire_;
222};
223
235template<typename T>
236class TwoPhaseLrfWorklist final : public Worklist<T>
237{
238public:
239 ~TwoPhaseLrfWorklist() override = default;
240
242
243 [[nodiscard]] bool
244 HasMoreWorkItems() const noexcept override
245 {
246 return !Current_.empty() || !Next_.empty();
247 }
248
249 T
250 PopWorkItem() override
251 {
252 if (Current_.empty())
253 {
254 JLM_ASSERT(!Next_.empty());
255 std::swap(Current_, Next_);
256 std::sort(Current_.rbegin(), Current_.rend()); // The least recently first work item gets last
257 }
258
259 auto [_, item] = Current_.back();
260 Current_.pop_back();
261 // Note down the moment this item fired
262 LastFire_[item] = ++FireCounter_;
263 return item;
264 }
265
266 void
267 PushWorkItem(T item) override
268 {
269 size_t & lastFire = LastFire_[item];
270 if (lastFire == InQueueSentinelValue)
271 return;
272
273 // Add the work item to the next list, with its last fire time used for sorting
274 Next_.push_back({ lastFire, item });
275 lastFire = InQueueSentinelValue;
276 }
277
278private:
279 // If a work item is currently in the queue, its "last fire" is set to this value
280 static inline const size_t InQueueSentinelValue = std::numeric_limits<size_t>::max();
281
282 // The current list being popped. The pair's first is when the work item was last fired
283 std::vector<std::pair<size_t, T>> Current_;
284
285 // The next list. The pair's first is when the work item was last fired
286 // When current is empty, this list is sorted by least recently fired, and becomes the new current
287 std::vector<std::pair<size_t, T>> Next_;
288
289 // Counter used to order fire events (work items being popped)
290 size_t FireCounter_ = 0;
291
292 // For each work item, when the item was last fired.
293 // If the work item is currently in the queue, InQueueSentinelValue is used instead
294 std::unordered_map<T, size_t> LastFire_;
295};
296
305template<typename T>
306class Workset final : public Worklist<T>
307{
308public:
309 ~Workset() override = default;
310
311 Workset() = default;
312
313 [[nodiscard]] bool
314 HasMoreWorkItems() const noexcept override
315 {
316 return !PushedItems_.IsEmpty();
317 }
318
319 T
320 PopWorkItem() override
321 {
322 JLM_UNREACHABLE("The Workset does not provide an iteration order");
323 }
324
325 void
326 PushWorkItem(T item) override
327 {
328 PushedItems_.insert(item);
329 }
330
331 [[nodiscard]] bool
332 HasWorkItem(T item) const noexcept
333 {
334 return PushedItems_.Contains(item);
335 }
336
337 void
339 {
340 PushedItems_.Remove(item);
341 }
342
343private:
345};
346
347}
348
349#endif // JLM_UTIL_WORKLIST_HPP
void PushWorkItem(T item) override
Definition Worklist.hpp:143
bool HasMoreWorkItems() const noexcept override
Definition Worklist.hpp:127
T PopWorkItem() override
Definition Worklist.hpp:133
util::HashSet< T > OnList_
Definition Worklist.hpp:151
std::queue< T > WorkItems_
Definition Worklist.hpp:154
~FifoWorklist() override=default
bool HasMoreWorkItems() const noexcept override
Definition Worklist.hpp:82
util::HashSet< T > OnList_
Definition Worklist.hpp:106
~LifoWorklist() override=default
T PopWorkItem() override
Definition Worklist.hpp:88
void PushWorkItem(T item) override
Definition Worklist.hpp:98
std::stack< T > WorkItems_
Definition Worklist.hpp:109
MinPriorityQueue< std::pair< size_t, T > > WorkItems_
Definition Worklist.hpp:214
bool HasMoreWorkItems() const noexcept override
Definition Worklist.hpp:177
std::unordered_map< T, size_t > LastFire_
Definition Worklist.hpp:221
T PopWorkItem() override
Definition Worklist.hpp:183
std::priority_queue< U, std::vector< U >, std::greater< U > > MinPriorityQueue
Definition Worklist.hpp:211
~LrfWorklist() override=default
void PushWorkItem(T item) override
Definition Worklist.hpp:194
std::vector< std::pair< size_t, T > > Current_
Definition Worklist.hpp:283
void PushWorkItem(T item) override
Definition Worklist.hpp:267
bool HasMoreWorkItems() const noexcept override
Definition Worklist.hpp:244
~TwoPhaseLrfWorklist() override=default
std::unordered_map< T, size_t > LastFire_
Definition Worklist.hpp:294
std::vector< std::pair< size_t, T > > Next_
Definition Worklist.hpp:287
virtual ~Worklist()=default
virtual T PopWorkItem()=0
virtual bool HasMoreWorkItems() const noexcept=0
Worklist(const Worklist &other)=delete
Worklist & operator=(Worklist &&other)=default
Worklist(Worklist &&other)=default
Worklist & operator=(const Worklist &other)=delete
virtual void PushWorkItem(T item)=0
util::HashSet< T > PushedItems_
Definition Worklist.hpp:344
~Workset() override=default
bool HasWorkItem(T item) const noexcept
Definition Worklist.hpp:332
bool HasMoreWorkItems() const noexcept override
Definition Worklist.hpp:314
T PopWorkItem() override
Definition Worklist.hpp:320
void RemoveWorkItem(T item)
Definition Worklist.hpp:338
void PushWorkItem(T item) override
Definition Worklist.hpp:326
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43