SeqAn3
The Modern C++ library for sequence analysis.
builtin_simd.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2019, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2019, 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 <type_traits>
17 
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>
59  requires is_power_of_two(length)
61 struct 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 
78 template <typename builtin_simd_t>
79 struct builtin_simd_traits_helper : std::false_type
80 {};
81 
86 template <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  }
95 struct builtin_simd_traits_helper<builtin_simd_t>
96 {
100  static constexpr auto length = min_viable_uint_v<sizeof(builtin_simd_t) / sizeof(scalar_type)>;
101 
104  static constexpr bool value = is_power_of_two(length) && std::is_same_v<builtin_simd_t, transformation_trait_or_t<builtin_simd<scalar_type, length>, void>>;
105 };
106 
116 template <typename builtin_simd_t>
117 struct is_builtin_simd : std::bool_constant<builtin_simd_traits_helper<builtin_simd_t>::value>
118 {};
119 
128 template <>
129 constexpr auto default_simd_max_length<builtin_simd> = []()
130 {
131 #if defined(__AVX512F__)
132  return min_viable_uint_v<64u>;
133 #elif defined(__AVX2__)
134  return min_viable_uint_v<32u>;
135 #elif defined(__SSE4_1__) && defined(__SSE4_2__)
136  return min_viable_uint_v<16u>;
137 #else
138  return min_viable_uint_v<0u>;
139 #endif
140 }();
141 
142 } // namespace seqan3::detail
143 
144 namespace seqan3
145 {
146 
147 inline namespace simd
148 {
149 
155 template <typename builtin_simd_t>
156 // \cond
157  requires detail::is_builtin_simd<builtin_simd_t>::value
158 // \endcond
159 struct simd_traits<builtin_simd_t>
160 {
162  using scalar_type = typename detail::builtin_simd_traits_helper<builtin_simd_t>::scalar_type;
164  static constexpr auto length = detail::builtin_simd_traits_helper<builtin_simd_t>::length;
166  static constexpr auto max_length = length == 1u ? length : sizeof(scalar_type) * length;
167 
168  static_assert(std::is_integral_v<scalar_type>, "For now we assume that builtin simd can only be integers");
170  using mask_type = decltype(std::declval<builtin_simd_t>() == std::declval<builtin_simd_t>());
172  using swizzle_type = typename detail::builtin_simd<uint8_t, max_length>::type;
173 };
174 
175 } // inline namespace simd
176 
177 } // namespace seqan3
Provides seqan3::simd::simd_traits.
Provides metaprogramming utilities for integer types.
Provides seqan3::detail::transformation_trait_or.
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:35
Provides utility functions for bit twiddling.
Provides seqan3::detail::default_simd_length and seqan3::detail::default_simd_max_length.