From 1b54b3be7c1cad240783830379f3da0dcc873381 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Thu, 23 Jul 2026 14:32:40 +0300 Subject: [PATCH 01/10] Add RISC-V Vector Extension config macro The BOOST_UUID_USE_RISCV_V config macro is automatically defined when the compiler defines __riscv_v, indicating RISC-V Vector Extension (V 1.0+) support is available. The macro is also added to the BOOST_UUID_NO_SIMD exclusion list. --- include/boost/uuid/detail/config.hpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/boost/uuid/detail/config.hpp b/include/boost/uuid/detail/config.hpp index 0d886eff..29752e10 100644 --- a/include/boost/uuid/detail/config.hpp +++ b/include/boost/uuid/detail/config.hpp @@ -29,6 +29,7 @@ #undef BOOST_UUID_USE_AVX2 #undef BOOST_UUID_USE_AVX512_V1 #undef BOOST_UUID_USE_AVX10_1 +#undef BOOST_UUID_USE_RISCV_V #else @@ -91,6 +92,15 @@ #endif +#if defined(__riscv_v) + +// RISC-V Vector Extension (V 1.0+), GCC 12+ / Clang 15+ +#ifndef BOOST_UUID_USE_RISCV_V +#define BOOST_UUID_USE_RISCV_V +#endif + +#endif + // More advanced ISA extensions imply less advanced are also available #if !defined(BOOST_UUID_USE_AVX512_V1) && defined(BOOST_UUID_USE_AVX10_1) #define BOOST_UUID_USE_AVX512_V1 @@ -128,7 +138,8 @@ !defined(BOOST_UUID_USE_SSE41) && \ !defined(BOOST_UUID_USE_SSSE3) && \ !defined(BOOST_UUID_USE_SSE3) && \ - !defined(BOOST_UUID_USE_SSE2) + !defined(BOOST_UUID_USE_SSE2) && \ + !defined(BOOST_UUID_USE_RISCV_V) #define BOOST_UUID_NO_SIMD #endif From a3b8f19c17861507a13cbbfa4b9b396f82699694 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Thu, 23 Jul 2026 14:32:51 +0300 Subject: [PATCH 02/10] Add RISC-V Vector implementation of from_chars This adds a RISC-V Vector (RVV) implementation of the from_chars algorithm, ported from the x86 SIMD implementation. The RVV version supports VLEN >= 128 and handles narrow and wide character types (char, char16_t, char32_t). The implementation follows the same structure as from_chars_x86.hpp: deinterleaving of input character pairs, dash validation, hex character validation, and nibble packing. It uses two separate expected dash vectors (one per character pair) instead of x86's single shuffled vector, as RVV's vrgather-based deinterleaving makes this approach more natural. The generic fallback path is preserved: both the x86 and RISC-V SIMD paths dispatch to from_chars_generic when std::is_constant_evaluated() is true. --- include/boost/uuid/detail/from_chars.hpp | 5 +- .../boost/uuid/detail/from_chars_riscv.hpp | 735 ++++++++++++++++++ 2 files changed, 739 insertions(+), 1 deletion(-) create mode 100644 include/boost/uuid/detail/from_chars_riscv.hpp diff --git a/include/boost/uuid/detail/from_chars.hpp b/include/boost/uuid/detail/from_chars.hpp index 2639a724..572b598a 100644 --- a/include/boost/uuid/detail/from_chars.hpp +++ b/include/boost/uuid/detail/from_chars.hpp @@ -14,6 +14,9 @@ #if defined(BOOST_UUID_USE_SSE2) # include +#elif defined(BOOST_UUID_USE_RISCV_V) +# include + #elif defined(BOOST_UUID_REPORT_IMPLEMENTATION) # include BOOST_PRAGMA_MESSAGE( "Using from_chars_generic.hpp" ) @@ -27,7 +30,7 @@ template BOOST_UUID_CXX14_CONSTEXPR_RT inline from_chars_result from_chars( Ch const* first, Ch const* last, uuid& u ) noexcept { -#if defined(BOOST_UUID_USE_SSE2) +#if defined(BOOST_UUID_USE_SSE2) || defined(BOOST_UUID_USE_RISCV_V) if( detail::is_constant_evaluated_rt() ) { return detail::from_chars_generic( first, last, u ); diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp new file mode 100644 index 00000000..39353058 --- /dev/null +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -0,0 +1,735 @@ +#ifndef BOOST_UUID_DETAIL_FROM_CHARS_RISCV_HPP_INCLUDED +#define BOOST_UUID_DETAIL_FROM_CHARS_RISCV_HPP_INCLUDED + +// Copyright 2025 Andrey Semashev +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +#if defined(BOOST_UUID_USE_RISCV_V) + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_UUID_REPORT_IMPLEMENTATION) +#include +BOOST_PRAGMA_MESSAGE( "Using from_chars_riscv.hpp, RISC-V Vector Extension" ) +#endif // #if defined(BOOST_UUID_REPORT_IMPLEMENTATION) + +namespace boost { +namespace uuids { +namespace detail { + +template< + typename Char, + bool IsCharASCIICompatible = ('0' == 0x30 && '9' == 0x39 && 'A' == 0x41 && 'F' == 0x46 && 'a' == 0x61 && 'f' == 0x66 && '-' == 0x2D), + bool IsWCharASCIICompatible = (L'0' == 0x30 && L'9' == 0x39 && L'A' == 0x41 && L'F' == 0x46 && L'a' == 0x61 && L'f' == 0x66 && L'-' == 0x2D) +> +struct from_chars_simd_char_constants +{ + static const simd_vector128< std::uint8_t > mm_expected_dashes1; + static const simd_vector128< std::uint8_t > mm_expected_dashes2; + + static constexpr std::uint8_t char_code2 = 0x61; // 'a' in ASCII + static constexpr std::uint8_t char_code2_sub = static_cast< std::uint8_t >(char_code2 - 10u); + static constexpr std::uint8_t char_code1 = 0x41; // 'A' in ASCII + static constexpr std::uint8_t char_code1_sub = static_cast< std::uint8_t >(char_code1 - 10u); + static constexpr std::uint8_t char_code0 = 0x30; // '0' in ASCII + static constexpr std::uint8_t char_code0_sub = char_code0; + + static constexpr std::uint32_t char_code_sub = + (static_cast< std::uint32_t >(char_code0_sub) << 16u) | (static_cast< std::uint32_t >(char_code1_sub) << 8u) | char_code2_sub; + + static const simd_vector128< std::uint8_t > mm_char_code2_cmp; + static const simd_vector128< std::uint8_t > mm_char_code1_cmp; + + static const simd_vector128< std::uint8_t > mm_char_code2_sub; + static const simd_vector128< std::uint8_t > mm_char_code1_sub; + static const simd_vector128< std::uint8_t > mm_char_code0_sub; +}; + +template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_expected_dashes1 = + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00 }}; + +template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_expected_dashes2 = + {{ 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; + +template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code2_cmp = +{{ + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u) +}}; + +template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code1_cmp = +{{ + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u) +}}; + +template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code2_sub = +{{ + char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, + char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub +}}; + +template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code1_sub = +{{ + char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, + char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub +}}; + +template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code0_sub = +{{ + char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, + char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub +}}; + +template< bool IsWCharASCIICompatible > +struct from_chars_simd_char_constants< char, false, IsWCharASCIICompatible > +{ + static_assert(static_cast< std::int8_t >('0') > -128 && static_cast< std::int8_t >('A') > -128 && static_cast< std::int8_t >('a') > -128, + "Boost.UUID: Unsupported char encoding, hexadecimal character codes are expected to be greater than -128"); + + static const simd_vector128< std::uint8_t > mm_expected_dashes1; + static const simd_vector128< std::uint8_t > mm_expected_dashes2; + + static constexpr std::uint8_t char_code2 = static_cast< std::uint8_t > + ( + static_cast< std::int8_t >('a') > static_cast< std::int8_t >('A') ? + ( + static_cast< std::int8_t >('a') > static_cast< std::int8_t >('0') ? 'a' : '0' + ) : + ( + static_cast< std::int8_t >('A') > static_cast< std::int8_t >('0') ? 'A' : '0' + ) + ); + static constexpr std::uint8_t char_code2_sub = char_code2 == static_cast< std::uint8_t >('0') ? + static_cast< std::uint8_t >('0') : static_cast< std::uint8_t >(char_code2 - 10u); + + static constexpr std::uint8_t char_code1 = static_cast< std::uint8_t > + ( + static_cast< std::int8_t >('a') > static_cast< std::int8_t >('A') ? + ( + static_cast< std::int8_t >('a') < static_cast< std::int8_t >('0') ? 'a' : '0' + ) : + ( + static_cast< std::int8_t >('A') < static_cast< std::int8_t >('0') ? 'A' : '0' + ) + ); + static constexpr std::uint8_t char_code1_sub = char_code1 == static_cast< std::uint8_t >('0') ? + static_cast< std::uint8_t >('0') : static_cast< std::uint8_t >(char_code1 - 10u); + + static constexpr std::uint8_t char_code0 = static_cast< std::uint8_t > + ( + static_cast< std::int8_t >('a') < static_cast< std::int8_t >('A') ? + ( + static_cast< std::int8_t >('a') < static_cast< std::int8_t >('0') ? 'a' : '0' + ) : + ( + static_cast< std::int8_t >('A') < static_cast< std::int8_t >('0') ? 'A' : '0' + ) + ); + static constexpr std::uint8_t char_code0_sub = char_code0 == static_cast< std::uint8_t >('0') ? + static_cast< std::uint8_t >('0') : static_cast< std::uint8_t >(char_code0 - 10u); + + static constexpr std::uint32_t char_code_sub = + (static_cast< std::uint32_t >(char_code0_sub) << 16u) | (static_cast< std::uint32_t >(char_code1_sub) << 8u) | char_code2_sub; + + static const simd_vector128< std::uint8_t > mm_char_code2_cmp; + static const simd_vector128< std::uint8_t > mm_char_code1_cmp; + + static const simd_vector128< std::uint8_t > mm_char_code2_sub; + static const simd_vector128< std::uint8_t > mm_char_code1_sub; + static const simd_vector128< std::uint8_t > mm_char_code0_sub; +}; + +template< bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_expected_dashes1 = +{{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + static_cast< std::uint8_t >('-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >('-'), 0x00, 0x00 +}}; + +template< bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_expected_dashes2 = +{{ + 0x00, 0x00, static_cast< std::uint8_t >('-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >('-'), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}}; + +template< bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code2_cmp = +{{ + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u) +}}; + +template< bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code1_cmp = +{{ + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u) +}}; + +template< bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code2_sub = +{{ + char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, + char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub +}}; + +template< bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code1_sub = +{{ + char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, + char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub +}}; + +template< bool IsWCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code0_sub = +{{ + char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, + char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub +}}; + +template< bool IsCharASCIICompatible > +struct from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false > +{ + static_assert(static_cast< wchar_t >(static_cast< std::uint8_t >(L'0')) == L'0' && static_cast< wchar_t >(static_cast< std::uint8_t >(L'9')) == L'9' && + static_cast< wchar_t >(static_cast< std::uint8_t >(L'a')) == L'a' && static_cast< wchar_t >(static_cast< std::uint8_t >(L'f')) == L'f' && + static_cast< wchar_t >(static_cast< std::uint8_t >(L'-')) == L'-', + "Boost.UUID: Unsupported wchar_t encoding, hexadecimal and dash character codes are expected to be representable by a single byte"); + + static_assert(static_cast< std::int8_t >(L'0') > -128 && static_cast< std::int8_t >(L'A') > -128 && static_cast< std::int8_t >(L'a') > -128, + "Boost.UUID: Unsupported wchar_t encoding, hexadecimal character codes are expected to be greater than -128"); + + static const simd_vector128< std::uint8_t > mm_expected_dashes1; + static const simd_vector128< std::uint8_t > mm_expected_dashes2; + + static constexpr std::uint8_t char_code2 = static_cast< std::uint8_t > + ( + static_cast< std::int8_t >(L'a') > static_cast< std::int8_t >(L'A') ? + ( + static_cast< std::int8_t >(L'a') > static_cast< std::int8_t >(L'0') ? L'a' : L'0' + ) : + ( + static_cast< std::int8_t >(L'A') > static_cast< std::int8_t >(L'0') ? L'A' : L'0' + ) + ); + static constexpr std::uint8_t char_code2_sub = char_code2 == static_cast< std::uint8_t >(L'0') ? + static_cast< std::uint8_t >(L'0') : static_cast< std::uint8_t >(char_code2 - 10u); + + static constexpr std::uint8_t char_code1 = static_cast< std::uint8_t > + ( + static_cast< std::int8_t >(L'a') > static_cast< std::int8_t >(L'A') ? + ( + static_cast< std::int8_t >(L'a') < static_cast< std::int8_t >(L'0') ? L'a' : L'0' + ) : + ( + static_cast< std::int8_t >(L'A') < static_cast< std::int8_t >(L'0') ? L'A' : L'0' + ) + ); + static constexpr std::uint8_t char_code1_sub = char_code1 == static_cast< std::uint8_t >(L'0') ? + static_cast< std::uint8_t >(L'0') : static_cast< std::uint8_t >(char_code1 - 10u); + + static constexpr std::uint8_t char_code0 = static_cast< std::uint8_t > + ( + static_cast< std::int8_t >(L'a') < static_cast< std::int8_t >(L'A') ? + ( + static_cast< std::int8_t >(L'a') < static_cast< std::int8_t >(L'0') ? L'a' : L'0' + ) : + ( + static_cast< std::int8_t >(L'A') < static_cast< std::int8_t >(L'0') ? L'A' : L'0' + ) + ); + static constexpr std::uint8_t char_code0_sub = char_code0 == static_cast< std::uint8_t >(L'0') ? + static_cast< std::uint8_t >(L'0') : static_cast< std::uint8_t >(char_code0 - 10u); + + static constexpr std::uint32_t char_code_sub = + (static_cast< std::uint32_t >(char_code0_sub) << 16u) | (static_cast< std::uint32_t >(char_code1_sub) << 8u) | char_code2_sub; + + static const simd_vector128< std::uint8_t > mm_char_code2_cmp; + static const simd_vector128< std::uint8_t > mm_char_code1_cmp; + + static const simd_vector128< std::uint8_t > mm_char_code2_sub; + static const simd_vector128< std::uint8_t > mm_char_code1_sub; + static const simd_vector128< std::uint8_t > mm_char_code0_sub; +}; + +template< bool IsCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_expected_dashes1 = +{{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + static_cast< std::uint8_t >(L'-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >(L'-'), 0x00, 0x00 +}}; + +template< bool IsCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_expected_dashes2 = +{{ + 0x00, 0x00, static_cast< std::uint8_t >(L'-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >(L'-'), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}}; + +template< bool IsCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code2_cmp = +{{ + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u), + static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u) +}}; + +template< bool IsCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code1_cmp = +{{ + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u), + static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u) +}}; + +template< bool IsCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code2_sub = +{{ + char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, + char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub +}}; + +template< bool IsCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code1_sub = +{{ + char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, + char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub +}}; + +template< bool IsCharASCIICompatible > +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code0_sub = +{{ + char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, + char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub +}}; + + +template< typename > +struct from_chars_simd_constants +{ + static const simd_vector128< std::uint8_t > mm_F0; + + // Gather patterns for deinterleaving even and odd positioned hex digits from the three input vectors. + // Each index is a position within the source vector (chars1, chars2 or chars3). + static const simd_vector128< std::uint8_t > mm_upper_idx_chars1; + static const simd_vector128< std::uint8_t > mm_upper_idx_chars2; + static const simd_vector128< std::uint8_t > mm_upper_idx_chars3; + + static const simd_vector128< std::uint8_t > mm_lower_idx_chars1; + static const simd_vector128< std::uint8_t > mm_lower_idx_chars2; + static const simd_vector128< std::uint8_t > mm_lower_idx_chars3; +}; + +template< typename T > +const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_F0 = + {{ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0 }}; + +// Even-positioned hex digits in the original 36-character string become the high nibbles of the output bytes. +template< typename T > +const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_upper_idx_chars1 = + {{ 0x00, 0x02, 0x04, 0x06, 0x09, 0x0B, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; + +template< typename T > +const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_upper_idx_chars2 = + {{ 0x00, 0x03, 0x05, 0x08, 0x0A, 0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; + +template< typename T > +const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_upper_idx_chars3 = + {{ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; + +// Odd-positioned hex digits in the original 36-character string become the low nibbles of the output bytes. +template< typename T > +const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_lower_idx_chars1 = + {{ 0x01, 0x03, 0x05, 0x07, 0x0A, 0x0C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; + +template< typename T > +const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_lower_idx_chars2 = + {{ 0x01, 0x04, 0x06, 0x09, 0x0B, 0x0D, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; + +template< typename T > +const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_lower_idx_chars3 = + {{ 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; + + +BOOST_FORCEINLINE vuint8m1_t load_vector128(const simd_vector128< std::uint8_t >& v, size_t vl) noexcept +{ + return __riscv_vle8_v_u8m1(v.bytes, vl); +} + +template< typename Char, std::size_t Size = sizeof(Char) > +struct from_chars_simd_load_traits; + +template< typename Char > +struct from_chars_simd_load_traits< Char, 1u > +{ + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, size_t vl) noexcept + { + return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), vl); + } + + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, size_t vl) noexcept + { + (void)vl; + return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), 4); + } + + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, size_t vl) noexcept + { + alignas(16) std::uint8_t buf[16] = {}; + detail::memcpy(buf, p, n); + return __riscv_vle8_v_u8m1(buf, vl); + } +}; + +template< typename Char > +struct from_chars_simd_load_traits< Char, 2u > +{ + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, size_t vl) noexcept + { + (void)vl; + size_t vl16 = __riscv_vsetvl_e16m2(16); + vuint16m2_t v16 = __riscv_vle16_v_u16m2(reinterpret_cast< const std::uint16_t* >(p), vl16); + return __riscv_vnsrl_wx_u8m1(v16, 0, 16); + } + + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, size_t vl) noexcept + { + (void)vl; + vuint16m1_t v16 = __riscv_vle16_v_u16m1(reinterpret_cast< const std::uint16_t* >(p), 4); + vuint16m2_t v16_w = __riscv_vlmul_ext_v_u16m1_u16m2(v16); + return __riscv_vnsrl_wx_u8m1(v16_w, 0, 4); + } + + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, size_t vl) noexcept + { + alignas(16) std::uint8_t buf[16] = {}; + for (unsigned int i = 0u; i < n; ++i) + { + buf[i] = static_cast< std::uint8_t >(p[i]); + } + return __riscv_vle8_v_u8m1(buf, vl); + } +}; + +template< typename Char > +struct from_chars_simd_load_traits< Char, 4u > +{ + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, size_t vl) noexcept + { + (void)vl; + size_t vl32 = __riscv_vsetvl_e32m4(16); + vuint32m4_t v32 = __riscv_vle32_v_u32m4(reinterpret_cast< const std::uint32_t* >(p), vl32); + vuint16m2_t v16 = __riscv_vnsrl_wx_u16m2(v32, 0, 16); + return __riscv_vnsrl_wx_u8m1(v16, 0, 16); + } + + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, size_t vl) noexcept + { + (void)vl; + vuint32m1_t v32 = __riscv_vle32_v_u32m1(reinterpret_cast< const std::uint32_t* >(p), 4); + vuint32m4_t v32_w = __riscv_vlmul_ext_v_u32m1_u32m4(v32); + vuint16m2_t v16 = __riscv_vnsrl_wx_u16m2(v32_w, 0, 4); + return __riscv_vnsrl_wx_u8m1(v16, 0, 4); + } + + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, size_t vl) noexcept + { + alignas(16) std::uint8_t buf[16] = {}; + for (unsigned int i = 0u; i < n; ++i) + { + buf[i] = static_cast< std::uint8_t >(p[i]); + } + return __riscv_vle8_v_u8m1(buf, vl); + } +}; + + +/*! + * Converts a string of 36 hexadecimal UUID characters in `chars1`/`chars2`/`chars3` to a 16-byte binary value and, + * if successful, stores it into `data`. If not successful, stores the failure character position to `end_pos` + * and error code to `ec`. + */ +BOOST_FORCEINLINE void from_chars_simd_core +( + vuint8m1_t chars1, vuint8m1_t chars2, vuint8m1_t chars3, + vuint8m1_t const& expected_dashes1, + vuint8m1_t const& expected_dashes2, + vuint8m1_t const& char_code1_cmp, + vuint8m1_t const& char_code2_cmp, + vuint8m1_t const& char_code0_sub, + vuint8m1_t const& char_code1_sub, + vuint8m1_t const& char_code2_sub, + std::uint8_t* data, unsigned int& end_pos, from_chars_error& ec, size_t vl +) +{ + using constants = uuids::detail::from_chars_simd_constants< void >; + + // Check if dashes are in the expected positions + { + const vuint8m1_t dash_char = __riscv_vmv_v_x_u8m1(static_cast< std::uint8_t >('-'), vl); + + const vbool8_t expected1 = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes1, 0, vl); + const vbool8_t expected2 = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes2, 0, vl); + + const vbool8_t is_dash1 = __riscv_vmseq_vv_u8m1_b8(chars1, dash_char, vl); + const vbool8_t is_dash2 = __riscv_vmseq_vv_u8m1_b8(chars2, dash_char, vl); + + const vbool8_t missing1 = __riscv_vmandn_mm_b8(expected1, is_dash1, vl); + const vbool8_t missing2 = __riscv_vmandn_mm_b8(expected2, is_dash2, vl); + + const long first_missing1 = __riscv_vfirst_m_b8(missing1, vl); + const long first_missing2 = __riscv_vfirst_m_b8(missing2, vl); + + unsigned int dash_pos = 0xFFFFFFFFu; + if (first_missing1 >= 0) + { + dash_pos = static_cast< unsigned int >(first_missing1); + } + if (first_missing2 >= 0) + { + const unsigned int pos2 = static_cast< unsigned int >(first_missing2) + 16u; + if (pos2 < dash_pos) + dash_pos = pos2; + } + + if (BOOST_UNLIKELY(dash_pos < end_pos)) + { + end_pos = dash_pos; + ec = from_chars_error::dash_expected; + } + } + + // Deinterleave even and odd positioned hex digits into upper and lower nibbles + vuint8m1_t upper = __riscv_vmv_v_x_u8m1(0, vl); + vuint8m1_t lower = __riscv_vmv_v_x_u8m1(0, vl); + + { + const vuint8m1_t upper_idx1 = load_vector128(constants::mm_upper_idx_chars1, vl); + const vuint8m1_t upper_idx2 = load_vector128(constants::mm_upper_idx_chars2, vl); + const vuint8m1_t upper_idx3 = load_vector128(constants::mm_upper_idx_chars3, vl); + + const vuint8m1_t upper1 = __riscv_vrgather_vv_u8m1(chars1, upper_idx1, vl); + const vuint8m1_t upper2 = __riscv_vrgather_vv_u8m1(chars2, upper_idx2, vl); + const vuint8m1_t upper3 = __riscv_vrgather_vv_u8m1(chars3, upper_idx3, vl); + + upper = __riscv_vslideup_vx_u8m1(upper, upper1, 0, vl); + upper = __riscv_vslideup_vx_u8m1(upper, upper2, 7, vl); + upper = __riscv_vslideup_vx_u8m1(upper, upper3, 14, vl); + } + + { + const vuint8m1_t lower_idx1 = load_vector128(constants::mm_lower_idx_chars1, vl); + const vuint8m1_t lower_idx2 = load_vector128(constants::mm_lower_idx_chars2, vl); + const vuint8m1_t lower_idx3 = load_vector128(constants::mm_lower_idx_chars3, vl); + + const vuint8m1_t lower1 = __riscv_vrgather_vv_u8m1(chars1, lower_idx1, vl); + const vuint8m1_t lower2 = __riscv_vrgather_vv_u8m1(chars2, lower_idx2, vl); + const vuint8m1_t lower3 = __riscv_vrgather_vv_u8m1(chars3, lower_idx3, vl); + + lower = __riscv_vslideup_vx_u8m1(lower, lower1, 0, vl); + lower = __riscv_vslideup_vx_u8m1(lower, lower2, 7, vl); + lower = __riscv_vslideup_vx_u8m1(lower, lower3, 14, vl); + } + + // Convert characters to 8-bit integers. See the comment in from_chars_x86.hpp for the algorithm description. + const vint8m1_t upper_i8 = __riscv_vreinterpret_v_u8m1_i8m1(upper); + const vint8m1_t lower_i8 = __riscv_vreinterpret_v_u8m1_i8m1(lower); + const vint8m1_t char_code1_cmp_i8 = __riscv_vreinterpret_v_u8m1_i8m1(char_code1_cmp); + const vint8m1_t char_code2_cmp_i8 = __riscv_vreinterpret_v_u8m1_i8m1(char_code2_cmp); + + const vbool8_t upper_code2_mask = __riscv_vmsgt_vv_i8m1_b8(upper_i8, char_code2_cmp_i8, vl); + const vbool8_t upper_code1_mask = __riscv_vmsgt_vv_i8m1_b8(upper_i8, char_code1_cmp_i8, vl); + const vbool8_t lower_code2_mask = __riscv_vmsgt_vv_i8m1_b8(lower_i8, char_code2_cmp_i8, vl); + const vbool8_t lower_code1_mask = __riscv_vmsgt_vv_i8m1_b8(lower_i8, char_code1_cmp_i8, vl); + + vuint8m1_t upper_sub = __riscv_vmerge_vvm_u8m1(char_code1_sub, char_code2_sub, upper_code2_mask, vl); + upper_sub = __riscv_vmerge_vvm_u8m1(char_code0_sub, upper_sub, upper_code1_mask, vl); + + vuint8m1_t lower_sub = __riscv_vmerge_vvm_u8m1(char_code1_sub, char_code2_sub, lower_code2_mask, vl); + lower_sub = __riscv_vmerge_vvm_u8m1(char_code0_sub, lower_sub, lower_code1_mask, vl); + + upper = __riscv_vsub_vv_u8m1(upper, upper_sub, vl); + lower = __riscv_vsub_vv_u8m1(lower, lower_sub, vl); + + // Check hexadecimal character validity. Values outside 0-15 will have non-zero upper 4 bits. + const vuint8m1_t mm_F0 = load_vector128(constants::mm_F0, vl); + const vuint8m1_t upper_hi_bits = __riscv_vand_vv_u8m1(upper, mm_F0, vl); + const vuint8m1_t lower_hi_bits = __riscv_vand_vv_u8m1(lower, mm_F0, vl); + + const vbool8_t upper_valid = __riscv_vmseq_vx_u8m1_b8(upper_hi_bits, 0, vl); + const vbool8_t lower_valid = __riscv_vmseq_vx_u8m1_b8(lower_hi_bits, 0, vl); + + const vbool8_t upper_invalid = __riscv_vmnand_mm_b8(upper_valid, upper_valid, vl); + const vbool8_t lower_invalid = __riscv_vmnand_mm_b8(lower_valid, lower_valid, vl); + + const long first_invalid_upper = __riscv_vfirst_m_b8(upper_invalid, vl); + const long first_invalid_lower = __riscv_vfirst_m_b8(lower_invalid, vl); + + if (BOOST_UNLIKELY(first_invalid_upper >= 0 || first_invalid_lower >= 0)) + { + unsigned int pos_upper = 0xFFFFFFFFu; + unsigned int pos_lower = 0xFFFFFFFFu; + if (first_invalid_upper >= 0) + { + pos_upper = static_cast< unsigned int >(first_invalid_upper) * 2u; + } + if (first_invalid_lower >= 0) + { + pos_lower = static_cast< unsigned int >(first_invalid_lower) * 2u + 1u; + } + unsigned int pos = pos_upper < pos_lower ? pos_upper : pos_lower; + if (pos >= 8u) + { + unsigned int dash_count = (pos - 4u) / 4u; + if (dash_count > 4u) + dash_count = 4u; + pos += dash_count; + } + + if (pos < end_pos) + { + end_pos = pos; + ec = from_chars_error::hex_digit_expected; + } + } + else if (BOOST_LIKELY(ec == from_chars_error::none)) + { + const vuint8m1_t result = __riscv_vor_vv_u8m1( + __riscv_vsll_vx_u8m1(upper, 4, vl), + lower, + vl); + __riscv_vse8_v_u8m1(data, result, vl); + } +} + +template< typename Char > +BOOST_FORCEINLINE from_chars_result< Char > from_chars_simd(const Char* begin, const Char* end, uuid& u) noexcept +{ + static_assert(sizeof(Char) == 1u || sizeof(Char) == 2u || sizeof(Char) == 4u, "Boost.UUID: Unsupported input character type for from_chars"); + + using char_constants = uuids::detail::from_chars_simd_char_constants< Char >; + + const size_t vl = __riscv_vsetvl_e8m1(16); + + unsigned int end_pos = 36u; + from_chars_error ec = from_chars_error::none; + vuint8m1_t chars1, chars2, chars3; + + if (BOOST_LIKELY((end - begin) >= 36)) + { + chars1 = from_chars_simd_load_traits< Char >::load_packed_16(begin, vl); + chars2 = from_chars_simd_load_traits< Char >::load_packed_16(begin + 16, vl); + chars3 = from_chars_simd_load_traits< Char >::load_packed_4(begin + 32, vl); + } + else + { + end_pos = static_cast< unsigned int >(end - begin); + ec = from_chars_error::unexpected_end_of_input; + + const Char* p = begin; + unsigned int n = static_cast< unsigned int >(end - begin); + if (n >= 16u) + { + chars1 = from_chars_simd_load_traits< Char >::load_packed_16(p, vl); + p += 16; + n -= 16u; + } + else + { + chars1 = from_chars_simd_load_traits< Char >::load_packed_n(p, n, vl); + p += n; + n = 0u; + } + + if (n >= 16u) + { + chars2 = from_chars_simd_load_traits< Char >::load_packed_16(p, vl); + p += 16; + n -= 16u; + } + else + { + chars2 = from_chars_simd_load_traits< Char >::load_packed_n(p, n, vl); + p += n; + n = 0u; + } + + chars3 = from_chars_simd_load_traits< Char >::load_packed_n(p, n, vl); + } + + from_chars_simd_core + ( + chars1, chars2, chars3, + load_vector128(char_constants::mm_expected_dashes1, vl), + load_vector128(char_constants::mm_expected_dashes2, vl), + load_vector128(char_constants::mm_char_code1_cmp, vl), + load_vector128(char_constants::mm_char_code2_cmp, vl), + load_vector128(char_constants::mm_char_code0_sub, vl), + load_vector128(char_constants::mm_char_code1_sub, vl), + load_vector128(char_constants::mm_char_code2_sub, vl), + u.data(), end_pos, ec, vl + ); + + return { begin + end_pos, ec }; +} + +} // namespace detail +} // namespace uuids +} // namespace boost + +#endif // defined(BOOST_UUID_USE_RISCV_V) + +#endif // BOOST_UUID_DETAIL_FROM_CHARS_RISCV_HPP_INCLUDED + From 19f3e60510e5ef74a59a62d4361af81a2e7111f1 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Fri, 11 Sep 2026 22:25:43 +0300 Subject: [PATCH 03/10] Qualify size_t as std::size_t in from_chars_riscv.hpp --- .../boost/uuid/detail/from_chars_riscv.hpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp index 39353058..b6fc3465 100644 --- a/include/boost/uuid/detail/from_chars_riscv.hpp +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -403,7 +403,7 @@ const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_lower_id {{ 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; -BOOST_FORCEINLINE vuint8m1_t load_vector128(const simd_vector128< std::uint8_t >& v, size_t vl) noexcept +BOOST_FORCEINLINE vuint8m1_t load_vector128(const simd_vector128< std::uint8_t >& v, std::size_t vl) noexcept { return __riscv_vle8_v_u8m1(v.bytes, vl); } @@ -414,18 +414,18 @@ struct from_chars_simd_load_traits; template< typename Char > struct from_chars_simd_load_traits< Char, 1u > { - static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, std::size_t vl) noexcept { return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), vl); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, std::size_t vl) noexcept { (void)vl; return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), 4); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept { alignas(16) std::uint8_t buf[16] = {}; detail::memcpy(buf, p, n); @@ -436,15 +436,15 @@ struct from_chars_simd_load_traits< Char, 1u > template< typename Char > struct from_chars_simd_load_traits< Char, 2u > { - static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, std::size_t vl) noexcept { (void)vl; - size_t vl16 = __riscv_vsetvl_e16m2(16); + std::size_t vl16 = __riscv_vsetvl_e16m2(16); vuint16m2_t v16 = __riscv_vle16_v_u16m2(reinterpret_cast< const std::uint16_t* >(p), vl16); return __riscv_vnsrl_wx_u8m1(v16, 0, 16); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, std::size_t vl) noexcept { (void)vl; vuint16m1_t v16 = __riscv_vle16_v_u16m1(reinterpret_cast< const std::uint16_t* >(p), 4); @@ -452,7 +452,7 @@ struct from_chars_simd_load_traits< Char, 2u > return __riscv_vnsrl_wx_u8m1(v16_w, 0, 4); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept { alignas(16) std::uint8_t buf[16] = {}; for (unsigned int i = 0u; i < n; ++i) @@ -466,16 +466,16 @@ struct from_chars_simd_load_traits< Char, 2u > template< typename Char > struct from_chars_simd_load_traits< Char, 4u > { - static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, std::size_t vl) noexcept { (void)vl; - size_t vl32 = __riscv_vsetvl_e32m4(16); + std::size_t vl32 = __riscv_vsetvl_e32m4(16); vuint32m4_t v32 = __riscv_vle32_v_u32m4(reinterpret_cast< const std::uint32_t* >(p), vl32); vuint16m2_t v16 = __riscv_vnsrl_wx_u16m2(v32, 0, 16); return __riscv_vnsrl_wx_u8m1(v16, 0, 16); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, std::size_t vl) noexcept { (void)vl; vuint32m1_t v32 = __riscv_vle32_v_u32m1(reinterpret_cast< const std::uint32_t* >(p), 4); @@ -484,7 +484,7 @@ struct from_chars_simd_load_traits< Char, 4u > return __riscv_vnsrl_wx_u8m1(v16, 0, 4); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept { alignas(16) std::uint8_t buf[16] = {}; for (unsigned int i = 0u; i < n; ++i) @@ -511,7 +511,7 @@ BOOST_FORCEINLINE void from_chars_simd_core vuint8m1_t const& char_code0_sub, vuint8m1_t const& char_code1_sub, vuint8m1_t const& char_code2_sub, - std::uint8_t* data, unsigned int& end_pos, from_chars_error& ec, size_t vl + std::uint8_t* data, unsigned int& end_pos, from_chars_error& ec, std::size_t vl ) { using constants = uuids::detail::from_chars_simd_constants< void >; @@ -661,7 +661,7 @@ BOOST_FORCEINLINE from_chars_result< Char > from_chars_simd(const Char* begin, c using char_constants = uuids::detail::from_chars_simd_char_constants< Char >; - const size_t vl = __riscv_vsetvl_e8m1(16); + const std::size_t vl = __riscv_vsetvl_e8m1(16); unsigned int end_pos = 36u; from_chars_error ec = from_chars_error::none; From 60a78345763eecc0e655645828469cdb32125e67 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Fri, 11 Sep 2026 22:28:52 +0300 Subject: [PATCH 04/10] Correct the copyright in from_chars_riscv.hpp --- include/boost/uuid/detail/from_chars_riscv.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp index b6fc3465..5d30d85d 100644 --- a/include/boost/uuid/detail/from_chars_riscv.hpp +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -1,7 +1,7 @@ #ifndef BOOST_UUID_DETAIL_FROM_CHARS_RISCV_HPP_INCLUDED #define BOOST_UUID_DETAIL_FROM_CHARS_RISCV_HPP_INCLUDED -// Copyright 2025 Andrey Semashev +// Copyright 2026 Dan Kahyan // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt From 5aeeae1d1150bca271571d5eba16672bed6b8675 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Sat, 12 Sep 2026 18:35:42 +0300 Subject: [PATCH 05/10] Load partial character sequences directly in from_chars_riscv.hpp Use the number of available characters as the vector length instead of copying them into a zero-initialized temporary buffer. The lanes above n are tail-agnostic, but they are never observed, since the parse has already failed and the result is not stored. With the temporary buffers gone, the memcpy helper is no longer used and its include is dropped. --- .../boost/uuid/detail/from_chars_riscv.hpp | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp index 5d30d85d..2f87e08f 100644 --- a/include/boost/uuid/detail/from_chars_riscv.hpp +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -427,9 +426,8 @@ struct from_chars_simd_load_traits< Char, 1u > static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept { - alignas(16) std::uint8_t buf[16] = {}; - detail::memcpy(buf, p, n); - return __riscv_vle8_v_u8m1(buf, vl); + (void)vl; + return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), n); } }; @@ -454,12 +452,9 @@ struct from_chars_simd_load_traits< Char, 2u > static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept { - alignas(16) std::uint8_t buf[16] = {}; - for (unsigned int i = 0u; i < n; ++i) - { - buf[i] = static_cast< std::uint8_t >(p[i]); - } - return __riscv_vle8_v_u8m1(buf, vl); + (void)vl; + vuint16m2_t v16 = __riscv_vle16_v_u16m2(reinterpret_cast< const std::uint16_t* >(p), n); + return __riscv_vnsrl_wx_u8m1(v16, 0, 16); } }; @@ -486,12 +481,10 @@ struct from_chars_simd_load_traits< Char, 4u > static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept { - alignas(16) std::uint8_t buf[16] = {}; - for (unsigned int i = 0u; i < n; ++i) - { - buf[i] = static_cast< std::uint8_t >(p[i]); - } - return __riscv_vle8_v_u8m1(buf, vl); + (void)vl; + vuint32m4_t v32 = __riscv_vle32_v_u32m4(reinterpret_cast< const std::uint32_t* >(p), n); + vuint16m2_t v16 = __riscv_vnsrl_wx_u16m2(v32, 0, 16); + return __riscv_vnsrl_wx_u8m1(v16, 0, 16); } }; From fd9eaf36e79f1d975977402046f14c61db620b0f Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Sat, 12 Sep 2026 20:15:40 +0300 Subject: [PATCH 06/10] Load character constants in from_chars_simd_core Template the core on the character type and load each constant where it is used instead of passing seven preloaded vectors, shortening the signature. No change in behavior. --- .../boost/uuid/detail/from_chars_riscv.hpp | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp index 2f87e08f..bc0cce94 100644 --- a/include/boost/uuid/detail/from_chars_riscv.hpp +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -494,25 +494,23 @@ struct from_chars_simd_load_traits< Char, 4u > * if successful, stores it into `data`. If not successful, stores the failure character position to `end_pos` * and error code to `ec`. */ +template< typename Char > BOOST_FORCEINLINE void from_chars_simd_core ( vuint8m1_t chars1, vuint8m1_t chars2, vuint8m1_t chars3, - vuint8m1_t const& expected_dashes1, - vuint8m1_t const& expected_dashes2, - vuint8m1_t const& char_code1_cmp, - vuint8m1_t const& char_code2_cmp, - vuint8m1_t const& char_code0_sub, - vuint8m1_t const& char_code1_sub, - vuint8m1_t const& char_code2_sub, std::uint8_t* data, unsigned int& end_pos, from_chars_error& ec, std::size_t vl ) { using constants = uuids::detail::from_chars_simd_constants< void >; + using char_constants = uuids::detail::from_chars_simd_char_constants< Char >; // Check if dashes are in the expected positions { const vuint8m1_t dash_char = __riscv_vmv_v_x_u8m1(static_cast< std::uint8_t >('-'), vl); + const vuint8m1_t expected_dashes1 = load_vector128(char_constants::mm_expected_dashes1, vl); + const vuint8m1_t expected_dashes2 = load_vector128(char_constants::mm_expected_dashes2, vl); + const vbool8_t expected1 = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes1, 0, vl); const vbool8_t expected2 = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes2, 0, vl); @@ -579,6 +577,9 @@ BOOST_FORCEINLINE void from_chars_simd_core // Convert characters to 8-bit integers. See the comment in from_chars_x86.hpp for the algorithm description. const vint8m1_t upper_i8 = __riscv_vreinterpret_v_u8m1_i8m1(upper); const vint8m1_t lower_i8 = __riscv_vreinterpret_v_u8m1_i8m1(lower); + const vuint8m1_t char_code1_cmp = load_vector128(char_constants::mm_char_code1_cmp, vl); + const vuint8m1_t char_code2_cmp = load_vector128(char_constants::mm_char_code2_cmp, vl); + const vint8m1_t char_code1_cmp_i8 = __riscv_vreinterpret_v_u8m1_i8m1(char_code1_cmp); const vint8m1_t char_code2_cmp_i8 = __riscv_vreinterpret_v_u8m1_i8m1(char_code2_cmp); @@ -587,6 +588,10 @@ BOOST_FORCEINLINE void from_chars_simd_core const vbool8_t lower_code2_mask = __riscv_vmsgt_vv_i8m1_b8(lower_i8, char_code2_cmp_i8, vl); const vbool8_t lower_code1_mask = __riscv_vmsgt_vv_i8m1_b8(lower_i8, char_code1_cmp_i8, vl); + const vuint8m1_t char_code0_sub = load_vector128(char_constants::mm_char_code0_sub, vl); + const vuint8m1_t char_code1_sub = load_vector128(char_constants::mm_char_code1_sub, vl); + const vuint8m1_t char_code2_sub = load_vector128(char_constants::mm_char_code2_sub, vl); + vuint8m1_t upper_sub = __riscv_vmerge_vvm_u8m1(char_code1_sub, char_code2_sub, upper_code2_mask, vl); upper_sub = __riscv_vmerge_vvm_u8m1(char_code0_sub, upper_sub, upper_code1_mask, vl); @@ -652,8 +657,6 @@ BOOST_FORCEINLINE from_chars_result< Char > from_chars_simd(const Char* begin, c { static_assert(sizeof(Char) == 1u || sizeof(Char) == 2u || sizeof(Char) == 4u, "Boost.UUID: Unsupported input character type for from_chars"); - using char_constants = uuids::detail::from_chars_simd_char_constants< Char >; - const std::size_t vl = __riscv_vsetvl_e8m1(16); unsigned int end_pos = 36u; @@ -702,16 +705,9 @@ BOOST_FORCEINLINE from_chars_result< Char > from_chars_simd(const Char* begin, c chars3 = from_chars_simd_load_traits< Char >::load_packed_n(p, n, vl); } - from_chars_simd_core + from_chars_simd_core< Char > ( chars1, chars2, chars3, - load_vector128(char_constants::mm_expected_dashes1, vl), - load_vector128(char_constants::mm_expected_dashes2, vl), - load_vector128(char_constants::mm_char_code1_cmp, vl), - load_vector128(char_constants::mm_char_code2_cmp, vl), - load_vector128(char_constants::mm_char_code0_sub, vl), - load_vector128(char_constants::mm_char_code1_sub, vl), - load_vector128(char_constants::mm_char_code2_sub, vl), u.data(), end_pos, ec, vl ); From 5bb96cdd358c98db2622deeeeb67a8e01caaded7 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Sat, 12 Sep 2026 21:39:43 +0300 Subject: [PATCH 07/10] Explicitly require 128-bit vectors for from_chars_riscv.hpp Check __riscv_vector and __riscv_v_min_vlen instead of __riscv_v, so that targets with shorter vectors (Zve32*, Zve64*) use the generic implementation rather than producing incorrect results. The vector length the algorithm requires is now specified where it is used instead of being passed around as a vl parameter. --- include/boost/uuid/detail/config.hpp | 6 +- .../boost/uuid/detail/from_chars_riscv.hpp | 92 +++++++++---------- 2 files changed, 47 insertions(+), 51 deletions(-) diff --git a/include/boost/uuid/detail/config.hpp b/include/boost/uuid/detail/config.hpp index 29752e10..5355466d 100644 --- a/include/boost/uuid/detail/config.hpp +++ b/include/boost/uuid/detail/config.hpp @@ -92,9 +92,13 @@ #endif -#if defined(__riscv_v) +#if defined(__riscv_vector) && defined(__riscv_v_min_vlen) && (__riscv_v_min_vlen >= 128) // RISC-V Vector Extension (V 1.0+), GCC 12+ / Clang 15+ +// The implementation processes 16 characters at a time, so it requires at least 16 8-bit +// vector lanes, i.e. vectors of at least 128 bits. __riscv_v_min_vlen is 128 for the V +// extension and for targets with Zvl128b and above, and lower for the Zve32*/Zve64* +// subsets, on which the implementation would produce incorrect results. #ifndef BOOST_UUID_USE_RISCV_V #define BOOST_UUID_USE_RISCV_V #endif diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp index bc0cce94..452d2898 100644 --- a/include/boost/uuid/detail/from_chars_riscv.hpp +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -402,9 +402,9 @@ const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_lower_id {{ 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; -BOOST_FORCEINLINE vuint8m1_t load_vector128(const simd_vector128< std::uint8_t >& v, std::size_t vl) noexcept +BOOST_FORCEINLINE vuint8m1_t load_vector128(const simd_vector128< std::uint8_t >& v) noexcept { - return __riscv_vle8_v_u8m1(v.bytes, vl); + return __riscv_vle8_v_u8m1(v.bytes, 16); } template< typename Char, std::size_t Size = sizeof(Char) > @@ -413,20 +413,18 @@ struct from_chars_simd_load_traits; template< typename Char > struct from_chars_simd_load_traits< Char, 1u > { - static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p) noexcept { - return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), vl); + return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), 16); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p) noexcept { - (void)vl; return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), 4); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n) noexcept { - (void)vl; return __riscv_vle8_v_u8m1(reinterpret_cast< const std::uint8_t* >(p), n); } }; @@ -434,25 +432,21 @@ struct from_chars_simd_load_traits< Char, 1u > template< typename Char > struct from_chars_simd_load_traits< Char, 2u > { - static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p) noexcept { - (void)vl; - std::size_t vl16 = __riscv_vsetvl_e16m2(16); - vuint16m2_t v16 = __riscv_vle16_v_u16m2(reinterpret_cast< const std::uint16_t* >(p), vl16); + vuint16m2_t v16 = __riscv_vle16_v_u16m2(reinterpret_cast< const std::uint16_t* >(p), 16); return __riscv_vnsrl_wx_u8m1(v16, 0, 16); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p) noexcept { - (void)vl; vuint16m1_t v16 = __riscv_vle16_v_u16m1(reinterpret_cast< const std::uint16_t* >(p), 4); vuint16m2_t v16_w = __riscv_vlmul_ext_v_u16m1_u16m2(v16); return __riscv_vnsrl_wx_u8m1(v16_w, 0, 4); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n) noexcept { - (void)vl; vuint16m2_t v16 = __riscv_vle16_v_u16m2(reinterpret_cast< const std::uint16_t* >(p), n); return __riscv_vnsrl_wx_u8m1(v16, 0, 16); } @@ -461,27 +455,23 @@ struct from_chars_simd_load_traits< Char, 2u > template< typename Char > struct from_chars_simd_load_traits< Char, 4u > { - static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_16(const Char* p) noexcept { - (void)vl; - std::size_t vl32 = __riscv_vsetvl_e32m4(16); - vuint32m4_t v32 = __riscv_vle32_v_u32m4(reinterpret_cast< const std::uint32_t* >(p), vl32); + vuint32m4_t v32 = __riscv_vle32_v_u32m4(reinterpret_cast< const std::uint32_t* >(p), 16); vuint16m2_t v16 = __riscv_vnsrl_wx_u16m2(v32, 0, 16); return __riscv_vnsrl_wx_u8m1(v16, 0, 16); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_4(const Char* p) noexcept { - (void)vl; vuint32m1_t v32 = __riscv_vle32_v_u32m1(reinterpret_cast< const std::uint32_t* >(p), 4); vuint32m4_t v32_w = __riscv_vlmul_ext_v_u32m1_u32m4(v32); vuint16m2_t v16 = __riscv_vnsrl_wx_u16m2(v32_w, 0, 4); return __riscv_vnsrl_wx_u8m1(v16, 0, 4); } - static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n, std::size_t vl) noexcept + static BOOST_FORCEINLINE vuint8m1_t load_packed_n(const Char* p, unsigned int n) noexcept { - (void)vl; vuint32m4_t v32 = __riscv_vle32_v_u32m4(reinterpret_cast< const std::uint32_t* >(p), n); vuint16m2_t v16 = __riscv_vnsrl_wx_u16m2(v32, 0, 16); return __riscv_vnsrl_wx_u8m1(v16, 0, 16); @@ -498,18 +488,22 @@ template< typename Char > BOOST_FORCEINLINE void from_chars_simd_core ( vuint8m1_t chars1, vuint8m1_t chars2, vuint8m1_t chars3, - std::uint8_t* data, unsigned int& end_pos, from_chars_error& ec, std::size_t vl + std::uint8_t* data, unsigned int& end_pos, from_chars_error& ec ) { using constants = uuids::detail::from_chars_simd_constants< void >; using char_constants = uuids::detail::from_chars_simd_char_constants< Char >; + // The algorithm processes 16 characters at a time. BOOST_UUID_USE_RISCV_V is only defined for + // targets with vectors of at least 128 bits, so 16 lanes are always available. + constexpr std::size_t vl = 16u; + // Check if dashes are in the expected positions { const vuint8m1_t dash_char = __riscv_vmv_v_x_u8m1(static_cast< std::uint8_t >('-'), vl); - const vuint8m1_t expected_dashes1 = load_vector128(char_constants::mm_expected_dashes1, vl); - const vuint8m1_t expected_dashes2 = load_vector128(char_constants::mm_expected_dashes2, vl); + const vuint8m1_t expected_dashes1 = load_vector128(char_constants::mm_expected_dashes1); + const vuint8m1_t expected_dashes2 = load_vector128(char_constants::mm_expected_dashes2); const vbool8_t expected1 = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes1, 0, vl); const vbool8_t expected2 = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes2, 0, vl); @@ -547,9 +541,9 @@ BOOST_FORCEINLINE void from_chars_simd_core vuint8m1_t lower = __riscv_vmv_v_x_u8m1(0, vl); { - const vuint8m1_t upper_idx1 = load_vector128(constants::mm_upper_idx_chars1, vl); - const vuint8m1_t upper_idx2 = load_vector128(constants::mm_upper_idx_chars2, vl); - const vuint8m1_t upper_idx3 = load_vector128(constants::mm_upper_idx_chars3, vl); + const vuint8m1_t upper_idx1 = load_vector128(constants::mm_upper_idx_chars1); + const vuint8m1_t upper_idx2 = load_vector128(constants::mm_upper_idx_chars2); + const vuint8m1_t upper_idx3 = load_vector128(constants::mm_upper_idx_chars3); const vuint8m1_t upper1 = __riscv_vrgather_vv_u8m1(chars1, upper_idx1, vl); const vuint8m1_t upper2 = __riscv_vrgather_vv_u8m1(chars2, upper_idx2, vl); @@ -561,9 +555,9 @@ BOOST_FORCEINLINE void from_chars_simd_core } { - const vuint8m1_t lower_idx1 = load_vector128(constants::mm_lower_idx_chars1, vl); - const vuint8m1_t lower_idx2 = load_vector128(constants::mm_lower_idx_chars2, vl); - const vuint8m1_t lower_idx3 = load_vector128(constants::mm_lower_idx_chars3, vl); + const vuint8m1_t lower_idx1 = load_vector128(constants::mm_lower_idx_chars1); + const vuint8m1_t lower_idx2 = load_vector128(constants::mm_lower_idx_chars2); + const vuint8m1_t lower_idx3 = load_vector128(constants::mm_lower_idx_chars3); const vuint8m1_t lower1 = __riscv_vrgather_vv_u8m1(chars1, lower_idx1, vl); const vuint8m1_t lower2 = __riscv_vrgather_vv_u8m1(chars2, lower_idx2, vl); @@ -577,8 +571,8 @@ BOOST_FORCEINLINE void from_chars_simd_core // Convert characters to 8-bit integers. See the comment in from_chars_x86.hpp for the algorithm description. const vint8m1_t upper_i8 = __riscv_vreinterpret_v_u8m1_i8m1(upper); const vint8m1_t lower_i8 = __riscv_vreinterpret_v_u8m1_i8m1(lower); - const vuint8m1_t char_code1_cmp = load_vector128(char_constants::mm_char_code1_cmp, vl); - const vuint8m1_t char_code2_cmp = load_vector128(char_constants::mm_char_code2_cmp, vl); + const vuint8m1_t char_code1_cmp = load_vector128(char_constants::mm_char_code1_cmp); + const vuint8m1_t char_code2_cmp = load_vector128(char_constants::mm_char_code2_cmp); const vint8m1_t char_code1_cmp_i8 = __riscv_vreinterpret_v_u8m1_i8m1(char_code1_cmp); const vint8m1_t char_code2_cmp_i8 = __riscv_vreinterpret_v_u8m1_i8m1(char_code2_cmp); @@ -588,9 +582,9 @@ BOOST_FORCEINLINE void from_chars_simd_core const vbool8_t lower_code2_mask = __riscv_vmsgt_vv_i8m1_b8(lower_i8, char_code2_cmp_i8, vl); const vbool8_t lower_code1_mask = __riscv_vmsgt_vv_i8m1_b8(lower_i8, char_code1_cmp_i8, vl); - const vuint8m1_t char_code0_sub = load_vector128(char_constants::mm_char_code0_sub, vl); - const vuint8m1_t char_code1_sub = load_vector128(char_constants::mm_char_code1_sub, vl); - const vuint8m1_t char_code2_sub = load_vector128(char_constants::mm_char_code2_sub, vl); + const vuint8m1_t char_code0_sub = load_vector128(char_constants::mm_char_code0_sub); + const vuint8m1_t char_code1_sub = load_vector128(char_constants::mm_char_code1_sub); + const vuint8m1_t char_code2_sub = load_vector128(char_constants::mm_char_code2_sub); vuint8m1_t upper_sub = __riscv_vmerge_vvm_u8m1(char_code1_sub, char_code2_sub, upper_code2_mask, vl); upper_sub = __riscv_vmerge_vvm_u8m1(char_code0_sub, upper_sub, upper_code1_mask, vl); @@ -602,7 +596,7 @@ BOOST_FORCEINLINE void from_chars_simd_core lower = __riscv_vsub_vv_u8m1(lower, lower_sub, vl); // Check hexadecimal character validity. Values outside 0-15 will have non-zero upper 4 bits. - const vuint8m1_t mm_F0 = load_vector128(constants::mm_F0, vl); + const vuint8m1_t mm_F0 = load_vector128(constants::mm_F0); const vuint8m1_t upper_hi_bits = __riscv_vand_vv_u8m1(upper, mm_F0, vl); const vuint8m1_t lower_hi_bits = __riscv_vand_vv_u8m1(lower, mm_F0, vl); @@ -657,17 +651,15 @@ BOOST_FORCEINLINE from_chars_result< Char > from_chars_simd(const Char* begin, c { static_assert(sizeof(Char) == 1u || sizeof(Char) == 2u || sizeof(Char) == 4u, "Boost.UUID: Unsupported input character type for from_chars"); - const std::size_t vl = __riscv_vsetvl_e8m1(16); - unsigned int end_pos = 36u; from_chars_error ec = from_chars_error::none; vuint8m1_t chars1, chars2, chars3; if (BOOST_LIKELY((end - begin) >= 36)) { - chars1 = from_chars_simd_load_traits< Char >::load_packed_16(begin, vl); - chars2 = from_chars_simd_load_traits< Char >::load_packed_16(begin + 16, vl); - chars3 = from_chars_simd_load_traits< Char >::load_packed_4(begin + 32, vl); + chars1 = from_chars_simd_load_traits< Char >::load_packed_16(begin); + chars2 = from_chars_simd_load_traits< Char >::load_packed_16(begin + 16); + chars3 = from_chars_simd_load_traits< Char >::load_packed_4(begin + 32); } else { @@ -678,37 +670,37 @@ BOOST_FORCEINLINE from_chars_result< Char > from_chars_simd(const Char* begin, c unsigned int n = static_cast< unsigned int >(end - begin); if (n >= 16u) { - chars1 = from_chars_simd_load_traits< Char >::load_packed_16(p, vl); + chars1 = from_chars_simd_load_traits< Char >::load_packed_16(p); p += 16; n -= 16u; } else { - chars1 = from_chars_simd_load_traits< Char >::load_packed_n(p, n, vl); + chars1 = from_chars_simd_load_traits< Char >::load_packed_n(p, n); p += n; n = 0u; } if (n >= 16u) { - chars2 = from_chars_simd_load_traits< Char >::load_packed_16(p, vl); + chars2 = from_chars_simd_load_traits< Char >::load_packed_16(p); p += 16; n -= 16u; } else { - chars2 = from_chars_simd_load_traits< Char >::load_packed_n(p, n, vl); + chars2 = from_chars_simd_load_traits< Char >::load_packed_n(p, n); p += n; n = 0u; } - chars3 = from_chars_simd_load_traits< Char >::load_packed_n(p, n, vl); + chars3 = from_chars_simd_load_traits< Char >::load_packed_n(p, n); } from_chars_simd_core< Char > ( chars1, chars2, chars3, - u.data(), end_pos, ec, vl + u.data(), end_pos, ec ); return { begin + end_pos, ec }; From 01d2345e8aa9af8fd363f03b06657ed9c7645636 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Sat, 12 Sep 2026 22:15:31 +0300 Subject: [PATCH 08/10] Use vmsne in the hex digit validity check in from_chars_riscv.hpp The valid masks were only negated right after being computed, so a single non-zero test replaces the vmseq/vmnand pair. --- include/boost/uuid/detail/from_chars_riscv.hpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp index 452d2898..4bf58ac3 100644 --- a/include/boost/uuid/detail/from_chars_riscv.hpp +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -600,11 +600,8 @@ BOOST_FORCEINLINE void from_chars_simd_core const vuint8m1_t upper_hi_bits = __riscv_vand_vv_u8m1(upper, mm_F0, vl); const vuint8m1_t lower_hi_bits = __riscv_vand_vv_u8m1(lower, mm_F0, vl); - const vbool8_t upper_valid = __riscv_vmseq_vx_u8m1_b8(upper_hi_bits, 0, vl); - const vbool8_t lower_valid = __riscv_vmseq_vx_u8m1_b8(lower_hi_bits, 0, vl); - - const vbool8_t upper_invalid = __riscv_vmnand_mm_b8(upper_valid, upper_valid, vl); - const vbool8_t lower_invalid = __riscv_vmnand_mm_b8(lower_valid, lower_valid, vl); + const vbool8_t upper_invalid = __riscv_vmsne_vx_u8m1_b8(upper_hi_bits, 0, vl); + const vbool8_t lower_invalid = __riscv_vmsne_vx_u8m1_b8(lower_hi_bits, 0, vl); const long first_invalid_upper = __riscv_vfirst_m_b8(upper_invalid, vl); const long first_invalid_lower = __riscv_vfirst_m_b8(lower_invalid, vl); From d5a3794dda23dd2485a5aa952bc6f94ee4ae9789 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Sat, 12 Sep 2026 23:49:51 +0300 Subject: [PATCH 09/10] Use a single middle vector for the dash check in from_chars_riscv.hpp All four dashes are at character positions 8..23, so sliding chars1 down by 8 and chars2 into lanes 8..15 gives a single vector to check against one dash constant, instead of two comparisons plus a dash character splat. The middle constant replaces mm_expected_dashes1 and mm_expected_dashes2. --- .../boost/uuid/detail/from_chars_riscv.hpp | 91 ++++++------------- 1 file changed, 28 insertions(+), 63 deletions(-) diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp index 4bf58ac3..934ce071 100644 --- a/include/boost/uuid/detail/from_chars_riscv.hpp +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -33,8 +33,7 @@ template< > struct from_chars_simd_char_constants { - static const simd_vector128< std::uint8_t > mm_expected_dashes1; - static const simd_vector128< std::uint8_t > mm_expected_dashes2; + static const simd_vector128< std::uint8_t > mm_expected_dashes; static constexpr std::uint8_t char_code2 = 0x61; // 'a' in ASCII static constexpr std::uint8_t char_code2_sub = static_cast< std::uint8_t >(char_code2 - 10u); @@ -55,12 +54,8 @@ struct from_chars_simd_char_constants }; template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > -const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_expected_dashes1 = - {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00 }}; - -template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > -const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_expected_dashes2 = - {{ 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_expected_dashes = + {{ 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D }}; template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible > const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code2_cmp = @@ -115,8 +110,7 @@ struct from_chars_simd_char_constants< char, false, IsWCharASCIICompatible > static_assert(static_cast< std::int8_t >('0') > -128 && static_cast< std::int8_t >('A') > -128 && static_cast< std::int8_t >('a') > -128, "Boost.UUID: Unsupported char encoding, hexadecimal character codes are expected to be greater than -128"); - static const simd_vector128< std::uint8_t > mm_expected_dashes1; - static const simd_vector128< std::uint8_t > mm_expected_dashes2; + static const simd_vector128< std::uint8_t > mm_expected_dashes; static constexpr std::uint8_t char_code2 = static_cast< std::uint8_t > ( @@ -169,17 +163,10 @@ struct from_chars_simd_char_constants< char, false, IsWCharASCIICompatible > }; template< bool IsWCharASCIICompatible > -const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_expected_dashes1 = -{{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - static_cast< std::uint8_t >('-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >('-'), 0x00, 0x00 -}}; - -template< bool IsWCharASCIICompatible > -const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_expected_dashes2 = +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_expected_dashes = {{ - 0x00, 0x00, static_cast< std::uint8_t >('-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >('-'), - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + static_cast< std::uint8_t >('-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >('-'), 0x00, 0x00, + 0x00, 0x00, static_cast< std::uint8_t >('-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >('-') }}; template< bool IsWCharASCIICompatible > @@ -240,8 +227,7 @@ struct from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false > static_assert(static_cast< std::int8_t >(L'0') > -128 && static_cast< std::int8_t >(L'A') > -128 && static_cast< std::int8_t >(L'a') > -128, "Boost.UUID: Unsupported wchar_t encoding, hexadecimal character codes are expected to be greater than -128"); - static const simd_vector128< std::uint8_t > mm_expected_dashes1; - static const simd_vector128< std::uint8_t > mm_expected_dashes2; + static const simd_vector128< std::uint8_t > mm_expected_dashes; static constexpr std::uint8_t char_code2 = static_cast< std::uint8_t > ( @@ -294,17 +280,10 @@ struct from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false > }; template< bool IsCharASCIICompatible > -const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_expected_dashes1 = -{{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - static_cast< std::uint8_t >(L'-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >(L'-'), 0x00, 0x00 -}}; - -template< bool IsCharASCIICompatible > -const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_expected_dashes2 = +const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_expected_dashes = {{ - 0x00, 0x00, static_cast< std::uint8_t >(L'-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >(L'-'), - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + static_cast< std::uint8_t >(L'-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >(L'-'), 0x00, 0x00, + 0x00, 0x00, static_cast< std::uint8_t >(L'-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >(L'-') }}; template< bool IsCharASCIICompatible > @@ -498,41 +477,27 @@ BOOST_FORCEINLINE void from_chars_simd_core // targets with vectors of at least 128 bits, so 16 lanes are always available. constexpr std::size_t vl = 16u; - // Check if dashes are in the expected positions + // Check if dashes are in the expected positions. All four dashes are at character positions + // 8, 13, 18 and 23, so they all fit into the middle vector formed by characters 8..23, where + // they are in lanes 0, 5, 10 and 15. { - const vuint8m1_t dash_char = __riscv_vmv_v_x_u8m1(static_cast< std::uint8_t >('-'), vl); + const vuint8m1_t middle_lower = __riscv_vslidedown_vx_u8m1(chars1, 8, vl); + const vuint8m1_t middle = __riscv_vslideup_vx_u8m1(middle_lower, chars2, 8, vl); - const vuint8m1_t expected_dashes1 = load_vector128(char_constants::mm_expected_dashes1); - const vuint8m1_t expected_dashes2 = load_vector128(char_constants::mm_expected_dashes2); - - const vbool8_t expected1 = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes1, 0, vl); - const vbool8_t expected2 = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes2, 0, vl); - - const vbool8_t is_dash1 = __riscv_vmseq_vv_u8m1_b8(chars1, dash_char, vl); - const vbool8_t is_dash2 = __riscv_vmseq_vv_u8m1_b8(chars2, dash_char, vl); - - const vbool8_t missing1 = __riscv_vmandn_mm_b8(expected1, is_dash1, vl); - const vbool8_t missing2 = __riscv_vmandn_mm_b8(expected2, is_dash2, vl); - - const long first_missing1 = __riscv_vfirst_m_b8(missing1, vl); - const long first_missing2 = __riscv_vfirst_m_b8(missing2, vl); - - unsigned int dash_pos = 0xFFFFFFFFu; - if (first_missing1 >= 0) - { - dash_pos = static_cast< unsigned int >(first_missing1); - } - if (first_missing2 >= 0) - { - const unsigned int pos2 = static_cast< unsigned int >(first_missing2) + 16u; - if (pos2 < dash_pos) - dash_pos = pos2; - } + const vuint8m1_t expected_dashes = load_vector128(char_constants::mm_expected_dashes); + const vbool8_t expected = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes, 0, vl); + const vbool8_t is_dash = __riscv_vmseq_vv_u8m1_b8(middle, expected_dashes, vl); + const vbool8_t missing = __riscv_vmandn_mm_b8(expected, is_dash, vl); - if (BOOST_UNLIKELY(dash_pos < end_pos)) + const long first_missing = __riscv_vfirst_m_b8(missing, vl); + if (first_missing >= 0) { - end_pos = dash_pos; - ec = from_chars_error::dash_expected; + const unsigned int dash_pos = static_cast< unsigned int >(first_missing) + 8u; + if (dash_pos < end_pos) + { + end_pos = dash_pos; + ec = from_chars_error::dash_expected; + } } } From 2dafb4634fde1f5241f9936fced5875e7bc94c56 Mon Sep 17 00:00:00 2001 From: Dan Kahyan Date: Sun, 13 Sep 2026 00:46:31 +0300 Subject: [PATCH 10/10] Spell out the vector constant loads in from_chars_riscv.hpp load_vector128 was a one-line wrapper around the load intrinsic. Inline it at its call sites, where the required vector length is already available as the local vl. --- .../boost/uuid/detail/from_chars_riscv.hpp | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/include/boost/uuid/detail/from_chars_riscv.hpp b/include/boost/uuid/detail/from_chars_riscv.hpp index 934ce071..2526bf00 100644 --- a/include/boost/uuid/detail/from_chars_riscv.hpp +++ b/include/boost/uuid/detail/from_chars_riscv.hpp @@ -381,11 +381,6 @@ const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_lower_id {{ 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; -BOOST_FORCEINLINE vuint8m1_t load_vector128(const simd_vector128< std::uint8_t >& v) noexcept -{ - return __riscv_vle8_v_u8m1(v.bytes, 16); -} - template< typename Char, std::size_t Size = sizeof(Char) > struct from_chars_simd_load_traits; @@ -484,7 +479,7 @@ BOOST_FORCEINLINE void from_chars_simd_core const vuint8m1_t middle_lower = __riscv_vslidedown_vx_u8m1(chars1, 8, vl); const vuint8m1_t middle = __riscv_vslideup_vx_u8m1(middle_lower, chars2, 8, vl); - const vuint8m1_t expected_dashes = load_vector128(char_constants::mm_expected_dashes); + const vuint8m1_t expected_dashes = __riscv_vle8_v_u8m1(char_constants::mm_expected_dashes.bytes, vl); const vbool8_t expected = __riscv_vmsgtu_vx_u8m1_b8(expected_dashes, 0, vl); const vbool8_t is_dash = __riscv_vmseq_vv_u8m1_b8(middle, expected_dashes, vl); const vbool8_t missing = __riscv_vmandn_mm_b8(expected, is_dash, vl); @@ -506,9 +501,9 @@ BOOST_FORCEINLINE void from_chars_simd_core vuint8m1_t lower = __riscv_vmv_v_x_u8m1(0, vl); { - const vuint8m1_t upper_idx1 = load_vector128(constants::mm_upper_idx_chars1); - const vuint8m1_t upper_idx2 = load_vector128(constants::mm_upper_idx_chars2); - const vuint8m1_t upper_idx3 = load_vector128(constants::mm_upper_idx_chars3); + const vuint8m1_t upper_idx1 = __riscv_vle8_v_u8m1(constants::mm_upper_idx_chars1.bytes, vl); + const vuint8m1_t upper_idx2 = __riscv_vle8_v_u8m1(constants::mm_upper_idx_chars2.bytes, vl); + const vuint8m1_t upper_idx3 = __riscv_vle8_v_u8m1(constants::mm_upper_idx_chars3.bytes, vl); const vuint8m1_t upper1 = __riscv_vrgather_vv_u8m1(chars1, upper_idx1, vl); const vuint8m1_t upper2 = __riscv_vrgather_vv_u8m1(chars2, upper_idx2, vl); @@ -520,9 +515,9 @@ BOOST_FORCEINLINE void from_chars_simd_core } { - const vuint8m1_t lower_idx1 = load_vector128(constants::mm_lower_idx_chars1); - const vuint8m1_t lower_idx2 = load_vector128(constants::mm_lower_idx_chars2); - const vuint8m1_t lower_idx3 = load_vector128(constants::mm_lower_idx_chars3); + const vuint8m1_t lower_idx1 = __riscv_vle8_v_u8m1(constants::mm_lower_idx_chars1.bytes, vl); + const vuint8m1_t lower_idx2 = __riscv_vle8_v_u8m1(constants::mm_lower_idx_chars2.bytes, vl); + const vuint8m1_t lower_idx3 = __riscv_vle8_v_u8m1(constants::mm_lower_idx_chars3.bytes, vl); const vuint8m1_t lower1 = __riscv_vrgather_vv_u8m1(chars1, lower_idx1, vl); const vuint8m1_t lower2 = __riscv_vrgather_vv_u8m1(chars2, lower_idx2, vl); @@ -536,8 +531,8 @@ BOOST_FORCEINLINE void from_chars_simd_core // Convert characters to 8-bit integers. See the comment in from_chars_x86.hpp for the algorithm description. const vint8m1_t upper_i8 = __riscv_vreinterpret_v_u8m1_i8m1(upper); const vint8m1_t lower_i8 = __riscv_vreinterpret_v_u8m1_i8m1(lower); - const vuint8m1_t char_code1_cmp = load_vector128(char_constants::mm_char_code1_cmp); - const vuint8m1_t char_code2_cmp = load_vector128(char_constants::mm_char_code2_cmp); + const vuint8m1_t char_code1_cmp = __riscv_vle8_v_u8m1(char_constants::mm_char_code1_cmp.bytes, vl); + const vuint8m1_t char_code2_cmp = __riscv_vle8_v_u8m1(char_constants::mm_char_code2_cmp.bytes, vl); const vint8m1_t char_code1_cmp_i8 = __riscv_vreinterpret_v_u8m1_i8m1(char_code1_cmp); const vint8m1_t char_code2_cmp_i8 = __riscv_vreinterpret_v_u8m1_i8m1(char_code2_cmp); @@ -547,9 +542,9 @@ BOOST_FORCEINLINE void from_chars_simd_core const vbool8_t lower_code2_mask = __riscv_vmsgt_vv_i8m1_b8(lower_i8, char_code2_cmp_i8, vl); const vbool8_t lower_code1_mask = __riscv_vmsgt_vv_i8m1_b8(lower_i8, char_code1_cmp_i8, vl); - const vuint8m1_t char_code0_sub = load_vector128(char_constants::mm_char_code0_sub); - const vuint8m1_t char_code1_sub = load_vector128(char_constants::mm_char_code1_sub); - const vuint8m1_t char_code2_sub = load_vector128(char_constants::mm_char_code2_sub); + const vuint8m1_t char_code0_sub = __riscv_vle8_v_u8m1(char_constants::mm_char_code0_sub.bytes, vl); + const vuint8m1_t char_code1_sub = __riscv_vle8_v_u8m1(char_constants::mm_char_code1_sub.bytes, vl); + const vuint8m1_t char_code2_sub = __riscv_vle8_v_u8m1(char_constants::mm_char_code2_sub.bytes, vl); vuint8m1_t upper_sub = __riscv_vmerge_vvm_u8m1(char_code1_sub, char_code2_sub, upper_code2_mask, vl); upper_sub = __riscv_vmerge_vvm_u8m1(char_code0_sub, upper_sub, upper_code1_mask, vl); @@ -561,7 +556,7 @@ BOOST_FORCEINLINE void from_chars_simd_core lower = __riscv_vsub_vv_u8m1(lower, lower_sub, vl); // Check hexadecimal character validity. Values outside 0-15 will have non-zero upper 4 bits. - const vuint8m1_t mm_F0 = load_vector128(constants::mm_F0); + const vuint8m1_t mm_F0 = __riscv_vle8_v_u8m1(constants::mm_F0.bytes, vl); const vuint8m1_t upper_hi_bits = __riscv_vand_vv_u8m1(upper, mm_F0, vl); const vuint8m1_t lower_hi_bits = __riscv_vand_vv_u8m1(lower, mm_F0, vl);