DAW JSON Link
Loading...
Searching...
No Matches
daw_json_simd_neon.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
13#define DAW_JSON_HAS_NEON_SIMD 1
14
15#include <arm_neon.h>
16
17#include <cstddef>
18#include <cstdint>
19#include <cstring>
20#include <type_traits>
21
22namespace daw::simd_impl::neon {
23 namespace details {
24 [[nodiscard]] inline std::uint64_t
25 to_bits( uint8x16_t comparison ) noexcept {
26 alignas( 16 ) static constexpr std::uint8_t bit_values[16] = { 0x01,
27 0x02,
28 0x04,
29 0x08,
30 0x10,
31 0x20,
32 0x40,
33 0x80,
34 0x01,
35 0x02,
36 0x04,
37 0x08,
38 0x10,
39 0x20,
40 0x40,
41 0x80 };
42 auto const bits = vandq_u8( comparison, vld1q_u8( bit_values ) );
43 auto const pairs = vpaddlq_u8( bits );
44 auto const quads = vpaddlq_u16( pairs );
45 auto const octets = vpaddlq_u32( quads );
46 return vgetq_lane_u64( octets, 0 ) |
47 ( vgetq_lane_u64( octets, 1 ) << 8U );
48 }
49 } // namespace details
50
51 class mask {
52 uint8x16_t m_value;
53
54 public:
55 explicit mask( uint8x16_t value ) noexcept
56 : m_value( value ) {}
57
58 [[nodiscard]] std::uint64_t to_ullong( ) const noexcept {
59 return details::to_bits( m_value );
60 }
61
62 [[nodiscard]] std::uint64_t to_ullong_sparse( ) const noexcept {
63 auto reduced =
64 vorr_u8( vget_low_u8( m_value ), vget_high_u8( m_value ) );
65 reduced = vpmax_u8( reduced, reduced );
66 reduced = vpmax_u8( reduced, reduced );
67 reduced = vpmax_u8( reduced, reduced );
68 if( vget_lane_u8( reduced, 0 ) == 0 ) {
69 return 0;
70 }
71 return details::to_bits( m_value );
72 }
73
74 [[nodiscard]] friend mask operator|( mask lhs, mask rhs ) noexcept {
75 return mask( vorrq_u8( lhs.m_value, rhs.m_value ) );
76 }
77
78 [[nodiscard]] friend mask operator&( mask lhs, mask rhs ) noexcept {
79 return mask( vandq_u8( lhs.m_value, rhs.m_value ) );
80 }
81
82 [[nodiscard]] friend mask operator!( mask value ) noexcept {
83 return mask( vmvnq_u8( value.m_value ) );
84 }
85 };
86
87 template<typename T, std::size_t /*MaximumSize*/ = 16U>
88 class vec {
89 static_assert( sizeof( T ) == 1,
90 "The NEON JSON SIMD implementation supports byte types" );
91 static_assert(
92 std::is_integral_v<T>,
93 "The NEON JSON SIMD implementation requires an integral type" );
94
95 uint8x16_t m_value;
96
97 template<typename U, std::size_t MaximumSize>
98 friend class vec;
99
100 template<typename Simd, typename Range, typename Flag>
101 friend Simd unchecked_load( Range values, Flag );
102
103 template<typename Simd, typename Range, typename Flag>
104 friend Simd partial_load( Range values, Flag );
105
106 explicit vec( uint8x16_t value ) noexcept
107 : m_value( value ) {}
108
109 public:
110 using value_type = T;
111 using mask_type = mask;
112
113 explicit vec( value_type value ) noexcept
114 : m_value( vdupq_n_u8( static_cast<std::uint8_t>( value ) ) ) {}
115
116 [[nodiscard]] static constexpr std::size_t size( ) noexcept {
117 return 16;
118 }
119
120 [[nodiscard]] friend mask operator==( vec lhs, vec rhs ) noexcept {
121 return mask( vceqq_u8( lhs.m_value, rhs.m_value ) );
122 }
123
124 [[nodiscard]] friend mask operator>=( vec lhs, vec rhs ) noexcept {
125 return mask( vcgeq_u8( lhs.m_value, rhs.m_value ) );
126 }
127
128 [[nodiscard]] friend mask operator<=( vec lhs, vec rhs ) noexcept {
129 return mask( vcleq_u8( lhs.m_value, rhs.m_value ) );
130 }
131 };
132
133 struct flag_default_t {};
134 struct flag_convert_t {};
135
136 inline constexpr flag_default_t flag_default = { };
137 inline constexpr flag_convert_t flag_convert = { };
138
139 template<typename Simd, typename Range, typename Flag = flag_default_t>
140 [[nodiscard]] inline Simd unchecked_load( Range values,
141 Flag = flag_default ) {
142 static_assert( Simd::size( ) == 16 );
143 return Simd(
144 vld1q_u8( reinterpret_cast<std::uint8_t const *>( values.data( ) ) ) );
145 }
146
147 template<typename Simd, typename Range, typename Flag = flag_default_t>
148 [[nodiscard]] inline Simd partial_load( Range values, Flag = flag_default ) {
149 static_assert( Simd::size( ) == 16 );
150 auto result = vdupq_n_u8( 0 );
151 std::memcpy( &result, values.data( ), values.size( ) );
152 return Simd( result );
153 }
154} // namespace daw::simd_impl::neon