| // Copyright (c) 2017 ARM Limited | |
| // All rights reserved | |
| // | |
| // The license below extends only to copyright in the software and shall | |
| // not be construed as granting a license to any other intellectual | |
| // property including but not limited to intellectual property relating | |
| // to a hardware implementation of the functionality of the software | |
| // licensed hereunder. You may use the software subject to the license | |
| // terms below provided that you ensure that this notice is replicated | |
| // unmodified and in its entirety in all distributions of the software, | |
| // modified or unmodified, in source code or in binary form. | |
| // | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions are | |
| // met: redistributions of source code must retain the above copyright | |
| // notice, this list of conditions and the following disclaimer; | |
| // redistributions in binary form must reproduce the above copyright | |
| // notice, this list of conditions and the following disclaimer in the | |
| // documentation and/or other materials provided with the distribution; | |
| // neither the name of the copyright holders nor the names of its | |
| // contributors may be used to endorse or promote products derived from | |
| // this software without specific prior written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| // | |
| // Authors: Giacomo Gabrielli | |
| // Rekai Gonzalez | |
| // Javier Setoain | |
| #ifndef __ARCH_GENERIC_VEC_PRED_REG_HH__ | |
| #define __ARCH_GENERIC_VEC_PRED_REG_HH__ | |
| #include <array> | |
| #include <cassert> | |
| #include <vector> | |
| #include "arch/generic/vec_reg.hh" | |
| #include "base/cprintf.hh" | |
| template <size_t NumBits, bool Packed> | |
| class VecPredRegContainer; | |
| /// Predicate register view. | |
| /// | |
| /// This generic class implements the View in an MVC pattern, similarly to | |
| /// @see VecRegT. Since predicates are mainly used in conjunction with vectors | |
| /// to specify which lanes are active in a vector operation, the class is | |
| /// templated on the vector element type to simplify ISA definitions. | |
| /// @tparam VecElem Type of the vector elements. | |
| /// @tparam NumElems Number of vector elements making up the view. | |
| /// @tparam Packed True if the predicate register relies on a packed | |
| /// representation, i.e. adjacent bits refer to different vector elements | |
| /// irrespective of the vector element size (e.g. this is the case for | |
| /// AVX-512). If false, the predicate register relies on an unpacked | |
| /// representation, where each bit refers to the corresponding byte in a vector | |
| /// register (e.g. this is the case for ARM SVE). | |
| /// @tparam Const True if the underlying container can be modified through | |
| /// the view. | |
| template <typename VecElem, size_t NumElems, bool Packed, bool Const> | |
| class VecPredRegT | |
| { | |
| protected: | |
| /// Size of the register in bits. | |
| static constexpr size_t NUM_BITS = Packed ? NumElems : | |
| sizeof(VecElem) * NumElems; | |
| public: | |
| /// Container type alias. | |
| using Container = typename std::conditional< | |
| Const, | |
| const VecPredRegContainer<NUM_BITS, Packed>, | |
| VecPredRegContainer<NUM_BITS, Packed>>::type; | |
| protected: | |
| // Alias for this type | |
| using MyClass = VecPredRegT<VecElem, NumElems, Packed, Const>; | |
| /// Container corresponding to this view. | |
| Container& container; | |
| public: | |
| VecPredRegT(Container& c) : container(c) {} | |
| /// Reset the register to an all-false value. | |
| template<bool Condition = !Const> | |
| typename std::enable_if<Condition, void>::type | |
| reset() { container.reset(); } | |
| /// Reset the register to an all-true value. | |
| template<bool Condition = !Const> | |
| typename std::enable_if<Condition, void>::type | |
| set() { container.set(); } | |
| template<bool Condition = !Const> | |
| typename std::enable_if<Condition, MyClass&>::type | |
| operator=(const MyClass& that) | |
| { | |
| container = that.container; | |
| return *this; | |
| } | |
| const bool& | |
| operator[](size_t idx) const | |
| { | |
| return container[idx * (Packed ? 1 : sizeof(VecElem))]; | |
| } | |
| template<bool Condition = !Const> | |
| typename std::enable_if<Condition, bool&>::type | |
| operator[](size_t idx) | |
| { | |
| return container[idx * (Packed ? 1 : sizeof(VecElem))]; | |
| } | |
| /// Return an element of the predicate register as it appears | |
| /// in the raw (untyped) internal representation | |
| uint8_t | |
| get_raw(size_t idx) const | |
| { | |
| return container.get_bits(idx * (Packed ? 1 : sizeof(VecElem)), | |
| (Packed ? 1 : sizeof(VecElem))); | |
| } | |
| /// Write a raw value in an element of the predicate register | |
| template<bool Condition = !Const> | |
| typename std::enable_if<Condition, void>::type | |
| set_raw(size_t idx, uint8_t val) | |
| { | |
| container.set_bits(idx * (Packed ? 1 : sizeof(VecElem)), | |
| (Packed ? 1 : sizeof(VecElem)), val); | |
| } | |
| /// Equality operator, required to compare thread contexts. | |
| template<typename VE2, size_t NE2, bool P2, bool C2> | |
| bool | |
| operator==(const VecPredRegT<VE2, NE2, P2, C2>& that) const | |
| { | |
| return container == that.container; | |
| } | |
| /// Inequality operator, required to compare thread contexts. | |
| template<typename VE2, size_t NE2, bool P2, bool C2> | |
| bool | |
| operator!=(const VecPredRegT<VE2, NE2, P2, C2>& that) const | |
| { | |
| return !operator==(that); | |
| } | |
| friend std::ostream& | |
| operator<<(std::ostream& os, const MyClass& p) | |
| { | |
| // 0-sized is not allowed | |
| os << '[' << p.container[0]; | |
| for (int i = 0; i < p.NUM_BITS; ++i) { | |
| os << " " << (p.container[i] ? 1 : 0); | |
| } | |
| os << ']'; | |
| return os; | |
| } | |
| /// Returns a string representation of the register content. | |
| const std::string print() const { return csprintf("%s", *this); } | |
| /// Returns true if the first active element of the register is true. | |
| /// @param mask Input mask used to filter the predicates to be tested. | |
| /// @param actual_num_elems Actual number of vector elements considered for | |
| /// the test (corresponding to the current vector length). | |
| template <bool MC> | |
| bool | |
| firstActive(const VecPredRegT<VecElem, NumElems, Packed, MC>& mask, | |
| size_t actual_num_elems) const | |
| { | |
| assert(actual_num_elems <= NumElems); | |
| for (int i = 0; i < actual_num_elems; ++i) { | |
| if (mask[i]) { | |
| return (*this)[i]; | |
| } | |
| } | |
| return false; | |
| } | |
| /// Returns true if there are no active elements in the register. | |
| /// @param mask Input mask used to filter the predicates to be tested. | |
| /// @param actual_num_elems Actual number of vector elements considered for | |
| /// the test (corresponding to the current vector length). | |
| template <bool MC> | |
| bool | |
| noneActive(const VecPredRegT<VecElem, NumElems, Packed, MC>& mask, | |
| size_t actual_num_elems) const | |
| { | |
| assert(actual_num_elems <= NumElems); | |
| for (int i = 0; i < actual_num_elems; ++i) { | |
| if (mask[i] && operator[](i)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /// Returns true if the last active element of the register is true. | |
| /// @param mask Input mask used to filter the predicates to be tested. | |
| /// @param actual_num_elems Actual number of vector elements considered for | |
| /// the test (corresponding to the current vector length). | |
| template <bool MC> | |
| bool | |
| lastActive(const VecPredRegT<VecElem, NumElems, Packed, MC>& mask, | |
| size_t actual_num_elems) const | |
| { | |
| assert(actual_num_elems <= NumElems); | |
| for (int i = actual_num_elems - 1; i >= 0; --i) { | |
| if (mask[i]) { | |
| return operator[](i); | |
| } | |
| } | |
| return false; | |
| } | |
| }; | |
| /// Generic predicate register container. | |
| /// | |
| /// This generic class implements the Model in an MVC pattern, similarly to | |
| /// @see VecRegContainer. | |
| /// @tparam NumBits Size of the container in bits. | |
| /// @tparam Packed See @VecRegT. | |
| template <size_t NumBits, bool Packed> | |
| class VecPredRegContainer | |
| { | |
| static_assert(NumBits > 0, | |
| "Size of a predicate register must be > 0"); | |
| public: | |
| static constexpr size_t NUM_BITS = NumBits; | |
| using Container = std::array<bool, NumBits>; | |
| private: | |
| Container container; | |
| // Alias for this type | |
| using MyClass = VecPredRegContainer<NumBits, Packed>; | |
| public: | |
| VecPredRegContainer() {} | |
| MyClass& | |
| operator=(const MyClass& that) | |
| { | |
| if (&that == this) | |
| return *this; | |
| container = that.container; | |
| return *this; | |
| } | |
| /// Required for de-serialization. | |
| MyClass& | |
| operator=(const std::vector<uint8_t>& that) | |
| { | |
| assert(that.size() == NUM_BITS); | |
| std::copy(that.begin(), that.end(), container.begin()); | |
| return *this; | |
| } | |
| /// Resets the predicate register to an all-false register. | |
| void | |
| reset() | |
| { | |
| container.fill(false); | |
| } | |
| /// Sets the predicate register to an all-true value. | |
| void | |
| set() | |
| { | |
| container.fill(true); | |
| } | |
| /// Equality operator, required to compare thread contexts. | |
| template<size_t N2, bool P2> | |
| inline bool | |
| operator==(const VecPredRegContainer<N2, P2>& that) const | |
| { | |
| return NumBits == N2 && Packed == P2 && container == that.container; | |
| } | |
| /// Inequality operator, required to compare thread contexts. | |
| template<size_t N2, bool P2> | |
| bool | |
| operator!=(const VecPredRegContainer<N2, P2>& that) const | |
| { | |
| return !operator==(that); | |
| } | |
| /// Returns a reference to a specific element of the internal container. | |
| bool& operator[](size_t idx) { return container[idx]; } | |
| /// Returns a const reference to a specific element of the internal | |
| /// container. | |
| const bool& operator[](size_t idx) const { return container[idx]; } | |
| /// Returns a subset of bits starting from a specific element in the | |
| /// container. | |
| uint8_t | |
| get_bits(size_t idx, uint8_t nbits) const | |
| { | |
| assert(nbits > 0 && nbits <= 8 && (idx + nbits - 1) < NumBits); | |
| uint8_t v = 0; | |
| idx = idx + nbits - 1; | |
| for (int i = 0; i < nbits; ++i, --idx) { | |
| v <<= 1; | |
| v |= container[idx]; | |
| } | |
| return v; | |
| } | |
| /// Set a subset of bits starting from a specific element in the | |
| /// container. | |
| void | |
| set_bits(size_t idx, uint8_t nbits, uint8_t bval) | |
| { | |
| assert(nbits > 0 && nbits <= 8 && (idx + nbits - 1) < NumBits); | |
| for (int i = 0; i < nbits; ++i, ++idx) { | |
| container[idx] = bval & 1; | |
| bval >>= 1; | |
| } | |
| } | |
| /// Returns a string representation of the register content. | |
| const std::string print() const { return csprintf("%s", *this); } | |
| friend std::ostream& | |
| operator<<(std::ostream& os, const MyClass& v) | |
| { | |
| for (auto b: v.container) { | |
| os << csprintf("%d", b); | |
| } | |
| return os; | |
| } | |
| /// Create a view of this container. | |
| /// | |
| /// If NumElems is provided, the size of the container is bounds-checked, | |
| /// otherwise the size is inferred from the container size. | |
| /// @tparam VecElem Type of the vector elements. | |
| /// @tparam NumElems Number of vector elements making up the view. | |
| /// @{ | |
| template <typename VecElem, | |
| size_t NumElems = (Packed ? NumBits : NumBits / sizeof(VecElem))> | |
| VecPredRegT<VecElem, NumElems, Packed, true> as() const | |
| { | |
| static_assert((Packed && NumElems <= NumBits) || | |
| (!Packed && | |
| NumBits % sizeof(VecElem) == 0 && | |
| sizeof(VecElem) * NumElems <= NumBits), | |
| "Container size incompatible with view size"); | |
| return VecPredRegT<VecElem, NumElems, Packed, true>(*this); | |
| } | |
| template <typename VecElem, | |
| size_t NumElems = (Packed ? NumBits : NumBits / sizeof(VecElem))> | |
| VecPredRegT<VecElem, NumElems, Packed, false> as() | |
| { | |
| static_assert((Packed && NumElems <= NumBits) || | |
| (!Packed && | |
| NumBits % sizeof(VecElem) == 0 && | |
| sizeof(VecElem) * NumElems <= NumBits), | |
| "Container size incompatible with view size"); | |
| return VecPredRegT<VecElem, NumElems, Packed, false>(*this); | |
| } | |
| /// @} | |
| }; | |
| /// Helper functions used for serialization/de-serialization | |
| template <size_t NumBits, bool Packed> | |
| inline bool | |
| to_number(const std::string& value, VecPredRegContainer<NumBits, Packed>& p) | |
| { | |
| int i = 0; | |
| for (const auto& c: value) { | |
| p[i] = (c == '1'); | |
| } | |
| return true; | |
| } | |
| /// Dummy type aliases and constants for architectures that do not implement | |
| /// vector predicate registers. | |
| /// @{ | |
| constexpr bool DummyVecPredRegHasPackedRepr = false; | |
| using DummyVecPredReg = VecPredRegT<DummyVecElem, DummyNumVecElemPerVecReg, | |
| DummyVecPredRegHasPackedRepr, false>; | |
| using DummyConstVecPredReg = VecPredRegT<DummyVecElem, | |
| DummyNumVecElemPerVecReg, | |
| DummyVecPredRegHasPackedRepr, true>; | |
| using DummyVecPredRegContainer = DummyVecPredReg::Container; | |
| constexpr size_t DummyVecPredRegSizeBits = 8; | |
| /// @} | |
| #endif // __ARCH_GENERIC_VEC_PRED_REG_HH__ |