VCTR
Loading...
Searching...
No Matches
SIMDHelpers.h
1/*
2 ==============================================================================
3 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
5 Copyright 2022- by sonible GmbH.
6
7 This file is part of VCTR - Versatile Container Templates Reconceptualized.
8
9 VCTR is free software: you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License version 3
11 only, as published by the Free Software Foundation.
12
13 VCTR is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License version 3 for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 version 3 along with VCTR. If not, see <https://www.gnu.org/licenses/>.
20 ==============================================================================
21*/
22
23namespace vctr::detail
24{
25template <size_t value>
26requires (is::powerOfTwoInt<value>)
27constexpr size_t previousMultipleOf (size_t numElements)
28{
29 constexpr auto numMaskBits = std::bit_width (value) - 1;
30 constexpr auto allBitsOne = size_t (-1);
31 constexpr auto mask = allBitsOne << numMaskBits;
32
33 return numElements & mask;
34}
35
36template <size_t value>
37requires (is::powerOfTwoInt<value>)
38constexpr size_t nextMultipleOf (size_t numElements)
39{
40 return size_t ((int64_t (numElements) + int64_t (value) - 1) & -int64_t (value));
41}
42
43} // namespace vctr::detail
44
45namespace vctr
46{
47
48#if (! VCTR_X64)
49// These are defined in immintrin.h – defining them here for non x86 builds
50// to be able to assign the CompareOp enum cross-platform
51// NOLINTBEGIN (*-reserved-identifier)
52constexpr auto _CMP_LT_OQ = 0;
53constexpr auto _CMP_LE_OQ = 1;
54constexpr auto _CMP_GT_OQ = 2;
55constexpr auto _CMP_GE_OQ = 3;
56constexpr auto _CMP_EQ_OQ = 4;
57constexpr auto _CMP_NEQ_OQ = 5;
58// NOLINTEND (*-reserved-identifier)
59#endif
60
62enum class CompareOp : int
63{
64 less = _CMP_LT_OQ, // <
65 lessOrEqual = _CMP_LE_OQ, // <=
66 greater = _CMP_GT_OQ, // >
67 greaterOrEqual = _CMP_GE_OQ, // >=
68 equal = _CMP_EQ_OQ, // ==
69 notEqual = _CMP_NEQ_OQ // !=
70};
71
80template <uintptr_t requiredAlignment = Config::maxSIMDRegisterSize>
81inline constexpr bool isPtrAligned (const void* ptr)
82{
83 // SIMD alignment is not meaningful in case of constant evaluation
84 if (std::is_constant_evaluated())
85 return false;
86
87 return reinterpret_cast<std::uintptr_t> (ptr) % requiredAlignment == 0;
88}
89
105template <class StorageType>
107{
108 // The default implementation is empty and should never be used
109};
110
111template <has::sizeAndData StorageType>
112struct StorageInfo<StorageType>
113{
114 constexpr StorageInfo()
115 : dataIsSIMDAligned (false),
116 hasSIMDExtendedStorage (false)
117 {}
118
119 template <is::storageInfo OtherStorageInfoType>
120 constexpr StorageInfo (const OtherStorageInfoType& other)
121 : dataIsSIMDAligned (other.dataIsSIMDAligned),
122 hasSIMDExtendedStorage (other.hasSIMDExtendedStorage)
123 {}
124
125 template <class T>
126 constexpr StorageInfo init (const T* ptr, size_t s)
127 {
128 dataIsSIMDAligned = isPtrAligned (ptr);
129 hasSIMDExtendedStorage = (s * sizeof (T)) % Config::maxSIMDRegisterSize == 0;
130 return *this;
131 }
132
133 static constexpr size_t memberAlignment = alignof (StorageType);
134
135 bool dataIsSIMDAligned;
136
137 bool hasSIMDExtendedStorage;
138};
139
140template <class ElementType, size_t alignmentInBytes>
141struct StorageInfo<std::vector<ElementType, AlignedAllocator<ElementType, alignmentInBytes>>>
142{
143 constexpr StorageInfo init (const void*, size_t) { return *this; }
144
145 static constexpr size_t memberAlignment = alignof (std::vector<ElementType, AlignedAllocator<ElementType, alignmentInBytes>>);
146
147 static constexpr bool dataIsSIMDAligned = alignmentInBytes == Config::maxSIMDRegisterSize;
148
150 static constexpr bool hasSIMDExtendedStorage = true;
151};
152
153template <class ElementType, size_t size>
154struct StorageInfo<std::array<ElementType, size>>
155{
156 constexpr StorageInfo init (const void*, size_t) { return *this; }
157
158 static constexpr size_t memberAlignment = Config::alignedArray ? Config::maxSIMDRegisterSize : alignof (std::array<ElementType, size>);
159
161 static constexpr bool dataIsSIMDAligned = Config::alignedArray;
162
163 static constexpr bool hasSIMDExtendedStorage = (size * sizeof (ElementType)) % Config::maxSIMDRegisterSize == 0;
164};
165
166template <class Allocator>
167struct StorageInfo<detail::VectorBoolWorkaround<Allocator>>
168{
169 constexpr StorageInfo init (const void*, size_t) { return *this; }
170
171 static constexpr size_t memberAlignment = alignof (detail::VectorBoolWorkaround<Allocator>);
172
173 static constexpr bool dataIsSIMDAligned = false;
174
175 static constexpr bool hasSIMDExtendedStorage = false;
176};
177
181template <bool isDataSIMDAligned, bool isStorageSIMDExtended, size_t customMemberAlignment>
183{
184 static constexpr bool dataIsSIMDAligned = isDataSIMDAligned;
185 static constexpr bool hasSIMDExtendedStorage = isStorageSIMDExtended;
186 static constexpr size_t memberAlignment = customMemberAlignment;
187};
188
195template <size_t alignment, class WrappedInfo>
197{
198 constexpr StorageInfoWithMemberAlignment() = default;
199
200 constexpr StorageInfoWithMemberAlignment (const WrappedInfo& i) : WrappedInfo (i) {}
201
202 static constexpr size_t memberAlignment = alignment;
203};
204
205namespace detail
206{
207
208template <bool, bool>
209struct ConstexprStorageInfoChecker
210{
211};
212} // namespace detail
213
214namespace is
215{
216template <class T>
217concept constexprStorageInfo = requires (const T&) { detail::ConstexprStorageInfoChecker<T::dataIsSIMDAligned, T::hasSIMDExtendedStorage>(); };
218}
219
220template <class First, class... Others>
222{
223 CombinedStorageInfo (const First& first, const Others&... others)
224 : dataIsSIMDAligned (first.dataIsSIMDAligned && (others.dataIsSIMDAligned && ...)),
225 hasSIMDExtendedStorage (first.hasSIMDExtendedStorage && (others.hasSIMDExtendedStorage && ...))
226 {}
227
228 bool dataIsSIMDAligned;
229
230 bool hasSIMDExtendedStorage;
231};
232
233template <is::constexprStorageInfo First, is::constexprStorageInfo... Others>
234struct CombinedStorageInfo<First, Others...>
235{
236 constexpr CombinedStorageInfo (const First&, const Others&...) {}
237
238 static constexpr bool dataIsSIMDAligned = First::dataIsSIMDAligned && (Others::dataIsSIMDAligned && ...);
239
240 static constexpr bool hasSIMDExtendedStorage = First::hasSIMDExtendedStorage && (Others::hasSIMDExtendedStorage && ...);
241};
242
243} // namespace vctr
Definition: SIMDHelpers.h:217
The main namespace of the VCTR project.
Definition: Array.h:24
constexpr bool isPtrAligned(const void *ptr)
Helper function to check if a pointer is aligned to the required alignment value.
Definition: SIMDHelpers.h:81
CompareOp
Possible types of (SIMD) compare operations.
Definition: SIMDHelpers.h:63
Definition: SIMDHelpers.h:222
A storage info type especially used to pass compile time constant traits when viewing externally owne...
Definition: SIMDHelpers.h:183
A storage info type especially used for vctr::Span.
Definition: SIMDHelpers.h:197
A helper class to describe some properties regarding the storage class wrapped in a VctrBase instance...
Definition: SIMDHelpers.h:107