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