// See Notices.txt for copyright information
#pragma once
+#include <bits/c++config.h>
+#include <sys/cdefs.h>
#ifndef __cplusplus
#error to use SimpleV Cpp with C, include "simplev_c.h"
#endif
#include <cstdint>
#include <type_traits>
-template <typename ElementType, std::size_t MAX_VL, typename = void>
-struct SVVecTypeStruct;
+// we need to use the register keyword as part of assigning particular variables to registers for
+// inline assembly
+#define DECLARE_ASM_REG(type, name, reg, value) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wregister\"") register type name asm(reg); \
+ _Pragma("GCC diagnostic pop") name = value;
-template <typename ElementType, std::size_t MAX_VL>
-using SVVecType = typename SVVecTypeStruct<ElementType, MAX_VL>::Type;
+namespace sv
+{
+template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL, typename = void>
+struct VecTypeStruct;
+
+template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL>
+using VecType = typename VecTypeStruct<ElementType, SUB_VL, MAX_VL>::Type;
-#define MAKE_VEC_TYPE(size) \
- template <typename ElementType, std::size_t MAX_VL> \
- struct SVVecTypeStruct<ElementType, \
- MAX_VL, \
- std::enable_if_t<sizeof(ElementType) * MAX_VL == (size)>> \
- final \
- { \
- typedef ElementType Type __attribute__((vector_size(size))); \
+#define MAKE_VEC_TYPE(size) \
+ template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL> \
+ struct VecTypeStruct<ElementType, \
+ SUB_VL, \
+ MAX_VL, \
+ std::enable_if_t<sizeof(ElementType) * SUB_VL * MAX_VL == (size)>> \
+ final \
+ { \
+ typedef ElementType Type __attribute__((vector_size(size))); \
};
MAKE_VEC_TYPE(1)
#undef MAKE_VEC_TYPE
-template <typename ElementType, std::size_t MAX_VL>
-struct SVVec final
+template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL>
+struct Vec final
{
- using Type = SVVecType<ElementType, MAX_VL>;
+ static_assert(MAX_VL > 0 && MAX_VL <= 64);
+ static_assert(SUB_VL >= 1 && SUB_VL <= 4);
+ using Type = VecType<ElementType, SUB_VL, MAX_VL>;
Type value;
};
template <size_t MAX_VL = 64>
struct VL final
{
+ static_assert(MAX_VL > 0 && MAX_VL <= 64);
std::size_t value = MAX_VL;
};
-namespace opcodes
-{
inline constexpr std::size_t PRIMARY_OPCODE_SHIFT = 32 - 6;
/// unofficial value. see https://libre-soc.org/openpower/sv/setvl/
/// FIXME: incorrect extended opcode value
inline constexpr std::size_t REG_FIELD_WIDTH = 5;
inline constexpr std::size_t XL_FORM_RT_SHIFT = 32 - REG_FIELD_WIDTH - 6;
inline constexpr std::size_t XL_FORM_RA_SHIFT = 32 - REG_FIELD_WIDTH - 11;
-} // namespace opcodes
+
+constexpr std::uint32_t encode_sv_prefix(std::uint32_t remapped_bits24)
+{
+ std::uint32_t expanded26bits = (remapped_bits24 & 0x3FFFFFUL)
+ | ((remapped_bits24 & 0x400000UL) << 1)
+ | ((remapped_bits24 & 0x800000UL) << 2);
+ expanded26bits |= 0x01400000UL; // set 2 constant-1 bits
+ return expanded26bits | (1UL << PRIMARY_OPCODE_SHIFT);
+}
+
+enum class MaskMode : std::uint32_t
+{
+ Int = 0,
+ CR = 1,
+};
+
+enum class MaskField : std::uint32_t
+{
+ Always = 0,
+ OneShlR3 = 1, // 1 << R3
+ R3 = 2,
+ NotR3 = 3,
+ R10 = 4,
+ NotR10 = 5,
+ R30 = 6,
+ NotR30 = 7,
+
+ Lt = 0,
+ NL = 1,
+ Gt = 2,
+ NG = 3,
+ Eq = 4,
+ NE = 5,
+ SO = 6,
+ NS = 7,
+};
+
+enum class Mode : std::uint32_t
+{
+ Normal = 0,
+ // TODO: fill out
+};
+
+enum class ElementWidth : std::uint32_t
+{
+ I8 = 3,
+ I16 = 2,
+ I32 = 1,
+ I64 = 0,
+ Default = 0,
+ F64 = 0,
+ F32 = 1,
+ F16 = 2,
+ BF16 = 3,
+};
+
+template <typename ElementType,
+ std::size_t ELEMENT_SIZE = sizeof(ElementType),
+ bool IS_INTEGRAL = std::is_integral_v<ElementType>>
+struct ElementProperties;
+
+template <typename ElementType>
+struct ElementProperties<ElementType, 1, true> final
+{
+ static inline constexpr ElementWidth element_width = ElementWidth::I8;
+};
+
+template <typename ElementType>
+struct ElementProperties<ElementType, 2, true> final
+{
+ static inline constexpr ElementWidth element_width = ElementWidth::I16;
+};
+
+template <typename ElementType>
+struct ElementProperties<ElementType, 4, true> final
+{
+ static inline constexpr ElementWidth element_width = ElementWidth::I32;
+};
+
+template <typename ElementType>
+struct ElementProperties<ElementType, 8, true> final
+{
+ static inline constexpr ElementWidth element_width = ElementWidth::I64;
+};
+
+template <>
+struct ElementProperties<float, 4, false> final
+{
+ static inline constexpr ElementWidth element_width = ElementWidth::F32;
+};
+
+template <>
+struct ElementProperties<double, 8, false> final
+{
+ static inline constexpr ElementWidth element_width = ElementWidth::F64;
+};
+
+template <typename ElementType>
+inline constexpr ElementWidth element_width_for = ElementProperties<ElementType>::element_width;
+
+template <std::size_t SUB_VL>
+constexpr std::uint32_t encode_sv_prefix(MaskMode mask_mode,
+ MaskField mask_field,
+ ElementWidth elwidth,
+ ElementWidth elwidth_src,
+ Mode mode,
+ std::uint32_t remapped_bits24)
+{
+ static_assert(SUB_VL >= 1 && SUB_VL <= 4);
+ remapped_bits24 |= static_cast<std::uint32_t>(mask_mode) << (23 - 0);
+ remapped_bits24 |= static_cast<std::uint32_t>(mask_field) << (23 - 3);
+ remapped_bits24 |= static_cast<std::uint32_t>(elwidth) << (23 - 5);
+ remapped_bits24 |= static_cast<std::uint32_t>(elwidth_src) << (23 - 7);
+ remapped_bits24 |= static_cast<std::uint32_t>(SUB_VL - 1) << (23 - 9);
+ remapped_bits24 |= static_cast<std::uint32_t>(mode);
+ return remapped_bits24;
+}
+
+enum class RegExtra2 : std::uint32_t
+{
+ Scalar0 = 0,
+ Scalar1 = 1,
+ Vector0 = 2,
+ Vector1 = 3,
+};
+
+enum class RegExtra3 : std::uint32_t
+{
+ Scalar0 = 0,
+ Scalar1 = 1,
+ Scalar2 = 2,
+ Scalar3 = 3,
+ Vector0 = 4,
+ Vector1 = 5,
+ Vector2 = 6,
+ Vector3 = 7,
+};
+
+template <std::size_t SUB_VL>
+constexpr std::uint32_t encode_sv_prefix_rm_1p_3s1d(MaskMode mask_mode,
+ MaskField mask_field,
+ ElementWidth elwidth,
+ ElementWidth elwidth_src,
+ Mode mode,
+ RegExtra2 rdest_extra2,
+ RegExtra2 rsrc1_extra2,
+ RegExtra2 rsrc2_extra2,
+ RegExtra2 rsrc3_extra2)
+{
+ std::uint32_t remapped_bits24 = 0;
+ remapped_bits24 |= static_cast<std::uint32_t>(rdest_extra2) << (23 - 11);
+ remapped_bits24 |= static_cast<std::uint32_t>(rsrc1_extra2) << (23 - 13);
+ remapped_bits24 |= static_cast<std::uint32_t>(rsrc2_extra2) << (23 - 15);
+ remapped_bits24 |= static_cast<std::uint32_t>(rsrc3_extra2) << (23 - 17);
+ return encode_sv_prefix<SUB_VL>(
+ mask_mode, mask_field, elwidth, elwidth_src, mode, remapped_bits24);
+}
+
+template <std::size_t SUB_VL>
+constexpr std::uint32_t encode_sv_prefix_rm_1p_2s1d(MaskMode mask_mode,
+ MaskField mask_field,
+ ElementWidth elwidth,
+ ElementWidth elwidth_src,
+ Mode mode,
+ RegExtra3 rdest_extra3,
+ RegExtra3 rsrc1_extra3,
+ RegExtra3 rsrc2_extra3)
+{
+ std::uint32_t remapped_bits24 = 0;
+ remapped_bits24 |= static_cast<std::uint32_t>(rdest_extra3) << (23 - 12);
+ remapped_bits24 |= static_cast<std::uint32_t>(rsrc1_extra3) << (23 - 15);
+ remapped_bits24 |= static_cast<std::uint32_t>(rsrc2_extra3) << (23 - 18);
+ return encode_sv_prefix<SUB_VL>(
+ mask_mode, mask_field, elwidth, elwidth_src, mode, remapped_bits24);
+}
#define SETVL_ASM(retval, vl) \
"# setvl " retval ", " vl \
".long %[setvl_opcode] | (" retval " << %[xl_form_rt_shift]) | (" vl \
" << %[xl_form_ra_shift]) | ((%[max_vl] - 1) << %[setvl_immediate_shift])"
-#define SETVL_ASM_INPUT_ARGS() \
- [setvl_opcode] "n"(opcodes::SETVL_OPCODE), \
- [setvl_immediate_shift] "n"(opcodes::SETVL_IMMEDIATE_SHIFT), \
- [xl_form_rt_shift] "n"(opcodes::XL_FORM_RT_SHIFT), \
- [xl_form_ra_shift] "n"(opcodes::XL_FORM_RA_SHIFT)
+#define SETVL_ASM_INPUT_ARGS() \
+ [setvl_opcode] "n"(sv::SETVL_OPCODE), [setvl_immediate_shift] "n"(sv::SETVL_IMMEDIATE_SHIFT), \
+ [xl_form_rt_shift] "n"(sv::XL_FORM_RT_SHIFT), [xl_form_ra_shift] "n"(sv::XL_FORM_RA_SHIFT)
template <std::size_t MAX_VL>
-inline __attribute__((always_inline)) VL<MAX_VL> sv_setvl(std::size_t vl)
+inline __attribute__((always_inline)) VL<MAX_VL> setvl(std::size_t vl)
{
- static_assert(MAX_VL > 0 && MAX_VL < 64);
VL<MAX_VL> retval;
asm(SETVL_ASM("%[retval]", "%[vl]")
: [retval] "=b"(retval.value)
: [vl] "b"(vl), [max_vl] "n"(MAX_VL), SETVL_ASM_INPUT_ARGS());
return retval;
}
+
+template <typename ElementType,
+ std::size_t SUB_VL,
+ std::size_t MAX_VL,
+ typename = std::enable_if_t<std::is_integral_v<ElementType>>>
+inline __attribute__((always_inline)) Vec<ElementType, SUB_VL, MAX_VL> add(
+ Vec<ElementType, SUB_VL, MAX_VL> ra,
+ Vec<ElementType, SUB_VL, MAX_VL> rb,
+ VL<MAX_VL> vl = VL<MAX_VL>(),
+ Mask mask = Mask())
+{
+ constexpr std::uint32_t prefix =
+ encode_sv_prefix_rm_1p_2s1d<SUB_VL>(MaskMode::Int,
+ MaskField::R10,
+ element_width_for<ElementType>,
+ element_width_for<ElementType>,
+ Mode::Normal,
+ RegExtra3::Vector0,
+ RegExtra3::Vector0,
+ RegExtra3::Vector0);
+ Vec<ElementType, SUB_VL, MAX_VL> retval;
+ DECLARE_ASM_REG(std::uint64_t, mask_r10, "r10", mask.value)
+ asm(SETVL_ASM("0", "%[vl]") "\n\t"
+ "# sv.add ew=%[el_width], subvl=%[sub_vl], m=%[mask], %[retval].v, %[ra].v, %[rb].v\n\t"
+ ".long %[prefix]\n\t"
+ "add %[retval], %[ra], %[rb]"
+ : [retval] "=&b"(retval.value)
+ : [vl] "b"(vl),
+ [max_vl] "n"(MAX_VL),
+ [sub_vl] "n"(SUB_VL),
+ [mask] "b"(mask_r10),
+ [ra] "b"(ra.value),
+ [rb] "b"(rb.value),
+ [el_width] "n"(8 * sizeof(ElementType)),
+ [prefix] "n"(prefix),
+ SETVL_ASM_INPUT_ARGS());
+ return retval;
+}
+
+template <typename ElementType,
+ std::size_t SUB_VL,
+ std::size_t MAX_VL,
+ typename = std::enable_if_t<std::is_integral_v<ElementType>>>
+inline __attribute__((always_inline)) Vec<ElementType, SUB_VL, MAX_VL> sub(
+ Vec<ElementType, SUB_VL, MAX_VL> rb, // intentionally reversed since we use sv.subf instruction
+ Vec<ElementType, SUB_VL, MAX_VL> ra,
+ VL<MAX_VL> vl = VL<MAX_VL>(),
+ Mask mask = Mask())
+{
+ constexpr std::uint32_t prefix =
+ encode_sv_prefix_rm_1p_2s1d<SUB_VL>(MaskMode::Int,
+ MaskField::R10,
+ element_width_for<ElementType>,
+ element_width_for<ElementType>,
+ Mode::Normal,
+ RegExtra3::Vector0,
+ RegExtra3::Vector0,
+ RegExtra3::Vector0);
+ Vec<ElementType, SUB_VL, MAX_VL> retval;
+ DECLARE_ASM_REG(std::uint64_t, mask_r10, "r10", mask.value)
+ asm(SETVL_ASM("0", "%[vl]") "\n\t"
+ "# sv.subf ew=%[el_width], subvl=%[sub_vl], m=%[mask], %[retval].v, %[ra].v, %[rb].v\n\t"
+ ".long %[prefix]\n\t"
+ "subf %[retval], %[ra], %[rb]"
+ : [retval] "=&b"(retval.value)
+ : [vl] "b"(vl),
+ [max_vl] "n"(MAX_VL),
+ [sub_vl] "n"(SUB_VL),
+ [mask] "b"(mask_r10),
+ [ra] "b"(ra.value),
+ [rb] "b"(rb.value),
+ [el_width] "n"(8 * sizeof(ElementType)),
+ [prefix] "n"(prefix),
+ SETVL_ASM_INPUT_ARGS());
+ return retval;
+}
+
+#undef SETVL_ASM
+#undef SETVL_ASM_INPUT_ARGS
+#undef DECLARE_ASM_REG
+} // namespace sv