vec_pred_reg.hh revision 13610
112855Sgabeblack@google.com// Copyright (c) 2017 ARM Limited 212855Sgabeblack@google.com// All rights reserved 312855Sgabeblack@google.com// 412855Sgabeblack@google.com// The license below extends only to copyright in the software and shall 512855Sgabeblack@google.com// not be construed as granting a license to any other intellectual 612855Sgabeblack@google.com// property including but not limited to intellectual property relating 712855Sgabeblack@google.com// to a hardware implementation of the functionality of the software 812855Sgabeblack@google.com// licensed hereunder. You may use the software subject to the license 912855Sgabeblack@google.com// terms below provided that you ensure that this notice is replicated 1012855Sgabeblack@google.com// unmodified and in its entirety in all distributions of the software, 1112855Sgabeblack@google.com// modified or unmodified, in source code or in binary form. 1212855Sgabeblack@google.com// 1312855Sgabeblack@google.com// Redistribution and use in source and binary forms, with or without 1412855Sgabeblack@google.com// modification, are permitted provided that the following conditions are 1512855Sgabeblack@google.com// met: redistributions of source code must retain the above copyright 1612855Sgabeblack@google.com// notice, this list of conditions and the following disclaimer; 1712855Sgabeblack@google.com// redistributions in binary form must reproduce the above copyright 1812855Sgabeblack@google.com// notice, this list of conditions and the following disclaimer in the 1912855Sgabeblack@google.com// documentation and/or other materials provided with the distribution; 2012855Sgabeblack@google.com// neither the name of the copyright holders nor the names of its 2112855Sgabeblack@google.com// contributors may be used to endorse or promote products derived from 2212855Sgabeblack@google.com// this software without specific prior written permission. 2312855Sgabeblack@google.com// 2412855Sgabeblack@google.com// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2512855Sgabeblack@google.com// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2612855Sgabeblack@google.com// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2712855Sgabeblack@google.com// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2812855Sgabeblack@google.com// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2912855Sgabeblack@google.com// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3012855Sgabeblack@google.com// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3112855Sgabeblack@google.com// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3212855Sgabeblack@google.com// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3312855Sgabeblack@google.com// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3412855Sgabeblack@google.com// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3512855Sgabeblack@google.com// 3612855Sgabeblack@google.com// Authors: Giacomo Gabrielli 3712855Sgabeblack@google.com// Rekai Gonzalez 3812855Sgabeblack@google.com// Javier Setoain 3912855Sgabeblack@google.com 4012855Sgabeblack@google.com#ifndef __ARCH_GENERIC_VEC_PRED_REG_HH__ 4112855Sgabeblack@google.com#define __ARCH_GENERIC_VEC_PRED_REG_HH__ 4212855Sgabeblack@google.com 4312855Sgabeblack@google.com#include <array> 4412855Sgabeblack@google.com#include <cassert> 4512855Sgabeblack@google.com#include <vector> 4612855Sgabeblack@google.com 4712855Sgabeblack@google.com#include "arch/generic/vec_reg.hh" 4812855Sgabeblack@google.com#include "base/cprintf.hh" 4912855Sgabeblack@google.com 5012855Sgabeblack@google.comtemplate <size_t NumBits, bool Packed> 5112855Sgabeblack@google.comclass VecPredRegContainer; 5212855Sgabeblack@google.com 5312855Sgabeblack@google.com/// Predicate register view. 5412855Sgabeblack@google.com/// 5512855Sgabeblack@google.com/// This generic class implements the View in an MVC pattern, similarly to 5612855Sgabeblack@google.com/// @see VecRegT. Since predicates are mainly used in conjunction with vectors 5712855Sgabeblack@google.com/// to specify which lanes are active in a vector operation, the class is 5812855Sgabeblack@google.com/// templated on the vector element type to simplify ISA definitions. 5912855Sgabeblack@google.com/// @tparam VecElem Type of the vector elements. 6012855Sgabeblack@google.com/// @tparam NumElems Number of vector elements making up the view. 6112855Sgabeblack@google.com/// @tparam Packed True if the predicate register relies on a packed 6212855Sgabeblack@google.com/// representation, i.e. adjacent bits refer to different vector elements 6312855Sgabeblack@google.com/// irrespective of the vector element size (e.g. this is the case for 6412855Sgabeblack@google.com/// AVX-512). If false, the predicate register relies on an unpacked 6512855Sgabeblack@google.com/// representation, where each bit refers to the corresponding byte in a vector 6612855Sgabeblack@google.com/// register (e.g. this is the case for ARM SVE). 6712855Sgabeblack@google.com/// @tparam Const True if the underlying container can be modified through 6812855Sgabeblack@google.com/// the view. 6912855Sgabeblack@google.comtemplate <typename VecElem, size_t NumElems, bool Packed, bool Const> 7012855Sgabeblack@google.comclass VecPredRegT 7112855Sgabeblack@google.com{ 7212855Sgabeblack@google.com protected: 7312855Sgabeblack@google.com /// Size of the register in bits. 7412855Sgabeblack@google.com static constexpr size_t NUM_BITS = Packed ? NumElems : 7512855Sgabeblack@google.com sizeof(VecElem) * NumElems; 7612855Sgabeblack@google.com 7712855Sgabeblack@google.com public: 7812855Sgabeblack@google.com /// Container type alias. 7912855Sgabeblack@google.com using Container = typename std::conditional< 8012855Sgabeblack@google.com Const, 8112855Sgabeblack@google.com const VecPredRegContainer<NUM_BITS, Packed>, 8212855Sgabeblack@google.com VecPredRegContainer<NUM_BITS, Packed>>::type; 8312855Sgabeblack@google.com 8412855Sgabeblack@google.com protected: 8512855Sgabeblack@google.com // Alias for this type 8612855Sgabeblack@google.com using MyClass = VecPredRegT<VecElem, NumElems, Packed, Const>; 8712855Sgabeblack@google.com /// Container corresponding to this view. 8812855Sgabeblack@google.com Container& container; 8912855Sgabeblack@google.com 9012855Sgabeblack@google.com public: 9112855Sgabeblack@google.com VecPredRegT(Container& c) : container(c) {} 9212855Sgabeblack@google.com 9312855Sgabeblack@google.com /// Reset the register to an all-false value. 9412855Sgabeblack@google.com template<bool Condition = !Const> 9512855Sgabeblack@google.com typename std::enable_if<Condition, void>::type 9612855Sgabeblack@google.com reset() { container.reset(); } 9712855Sgabeblack@google.com 9812855Sgabeblack@google.com /// Reset the register to an all-true value. 9912855Sgabeblack@google.com template<bool Condition = !Const> 10012855Sgabeblack@google.com typename std::enable_if<Condition, void>::type 10112855Sgabeblack@google.com set() { container.set(); } 10212855Sgabeblack@google.com 10312855Sgabeblack@google.com template<bool Condition = !Const> 10412855Sgabeblack@google.com typename std::enable_if<Condition, MyClass&>::type 10512855Sgabeblack@google.com operator=(const MyClass& that) 10612855Sgabeblack@google.com { 10712855Sgabeblack@google.com container = that.container; 10812855Sgabeblack@google.com return *this; 10912855Sgabeblack@google.com } 11012855Sgabeblack@google.com 11112855Sgabeblack@google.com const bool& 11212855Sgabeblack@google.com 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