1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_REGMASK_H
17 #define PANDA_REGMASK_H
18 
19 #include "utils/bit_utils.h"
20 #include "utils/type_helpers.h"
21 #include <array>
22 
23 namespace ark {
24 
25 template <typename T, size_t N>
MakeMask(const std::array<T, N> &indexes)26 static constexpr size_t MakeMask(const std::array<T, N> &indexes)
27 {
28     size_t res = 0;
29     for (size_t i : indexes) {
30         res |= (1UL << i);
31     }
32     return res;
33 }
34 
35 template <typename... Indexes>
MakeMask(Indexes.... indexes)36 static constexpr size_t MakeMask(Indexes... indexes)
37 {
38     return ((1UL << helpers::ToUnsigned(indexes)) | ...);
39 }
40 
41 template <typename... Indexes>
MakeMaskByExcluding(size_t width, Indexes... indexes)42 static constexpr size_t MakeMaskByExcluding(size_t width, Indexes... indexes)
43 {
44     size_t res = (1ULL << width) - 1;
45     size_t exclude = ((1ULL << helpers::ToUnsigned(indexes)) | ...);
46     return res & ~exclude;
47 }
48 
49 /**
50  * Base struct for registers mask, template-parametrized by number of registers.
51  * Currently we don't support registers number greater than 32.
52  * Previously, Regmask class just inherited std::bitset, but std::bitset has poor constexpr support, that was the main
53  * reason to implement own RegMask class.
54  * Regmask has interface, similar to std::bitset.
55  */
56 template <size_t N>
57 class RegMaskImpl {
58 public:
59     // We don't support architectures with CPU registers number, greater than 32.
60     static_assert(N <= sizeof(uint32_t) * BITS_PER_BYTE);
61 
62     using ValueType = uint32_t;
63     using Self = RegMaskImpl<N>;
64 
65     constexpr RegMaskImpl() = default;
66 
67     // NOLINTNEXTLINE(google-explicit-constructor)
RegMaskImpl(ValueType v)68     constexpr RegMaskImpl(ValueType v) : value_(v) {}
69 
GetValue() const70     constexpr ValueType GetValue() const
71     {
72         return value_;
73     }
74 
Size()75     static constexpr size_t Size()
76     {
77         return N;
78     }
79 
Any() const80     constexpr bool Any() const
81     {
82         return value_ != 0;
83     }
84 
None() const85     constexpr bool None() const
86     {
87         return value_ == 0;
88     }
89 
Test(size_t bit) const90     constexpr bool Test(size_t bit) const
91     {
92         ASSERT(bit < Size());
93         return ((value_ >> static_cast<ValueType>(bit)) & 1U) != 0;
94     }
95 
Set()96     constexpr void Set()
97     {
98         value_ = ~static_cast<ValueType>(0U);
99     }
Reset()100     constexpr void Reset()
101     {
102         value_ = 0;
103     }
104 
Set(size_t bit)105     constexpr void Set(size_t bit)
106     {
107         ASSERT(bit < Size());
108         value_ |= (1U << bit);
109     }
110 
111     constexpr void Set(size_t bit, bool value)
112     {
113         ASSERT(bit < Size());
114         if (value) {
115             Set(bit);
116         } else {
117             Reset(bit);
118         }
119     }
120 
121     constexpr void Reset(size_t bit)
122     {
123         ASSERT(bit < Size());
124         value_ &= ~(1U << bit);
125     }
126 
127     constexpr size_t Count() const
128     {
129         return Popcount(GetValue());
130     }
131 
132     constexpr bool CountIsEven() const
133     {
134         return (Count() & 1U) == 0;
135     }
136 
137     // Get number of registers from tail to the given register, counting only set bits.
138     // Given `reg` is not counted even if it is set.
139     constexpr size_t GetDistanceFromTail(size_t reg) const
140     {
141         ASSERT(reg < Size());
142         uint32_t val = GetValue() & ((1U << reg) - 1);
143         return Popcount(val);
144     }
145 
146     // Get number of registers from head to the given register, counting only set bits.
147     // Given `reg` is not counted even if it is set.
148     constexpr size_t GetDistanceFromHead(size_t reg) const
149     {
150         if (reg < (Size() - 1)) {
151             uint32_t val = GetValue() & ~((1U << (reg + 1)) - 1);
152             return Popcount(val);
153         }
154         if (reg == Size() - 1) {
155             return 0;
156         }
157         // reg > (Size() - 1), something goes wrong...
158         UNREACHABLE();
159         return 0;
160     }
161 
162     constexpr uint32_t GetMinRegister() const
163     {
164         ASSERT(Any());
165         return ark::Ctz(GetValue());
166     }
167 
168     constexpr uint32_t GetMaxRegister() const
169     {
170         ASSERT(Any());
171         return (sizeof(decltype(GetValue())) * BITS_PER_BYTE) - 1 - ark::Clz(GetValue());
172     }
173 
174     constexpr static auto GetZeroMask()
175     {
176         return RegMaskImpl();
177     }
178 
179     constexpr Self operator~() const
180     {
181         return Self(~GetValue());
182     }
183 
184     constexpr Self operator&(Self other) const
185     {
186         return Self(GetValue() & other.GetValue());
187     }
188 
189     constexpr Self operator|(Self other) const
190     {
191         return Self(GetValue() | other.GetValue());
192     }
193 
194     constexpr Self operator^(Self other) const
195     {
196         return Self(GetValue() ^ other.GetValue());
197     }
198 
199     constexpr Self operator&=(Self other)
200     {
201         value_ &= other.GetValue();
202         return *this;
203     }
204 
205     constexpr Self operator|=(Self other)
206     {
207         value_ |= other.GetValue();
208         return *this;
209     }
210 
211     constexpr Self operator^=(Self other)
212     {
213         value_ ^= other.GetValue();
214         return *this;
215     }
216     constexpr bool operator[](size_t bit) const
217     {
218         return Test(bit);
219     }
220     constexpr bool operator==(Self other) const
221     {
222         return value_ == other.value_;
223     }
224 
225     constexpr bool operator!=(Self other) const
226     {
227         return !(*this == other);
228     }
229 
230     // NOLINTNEXTLINE(readability-identifier-naming)
231     constexpr ValueType to_ulong() const
232     {
233         return GetValue();
234     }
235 
236     void Dump(std::ostream &out = std::cerr) const
237     {
238         out << "Regmask[" << N << "]: ";
239         for (size_t i = 0; i < N; i++) {
240             if (Test(i)) {
241                 out << i << " ";
242             }
243         }
244     }
245 
246     // The following methods are for compatibility with `std::bitset`, since we used `std::bitset` before.
247     // Don't use these method in a new code.
248     // NOLINTBEGIN(readability-identifier-naming)
249     constexpr bool any() const
250     {
251         return Any();
252     }
253     constexpr bool none() const
254     {
255         return None();
256     }
257     constexpr bool test(size_t bit) const
258     {
259         return Test(bit);
260     }
261     constexpr void set(size_t bit)
262     {
263         Set(bit);
264     }
265     constexpr void set(size_t bit, bool value)
266     {
267         Set(bit, value);
268     }
269     constexpr Self set()
270     {
271         Set();
272         return *this;
273     }
274     constexpr Self reset()
275     {
276         Reset();
277         return *this;
278     }
279     constexpr void reset(size_t bit)
280     {
281         Reset(bit);
282     }
283     constexpr size_t count() const
284     {
285         return Count();
286     }
287     constexpr size_t size() const
288     {
289         return Size();
290     }
291     // NOLINTEND(readability-identifier-naming)
292 
293 private:
294     ValueType value_ {0};
295 };
296 
297 static constexpr uint8_t REGISTERS_NUM = 32;
298 static constexpr uint8_t VREGISTERS_NUM = 32;
299 
300 using RegMask = RegMaskImpl<REGISTERS_NUM>;
301 using VRegMask = RegMaskImpl<VREGISTERS_NUM>;
302 
303 inline std::ostream &operator<<(std::ostream &stream, const RegMask &mask)
304 {
305     mask.Dump(stream);
306     return stream;
307 }
308 
309 }  // namespace ark
310 
311 #endif  // PANDA_REGMASK_H
312