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