diff -r e62eb2fb62b4 -r 8b0fdbea39bf src/arch/generic/vec_reg.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/arch/generic/vec_reg.hh Mon Jan 16 11:54:13 2017 +0000 @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2015-2016 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 + * Nathanael Premillieu + * Rekai Gonzalez + */ + +/* Vector Registers layout specification + * + * This register type is to be used to model the SIMD registers. + * It takes into account the possibility that different architectural names + * may overlap (like for ARMv8 AArch32 for example). + */ + +#ifndef __ARCH_GENERIC_VEC_REG_HH__ +#define __ARCH_GENERIC_VEC_REG_HH__ + +#include +#include +#include +#include +#include +#include + +#include "base/cprintf.hh" + +template +class VecRegContainer; + +/** Vector Register Abstraction + * This generic class is a view in a particularization of MVC, to vector + * registers. There is a VecRegContainer that implements the model, and + * contains the data. To that model we can interpose different instantiations + * of VecRegT to view the container as a vector of NumElems elems of type + * VecElem. + * @tparam VecElem Type of each element of the vector. + * @tparam NumElems Amount of components of the vector. + * @tparam Const Indicate if the underlying container can be modified through + * the view. + */ +template +class VecRegT +{ + /** Size of the register in bytes. */ + static constexpr size_t SIZE = sizeof(VecElem) * NumElems; + public: + /** Container type alias. */ + using Container = typename std::conditional, + VecRegContainer>::type; + private: + /** My type alias. */ + using MyClass = VecRegT; + /** Reference to container. */ + Container& container; + + public: + /** Constructor. */ + VecRegT(Container& cnt) : container(cnt) {}; + + /** Zero the container. */ + template + typename std::enable_if::type + zero() { container.zero(); } + + template + typename std::enable_if::type + operator=(const MyClass& that) + { + container = that.container; + return *this; + } + + /** Index operator. */ + const VecElem& operator[](size_t idx) const + { + return container.template raw_ptr()[idx]; + } + + /** Index operator. */ + template + typename std::enable_if::type + operator[](size_t idx) + { + return container.template raw_ptr()[idx]; + } + + /** Equality operator. + * Required to compare thread contexts. + */ + template + bool + operator==(const VecRegT& that) const + { + return container == that.container; + } + /** Inequality operator. + * Required to compare thread contexts. + */ + template + bool + operator!=(const VecRegT& that) const + { + return !operator==(that); + } + + /** Output stream operator. */ + friend std::ostream& + operator<<(std::ostream& os, const MyClass& vr) + { + /* 0-sized is not allowed */ + os << "[" << std::hex << (uint32_t)vr[0]; + for (uint32_t e = 1; e < vr.SIZE; e++) + os << " " << std::hex << (uint32_t)vr[e]; + os << ']'; + return os; + } + + const std::string print() const { return csprintf("%s", *this); } + /** + * Cast to VecRegContainer& + * It is useful to get the reference to the container for ISA tricks, + * because casting to reference prevents unnecessary copies. + */ + operator Container&() { return container; } +}; + +/* Forward declaration. */ +template +class VecLaneT; + +/** + * Vector Register Abstraction + * This generic class is the model in a particularization of MVC, to vector + * registers. The model has functionality to create views of itself, or a + * portion through the method 'as + * @tparam Sz Size of the container in bytes. + */ +template +class VecRegContainer +{ + static_assert(Sz > 0, + "Cannot create Vector Register Container of zero size"); + public: + static constexpr size_t SIZE = Sz; + using Container = std::array; + private: + Container container; + using MyClass = VecRegContainer; + + public: + VecRegContainer() {} + /* This is required for de-serialisation. */ + VecRegContainer(const std::vector& that) + { + assert(that.size() >= SIZE); + std::memcpy(container.data(), &that[0], SIZE); + } + + /** Zero the container. */ + void zero() { memset(container.data(), 0, SIZE); } + + /** Assignment operators. */ + /** @{ */ + /** From VecRegContainer */ + MyClass& operator=(const MyClass& that) + { + if (&that == this) + return *this; + memcpy(container.data(), that.container.data(), SIZE); + return *this; + } + + /** From appropriately sized uint8_t[]. */ + MyClass& operator=(const Container& that) + { + std::memcpy(container.data(), that.data(), SIZE); + return *this; + } + + /** From vector. + * This is required for de-serialisation. + * */ + MyClass& operator=(const std::vector& that) + { + assert(that.size() >= SIZE); + std::memcpy(container.data(), that.data(), SIZE); + return *this; + } + /** @} */ + + /** Copy the contents into the input buffer. */ + /** @{ */ + /** To appropriately sized uint8_t[] */ + void copyTo(Container& dst) const + { + std::memcpy(dst.data(), container.data(), SIZE); + } + + /** To vector + * This is required for serialisation. + * */ + void copyTo(std::vector& dst) const + { + dst.resize(SIZE); + std::memcpy(dst.data(), container.data(), SIZE); + } + /** @} */ + + /** Equality operator. + * Required to compare thread contexts. + */ + template + inline bool + operator==(const VecRegContainer& that) const + { + return SIZE == S2 && + !memcmp(container.data(), that.container.data(), SIZE); + } + /** Inequality operator. + * Required to compare thread contexts. + */ + template + bool + operator!=(const VecRegContainer& that) const + { + return !operator==(that); + } + + const std::string print() const { return csprintf("%s", *this); } + /** Get pointer to bytes. */ + template + const Ret* raw_ptr() const { return (const Ret*)container.data(); } + + template + Ret* raw_ptr() { return (Ret*)container.data(); } + + /** + * View interposers. + * Create a view of this container as a vector of VecElems with an + * optional amount of elements. If the amount of elements is provided, + * the size of the container is checked, to test bounds. If it is not + * provided, the length is inferred from the container size and the + * element size. + * @tparam VecElem Type of each element of the vector for the view. + * @tparam NumElem Amount of elements in the view. + */ + /** @{ */ + template + VecRegT as() const + { + static_assert(SIZE % sizeof(VecElem) == 0, + "VecElem does not evenly divide the register size"); + static_assert(sizeof(VecElem) * NumElems <= SIZE, + "Viewing VecReg as something bigger than it is"); + return VecRegT(*this); + } + + template + VecRegT as() + { + static_assert(SIZE % sizeof(VecElem) == 0, + "VecElem does not evenly divide the register size"); + static_assert(sizeof(VecElem) * NumElems <= SIZE, + "Viewing VecReg as something bigger than it is"); + return VecRegT(*this); + } + + template + VecLaneT laneView(); + template + VecLaneT laneView() const; + template + VecLaneT laneView(int laneIdx); + template + VecLaneT laneView(int laneIdx) const; + /** @} */ + /** + * Output operator. + * Used for serialization. + */ + friend std::ostream& operator<<(std::ostream& os, const MyClass& v) + { + for (auto& b: v.container) { + os << csprintf("%02hhx", b); + } + return os; + } +}; + +enum class LaneSize +{ + Empty = 0, + Byte, + TwoByte, + FourByte, + EightByte, +}; + +template +class LaneData +{ + public: + /** Alias to the native type of the appropriate size. */ + using UnderlyingType = + typename std::conditional::type + >::type + >::type + >::type; + private: + static constexpr auto ByteSz = sizeof(UnderlyingType); + UnderlyingType _val; + using MyClass = LaneData; + + public: + template explicit + LaneData(typename std::enable_if::type t) + : _val(t) {} + + template + typename std::enable_if::type + operator=(const T& that) + { + _val = that; + return *this; + } + template::type I = 0> + operator T() const { + return *static_cast(&_val); + } +}; + +/** Output operator overload for LaneData. */ +template +inline std::ostream& +operator<<(std::ostream& os, const LaneData& d) +{ + return os << static_cast::UnderlyingType>(d); +} + +/** Vector Lane abstraction + * Another view of a container. This time only a partial part of it is exposed. + * @tparam VecElem Type of each element of the vector. + * @tparam Const Indicate if the underlying container can be modified through + * the view. + */ +/** @{ */ +/* General */ +template +class VecLaneT +{ + public: + /** VecRegContainer friendship to access private VecLaneT constructors. + * Only VecRegContainers can build VecLanes. + */ + /** @{ */ + template + template + friend VecLaneT VecRegContainer::template + laneView(int) const; + + template + template + friend VecLaneT VecRegContainer::template laneView(int); + + template + template + friend VecLaneT VecRegContainer::template laneView() const; + + template + template + friend VecLaneT VecRegContainer::template laneView(); + + /** My type alias. */ + using MyClass = VecLaneT; + + private: + using Cont = typename std::conditional::type; + static_assert(!std::is_const::value || Const, + "Asked for non-const lane of const type!"); + static_assert(std::is_integral::value, + "VecElem type is not integral!"); + /** Reference to data. */ + Cont& container; + + /** Constructor */ + VecLaneT(Cont& cont) : container(cont) { } + + public: + /** Assignment operators. + * Assignment operators are only enabled if the underlying container is + * non-constant. + */ + /** @{ */ + template + typename std::enable_if::type + operator=(const VecElem& that) { + container = that; + return *this; + } + /** + * Generic. + * Generic bitwise assignment. Narrowing and widening assignemnts are + * not allowed, pre-treatment of the rhs is required to conform. + */ + template + typename std::enable_if::type + operator=(const T& that) { + static_assert(sizeof(T) >= sizeof(VecElem), + "Attempt to perform widening bitwise copy."); + static_assert(sizeof(T) <= sizeof(VecElem), + "Attempt to perform narrowing bitwise copy."); + container = static_cast(that); + return *this; + } + /** @} */ + /** Cast to vecElem. */ + operator VecElem() const { return container; } + + /** Constification. */ + template ::type = 0> + operator VecLaneT() + { + return VecLaneT(container); + } +}; + +namespace std { + template<> + template + struct add_const> { typedef VecLaneT type; }; +} + +/** View as the Nth lane of type VecElem. */ +template +template +VecLaneT +VecRegContainer::laneView() +{ + return VecLaneT(as()[LaneIdx]); +} + +/** View as the const Nth lane of type VecElem. */ +template +template +VecLaneT +VecRegContainer::laneView() const +{ + return VecLaneT(as()[LaneIdx]); +} + +/** View as the Nth lane of type VecElem. */ +template +template +VecLaneT +VecRegContainer::laneView(int laneIdx) +{ + return VecLaneT(as()[laneIdx]); +} + +/** View as the const Nth lane of type VecElem. */ +template +template +VecLaneT +VecRegContainer::laneView(int laneIdx) const +{ + return VecLaneT(as()[laneIdx]); +} + +using VecLane8 = VecLaneT; +using VecLane16 = VecLaneT; +using VecLane32 = VecLaneT; +using VecLane64 = VecLaneT; + +using ConstVecLane8 = VecLaneT; +using ConstVecLane16 = VecLaneT; +using ConstVecLane32 = VecLaneT; +using ConstVecLane64 = VecLaneT; + +/** + * Calls required for serialization/deserialization + */ +/** @{ */ +template +inline bool +to_number(const std::string& value, VecRegContainer& v) +{ + int i = 0; + while (i < value.size()) { + std::string byte = value.substr(i<<1, 2); + v.template raw_ptr()[i] = stoul(byte, 0, 16); + i++; + } + return true; +} +/** @} */ + +#endif /* __ARCH_GENERIC_VEC_REG_HH__ */