112108SRekai.GonzalezAlberquilla@arm.com/*
213759Sgiacomo.gabrielli@arm.com * Copyright (c) 2015-2018 ARM Limited
312108SRekai.GonzalezAlberquilla@arm.com * All rights reserved
412108SRekai.GonzalezAlberquilla@arm.com *
512108SRekai.GonzalezAlberquilla@arm.com * The license below extends only to copyright in the software and shall
612108SRekai.GonzalezAlberquilla@arm.com * not be construed as granting a license to any other intellectual
712108SRekai.GonzalezAlberquilla@arm.com * property including but not limited to intellectual property relating
812108SRekai.GonzalezAlberquilla@arm.com * to a hardware implementation of the functionality of the software
912108SRekai.GonzalezAlberquilla@arm.com * licensed hereunder.  You may use the software subject to the license
1012108SRekai.GonzalezAlberquilla@arm.com * terms below provided that you ensure that this notice is replicated
1112108SRekai.GonzalezAlberquilla@arm.com * unmodified and in its entirety in all distributions of the software,
1212108SRekai.GonzalezAlberquilla@arm.com * modified or unmodified, in source code or in binary form.
1312108SRekai.GonzalezAlberquilla@arm.com *
1412108SRekai.GonzalezAlberquilla@arm.com * Redistribution and use in source and binary forms, with or without
1512108SRekai.GonzalezAlberquilla@arm.com * modification, are permitted provided that the following conditions are
1612108SRekai.GonzalezAlberquilla@arm.com * met: redistributions of source code must retain the above copyright
1712108SRekai.GonzalezAlberquilla@arm.com * notice, this list of conditions and the following disclaimer;
1812108SRekai.GonzalezAlberquilla@arm.com * redistributions in binary form must reproduce the above copyright
1912108SRekai.GonzalezAlberquilla@arm.com * notice, this list of conditions and the following disclaimer in the
2012108SRekai.GonzalezAlberquilla@arm.com * documentation and/or other materials provided with the distribution;
2112108SRekai.GonzalezAlberquilla@arm.com * neither the name of the copyright holders nor the names of its
2212108SRekai.GonzalezAlberquilla@arm.com * contributors may be used to endorse or promote products derived from
2312108SRekai.GonzalezAlberquilla@arm.com * this software without specific prior written permission.
2412108SRekai.GonzalezAlberquilla@arm.com *
2512108SRekai.GonzalezAlberquilla@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2612108SRekai.GonzalezAlberquilla@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2712108SRekai.GonzalezAlberquilla@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2812108SRekai.GonzalezAlberquilla@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2912108SRekai.GonzalezAlberquilla@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3012108SRekai.GonzalezAlberquilla@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3112108SRekai.GonzalezAlberquilla@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3212108SRekai.GonzalezAlberquilla@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3312108SRekai.GonzalezAlberquilla@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3412108SRekai.GonzalezAlberquilla@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3512108SRekai.GonzalezAlberquilla@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3612108SRekai.GonzalezAlberquilla@arm.com *
3712108SRekai.GonzalezAlberquilla@arm.com * Authors: Giacomo Gabrielli
3812108SRekai.GonzalezAlberquilla@arm.com *          Nathanael Premillieu
3912108SRekai.GonzalezAlberquilla@arm.com *          Rekai Gonzalez
4012108SRekai.GonzalezAlberquilla@arm.com */
4112108SRekai.GonzalezAlberquilla@arm.com
4212108SRekai.GonzalezAlberquilla@arm.com/** \file arch/generic/vec_reg.hh
4312108SRekai.GonzalezAlberquilla@arm.com * Vector Registers layout specification.
4412108SRekai.GonzalezAlberquilla@arm.com *
4512108SRekai.GonzalezAlberquilla@arm.com * This register type is to be used to model the SIMD registers.
4612108SRekai.GonzalezAlberquilla@arm.com * It takes into account the possibility that different architectural names
4712108SRekai.GonzalezAlberquilla@arm.com * may overlap (like for ARMv8 AArch32 for example).
4812108SRekai.GonzalezAlberquilla@arm.com *
4912108SRekai.GonzalezAlberquilla@arm.com * The design is having a basic vector register container that holds the
5012108SRekai.GonzalezAlberquilla@arm.com * bytes, unaware of anything else. This is implemented by VecRegContainer.
5112108SRekai.GonzalezAlberquilla@arm.com * As the (maximum) length of the physical vector register is a compile-time
5212108SRekai.GonzalezAlberquilla@arm.com * constant, it is defined as a template parameter.
5312108SRekai.GonzalezAlberquilla@arm.com *
5412108SRekai.GonzalezAlberquilla@arm.com * This file also describes two views of the container that have semantic
5512108SRekai.GonzalezAlberquilla@arm.com * information about the bytes. The first of this views is VecRegT.
5612108SRekai.GonzalezAlberquilla@arm.com *    A VecRegT is a view of a VecRegContainer (by reference). The VecRegT has
5712108SRekai.GonzalezAlberquilla@arm.com *    a type (VecElem) to which bytes are casted, and the amount of such
5812108SRekai.GonzalezAlberquilla@arm.com *    elements that the vector contains (NumElems). The size of a view,
5912108SRekai.GonzalezAlberquilla@arm.com *    calculated as sizeof(VecElem) * NumElems must match the size of the
6012108SRekai.GonzalezAlberquilla@arm.com *    underlying container. As VecRegT has some degree of type information it
6112108SRekai.GonzalezAlberquilla@arm.com *    has vector semantics, and defines the index operator ([]) to get
6212108SRekai.GonzalezAlberquilla@arm.com *    references to particular bytes understood as a VecElem.
6312108SRekai.GonzalezAlberquilla@arm.com * The second view of a container implemented in this file is VecLaneT, which
6412108SRekai.GonzalezAlberquilla@arm.com * is a view of a subset of the container.
6512108SRekai.GonzalezAlberquilla@arm.com *    A VecLaneT is a view of a lane of a vector register, where a lane is
6612108SRekai.GonzalezAlberquilla@arm.com *    identified by a type (VecElem) and an index (although the view is
6712108SRekai.GonzalezAlberquilla@arm.com *    unaware of its index). Operations on the lane are directly applied to
6812108SRekai.GonzalezAlberquilla@arm.com *    the corresponding bytes of the underlying VecRegContainer through a
6912108SRekai.GonzalezAlberquilla@arm.com *    reference.
7012108SRekai.GonzalezAlberquilla@arm.com *
7112108SRekai.GonzalezAlberquilla@arm.com * The intended usage is requesting views to the VecRegContainer via the
7212108SRekai.GonzalezAlberquilla@arm.com * member 'as' for VecRegT and the member 'laneView' for VecLaneT. Kindly
7312108SRekai.GonzalezAlberquilla@arm.com * find an example of usage in the following.
7412108SRekai.GonzalezAlberquilla@arm.com *
7512108SRekai.GonzalezAlberquilla@arm.com *
7612108SRekai.GonzalezAlberquilla@arm.com * // We declare 512 bits vectors
7712108SRekai.GonzalezAlberquilla@arm.com * using Vec512 = VecRegContainer<64>;
7812108SRekai.GonzalezAlberquilla@arm.com * ...
7912108SRekai.GonzalezAlberquilla@arm.com * // We implement the physical vector register file
8012108SRekai.GonzalezAlberquilla@arm.com * Vec512 physicalVecRegFile[NUM_VREGS];
8112108SRekai.GonzalezAlberquilla@arm.com * ...
8212108SRekai.GonzalezAlberquilla@arm.com * // Usage example, for a macro op:
8312108SRekai.GonzalezAlberquilla@arm.com * VecFloat8Add(ExecContext* xd) {
8412108SRekai.GonzalezAlberquilla@arm.com *    // Request source vector register to the execution context (const as it
8512108SRekai.GonzalezAlberquilla@arm.com *    // is read only).
8612108SRekai.GonzalezAlberquilla@arm.com *    const Vec512& vsrc1raw = xc->readVecRegOperand(this, 0);
8712108SRekai.GonzalezAlberquilla@arm.com *    // View it as a vector of floats (we could just specify the first
8812108SRekai.GonzalezAlberquilla@arm.com *    // template parametre, the second has a default value that works, and the
8912108SRekai.GonzalezAlberquilla@arm.com *    // last one is derived by the constness of vsrc1raw).
9012108SRekai.GonzalezAlberquilla@arm.com *    VecRegT<float, 8, true>& vsrc1 = vsrc1raw->as<float, 8>();
9112108SRekai.GonzalezAlberquilla@arm.com *
9212108SRekai.GonzalezAlberquilla@arm.com *    // Second source and view
9312108SRekai.GonzalezAlberquilla@arm.com *    const Vec512& vsrc2raw = xc->readVecRegOperand(this, 1);
9412108SRekai.GonzalezAlberquilla@arm.com *    VecRegT<float, 8, true>& vsrc2 = vsrc2raw->as<float, 8>();
9512108SRekai.GonzalezAlberquilla@arm.com *
9612108SRekai.GonzalezAlberquilla@arm.com *    // Destination and view
9712108SRekai.GonzalezAlberquilla@arm.com *    Vec512 vdstraw;
9812108SRekai.GonzalezAlberquilla@arm.com *    VecRegT<float, 8, false>& vdst = vdstraw->as<float, 8>();
9912108SRekai.GonzalezAlberquilla@arm.com *
10012108SRekai.GonzalezAlberquilla@arm.com *    for (auto i = 0; i < 8; i++) {
10112108SRekai.GonzalezAlberquilla@arm.com *        // This asignment sets the bits in the underlying Vec512: vdstraw
10212108SRekai.GonzalezAlberquilla@arm.com *        vdst[i] = vsrc1[i] + vsrc2[i];
10312108SRekai.GonzalezAlberquilla@arm.com *    }
10412108SRekai.GonzalezAlberquilla@arm.com *    xc->setWriteRegOperand(this, 0, vdstraw);
10512108SRekai.GonzalezAlberquilla@arm.com * }
10612108SRekai.GonzalezAlberquilla@arm.com *
10712108SRekai.GonzalezAlberquilla@arm.com * // Usage example, for a micro op that operates over lane number _lidx:
10812108SRekai.GonzalezAlberquilla@arm.com * VecFloatLaneAdd(ExecContext* xd) {
10912108SRekai.GonzalezAlberquilla@arm.com *    // Request source vector register to the execution context (const as it
11012108SRekai.GonzalezAlberquilla@arm.com *    // is read only).
11112108SRekai.GonzalezAlberquilla@arm.com *    const Vec512& vsrc1raw = xc->readVecRegOperand(this, 0);
11212108SRekai.GonzalezAlberquilla@arm.com *    // View it as a lane of a vector of floats (we could just specify the
11312108SRekai.GonzalezAlberquilla@arm.com *    // first template parametre, the second is derived by the constness of
11412108SRekai.GonzalezAlberquilla@arm.com *    // vsrc1raw).
11512108SRekai.GonzalezAlberquilla@arm.com *    VecLaneT<float, true>& src1 = vsrc1raw->laneView<float>(this->_lidx);
11612108SRekai.GonzalezAlberquilla@arm.com *
11712108SRekai.GonzalezAlberquilla@arm.com *    // Second source and view
11812108SRekai.GonzalezAlberquilla@arm.com *    const Vec512& vsrc2raw = xc->readVecRegOperand(this, 1);
11912108SRekai.GonzalezAlberquilla@arm.com *    VecLaneT<float, true>& src2 = vsrc2raw->laneView<float>(this->_lidx);
12012108SRekai.GonzalezAlberquilla@arm.com *
12112108SRekai.GonzalezAlberquilla@arm.com *    // (Writable) destination and view
12212108SRekai.GonzalezAlberquilla@arm.com *    // As this is a partial write, we need the exec context to support that
12312108SRekai.GonzalezAlberquilla@arm.com *    // through, e.g., 'readVecRegOperandToWrite' returning a writable
12412108SRekai.GonzalezAlberquilla@arm.com *    // reference to the register
12512108SRekai.GonzalezAlberquilla@arm.com *    Vec512 vdstraw = xc->readVecRegOperandToWrite(this, 3);
12612108SRekai.GonzalezAlberquilla@arm.com *    VecLaneT<float, false>& dst = vdstraw->laneView<float>(this->_lidx);
12712108SRekai.GonzalezAlberquilla@arm.com *
12812108SRekai.GonzalezAlberquilla@arm.com *    dst = src1 + src2;
12912108SRekai.GonzalezAlberquilla@arm.com *    // There is no need to copy the value back into the exec context, as
13012108SRekai.GonzalezAlberquilla@arm.com *    // the assignment to dst modifies the appropriate bytes in vdstraw which
13112108SRekai.GonzalezAlberquilla@arm.com *    // is in turn, a reference to the register in the cpu model.
13212108SRekai.GonzalezAlberquilla@arm.com *    // For operations that do conditional writeback, we can decouple the
13312108SRekai.GonzalezAlberquilla@arm.com *    // write by doing:
13412108SRekai.GonzalezAlberquilla@arm.com *    //   auto tmp = src1 + src2;
13512108SRekai.GonzalezAlberquilla@arm.com *    //   if (test) {
13612108SRekai.GonzalezAlberquilla@arm.com *    //       dst = tmp; // do writeback
13712108SRekai.GonzalezAlberquilla@arm.com *    //   } else {
13812108SRekai.GonzalezAlberquilla@arm.com *    //      // do not do writeback
13912108SRekai.GonzalezAlberquilla@arm.com *    //   }
14012108SRekai.GonzalezAlberquilla@arm.com * }
14112108SRekai.GonzalezAlberquilla@arm.com *
14212108SRekai.GonzalezAlberquilla@arm.com */
14312108SRekai.GonzalezAlberquilla@arm.com
14412108SRekai.GonzalezAlberquilla@arm.com#ifndef __ARCH_GENERIC_VEC_REG_HH__
14512108SRekai.GonzalezAlberquilla@arm.com#define __ARCH_GENERIC_VEC_REG_HH__
14612108SRekai.GonzalezAlberquilla@arm.com
14712108SRekai.GonzalezAlberquilla@arm.com#include <array>
14812108SRekai.GonzalezAlberquilla@arm.com#include <cassert>
14912108SRekai.GonzalezAlberquilla@arm.com#include <iostream>
15012108SRekai.GonzalezAlberquilla@arm.com#include <string>
15112108SRekai.GonzalezAlberquilla@arm.com#include <type_traits>
15212108SRekai.GonzalezAlberquilla@arm.com#include <vector>
15312108SRekai.GonzalezAlberquilla@arm.com
15412108SRekai.GonzalezAlberquilla@arm.com#include "base/cprintf.hh"
15512334Sgabeblack@google.com#include "base/logging.hh"
15612108SRekai.GonzalezAlberquilla@arm.com
15714144Santhony.gutierrez@amd.comconstexpr unsigned MaxVecRegLenInBytes = 4096;
15813759Sgiacomo.gabrielli@arm.com
15912108SRekai.GonzalezAlberquilla@arm.comtemplate <size_t Sz>
16012108SRekai.GonzalezAlberquilla@arm.comclass VecRegContainer;
16112108SRekai.GonzalezAlberquilla@arm.com
16212108SRekai.GonzalezAlberquilla@arm.com/** Vector Register Abstraction
16312108SRekai.GonzalezAlberquilla@arm.com * This generic class is a view in a particularization of MVC, to vector
16412108SRekai.GonzalezAlberquilla@arm.com * registers. There is a VecRegContainer that implements the model, and
16512108SRekai.GonzalezAlberquilla@arm.com * contains the data. To that model we can interpose different instantiations
16612108SRekai.GonzalezAlberquilla@arm.com * of VecRegT to view the container as a vector of NumElems elems of type
16712108SRekai.GonzalezAlberquilla@arm.com * VecElem.
16812108SRekai.GonzalezAlberquilla@arm.com * @tparam VecElem Type of each element of the vector.
16912108SRekai.GonzalezAlberquilla@arm.com * @tparam NumElems Amount of components of the vector.
17012108SRekai.GonzalezAlberquilla@arm.com * @tparam Const Indicate if the underlying container can be modified through
17112108SRekai.GonzalezAlberquilla@arm.com * the view.
17212108SRekai.GonzalezAlberquilla@arm.com */
17312108SRekai.GonzalezAlberquilla@arm.comtemplate <typename VecElem, size_t NumElems, bool Const>
17412108SRekai.GonzalezAlberquilla@arm.comclass VecRegT
17512108SRekai.GonzalezAlberquilla@arm.com{
17612108SRekai.GonzalezAlberquilla@arm.com    /** Size of the register in bytes. */
17712108SRekai.GonzalezAlberquilla@arm.com    static constexpr size_t SIZE = sizeof(VecElem) * NumElems;
17812108SRekai.GonzalezAlberquilla@arm.com  public:
17912108SRekai.GonzalezAlberquilla@arm.com    /** Container type alias. */
18012108SRekai.GonzalezAlberquilla@arm.com    using Container = typename std::conditional<Const,
18112108SRekai.GonzalezAlberquilla@arm.com                                              const VecRegContainer<SIZE>,
18212108SRekai.GonzalezAlberquilla@arm.com                                              VecRegContainer<SIZE>>::type;
18312108SRekai.GonzalezAlberquilla@arm.com  private:
18412108SRekai.GonzalezAlberquilla@arm.com    /** My type alias. */
18512108SRekai.GonzalezAlberquilla@arm.com    using MyClass = VecRegT<VecElem, NumElems, Const>;
18612108SRekai.GonzalezAlberquilla@arm.com    /** Reference to container. */
18712108SRekai.GonzalezAlberquilla@arm.com    Container& container;
18812108SRekai.GonzalezAlberquilla@arm.com
18912108SRekai.GonzalezAlberquilla@arm.com  public:
19012108SRekai.GonzalezAlberquilla@arm.com    /** Constructor. */
19112108SRekai.GonzalezAlberquilla@arm.com    VecRegT(Container& cnt) : container(cnt) {};
19212108SRekai.GonzalezAlberquilla@arm.com
19312108SRekai.GonzalezAlberquilla@arm.com    /** Zero the container. */
19412108SRekai.GonzalezAlberquilla@arm.com    template<bool Condition = !Const>
19512108SRekai.GonzalezAlberquilla@arm.com    typename std::enable_if<Condition, void>::type
19612108SRekai.GonzalezAlberquilla@arm.com    zero() { container.zero(); }
19712108SRekai.GonzalezAlberquilla@arm.com
19812108SRekai.GonzalezAlberquilla@arm.com    template<bool Condition = !Const>
19912108SRekai.GonzalezAlberquilla@arm.com    typename std::enable_if<Condition, MyClass&>::type
20012108SRekai.GonzalezAlberquilla@arm.com    operator=(const MyClass& that)
20112108SRekai.GonzalezAlberquilla@arm.com    {
20212108SRekai.GonzalezAlberquilla@arm.com        container = that.container;
20312108SRekai.GonzalezAlberquilla@arm.com        return *this;
20412108SRekai.GonzalezAlberquilla@arm.com    }
20512108SRekai.GonzalezAlberquilla@arm.com
20612108SRekai.GonzalezAlberquilla@arm.com    /** Index operator. */
20712108SRekai.GonzalezAlberquilla@arm.com    const VecElem& operator[](size_t idx) const
20812108SRekai.GonzalezAlberquilla@arm.com    {
20912108SRekai.GonzalezAlberquilla@arm.com        return container.template raw_ptr<VecElem>()[idx];
21012108SRekai.GonzalezAlberquilla@arm.com    }
21112108SRekai.GonzalezAlberquilla@arm.com
21212108SRekai.GonzalezAlberquilla@arm.com    /** Index operator. */
21312108SRekai.GonzalezAlberquilla@arm.com    template<bool Condition = !Const>
21412108SRekai.GonzalezAlberquilla@arm.com    typename std::enable_if<Condition, VecElem&>::type
21512108SRekai.GonzalezAlberquilla@arm.com    operator[](size_t idx)
21612108SRekai.GonzalezAlberquilla@arm.com    {
21712108SRekai.GonzalezAlberquilla@arm.com        return container.template raw_ptr<VecElem>()[idx];
21812108SRekai.GonzalezAlberquilla@arm.com    }
21912108SRekai.GonzalezAlberquilla@arm.com
22012108SRekai.GonzalezAlberquilla@arm.com    /** Equality operator.
22112108SRekai.GonzalezAlberquilla@arm.com     * Required to compare thread contexts.
22212108SRekai.GonzalezAlberquilla@arm.com     */
22312108SRekai.GonzalezAlberquilla@arm.com    template<typename VE2, size_t NE2, bool C2>
22412108SRekai.GonzalezAlberquilla@arm.com    bool
22512108SRekai.GonzalezAlberquilla@arm.com    operator==(const VecRegT<VE2, NE2, C2>& that) const
22612108SRekai.GonzalezAlberquilla@arm.com    {
22712108SRekai.GonzalezAlberquilla@arm.com        return container == that.container;
22812108SRekai.GonzalezAlberquilla@arm.com    }
22912108SRekai.GonzalezAlberquilla@arm.com    /** Inequality operator.
23012108SRekai.GonzalezAlberquilla@arm.com     * Required to compare thread contexts.
23112108SRekai.GonzalezAlberquilla@arm.com     */
23212108SRekai.GonzalezAlberquilla@arm.com    template<typename VE2, size_t NE2, bool C2>
23312108SRekai.GonzalezAlberquilla@arm.com    bool
23412108SRekai.GonzalezAlberquilla@arm.com    operator!=(const VecRegT<VE2, NE2, C2>& that) const
23512108SRekai.GonzalezAlberquilla@arm.com    {
23612108SRekai.GonzalezAlberquilla@arm.com        return !operator==(that);
23712108SRekai.GonzalezAlberquilla@arm.com    }
23812108SRekai.GonzalezAlberquilla@arm.com
23912108SRekai.GonzalezAlberquilla@arm.com    /** Output stream operator. */
24012108SRekai.GonzalezAlberquilla@arm.com    friend std::ostream&
24112108SRekai.GonzalezAlberquilla@arm.com    operator<<(std::ostream& os, const MyClass& vr)
24212108SRekai.GonzalezAlberquilla@arm.com    {
24312108SRekai.GonzalezAlberquilla@arm.com        /* 0-sized is not allowed */
24412108SRekai.GonzalezAlberquilla@arm.com        os << "[" << std::hex << (uint32_t)vr[0];
24512108SRekai.GonzalezAlberquilla@arm.com        for (uint32_t e = 1; e < vr.SIZE; e++)
24612108SRekai.GonzalezAlberquilla@arm.com            os << " " << std::hex << (uint32_t)vr[e];
24712108SRekai.GonzalezAlberquilla@arm.com        os << ']';
24812108SRekai.GonzalezAlberquilla@arm.com        return os;
24912108SRekai.GonzalezAlberquilla@arm.com    }
25012108SRekai.GonzalezAlberquilla@arm.com
25112108SRekai.GonzalezAlberquilla@arm.com    const std::string print() const { return csprintf("%s", *this); }
25212108SRekai.GonzalezAlberquilla@arm.com    /**
25312108SRekai.GonzalezAlberquilla@arm.com     * Cast to VecRegContainer&
25412108SRekai.GonzalezAlberquilla@arm.com     * It is useful to get the reference to the container for ISA tricks,
25512108SRekai.GonzalezAlberquilla@arm.com     * because casting to reference prevents unnecessary copies.
25612108SRekai.GonzalezAlberquilla@arm.com     */
25712108SRekai.GonzalezAlberquilla@arm.com    operator Container&() { return container; }
25812108SRekai.GonzalezAlberquilla@arm.com};
25912108SRekai.GonzalezAlberquilla@arm.com
26012108SRekai.GonzalezAlberquilla@arm.com/* Forward declaration. */
26112108SRekai.GonzalezAlberquilla@arm.comtemplate <typename VecElem, bool Const>
26212108SRekai.GonzalezAlberquilla@arm.comclass VecLaneT;
26312108SRekai.GonzalezAlberquilla@arm.com
26412108SRekai.GonzalezAlberquilla@arm.com/**
26512108SRekai.GonzalezAlberquilla@arm.com * Vector Register Abstraction
26612108SRekai.GonzalezAlberquilla@arm.com * This generic class is the model in a particularization of MVC, to vector
26712108SRekai.GonzalezAlberquilla@arm.com * registers. The model has functionality to create views of itself, or a
26812108SRekai.GonzalezAlberquilla@arm.com * portion through the method 'as
26912108SRekai.GonzalezAlberquilla@arm.com * @tparam Sz Size of the container in bytes.
27012108SRekai.GonzalezAlberquilla@arm.com */
27112108SRekai.GonzalezAlberquilla@arm.comtemplate <size_t Sz>
27212108SRekai.GonzalezAlberquilla@arm.comclass VecRegContainer
27312108SRekai.GonzalezAlberquilla@arm.com{
27412108SRekai.GonzalezAlberquilla@arm.com  static_assert(Sz > 0,
27512108SRekai.GonzalezAlberquilla@arm.com          "Cannot create Vector Register Container of zero size");
27613759Sgiacomo.gabrielli@arm.com  static_assert(Sz <= MaxVecRegLenInBytes,
27713759Sgiacomo.gabrielli@arm.com          "Vector Register size limit exceeded");
27812108SRekai.GonzalezAlberquilla@arm.com  public:
27912108SRekai.GonzalezAlberquilla@arm.com    static constexpr size_t SIZE = Sz;
28012108SRekai.GonzalezAlberquilla@arm.com    using Container = std::array<uint8_t,Sz>;
28112108SRekai.GonzalezAlberquilla@arm.com  private:
28212108SRekai.GonzalezAlberquilla@arm.com    Container container;
28312108SRekai.GonzalezAlberquilla@arm.com    using MyClass = VecRegContainer<SIZE>;
28412108SRekai.GonzalezAlberquilla@arm.com
28512108SRekai.GonzalezAlberquilla@arm.com  public:
28612108SRekai.GonzalezAlberquilla@arm.com    VecRegContainer() {}
28712108SRekai.GonzalezAlberquilla@arm.com    /* This is required for de-serialisation. */
28812108SRekai.GonzalezAlberquilla@arm.com    VecRegContainer(const std::vector<uint8_t>& that)
28912108SRekai.GonzalezAlberquilla@arm.com    {
29012108SRekai.GonzalezAlberquilla@arm.com        assert(that.size() >= SIZE);
29112108SRekai.GonzalezAlberquilla@arm.com        std::memcpy(container.data(), &that[0], SIZE);
29212108SRekai.GonzalezAlberquilla@arm.com    }
29312108SRekai.GonzalezAlberquilla@arm.com
29412108SRekai.GonzalezAlberquilla@arm.com    /** Zero the container. */
29512108SRekai.GonzalezAlberquilla@arm.com    void zero() { memset(container.data(), 0, SIZE); }
29612108SRekai.GonzalezAlberquilla@arm.com
29712108SRekai.GonzalezAlberquilla@arm.com    /** Assignment operators. */
29812108SRekai.GonzalezAlberquilla@arm.com    /** @{ */
29912108SRekai.GonzalezAlberquilla@arm.com    /** From VecRegContainer */
30012108SRekai.GonzalezAlberquilla@arm.com    MyClass& operator=(const MyClass& that)
30112108SRekai.GonzalezAlberquilla@arm.com    {
30212108SRekai.GonzalezAlberquilla@arm.com        if (&that == this)
30312108SRekai.GonzalezAlberquilla@arm.com            return *this;
30412108SRekai.GonzalezAlberquilla@arm.com        memcpy(container.data(), that.container.data(), SIZE);
30512108SRekai.GonzalezAlberquilla@arm.com        return *this;
30612108SRekai.GonzalezAlberquilla@arm.com    }
30712108SRekai.GonzalezAlberquilla@arm.com
30812108SRekai.GonzalezAlberquilla@arm.com    /** From appropriately sized uint8_t[]. */
30912108SRekai.GonzalezAlberquilla@arm.com    MyClass& operator=(const Container& that)
31012108SRekai.GonzalezAlberquilla@arm.com    {
31112108SRekai.GonzalezAlberquilla@arm.com        std::memcpy(container.data(), that.data(), SIZE);
31212108SRekai.GonzalezAlberquilla@arm.com        return *this;
31312108SRekai.GonzalezAlberquilla@arm.com    }
31412108SRekai.GonzalezAlberquilla@arm.com
31512108SRekai.GonzalezAlberquilla@arm.com    /** From vector<uint8_t>.
31612108SRekai.GonzalezAlberquilla@arm.com     * This is required for de-serialisation.
31712108SRekai.GonzalezAlberquilla@arm.com     * */
31812108SRekai.GonzalezAlberquilla@arm.com    MyClass& operator=(const std::vector<uint8_t>& that)
31912108SRekai.GonzalezAlberquilla@arm.com    {
32012108SRekai.GonzalezAlberquilla@arm.com        assert(that.size() >= SIZE);
32112108SRekai.GonzalezAlberquilla@arm.com        std::memcpy(container.data(), that.data(), SIZE);
32212108SRekai.GonzalezAlberquilla@arm.com        return *this;
32312108SRekai.GonzalezAlberquilla@arm.com    }
32412108SRekai.GonzalezAlberquilla@arm.com    /** @} */
32512108SRekai.GonzalezAlberquilla@arm.com
32612108SRekai.GonzalezAlberquilla@arm.com    /** Copy the contents into the input buffer. */
32712108SRekai.GonzalezAlberquilla@arm.com    /** @{ */
32812108SRekai.GonzalezAlberquilla@arm.com    /** To appropriately sized uint8_t[] */
32912108SRekai.GonzalezAlberquilla@arm.com    void copyTo(Container& dst) const
33012108SRekai.GonzalezAlberquilla@arm.com    {
33112108SRekai.GonzalezAlberquilla@arm.com        std::memcpy(dst.data(), container.data(), SIZE);
33212108SRekai.GonzalezAlberquilla@arm.com    }
33312108SRekai.GonzalezAlberquilla@arm.com
33412108SRekai.GonzalezAlberquilla@arm.com    /** To vector<uint8_t>
33512108SRekai.GonzalezAlberquilla@arm.com     * This is required for serialisation.
33612108SRekai.GonzalezAlberquilla@arm.com     * */
33712108SRekai.GonzalezAlberquilla@arm.com    void copyTo(std::vector<uint8_t>& dst) const
33812108SRekai.GonzalezAlberquilla@arm.com    {
33912108SRekai.GonzalezAlberquilla@arm.com        dst.resize(SIZE);
34012108SRekai.GonzalezAlberquilla@arm.com        std::memcpy(dst.data(), container.data(), SIZE);
34112108SRekai.GonzalezAlberquilla@arm.com    }
34212108SRekai.GonzalezAlberquilla@arm.com    /** @} */
34312108SRekai.GonzalezAlberquilla@arm.com
34412108SRekai.GonzalezAlberquilla@arm.com    /** Equality operator.
34512108SRekai.GonzalezAlberquilla@arm.com     * Required to compare thread contexts.
34612108SRekai.GonzalezAlberquilla@arm.com     */
34712108SRekai.GonzalezAlberquilla@arm.com    template<size_t S2>
34812108SRekai.GonzalezAlberquilla@arm.com    inline bool
34912108SRekai.GonzalezAlberquilla@arm.com    operator==(const VecRegContainer<S2>& that) const
35012108SRekai.GonzalezAlberquilla@arm.com    {
35112108SRekai.GonzalezAlberquilla@arm.com        return SIZE == S2 &&
35212108SRekai.GonzalezAlberquilla@arm.com               !memcmp(container.data(), that.container.data(), SIZE);
35312108SRekai.GonzalezAlberquilla@arm.com    }
35412108SRekai.GonzalezAlberquilla@arm.com    /** Inequality operator.
35512108SRekai.GonzalezAlberquilla@arm.com     * Required to compare thread contexts.
35612108SRekai.GonzalezAlberquilla@arm.com     */
35712108SRekai.GonzalezAlberquilla@arm.com    template<size_t S2>
35812108SRekai.GonzalezAlberquilla@arm.com    bool
35912108SRekai.GonzalezAlberquilla@arm.com    operator!=(const VecRegContainer<S2>& that) const
36012108SRekai.GonzalezAlberquilla@arm.com    {
36112108SRekai.GonzalezAlberquilla@arm.com        return !operator==(that);
36212108SRekai.GonzalezAlberquilla@arm.com    }
36312108SRekai.GonzalezAlberquilla@arm.com
36412108SRekai.GonzalezAlberquilla@arm.com    const std::string print() const { return csprintf("%s", *this); }
36512108SRekai.GonzalezAlberquilla@arm.com    /** Get pointer to bytes. */
36612108SRekai.GonzalezAlberquilla@arm.com    template <typename Ret>
36712108SRekai.GonzalezAlberquilla@arm.com    const Ret* raw_ptr() const { return (const Ret*)container.data(); }
36812108SRekai.GonzalezAlberquilla@arm.com
36912108SRekai.GonzalezAlberquilla@arm.com    template <typename Ret>
37012108SRekai.GonzalezAlberquilla@arm.com    Ret* raw_ptr() { return (Ret*)container.data(); }
37112108SRekai.GonzalezAlberquilla@arm.com
37212108SRekai.GonzalezAlberquilla@arm.com    /**
37312108SRekai.GonzalezAlberquilla@arm.com     * View interposers.
37412108SRekai.GonzalezAlberquilla@arm.com     * Create a view of this container as a vector of VecElems with an
37512108SRekai.GonzalezAlberquilla@arm.com     * optional amount of elements. If the amount of elements is provided,
37612108SRekai.GonzalezAlberquilla@arm.com     * the size of the container is checked, to test bounds. If it is not
37712108SRekai.GonzalezAlberquilla@arm.com     * provided, the length is inferred from the container size and the
37812108SRekai.GonzalezAlberquilla@arm.com     * element size.
37912108SRekai.GonzalezAlberquilla@arm.com     * @tparam VecElem Type of each element of the vector for the view.
38012108SRekai.GonzalezAlberquilla@arm.com     * @tparam NumElem Amount of elements in the view.
38112108SRekai.GonzalezAlberquilla@arm.com     */
38212108SRekai.GonzalezAlberquilla@arm.com    /** @{ */
38312108SRekai.GonzalezAlberquilla@arm.com    template <typename VecElem, size_t NumElems = SIZE/sizeof(VecElem)>
38412108SRekai.GonzalezAlberquilla@arm.com    VecRegT<VecElem, NumElems, true> as() const
38512108SRekai.GonzalezAlberquilla@arm.com    {
38612108SRekai.GonzalezAlberquilla@arm.com        static_assert(SIZE % sizeof(VecElem) == 0,
38712108SRekai.GonzalezAlberquilla@arm.com                "VecElem does not evenly divide the register size");
38812108SRekai.GonzalezAlberquilla@arm.com        static_assert(sizeof(VecElem) * NumElems <= SIZE,
38912108SRekai.GonzalezAlberquilla@arm.com                "Viewing VecReg as something bigger than it is");
39012108SRekai.GonzalezAlberquilla@arm.com        return VecRegT<VecElem, NumElems, true>(*this);
39112108SRekai.GonzalezAlberquilla@arm.com    }
39212108SRekai.GonzalezAlberquilla@arm.com
39312108SRekai.GonzalezAlberquilla@arm.com    template <typename VecElem, size_t NumElems = SIZE/sizeof(VecElem)>
39412108SRekai.GonzalezAlberquilla@arm.com    VecRegT<VecElem, NumElems, false> as()
39512108SRekai.GonzalezAlberquilla@arm.com    {
39612108SRekai.GonzalezAlberquilla@arm.com        static_assert(SIZE % sizeof(VecElem) == 0,
39712108SRekai.GonzalezAlberquilla@arm.com                "VecElem does not evenly divide the register size");
39812108SRekai.GonzalezAlberquilla@arm.com        static_assert(sizeof(VecElem) * NumElems <= SIZE,
39912108SRekai.GonzalezAlberquilla@arm.com                "Viewing VecReg as something bigger than it is");
40012108SRekai.GonzalezAlberquilla@arm.com        return VecRegT<VecElem, NumElems, false>(*this);
40112108SRekai.GonzalezAlberquilla@arm.com    }
40212108SRekai.GonzalezAlberquilla@arm.com
40312108SRekai.GonzalezAlberquilla@arm.com    template <typename VecElem, int LaneIdx>
40412108SRekai.GonzalezAlberquilla@arm.com    VecLaneT<VecElem, false> laneView();
40512108SRekai.GonzalezAlberquilla@arm.com    template <typename VecElem, int LaneIdx>
40612108SRekai.GonzalezAlberquilla@arm.com    VecLaneT<VecElem, true> laneView() const;
40712108SRekai.GonzalezAlberquilla@arm.com    template <typename VecElem>
40812108SRekai.GonzalezAlberquilla@arm.com    VecLaneT<VecElem, false> laneView(int laneIdx);
40912108SRekai.GonzalezAlberquilla@arm.com    template <typename VecElem>
41012108SRekai.GonzalezAlberquilla@arm.com    VecLaneT<VecElem, true> laneView(int laneIdx) const;
41112108SRekai.GonzalezAlberquilla@arm.com    /** @} */
41212108SRekai.GonzalezAlberquilla@arm.com    /**
41312108SRekai.GonzalezAlberquilla@arm.com     * Output operator.
41412108SRekai.GonzalezAlberquilla@arm.com     * Used for serialization.
41512108SRekai.GonzalezAlberquilla@arm.com     */
41612108SRekai.GonzalezAlberquilla@arm.com    friend std::ostream& operator<<(std::ostream& os, const MyClass& v)
41712108SRekai.GonzalezAlberquilla@arm.com    {
41812108SRekai.GonzalezAlberquilla@arm.com        for (auto& b: v.container) {
41912108SRekai.GonzalezAlberquilla@arm.com            os << csprintf("%02x", b);
42012108SRekai.GonzalezAlberquilla@arm.com        }
42112108SRekai.GonzalezAlberquilla@arm.com        return os;
42212108SRekai.GonzalezAlberquilla@arm.com    }
42312108SRekai.GonzalezAlberquilla@arm.com};
42412108SRekai.GonzalezAlberquilla@arm.com
42512108SRekai.GonzalezAlberquilla@arm.com/** We define an auxiliary abstraction for LaneData. The ISA should care
42612108SRekai.GonzalezAlberquilla@arm.com * about the semantics of a, e.g., 32bit element, treating it as a signed or
42712108SRekai.GonzalezAlberquilla@arm.com * unsigned int, or a float depending on the semantics of a particular
42812108SRekai.GonzalezAlberquilla@arm.com * instruction. On the other hand, the cpu model should only care about it
42912108SRekai.GonzalezAlberquilla@arm.com * being a 32-bit value. */
43012108SRekai.GonzalezAlberquilla@arm.comenum class LaneSize
43112108SRekai.GonzalezAlberquilla@arm.com{
43212108SRekai.GonzalezAlberquilla@arm.com    Empty = 0,
43312108SRekai.GonzalezAlberquilla@arm.com    Byte,
43412108SRekai.GonzalezAlberquilla@arm.com    TwoByte,
43512108SRekai.GonzalezAlberquilla@arm.com    FourByte,
43612108SRekai.GonzalezAlberquilla@arm.com    EightByte,
43712108SRekai.GonzalezAlberquilla@arm.com};
43812108SRekai.GonzalezAlberquilla@arm.com
43912108SRekai.GonzalezAlberquilla@arm.com/** LaneSize is an abstraction of a LS byte value for the execution and thread
44012108SRekai.GonzalezAlberquilla@arm.com * contexts to handle values just depending on its width. That way, the ISA
44112108SRekai.GonzalezAlberquilla@arm.com * can request, for example, the second 4 byte lane of register 5 to the model.
44212108SRekai.GonzalezAlberquilla@arm.com * The model serves that value, agnostic of the semantics of those bits. Then,
44312108SRekai.GonzalezAlberquilla@arm.com * it is up to the ISA to interpret those bits as a float, or as an uint.
44412108SRekai.GonzalezAlberquilla@arm.com * To maximize the utility, this class implements the assignment operator and
44512108SRekai.GonzalezAlberquilla@arm.com * the casting to equal-size types.
44612108SRekai.GonzalezAlberquilla@arm.com * As opposed to a RegLaneT, LaneData is not 'backed' by a VecRegContainer.
44712108SRekai.GonzalezAlberquilla@arm.com * The idea is:
44812108SRekai.GonzalezAlberquilla@arm.com *  When data is passed and is susceptible to being copied, use LaneData, as
44912108SRekai.GonzalezAlberquilla@arm.com *     copying the primitive type is build on is cheap.
45012108SRekai.GonzalezAlberquilla@arm.com *  When data is passed as references (const or not), use RegLaneT, as all
45112108SRekai.GonzalezAlberquilla@arm.com *     operations happen 'in place', avoiding any copies (no copies is always
45212108SRekai.GonzalezAlberquilla@arm.com *     cheaper than cheap copies), especially when things are inlined, and
45312108SRekai.GonzalezAlberquilla@arm.com *     references are not explicitly passed.
45412108SRekai.GonzalezAlberquilla@arm.com */
45512108SRekai.GonzalezAlberquilla@arm.comtemplate <LaneSize LS>
45612108SRekai.GonzalezAlberquilla@arm.comclass LaneData
45712108SRekai.GonzalezAlberquilla@arm.com{
45812108SRekai.GonzalezAlberquilla@arm.com  public:
45912108SRekai.GonzalezAlberquilla@arm.com    /** Alias to the native type of the appropriate size. */
46012108SRekai.GonzalezAlberquilla@arm.com    using UnderlyingType =
46112108SRekai.GonzalezAlberquilla@arm.com        typename std::conditional<LS == LaneSize::EightByte, uint64_t,
46212108SRekai.GonzalezAlberquilla@arm.com            typename std::conditional<LS == LaneSize::FourByte, uint32_t,
46312108SRekai.GonzalezAlberquilla@arm.com                typename std::conditional<LS == LaneSize::TwoByte, uint16_t,
46412108SRekai.GonzalezAlberquilla@arm.com                    typename std::conditional<LS == LaneSize::Byte, uint8_t,
46512108SRekai.GonzalezAlberquilla@arm.com                    void>::type
46612108SRekai.GonzalezAlberquilla@arm.com                >::type
46712108SRekai.GonzalezAlberquilla@arm.com            >::type
46812108SRekai.GonzalezAlberquilla@arm.com        >::type;
46912108SRekai.GonzalezAlberquilla@arm.com  private:
47012108SRekai.GonzalezAlberquilla@arm.com    static constexpr auto ByteSz = sizeof(UnderlyingType);
47112108SRekai.GonzalezAlberquilla@arm.com    UnderlyingType _val;
47212108SRekai.GonzalezAlberquilla@arm.com    using MyClass = LaneData<LS>;
47312108SRekai.GonzalezAlberquilla@arm.com
47412108SRekai.GonzalezAlberquilla@arm.com  public:
47512108SRekai.GonzalezAlberquilla@arm.com    template <typename T> explicit
47612108SRekai.GonzalezAlberquilla@arm.com    LaneData(typename std::enable_if<sizeof(T) == ByteSz, const T&>::type t)
47712108SRekai.GonzalezAlberquilla@arm.com                : _val(t) {}
47812108SRekai.GonzalezAlberquilla@arm.com
47912108SRekai.GonzalezAlberquilla@arm.com    template <typename T>
48012108SRekai.GonzalezAlberquilla@arm.com    typename std::enable_if<sizeof(T) == ByteSz, MyClass&>::type
48112108SRekai.GonzalezAlberquilla@arm.com    operator=(const T& that)
48212108SRekai.GonzalezAlberquilla@arm.com    {
48312108SRekai.GonzalezAlberquilla@arm.com        _val = that;
48412108SRekai.GonzalezAlberquilla@arm.com        return *this;
48512108SRekai.GonzalezAlberquilla@arm.com    }
48612108SRekai.GonzalezAlberquilla@arm.com    template<typename T,
48712108SRekai.GonzalezAlberquilla@arm.com             typename std::enable_if<sizeof(T) == ByteSz, int>::type I = 0>
48812108SRekai.GonzalezAlberquilla@arm.com    operator T() const {
48912108SRekai.GonzalezAlberquilla@arm.com        return *static_cast<const T*>(&_val);
49012108SRekai.GonzalezAlberquilla@arm.com    }
49112108SRekai.GonzalezAlberquilla@arm.com};
49212108SRekai.GonzalezAlberquilla@arm.com
49312108SRekai.GonzalezAlberquilla@arm.com/** Output operator overload for LaneData<Size>. */
49412108SRekai.GonzalezAlberquilla@arm.comtemplate <LaneSize LS>
49512108SRekai.GonzalezAlberquilla@arm.cominline std::ostream&
49612108SRekai.GonzalezAlberquilla@arm.comoperator<<(std::ostream& os, const LaneData<LS>& d)
49712108SRekai.GonzalezAlberquilla@arm.com{
49812108SRekai.GonzalezAlberquilla@arm.com    return os << static_cast<typename LaneData<LS>::UnderlyingType>(d);
49912108SRekai.GonzalezAlberquilla@arm.com}
50012108SRekai.GonzalezAlberquilla@arm.com
50112108SRekai.GonzalezAlberquilla@arm.com/** Vector Lane abstraction
50212108SRekai.GonzalezAlberquilla@arm.com * Another view of a container. This time only a partial part of it is exposed.
50312108SRekai.GonzalezAlberquilla@arm.com * @tparam VecElem Type of each element of the vector.
50412108SRekai.GonzalezAlberquilla@arm.com * @tparam Const Indicate if the underlying container can be modified through
50512108SRekai.GonzalezAlberquilla@arm.com * the view.
50612108SRekai.GonzalezAlberquilla@arm.com */
50712108SRekai.GonzalezAlberquilla@arm.com/** @{ */
50812108SRekai.GonzalezAlberquilla@arm.com/* General */
50912108SRekai.GonzalezAlberquilla@arm.comtemplate <typename VecElem, bool Const>
51012108SRekai.GonzalezAlberquilla@arm.comclass VecLaneT
51112108SRekai.GonzalezAlberquilla@arm.com{
51212108SRekai.GonzalezAlberquilla@arm.com  public:
51312108SRekai.GonzalezAlberquilla@arm.com    /** VecRegContainer friendship to access private VecLaneT constructors.
51412108SRekai.GonzalezAlberquilla@arm.com     * Only VecRegContainers can build VecLanes.
51512108SRekai.GonzalezAlberquilla@arm.com     */
51612108SRekai.GonzalezAlberquilla@arm.com    /** @{ */
51712108SRekai.GonzalezAlberquilla@arm.com    friend VecLaneT<VecElem, !Const>;
51812108SRekai.GonzalezAlberquilla@arm.com
51912108SRekai.GonzalezAlberquilla@arm.com    /*template <size_t Sz>
52012108SRekai.GonzalezAlberquilla@arm.com    friend class VecRegContainer;*/
52112108SRekai.GonzalezAlberquilla@arm.com    friend class VecRegContainer<8>;
52212108SRekai.GonzalezAlberquilla@arm.com    friend class VecRegContainer<16>;
52312108SRekai.GonzalezAlberquilla@arm.com    friend class VecRegContainer<32>;
52412108SRekai.GonzalezAlberquilla@arm.com    friend class VecRegContainer<64>;
52512108SRekai.GonzalezAlberquilla@arm.com    friend class VecRegContainer<128>;
52614144Santhony.gutierrez@amd.com    friend class VecRegContainer<256>;
52713759Sgiacomo.gabrielli@arm.com    friend class VecRegContainer<MaxVecRegLenInBytes>;
52812108SRekai.GonzalezAlberquilla@arm.com
52912108SRekai.GonzalezAlberquilla@arm.com    /** My type alias. */
53012108SRekai.GonzalezAlberquilla@arm.com    using MyClass = VecLaneT<VecElem, Const>;
53112108SRekai.GonzalezAlberquilla@arm.com
53212108SRekai.GonzalezAlberquilla@arm.com  private:
53312108SRekai.GonzalezAlberquilla@arm.com    using Cont = typename std::conditional<Const,
53412108SRekai.GonzalezAlberquilla@arm.com                                              const VecElem,
53512108SRekai.GonzalezAlberquilla@arm.com                                              VecElem>::type;
53612108SRekai.GonzalezAlberquilla@arm.com    static_assert(!std::is_const<VecElem>::value || Const,
53712108SRekai.GonzalezAlberquilla@arm.com            "Asked for non-const lane of const type!");
53812108SRekai.GonzalezAlberquilla@arm.com    static_assert(std::is_integral<VecElem>::value,
53912108SRekai.GonzalezAlberquilla@arm.com            "VecElem type is not integral!");
54012108SRekai.GonzalezAlberquilla@arm.com    /** Reference to data. */
54112108SRekai.GonzalezAlberquilla@arm.com    Cont& container;
54212108SRekai.GonzalezAlberquilla@arm.com
54312108SRekai.GonzalezAlberquilla@arm.com    /** Constructor */
54412108SRekai.GonzalezAlberquilla@arm.com    VecLaneT(Cont& cont) : container(cont) { }
54512108SRekai.GonzalezAlberquilla@arm.com
54612108SRekai.GonzalezAlberquilla@arm.com  public:
54712108SRekai.GonzalezAlberquilla@arm.com    /** Assignment operators.
54812108SRekai.GonzalezAlberquilla@arm.com     * Assignment operators are only enabled if the underlying container is
54912108SRekai.GonzalezAlberquilla@arm.com     * non-constant.
55012108SRekai.GonzalezAlberquilla@arm.com     */
55112108SRekai.GonzalezAlberquilla@arm.com    /** @{ */
55212108SRekai.GonzalezAlberquilla@arm.com    template <bool Assignable = !Const>
55312108SRekai.GonzalezAlberquilla@arm.com    typename std::enable_if<Assignable, MyClass&>::type
55412108SRekai.GonzalezAlberquilla@arm.com    operator=(const VecElem& that) {
55512108SRekai.GonzalezAlberquilla@arm.com        container = that;
55612108SRekai.GonzalezAlberquilla@arm.com        return *this;
55712108SRekai.GonzalezAlberquilla@arm.com    }
55812108SRekai.GonzalezAlberquilla@arm.com    /**
55912108SRekai.GonzalezAlberquilla@arm.com     * Generic.
56012108SRekai.GonzalezAlberquilla@arm.com     * Generic bitwise assignment. Narrowing and widening assignemnts are
56112108SRekai.GonzalezAlberquilla@arm.com     * not allowed, pre-treatment of the rhs is required to conform.
56212108SRekai.GonzalezAlberquilla@arm.com     */
56312108SRekai.GonzalezAlberquilla@arm.com    template <bool Assignable = !Const, typename T>
56412108SRekai.GonzalezAlberquilla@arm.com    typename std::enable_if<Assignable, MyClass&>::type
56512108SRekai.GonzalezAlberquilla@arm.com    operator=(const T& that) {
56612108SRekai.GonzalezAlberquilla@arm.com        static_assert(sizeof(T) >= sizeof(VecElem),
56712108SRekai.GonzalezAlberquilla@arm.com                "Attempt to perform widening bitwise copy.");
56812108SRekai.GonzalezAlberquilla@arm.com        static_assert(sizeof(T) <= sizeof(VecElem),
56912108SRekai.GonzalezAlberquilla@arm.com                "Attempt to perform narrowing bitwise copy.");
57012108SRekai.GonzalezAlberquilla@arm.com        container = static_cast<VecElem>(that);
57112108SRekai.GonzalezAlberquilla@arm.com        return *this;
57212108SRekai.GonzalezAlberquilla@arm.com    }
57312108SRekai.GonzalezAlberquilla@arm.com    /** @} */
57412108SRekai.GonzalezAlberquilla@arm.com    /** Cast to vecElem. */
57512108SRekai.GonzalezAlberquilla@arm.com    operator VecElem() const { return container; }
57612108SRekai.GonzalezAlberquilla@arm.com
57712108SRekai.GonzalezAlberquilla@arm.com    /** Constification. */
57812108SRekai.GonzalezAlberquilla@arm.com    template <bool Cond = !Const, typename std::enable_if<Cond, int>::type = 0>
57912108SRekai.GonzalezAlberquilla@arm.com    operator VecLaneT<typename std::enable_if<Cond, VecElem>::type, true>()
58012108SRekai.GonzalezAlberquilla@arm.com    {
58112108SRekai.GonzalezAlberquilla@arm.com        return VecLaneT<VecElem, true>(container);
58212108SRekai.GonzalezAlberquilla@arm.com    }
58312108SRekai.GonzalezAlberquilla@arm.com};
58412108SRekai.GonzalezAlberquilla@arm.com
58512108SRekai.GonzalezAlberquilla@arm.comnamespace std {
58612108SRekai.GonzalezAlberquilla@arm.com    template<typename T, bool Const>
58712108SRekai.GonzalezAlberquilla@arm.com    struct add_const<VecLaneT<T, Const>> { typedef VecLaneT<T, true> type; };
58812108SRekai.GonzalezAlberquilla@arm.com}
58912108SRekai.GonzalezAlberquilla@arm.com
59012108SRekai.GonzalezAlberquilla@arm.com/** View as the Nth lane of type VecElem. */
59112108SRekai.GonzalezAlberquilla@arm.comtemplate <size_t Sz>
59212108SRekai.GonzalezAlberquilla@arm.comtemplate <typename VecElem, int LaneIdx>
59312108SRekai.GonzalezAlberquilla@arm.comVecLaneT<VecElem, false>
59412108SRekai.GonzalezAlberquilla@arm.comVecRegContainer<Sz>::laneView()
59512108SRekai.GonzalezAlberquilla@arm.com{
59612108SRekai.GonzalezAlberquilla@arm.com    return VecLaneT<VecElem, false>(as<VecElem>()[LaneIdx]);
59712108SRekai.GonzalezAlberquilla@arm.com}
59812108SRekai.GonzalezAlberquilla@arm.com
59912108SRekai.GonzalezAlberquilla@arm.com/** View as the const Nth lane of type VecElem. */
60012108SRekai.GonzalezAlberquilla@arm.comtemplate <size_t Sz>
60112108SRekai.GonzalezAlberquilla@arm.comtemplate <typename VecElem, int LaneIdx>
60212108SRekai.GonzalezAlberquilla@arm.comVecLaneT<VecElem, true>
60312108SRekai.GonzalezAlberquilla@arm.comVecRegContainer<Sz>::laneView() const
60412108SRekai.GonzalezAlberquilla@arm.com{
60512108SRekai.GonzalezAlberquilla@arm.com    return VecLaneT<VecElem, true>(as<VecElem>()[LaneIdx]);
60612108SRekai.GonzalezAlberquilla@arm.com}
60712108SRekai.GonzalezAlberquilla@arm.com
60812108SRekai.GonzalezAlberquilla@arm.com/** View as the Nth lane of type VecElem. */
60912108SRekai.GonzalezAlberquilla@arm.comtemplate <size_t Sz>
61012108SRekai.GonzalezAlberquilla@arm.comtemplate <typename VecElem>
61112108SRekai.GonzalezAlberquilla@arm.comVecLaneT<VecElem, false>
61212108SRekai.GonzalezAlberquilla@arm.comVecRegContainer<Sz>::laneView(int laneIdx)
61312108SRekai.GonzalezAlberquilla@arm.com{
61412108SRekai.GonzalezAlberquilla@arm.com    return VecLaneT<VecElem, false>(as<VecElem>()[laneIdx]);
61512108SRekai.GonzalezAlberquilla@arm.com}
61612108SRekai.GonzalezAlberquilla@arm.com
61712108SRekai.GonzalezAlberquilla@arm.com/** View as the const Nth lane of type VecElem. */
61812108SRekai.GonzalezAlberquilla@arm.comtemplate <size_t Sz>
61912108SRekai.GonzalezAlberquilla@arm.comtemplate <typename VecElem>
62012108SRekai.GonzalezAlberquilla@arm.comVecLaneT<VecElem, true>
62112108SRekai.GonzalezAlberquilla@arm.comVecRegContainer<Sz>::laneView(int laneIdx) const
62212108SRekai.GonzalezAlberquilla@arm.com{
62312108SRekai.GonzalezAlberquilla@arm.com    return VecLaneT<VecElem, true>(as<VecElem>()[laneIdx]);
62412108SRekai.GonzalezAlberquilla@arm.com}
62512108SRekai.GonzalezAlberquilla@arm.com
62612108SRekai.GonzalezAlberquilla@arm.comusing VecLane8 = VecLaneT<uint8_t, false>;
62712108SRekai.GonzalezAlberquilla@arm.comusing VecLane16 = VecLaneT<uint16_t, false>;
62812108SRekai.GonzalezAlberquilla@arm.comusing VecLane32 = VecLaneT<uint32_t, false>;
62912108SRekai.GonzalezAlberquilla@arm.comusing VecLane64 = VecLaneT<uint64_t, false>;
63012108SRekai.GonzalezAlberquilla@arm.com
63112108SRekai.GonzalezAlberquilla@arm.comusing ConstVecLane8 = VecLaneT<uint8_t, true>;
63212108SRekai.GonzalezAlberquilla@arm.comusing ConstVecLane16 = VecLaneT<uint16_t, true>;
63312108SRekai.GonzalezAlberquilla@arm.comusing ConstVecLane32 = VecLaneT<uint32_t, true>;
63412108SRekai.GonzalezAlberquilla@arm.comusing ConstVecLane64 = VecLaneT<uint64_t, true>;
63512108SRekai.GonzalezAlberquilla@arm.com
63612108SRekai.GonzalezAlberquilla@arm.com/**
63712108SRekai.GonzalezAlberquilla@arm.com * Calls required for serialization/deserialization
63812108SRekai.GonzalezAlberquilla@arm.com */
63912108SRekai.GonzalezAlberquilla@arm.com/** @{ */
64012108SRekai.GonzalezAlberquilla@arm.comtemplate <size_t Sz>
64112108SRekai.GonzalezAlberquilla@arm.cominline bool
64212108SRekai.GonzalezAlberquilla@arm.comto_number(const std::string& value, VecRegContainer<Sz>& v)
64312108SRekai.GonzalezAlberquilla@arm.com{
64413119Sgabor.dozsa@arm.com    fatal_if(value.size() > 2 * VecRegContainer<Sz>::SIZE,
64513119Sgabor.dozsa@arm.com             "Vector register value overflow at unserialize");
64613119Sgabor.dozsa@arm.com
64713119Sgabor.dozsa@arm.com    for (int i = 0; i < VecRegContainer<Sz>::SIZE; i++) {
64813119Sgabor.dozsa@arm.com        uint8_t b = 0;
64913119Sgabor.dozsa@arm.com        if (2 * i < value.size())
65013119Sgabor.dozsa@arm.com            b = stoul(value.substr(i * 2, 2), nullptr, 16);
65113119Sgabor.dozsa@arm.com        v.template raw_ptr<uint8_t>()[i] = b;
65212108SRekai.GonzalezAlberquilla@arm.com    }
65312108SRekai.GonzalezAlberquilla@arm.com    return true;
65412108SRekai.GonzalezAlberquilla@arm.com}
65512108SRekai.GonzalezAlberquilla@arm.com/** @} */
65612108SRekai.GonzalezAlberquilla@arm.com
65713610Sgiacomo.gabrielli@arm.com/**
65813610Sgiacomo.gabrielli@arm.com * Dummy type aliases and constants for architectures that do not implement
65913610Sgiacomo.gabrielli@arm.com * vector registers.
66013610Sgiacomo.gabrielli@arm.com */
66113610Sgiacomo.gabrielli@arm.com/** @{ */
66213610Sgiacomo.gabrielli@arm.comusing DummyVecElem = uint32_t;
66313610Sgiacomo.gabrielli@arm.comconstexpr unsigned DummyNumVecElemPerVecReg = 2;
66413610Sgiacomo.gabrielli@arm.comusing DummyVecReg = VecRegT<DummyVecElem, DummyNumVecElemPerVecReg, false>;
66513610Sgiacomo.gabrielli@arm.comusing DummyConstVecReg = VecRegT<DummyVecElem, DummyNumVecElemPerVecReg, true>;
66613610Sgiacomo.gabrielli@arm.comusing DummyVecRegContainer = DummyVecReg::Container;
66713610Sgiacomo.gabrielli@arm.comconstexpr size_t DummyVecRegSizeBytes = DummyNumVecElemPerVecReg *
66813610Sgiacomo.gabrielli@arm.com    sizeof(DummyVecElem);
66913610Sgiacomo.gabrielli@arm.com/** @} */
67013610Sgiacomo.gabrielli@arm.com
67112108SRekai.GonzalezAlberquilla@arm.com#endif /* __ARCH_GENERIC_VEC_REG_HH__ */
672