1// Copyright (c) 2017 ARM Limited 2// All rights reserved 3// 4// The license below extends only to copyright in the software and shall 5// not be construed as granting a license to any other intellectual 6// property including but not limited to intellectual property relating 7// to a hardware implementation of the functionality of the software 8// licensed hereunder. You may use the software subject to the license 9// terms below provided that you ensure that this notice is replicated 10// unmodified and in its entirety in all distributions of the software, 11// modified or unmodified, in source code or in binary form. 12// 13// Redistribution and use in source and binary forms, with or without 14// modification, are permitted provided that the following conditions are 15// met: redistributions of source code must retain the above copyright 16// notice, this list of conditions and the following disclaimer; 17// redistributions in binary form must reproduce the above copyright 18// notice, this list of conditions and the following disclaimer in the 19// documentation and/or other materials provided with the distribution; 20// neither the name of the copyright holders nor the names of its 21// contributors may be used to endorse or promote products derived from 22// this software without specific prior written permission. 23// 24// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35// 36// Authors: Giacomo Gabrielli 37// Rekai Gonzalez 38// Javier Setoain 39 40#ifndef __ARCH_GENERIC_VEC_PRED_REG_HH__ 41#define __ARCH_GENERIC_VEC_PRED_REG_HH__ 42 43#include <array> 44#include <cassert> 45#include <vector> 46 47#include "arch/generic/vec_reg.hh" 48#include "base/cprintf.hh" 49 50template <size_t NumBits, bool Packed> 51class VecPredRegContainer; 52 53/// Predicate register view. 54/// 55/// This generic class implements the View in an MVC pattern, similarly to 56/// @see VecRegT. Since predicates are mainly used in conjunction with vectors 57/// to specify which lanes are active in a vector operation, the class is 58/// templated on the vector element type to simplify ISA definitions. 59/// @tparam VecElem Type of the vector elements. 60/// @tparam NumElems Number of vector elements making up the view. 61/// @tparam Packed True if the predicate register relies on a packed 62/// representation, i.e. adjacent bits refer to different vector elements 63/// irrespective of the vector element size (e.g. this is the case for 64/// AVX-512). If false, the predicate register relies on an unpacked 65/// representation, where each bit refers to the corresponding byte in a vector 66/// register (e.g. this is the case for ARM SVE). 67/// @tparam Const True if the underlying container can be modified through 68/// the view. 69template <typename VecElem, size_t NumElems, bool Packed, bool Const> 70class VecPredRegT 71{ 72 protected: 73 /// Size of the register in bits. 74 static constexpr size_t NUM_BITS = Packed ? NumElems : 75 sizeof(VecElem) * NumElems; 76 77 public: 78 /// Container type alias. 79 using Container = typename std::conditional< 80 Const, 81 const VecPredRegContainer<NUM_BITS, Packed>, 82 VecPredRegContainer<NUM_BITS, Packed>>::type; 83 84 protected: 85 // Alias for this type 86 using MyClass = VecPredRegT<VecElem, NumElems, Packed, Const>; 87 /// Container corresponding to this view. 88 Container& container; 89 90 public: 91 VecPredRegT(Container& c) : container(c) {} 92 93 /// Reset the register to an all-false value. 94 template<bool Condition = !Const> 95 typename std::enable_if<Condition, void>::type 96 reset() { container.reset(); } 97 98 /// Reset the register to an all-true value. 99 template<bool Condition = !Const> 100 typename std::enable_if<Condition, void>::type 101 set() { container.set(); } 102 103 template<bool Condition = !Const> 104 typename std::enable_if<Condition, MyClass&>::type 105 operator=(const MyClass& that) 106 { 107 container = that.container; 108 return *this; 109 } 110 111 const bool& 112 operator[](size_t idx) const 113 { 114 return container[idx * (Packed ? 1 : sizeof(VecElem))]; 115 } 116 117 template<bool Condition = !Const> 118 typename std::enable_if<Condition, bool&>::type 119 operator[](size_t idx) 120 { 121 return container[idx * (Packed ? 1 : sizeof(VecElem))]; 122 } 123 124 /// Return an element of the predicate register as it appears 125 /// in the raw (untyped) internal representation 126 uint8_t 127 get_raw(size_t idx) const 128 { 129 return container.get_bits(idx * (Packed ? 1 : sizeof(VecElem)), 130 (Packed ? 1 : sizeof(VecElem))); 131 } 132 133 /// Write a raw value in an element of the predicate register 134 template<bool Condition = !Const> 135 typename std::enable_if<Condition, void>::type 136 set_raw(size_t idx, uint8_t val) 137 { 138 container.set_bits(idx * (Packed ? 1 : sizeof(VecElem)), 139 (Packed ? 1 : sizeof(VecElem)), val); 140 } 141 142 /// Equality operator, required to compare thread contexts. 143 template<typename VE2, size_t NE2, bool P2, bool C2> 144 bool 145 operator==(const VecPredRegT<VE2, NE2, P2, C2>& that) const 146 { 147 return container == that.container; 148 } 149 150 /// Inequality operator, required to compare thread contexts. 151 template<typename VE2, size_t NE2, bool P2, bool C2> 152 bool 153 operator!=(const VecPredRegT<VE2, NE2, P2, C2>& that) const 154 { 155 return !operator==(that); 156 } 157 158 friend std::ostream& 159 operator<<(std::ostream& os, const MyClass& p) 160 { 161 // 0-sized is not allowed 162 os << '[' << p.container[0]; 163 for (int i = 0; i < p.NUM_BITS; ++i) { 164 os << " " << (p.container[i] ? 1 : 0); 165 } 166 os << ']'; 167 return os; 168 } 169 170 /// Returns a string representation of the register content. 171 const std::string print() const { return csprintf("%s", *this); } 172 173 /// Returns true if the first active element of the register is true. 174 /// @param mask Input mask used to filter the predicates to be tested. 175 /// @param actual_num_elems Actual number of vector elements considered for 176 /// the test (corresponding to the current vector length). 177 template <bool MC> 178 bool 179 firstActive(const VecPredRegT<VecElem, NumElems, Packed, MC>& mask, 180 size_t actual_num_elems) const 181 { 182 assert(actual_num_elems <= NumElems); 183 for (int i = 0; i < actual_num_elems; ++i) { 184 if (mask[i]) { 185 return (*this)[i]; 186 } 187 } 188 return false; 189 } 190 191 /// Returns true if there are no active elements in the register. 192 /// @param mask Input mask used to filter the predicates to be tested. 193 /// @param actual_num_elems Actual number of vector elements considered for 194 /// the test (corresponding to the current vector length). 195 template <bool MC> 196 bool 197 noneActive(const VecPredRegT<VecElem, NumElems, Packed, MC>& mask, 198 size_t actual_num_elems) const 199 { 200 assert(actual_num_elems <= NumElems); 201 for (int i = 0; i < actual_num_elems; ++i) { 202 if (mask[i] && operator[](i)) { 203 return false; 204 } 205 } 206 return true; 207 } 208 209 /// Returns true if the last active element of the register is true. 210 /// @param mask Input mask used to filter the predicates to be tested. 211 /// @param actual_num_elems Actual number of vector elements considered for 212 /// the test (corresponding to the current vector length). 213 template <bool MC> 214 bool 215 lastActive(const VecPredRegT<VecElem, NumElems, Packed, MC>& mask, 216 size_t actual_num_elems) const 217 { 218 assert(actual_num_elems <= NumElems); 219 for (int i = actual_num_elems - 1; i >= 0; --i) { 220 if (mask[i]) { 221 return operator[](i); 222 } 223 } 224 return false; 225 } 226}; 227 228/// Generic predicate register container. 229/// 230/// This generic class implements the Model in an MVC pattern, similarly to 231/// @see VecRegContainer. 232/// @tparam NumBits Size of the container in bits. 233/// @tparam Packed See @VecRegT. 234template <size_t NumBits, bool Packed> 235class VecPredRegContainer 236{ 237 static_assert(NumBits > 0, 238 "Size of a predicate register must be > 0"); 239 240 public: 241 static constexpr size_t NUM_BITS = NumBits; 242 using Container = std::array<bool, NumBits>; 243 244 private: 245 Container container; 246 // Alias for this type 247 using MyClass = VecPredRegContainer<NumBits, Packed>; 248 249 public: 250 VecPredRegContainer() {} 251 252 MyClass& 253 operator=(const MyClass& that) 254 { 255 if (&that == this) 256 return *this; 257 container = that.container; 258 return *this; 259 } 260 261 /// Required for de-serialization. 262 MyClass& 263 operator=(const std::vector<uint8_t>& that) 264 { 265 assert(that.size() == NUM_BITS); 266 std::copy(that.begin(), that.end(), container.begin()); 267 return *this; 268 } 269 270 /// Resets the predicate register to an all-false register. 271 void 272 reset() 273 { 274 container.fill(false); 275 } 276 277 /// Sets the predicate register to an all-true value. 278 void 279 set() 280 { 281 container.fill(true); 282 } 283 284 /// Equality operator, required to compare thread contexts. 285 template<size_t N2, bool P2> 286 inline bool 287 operator==(const VecPredRegContainer<N2, P2>& that) const 288 { 289 return NumBits == N2 && Packed == P2 && container == that.container; 290 } 291 292 /// Inequality operator, required to compare thread contexts. 293 template<size_t N2, bool P2> 294 bool 295 operator!=(const VecPredRegContainer<N2, P2>& that) const 296 { 297 return !operator==(that); 298 } 299 300 /// Returns a reference to a specific element of the internal container. 301 bool& operator[](size_t idx) { return container[idx]; } 302 303 /// Returns a const reference to a specific element of the internal 304 /// container. 305 const bool& operator[](size_t idx) const { return container[idx]; } 306 307 /// Returns a subset of bits starting from a specific element in the 308 /// container. 309 uint8_t 310 get_bits(size_t idx, uint8_t nbits) const 311 { 312 assert(nbits > 0 && nbits <= 8 && (idx + nbits - 1) < NumBits); 313 uint8_t v = 0; 314 idx = idx + nbits - 1; 315 for (int i = 0; i < nbits; ++i, --idx) { 316 v <<= 1; 317 v |= container[idx]; 318 } 319 return v; 320 } 321 322 /// Set a subset of bits starting from a specific element in the 323 /// container. 324 void 325 set_bits(size_t idx, uint8_t nbits, uint8_t bval) 326 { 327 assert(nbits > 0 && nbits <= 8 && (idx + nbits - 1) < NumBits); 328 for (int i = 0; i < nbits; ++i, ++idx) { 329 container[idx] = bval & 1; 330 bval >>= 1; 331 } 332 } 333 334 /// Returns a string representation of the register content. 335 const std::string print() const { return csprintf("%s", *this); } 336 337 friend std::ostream& 338 operator<<(std::ostream& os, const MyClass& v) 339 { 340 for (auto b: v.container) { 341 os << csprintf("%d", b); 342 } 343 return os; 344 } 345 346 /// Create a view of this container. 347 /// 348 /// If NumElems is provided, the size of the container is bounds-checked, 349 /// otherwise the size is inferred from the container size. 350 /// @tparam VecElem Type of the vector elements. 351 /// @tparam NumElems Number of vector elements making up the view. 352 /// @{ 353 template <typename VecElem, 354 size_t NumElems = (Packed ? NumBits : NumBits / sizeof(VecElem))> 355 VecPredRegT<VecElem, NumElems, Packed, true> as() const 356 { 357 static_assert((Packed && NumElems <= NumBits) || 358 (!Packed && 359 NumBits % sizeof(VecElem) == 0 && 360 sizeof(VecElem) * NumElems <= NumBits), 361 "Container size incompatible with view size"); 362 return VecPredRegT<VecElem, NumElems, Packed, true>(*this); 363 } 364 365 template <typename VecElem, 366 size_t NumElems = (Packed ? NumBits : NumBits / sizeof(VecElem))> 367 VecPredRegT<VecElem, NumElems, Packed, false> as() 368 { 369 static_assert((Packed && NumElems <= NumBits) || 370 (!Packed && 371 NumBits % sizeof(VecElem) == 0 && 372 sizeof(VecElem) * NumElems <= NumBits), 373 "Container size incompatible with view size"); 374 return VecPredRegT<VecElem, NumElems, Packed, false>(*this); 375 } 376 /// @} 377}; 378 379/// Helper functions used for serialization/de-serialization 380template <size_t NumBits, bool Packed> 381inline bool 382to_number(const std::string& value, VecPredRegContainer<NumBits, Packed>& p) 383{ 384 int i = 0; 385 for (const auto& c: value) { 386 p[i] = (c == '1'); 387 } 388 return true; 389} 390 391/// Dummy type aliases and constants for architectures that do not implement 392/// vector predicate registers. 393/// @{ 394constexpr bool DummyVecPredRegHasPackedRepr = false; 395using DummyVecPredReg = VecPredRegT<DummyVecElem, DummyNumVecElemPerVecReg, 396 DummyVecPredRegHasPackedRepr, false>; 397using DummyConstVecPredReg = VecPredRegT<DummyVecElem, 398 DummyNumVecElemPerVecReg, 399 DummyVecPredRegHasPackedRepr, true>; 400using DummyVecPredRegContainer = DummyVecPredReg::Container; 401constexpr size_t DummyVecPredRegSizeBits = 8; 402/// @} 403 404#endif // __ARCH_GENERIC_VEC_PRED_REG_HH__ 405