vec_reg.hh (13759:9941fca869a9) vec_reg.hh (14144:371f9982fe4c)
1/*
2 * Copyright (c) 2015-2018 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Giacomo Gabrielli
38 * Nathanael Premillieu
39 * Rekai Gonzalez
40 */
41
42/** \file arch/generic/vec_reg.hh
43 * Vector Registers layout specification.
44 *
45 * This register type is to be used to model the SIMD registers.
46 * It takes into account the possibility that different architectural names
47 * may overlap (like for ARMv8 AArch32 for example).
48 *
49 * The design is having a basic vector register container that holds the
50 * bytes, unaware of anything else. This is implemented by VecRegContainer.
51 * As the (maximum) length of the physical vector register is a compile-time
52 * constant, it is defined as a template parameter.
53 *
54 * This file also describes two views of the container that have semantic
55 * information about the bytes. The first of this views is VecRegT.
56 * A VecRegT is a view of a VecRegContainer (by reference). The VecRegT has
57 * a type (VecElem) to which bytes are casted, and the amount of such
58 * elements that the vector contains (NumElems). The size of a view,
59 * calculated as sizeof(VecElem) * NumElems must match the size of the
60 * underlying container. As VecRegT has some degree of type information it
61 * has vector semantics, and defines the index operator ([]) to get
62 * references to particular bytes understood as a VecElem.
63 * The second view of a container implemented in this file is VecLaneT, which
64 * is a view of a subset of the container.
65 * A VecLaneT is a view of a lane of a vector register, where a lane is
66 * identified by a type (VecElem) and an index (although the view is
67 * unaware of its index). Operations on the lane are directly applied to
68 * the corresponding bytes of the underlying VecRegContainer through a
69 * reference.
70 *
71 * The intended usage is requesting views to the VecRegContainer via the
72 * member 'as' for VecRegT and the member 'laneView' for VecLaneT. Kindly
73 * find an example of usage in the following.
74 *
75 *
76 * // We declare 512 bits vectors
77 * using Vec512 = VecRegContainer<64>;
78 * ...
79 * // We implement the physical vector register file
80 * Vec512 physicalVecRegFile[NUM_VREGS];
81 * ...
82 * // Usage example, for a macro op:
83 * VecFloat8Add(ExecContext* xd) {
84 * // Request source vector register to the execution context (const as it
85 * // is read only).
86 * const Vec512& vsrc1raw = xc->readVecRegOperand(this, 0);
87 * // View it as a vector of floats (we could just specify the first
88 * // template parametre, the second has a default value that works, and the
89 * // last one is derived by the constness of vsrc1raw).
90 * VecRegT<float, 8, true>& vsrc1 = vsrc1raw->as<float, 8>();
91 *
92 * // Second source and view
93 * const Vec512& vsrc2raw = xc->readVecRegOperand(this, 1);
94 * VecRegT<float, 8, true>& vsrc2 = vsrc2raw->as<float, 8>();
95 *
96 * // Destination and view
97 * Vec512 vdstraw;
98 * VecRegT<float, 8, false>& vdst = vdstraw->as<float, 8>();
99 *
100 * for (auto i = 0; i < 8; i++) {
101 * // This asignment sets the bits in the underlying Vec512: vdstraw
102 * vdst[i] = vsrc1[i] + vsrc2[i];
103 * }
104 * xc->setWriteRegOperand(this, 0, vdstraw);
105 * }
106 *
107 * // Usage example, for a micro op that operates over lane number _lidx:
108 * VecFloatLaneAdd(ExecContext* xd) {
109 * // Request source vector register to the execution context (const as it
110 * // is read only).
111 * const Vec512& vsrc1raw = xc->readVecRegOperand(this, 0);
112 * // View it as a lane of a vector of floats (we could just specify the
113 * // first template parametre, the second is derived by the constness of
114 * // vsrc1raw).
115 * VecLaneT<float, true>& src1 = vsrc1raw->laneView<float>(this->_lidx);
116 *
117 * // Second source and view
118 * const Vec512& vsrc2raw = xc->readVecRegOperand(this, 1);
119 * VecLaneT<float, true>& src2 = vsrc2raw->laneView<float>(this->_lidx);
120 *
121 * // (Writable) destination and view
122 * // As this is a partial write, we need the exec context to support that
123 * // through, e.g., 'readVecRegOperandToWrite' returning a writable
124 * // reference to the register
125 * Vec512 vdstraw = xc->readVecRegOperandToWrite(this, 3);
126 * VecLaneT<float, false>& dst = vdstraw->laneView<float>(this->_lidx);
127 *
128 * dst = src1 + src2;
129 * // There is no need to copy the value back into the exec context, as
130 * // the assignment to dst modifies the appropriate bytes in vdstraw which
131 * // is in turn, a reference to the register in the cpu model.
132 * // For operations that do conditional writeback, we can decouple the
133 * // write by doing:
134 * // auto tmp = src1 + src2;
135 * // if (test) {
136 * // dst = tmp; // do writeback
137 * // } else {
138 * // // do not do writeback
139 * // }
140 * }
141 *
142 */
143
144#ifndef __ARCH_GENERIC_VEC_REG_HH__
145#define __ARCH_GENERIC_VEC_REG_HH__
146
147#include <array>
148#include <cassert>
149#include <iostream>
150#include <string>
151#include <type_traits>
152#include <vector>
153
154#include "base/cprintf.hh"
155#include "base/logging.hh"
156
1/*
2 * Copyright (c) 2015-2018 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Giacomo Gabrielli
38 * Nathanael Premillieu
39 * Rekai Gonzalez
40 */
41
42/** \file arch/generic/vec_reg.hh
43 * Vector Registers layout specification.
44 *
45 * This register type is to be used to model the SIMD registers.
46 * It takes into account the possibility that different architectural names
47 * may overlap (like for ARMv8 AArch32 for example).
48 *
49 * The design is having a basic vector register container that holds the
50 * bytes, unaware of anything else. This is implemented by VecRegContainer.
51 * As the (maximum) length of the physical vector register is a compile-time
52 * constant, it is defined as a template parameter.
53 *
54 * This file also describes two views of the container that have semantic
55 * information about the bytes. The first of this views is VecRegT.
56 * A VecRegT is a view of a VecRegContainer (by reference). The VecRegT has
57 * a type (VecElem) to which bytes are casted, and the amount of such
58 * elements that the vector contains (NumElems). The size of a view,
59 * calculated as sizeof(VecElem) * NumElems must match the size of the
60 * underlying container. As VecRegT has some degree of type information it
61 * has vector semantics, and defines the index operator ([]) to get
62 * references to particular bytes understood as a VecElem.
63 * The second view of a container implemented in this file is VecLaneT, which
64 * is a view of a subset of the container.
65 * A VecLaneT is a view of a lane of a vector register, where a lane is
66 * identified by a type (VecElem) and an index (although the view is
67 * unaware of its index). Operations on the lane are directly applied to
68 * the corresponding bytes of the underlying VecRegContainer through a
69 * reference.
70 *
71 * The intended usage is requesting views to the VecRegContainer via the
72 * member 'as' for VecRegT and the member 'laneView' for VecLaneT. Kindly
73 * find an example of usage in the following.
74 *
75 *
76 * // We declare 512 bits vectors
77 * using Vec512 = VecRegContainer<64>;
78 * ...
79 * // We implement the physical vector register file
80 * Vec512 physicalVecRegFile[NUM_VREGS];
81 * ...
82 * // Usage example, for a macro op:
83 * VecFloat8Add(ExecContext* xd) {
84 * // Request source vector register to the execution context (const as it
85 * // is read only).
86 * const Vec512& vsrc1raw = xc->readVecRegOperand(this, 0);
87 * // View it as a vector of floats (we could just specify the first
88 * // template parametre, the second has a default value that works, and the
89 * // last one is derived by the constness of vsrc1raw).
90 * VecRegT<float, 8, true>& vsrc1 = vsrc1raw->as<float, 8>();
91 *
92 * // Second source and view
93 * const Vec512& vsrc2raw = xc->readVecRegOperand(this, 1);
94 * VecRegT<float, 8, true>& vsrc2 = vsrc2raw->as<float, 8>();
95 *
96 * // Destination and view
97 * Vec512 vdstraw;
98 * VecRegT<float, 8, false>& vdst = vdstraw->as<float, 8>();
99 *
100 * for (auto i = 0; i < 8; i++) {
101 * // This asignment sets the bits in the underlying Vec512: vdstraw
102 * vdst[i] = vsrc1[i] + vsrc2[i];
103 * }
104 * xc->setWriteRegOperand(this, 0, vdstraw);
105 * }
106 *
107 * // Usage example, for a micro op that operates over lane number _lidx:
108 * VecFloatLaneAdd(ExecContext* xd) {
109 * // Request source vector register to the execution context (const as it
110 * // is read only).
111 * const Vec512& vsrc1raw = xc->readVecRegOperand(this, 0);
112 * // View it as a lane of a vector of floats (we could just specify the
113 * // first template parametre, the second is derived by the constness of
114 * // vsrc1raw).
115 * VecLaneT<float, true>& src1 = vsrc1raw->laneView<float>(this->_lidx);
116 *
117 * // Second source and view
118 * const Vec512& vsrc2raw = xc->readVecRegOperand(this, 1);
119 * VecLaneT<float, true>& src2 = vsrc2raw->laneView<float>(this->_lidx);
120 *
121 * // (Writable) destination and view
122 * // As this is a partial write, we need the exec context to support that
123 * // through, e.g., 'readVecRegOperandToWrite' returning a writable
124 * // reference to the register
125 * Vec512 vdstraw = xc->readVecRegOperandToWrite(this, 3);
126 * VecLaneT<float, false>& dst = vdstraw->laneView<float>(this->_lidx);
127 *
128 * dst = src1 + src2;
129 * // There is no need to copy the value back into the exec context, as
130 * // the assignment to dst modifies the appropriate bytes in vdstraw which
131 * // is in turn, a reference to the register in the cpu model.
132 * // For operations that do conditional writeback, we can decouple the
133 * // write by doing:
134 * // auto tmp = src1 + src2;
135 * // if (test) {
136 * // dst = tmp; // do writeback
137 * // } else {
138 * // // do not do writeback
139 * // }
140 * }
141 *
142 */
143
144#ifndef __ARCH_GENERIC_VEC_REG_HH__
145#define __ARCH_GENERIC_VEC_REG_HH__
146
147#include <array>
148#include <cassert>
149#include <iostream>
150#include <string>
151#include <type_traits>
152#include <vector>
153
154#include "base/cprintf.hh"
155#include "base/logging.hh"
156
157constexpr unsigned MaxVecRegLenInBytes = 256;
157constexpr unsigned MaxVecRegLenInBytes = 4096;
158
159template <size_t Sz>
160class VecRegContainer;
161
162/** Vector Register Abstraction
163 * This generic class is a view in a particularization of MVC, to vector
164 * registers. There is a VecRegContainer that implements the model, and
165 * contains the data. To that model we can interpose different instantiations
166 * of VecRegT to view the container as a vector of NumElems elems of type
167 * VecElem.
168 * @tparam VecElem Type of each element of the vector.
169 * @tparam NumElems Amount of components of the vector.
170 * @tparam Const Indicate if the underlying container can be modified through
171 * the view.
172 */
173template <typename VecElem, size_t NumElems, bool Const>
174class VecRegT
175{
176 /** Size of the register in bytes. */
177 static constexpr size_t SIZE = sizeof(VecElem) * NumElems;
178 public:
179 /** Container type alias. */
180 using Container = typename std::conditional<Const,
181 const VecRegContainer<SIZE>,
182 VecRegContainer<SIZE>>::type;
183 private:
184 /** My type alias. */
185 using MyClass = VecRegT<VecElem, NumElems, Const>;
186 /** Reference to container. */
187 Container& container;
188
189 public:
190 /** Constructor. */
191 VecRegT(Container& cnt) : container(cnt) {};
192
193 /** Zero the container. */
194 template<bool Condition = !Const>
195 typename std::enable_if<Condition, void>::type
196 zero() { container.zero(); }
197
198 template<bool Condition = !Const>
199 typename std::enable_if<Condition, MyClass&>::type
200 operator=(const MyClass& that)
201 {
202 container = that.container;
203 return *this;
204 }
205
206 /** Index operator. */
207 const VecElem& operator[](size_t idx) const
208 {
209 return container.template raw_ptr<VecElem>()[idx];
210 }
211
212 /** Index operator. */
213 template<bool Condition = !Const>
214 typename std::enable_if<Condition, VecElem&>::type
215 operator[](size_t idx)
216 {
217 return container.template raw_ptr<VecElem>()[idx];
218 }
219
220 /** Equality operator.
221 * Required to compare thread contexts.
222 */
223 template<typename VE2, size_t NE2, bool C2>
224 bool
225 operator==(const VecRegT<VE2, NE2, C2>& that) const
226 {
227 return container == that.container;
228 }
229 /** Inequality operator.
230 * Required to compare thread contexts.
231 */
232 template<typename VE2, size_t NE2, bool C2>
233 bool
234 operator!=(const VecRegT<VE2, NE2, C2>& that) const
235 {
236 return !operator==(that);
237 }
238
239 /** Output stream operator. */
240 friend std::ostream&
241 operator<<(std::ostream& os, const MyClass& vr)
242 {
243 /* 0-sized is not allowed */
244 os << "[" << std::hex << (uint32_t)vr[0];
245 for (uint32_t e = 1; e < vr.SIZE; e++)
246 os << " " << std::hex << (uint32_t)vr[e];
247 os << ']';
248 return os;
249 }
250
251 const std::string print() const { return csprintf("%s", *this); }
252 /**
253 * Cast to VecRegContainer&
254 * It is useful to get the reference to the container for ISA tricks,
255 * because casting to reference prevents unnecessary copies.
256 */
257 operator Container&() { return container; }
258};
259
260/* Forward declaration. */
261template <typename VecElem, bool Const>
262class VecLaneT;
263
264/**
265 * Vector Register Abstraction
266 * This generic class is the model in a particularization of MVC, to vector
267 * registers. The model has functionality to create views of itself, or a
268 * portion through the method 'as
269 * @tparam Sz Size of the container in bytes.
270 */
271template <size_t Sz>
272class VecRegContainer
273{
274 static_assert(Sz > 0,
275 "Cannot create Vector Register Container of zero size");
276 static_assert(Sz <= MaxVecRegLenInBytes,
277 "Vector Register size limit exceeded");
278 public:
279 static constexpr size_t SIZE = Sz;
280 using Container = std::array<uint8_t,Sz>;
281 private:
282 Container container;
283 using MyClass = VecRegContainer<SIZE>;
284
285 public:
286 VecRegContainer() {}
287 /* This is required for de-serialisation. */
288 VecRegContainer(const std::vector<uint8_t>& that)
289 {
290 assert(that.size() >= SIZE);
291 std::memcpy(container.data(), &that[0], SIZE);
292 }
293
294 /** Zero the container. */
295 void zero() { memset(container.data(), 0, SIZE); }
296
297 /** Assignment operators. */
298 /** @{ */
299 /** From VecRegContainer */
300 MyClass& operator=(const MyClass& that)
301 {
302 if (&that == this)
303 return *this;
304 memcpy(container.data(), that.container.data(), SIZE);
305 return *this;
306 }
307
308 /** From appropriately sized uint8_t[]. */
309 MyClass& operator=(const Container& that)
310 {
311 std::memcpy(container.data(), that.data(), SIZE);
312 return *this;
313 }
314
315 /** From vector<uint8_t>.
316 * This is required for de-serialisation.
317 * */
318 MyClass& operator=(const std::vector<uint8_t>& that)
319 {
320 assert(that.size() >= SIZE);
321 std::memcpy(container.data(), that.data(), SIZE);
322 return *this;
323 }
324 /** @} */
325
326 /** Copy the contents into the input buffer. */
327 /** @{ */
328 /** To appropriately sized uint8_t[] */
329 void copyTo(Container& dst) const
330 {
331 std::memcpy(dst.data(), container.data(), SIZE);
332 }
333
334 /** To vector<uint8_t>
335 * This is required for serialisation.
336 * */
337 void copyTo(std::vector<uint8_t>& dst) const
338 {
339 dst.resize(SIZE);
340 std::memcpy(dst.data(), container.data(), SIZE);
341 }
342 /** @} */
343
344 /** Equality operator.
345 * Required to compare thread contexts.
346 */
347 template<size_t S2>
348 inline bool
349 operator==(const VecRegContainer<S2>& that) const
350 {
351 return SIZE == S2 &&
352 !memcmp(container.data(), that.container.data(), SIZE);
353 }
354 /** Inequality operator.
355 * Required to compare thread contexts.
356 */
357 template<size_t S2>
358 bool
359 operator!=(const VecRegContainer<S2>& that) const
360 {
361 return !operator==(that);
362 }
363
364 const std::string print() const { return csprintf("%s", *this); }
365 /** Get pointer to bytes. */
366 template <typename Ret>
367 const Ret* raw_ptr() const { return (const Ret*)container.data(); }
368
369 template <typename Ret>
370 Ret* raw_ptr() { return (Ret*)container.data(); }
371
372 /**
373 * View interposers.
374 * Create a view of this container as a vector of VecElems with an
375 * optional amount of elements. If the amount of elements is provided,
376 * the size of the container is checked, to test bounds. If it is not
377 * provided, the length is inferred from the container size and the
378 * element size.
379 * @tparam VecElem Type of each element of the vector for the view.
380 * @tparam NumElem Amount of elements in the view.
381 */
382 /** @{ */
383 template <typename VecElem, size_t NumElems = SIZE/sizeof(VecElem)>
384 VecRegT<VecElem, NumElems, true> as() const
385 {
386 static_assert(SIZE % sizeof(VecElem) == 0,
387 "VecElem does not evenly divide the register size");
388 static_assert(sizeof(VecElem) * NumElems <= SIZE,
389 "Viewing VecReg as something bigger than it is");
390 return VecRegT<VecElem, NumElems, true>(*this);
391 }
392
393 template <typename VecElem, size_t NumElems = SIZE/sizeof(VecElem)>
394 VecRegT<VecElem, NumElems, false> as()
395 {
396 static_assert(SIZE % sizeof(VecElem) == 0,
397 "VecElem does not evenly divide the register size");
398 static_assert(sizeof(VecElem) * NumElems <= SIZE,
399 "Viewing VecReg as something bigger than it is");
400 return VecRegT<VecElem, NumElems, false>(*this);
401 }
402
403 template <typename VecElem, int LaneIdx>
404 VecLaneT<VecElem, false> laneView();
405 template <typename VecElem, int LaneIdx>
406 VecLaneT<VecElem, true> laneView() const;
407 template <typename VecElem>
408 VecLaneT<VecElem, false> laneView(int laneIdx);
409 template <typename VecElem>
410 VecLaneT<VecElem, true> laneView(int laneIdx) const;
411 /** @} */
412 /**
413 * Output operator.
414 * Used for serialization.
415 */
416 friend std::ostream& operator<<(std::ostream& os, const MyClass& v)
417 {
418 for (auto& b: v.container) {
419 os << csprintf("%02x", b);
420 }
421 return os;
422 }
423};
424
425/** We define an auxiliary abstraction for LaneData. The ISA should care
426 * about the semantics of a, e.g., 32bit element, treating it as a signed or
427 * unsigned int, or a float depending on the semantics of a particular
428 * instruction. On the other hand, the cpu model should only care about it
429 * being a 32-bit value. */
430enum class LaneSize
431{
432 Empty = 0,
433 Byte,
434 TwoByte,
435 FourByte,
436 EightByte,
437};
438
439/** LaneSize is an abstraction of a LS byte value for the execution and thread
440 * contexts to handle values just depending on its width. That way, the ISA
441 * can request, for example, the second 4 byte lane of register 5 to the model.
442 * The model serves that value, agnostic of the semantics of those bits. Then,
443 * it is up to the ISA to interpret those bits as a float, or as an uint.
444 * To maximize the utility, this class implements the assignment operator and
445 * the casting to equal-size types.
446 * As opposed to a RegLaneT, LaneData is not 'backed' by a VecRegContainer.
447 * The idea is:
448 * When data is passed and is susceptible to being copied, use LaneData, as
449 * copying the primitive type is build on is cheap.
450 * When data is passed as references (const or not), use RegLaneT, as all
451 * operations happen 'in place', avoiding any copies (no copies is always
452 * cheaper than cheap copies), especially when things are inlined, and
453 * references are not explicitly passed.
454 */
455template <LaneSize LS>
456class LaneData
457{
458 public:
459 /** Alias to the native type of the appropriate size. */
460 using UnderlyingType =
461 typename std::conditional<LS == LaneSize::EightByte, uint64_t,
462 typename std::conditional<LS == LaneSize::FourByte, uint32_t,
463 typename std::conditional<LS == LaneSize::TwoByte, uint16_t,
464 typename std::conditional<LS == LaneSize::Byte, uint8_t,
465 void>::type
466 >::type
467 >::type
468 >::type;
469 private:
470 static constexpr auto ByteSz = sizeof(UnderlyingType);
471 UnderlyingType _val;
472 using MyClass = LaneData<LS>;
473
474 public:
475 template <typename T> explicit
476 LaneData(typename std::enable_if<sizeof(T) == ByteSz, const T&>::type t)
477 : _val(t) {}
478
479 template <typename T>
480 typename std::enable_if<sizeof(T) == ByteSz, MyClass&>::type
481 operator=(const T& that)
482 {
483 _val = that;
484 return *this;
485 }
486 template<typename T,
487 typename std::enable_if<sizeof(T) == ByteSz, int>::type I = 0>
488 operator T() const {
489 return *static_cast<const T*>(&_val);
490 }
491};
492
493/** Output operator overload for LaneData<Size>. */
494template <LaneSize LS>
495inline std::ostream&
496operator<<(std::ostream& os, const LaneData<LS>& d)
497{
498 return os << static_cast<typename LaneData<LS>::UnderlyingType>(d);
499}
500
501/** Vector Lane abstraction
502 * Another view of a container. This time only a partial part of it is exposed.
503 * @tparam VecElem Type of each element of the vector.
504 * @tparam Const Indicate if the underlying container can be modified through
505 * the view.
506 */
507/** @{ */
508/* General */
509template <typename VecElem, bool Const>
510class VecLaneT
511{
512 public:
513 /** VecRegContainer friendship to access private VecLaneT constructors.
514 * Only VecRegContainers can build VecLanes.
515 */
516 /** @{ */
517 friend VecLaneT<VecElem, !Const>;
518
519 /*template <size_t Sz>
520 friend class VecRegContainer;*/
521 friend class VecRegContainer<8>;
522 friend class VecRegContainer<16>;
523 friend class VecRegContainer<32>;
524 friend class VecRegContainer<64>;
525 friend class VecRegContainer<128>;
158
159template <size_t Sz>
160class VecRegContainer;
161
162/** Vector Register Abstraction
163 * This generic class is a view in a particularization of MVC, to vector
164 * registers. There is a VecRegContainer that implements the model, and
165 * contains the data. To that model we can interpose different instantiations
166 * of VecRegT to view the container as a vector of NumElems elems of type
167 * VecElem.
168 * @tparam VecElem Type of each element of the vector.
169 * @tparam NumElems Amount of components of the vector.
170 * @tparam Const Indicate if the underlying container can be modified through
171 * the view.
172 */
173template <typename VecElem, size_t NumElems, bool Const>
174class VecRegT
175{
176 /** Size of the register in bytes. */
177 static constexpr size_t SIZE = sizeof(VecElem) * NumElems;
178 public:
179 /** Container type alias. */
180 using Container = typename std::conditional<Const,
181 const VecRegContainer<SIZE>,
182 VecRegContainer<SIZE>>::type;
183 private:
184 /** My type alias. */
185 using MyClass = VecRegT<VecElem, NumElems, Const>;
186 /** Reference to container. */
187 Container& container;
188
189 public:
190 /** Constructor. */
191 VecRegT(Container& cnt) : container(cnt) {};
192
193 /** Zero the container. */
194 template<bool Condition = !Const>
195 typename std::enable_if<Condition, void>::type
196 zero() { container.zero(); }
197
198 template<bool Condition = !Const>
199 typename std::enable_if<Condition, MyClass&>::type
200 operator=(const MyClass& that)
201 {
202 container = that.container;
203 return *this;
204 }
205
206 /** Index operator. */
207 const VecElem& operator[](size_t idx) const
208 {
209 return container.template raw_ptr<VecElem>()[idx];
210 }
211
212 /** Index operator. */
213 template<bool Condition = !Const>
214 typename std::enable_if<Condition, VecElem&>::type
215 operator[](size_t idx)
216 {
217 return container.template raw_ptr<VecElem>()[idx];
218 }
219
220 /** Equality operator.
221 * Required to compare thread contexts.
222 */
223 template<typename VE2, size_t NE2, bool C2>
224 bool
225 operator==(const VecRegT<VE2, NE2, C2>& that) const
226 {
227 return container == that.container;
228 }
229 /** Inequality operator.
230 * Required to compare thread contexts.
231 */
232 template<typename VE2, size_t NE2, bool C2>
233 bool
234 operator!=(const VecRegT<VE2, NE2, C2>& that) const
235 {
236 return !operator==(that);
237 }
238
239 /** Output stream operator. */
240 friend std::ostream&
241 operator<<(std::ostream& os, const MyClass& vr)
242 {
243 /* 0-sized is not allowed */
244 os << "[" << std::hex << (uint32_t)vr[0];
245 for (uint32_t e = 1; e < vr.SIZE; e++)
246 os << " " << std::hex << (uint32_t)vr[e];
247 os << ']';
248 return os;
249 }
250
251 const std::string print() const { return csprintf("%s", *this); }
252 /**
253 * Cast to VecRegContainer&
254 * It is useful to get the reference to the container for ISA tricks,
255 * because casting to reference prevents unnecessary copies.
256 */
257 operator Container&() { return container; }
258};
259
260/* Forward declaration. */
261template <typename VecElem, bool Const>
262class VecLaneT;
263
264/**
265 * Vector Register Abstraction
266 * This generic class is the model in a particularization of MVC, to vector
267 * registers. The model has functionality to create views of itself, or a
268 * portion through the method 'as
269 * @tparam Sz Size of the container in bytes.
270 */
271template <size_t Sz>
272class VecRegContainer
273{
274 static_assert(Sz > 0,
275 "Cannot create Vector Register Container of zero size");
276 static_assert(Sz <= MaxVecRegLenInBytes,
277 "Vector Register size limit exceeded");
278 public:
279 static constexpr size_t SIZE = Sz;
280 using Container = std::array<uint8_t,Sz>;
281 private:
282 Container container;
283 using MyClass = VecRegContainer<SIZE>;
284
285 public:
286 VecRegContainer() {}
287 /* This is required for de-serialisation. */
288 VecRegContainer(const std::vector<uint8_t>& that)
289 {
290 assert(that.size() >= SIZE);
291 std::memcpy(container.data(), &that[0], SIZE);
292 }
293
294 /** Zero the container. */
295 void zero() { memset(container.data(), 0, SIZE); }
296
297 /** Assignment operators. */
298 /** @{ */
299 /** From VecRegContainer */
300 MyClass& operator=(const MyClass& that)
301 {
302 if (&that == this)
303 return *this;
304 memcpy(container.data(), that.container.data(), SIZE);
305 return *this;
306 }
307
308 /** From appropriately sized uint8_t[]. */
309 MyClass& operator=(const Container& that)
310 {
311 std::memcpy(container.data(), that.data(), SIZE);
312 return *this;
313 }
314
315 /** From vector<uint8_t>.
316 * This is required for de-serialisation.
317 * */
318 MyClass& operator=(const std::vector<uint8_t>& that)
319 {
320 assert(that.size() >= SIZE);
321 std::memcpy(container.data(), that.data(), SIZE);
322 return *this;
323 }
324 /** @} */
325
326 /** Copy the contents into the input buffer. */
327 /** @{ */
328 /** To appropriately sized uint8_t[] */
329 void copyTo(Container& dst) const
330 {
331 std::memcpy(dst.data(), container.data(), SIZE);
332 }
333
334 /** To vector<uint8_t>
335 * This is required for serialisation.
336 * */
337 void copyTo(std::vector<uint8_t>& dst) const
338 {
339 dst.resize(SIZE);
340 std::memcpy(dst.data(), container.data(), SIZE);
341 }
342 /** @} */
343
344 /** Equality operator.
345 * Required to compare thread contexts.
346 */
347 template<size_t S2>
348 inline bool
349 operator==(const VecRegContainer<S2>& that) const
350 {
351 return SIZE == S2 &&
352 !memcmp(container.data(), that.container.data(), SIZE);
353 }
354 /** Inequality operator.
355 * Required to compare thread contexts.
356 */
357 template<size_t S2>
358 bool
359 operator!=(const VecRegContainer<S2>& that) const
360 {
361 return !operator==(that);
362 }
363
364 const std::string print() const { return csprintf("%s", *this); }
365 /** Get pointer to bytes. */
366 template <typename Ret>
367 const Ret* raw_ptr() const { return (const Ret*)container.data(); }
368
369 template <typename Ret>
370 Ret* raw_ptr() { return (Ret*)container.data(); }
371
372 /**
373 * View interposers.
374 * Create a view of this container as a vector of VecElems with an
375 * optional amount of elements. If the amount of elements is provided,
376 * the size of the container is checked, to test bounds. If it is not
377 * provided, the length is inferred from the container size and the
378 * element size.
379 * @tparam VecElem Type of each element of the vector for the view.
380 * @tparam NumElem Amount of elements in the view.
381 */
382 /** @{ */
383 template <typename VecElem, size_t NumElems = SIZE/sizeof(VecElem)>
384 VecRegT<VecElem, NumElems, true> as() const
385 {
386 static_assert(SIZE % sizeof(VecElem) == 0,
387 "VecElem does not evenly divide the register size");
388 static_assert(sizeof(VecElem) * NumElems <= SIZE,
389 "Viewing VecReg as something bigger than it is");
390 return VecRegT<VecElem, NumElems, true>(*this);
391 }
392
393 template <typename VecElem, size_t NumElems = SIZE/sizeof(VecElem)>
394 VecRegT<VecElem, NumElems, false> as()
395 {
396 static_assert(SIZE % sizeof(VecElem) == 0,
397 "VecElem does not evenly divide the register size");
398 static_assert(sizeof(VecElem) * NumElems <= SIZE,
399 "Viewing VecReg as something bigger than it is");
400 return VecRegT<VecElem, NumElems, false>(*this);
401 }
402
403 template <typename VecElem, int LaneIdx>
404 VecLaneT<VecElem, false> laneView();
405 template <typename VecElem, int LaneIdx>
406 VecLaneT<VecElem, true> laneView() const;
407 template <typename VecElem>
408 VecLaneT<VecElem, false> laneView(int laneIdx);
409 template <typename VecElem>
410 VecLaneT<VecElem, true> laneView(int laneIdx) const;
411 /** @} */
412 /**
413 * Output operator.
414 * Used for serialization.
415 */
416 friend std::ostream& operator<<(std::ostream& os, const MyClass& v)
417 {
418 for (auto& b: v.container) {
419 os << csprintf("%02x", b);
420 }
421 return os;
422 }
423};
424
425/** We define an auxiliary abstraction for LaneData. The ISA should care
426 * about the semantics of a, e.g., 32bit element, treating it as a signed or
427 * unsigned int, or a float depending on the semantics of a particular
428 * instruction. On the other hand, the cpu model should only care about it
429 * being a 32-bit value. */
430enum class LaneSize
431{
432 Empty = 0,
433 Byte,
434 TwoByte,
435 FourByte,
436 EightByte,
437};
438
439/** LaneSize is an abstraction of a LS byte value for the execution and thread
440 * contexts to handle values just depending on its width. That way, the ISA
441 * can request, for example, the second 4 byte lane of register 5 to the model.
442 * The model serves that value, agnostic of the semantics of those bits. Then,
443 * it is up to the ISA to interpret those bits as a float, or as an uint.
444 * To maximize the utility, this class implements the assignment operator and
445 * the casting to equal-size types.
446 * As opposed to a RegLaneT, LaneData is not 'backed' by a VecRegContainer.
447 * The idea is:
448 * When data is passed and is susceptible to being copied, use LaneData, as
449 * copying the primitive type is build on is cheap.
450 * When data is passed as references (const or not), use RegLaneT, as all
451 * operations happen 'in place', avoiding any copies (no copies is always
452 * cheaper than cheap copies), especially when things are inlined, and
453 * references are not explicitly passed.
454 */
455template <LaneSize LS>
456class LaneData
457{
458 public:
459 /** Alias to the native type of the appropriate size. */
460 using UnderlyingType =
461 typename std::conditional<LS == LaneSize::EightByte, uint64_t,
462 typename std::conditional<LS == LaneSize::FourByte, uint32_t,
463 typename std::conditional<LS == LaneSize::TwoByte, uint16_t,
464 typename std::conditional<LS == LaneSize::Byte, uint8_t,
465 void>::type
466 >::type
467 >::type
468 >::type;
469 private:
470 static constexpr auto ByteSz = sizeof(UnderlyingType);
471 UnderlyingType _val;
472 using MyClass = LaneData<LS>;
473
474 public:
475 template <typename T> explicit
476 LaneData(typename std::enable_if<sizeof(T) == ByteSz, const T&>::type t)
477 : _val(t) {}
478
479 template <typename T>
480 typename std::enable_if<sizeof(T) == ByteSz, MyClass&>::type
481 operator=(const T& that)
482 {
483 _val = that;
484 return *this;
485 }
486 template<typename T,
487 typename std::enable_if<sizeof(T) == ByteSz, int>::type I = 0>
488 operator T() const {
489 return *static_cast<const T*>(&_val);
490 }
491};
492
493/** Output operator overload for LaneData<Size>. */
494template <LaneSize LS>
495inline std::ostream&
496operator<<(std::ostream& os, const LaneData<LS>& d)
497{
498 return os << static_cast<typename LaneData<LS>::UnderlyingType>(d);
499}
500
501/** Vector Lane abstraction
502 * Another view of a container. This time only a partial part of it is exposed.
503 * @tparam VecElem Type of each element of the vector.
504 * @tparam Const Indicate if the underlying container can be modified through
505 * the view.
506 */
507/** @{ */
508/* General */
509template <typename VecElem, bool Const>
510class VecLaneT
511{
512 public:
513 /** VecRegContainer friendship to access private VecLaneT constructors.
514 * Only VecRegContainers can build VecLanes.
515 */
516 /** @{ */
517 friend VecLaneT<VecElem, !Const>;
518
519 /*template <size_t Sz>
520 friend class VecRegContainer;*/
521 friend class VecRegContainer<8>;
522 friend class VecRegContainer<16>;
523 friend class VecRegContainer<32>;
524 friend class VecRegContainer<64>;
525 friend class VecRegContainer<128>;
526 friend class VecRegContainer<256>;
526 friend class VecRegContainer<MaxVecRegLenInBytes>;
527
528 /** My type alias. */
529 using MyClass = VecLaneT<VecElem, Const>;
530
531 private:
532 using Cont = typename std::conditional<Const,
533 const VecElem,
534 VecElem>::type;
535 static_assert(!std::is_const<VecElem>::value || Const,
536 "Asked for non-const lane of const type!");
537 static_assert(std::is_integral<VecElem>::value,
538 "VecElem type is not integral!");
539 /** Reference to data. */
540 Cont& container;
541
542 /** Constructor */
543 VecLaneT(Cont& cont) : container(cont) { }
544
545 public:
546 /** Assignment operators.
547 * Assignment operators are only enabled if the underlying container is
548 * non-constant.
549 */
550 /** @{ */
551 template <bool Assignable = !Const>
552 typename std::enable_if<Assignable, MyClass&>::type
553 operator=(const VecElem& that) {
554 container = that;
555 return *this;
556 }
557 /**
558 * Generic.
559 * Generic bitwise assignment. Narrowing and widening assignemnts are
560 * not allowed, pre-treatment of the rhs is required to conform.
561 */
562 template <bool Assignable = !Const, typename T>
563 typename std::enable_if<Assignable, MyClass&>::type
564 operator=(const T& that) {
565 static_assert(sizeof(T) >= sizeof(VecElem),
566 "Attempt to perform widening bitwise copy.");
567 static_assert(sizeof(T) <= sizeof(VecElem),
568 "Attempt to perform narrowing bitwise copy.");
569 container = static_cast<VecElem>(that);
570 return *this;
571 }
572 /** @} */
573 /** Cast to vecElem. */
574 operator VecElem() const { return container; }
575
576 /** Constification. */
577 template <bool Cond = !Const, typename std::enable_if<Cond, int>::type = 0>
578 operator VecLaneT<typename std::enable_if<Cond, VecElem>::type, true>()
579 {
580 return VecLaneT<VecElem, true>(container);
581 }
582};
583
584namespace std {
585 template<typename T, bool Const>
586 struct add_const<VecLaneT<T, Const>> { typedef VecLaneT<T, true> type; };
587}
588
589/** View as the Nth lane of type VecElem. */
590template <size_t Sz>
591template <typename VecElem, int LaneIdx>
592VecLaneT<VecElem, false>
593VecRegContainer<Sz>::laneView()
594{
595 return VecLaneT<VecElem, false>(as<VecElem>()[LaneIdx]);
596}
597
598/** View as the const Nth lane of type VecElem. */
599template <size_t Sz>
600template <typename VecElem, int LaneIdx>
601VecLaneT<VecElem, true>
602VecRegContainer<Sz>::laneView() const
603{
604 return VecLaneT<VecElem, true>(as<VecElem>()[LaneIdx]);
605}
606
607/** View as the Nth lane of type VecElem. */
608template <size_t Sz>
609template <typename VecElem>
610VecLaneT<VecElem, false>
611VecRegContainer<Sz>::laneView(int laneIdx)
612{
613 return VecLaneT<VecElem, false>(as<VecElem>()[laneIdx]);
614}
615
616/** View as the const Nth lane of type VecElem. */
617template <size_t Sz>
618template <typename VecElem>
619VecLaneT<VecElem, true>
620VecRegContainer<Sz>::laneView(int laneIdx) const
621{
622 return VecLaneT<VecElem, true>(as<VecElem>()[laneIdx]);
623}
624
625using VecLane8 = VecLaneT<uint8_t, false>;
626using VecLane16 = VecLaneT<uint16_t, false>;
627using VecLane32 = VecLaneT<uint32_t, false>;
628using VecLane64 = VecLaneT<uint64_t, false>;
629
630using ConstVecLane8 = VecLaneT<uint8_t, true>;
631using ConstVecLane16 = VecLaneT<uint16_t, true>;
632using ConstVecLane32 = VecLaneT<uint32_t, true>;
633using ConstVecLane64 = VecLaneT<uint64_t, true>;
634
635/**
636 * Calls required for serialization/deserialization
637 */
638/** @{ */
639template <size_t Sz>
640inline bool
641to_number(const std::string& value, VecRegContainer<Sz>& v)
642{
643 fatal_if(value.size() > 2 * VecRegContainer<Sz>::SIZE,
644 "Vector register value overflow at unserialize");
645
646 for (int i = 0; i < VecRegContainer<Sz>::SIZE; i++) {
647 uint8_t b = 0;
648 if (2 * i < value.size())
649 b = stoul(value.substr(i * 2, 2), nullptr, 16);
650 v.template raw_ptr<uint8_t>()[i] = b;
651 }
652 return true;
653}
654/** @} */
655
656/**
657 * Dummy type aliases and constants for architectures that do not implement
658 * vector registers.
659 */
660/** @{ */
661using DummyVecElem = uint32_t;
662constexpr unsigned DummyNumVecElemPerVecReg = 2;
663using DummyVecReg = VecRegT<DummyVecElem, DummyNumVecElemPerVecReg, false>;
664using DummyConstVecReg = VecRegT<DummyVecElem, DummyNumVecElemPerVecReg, true>;
665using DummyVecRegContainer = DummyVecReg::Container;
666constexpr size_t DummyVecRegSizeBytes = DummyNumVecElemPerVecReg *
667 sizeof(DummyVecElem);
668/** @} */
669
670#endif /* __ARCH_GENERIC_VEC_REG_HH__ */
527 friend class VecRegContainer<MaxVecRegLenInBytes>;
528
529 /** My type alias. */
530 using MyClass = VecLaneT<VecElem, Const>;
531
532 private:
533 using Cont = typename std::conditional<Const,
534 const VecElem,
535 VecElem>::type;
536 static_assert(!std::is_const<VecElem>::value || Const,
537 "Asked for non-const lane of const type!");
538 static_assert(std::is_integral<VecElem>::value,
539 "VecElem type is not integral!");
540 /** Reference to data. */
541 Cont& container;
542
543 /** Constructor */
544 VecLaneT(Cont& cont) : container(cont) { }
545
546 public:
547 /** Assignment operators.
548 * Assignment operators are only enabled if the underlying container is
549 * non-constant.
550 */
551 /** @{ */
552 template <bool Assignable = !Const>
553 typename std::enable_if<Assignable, MyClass&>::type
554 operator=(const VecElem& that) {
555 container = that;
556 return *this;
557 }
558 /**
559 * Generic.
560 * Generic bitwise assignment. Narrowing and widening assignemnts are
561 * not allowed, pre-treatment of the rhs is required to conform.
562 */
563 template <bool Assignable = !Const, typename T>
564 typename std::enable_if<Assignable, MyClass&>::type
565 operator=(const T& that) {
566 static_assert(sizeof(T) >= sizeof(VecElem),
567 "Attempt to perform widening bitwise copy.");
568 static_assert(sizeof(T) <= sizeof(VecElem),
569 "Attempt to perform narrowing bitwise copy.");
570 container = static_cast<VecElem>(that);
571 return *this;
572 }
573 /** @} */
574 /** Cast to vecElem. */
575 operator VecElem() const { return container; }
576
577 /** Constification. */
578 template <bool Cond = !Const, typename std::enable_if<Cond, int>::type = 0>
579 operator VecLaneT<typename std::enable_if<Cond, VecElem>::type, true>()
580 {
581 return VecLaneT<VecElem, true>(container);
582 }
583};
584
585namespace std {
586 template<typename T, bool Const>
587 struct add_const<VecLaneT<T, Const>> { typedef VecLaneT<T, true> type; };
588}
589
590/** View as the Nth lane of type VecElem. */
591template <size_t Sz>
592template <typename VecElem, int LaneIdx>
593VecLaneT<VecElem, false>
594VecRegContainer<Sz>::laneView()
595{
596 return VecLaneT<VecElem, false>(as<VecElem>()[LaneIdx]);
597}
598
599/** View as the const Nth lane of type VecElem. */
600template <size_t Sz>
601template <typename VecElem, int LaneIdx>
602VecLaneT<VecElem, true>
603VecRegContainer<Sz>::laneView() const
604{
605 return VecLaneT<VecElem, true>(as<VecElem>()[LaneIdx]);
606}
607
608/** View as the Nth lane of type VecElem. */
609template <size_t Sz>
610template <typename VecElem>
611VecLaneT<VecElem, false>
612VecRegContainer<Sz>::laneView(int laneIdx)
613{
614 return VecLaneT<VecElem, false>(as<VecElem>()[laneIdx]);
615}
616
617/** View as the const Nth lane of type VecElem. */
618template <size_t Sz>
619template <typename VecElem>
620VecLaneT<VecElem, true>
621VecRegContainer<Sz>::laneView(int laneIdx) const
622{
623 return VecLaneT<VecElem, true>(as<VecElem>()[laneIdx]);
624}
625
626using VecLane8 = VecLaneT<uint8_t, false>;
627using VecLane16 = VecLaneT<uint16_t, false>;
628using VecLane32 = VecLaneT<uint32_t, false>;
629using VecLane64 = VecLaneT<uint64_t, false>;
630
631using ConstVecLane8 = VecLaneT<uint8_t, true>;
632using ConstVecLane16 = VecLaneT<uint16_t, true>;
633using ConstVecLane32 = VecLaneT<uint32_t, true>;
634using ConstVecLane64 = VecLaneT<uint64_t, true>;
635
636/**
637 * Calls required for serialization/deserialization
638 */
639/** @{ */
640template <size_t Sz>
641inline bool
642to_number(const std::string& value, VecRegContainer<Sz>& v)
643{
644 fatal_if(value.size() > 2 * VecRegContainer<Sz>::SIZE,
645 "Vector register value overflow at unserialize");
646
647 for (int i = 0; i < VecRegContainer<Sz>::SIZE; i++) {
648 uint8_t b = 0;
649 if (2 * i < value.size())
650 b = stoul(value.substr(i * 2, 2), nullptr, 16);
651 v.template raw_ptr<uint8_t>()[i] = b;
652 }
653 return true;
654}
655/** @} */
656
657/**
658 * Dummy type aliases and constants for architectures that do not implement
659 * vector registers.
660 */
661/** @{ */
662using DummyVecElem = uint32_t;
663constexpr unsigned DummyNumVecElemPerVecReg = 2;
664using DummyVecReg = VecRegT<DummyVecElem, DummyNumVecElemPerVecReg, false>;
665using DummyConstVecReg = VecRegT<DummyVecElem, DummyNumVecElemPerVecReg, true>;
666using DummyVecRegContainer = DummyVecReg::Container;
667constexpr size_t DummyVecRegSizeBytes = DummyNumVecElemPerVecReg *
668 sizeof(DummyVecElem);
669/** @} */
670
671#endif /* __ARCH_GENERIC_VEC_REG_HH__ */