DAW JSON Link
Loading...
Searching...
No Matches
daw_json_simd.h
Go to the documentation of this file.
1// Copyright (c) Darrell Wright
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6// Official repository: https://github.com/beached/daw_json_link
7//
8
9#pragma once
10
11#include <daw/daw_cpp_feature_check.h>
12#include <daw/daw_is_constant_evaluated.h>
13#include <daw/daw_span.h>
14
16
17#include <cstddef>
18#include <cstdint>
19#include <cstring>
20#include <type_traits>
21
22#if defined( __BMI2__ ) and ( defined( __x86_64__ ) or defined( _M_X64 ) )
23#include <immintrin.h>
24#endif
25
26#if __has_include( <simd> )
27#include <simd>
28#endif
29
30#if defined( __cpp_lib_simd ) or defined( __glibcxx_simd )
31
32#define DAW_JSON_HAS_STD_SIMD 1
33
34#endif
35
36#if ( defined( __ARM_NEON ) or defined( __ARM_NEON__ ) )
38#endif
39
40#if defined( __AVX2__ ) or defined( _M_AVX2 )
42#elif defined( __SSE4_2__ ) or defined( __AVX__ ) or defined( _M_X64 ) or \
43 ( defined( _M_IX86_FP ) and _M_IX86_FP >= 2 )
45#endif
46
47#if defined( DAW_JSON_HAS_STD_SIMD )
48
49#define DAW_JSON_HAS_SIMD 1
50#define DAW_JSON_SIMD_CONSTEXPR constexpr
51
52#if defined( DAW_JSON_SIMD_MAX_256 )
53// vec<T> is at most 256 bits, so a build with AVX-512 enabled stays in 256-bit
54// registers. 512-bit instructions lower the clock on some CPUs, mostly older
55// Xeons; where that costs less than the wider blocks save, as on Tiger Lake
56// and Zen 4, leave this undefined. Narrower native widths are kept
57namespace daw::simd {
58 using namespace std::simd;
59
60 template<typename T>
61 inline constexpr int max_256_size_v =
62 static_cast<int>( std::simd::vec<T>::size( ) ) <
63 static_cast<int>( 32 / sizeof( T ) )
64 ? static_cast<int>( std::simd::vec<T>::size( ) )
65 : static_cast<int>( 32 / sizeof( T ) );
66
67 template<typename T, int N = max_256_size_v<T>>
68 using vec = std::simd::vec<T, N>;
69} // namespace daw::simd
70#else
71namespace daw {
72 namespace simd = std::simd;
73}
74#endif
75
76#elif defined( DAW_JSON_HAS_NEON_SIMD )
77
78#define DAW_JSON_HAS_SIMD 1
79#define DAW_JSON_SIMD_CONSTEXPR inline
80
81namespace daw {
82 namespace simd = simd_impl::neon;
83}
84
85#elif defined( DAW_JSON_HAS_AVX2_SIMD )
86
87#define DAW_JSON_HAS_SIMD 1
88#define DAW_JSON_SIMD_CONSTEXPR inline
89
90namespace daw {
91 namespace simd = simd_impl::avx2;
92}
93
94#elif defined( DAW_JSON_HAS_SSE42_SIMD )
95
96#define DAW_JSON_HAS_SIMD 1
97#define DAW_JSON_SIMD_CONSTEXPR inline
98
99namespace daw {
100 namespace simd = simd_impl::sse42;
101}
102
103#endif
104
105#if defined( DAW_JSON_HAS_SIMD )
106
107namespace daw::simd_impl {
113 [[nodiscard]] constexpr std::uint64_t
114 compress_bits( std::uint64_t values, std::uint64_t selection ) noexcept {
115#if defined( __BMI2__ ) and ( defined( __x86_64__ ) or defined( _M_X64 ) )
116 if( not DAW_IS_CONSTANT_EVALUATED_COMPAT( ) ) {
117 return _pext_u64( values, selection );
118 }
119#endif
120 auto result = std::uint64_t{ 0 };
121 auto output_bit = std::uint64_t{ 1 };
122 while( selection != 0 ) {
123 auto const selected_bit = selection & ( ~selection + 1U );
124 if( ( values & selected_bit ) != 0 ) {
125 result |= output_bit;
126 }
127 selection &= selection - 1U;
128 output_bit <<= 1U;
129 }
130 return result;
131 }
132
139 template<typename Mask,
140 std::enable_if_t<not std::is_integral_v<Mask>, int> = 0>
141 [[nodiscard]] DAW_JSON_SIMD_CONSTEXPR std::uint64_t
142 compress_bits( Mask values, std::uint64_t selection ) noexcept {
143 return compress_bits( values.to_ullong( ), selection );
144 }
145
146 template<typename Mask,
147 std::enable_if_t<not std::is_integral_v<Mask>, int> = 0>
148 [[nodiscard]] DAW_JSON_SIMD_CONSTEXPR std::uint64_t
149 compress_bits( Mask values, Mask selection ) noexcept {
150 return compress_bits( values.to_ullong( ), selection.to_ullong( ) );
151 }
152} // namespace daw::simd_impl
153
154// Scans load whole aligned blocks, which can extend past either end of the
155// range being scanned. An aligned load never crosses a page so this cannot
156// fault, but sanitizers report the bytes outside the range. Under a
157// sanitizer only the bytes inside the range are copied to an aligned local
158// block and loaded from there.
159#if defined( __SANITIZE_ADDRESS__ ) or defined( __SANITIZE_HWADDRESS__ )
160#define DAW_JSON_SIMD_SAFE_ALIGNED_LOADS 1
161#elif defined( __has_feature )
162#if __has_feature( address_sanitizer ) or \
163 __has_feature( hwaddress_sanitizer ) or __has_feature( memory_sanitizer )
164#define DAW_JSON_SIMD_SAFE_ALIGNED_LOADS 1
165#endif
166#endif
167
168namespace daw::json {
169 inline namespace DAW_JSON_VER {
170 namespace json_details {
174 template<typename Simd>
175 [[nodiscard]] inline Simd
176 load_aligned_block( std::uintptr_t block_addr,
177 [[maybe_unused]] std::uintptr_t first_addr,
178 [[maybe_unused]] std::uintptr_t last_addr ) {
179 using value_t = typename Simd::value_type;
180 static_assert( sizeof( value_t ) == 1 );
181 constexpr std::size_t block_size = Simd::size( );
182#if defined( DAW_JSON_SIMD_SAFE_ALIGNED_LOADS )
183 alignas( block_size ) value_t buff[block_size] = { };
184 auto const lo = block_addr < first_addr ? first_addr : block_addr;
185 auto const hi = last_addr < block_addr + block_size
186 ? last_addr
187 : block_addr + block_size;
188 std::memcpy( buff + ( lo - block_addr ),
189 reinterpret_cast<void const *>( lo ), hi - lo );
190 value_t const *const ptr = buff;
191#else
192 auto const *const ptr = reinterpret_cast<value_t const *>( block_addr );
193#endif
194 return daw::simd::unchecked_load<Simd>( daw::span( ptr, block_size ),
195 daw::simd::flag_aligned );
196 }
197 } // namespace json_details
198 } // namespace DAW_JSON_VER
199} // namespace daw::json
200
201#if defined( DAW_JSON_SIMD_SAFE_ALIGNED_LOADS )
202#undef DAW_JSON_SIMD_SAFE_ALIGNED_LOADS
203#endif
204
205namespace daw::json {
206 inline namespace DAW_JSON_VER {
207 namespace json_details {
208 struct number_span {
209 char const *first = nullptr;
210 char const *last = nullptr;
211 char const *decimal_point = nullptr;
212 char const *exponent_marker = nullptr;
213 };
214
215 struct pending_number_span {
216 char const *first = nullptr;
217 char const *decimal_point = nullptr;
218 char const *exponent_marker = nullptr;
219 };
220
221 struct integer_span {
222 char const *first = nullptr;
223 char const *last = nullptr;
224 };
225
226 struct pending_integer_span {
227 char const *first = nullptr;
228 };
229 } // namespace json_details
230 } // namespace DAW_JSON_VER
231} // namespace daw::json
232
233#endif
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20