File indexing completed on 2025-08-28 09:11:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef XSIMD_RVV_REGISTER_HPP
0014 #define XSIMD_RVV_REGISTER_HPP
0015
0016 #include "xsimd_generic_arch.hpp"
0017 #include "xsimd_register.hpp"
0018
0019 #if XSIMD_WITH_RVV
0020 #include <riscv_vector.h>
0021 #endif
0022
0023 namespace xsimd
0024 {
0025 namespace detail
0026 {
0027
0028
0029
0030
0031
0032 template <size_t Width>
0033 struct rvv : xsimd::generic
0034 {
0035 static constexpr size_t width = Width;
0036 static constexpr bool supported() noexcept { return Width == XSIMD_RVV_BITS; }
0037 static constexpr bool available() noexcept { return true; }
0038 static constexpr bool requires_alignment() noexcept { return true; }
0039 static constexpr std::size_t alignment() noexcept { return 16; }
0040 static constexpr char const* name() noexcept { return "riscv+rvv"; }
0041 };
0042 }
0043
0044 #if XSIMD_WITH_RVV
0045
0046 using rvv = detail::rvv<__riscv_v_fixed_vlen>;
0047
0048 #define XSIMD_RVV_JOINT_(a, b, c) a##b##c
0049 #define XSIMD_RVV_JOINT(a, b, c) XSIMD_RVV_JOINT_(a, b, c)
0050 #define XSIMD_RVV_JOINT5(a, b, c, d, e) XSIMD_RVV_JOINT(XSIMD_RVV_JOINT(a, b, c), d, e)
0051
0052 #define XSIMD_RVV_TYPE_i(S, V) XSIMD_RVV_JOINT5(vint, S, m, V, _t)
0053 #define XSIMD_RVV_TYPE_u(S, V) XSIMD_RVV_JOINT5(vuint, S, m, V, _t)
0054 #define XSIMD_RVV_TYPE_f(S, V) XSIMD_RVV_JOINT5(vfloat, S, m, V, _t)
0055 #define XSIMD_RVV_TYPE(T, S, V) XSIMD_RVV_JOINT(XSIMD_RVV_TYPE, _, T)(S, V)
0056
0057 namespace types
0058 {
0059 namespace detail
0060 {
0061 static constexpr size_t rvv_width_mf8 = XSIMD_RVV_BITS / 8;
0062 static constexpr size_t rvv_width_mf4 = XSIMD_RVV_BITS / 4;
0063 static constexpr size_t rvv_width_mf2 = XSIMD_RVV_BITS / 2;
0064 static constexpr size_t rvv_width_m1 = XSIMD_RVV_BITS;
0065 static constexpr size_t rvv_width_m2 = XSIMD_RVV_BITS * 2;
0066 static constexpr size_t rvv_width_m4 = XSIMD_RVV_BITS * 4;
0067 static constexpr size_t rvv_width_m8 = XSIMD_RVV_BITS * 8;
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 template <class T, size_t Width>
0081 struct rvv_type_info;
0082 #define XSIMD_RVV_MAKE_TYPE(scalar, t, s, vmul) \
0083 template <> \
0084 struct rvv_type_info<scalar, rvv_width_m1 * vmul> \
0085 { \
0086 static constexpr size_t width = rvv_width_m1 * vmul; \
0087 using type = XSIMD_RVV_TYPE(t, s, vmul); \
0088 using byte_type = XSIMD_RVV_TYPE(u, 8, vmul); \
0089 using fixed_type = type __attribute__((riscv_rvv_vector_bits(width))); \
0090 template <class U> \
0091 static XSIMD_INLINE type bitcast(U x) noexcept \
0092 { \
0093 const auto words = XSIMD_RVV_JOINT5(__riscv_vreinterpret_, u, s, m, vmul)(x); \
0094 return XSIMD_RVV_JOINT5(__riscv_vreinterpret_, t, s, m, vmul)(words); \
0095 } \
0096 template <> \
0097 XSIMD_INLINE type bitcast<type>(type x) noexcept { return x; } \
0098 template <class U> \
0099 static XSIMD_INLINE byte_type as_bytes(U x) noexcept \
0100 { \
0101 static_assert(std::is_same<U, type>::value, "inconsistent conversion types"); \
0102 const auto words = XSIMD_RVV_JOINT5(__riscv_vreinterpret_, u, s, m, vmul)(x); \
0103 return XSIMD_RVV_JOINT5(__riscv_vreinterpret_, u, 8, m, vmul)(words); \
0104 } \
0105 };
0106
0107 #define XSIMD_RVV_MAKE_TYPES(vmul) \
0108 XSIMD_RVV_MAKE_TYPE(int8_t, i, 8, vmul) \
0109 XSIMD_RVV_MAKE_TYPE(uint8_t, u, 8, vmul) \
0110 XSIMD_RVV_MAKE_TYPE(int16_t, i, 16, vmul) \
0111 XSIMD_RVV_MAKE_TYPE(uint16_t, u, 16, vmul) \
0112 XSIMD_RVV_MAKE_TYPE(int32_t, i, 32, vmul) \
0113 XSIMD_RVV_MAKE_TYPE(uint32_t, u, 32, vmul) \
0114 XSIMD_RVV_MAKE_TYPE(int64_t, i, 64, vmul) \
0115 XSIMD_RVV_MAKE_TYPE(uint64_t, u, 64, vmul) \
0116 XSIMD_RVV_MAKE_TYPE(float, f, 32, vmul) \
0117 XSIMD_RVV_MAKE_TYPE(double, f, 64, vmul)
0118
0119 XSIMD_RVV_MAKE_TYPES(8)
0120 XSIMD_RVV_MAKE_TYPES(4)
0121 XSIMD_RVV_MAKE_TYPES(2)
0122 XSIMD_RVV_MAKE_TYPES(1)
0123 #undef XSIMD_RVV_TYPE
0124 #undef XSIMD_RVV_TYPE_f
0125 #undef XSIMD_RVV_TYPE_u
0126 #undef XSIMD_RVV_TYPE_i
0127 #undef XSIMD_RVV_MAKE_TYPES
0128 #undef XSIMD_RVV_MAKE_TYPE
0129
0130
0131 template <>
0132 XSIMD_INLINE rvv_type_info<int8_t, rvv_width_m1 * 8>::type
0133 rvv_type_info<int8_t, rvv_width_m1 * 8>::bitcast<__rvv_uint8m8_t>(
0134 __rvv_uint8m8_t x) noexcept
0135 {
0136 return __riscv_vreinterpret_i8m8(x);
0137 }
0138 template <>
0139 XSIMD_INLINE rvv_type_info<int8_t, rvv_width_m1 * 1>::type
0140 rvv_type_info<int8_t, rvv_width_m1 * 1>::bitcast<__rvv_uint8m1_t>(
0141 __rvv_uint8m1_t x) noexcept
0142 {
0143 return __riscv_vreinterpret_i8m1(x);
0144 }
0145 template <>
0146 XSIMD_INLINE rvv_type_info<uint16_t, rvv_width_m1 * 1>::type
0147 rvv_type_info<uint16_t, rvv_width_m1 * 1>::bitcast<__rvv_uint8m1_t>(
0148 __rvv_uint8m1_t x) noexcept
0149 {
0150 return __riscv_vreinterpret_u16m1(x);
0151 }
0152 template <>
0153 XSIMD_INLINE rvv_type_info<uint32_t, rvv_width_m1 * 1>::type
0154 rvv_type_info<uint32_t, rvv_width_m1 * 1>::bitcast<__rvv_uint8m1_t>(
0155 __rvv_uint8m1_t x) noexcept
0156 {
0157 return __riscv_vreinterpret_u32m1(x);
0158 }
0159 template <>
0160 XSIMD_INLINE rvv_type_info<uint64_t, rvv_width_m1 * 1>::type
0161 rvv_type_info<uint64_t, rvv_width_m1 * 1>::bitcast<__rvv_uint8m1_t>(
0162 __rvv_uint8m1_t x) noexcept
0163 {
0164 return __riscv_vreinterpret_u64m1(x);
0165 }
0166
0167
0168
0169 template <>
0170 XSIMD_INLINE rvv_type_info<int8_t, rvv_width_m1 * 8>::byte_type
0171 rvv_type_info<int8_t, rvv_width_m1 * 8>::as_bytes<__rvv_int8m8_t>(__rvv_int8m8_t x) noexcept
0172 {
0173 return __riscv_vreinterpret_u8m8(x);
0174 }
0175 template <>
0176 XSIMD_INLINE rvv_type_info<int8_t, rvv_width_m1 * 1>::byte_type
0177 rvv_type_info<int8_t, rvv_width_m1 * 1>::as_bytes<__rvv_int8m1_t>(__rvv_int8m1_t x) noexcept
0178 {
0179 return __riscv_vreinterpret_u8m1(x);
0180 }
0181
0182 template <>
0183 XSIMD_INLINE rvv_type_info<uint8_t, rvv_width_m1 * 1>::byte_type
0184 rvv_type_info<uint8_t, rvv_width_m1 * 1>::as_bytes<__rvv_uint8m1_t>(__rvv_uint8m1_t x) noexcept
0185 {
0186 return x;
0187 }
0188 template <>
0189 XSIMD_INLINE rvv_type_info<uint16_t, rvv_width_m1 * 1>::byte_type
0190 rvv_type_info<uint16_t, rvv_width_m1 * 1>::as_bytes<__rvv_uint16m1_t>(__rvv_uint16m1_t x) noexcept
0191 {
0192 return __riscv_vreinterpret_u8m1(x);
0193 }
0194 template <>
0195 XSIMD_INLINE rvv_type_info<uint32_t, rvv_width_m1 * 1>::byte_type
0196 rvv_type_info<uint32_t, rvv_width_m1 * 1>::as_bytes<__rvv_uint32m1_t>(__rvv_uint32m1_t x) noexcept
0197 {
0198 return __riscv_vreinterpret_u8m1(x);
0199 }
0200 template <>
0201 XSIMD_INLINE rvv_type_info<uint64_t, rvv_width_m1 * 1>::byte_type
0202 rvv_type_info<uint64_t, rvv_width_m1 * 1>::as_bytes<__rvv_uint64m1_t>(__rvv_uint64m1_t x) noexcept
0203 {
0204 return __riscv_vreinterpret_u8m1(x);
0205 }
0206
0207
0208 template <class T, size_t Width>
0209 struct rvv_blob : public rvv_type_info<T, Width>
0210 {
0211 using super = rvv_type_info<T, Width>;
0212 using typename super::fixed_type;
0213 using typename super::type;
0214
0215 fixed_type value;
0216 type get() const { return value; }
0217 void set(type v) { value = v; }
0218 };
0219
0220
0221
0222
0223
0224
0225
0226
0227 template <class T, size_t divisor>
0228 struct rvv_semiblob : public rvv_type_info<T, rvv_width_m1>
0229 {
0230 using super = rvv_type_info<T, rvv_width_m1>;
0231 static constexpr size_t width = rvv_width_m1 / divisor;
0232 using typename super::type;
0233 template <size_t div>
0234 struct semitype;
0235 template <>
0236 struct semitype<2>
0237 {
0238 using type = vuint8mf2_t __attribute__((riscv_rvv_vector_bits(rvv_width_mf2)));
0239 };
0240 template <>
0241 struct semitype<4>
0242 {
0243 using type = vuint8mf4_t __attribute__((riscv_rvv_vector_bits(rvv_width_mf4)));
0244 };
0245 template <>
0246 struct semitype<8>
0247 {
0248 using type = vuint8mf8_t __attribute__((riscv_rvv_vector_bits(rvv_width_mf8)));
0249 };
0250 using fixed_type = typename semitype<divisor>::type;
0251 using super::as_bytes;
0252 using super::bitcast;
0253
0254 fixed_type value;
0255 template <size_t div>
0256 vuint8m1_t get_bytes() const;
0257 template <>
0258 vuint8m1_t get_bytes<2>() const { return __riscv_vlmul_ext_v_u8mf2_u8m1(value); }
0259 template <>
0260 vuint8m1_t get_bytes<4>() const { return __riscv_vlmul_ext_v_u8mf4_u8m1(value); }
0261 template <>
0262 vuint8m1_t get_bytes<8>() const { return __riscv_vlmul_ext_v_u8mf8_u8m1(value); }
0263 type get() const noexcept
0264 {
0265 vuint8m1_t bytes = get_bytes<divisor>();
0266 return bitcast(bytes);
0267 }
0268 template <size_t div>
0269 void set_bytes(vuint8m1_t);
0270 template <>
0271 void set_bytes<2>(vuint8m1_t v) { value = __riscv_vlmul_trunc_v_u8m1_u8mf2(v); }
0272 template <>
0273 void set_bytes<4>(vuint8m1_t v) { value = __riscv_vlmul_trunc_v_u8m1_u8mf4(v); }
0274 template <>
0275 void set_bytes<8>(vuint8m1_t v) { value = __riscv_vlmul_trunc_v_u8m1_u8mf8(v); }
0276 void set(type v)
0277 {
0278 vuint8m1_t bytes = as_bytes(v);
0279 set_bytes<divisor>(bytes);
0280 }
0281 };
0282 template <class T>
0283 struct rvv_blob<T, rvv_width_mf2> : rvv_semiblob<T, 2>
0284 {
0285 };
0286 template <class T>
0287 struct rvv_blob<T, rvv_width_mf4> : rvv_semiblob<T, 4>
0288 {
0289 };
0290 template <class T>
0291 struct rvv_blob<T, rvv_width_mf8> : rvv_semiblob<T, 8>
0292 {
0293 };
0294
0295
0296
0297
0298 using rvv_char_t = typename std::conditional<std::is_signed<char>::value, int8_t, uint8_t>::type;
0299 template <class T>
0300 using rvv_fix_char_t = typename std::conditional<
0301 std::is_same<char, typename std::decay<T>::type>::value,
0302 rvv_char_t, T>::type;
0303
0304
0305
0306
0307
0308 enum rvv_bitcast_flag
0309 {
0310 XSIMD_RVV_BITCAST
0311 };
0312
0313
0314
0315
0316
0317
0318 template <class T, size_t Width>
0319 struct rvv_reg
0320 {
0321 static constexpr size_t width = Width;
0322 static constexpr size_t vl = Width / (sizeof(T) * 8);
0323 using blob_type = rvv_blob<T, Width>;
0324 using register_type = typename blob_type::type;
0325 using byte_type = typename blob_type::byte_type;
0326 blob_type value;
0327 rvv_reg() noexcept = default;
0328 rvv_reg(register_type x) noexcept { value.set(x); }
0329 explicit rvv_reg(byte_type v, rvv_bitcast_flag) { value.set(value.bitcast(v)); }
0330 template <class U>
0331 explicit rvv_reg(rvv_reg<U, Width> v, rvv_bitcast_flag)
0332 : rvv_reg(v.get_bytes(), XSIMD_RVV_BITCAST)
0333 {
0334 }
0335 byte_type get_bytes() const noexcept
0336 {
0337 return blob_type::as_bytes(value.get());
0338 }
0339 operator register_type() const noexcept { return value.get(); }
0340 };
0341 template <class T, size_t Width = XSIMD_RVV_BITS>
0342 using rvv_reg_t = typename std::conditional<!std::is_void<T>::value, rvv_reg<rvv_fix_char_t<T>, Width>, void>::type;
0343
0344
0345
0346
0347 template <size_t>
0348 struct rvv_bool_info;
0349 #define XSIMD_RVV_MAKE_BOOL_TYPE(i) \
0350 template <> \
0351 struct rvv_bool_info<i> \
0352 { \
0353 using type = XSIMD_RVV_JOINT(vbool, i, _t); \
0354 template <class T> \
0355 static XSIMD_INLINE type bitcast(T value) noexcept \
0356 { \
0357 return XSIMD_RVV_JOINT(__riscv_vreinterpret_b, i, )(value); \
0358 } \
0359 \
0360 };
0361 XSIMD_RVV_MAKE_BOOL_TYPE(1);
0362 XSIMD_RVV_MAKE_BOOL_TYPE(2);
0363 XSIMD_RVV_MAKE_BOOL_TYPE(4);
0364 XSIMD_RVV_MAKE_BOOL_TYPE(8);
0365 XSIMD_RVV_MAKE_BOOL_TYPE(16);
0366 XSIMD_RVV_MAKE_BOOL_TYPE(32);
0367 XSIMD_RVV_MAKE_BOOL_TYPE(64);
0368 #undef XSIMD_RVV_MAKE_BOOL_TYPE
0369 #undef XSIMD_RVV_JOINT5
0370 #undef XSIMD_RVV_JOINT
0371 #undef XSIMD_RVV_JOINT_
0372
0373 template <class T, size_t Width>
0374 struct rvv_bool
0375 {
0376 using bool_info = rvv_bool_info<rvv_width_m1 * sizeof(T) * 8 / Width>;
0377 using storage_type = vuint8m1_t __attribute__((riscv_rvv_vector_bits(rvv_width_m1)));
0378 using type = typename bool_info::type;
0379 storage_type value;
0380 rvv_bool() = default;
0381 rvv_bool(type v) noexcept
0382 : value(__riscv_vreinterpret_u8m1(v))
0383 {
0384 }
0385 template <class U, typename std::enable_if<sizeof(T) == sizeof(U), int>::type = 0>
0386 rvv_bool(rvv_bool<U, Width> v)
0387 : value(v.value)
0388 {
0389 }
0390 explicit rvv_bool(uint8_t mask) noexcept
0391 : value(__riscv_vmv_v_x_u8m1(mask, rvv_width_m1 / 8))
0392 {
0393 }
0394 explicit rvv_bool(uint64_t mask) noexcept
0395 : value(__riscv_vreinterpret_v_u64m1_u8m1(__riscv_vmv_v_x_u64m1(mask, rvv_width_m1 / 64)))
0396 {
0397 }
0398 operator type() const noexcept { return bool_info::bitcast(value); }
0399 };
0400
0401 template <class T, size_t Width = XSIMD_RVV_BITS>
0402 using rvv_bool_t = typename std::enable_if < !std::is_void<T>::value,
0403 rvv_bool<rvv_fix_char_t<T>, Width<rvv_width_m1 ? rvv_width_m1 : Width>>::type;
0404
0405 template <size_t S>
0406 struct rvv_vector_type_impl;
0407
0408 template <>
0409 struct rvv_vector_type_impl<8>
0410 {
0411 using signed_type = rvv_reg_t<int8_t>;
0412 using unsigned_type = rvv_reg_t<uint8_t>;
0413 using floating_point_type = void;
0414 };
0415
0416 template <>
0417 struct rvv_vector_type_impl<16>
0418 {
0419 using signed_type = rvv_reg_t<int16_t>;
0420 using unsigned_type = rvv_reg_t<uint16_t>;
0421 using floating_point_type = rvv_reg_t<_Float16>;
0422 };
0423
0424 template <>
0425 struct rvv_vector_type_impl<32>
0426 {
0427 using signed_type = rvv_reg_t<int32_t>;
0428 using unsigned_type = rvv_reg_t<uint32_t>;
0429 using floating_point_type = rvv_reg_t<float>;
0430 };
0431
0432 template <>
0433 struct rvv_vector_type_impl<64>
0434 {
0435 using signed_type = rvv_reg_t<int64_t>;
0436 using unsigned_type = rvv_reg_t<uint64_t>;
0437 using floating_point_type = rvv_reg_t<double>;
0438 };
0439
0440 template <class T>
0441 using signed_int_rvv_vector_type = typename rvv_vector_type_impl<8 * sizeof(T)>::signed_type;
0442
0443 template <class T>
0444 using unsigned_int_rvv_vector_type = typename rvv_vector_type_impl<8 * sizeof(T)>::unsigned_type;
0445
0446 template <class T>
0447 using floating_point_rvv_vector_type = typename rvv_vector_type_impl<8 * sizeof(T)>::floating_point_type;
0448
0449 template <class T>
0450 using signed_int_or_floating_point_rvv_vector_type = typename std::conditional<std::is_floating_point<T>::value,
0451 floating_point_rvv_vector_type<T>,
0452 signed_int_rvv_vector_type<T>>::type;
0453
0454 template <class T>
0455 using rvv_vector_type = typename std::conditional<std::is_signed<T>::value,
0456 signed_int_or_floating_point_rvv_vector_type<T>,
0457 unsigned_int_rvv_vector_type<T>>::type;
0458 }
0459
0460 XSIMD_DECLARE_SIMD_REGISTER(bool, rvv, detail::rvv_vector_type<unsigned char>);
0461 XSIMD_DECLARE_SIMD_REGISTER(signed char, rvv, detail::rvv_vector_type<signed char>);
0462 XSIMD_DECLARE_SIMD_REGISTER(unsigned char, rvv, detail::rvv_vector_type<unsigned char>);
0463 XSIMD_DECLARE_SIMD_REGISTER(char, rvv, detail::rvv_vector_type<char>);
0464 XSIMD_DECLARE_SIMD_REGISTER(short, rvv, detail::rvv_vector_type<short>);
0465 XSIMD_DECLARE_SIMD_REGISTER(unsigned short, rvv, detail::rvv_vector_type<unsigned short>);
0466 XSIMD_DECLARE_SIMD_REGISTER(int, rvv, detail::rvv_vector_type<int>);
0467 XSIMD_DECLARE_SIMD_REGISTER(unsigned int, rvv, detail::rvv_vector_type<unsigned int>);
0468 XSIMD_DECLARE_SIMD_REGISTER(long int, rvv, detail::rvv_vector_type<long int>);
0469 XSIMD_DECLARE_SIMD_REGISTER(unsigned long int, rvv, detail::rvv_vector_type<unsigned long int>);
0470 XSIMD_DECLARE_SIMD_REGISTER(long long int, rvv, detail::rvv_vector_type<long long int>);
0471 XSIMD_DECLARE_SIMD_REGISTER(unsigned long long int, rvv, detail::rvv_vector_type<unsigned long long int>);
0472 XSIMD_DECLARE_SIMD_REGISTER(float, rvv, detail::rvv_vector_type<float>);
0473 XSIMD_DECLARE_SIMD_REGISTER(double, rvv, detail::rvv_vector_type<double>);
0474
0475 namespace detail
0476 {
0477 template <class T>
0478 struct rvv_bool_simd_register
0479 {
0480 using register_type = rvv_bool_t<T>;
0481 register_type data;
0482 operator register_type() const noexcept { return data; }
0483 };
0484 }
0485
0486 template <class T>
0487 struct get_bool_simd_register<T, rvv>
0488 {
0489 using type = detail::rvv_bool_simd_register<T>;
0490 };
0491 }
0492 #else
0493 using rvv = detail::rvv<0xFFFFFFFF>;
0494 #endif
0495 }
0496
0497 #endif