SeqAn3  3.2.0-rc.1
The Modern C++ library for sequence analysis.
builtin_simd.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2022, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
14 #pragma once
15 
16 #include <bit>
17 #include <type_traits>
18 
23 
24 namespace seqan3::detail
25 {
26 
52 template <typename scalar_t, size_t length>
53 struct builtin_simd;
54 
57 template <typename scalar_t, size_t length>
58  requires (std::has_single_bit(length))
59 struct builtin_simd<scalar_t, length>
60 {
62 #if SEQAN3_DOXYGEN_ONLY(1) 0
63  using type = scalar_t __attribute__((vector_size(sizeof(scalar_t) * length))));
64  // doxygen 1.8.13 does not support c++11 attributes, thus this doxygen-only definition
65 #elif defined(__clang__)
66  using type = scalar_t __attribute__((ext_vector_type(length)));
67 #else
68  using type [[gnu::vector_size(sizeof(scalar_t) * length)]] = scalar_t;
69 #endif
70 };
71 
76 template <typename builtin_simd_t>
77 struct builtin_simd_traits_helper : std::false_type
78 {};
79 
84 template <typename builtin_simd_t>
86 // NOTE: gcc throws a compile time error if builtin_simd_t is a pointer of an incomplete type. To tackle this we
87 // short-circuit the requires with is_pointer_v. See builtin_simd_test.cpp for a test case for this.
89  {
90  simd[0]
91  };
92  }
94 struct builtin_simd_traits_helper<builtin_simd_t>
95 {
99  static constexpr auto length = sizeof(builtin_simd_t) / sizeof(scalar_type);
100 
103  static constexpr bool value =
104  std::has_single_bit(length)
105  && std::is_same_v<builtin_simd_t, transformation_trait_or_t<builtin_simd<scalar_type, length>, void>>;
106 };
107 
116 template <typename builtin_simd_t>
117 struct is_builtin_simd : std::bool_constant<builtin_simd_traits_helper<builtin_simd_t>::value>
118 {};
119 
125 template <typename builtin_simd_t>
126 constexpr bool is_builtin_simd_v = is_builtin_simd<builtin_simd_t>::value;
127 
136 template <>
137 constexpr auto default_simd_max_length<builtin_simd> = []()
138 {
139 #if defined(__AVX512F__)
140  return min_viable_uint_v<64u>;
141 #elif defined(__AVX2__)
142  return min_viable_uint_v<32u>;
143 #elif defined(__SSE4_1__) && defined(__SSE4_2__)
144  return min_viable_uint_v<16u>;
145 #else
146  return min_viable_uint_v<0u>;
147 #endif
148 }();
149 
162 template <typename builtin_simd_t>
163 struct is_native_builtin_simd :
164  std::bool_constant<(default_simd_max_length<builtin_simd> != 0)
165  && ((builtin_simd_traits_helper<builtin_simd_t>::length
166  * sizeof(typename builtin_simd_traits_helper<builtin_simd_t>::scalar_type))
167  >= 16)
168  && ((builtin_simd_traits_helper<builtin_simd_t>::length
169  * sizeof(typename builtin_simd_traits_helper<builtin_simd_t>::scalar_type))
170  <= 64)>
171 {};
172 
178 template <typename builtin_simd_t>
179 constexpr bool is_native_builtin_simd_v = is_native_builtin_simd<builtin_simd_t>::value;
180 
181 } // namespace seqan3::detail
182 
183 namespace seqan3
184 {
185 
186 inline namespace simd
187 {
188 
194 template <typename builtin_simd_t>
195 // \cond
196  requires detail::is_builtin_simd<builtin_simd_t>::value
197 // \endcond
198 struct simd_traits<builtin_simd_t>
199 {
201  using scalar_type = typename detail::builtin_simd_traits_helper<builtin_simd_t>::scalar_type;
203  static constexpr auto length = detail::builtin_simd_traits_helper<builtin_simd_t>::length;
205  static constexpr auto max_length = length == 1u ? length : sizeof(scalar_type) * length;
206 
207  static_assert(std::is_integral_v<scalar_type>, "For now we assume that builtin simd can only be integers");
209  using mask_type = decltype(std::declval<builtin_simd_t>() == std::declval<builtin_simd_t>());
211  using swizzle_type = typename detail::builtin_simd<uint8_t, max_length>::type;
212 
214  template <typename new_scalar_type>
215  // \cond
216  requires (sizeof(scalar_type) == sizeof(new_scalar_type))
217  // \endcond
218  using rebind = typename detail::builtin_simd<new_scalar_type, length>::type;
219 };
220 
221 } // namespace simd
222 
223 } // namespace seqan3
The <bit> header from C++20's standard library.
Provides seqan3::detail::default_simd_length and seqan3::detail::default_simd_max_length.
requires requires
The rank_type of the semi-alphabet; defined as the return type of seqan3::to_rank....
Definition: alphabet/concept.hpp:164
Provides metaprogramming utilities for integer types.
T is_pointer_v
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
Provides seqan3::simd::simd_traits.
Provides seqan3::detail::transformation_trait_or.