KleidiCV Coverage Report


Directory: ./
File: kleidicv/include/kleidicv/utils.h
Date: 2026-03-05 15:57:40
Exec Total Coverage
Lines: 135 135 100.0%
Functions: 3080 3195 96.4%
Branches: 652 662 98.5%

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 88017 times.
✓ Branch 1 taken 394407 times.
482424 if (value > std::numeric_limits<U>::max()) {
25 88017 return std::numeric_limits<U>::max();
26 }
27
2/2
✓ Branch 0 taken 307181 times.
✓ Branch 1 taken 87226 times.
394407 if (value < 0) {
28 87226 return 0;
29 }
30
31 307181 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 212 times.
✓ Branch 1 taken 850 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 321 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 140 times.
1626 if (value > static_cast<SrcType>(max_value)) {
52 315 return max_value;
53 }
54
55 1311 return static_cast<DstType>(value);
56 1626 }
57
58 // Rounding shift right.
59 template <typename T>
60 446800 static T rounding_shift_right(T value, size_t shift) KLEIDICV_STREAMING {
61 446800 return (value + (T{1} << (shift - 1))) >> shift;
62 }
63
64 // When placed in a loop, it effectively disables loop vectorization.
65 834542 static inline void disable_loop_vectorization() KLEIDICV_STREAMING {
66 834542 __asm__("");
67 834542 }
68
69 // Helper class to unroll a loop as needed.
70 class LoopUnroll final {
71 public:
72 62578 explicit LoopUnroll(size_t length, size_t step) KLEIDICV_STREAMING
73 62578 : length_(length),
74 62578 step_(step),
75 62578 index_(0),
76 62578 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 37018 LoopUnroll &unroll_twice(CallbackType callback) KLEIDICV_STREAMING {
87 37018 return unroll_n_times<2>(callback);
88 }
89
90 // Unrolls the loop twice, if enabled.
91 template <bool Enable, typename CallbackType>
92 35230 LoopUnroll &unroll_twice_if([[maybe_unused]] CallbackType callback)
93 KLEIDICV_STREAMING {
94 if constexpr (Enable) {
95 35230 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 50478 LoopUnroll &remaining(CallbackType callback) KLEIDICV_STREAMING {
133
24/24
✓ Branch 0 taken 1894 times.
✓ Branch 1 taken 16638 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.
50478 if (length_) {
134 43119 callback(length_, step_);
135 43119 length_ = 0;
136 43119 }
137
138 50478 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 75281 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 58757 LoopUnroll &unroll_n_times(CallbackType callback) KLEIDICV_STREAMING {
158 58757 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 58757 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 20998 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.
713080 for (index_ = 0; index_ < max_index; ++index_) {
166 654323 callback(step);
167 654323 }
168
169 // Adjust length to reflect the processed data.
170 58757 length_ -= step * index_;
171 58757 return *this;
172 58757 }
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 705384 explicit LoopUnroll2(size_t length, size_t step) KLEIDICV_STREAMING
202 705384 : length_(length),
203 705384 step_(step),
204 705384 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 58860 LoopUnroll2 &unroll_four_times(CallbackType callback) KLEIDICV_STREAMING {
215 58860 return unroll_n_times<4>(callback);
216 }
217
218 // Loop unrolled twice.
219 template <typename CallbackType>
220 531588 KLEIDICV_FORCE_INLINE LoopUnroll2 &unroll_twice(CallbackType callback)
221 KLEIDICV_STREAMING {
222 531588 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 336963 KLEIDICV_FORCE_INLINE LoopUnroll2 &unroll_once(CallbackType callback)
238 KLEIDICV_STREAMING {
239 336963 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 82176 LoopUnroll2 &tail(CallbackType callback) KLEIDICV_STREAMING {
255
50/56
✓ Branch 0 taken 89133 times.
✓ Branch 1 taken 22289 times.
✓ Branch 2 taken 44501 times.
✓ Branch 3 taken 18804 times.
✓ Branch 4 taken 44475 times.
✓ Branch 5 taken 14075 times.
✓ Branch 6 taken 30133 times.
✓ Branch 7 taken 13236 times.
✓ Branch 8 taken 1744 times.
✓ Branch 9 taken 716 times.
✓ Branch 10 taken 112 times.
✓ Branch 11 taken 250 times.
✓ Branch 12 taken 3696 times.
✓ Branch 13 taken 1290 times.
✓ Branch 14 taken 1396 times.
✓ Branch 15 taken 1220 times.
✓ Branch 16 taken 2240 times.
✓ Branch 17 taken 970 times.
✓ Branch 18 taken 684 times.
✓ Branch 19 taken 504 times.
✓ Branch 20 taken 1300 times.
✓ Branch 21 taken 1466 times.
✓ Branch 22 taken 976 times.
✓ Branch 23 taken 786 times.
✓ Branch 24 taken 492 times.
✓ Branch 25 taken 552 times.
✓ Branch 26 taken 520 times.
✓ Branch 27 taken 120 times.
✓ Branch 28 taken 432 times.
✓ Branch 29 taken 890 times.
✓ Branch 30 taken 1384 times.
✓ Branch 31 taken 854 times.
✓ Branch 32 taken 148 times.
✓ Branch 33 taken 170 times.
✓ Branch 34 taken 388 times.
✓ Branch 35 taken 172 times.
✓ Branch 36 taken 196 times.
✓ Branch 37 taken 448 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.
306570 while (index_ < length_) {
256 224394 disable_loop_vectorization();
257 224394 callback(index_++);
258 }
259
260 82176 return *this;
261 }
262
263 // Processes all remaining data at once.
264 template <typename CallbackType>
265 579360 LoopUnroll2 &remaining(CallbackType callback) KLEIDICV_STREAMING {
266
64/64
✓ Branch 0 taken 3446 times.
✓ Branch 1 taken 90864 times.
✓ Branch 2 taken 8892 times.
✓ Branch 3 taken 81141 times.
✓ Branch 4 taken 1378 times.
✓ Branch 5 taken 66369 times.
✓ Branch 6 taken 11294 times.
✓ Branch 7 taken 72058 times.
✓ Branch 8 taken 1474 times.
✓ Branch 9 taken 17006 times.
✓ Branch 10 taken 10184 times.
✓ Branch 11 taken 14334 times.
✓ Branch 12 taken 1162 times.
✓ Branch 13 taken 7594 times.
✓ Branch 14 taken 21484 times.
✓ Branch 15 taken 11344 times.
✓ Branch 16 taken 1920 times.
✓ Branch 17 taken 10850 times.
✓ Branch 18 taken 660 times.
✓ Branch 19 taken 10438 times.
✓ Branch 20 taken 1464 times.
✓ Branch 21 taken 8888 times.
✓ Branch 22 taken 1950 times.
✓ Branch 23 taken 11960 times.
✓ Branch 24 taken 2476 times.
✓ Branch 25 taken 12798 times.
✓ Branch 26 taken 1102 times.
✓ Branch 27 taken 9262 times.
✓ Branch 28 taken 2116 times.
✓ Branch 29 taken 8642 times.
✓ Branch 30 taken 2278 times.
✓ Branch 31 taken 10424 times.
✓ Branch 32 taken 104 times.
✓ Branch 33 taken 2702 times.
✓ Branch 34 taken 142 times.
✓ Branch 35 taken 7168 times.
✓ Branch 36 taken 478 times.
✓ Branch 37 taken 3162 times.
✓ Branch 38 taken 796 times.
✓ Branch 39 taken 7768 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.
579360 if (remaining_length()) {
267 496226 callback(index_, length_);
268 496226 index_ = length_;
269 496226 }
270
271 579360 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 927411 size_t step() const KLEIDICV_STREAMING { return step_; }
279
280 // Returns the remaining length.
281 1661345 size_t remaining_length() const KLEIDICV_STREAMING {
282 1661345 return length_ - index_;
283 }
284
285 private:
286 template <const size_t UnrollFactor, typename CallbackType>
287 927411 KLEIDICV_FORCE_INLINE LoopUnroll2 &unroll_n_times(CallbackType callback)
288 KLEIDICV_STREAMING {
289 927411 const size_t n_step = UnrollFactor * step();
290 927411 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 3717 times.
✓ Branch 1 taken 3862 times.
✓ Branch 2 taken 2271 times.
✓ Branch 3 taken 4243 times.
✓ Branch 4 taken 3300 times.
✓ Branch 5 taken 1795 times.
✓ Branch 6 taken 2581 times.
✓ Branch 7 taken 6597 times.
✓ Branch 8 taken 564 times.
✓ Branch 9 taken 456 times.
✓ Branch 10 taken 142 times.
✓ Branch 11 taken 10212 times.
✓ Branch 12 taken 840 times.
✓ Branch 13 taken 712 times.
✓ Branch 14 taken 756 times.
✓ Branch 15 taken 20408 times.
✓ Branch 16 taken 506 times.
✓ Branch 17 taken 5676 times.
✓ Branch 18 taken 364 times.
✓ Branch 19 taken 406 times.
✓ Branch 20 taken 460 times.
✓ Branch 21 taken 2284 times.
✓ Branch 22 taken 960 times.
✓ Branch 23 taken 702 times.
✓ Branch 24 taken 416 times.
✓ Branch 25 taken 11442 times.
✓ Branch 26 taken 50 times.
✓ Branch 27 taken 3158 times.
✓ Branch 28 taken 516 times.
✓ Branch 29 taken 6122 times.
✓ Branch 30 taken 528 times.
✓ Branch 31 taken 3414 times.
✓ Branch 32 taken 90 times.
✓ Branch 33 taken 88 times.
✓ Branch 34 taken 98 times.
✓ Branch 35 taken 48 times.
✓ Branch 36 taken 188 times.
✓ Branch 37 taken 268 times.
✓ Branch 38 taken 316 times.
✓ Branch 39 taken 248 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.
116344 if (length_ >= n_step) {
299 // External loop only ends when all data has been processed
300
64/64
✓ Branch 0 taken 5428 times.
✓ Branch 1 taken 3862 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 872 times.
✓ Branch 9 taken 456 times.
✓ Branch 10 taken 15324 times.
✓ Branch 11 taken 10212 times.
✓ Branch 12 taken 1352 times.
✓ Branch 13 taken 712 times.
✓ Branch 14 taken 30476 times.
✓ Branch 15 taken 20408 times.
✓ Branch 16 taken 10142 times.
✓ Branch 17 taken 5676 times.
✓ Branch 18 taken 462 times.
✓ Branch 19 taken 406 times.
✓ Branch 20 taken 4086 times.
✓ Branch 21 taken 2284 times.
✓ Branch 22 taken 1006 times.
✓ Branch 23 taken 702 times.
✓ Branch 24 taken 20698 times.
✓ Branch 25 taken 11442 times.
✓ Branch 26 taken 4710 times.
✓ Branch 27 taken 3158 times.
✓ Branch 28 taken 10836 times.
✓ Branch 29 taken 6122 times.
✓ Branch 30 taken 5214 times.
✓ Branch 31 taken 3414 times.
✓ Branch 32 taken 168 times.
✓ Branch 33 taken 88 times.
✓ Branch 34 taken 68 times.
✓ Branch 35 taken 48 times.
✓ Branch 36 taken 490 times.
✓ Branch 37 taken 268 times.
✓ Branch 38 taken 412 times.
✓ Branch 39 taken 248 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.
250731 while (index_ < length_) {
301 // Internal loop checks if the vector path can be executed
302
64/64
✓ Branch 0 taken 8948 times.
✓ Branch 1 taken 5428 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 10760 times.
✓ Branch 9 taken 872 times.
✓ Branch 10 taken 870876 times.
✓ Branch 11 taken 15324 times.
✓ Branch 12 taken 21372 times.
✓ Branch 13 taken 1352 times.
✓ Branch 14 taken 3476908 times.
✓ Branch 15 taken 30476 times.
✓ Branch 16 taken 198640 times.
✓ Branch 17 taken 10142 times.
✓ Branch 18 taken 1346 times.
✓ Branch 19 taken 462 times.
✓ Branch 20 taken 97298 times.
✓ Branch 21 taken 4086 times.
✓ Branch 22 taken 2930 times.
✓ Branch 23 taken 1006 times.
✓ Branch 24 taken 24782 times.
✓ Branch 25 taken 20698 times.
✓ Branch 26 taken 4538 times.
✓ Branch 27 taken 4710 times.
✓ Branch 28 taken 12636 times.
✓ Branch 29 taken 10836 times.
✓ Branch 30 taken 6082 times.
✓ Branch 31 taken 5214 times.
✓ Branch 32 taken 736 times.
✓ Branch 33 taken 168 times.
✓ Branch 34 taken 380 times.
✓ Branch 35 taken 68 times.
✓ Branch 36 taken 2400 times.
✓ Branch 37 taken 490 times.
✓ Branch 38 taken 2700 times.
✓ Branch 39 taken 412 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.
5228203 while (index_ < max_index) {
303 5073629 callback(index_);
304 5073629 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 2836 times.
✓ Branch 1 taken 2592 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 456 times.
✓ Branch 9 taken 416 times.
✓ Branch 10 taken 10212 times.
✓ Branch 11 taken 5112 times.
✓ Branch 12 taken 712 times.
✓ Branch 13 taken 640 times.
✓ Branch 14 taken 20308 times.
✓ Branch 15 taken 10168 times.
✓ Branch 16 taken 5676 times.
✓ Branch 17 taken 4466 times.
✓ Branch 18 taken 406 times.
✓ Branch 19 taken 56 times.
✓ Branch 20 taken 2284 times.
✓ Branch 21 taken 1802 times.
✓ Branch 22 taken 702 times.
✓ Branch 23 taken 304 times.
✓ Branch 24 taken 11022 times.
✓ Branch 25 taken 9676 times.
✓ Branch 26 taken 2546 times.
✓ Branch 27 taken 2164 times.
✓ Branch 28 taken 5848 times.
✓ Branch 29 taken 4988 times.
✓ Branch 30 taken 2802 times.
✓ Branch 31 taken 2412 times.
✓ Branch 32 taken 88 times.
✓ Branch 33 taken 80 times.
✓ Branch 34 taken 48 times.
✓ Branch 35 taken 20 times.
✓ Branch 36 taken 268 times.
✓ Branch 37 taken 222 times.
✓ Branch 38 taken 248 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.
154574 if (remaining_length()) {
310 62885 index_ = length_ - n_step;
311 62885 max_index = length_;
312 62885 }
313 }
314 96157 }
315 } else {
316
112/112
✓ Branch 0 taken 64024 times.
✓ Branch 1 taken 116424 times.
✓ Branch 2 taken 18177 times.
✓ Branch 3 taken 116561 times.
✓ Branch 4 taken 28720 times.
✓ Branch 5 taken 99491 times.
✓ Branch 6 taken 31196 times.
✓ Branch 7 taken 114155 times.
✓ Branch 8 taken 75743 times.
✓ Branch 9 taken 54891 times.
✓ Branch 10 taken 33783 times.
✓ Branch 11 taken 45301 times.
✓ Branch 12 taken 26134 times.
✓ Branch 13 taken 25982 times.
✓ Branch 14 taken 3764 times.
✓ Branch 15 taken 27208 times.
✓ Branch 16 taken 1020 times.
✓ Branch 17 taken 6910 times.
✓ Branch 18 taken 1032 times.
✓ Branch 19 taken 10956 times.
✓ Branch 20 taken 4108 times.
✓ Branch 21 taken 11602 times.
✓ Branch 22 taken 4558 times.
✓ Branch 23 taken 16026 times.
✓ Branch 24 taken 1982 times.
✓ Branch 25 taken 5248 times.
✓ Branch 26 taken 626 times.
✓ Branch 27 taken 8450 times.
✓ Branch 28 taken 2174 times.
✓ Branch 29 taken 6118 times.
✓ Branch 30 taken 4592 times.
✓ Branch 31 taken 11084 times.
✓ Branch 32 taken 46582 times.
✓ Branch 33 taken 9636 times.
✓ Branch 34 taken 12102 times.
✓ Branch 35 taken 14140 times.
✓ Branch 36 taken 3182 times.
✓ Branch 37 taken 3592 times.
✓ Branch 38 taken 3770 times.
✓ Branch 39 taken 8516 times.
✓ Branch 40 taken 23100 times.
✓ Branch 41 taken 3872 times.
✓ Branch 42 taken 3354 times.
✓ Branch 43 taken 8478 times.
✓ Branch 44 taken 3158 times.
✓ Branch 45 taken 3694 times.
✓ Branch 46 taken 3794 times.
✓ Branch 47 taken 8618 times.
✓ Branch 48 taken 50772 times.
✓ Branch 49 taken 13166 times.
✓ Branch 50 taken 15158 times.
✓ Branch 51 taken 11768 times.
✓ Branch 52 taken 6174 times.
✓ Branch 53 taken 5894 times.
✓ Branch 54 taken 6974 times.
✓ Branch 55 taken 5786 times.
✓ Branch 56 taken 24708 times.
✓ Branch 57 taken 6168 times.
✓ Branch 58 taken 6394 times.
✓ Branch 59 taken 6168 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.
1349092 while (index_ < max_index) {
317 538025 callback(index_);
318 538025 index_ += n_step;
319 }
320 }
321
322 927411 return *this;
323 927411 }
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 6776 bool any_null(Pointers... pointers) KLEIDICV_STREAMING {
333
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2992 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 272 times.
6776 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 79199 bool is_misaligned(Value v) KLEIDICV_STREAMING {
345 79199 constexpr size_t kMask = alignof(AlignType) - 1;
346 static_assert(kMask == 0b0001 || kMask == 0b0011 || kMask == 0b0111 ||
347 kMask == 0b1111);
348 158398 return (v & kMask) != 0;
349 79199 }
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 31697 T align_up(T value, size_t alignment) KLEIDICV_STREAMING {
355 31697 return (value + alignment - 1) & ~(alignment - 1);
356 }
357
358 template <typename T>
359 2640 T *align_up(T *value, size_t alignment) KLEIDICV_STREAMING {
360 // NOLINTBEGIN(performance-no-int-to-ptr)
361 2640 return reinterpret_cast<T *>(
362 2640 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 78963 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 24345 times.
✓ Branch 1 taken 305 times.
✓ Branch 2 taken 15496 times.
✓ Branch 3 taken 241 times.
✓ Branch 4 taken 11272 times.
✓ Branch 5 taken 224 times.
✓ Branch 6 taken 5304 times.
✓ Branch 7 taken 188 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.
78963 if (pointer == nullptr) {
371 1198 return KLEIDICV_ERROR_NULL_POINTER;
372 }
373
48/48
✓ Branch 0 taken 21175 times.
✓ Branch 1 taken 3170 times.
✓ Branch 2 taken 21035 times.
✓ Branch 3 taken 140 times.
✓ Branch 4 taken 13820 times.
✓ Branch 5 taken 1676 times.
✓ Branch 6 taken 13724 times.
✓ Branch 7 taken 96 times.
✓ Branch 8 taken 9944 times.
✓ Branch 9 taken 1328 times.
✓ Branch 10 taken 9848 times.
✓ Branch 11 taken 96 times.
✓ Branch 12 taken 4844 times.
✓ Branch 13 taken 460 times.
✓ Branch 14 taken 4768 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.
77765 if (height > 1 && is_misaligned<T>(stride)) {
374 640 return KLEIDICV_ERROR_ALIGNMENT;
375 }
376 77125 return KLEIDICV_OK;
377 78963 }
378
379 // Specialisation for when stride misalignment is impossible.
380 template <typename T>
381 105233 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 50776 times.
✓ Branch 1 taken 1127 times.
✓ Branch 2 taken 44261 times.
✓ Branch 3 taken 843 times.
✓ Branch 4 taken 4819 times.
✓ Branch 5 taken 40 times.
✓ Branch 6 taken 3343 times.
✓ Branch 7 taken 24 times.
105233 if (pointer == nullptr) {
384 2034 return KLEIDICV_ERROR_NULL_POINTER;
385 }
386 103199 return KLEIDICV_OK;
387 105233 }
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