xref: /third_party/mesa3d/src/amd/compiler/aco_util.h (revision bf215546)
1/*
2 * Copyright Michael Schellenberger Costa
3 * Copyright © 2020 Valve Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 */
25
26#ifndef ACO_UTIL_H
27#define ACO_UTIL_H
28
29#include "util/bitscan.h"
30
31#include <cassert>
32#include <cstddef>
33#include <iterator>
34#include <vector>
35
36namespace aco {
37
38/*! \brief      Definition of a span object
39 *
40 *   \details    A "span" is an "array view" type for holding a view of contiguous
41 *               data. The "span" object does not own the data itself.
42 */
43template <typename T> class span {
44public:
45   using value_type = T;
46   using pointer = value_type*;
47   using const_pointer = const value_type*;
48   using reference = value_type&;
49   using const_reference = const value_type&;
50   using iterator = pointer;
51   using const_iterator = const_pointer;
52   using reverse_iterator = std::reverse_iterator<iterator>;
53   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
54   using size_type = uint16_t;
55   using difference_type = std::ptrdiff_t;
56
57   /*! \brief                  Compiler generated default constructor
58    */
59   constexpr span() = default;
60
61   /*! \brief                 Constructor taking a pointer and the length of the span
62    *  \param[in]   data      Pointer to the underlying data array
63    *  \param[in]   length    The size of the span
64    */
65   constexpr span(uint16_t offset_, const size_type length_) : offset{offset_}, length{length_} {}
66
67   /*! \brief                 Returns an iterator to the begin of the span
68    *  \return                data
69    */
70   constexpr iterator begin() noexcept { return (pointer)((uintptr_t)this + offset); }
71
72   /*! \brief                 Returns a const_iterator to the begin of the span
73    *  \return                data
74    */
75   constexpr const_iterator begin() const noexcept
76   {
77      return (const_pointer)((uintptr_t)this + offset);
78   }
79
80   /*! \brief                 Returns an iterator to the end of the span
81    *  \return                data + length
82    */
83   constexpr iterator end() noexcept { return std::next(begin(), length); }
84
85   /*! \brief                 Returns a const_iterator to the end of the span
86    *  \return                data + length
87    */
88   constexpr const_iterator end() const noexcept { return std::next(begin(), length); }
89
90   /*! \brief                 Returns a const_iterator to the begin of the span
91    *  \return                data
92    */
93   constexpr const_iterator cbegin() const noexcept { return begin(); }
94
95   /*! \brief                 Returns a const_iterator to the end of the span
96    *  \return                data + length
97    */
98   constexpr const_iterator cend() const noexcept { return std::next(begin(), length); }
99
100   /*! \brief                 Returns a reverse_iterator to the end of the span
101    *  \return                reverse_iterator(end())
102    */
103   constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
104
105   /*! \brief                 Returns a const_reverse_iterator to the end of the span
106    *  \return                reverse_iterator(end())
107    */
108   constexpr const_reverse_iterator rbegin() const noexcept
109   {
110      return const_reverse_iterator(end());
111   }
112
113   /*! \brief                 Returns a reverse_iterator to the begin of the span
114    *   \return                reverse_iterator(begin())
115    */
116   constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
117
118   /*! \brief                 Returns a const_reverse_iterator to the begin of the span
119    *  \return                reverse_iterator(begin())
120    */
121   constexpr const_reverse_iterator rend() const noexcept
122   {
123      return const_reverse_iterator(begin());
124   }
125
126   /*! \brief                 Returns a const_reverse_iterator to the end of the span
127    *  \return                rbegin()
128    */
129   constexpr const_reverse_iterator crbegin() const noexcept
130   {
131      return const_reverse_iterator(cend());
132   }
133
134   /*! \brief                 Returns a const_reverse_iterator to the begin of the span
135    *  \return                rend()
136    */
137   constexpr const_reverse_iterator crend() const noexcept
138   {
139      return const_reverse_iterator(cbegin());
140   }
141
142   /*! \brief                 Unchecked access operator
143    *  \param[in] index       Index of the element we want to access
144    *  \return                *(std::next(data, index))
145    */
146   constexpr reference operator[](const size_type index) noexcept
147   {
148      assert(length > index);
149      return *(std::next(begin(), index));
150   }
151
152   /*! \brief                 Unchecked const access operator
153    *  \param[in] index       Index of the element we want to access
154    *  \return                *(std::next(data, index))
155    */
156   constexpr const_reference operator[](const size_type index) const noexcept
157   {
158      assert(length > index);
159      return *(std::next(begin(), index));
160   }
161
162   /*! \brief                 Returns a reference to the last element of the span
163    *  \return                *(std::next(data, length - 1))
164    */
165   constexpr reference back() noexcept
166   {
167      assert(length > 0);
168      return *(std::next(begin(), length - 1));
169   }
170
171   /*! \brief                 Returns a const_reference to the last element of the span
172    *  \return                *(std::next(data, length - 1))
173    */
174   constexpr const_reference back() const noexcept
175   {
176      assert(length > 0);
177      return *(std::next(begin(), length - 1));
178   }
179
180   /*! \brief                 Returns a reference to the first element of the span
181    *  \return                *begin()
182    */
183   constexpr reference front() noexcept
184   {
185      assert(length > 0);
186      return *begin();
187   }
188
189   /*! \brief                 Returns a const_reference to the first element of the span
190    *  \return                *cbegin()
191    */
192   constexpr const_reference front() const noexcept
193   {
194      assert(length > 0);
195      return *cbegin();
196   }
197
198   /*! \brief                 Returns true if the span is empty
199    *  \return                length == 0
200    */
201   constexpr bool empty() const noexcept { return length == 0; }
202
203   /*! \brief                 Returns the size of the span
204    *  \return                length == 0
205    */
206   constexpr size_type size() const noexcept { return length; }
207
208   /*! \brief                 Decreases the size of the span by 1
209    */
210   constexpr void pop_back() noexcept
211   {
212      assert(length > 0);
213      --length;
214   }
215
216   /*! \brief                 Adds an element to the end of the span
217    */
218   constexpr void push_back(const_reference val) noexcept { *std::next(begin(), length++) = val; }
219
220   /*! \brief                 Clears the span
221    */
222   constexpr void clear() noexcept
223   {
224      offset = 0;
225      length = 0;
226   }
227
228private:
229   uint16_t offset{0};  //!> Byte offset from span to data
230   size_type length{0}; //!> Size of the span
231};
232
233/*
234 * Cache-friendly set of 32-bit IDs with O(1) insert/erase/lookup and
235 * the ability to efficiently iterate over contained elements.
236 *
237 * Internally implemented as a bit vector: If the set contains an ID, the
238 * corresponding bit is set. It doesn't use std::vector<bool> since we then
239 * couldn't efficiently iterate over the elements.
240 *
241 * The interface resembles a subset of std::set/std::unordered_set.
242 */
243struct IDSet {
244   struct Iterator {
245      const IDSet* set;
246      union {
247         struct {
248            uint32_t bit : 6;
249            uint32_t word : 26;
250         };
251         uint32_t id;
252      };
253
254      Iterator& operator++();
255
256      bool operator!=(const Iterator& other) const;
257
258      uint32_t operator*() const;
259   };
260
261   size_t count(uint32_t id) const
262   {
263      if (id >= words.size() * 64)
264         return 0;
265
266      return words[id / 64u] & (1ull << (id % 64u)) ? 1 : 0;
267   }
268
269   Iterator find(uint32_t id) const
270   {
271      if (!count(id))
272         return end();
273
274      Iterator it;
275      it.set = this;
276      it.bit = id % 64u;
277      it.word = id / 64u;
278      return it;
279   }
280
281   std::pair<Iterator, bool> insert(uint32_t id)
282   {
283      if (words.size() * 64u <= id)
284         words.resize(id / 64u + 1);
285
286      Iterator it;
287      it.set = this;
288      it.bit = id % 64u;
289      it.word = id / 64u;
290
291      uint64_t mask = 1ull << it.bit;
292      if (words[it.word] & mask)
293         return std::make_pair(it, false);
294
295      words[it.word] |= mask;
296      bits_set++;
297      return std::make_pair(it, true);
298   }
299
300   size_t erase(uint32_t id)
301   {
302      if (!count(id))
303         return 0;
304
305      words[id / 64u] ^= 1ull << (id % 64u);
306      bits_set--;
307      return 1;
308   }
309
310   Iterator cbegin() const
311   {
312      Iterator it;
313      it.set = this;
314      for (size_t i = 0; i < words.size(); i++) {
315         if (words[i]) {
316            it.word = i;
317            it.bit = ffsll(words[i]) - 1;
318            return it;
319         }
320      }
321      return end();
322   }
323
324   Iterator cend() const
325   {
326      Iterator it;
327      it.set = this;
328      it.word = words.size();
329      it.bit = 0;
330      return it;
331   }
332
333   Iterator begin() const { return cbegin(); }
334
335   Iterator end() const { return cend(); }
336
337   bool empty() const { return bits_set == 0; }
338
339   size_t size() const { return bits_set; }
340
341   std::vector<uint64_t> words;
342   uint32_t bits_set = 0;
343};
344
345inline IDSet::Iterator&
346IDSet::Iterator::operator++()
347{
348   uint64_t m = set->words[word];
349   m &= ~((2ull << bit) - 1ull);
350   if (!m) {
351      /* don't continue past the end */
352      if (word == set->words.size())
353         return *this;
354
355      word++;
356      for (; word < set->words.size(); word++) {
357         if (set->words[word]) {
358            bit = ffsll(set->words[word]) - 1;
359            return *this;
360         }
361      }
362      bit = 0;
363   } else {
364      bit = ffsll(m) - 1;
365   }
366   return *this;
367}
368
369inline bool
370IDSet::Iterator::operator!=(const IDSet::Iterator& other) const
371{
372   assert(set == other.set);
373   return id != other.id;
374}
375
376inline uint32_t
377IDSet::Iterator::operator*() const
378{
379   return (word << 6) | bit;
380}
381
382} // namespace aco
383
384#endif // ACO_UTIL_H
385