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 23namespace panda { 24 25template <typename T, size_t N> 26static 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 35template <typename... Indexes> 36static constexpr size_t MakeMask(Indexes... indexes) 37{ 38 return ((1UL << helpers::ToUnsigned(indexes)) | ...); 39} 40 41template <typename... Indexes> 42static 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 */ 56template <size_t N> 57class RegMaskImpl { 58public: 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) 68 constexpr RegMaskImpl(ValueType v) : value_(v) {} 69 70 constexpr ValueType GetValue() const 71 { 72 return value_; 73 } 74 75 static constexpr size_t Size() 76 { 77 return N; 78 } 79 80 constexpr bool Any() const 81 { 82 return value_ != 0; 83 } 84 85 constexpr bool None() const 86 { 87 return value_ == 0; 88 } 89 90 constexpr bool Test(size_t bit) const 91 { 92 ASSERT(bit < Size()); 93 return ((value_ >> static_cast<ValueType>(bit)) & 1U) != 0; 94 } 95 96 constexpr void Set() 97 { 98 value_ = ~static_cast<ValueType>(0U); 99 } 100 constexpr void Reset() 101 { 102 value_ = 0; 103 } 104 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 panda::Ctz(GetValue()); 166 } 167 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 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. 242 constexpr bool any() const 243 { 244 return Any(); 245 } 246 constexpr bool none() const 247 { 248 return None(); 249 } 250 constexpr bool test(size_t bit) const 251 { 252 return Test(bit); 253 } 254 constexpr void set(size_t bit) 255 { 256 Set(bit); 257 } 258 constexpr void set(size_t bit, bool value) 259 { 260 Set(bit, value); 261 } 262 constexpr Self set() 263 { 264 Set(); 265 return *this; 266 } 267 constexpr Self reset() 268 { 269 Reset(); 270 return *this; 271 } 272 constexpr void reset(size_t bit) 273 { 274 Reset(bit); 275 } 276 constexpr size_t count() const 277 { 278 return Count(); 279 } 280 constexpr size_t size() const 281 { 282 return Size(); 283 } 284 285private: 286 ValueType value_ {0}; 287}; 288 289static constexpr uint8_t REGISTERS_NUM = 32; 290static constexpr uint8_t VREGISTERS_NUM = 32; 291 292using RegMask = RegMaskImpl<REGISTERS_NUM>; 293using VRegMask = RegMaskImpl<VREGISTERS_NUM>; 294 295inline 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