KleidiCV Coverage Report


Directory: ./
File: kleidicv/include/kleidicv/utils.h
Date: 2026-01-20 20:58:59
Exec Total Coverage
Lines: 135 135 100.0%
Functions: 3018 3132 96.4%
Branches: 657 670 98.1%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2023 - 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 #ifndef KLEIDICV_UTILS_H
6 #define KLEIDICV_UTILS_H
7
8 #include <algorithm>
9 #include <limits>
10 #include <type_traits>
11
12 #include "kleidicv/config.h"
13 #include "kleidicv/ctypes.h"
14 #include "kleidicv/kleidicv.h"
15 #include "kleidicv/traits.h"
16
17 namespace KLEIDICV_TARGET_NAMESPACE {
18
19 // Saturating cast from signed to unsigned type.
20 template <typename S, typename U,
21 std::enable_if_t<std::numeric_limits<S>::is_signed, bool> = true,
22 std::enable_if_t<not std::numeric_limits<U>::is_signed, bool> = true>
23 482424 static U saturating_cast(S value) KLEIDICV_STREAMING {
24
2/2
✓ Branch 0 taken 88258 times.
✓ Branch 1 taken 394166 times.
482424 if (value > std::numeric_limits<U>::max()) {
25 88258 return std::numeric_limits<U>::max();
26 }
27
2/2
✓ Branch 0 taken 311991 times.
✓ Branch 1 taken 82175 times.
394166 if (value < 0) {
28 82175 return 0;
29 }
30
31 311991 return static_cast<U>(value);
32 482424 }
33
34 // Saturating cast from unsigned to unsigned type.
35 template <
36 typename SrcType, typename DstType,
37 std::enable_if_t<std::is_unsigned_v<DstType> && std::is_unsigned_v<SrcType>,
38 bool> = true>
39 1292 static DstType saturating_cast(SrcType value) KLEIDICV_STREAMING {
40 1292 return static_cast<DstType>(value);
41 }
42
43 // Saturating cast from unsigned to signed type.
44 template <
45 typename SrcType, typename DstType,
46 std::enable_if_t<std::is_signed_v<DstType> && std::is_unsigned_v<SrcType>,
47 bool> = true>
48 1626 static DstType saturating_cast(SrcType value) KLEIDICV_STREAMING {
49 1626 DstType max_value = std::numeric_limits<DstType>::max();
50
51
6/6
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 880 times.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 329 times.
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 143 times.
1626 if (value > static_cast<SrcType>(max_value)) {
52 274 return max_value;
53 }
54
55 1352 return static_cast<DstType>(value);
56 1626 }
57
58 // Rounding shift right.
59 template <typename T>
60 396118 static T rounding_shift_right(T value, size_t shift) KLEIDICV_STREAMING {
61 396118 return (value + (T{1} << (shift - 1))) >> shift;
62 }
63
64 // When placed in a loop, it effectively disables loop vectorization.
65 723838 static inline void disable_loop_vectorization() KLEIDICV_STREAMING {
66 723838 __asm__("");
67 723838 }
68
69 // Helper class to unroll a loop as needed.
70 class LoopUnroll final {
71 public:
72 62574 explicit LoopUnroll(size_t length, size_t step) KLEIDICV_STREAMING
73 62574 : length_(length),
74 62574 step_(step),
75 62574 index_(0),
76 62574 can_avoid_tail_(length >= step) {}
77
78 // Loop unrolled four times.
79 template <typename CallbackType>
80 LoopUnroll &unroll_four_times(CallbackType callback) KLEIDICV_STREAMING {
81 return unroll_n_times<4>(callback);
82 }
83
84 // Loop unrolled twice.
85 template <typename CallbackType>
86 37014 LoopUnroll &unroll_twice(CallbackType callback) KLEIDICV_STREAMING {
87 37014 return unroll_n_times<2>(callback);
88 }
89
90 // Unrolls the loop twice, if enabled.
91 template <bool Enable, typename CallbackType>
92 35226 LoopUnroll &unroll_twice_if([[maybe_unused]] CallbackType callback)
93 KLEIDICV_STREAMING {
94 if constexpr (Enable) {
95 35226 return unroll_twice(callback);
96 }
97
98 return *this;
99 }
100
101 // Loop unrolled once.
102 template <typename CallbackType>
103 15991 LoopUnroll &unroll_once(CallbackType callback) KLEIDICV_STREAMING {
104 15991 return unroll_n_times<1>(callback);
105 }
106
107 // Unrolls the loop once, if enabled.
108 template <bool Enable, typename CallbackType>
109 4328 LoopUnroll &unroll_once_if([[maybe_unused]] CallbackType callback)
110 KLEIDICV_STREAMING {
111 if constexpr (Enable) {
112 4328 return unroll_once(callback);
113 }
114
115 return *this;
116 }
117
118 // Processes trailing data.
119 template <typename CallbackType>
120 7582 LoopUnroll &tail(CallbackType callback) KLEIDICV_STREAMING {
121
16/16
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 2072 times.
✓ Branch 5 taken 2637 times.
✓ Branch 6 taken 1000 times.
✓ Branch 7 taken 1415 times.
✓ Branch 8 taken 40 times.
✓ Branch 9 taken 58 times.
✓ Branch 10 taken 1499 times.
✓ Branch 11 taken 1965 times.
✓ Branch 12 taken 112 times.
✓ Branch 13 taken 178 times.
✓ Branch 14 taken 839 times.
✓ Branch 15 taken 1225 times.
13224 for (index_ = 0; index_ < remaining_length(); ++index_) {
122 5642 disable_loop_vectorization();
123 5642 callback(index_);
124 5642 }
125
126 7582 length_ = 0;
127 7582 return *this;
128 }
129
130 // Processes all remaining data at once.
131 template <typename CallbackType>
132 50474 LoopUnroll &remaining(CallbackType callback) KLEIDICV_STREAMING {
133
24/24
✓ Branch 0 taken 1894 times.
✓ Branch 1 taken 16634 times.
✓ Branch 2 taken 1164 times.
✓ Branch 3 taken 6533 times.
✓ Branch 4 taken 984 times.
✓ Branch 5 taken 5710 times.
✓ Branch 6 taken 1066 times.
✓ Branch 7 taken 5108 times.
✓ Branch 8 taken 770 times.
✓ Branch 9 taken 3379 times.
✓ Branch 10 taken 511 times.
✓ Branch 11 taken 2479 times.
✓ Branch 12 taken 470 times.
✓ Branch 13 taken 1172 times.
✓ Branch 14 taken 452 times.
✓ Branch 15 taken 980 times.
✓ Branch 16 taken 8 times.
✓ Branch 17 taken 376 times.
✓ Branch 18 taken 24 times.
✓ Branch 19 taken 120 times.
✓ Branch 20 taken 8 times.
✓ Branch 21 taken 248 times.
✓ Branch 22 taken 8 times.
✓ Branch 23 taken 376 times.
50474 if (length_) {
134 43115 callback(length_, step_);
135 43115 length_ = 0;
136 43115 }
137
138 50474 return *this;
139 }
140
141 // Returns true if there is nothing left to process.
142 bool empty() const KLEIDICV_STREAMING { return length_ == 0; }
143
144 // Returns the step value.
145 2928 size_t step() const KLEIDICV_STREAMING { return step_; }
146
147 // Returns the remaining length.
148 75277 size_t remaining_length() const KLEIDICV_STREAMING { return length_; }
149
150 // Returns true if it is possible to avoid the tail loop.
151 bool can_avoid_tail() const KLEIDICV_STREAMING { return can_avoid_tail_; }
152
153 // Instructs the loop logic to prepare to avoid the tail loop.
154 void avoid_tail() KLEIDICV_STREAMING { length_ = step(); }
155
156 template <const size_t UnrollFactor, typename CallbackType>
157 58753 LoopUnroll &unroll_n_times(CallbackType callback) KLEIDICV_STREAMING {
158 58753 const size_t step = UnrollFactor * step_;
159 // In practice step will never be zero and we don't want to spend
160 // instructions on checking that.
161 // NOLINTBEGIN(clang-analyzer-core.DivideZero)
162 58753 const size_t max_index = remaining_length() / step;
163 // NOLINTEND(clang-analyzer-core.DivideZero)
164
165
24/24
✓ Branch 0 taken 468419 times.
✓ Branch 1 taken 20994 times.
✓ Branch 2 taken 37531 times.
✓ Branch 3 taken 7215 times.
✓ Branch 4 taken 31048 times.
✓ Branch 5 taken 6857 times.
✓ Branch 6 taken 34386 times.
✓ Branch 7 taken 8540 times.
✓ Branch 8 taken 25440 times.
✓ Branch 9 taken 4152 times.
✓ Branch 10 taken 22564 times.
✓ Branch 11 taken 3623 times.
✓ Branch 12 taken 16136 times.
✓ Branch 13 taken 3547 times.
✓ Branch 14 taken 15599 times.
✓ Branch 15 taken 2657 times.
✓ Branch 16 taken 1040 times.
✓ Branch 17 taken 384 times.
✓ Branch 18 taken 400 times.
✓ Branch 19 taken 144 times.
✓ Branch 20 taken 720 times.
✓ Branch 21 taken 256 times.
✓ Branch 22 taken 1040 times.
✓ Branch 23 taken 384 times.
713076 for (index_ = 0; index_ < max_index; ++index_) {
166 654323 callback(step);
167 654323 }
168
169 // Adjust length to reflect the processed data.
170 58753 length_ -= step * index_;
171 58753 return *this;
172 58753 }
173
174 // Instructs the loop logic to avoid the tail loop.
175 template <typename CallbackType>
176 1666 bool try_avoid_tail_loop(CallbackType callback) KLEIDICV_STREAMING {
177
8/8
✓ Branch 0 taken 290 times.
✓ Branch 1 taken 242 times.
✓ Branch 2 taken 248 times.
✓ Branch 3 taken 130 times.
✓ Branch 4 taken 248 times.
✓ Branch 5 taken 130 times.
✓ Branch 6 taken 248 times.
✓ Branch 7 taken 130 times.
1666 if (KLEIDICV_UNLIKELY(!can_avoid_tail_)) {
178 1034 return false;
179 }
180
181
8/8
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 74 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 74 times.
✓ Branch 5 taken 56 times.
✓ Branch 6 taken 74 times.
✓ Branch 7 taken 56 times.
632 if (KLEIDICV_UNLIKELY(!remaining_length())) {
182 372 return false;
183 }
184
185 260 callback(step() - remaining_length());
186 260 length_ = step();
187 260 return true;
188 1666 }
189
190 private:
191 size_t length_;
192 size_t step_;
193 size_t index_;
194 bool can_avoid_tail_;
195 }; // end of class LoopUnroll
196
197 // This is the same as LoopUnroll, except that it passes indices to callbacks.
198 template <class Tail = UsesTailPath>
199 class LoopUnroll2 final {
200 public:
201 654612 explicit LoopUnroll2(size_t length, size_t step) KLEIDICV_STREAMING
202 654612 : length_(length),
203 654612 step_(step),
204 654612 index_(0) {}
205
206 384 explicit LoopUnroll2(size_t start_index, size_t length,
207 size_t step) KLEIDICV_STREAMING
208 384 : length_(length),
209 384 step_(step),
210 384 index_(std::min(start_index, length)) {}
211
212 // Loop unrolled four times.
213 template <typename CallbackType>
214 58852 LoopUnroll2 &unroll_four_times(CallbackType callback) KLEIDICV_STREAMING {
215 58852 return unroll_n_times<4>(callback);
216 }
217
218 // Loop unrolled twice.
219 template <typename CallbackType>
220 468584 KLEIDICV_FORCE_INLINE LoopUnroll2 &unroll_twice(CallbackType callback)
221 KLEIDICV_STREAMING {
222 468584 return unroll_n_times<2>(callback);
223 }
224
225 // Unrolls the loop twice, if enabled.
226 template <bool Enable, typename CallbackType>
227 LoopUnroll2 &unroll_twice_if(CallbackType callback) KLEIDICV_STREAMING {
228 if constexpr (Enable) {
229 return unroll_twice(callback);
230 }
231
232 return *this;
233 }
234
235 // Loop unrolled once.
236 template <typename CallbackType>
237 294405 KLEIDICV_FORCE_INLINE LoopUnroll2 &unroll_once(CallbackType callback)
238 KLEIDICV_STREAMING {
239 294405 return unroll_n_times<1>(callback);
240 }
241
242 // Unrolls the loop once, if enabled.
243 template <bool Enable, typename CallbackType>
244 LoopUnroll2 &unroll_once_if(CallbackType callback) KLEIDICV_STREAMING {
245 if constexpr (Enable) {
246 return unroll_once(callback);
247 }
248
249 return *this;
250 }
251
252 // Processes trailing data.
253 template <typename CallbackType>
254 71550 LoopUnroll2 &tail(CallbackType callback) KLEIDICV_STREAMING {
255
47/56
✓ Branch 0 taken 54059 times.
✓ Branch 1 taken 15842 times.
✓ Branch 2 taken 33736 times.
✓ Branch 3 taken 14506 times.
✓ Branch 4 taken 44474 times.
✓ Branch 5 taken 14074 times.
✓ Branch 6 taken 30133 times.
✓ Branch 7 taken 13236 times.
✓ Branch 8 taken 3445 times.
✓ Branch 9 taken 1388 times.
✓ Branch 10 taken 409 times.
✓ Branch 11 taken 922 times.
✓ Branch 12 taken 3220 times.
✓ Branch 13 taken 1274 times.
✓ Branch 14 taken 1496 times.
✓ Branch 15 taken 1204 times.
✓ Branch 16 taken 1408 times.
✓ Branch 17 taken 1162 times.
✓ Branch 18 taken 164 times.
✓ Branch 19 taken 86 times.
✓ Branch 20 taken 384 times.
✓ Branch 21 taken 856 times.
✓ Branch 22 taken 1332 times.
✓ Branch 23 taken 820 times.
✓ Branch 24 taken 540 times.
✓ Branch 25 taken 586 times.
✓ Branch 26 taken 572 times.
✓ Branch 27 taken 154 times.
✓ Branch 28 taken 480 times.
✓ Branch 29 taken 924 times.
✓ Branch 30 taken 816 times.
✓ Branch 31 taken 748 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 64 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 32 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 308 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 416 times.
✗ Branch 40 not taken.
✓ Branch 41 taken 64 times.
✗ Branch 42 not taken.
✓ Branch 43 taken 32 times.
✗ Branch 44 not taken.
✓ Branch 45 taken 308 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 416 times.
✓ Branch 48 taken 168 times.
✓ Branch 49 taken 514 times.
✓ Branch 50 taken 4 times.
✓ Branch 51 taken 48 times.
✓ Branch 52 taken 272 times.
✓ Branch 53 taken 818 times.
✗ Branch 54 not taken.
✓ Branch 55 taken 748 times.
248662 while (index_ < length_) {
256 177112 disable_loop_vectorization();
257 177112 callback(index_++);
258 }
259
260 71550 return *this;
261 }
262
263 // Processes all remaining data at once.
264 template <typename CallbackType>
265 539298 LoopUnroll2 &remaining(CallbackType callback) KLEIDICV_STREAMING {
266
64/64
✓ Branch 0 taken 651 times.
✓ Branch 1 taken 74562 times.
✓ Branch 2 taken 7818 times.
✓ Branch 3 taken 68205 times.
✓ Branch 4 taken 970 times.
✓ Branch 5 taken 64038 times.
✓ Branch 6 taken 10592 times.
✓ Branch 7 taken 70464 times.
✓ Branch 8 taken 947 times.
✓ Branch 9 taken 17269 times.
✓ Branch 10 taken 11123 times.
✓ Branch 11 taken 15411 times.
✓ Branch 12 taken 1130 times.
✓ Branch 13 taken 7578 times.
✓ Branch 14 taken 21272 times.
✓ Branch 15 taken 11508 times.
✓ Branch 16 taken 1920 times.
✓ Branch 17 taken 11426 times.
✓ Branch 18 taken 804 times.
✓ Branch 19 taken 10870 times.
✓ Branch 20 taken 1464 times.
✓ Branch 21 taken 7058 times.
✓ Branch 22 taken 1500 times.
✓ Branch 23 taken 10580 times.
✓ Branch 24 taken 2476 times.
✓ Branch 25 taken 12900 times.
✓ Branch 26 taken 1132 times.
✓ Branch 27 taken 9334 times.
✓ Branch 28 taken 2116 times.
✓ Branch 29 taken 8744 times.
✓ Branch 30 taken 2308 times.
✓ Branch 31 taken 10496 times.
✓ Branch 32 taken 104 times.
✓ Branch 33 taken 2384 times.
✓ Branch 34 taken 52 times.
✓ Branch 35 taken 6940 times.
✓ Branch 36 taken 478 times.
✓ Branch 37 taken 2742 times.
✓ Branch 38 taken 676 times.
✓ Branch 39 taken 7468 times.
✓ Branch 40 taken 104 times.
✓ Branch 41 taken 2384 times.
✓ Branch 42 taken 52 times.
✓ Branch 43 taken 6940 times.
✓ Branch 44 taken 478 times.
✓ Branch 45 taken 2742 times.
✓ Branch 46 taken 676 times.
✓ Branch 47 taken 7468 times.
✓ Branch 48 taken 896 times.
✓ Branch 49 taken 784 times.
✓ Branch 50 taken 176 times.
✓ Branch 51 taken 114 times.
✓ Branch 52 taken 1310 times.
✓ Branch 53 taken 1282 times.
✓ Branch 54 taken 1178 times.
✓ Branch 55 taken 1212 times.
✓ Branch 56 taken 866 times.
✓ Branch 57 taken 2128 times.
✓ Branch 58 taken 866 times.
✓ Branch 59 taken 2136 times.
✓ Branch 60 taken 866 times.
✓ Branch 61 taken 2128 times.
✓ Branch 62 taken 866 times.
✓ Branch 63 taken 2136 times.
539298 if (remaining_length()) {
267 461431 callback(index_, length_);
268 461431 index_ = length_;
269 461431 }
270
271 539298 return *this;
272 }
273
274 // Returns true if there is nothing left to process.
275 bool empty() const KLEIDICV_STREAMING { return length_ == index_; }
276
277 // Returns the step value.
278 821841 size_t step() const KLEIDICV_STREAMING { return step_; }
279
280 // Returns the remaining length.
281 1513811 size_t remaining_length() const KLEIDICV_STREAMING {
282 1513811 return length_ - index_;
283 }
284
285 private:
286 template <const size_t UnrollFactor, typename CallbackType>
287 821841 KLEIDICV_FORCE_INLINE LoopUnroll2 &unroll_n_times(CallbackType callback)
288 KLEIDICV_STREAMING {
289 821841 const size_t n_step = UnrollFactor * step();
290 821841 size_t max_index = index_ + (remaining_length() / n_step) * n_step;
291
292 // A tail mechanism is built into the single vector processing loop, if
293 // enabled. The single vector path is executed iteratively, and at the end
294 // it rewinds the loop to one vector before the end of the data, and
295 // executes one final vector path, so the scalar path can be omitted.
296 if constexpr (try_to_avoid_tail_loop<Tail> && (UnrollFactor == 1)) {
297 // Enter this loop only if there's enough data for a full vector
298
60/64
✓ Branch 0 taken 3540 times.
✓ Branch 1 taken 1890 times.
✓ Branch 2 taken 2271 times.
✓ Branch 3 taken 4243 times.
✓ Branch 4 taken 3299 times.
✓ Branch 5 taken 1795 times.
✓ Branch 6 taken 2581 times.
✓ Branch 7 taken 6597 times.
✓ Branch 8 taken 915 times.
✓ Branch 9 taken 777 times.
✓ Branch 10 taken 525 times.
✓ Branch 11 taken 10501 times.
✓ Branch 12 taken 748 times.
✓ Branch 13 taken 788 times.
✓ Branch 14 taken 824 times.
✓ Branch 15 taken 20324 times.
✓ Branch 16 taken 386 times.
✓ Branch 17 taken 5988 times.
✓ Branch 18 taken 508 times.
✓ Branch 19 taken 454 times.
✓ Branch 20 taken 490 times.
✓ Branch 21 taken 1644 times.
✓ Branch 22 taken 502 times.
✓ Branch 23 taken 550 times.
✓ Branch 24 taken 442 times.
✓ Branch 25 taken 11450 times.
✓ Branch 26 taken 76 times.
✓ Branch 27 taken 3166 times.
✓ Branch 28 taken 518 times.
✓ Branch 29 taken 6154 times.
✓ Branch 30 taken 554 times.
✓ Branch 31 taken 3422 times.
✓ Branch 32 taken 32 times.
✓ Branch 33 taken 40 times.
✓ Branch 34 taken 16 times.
✓ Branch 35 taken 24 times.
✓ Branch 36 taken 144 times.
✓ Branch 37 taken 172 times.
✓ Branch 38 taken 208 times.
✓ Branch 39 taken 216 times.
✓ Branch 40 taken 32 times.
✓ Branch 41 taken 40 times.
✓ Branch 42 taken 16 times.
✓ Branch 43 taken 24 times.
✓ Branch 44 taken 144 times.
✓ Branch 45 taken 172 times.
✓ Branch 46 taken 208 times.
✓ Branch 47 taken 216 times.
✓ Branch 48 taken 318 times.
✓ Branch 49 taken 334 times.
✓ Branch 50 taken 20 times.
✓ Branch 51 taken 174 times.
✓ Branch 52 taken 450 times.
✓ Branch 53 taken 506 times.
✓ Branch 54 taken 336 times.
✓ Branch 55 taken 558 times.
✗ Branch 56 not taken.
✓ Branch 57 taken 2994 times.
✗ Branch 58 not taken.
✓ Branch 59 taken 3002 times.
✗ Branch 60 not taken.
✓ Branch 61 taken 2994 times.
✗ Branch 62 not taken.
✓ Branch 63 taken 3002 times.
114314 if (length_ >= n_step) {
299 // External loop only ends when all data has been processed
300
64/64
✓ Branch 0 taken 3708 times.
✓ Branch 1 taken 1890 times.
✓ Branch 2 taken 6978 times.
✓ Branch 3 taken 4243 times.
✓ Branch 4 taken 3450 times.
✓ Branch 5 taken 1795 times.
✓ Branch 6 taken 10022 times.
✓ Branch 7 taken 6597 times.
✓ Branch 8 taken 1425 times.
✓ Branch 9 taken 777 times.
✓ Branch 10 taken 15493 times.
✓ Branch 11 taken 10501 times.
✓ Branch 12 taken 1536 times.
✓ Branch 13 taken 788 times.
✓ Branch 14 taken 30396 times.
✓ Branch 15 taken 20324 times.
✓ Branch 16 taken 10766 times.
✓ Branch 17 taken 5988 times.
✓ Branch 18 taken 510 times.
✓ Branch 19 taken 454 times.
✓ Branch 20 taken 2806 times.
✓ Branch 21 taken 1644 times.
✓ Branch 22 taken 854 times.
✓ Branch 23 taken 550 times.
✓ Branch 24 taken 20714 times.
✓ Branch 25 taken 11450 times.
✓ Branch 26 taken 4718 times.
✓ Branch 27 taken 3166 times.
✓ Branch 28 taken 10900 times.
✓ Branch 29 taken 6154 times.
✓ Branch 30 taken 5222 times.
✓ Branch 31 taken 3422 times.
✓ Branch 32 taken 72 times.
✓ Branch 33 taken 40 times.
✓ Branch 34 taken 44 times.
✓ Branch 35 taken 24 times.
✓ Branch 36 taken 298 times.
✓ Branch 37 taken 172 times.
✓ Branch 38 taken 380 times.
✓ Branch 39 taken 216 times.
✓ Branch 40 taken 72 times.
✓ Branch 41 taken 40 times.
✓ Branch 42 taken 44 times.
✓ Branch 43 taken 24 times.
✓ Branch 44 taken 298 times.
✓ Branch 45 taken 172 times.
✓ Branch 46 taken 380 times.
✓ Branch 47 taken 216 times.
✓ Branch 48 taken 474 times.
✓ Branch 49 taken 334 times.
✓ Branch 50 taken 226 times.
✓ Branch 51 taken 174 times.
✓ Branch 52 taken 644 times.
✓ Branch 53 taken 506 times.
✓ Branch 54 taken 946 times.
✓ Branch 55 taken 558 times.
✓ Branch 56 taken 4510 times.
✓ Branch 57 taken 2994 times.
✓ Branch 58 taken 5138 times.
✓ Branch 59 taken 3002 times.
✓ Branch 60 taken 4510 times.
✓ Branch 61 taken 2994 times.
✓ Branch 62 taken 5138 times.
✓ Branch 63 taken 3002 times.
246883 while (index_ < length_) {
301 // Internal loop checks if the vector path can be executed
302
64/64
✓ Branch 0 taken 7764 times.
✓ Branch 1 taken 3708 times.
✓ Branch 2 taken 59100 times.
✓ Branch 3 taken 6978 times.
✓ Branch 4 taken 9249 times.
✓ Branch 5 taken 3450 times.
✓ Branch 6 taken 221736 times.
✓ Branch 7 taken 10022 times.
✓ Branch 8 taken 11633 times.
✓ Branch 9 taken 1425 times.
✓ Branch 10 taken 871013 times.
✓ Branch 11 taken 15493 times.
✓ Branch 12 taken 21824 times.
✓ Branch 13 taken 1536 times.
✓ Branch 14 taken 3476828 times.
✓ Branch 15 taken 30396 times.
✓ Branch 16 taken 199888 times.
✓ Branch 17 taken 10766 times.
✓ Branch 18 taken 1394 times.
✓ Branch 19 taken 510 times.
✓ Branch 20 taken 95058 times.
✓ Branch 21 taken 2806 times.
✓ Branch 22 taken 2778 times.
✓ Branch 23 taken 854 times.
✓ Branch 24 taken 24830 times.
✓ Branch 25 taken 20714 times.
✓ Branch 26 taken 4546 times.
✓ Branch 27 taken 4718 times.
✓ Branch 28 taken 12716 times.
✓ Branch 29 taken 10900 times.
✓ Branch 30 taken 6090 times.
✓ Branch 31 taken 5222 times.
✓ Branch 32 taken 592 times.
✓ Branch 33 taken 72 times.
✓ Branch 34 taken 356 times.
✓ Branch 35 taken 44 times.
✓ Branch 36 taken 2144 times.
✓ Branch 37 taken 298 times.
✓ Branch 38 taken 2668 times.
✓ Branch 39 taken 380 times.
✓ Branch 40 taken 488 times.
✓ Branch 41 taken 72 times.
✓ Branch 42 taken 356 times.
✓ Branch 43 taken 44 times.
✓ Branch 44 taken 2040 times.
✓ Branch 45 taken 298 times.
✓ Branch 46 taken 2668 times.
✓ Branch 47 taken 380 times.
✓ Branch 48 taken 1470 times.
✓ Branch 49 taken 474 times.
✓ Branch 50 taken 838 times.
✓ Branch 51 taken 226 times.
✓ Branch 52 taken 3326 times.
✓ Branch 53 taken 644 times.
✓ Branch 54 taken 3970 times.
✓ Branch 55 taken 946 times.
✓ Branch 56 taken 4238 times.
✓ Branch 57 taken 4510 times.
✓ Branch 58 taken 8290 times.
✓ Branch 59 taken 5138 times.
✓ Branch 60 taken 4238 times.
✓ Branch 61 taken 4510 times.
✓ Branch 62 taken 8290 times.
✓ Branch 63 taken 5138 times.
5225091 while (index_ < max_index) {
303 5072419 callback(index_);
304 5072419 index_ += n_step;
305 }
306 // Check if a final iteration is needed. The double loop is needed to
307 // avoid the repetition of the callback function, which is usually
308 // inlined into the binary. (Save some code space)
309
64/64
✓ Branch 0 taken 1882 times.
✓ Branch 1 taken 1826 times.
✓ Branch 2 taken 4227 times.
✓ Branch 3 taken 2751 times.
✓ Branch 4 taken 1795 times.
✓ Branch 5 taken 1655 times.
✓ Branch 6 taken 6413 times.
✓ Branch 7 taken 3609 times.
✓ Branch 8 taken 777 times.
✓ Branch 9 taken 648 times.
✓ Branch 10 taken 10333 times.
✓ Branch 11 taken 5160 times.
✓ Branch 12 taken 788 times.
✓ Branch 13 taken 748 times.
✓ Branch 14 taken 20324 times.
✓ Branch 15 taken 10072 times.
✓ Branch 16 taken 5988 times.
✓ Branch 17 taken 4778 times.
✓ Branch 18 taken 454 times.
✓ Branch 19 taken 56 times.
✓ Branch 20 taken 1644 times.
✓ Branch 21 taken 1162 times.
✓ Branch 22 taken 550 times.
✓ Branch 23 taken 304 times.
✓ Branch 24 taken 11030 times.
✓ Branch 25 taken 9684 times.
✓ Branch 26 taken 2554 times.
✓ Branch 27 taken 2164 times.
✓ Branch 28 taken 5880 times.
✓ Branch 29 taken 5020 times.
✓ Branch 30 taken 2810 times.
✓ Branch 31 taken 2412 times.
✓ Branch 32 taken 40 times.
✓ Branch 33 taken 32 times.
✓ Branch 34 taken 24 times.
✓ Branch 35 taken 20 times.
✓ Branch 36 taken 172 times.
✓ Branch 37 taken 126 times.
✓ Branch 38 taken 216 times.
✓ Branch 39 taken 164 times.
✓ Branch 40 taken 40 times.
✓ Branch 41 taken 32 times.
✓ Branch 42 taken 24 times.
✓ Branch 43 taken 20 times.
✓ Branch 44 taken 172 times.
✓ Branch 45 taken 126 times.
✓ Branch 46 taken 216 times.
✓ Branch 47 taken 164 times.
✓ Branch 48 taken 334 times.
✓ Branch 49 taken 140 times.
✓ Branch 50 taken 174 times.
✓ Branch 51 taken 52 times.
✓ Branch 52 taken 506 times.
✓ Branch 53 taken 138 times.
✓ Branch 54 taken 558 times.
✓ Branch 55 taken 388 times.
✓ Branch 56 taken 2382 times.
✓ Branch 57 taken 2128 times.
✓ Branch 58 taken 3002 times.
✓ Branch 59 taken 2136 times.
✓ Branch 60 taken 2382 times.
✓ Branch 61 taken 2128 times.
✓ Branch 62 taken 3002 times.
✓ Branch 63 taken 2136 times.
152672 if (remaining_length()) {
310 61979 index_ = length_ - n_step;
311 61979 max_index = length_;
312 61979 }
313 }
314 94211 }
315 } else {
316
112/112
✓ Branch 0 taken 11744 times.
✓ Branch 1 taken 90932 times.
✓ Branch 2 taken 12095 times.
✓ Branch 3 taken 92817 times.
✓ Branch 4 taken 10452 times.
✓ Branch 5 taken 75815 times.
✓ Branch 6 taken 11632 times.
✓ Branch 7 taken 88187 times.
✓ Branch 8 taken 52193 times.
✓ Branch 9 taken 52571 times.
✓ Branch 10 taken 4525 times.
✓ Branch 11 taken 43209 times.
✓ Branch 12 taken 26951 times.
✓ Branch 13 taken 27388 times.
✓ Branch 14 taken 4580 times.
✓ Branch 15 taken 29224 times.
✓ Branch 16 taken 1149 times.
✓ Branch 17 taken 8960 times.
✓ Branch 18 taken 1864 times.
✓ Branch 19 taken 10942 times.
✓ Branch 20 taken 4252 times.
✓ Branch 21 taken 11448 times.
✓ Branch 22 taken 4438 times.
✓ Branch 23 taken 15838 times.
✓ Branch 24 taken 3206 times.
✓ Branch 25 taken 5824 times.
✓ Branch 26 taken 770 times.
✓ Branch 27 taken 9026 times.
✓ Branch 28 taken 2318 times.
✓ Branch 29 taken 6694 times.
✓ Branch 30 taken 2096 times.
✓ Branch 31 taken 9254 times.
✓ Branch 32 taken 46126 times.
✓ Branch 33 taken 7806 times.
✓ Branch 34 taken 11646 times.
✓ Branch 35 taken 12310 times.
✓ Branch 36 taken 3254 times.
✓ Branch 37 taken 3694 times.
✓ Branch 38 taken 3794 times.
✓ Branch 39 taken 8618 times.
✓ Branch 40 taken 23124 times.
✓ Branch 41 taken 3974 times.
✓ Branch 42 taken 3450 times.
✓ Branch 43 taken 8580 times.
✓ Branch 44 taken 3182 times.
✓ Branch 45 taken 3796 times.
✓ Branch 46 taken 3818 times.
✓ Branch 47 taken 8720 times.
✓ Branch 48 taken 50532 times.
✓ Branch 49 taken 12848 times.
✓ Branch 50 taken 15086 times.
✓ Branch 51 taken 11450 times.
✓ Branch 52 taken 6102 times.
✓ Branch 53 taken 5576 times.
✓ Branch 54 taken 6622 times.
✓ Branch 55 taken 5366 times.
✓ Branch 56 taken 24612 times.
✓ Branch 57 taken 5748 times.
✓ Branch 58 taken 6298 times.
✓ Branch 59 taken 5748 times.
✓ Branch 60 taken 2228 times.
✓ Branch 61 taken 3122 times.
✓ Branch 62 taken 2238 times.
✓ Branch 63 taken 3122 times.
✓ Branch 64 taken 52 times.
✓ Branch 65 taken 8 times.
✓ Branch 66 taken 8 times.
✓ Branch 67 taken 8 times.
✓ Branch 68 taken 112 times.
✓ Branch 69 taken 8 times.
✓ Branch 70 taken 52 times.
✓ Branch 71 taken 8 times.
✓ Branch 72 taken 8 times.
✓ Branch 73 taken 8 times.
✓ Branch 74 taken 112 times.
✓ Branch 75 taken 8 times.
✓ Branch 76 taken 52 times.
✓ Branch 77 taken 8 times.
✓ Branch 78 taken 8 times.
✓ Branch 79 taken 8 times.
✓ Branch 80 taken 112 times.
✓ Branch 81 taken 8 times.
✓ Branch 82 taken 52 times.
✓ Branch 83 taken 8 times.
✓ Branch 84 taken 8 times.
✓ Branch 85 taken 8 times.
✓ Branch 86 taken 112 times.
✓ Branch 87 taken 8 times.
✓ Branch 88 taken 130 times.
✓ Branch 89 taken 138 times.
✓ Branch 90 taken 138 times.
✓ Branch 91 taken 138 times.
✓ Branch 92 taken 510 times.
✓ Branch 93 taken 146 times.
✓ Branch 94 taken 130 times.
✓ Branch 95 taken 138 times.
✓ Branch 96 taken 138 times.
✓ Branch 97 taken 138 times.
✓ Branch 98 taken 510 times.
✓ Branch 99 taken 146 times.
✓ Branch 100 taken 1966 times.
✓ Branch 101 taken 2994 times.
✓ Branch 102 taken 2110 times.
✓ Branch 103 taken 2994 times.
✓ Branch 104 taken 6154 times.
✓ Branch 105 taken 3002 times.
✓ Branch 106 taken 1966 times.
✓ Branch 107 taken 2994 times.
✓ Branch 108 taken 2110 times.
✓ Branch 109 taken 2994 times.
✓ Branch 110 taken 6154 times.
✓ Branch 111 taken 3002 times.
1096608 while (index_ < max_index) {
317 389081 callback(index_);
318 389081 index_ += n_step;
319 }
320 }
321
322 821841 return *this;
323 821841 }
324
325 size_t length_;
326 size_t step_;
327 size_t index_;
328 }; // end of class LoopUnroll2
329
330 // Check whether any of the arguments are null pointers.
331 template <typename... Pointers>
332 14160 bool any_null(Pointers... pointers) KLEIDICV_STREAMING {
333
12/12
✓ Branch 0 taken 336 times.
✓ Branch 1 taken 2724 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 300 times.
✓ Branch 4 taken 304 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 300 times.
✓ Branch 8 taken 300 times.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 296 times.
14160 return (... || (pointers == nullptr));
334 }
335
336 #define CHECK_POINTERS(...) \
337 do { \
338 if (KLEIDICV_TARGET_NAMESPACE::any_null(__VA_ARGS__)) { \
339 return KLEIDICV_ERROR_NULL_POINTER; \
340 } \
341 } while (false)
342
343 template <typename AlignType, typename Value>
344 78424 bool is_misaligned(Value v) KLEIDICV_STREAMING {
345 78424 constexpr size_t kMask = alignof(AlignType) - 1;
346 static_assert(kMask == 0b0001 || kMask == 0b0011 || kMask == 0b0111 ||
347 kMask == 0b1111);
348 156848 return (v & kMask) != 0;
349 78424 }
350
351 // Return value aligned up to the next multiple of alignment
352 // Assumes alignment is a power of two.
353 template <typename T>
354 14933 T align_up(T value, size_t alignment) KLEIDICV_STREAMING {
355 14933 return (value + alignment - 1) & ~(alignment - 1);
356 }
357
358 template <typename T>
359 6236 T *align_up(T *value, size_t alignment) KLEIDICV_STREAMING {
360 // NOLINTBEGIN(performance-no-int-to-ptr)
361 6236 return reinterpret_cast<T *>(
362 6236 align_up(reinterpret_cast<uintptr_t>(value), alignment));
363 // NOLINTEND(performance-no-int-to-ptr)
364 }
365
366 // Specialisation for when stride misalignment is possible.
367 template <typename T>
368 78201 std::enable_if_t<alignof(T) != 1, kleidicv_error_t> check_pointer_and_stride(
369 T *pointer, size_t stride, size_t height) KLEIDICV_STREAMING {
370
24/24
✓ Branch 0 taken 23184 times.
✓ Branch 1 taken 305 times.
✓ Branch 2 taken 15315 times.
✓ Branch 3 taken 241 times.
✓ Branch 4 taken 11560 times.
✓ Branch 5 taken 228 times.
✓ Branch 6 taken 5588 times.
✓ Branch 7 taken 192 times.
✓ Branch 8 taken 5940 times.
✓ Branch 9 taken 84 times.
✓ Branch 10 taken 4112 times.
✓ Branch 11 taken 68 times.
✓ Branch 12 taken 2400 times.
✓ Branch 13 taken 20 times.
✓ Branch 14 taken 1596 times.
✓ Branch 15 taken 12 times.
✓ Branch 16 taken 2900 times.
✓ Branch 17 taken 20 times.
✓ Branch 18 taken 2096 times.
✓ Branch 19 taken 12 times.
✓ Branch 20 taken 1552 times.
✓ Branch 21 taken 16 times.
✓ Branch 22 taken 752 times.
✓ Branch 23 taken 8 times.
78201 if (pointer == nullptr) {
371 1206 return KLEIDICV_ERROR_NULL_POINTER;
372 }
373
48/48
✓ Branch 0 taken 20019 times.
✓ Branch 1 taken 3165 times.
✓ Branch 2 taken 19879 times.
✓ Branch 3 taken 140 times.
✓ Branch 4 taken 13629 times.
✓ Branch 5 taken 1686 times.
✓ Branch 6 taken 13533 times.
✓ Branch 7 taken 96 times.
✓ Branch 8 taken 10232 times.
✓ Branch 9 taken 1328 times.
✓ Branch 10 taken 10136 times.
✓ Branch 11 taken 96 times.
✓ Branch 12 taken 5128 times.
✓ Branch 13 taken 460 times.
✓ Branch 14 taken 5052 times.
✓ Branch 15 taken 76 times.
✓ Branch 16 taken 5304 times.
✓ Branch 17 taken 636 times.
✓ Branch 18 taken 5216 times.
✓ Branch 19 taken 88 times.
✓ Branch 20 taken 3752 times.
✓ Branch 21 taken 360 times.
✓ Branch 22 taken 3680 times.
✓ Branch 23 taken 72 times.
✓ Branch 24 taken 2200 times.
✓ Branch 25 taken 200 times.
✓ Branch 26 taken 2184 times.
✓ Branch 27 taken 16 times.
✓ Branch 28 taken 1508 times.
✓ Branch 29 taken 88 times.
✓ Branch 30 taken 1500 times.
✓ Branch 31 taken 8 times.
✓ Branch 32 taken 2660 times.
✓ Branch 33 taken 240 times.
✓ Branch 34 taken 2644 times.
✓ Branch 35 taken 16 times.
✓ Branch 36 taken 1968 times.
✓ Branch 37 taken 128 times.
✓ Branch 38 taken 1960 times.
✓ Branch 39 taken 8 times.
✓ Branch 40 taken 1352 times.
✓ Branch 41 taken 200 times.
✓ Branch 42 taken 1336 times.
✓ Branch 43 taken 16 times.
✓ Branch 44 taken 664 times.
✓ Branch 45 taken 88 times.
✓ Branch 46 taken 656 times.
✓ Branch 47 taken 8 times.
76995 if (height > 1 && is_misaligned<T>(stride)) {
374 640 return KLEIDICV_ERROR_ALIGNMENT;
375 }
376 76355 return KLEIDICV_OK;
377 78201 }
378
379 // Specialisation for when stride misalignment is impossible.
380 template <typename T>
381 100549 std::enable_if_t<alignof(T) == 1, kleidicv_error_t> check_pointer_and_stride(
382 T *pointer, size_t /*stride*/, size_t /*height*/) KLEIDICV_STREAMING {
383
8/8
✓ Branch 0 taken 47949 times.
✓ Branch 1 taken 1117 times.
✓ Branch 2 taken 42424 times.
✓ Branch 3 taken 833 times.
✓ Branch 4 taken 4819 times.
✓ Branch 5 taken 40 times.
✓ Branch 6 taken 3343 times.
✓ Branch 7 taken 24 times.
100549 if (pointer == nullptr) {
384 2014 return KLEIDICV_ERROR_NULL_POINTER;
385 }
386 98535 return KLEIDICV_OK;
387 100549 }
388
389 #define CHECK_POINTER_AND_STRIDE(pointer, stride, height) \
390 do { \
391 if (kleidicv_error_t ptr_stride_err = \
392 KLEIDICV_TARGET_NAMESPACE::check_pointer_and_stride( \
393 pointer, stride, height)) { \
394 return ptr_stride_err; \
395 } \
396 } while (false)
397
398 #define MAKE_POINTER_CHECK_ALIGNMENT(ElementType, name, from) \
399 if constexpr (alignof(ElementType) > 1) { \
400 if (KLEIDICV_TARGET_NAMESPACE::is_misaligned<ElementType>( \
401 reinterpret_cast<uintptr_t>(from))) { \
402 return KLEIDICV_ERROR_ALIGNMENT; \
403 } \
404 } \
405 ElementType *name = reinterpret_cast<ElementType *>(from)
406
407 // Check whether the image size is acceptable by limiting it.
408 #define CHECK_IMAGE_SIZE(width, height) \
409 do { \
410 size_t image_size = 0; \
411 if (__builtin_mul_overflow(width, height, &image_size)) { \
412 return KLEIDICV_ERROR_RANGE; \
413 } \
414 \
415 if (image_size > KLEIDICV_MAX_IMAGE_PIXELS) { \
416 return KLEIDICV_ERROR_RANGE; \
417 } \
418 } while (false)
419
420 // Check whether the rectangle size is acceptable by limiting it.
421 #define CHECK_RECTANGLE_SIZE(rect) CHECK_IMAGE_SIZE(rect.width, rect.height)
422
423 } // namespace KLEIDICV_TARGET_NAMESPACE
424
425 #endif // KLEIDICV_UTILS_H
426