Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-28 09:11:40

0001 /***************************************************************************
0002  * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and         *
0003  * Martin Renou                                                             *
0004  * Copyright (c) QuantStack                                                 *
0005  * Copyright (c) Serge Guelton                                              *
0006  * Copyright (c) Yibo Cai                                                   *
0007  *                                                                          *
0008  * Distributed under the terms of the BSD 3-Clause License.                 *
0009  *                                                                          *
0010  * The full license is in the file LICENSE, distributed with this software. *
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          * @ingroup architectures
0029          *
0030          * RVV instructions (fixed vector size) for riscv
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             // rvv_type_info is a utility class to convert scalar type and
0070             // bitwidth into rvv register types.
0071             //
0072             // * `type` is the unadorned vector type.
0073             // * `fixed_type` is the same type, but with the storage attribute
0074             //    applied.
0075             // * `byte_type` is the type which is the same size in unsigned
0076             //    bytes, used as an intermediate step for bit-cast operations,
0077             //    because only a subset of __riscv_vreinterpret() intrinsics
0078             //    exist -- but always enough to get us to bytes and back.
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             // Specialization needed for #1058
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             // rvv_blob is storage-type abstraction for a vector register.
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             // But sometimes we want our storage type to be less than a whole
0221             // register, while presenting as a whole register to the outside
0222             // world.  This is because some partial-register types are not
0223             // defined, but they can (mostly) be emulated using shorter vl on a
0224             // full-width register for arithmetic, and cast back to a partial
0225             // byte register for storage.
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             // It's difficult dealing with both char and whichever *int8_t type
0296             // is compatible with char, so just avoid it altogether.
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             // An explicit constructor isn't really explicit enough to allow
0305             // implicit bit-casting operations between incompatible types, so
0306             // we add this vacuous flag argument when we're serious:
0307             //
0308             enum rvv_bitcast_flag
0309             {
0310                 XSIMD_RVV_BITCAST
0311             };
0312 
0313             // the general-purpose vector register type, usable within
0314             // templates, and supporting arithmetic on partial registers for
0315             // which there is no intrinsic type (by casting via a full register
0316             // type).
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             // And some more of the same stuff for bool types, which have
0345             // similar problems and similar workarounds.
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         /*template <> static XSIMD_INLINE type bitcast(type value) noexcept { return value; }*/ \
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         } // namespace detail
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         } // namespace detail
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     } // namespace types
0492 #else
0493     using rvv = detail::rvv<0xFFFFFFFF>;
0494 #endif
0495 } // namespace xsimd
0496 
0497 #endif