1 /**
2 * Copyright (c) 2021-2022 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 LIBPANDABASE_UTILS_REGMASK_H
17 #define LIBPANDABASE_UTILS_REGMASK_H
18
19 #include <array>
20 #include "utils/bit_utils.h"
21 #include "utils/type_helpers.h"
22
23 namespace panda {
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()70 constexpr ValueType GetValue() const
71 {
72 return value_;
73 }
74
Size()75 static constexpr size_t Size()
76 {
77 return N;
78 }
79
Any()80 constexpr bool Any() const
81 {
82 return value_ != 0;
83 }
84
None()85 constexpr bool None() const
86 {
87 return value_ == 0;
88 }
89
Test(size_t bit)90 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
Set(size_t bit,bool value)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
Reset(size_t bit)121 constexpr void Reset(size_t bit)
122 {
123 ASSERT(bit < Size());
124 value_ &= ~(1U << bit);
125 }
126
Count()127 constexpr size_t Count() const
128 {
129 return Popcount(GetValue());
130 }
131
CountIsEven()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.
GetDistanceFromTail(size_t reg)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.
GetDistanceFromHead(size_t reg)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
GetMinRegister()162 constexpr uint32_t GetMinRegister() const
163 {
164 ASSERT(Any());
165 return panda::Ctz(GetValue());
166 }
167
GetMaxRegister()168 constexpr uint32_t GetMaxRegister() const
169 {
170 ASSERT(Any());
171 return (sizeof(decltype(GetValue())) * BITS_PER_BYTE) - 1 - panda::Clz(GetValue());
172 }
173
174 constexpr Self operator~() const
175 {
176 return Self(~GetValue());
177 }
178
179 constexpr Self operator&(Self other) const
180 {
181 return Self(GetValue() & other.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)
195 {
196 value_ &= other.GetValue();
197 return *this;
198 }
199
200 constexpr Self operator|=(Self other)
201 {
202 value_ |= other.GetValue();
203 return *this;
204 }
205
206 constexpr Self operator^=(Self other)
207 {
208 value_ ^= other.GetValue();
209 return *this;
210 }
211 constexpr bool operator[](size_t bit) const
212 {
213 return Test(bit);
214 }
215 constexpr bool operator==(Self other) const
216 {
217 return value_ == other.value_;
218 }
219
220 constexpr bool operator!=(Self other) const
221 {
222 return !(*this == other);
223 }
224
to_ulong()225 constexpr ValueType to_ulong() const
226 {
227 return GetValue();
228 }
229
230 void Dump(std::ostream &out = std::cerr) const
231 {
232 out << "Regmask[" << N << "]: ";
233 for (size_t i = 0; i < N; i++) {
234 if (Test(i)) {
235 out << i << " ";
236 }
237 }
238 }
239
240 // The following methods are for compatibility with `std::bitset`, since we used `std::bitset` before.
241 // Don't use these method in a new code.
any()242 constexpr bool any() const
243 {
244 return Any();
245 }
none()246 constexpr bool none() const
247 {
248 return None();
249 }
test(size_t bit)250 constexpr bool test(size_t bit) const
251 {
252 return Test(bit);
253 }
set(size_t bit)254 constexpr void set(size_t bit)
255 {
256 Set(bit);
257 }
set(size_t bit,bool value)258 constexpr void set(size_t bit, bool value)
259 {
260 Set(bit, value);
261 }
set()262 constexpr Self set()
263 {
264 Set();
265 return *this;
266 }
reset()267 constexpr Self reset()
268 {
269 Reset();
270 return *this;
271 }
reset(size_t bit)272 constexpr void reset(size_t bit)
273 {
274 Reset(bit);
275 }
count()276 constexpr size_t count() const
277 {
278 return Count();
279 }
size()280 constexpr size_t size() const
281 {
282 return Size();
283 }
284
285 private:
286 ValueType value_ {0};
287 };
288
289 static constexpr uint8_t REGISTERS_NUM = 32;
290 static constexpr uint8_t VREGISTERS_NUM = 32;
291
292 using RegMask = RegMaskImpl<REGISTERS_NUM>;
293 using VRegMask = RegMaskImpl<VREGISTERS_NUM>;
294
295 inline std::ostream &operator<<(std::ostream &stream, const RegMask &mask)
296 {
297 mask.Dump(stream);
298 return stream;
299 }
300
301 } // namespace panda
302
303 #endif // LIBPANDABASE_UTILS_REGMASK_H
304