add setvl
[simplev-cpp.git] / include / simplev_cpp.h
index 7d9d40d002985dae2f23e9fecb8d225d9c242ed7..297f71ba52b19cf0759ab3e06aedd0a947e1c7fd 100644 (file)
@@ -1,3 +1,92 @@
 // SPDX-License-Identifier: LGPL-2.1-or-later
 // See Notices.txt for copyright information
-#pragma once
\ No newline at end of file
+#pragma once
+
+#ifndef __cplusplus
+#error to use SimpleV Cpp with C, include "simplev_c.h"
+#endif
+
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+template <typename ElementType, std::size_t MAX_VL, typename = void>
+struct SVVecTypeStruct;
+
+template <typename ElementType, std::size_t MAX_VL>
+using SVVecType = typename SVVecTypeStruct<ElementType, 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)));                 \
+    };
+
+MAKE_VEC_TYPE(1)
+MAKE_VEC_TYPE(2)
+MAKE_VEC_TYPE(3)
+MAKE_VEC_TYPE(4)
+MAKE_VEC_TYPE(5)
+MAKE_VEC_TYPE(6)
+MAKE_VEC_TYPE(7)
+MAKE_VEC_TYPE(8)
+
+#undef MAKE_VEC_TYPE
+
+template <typename ElementType, std::size_t MAX_VL>
+struct SVVec final
+{
+    using Type = SVVecType<ElementType, MAX_VL>;
+    Type value;
+};
+
+struct Mask final
+{
+    std::uint64_t value = ~0ULL;
+};
+
+template <size_t MAX_VL = 64>
+struct VL final
+{
+    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::uint32_t SETVL_OPCODE = (19 << PRIMARY_OPCODE_SHIFT) | (0 << 1);
+inline constexpr std::size_t SETVL_IMMEDIATE_SHIFT = 32 - 7 - 16;
+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
+
+#define SETVL_ASM(retval, vl)                                            \
+    "# setvl " retval ", " vl                                            \
+    ", MVL=%[max_vl]\n\t"                                                \
+    ".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)
+
+template <std::size_t MAX_VL>
+inline __attribute__((always_inline)) VL<MAX_VL> sv_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;
+}