SeqAn3 3.1.0
The Modern C++ library for sequence analysis.
builtin_simd.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2021, 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 <seqan3/std/bit>
17#include <type_traits>
18
23
24namespace seqan3::detail
25{
26
52template <typename scalar_t, size_t length>
53struct builtin_simd;
54
57template <typename scalar_t, size_t length>
59 requires (std::has_single_bit(length))
61struct builtin_simd<scalar_t, length>
62{
64#if SEQAN3_DOXYGEN_ONLY(1)0
65 using type = scalar_t __attribute__((vector_size(sizeof(scalar_t) * length))));
66 // doxygen 1.8.13 does not support c++11 attributes, thus this doxygen-only definition
67#elif defined(__clang__)
68 using type = scalar_t __attribute__((ext_vector_type(length)));
69#else
70 using type [[gnu::vector_size(sizeof(scalar_t) * length)]] = scalar_t;
71#endif
72};
73
78template <typename builtin_simd_t>
79struct builtin_simd_traits_helper : std::false_type
80{};
81
86template <typename builtin_simd_t>
88 // NOTE: gcc throws a compile time error if builtin_simd_t is a pointer of an incomplete type. To tackle this we
89 // short-circuit the requires with is_pointer_v. See builtin_simd_test.cpp for a test case for this.
90 requires (!std::is_pointer_v<std::decay_t<builtin_simd_t>>) && requires(builtin_simd_t simd)
91 {
92 { simd[0] };
93 }
95struct builtin_simd_traits_helper<builtin_simd_t>
96{
100 static constexpr auto length = sizeof(builtin_simd_t) / sizeof(scalar_type);
101
104 static constexpr bool value = std::has_single_bit(length) &&
105 std::is_same_v<builtin_simd_t,
106 transformation_trait_or_t<builtin_simd<scalar_type, length>, void>>;
107};
108
117template <typename builtin_simd_t>
118struct is_builtin_simd : std::bool_constant<builtin_simd_traits_helper<builtin_simd_t>::value>
119{};
120
126template <typename builtin_simd_t>
127constexpr bool is_builtin_simd_v = is_builtin_simd<builtin_simd_t>::value;
128
137template <>
138constexpr auto default_simd_max_length<builtin_simd> = []()
139{
140#if defined(__AVX512F__)
141 return min_viable_uint_v<64u>;
142#elif defined(__AVX2__)
143 return min_viable_uint_v<32u>;
144#elif defined(__SSE4_1__) && defined(__SSE4_2__)
145 return min_viable_uint_v<16u>;
146#else
147 return min_viable_uint_v<0u>;
148#endif
149}();
150
163template <typename builtin_simd_t>
164struct is_native_builtin_simd :
165 std::bool_constant<(default_simd_max_length<builtin_simd> != 0) &&
166 ((builtin_simd_traits_helper<builtin_simd_t>::length *
167 sizeof(typename builtin_simd_traits_helper<builtin_simd_t>::scalar_type)) >= 16) &&
168 ((builtin_simd_traits_helper<builtin_simd_t>::length *
169 sizeof(typename builtin_simd_traits_helper<builtin_simd_t>::scalar_type)) <= 64)>
170{};
171
172
178template <typename builtin_simd_t>
179constexpr bool is_native_builtin_simd_v = is_native_builtin_simd<builtin_simd_t>::value;
180
181} // namespace seqan3::detail
182
183namespace seqan3
184{
185
186inline namespace simd
187{
188
194template <typename builtin_simd_t>
195// \cond
196 requires detail::is_builtin_simd<builtin_simd_t>::value
197// \endcond
198struct 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} // inline 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.
constexpr bool has_single_bit(T x) noexcept
Checks if x is an integral power of two.
Definition: bit:151
Provides metaprogramming utilities for integer types.
T is_same_v
The main SeqAn3 namespace.
Definition: cigar_operation_table.hpp:2
Provides seqan3::simd::simd_traits.
Provides seqan3::detail::transformation_trait_or.