DAW JSON Link
Loading...
Searching...
No Matches
daw_json_simd_sse42.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_SSE42_SIMD 1
14
15#include <nmmintrin.h>
16
17#include <cstddef>
18#include <cstdint>
19#include <cstring>
20#include <type_traits>
21
22namespace daw::simd_impl::sse42 {
23 class mask {
24 __m128i m_value;
25
26 public:
27 explicit mask( __m128i value ) noexcept
28 : m_value( value ) {}
29
30 [[nodiscard]] std::uint64_t to_ullong( ) const noexcept {
31 return static_cast<std::uint32_t>( _mm_movemask_epi8( m_value ) );
32 }
33
34 [[nodiscard]] friend mask operator|( mask lhs, mask rhs ) noexcept {
35 return mask( _mm_or_si128( lhs.m_value, rhs.m_value ) );
36 }
37
38 [[nodiscard]] friend mask operator&( mask lhs, mask rhs ) noexcept {
39 return mask( _mm_and_si128( lhs.m_value, rhs.m_value ) );
40 }
41
42 [[nodiscard]] friend mask operator!( mask value ) noexcept {
43 return mask( _mm_xor_si128( value.m_value,
44 _mm_set1_epi8( static_cast<char>( 0xFF ) ) ) );
45 }
46 };
47
48 template<typename T, std::size_t /*MaximumSize*/ = 16U>
49 class vec {
50 static_assert( sizeof( T ) == 1,
51 "The SSE4.2 JSON SIMD implementation supports byte types" );
52 static_assert(
53 std::is_integral_v<T>,
54 "The SSE4.2 JSON SIMD implementation requires an integral type" );
55
56 __m128i m_value;
57
58 template<typename U, std::size_t MaximumSize>
59 friend class vec;
60
61 template<typename Simd, typename Range, typename Flag>
62 friend Simd unchecked_load( Range values, Flag );
63
64 template<typename Simd, typename Range, typename Flag>
65 friend Simd partial_load( Range values, Flag );
66
67 explicit vec( __m128i value ) noexcept
68 : m_value( value ) {}
69
70 [[nodiscard]] static __m128i order_bytes( __m128i value ) noexcept {
71 return _mm_xor_si128( value,
72 _mm_set1_epi8( static_cast<char>( 0x80 ) ) );
73 }
74
75 public:
76 using value_type = T;
77 using mask_type = mask;
78
79 explicit vec( value_type value ) noexcept
80 : m_value( _mm_set1_epi8( static_cast<char>( value ) ) ) {}
81
82 [[nodiscard]] static constexpr std::size_t size( ) noexcept {
83 return 16;
84 }
85
86 [[nodiscard]] friend mask operator==( vec lhs, vec rhs ) noexcept {
87 return mask( _mm_cmpeq_epi8( lhs.m_value, rhs.m_value ) );
88 }
89
90 [[nodiscard]] friend mask operator>=( vec lhs, vec rhs ) noexcept {
91 auto const ordered_lhs = order_bytes( lhs.m_value );
92 auto const ordered_rhs = order_bytes( rhs.m_value );
93 return mask( _mm_or_si128( _mm_cmpgt_epi8( ordered_lhs, ordered_rhs ),
94 _mm_cmpeq_epi8( lhs.m_value, rhs.m_value ) ) );
95 }
96
97 [[nodiscard]] friend mask operator<=( vec lhs, vec rhs ) noexcept {
98 auto const ordered_lhs = order_bytes( lhs.m_value );
99 auto const ordered_rhs = order_bytes( rhs.m_value );
100 return mask( _mm_or_si128( _mm_cmpgt_epi8( ordered_rhs, ordered_lhs ),
101 _mm_cmpeq_epi8( lhs.m_value, rhs.m_value ) ) );
102 }
103 };
104
105 struct flag_default_t {};
106 struct flag_convert_t {};
107
108 inline constexpr flag_default_t flag_default = { };
109 inline constexpr flag_convert_t flag_convert = { };
110
111 template<typename Simd, typename Range, typename Flag = flag_default_t>
112 [[nodiscard]] inline Simd unchecked_load( Range values,
113 Flag = flag_default ) {
114 static_assert( Simd::size( ) == 16 );
115 return Simd( _mm_loadu_si128(
116 reinterpret_cast<__m128i const *>( values.data( ) ) ) );
117 }
118
119 template<typename Simd, typename Range, typename Flag = flag_default_t>
120 [[nodiscard]] inline Simd partial_load( Range values, Flag = flag_default ) {
121 static_assert( Simd::size( ) == 16 );
122 auto result = _mm_setzero_si128( );
123 std::memcpy( &result, values.data( ), values.size( ) );
124 return Simd( result );
125 }
126} // namespace daw::simd_impl::sse42