KleidiCV Coverage Report


Directory: ./
File: kleidicv/include/kleidicv/utils.h
Date: 2025-11-25 17:23:32
Exec Total Coverage
Lines: 137 137 100.0%
Functions: 3030 3104 97.6%
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 140376 static U saturating_cast(S value) KLEIDICV_STREAMING {
24
2/2
✓ Branch 0 taken 27853 times.
✓ Branch 1 taken 112523 times.
140376 if (value > std::numeric_limits<U>::max()) {
25 27853 return std::numeric_limits<U>::max();
26 }
27
2/2
✓ Branch 0 taken 84464 times.
✓ Branch 1 taken 28059 times.
112523 if (value < 0) {
28 28059 return 0;
29 }
30
31 84464 return static_cast<U>(value);
32 140376 }
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 764 static DstType saturating_cast(SrcType value) KLEIDICV_STREAMING {
40 764 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 1042 static DstType saturating_cast(SrcType value) KLEIDICV_STREAMING {
49 1042 DstType max_value = std::numeric_limits<DstType>::max();
50
51
6/6
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 575 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 200 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 88 times.
1042 if (value > static_cast<SrcType>(max_value)) {
52 179 return max_value;
53 }
54
55 863 return static_cast<DstType>(value);
56 1042 }
57
58 // Rounding shift right.
59 template <typename T>
60 310054 static T rounding_shift_right(T value, size_t shift) KLEIDICV_STREAMING {
61 310054 return (value + (T{1} << (shift - 1))) >> shift;
62 }
63
64 // When placed in a loop, it effectively disables loop vectorization.
65 650562 static inline void disable_loop_vectorization() KLEIDICV_STREAMING {
66 650562 __asm__("");
67 650562 }
68
69 // Helper class to unroll a loop as needed.
70 class LoopUnroll final {
71 public:
72 57408 explicit LoopUnroll(size_t length, size_t step) KLEIDICV_STREAMING
73 57408 : length_(length),
74 57408 step_(step),
75 57408 index_(0),
76 57408 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 33068 LoopUnroll &unroll_twice(CallbackType callback) KLEIDICV_STREAMING {
87 33068 return unroll_n_times<2>(callback);
88 }
89
90 // Unrolls the loop twice, if enabled.
91 template <bool Enable, typename CallbackType>
92 38023 LoopUnroll &unroll_twice_if([[maybe_unused]] CallbackType callback)
93 KLEIDICV_STREAMING {
94 if constexpr (Enable) {
95 31496 return unroll_twice(callback);
96 }
97
98 6527 return *this;
99 }
100
101 // Loop unrolled once.
102 template <typename CallbackType>
103 14864 LoopUnroll &unroll_once(CallbackType callback) KLEIDICV_STREAMING {
104 14864 return unroll_n_times<1>(callback);
105 }
106
107 // Unrolls the loop once, if enabled.
108 template <bool Enable, typename CallbackType>
109 38216 LoopUnroll &unroll_once_if([[maybe_unused]] CallbackType callback)
110 KLEIDICV_STREAMING {
111 if constexpr (Enable) {
112 3939 return unroll_once(callback);
113 }
114
115 34277 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 45320 LoopUnroll &remaining(CallbackType callback) KLEIDICV_STREAMING {
133
24/24
✓ Branch 0 taken 2319 times.
✓ Branch 1 taken 14774 times.
✓ Branch 2 taken 1485 times.
✓ Branch 3 taken 5194 times.
✓ Branch 4 taken 1275 times.
✓ Branch 5 taken 4755 times.
✓ Branch 6 taken 1299 times.
✓ Branch 7 taken 4064 times.
✓ Branch 8 taken 876 times.
✓ Branch 9 taken 2767 times.
✓ Branch 10 taken 541 times.
✓ Branch 11 taken 2089 times.
✓ Branch 12 taken 452 times.
✓ Branch 13 taken 1010 times.
✓ Branch 14 taken 434 times.
✓ Branch 15 taken 818 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.
45320 if (length_) {
134 36591 callback(length_, step_);
135 36591 length_ = 0;
136 36591 }
137
138 45320 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 2362 size_t step() const KLEIDICV_STREAMING { return step_; }
146
147 // Returns the remaining length.
148 69588 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 53488 LoopUnroll &unroll_n_times(CallbackType callback) KLEIDICV_STREAMING {
158 53488 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 53488 const size_t max_index = remaining_length() / step;
163 // NOLINTEND(clang-analyzer-core.DivideZero)
164
165
24/24
✓ Branch 0 taken 469103 times.
✓ Branch 1 taken 19589 times.
✓ Branch 2 taken 37862 times.
✓ Branch 3 taken 6154 times.
✓ Branch 4 taken 31291 times.
✓ Branch 5 taken 6179 times.
✓ Branch 6 taken 34494 times.
✓ Branch 7 taken 7785 times.
✓ Branch 8 taken 25678 times.
✓ Branch 9 taken 3594 times.
✓ Branch 10 taken 22699 times.
✓ Branch 11 taken 3193 times.
✓ Branch 12 taken 16202 times.
✓ Branch 13 taken 3349 times.
✓ Branch 14 taken 15653 times.
✓ Branch 15 taken 2477 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.
709670 for (index_ = 0; index_ < max_index; ++index_) {
166 656182 callback(step);
167 656182 }
168
169 // Adjust length to reflect the processed data.
170 53488 length_ -= step * index_;
171 53488 return *this;
172 53488 }
173
174 // Instructs the loop logic to avoid the tail loop.
175 template <typename CallbackType>
176 1653 bool try_avoid_tail_loop(CallbackType callback) KLEIDICV_STREAMING {
177
8/8
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 245 times.
✓ Branch 2 taken 228 times.
✓ Branch 3 taken 154 times.
✓ Branch 4 taken 228 times.
✓ Branch 5 taken 154 times.
✓ Branch 6 taken 228 times.
✓ Branch 7 taken 154 times.
1653 if (KLEIDICV_UNLIKELY(!can_avoid_tail_)) {
178 946 return false;
179 }
180
181
8/8
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 112 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 112 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 112 times.
✓ Branch 7 taken 42 times.
707 if (KLEIDICV_UNLIKELY(!remaining_length())) {
182 514 return false;
183 }
184
185 193 callback(step() - remaining_length());
186 193 length_ = step();
187 193 return true;
188 1653 }
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 393028 explicit LoopUnroll2(size_t length, size_t step) KLEIDICV_STREAMING
202 393028 : length_(length),
203 393028 step_(step),
204 393028 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 58744 LoopUnroll2 &unroll_four_times(CallbackType callback) KLEIDICV_STREAMING {
215 58744 return unroll_n_times<4>(callback);
216 }
217
218 // Loop unrolled twice.
219 template <typename CallbackType>
220 207320 LoopUnroll2 &unroll_twice(CallbackType callback) KLEIDICV_STREAMING {
221 207320 return unroll_n_times<2>(callback);
222 }
223
224 // Unrolls the loop twice, if enabled.
225 template <bool Enable, typename CallbackType>
226 LoopUnroll2 &unroll_twice_if(CallbackType callback) KLEIDICV_STREAMING {
227 if constexpr (Enable) {
228 return unroll_twice(callback);
229 }
230
231 return *this;
232 }
233
234 // Loop unrolled once.
235 template <typename CallbackType>
236 275653 LoopUnroll2 &unroll_once(CallbackType callback) KLEIDICV_STREAMING {
237 275653 return unroll_n_times<1>(callback);
238 }
239
240 // Unrolls the loop once, if enabled.
241 template <bool Enable, typename CallbackType>
242 LoopUnroll2 &unroll_once_if(CallbackType callback) KLEIDICV_STREAMING {
243 if constexpr (Enable) {
244 return unroll_once(callback);
245 }
246
247 return *this;
248 }
249
250 // Processes trailing data.
251 template <typename CallbackType>
252 53798 LoopUnroll2 &tail(CallbackType callback) KLEIDICV_STREAMING {
253
47/56
✓ Branch 0 taken 42289 times.
✓ Branch 1 taken 11410 times.
✓ Branch 2 taken 21966 times.
✓ Branch 3 taken 10074 times.
✓ Branch 4 taken 32704 times.
✓ Branch 5 taken 9642 times.
✓ Branch 6 taken 18363 times.
✓ Branch 7 taken 8804 times.
✓ Branch 8 taken 3485 times.
✓ Branch 9 taken 1394 times.
✓ Branch 10 taken 329 times.
✓ Branch 11 taken 910 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 1168 times.
✓ Branch 18 taken 164 times.
✓ Branch 19 taken 74 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 592 times.
✓ Branch 26 taken 572 times.
✓ Branch 27 taken 142 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 520 times.
✓ Branch 50 taken 4 times.
✓ Branch 51 taken 36 times.
✓ Branch 52 taken 272 times.
✓ Branch 53 taken 818 times.
✗ Branch 54 not taken.
✓ Branch 55 taken 748 times.
183790 while (index_ < length_) {
254 129992 disable_loop_vectorization();
255 129992 callback(index_++);
256 }
257
258 53798 return *this;
259 }
260
261 // Processes all remaining data at once.
262 template <typename CallbackType>
263 295618 LoopUnroll2 &remaining(CallbackType callback) KLEIDICV_STREAMING {
264
64/64
✓ Branch 0 taken 597 times.
✓ Branch 1 taken 46504 times.
✓ Branch 2 taken 7764 times.
✓ Branch 3 taken 37835 times.
✓ Branch 4 taken 916 times.
✓ Branch 5 taken 40556 times.
✓ Branch 6 taken 10538 times.
✓ Branch 7 taken 33230 times.
✓ Branch 8 taken 947 times.
✓ Branch 9 taken 3511 times.
✓ Branch 10 taken 11123 times.
✓ Branch 11 taken 1575 times.
✓ Branch 12 taken 1130 times.
✓ Branch 13 taken 2954 times.
✓ Branch 14 taken 21272 times.
✓ Branch 15 taken 2284 times.
✓ Branch 16 taken 1900 times.
✓ Branch 17 taken 6804 times.
✓ Branch 18 taken 804 times.
✓ Branch 19 taken 1610 times.
✓ Branch 20 taken 1464 times.
✓ Branch 21 taken 2434 times.
✓ Branch 22 taken 1500 times.
✓ Branch 23 taken 1356 times.
✓ Branch 24 taken 2456 times.
✓ Branch 25 taken 10614 times.
✓ Branch 26 taken 1132 times.
✓ Branch 27 taken 2410 times.
✓ Branch 28 taken 2116 times.
✓ Branch 29 taken 6456 times.
✓ Branch 30 taken 2308 times.
✓ Branch 31 taken 3608 times.
✓ Branch 32 taken 104 times.
✓ Branch 33 taken 96 times.
✓ Branch 34 taken 52 times.
✓ Branch 35 taken 52 times.
✓ Branch 36 taken 478 times.
✓ Branch 37 taken 454 times.
✓ Branch 38 taken 676 times.
✓ Branch 39 taken 580 times.
✓ Branch 40 taken 104 times.
✓ Branch 41 taken 96 times.
✓ Branch 42 taken 52 times.
✓ Branch 43 taken 52 times.
✓ Branch 44 taken 478 times.
✓ Branch 45 taken 454 times.
✓ Branch 46 taken 676 times.
✓ Branch 47 taken 580 times.
✓ Branch 48 taken 896 times.
✓ Branch 49 taken 802 times.
✓ Branch 50 taken 176 times.
✓ Branch 51 taken 78 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.
295618 if (remaining_length()) {
265 218007 callback(index_, length_);
266 218007 index_ = length_;
267 218007 }
268
269 295618 return *this;
270 }
271
272 // Returns true if there is nothing left to process.
273 bool empty() const KLEIDICV_STREAMING { return length_ == index_; }
274
275 // Returns the step value.
276 541717 size_t step() const KLEIDICV_STREAMING { return step_; }
277
278 // Returns the remaining length.
279 989869 size_t remaining_length() const KLEIDICV_STREAMING {
280 989869 return length_ - index_;
281 }
282
283 private:
284 template <const size_t UnrollFactor, typename CallbackType>
285 541717 LoopUnroll2 &unroll_n_times(CallbackType callback) KLEIDICV_STREAMING {
286 541717 const size_t n_step = UnrollFactor * step();
287 541717 size_t max_index = index_ + (remaining_length() / n_step) * n_step;
288
289 // A tail mechanism is built into the single vector processing loop, if
290 // enabled. The single vector path is executed iteratively, and at the end
291 // it rewinds the loop to one vector before the end of the data, and
292 // executes one final vector path, so the scalar path can be omitted.
293 if constexpr (try_to_avoid_tail_loop<Tail> && (UnrollFactor == 1)) {
294 // Enter this loop only if there's enough data for a full vector
295
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 919 times.
✓ Branch 9 taken 779 times.
✓ Branch 10 taken 517 times.
✓ Branch 11 taken 10497 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 5958 times.
✓ Branch 18 taken 508 times.
✓ Branch 19 taken 442 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 11420 times.
✓ Branch 26 taken 76 times.
✓ Branch 27 taken 3154 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 340 times.
✓ Branch 50 taken 20 times.
✓ Branch 51 taken 162 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.
114218 if (length_ >= n_step) {
296 // External loop only ends when all data has been processed
297
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 1429 times.
✓ Branch 9 taken 779 times.
✓ Branch 10 taken 15485 times.
✓ Branch 11 taken 10497 times.
✓ Branch 12 taken 1536 times.
✓ Branch 13 taken 788 times.
✓ Branch 14 taken 30396 times.
✓ Branch 15 taken 20324 times.
✓ Branch 16 taken 10726 times.
✓ Branch 17 taken 5958 times.
✓ Branch 18 taken 486 times.
✓ Branch 19 taken 442 times.
✓ Branch 20 taken 2806 times.
✓ Branch 21 taken 1644 times.
✓ Branch 22 taken 854 times.
✓ Branch 23 taken 550 times.
✓ Branch 24 taken 20680 times.
✓ Branch 25 taken 11420 times.
✓ Branch 26 taken 4694 times.
✓ Branch 27 taken 3154 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 486 times.
✓ Branch 49 taken 340 times.
✓ Branch 50 taken 202 times.
✓ Branch 51 taken 162 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.
246653 while (index_ < length_) {
298 // Internal loop checks if the vector path can be executed
299
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 11639 times.
✓ Branch 9 taken 1429 times.
✓ Branch 10 taken 871001 times.
✓ Branch 11 taken 15485 times.
✓ Branch 12 taken 21824 times.
✓ Branch 13 taken 1536 times.
✓ Branch 14 taken 3476828 times.
✓ Branch 15 taken 30396 times.
✓ Branch 16 taken 199720 times.
✓ Branch 17 taken 10726 times.
✓ Branch 18 taken 1358 times.
✓ Branch 19 taken 486 times.
✓ Branch 20 taken 95058 times.
✓ Branch 21 taken 2806 times.
✓ Branch 22 taken 2778 times.
✓ Branch 23 taken 854 times.
✓ Branch 24 taken 24782 times.
✓ Branch 25 taken 20680 times.
✓ Branch 26 taken 4510 times.
✓ Branch 27 taken 4694 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 1502 times.
✓ Branch 49 taken 486 times.
✓ Branch 50 taken 774 times.
✓ Branch 51 taken 202 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.
5224627 while (index_ < max_index) {
300 5072093 callback(index_);
301 5072093 index_ += n_step;
302 }
303 // Check if a final iteration is needed. The double loop is needed to
304 // avoid the repetition of the callback function, which is usually
305 // inlined into the binary. (Save some code space)
306
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 779 times.
✓ Branch 9 taken 650 times.
✓ Branch 10 taken 10329 times.
✓ Branch 11 taken 5156 times.
✓ Branch 12 taken 788 times.
✓ Branch 13 taken 748 times.
✓ Branch 14 taken 20324 times.
✓ Branch 15 taken 10072 times.
✓ Branch 16 taken 5958 times.
✓ Branch 17 taken 4768 times.
✓ Branch 18 taken 442 times.
✓ Branch 19 taken 44 times.
✓ Branch 20 taken 1644 times.
✓ Branch 21 taken 1162 times.
✓ Branch 22 taken 550 times.
✓ Branch 23 taken 304 times.
✓ Branch 24 taken 11006 times.
✓ Branch 25 taken 9674 times.
✓ Branch 26 taken 2542 times.
✓ Branch 27 taken 2152 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 340 times.
✓ Branch 49 taken 146 times.
✓ Branch 50 taken 162 times.
✓ Branch 51 taken 40 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.
152534 if (remaining_length()) {
307 61927 index_ = length_ - n_step;
308 61927 max_index = length_;
309 61927 }
310 }
311 94119 }
312 } else {
313
112/112
✓ Branch 0 taken 11632 times.
✓ Branch 1 taken 58308 times.
✓ Branch 2 taken 11897 times.
✓ Branch 3 taken 57961 times.
✓ Branch 4 taken 10340 times.
✓ Branch 5 taken 47847 times.
✓ Branch 6 taken 11434 times.
✓ Branch 7 taken 46467 times.
✓ Branch 8 taken 52055 times.
✓ Branch 9 taken 34169 times.
✓ Branch 10 taken 4319 times.
✓ Branch 11 taken 24765 times.
✓ Branch 12 taken 26839 times.
✓ Branch 13 taken 18156 times.
✓ Branch 14 taken 4382 times.
✓ Branch 15 taken 15392 times.
✓ Branch 16 taken 1053 times.
✓ Branch 17 taken 4354 times.
✓ Branch 18 taken 1672 times.
✓ Branch 19 taken 1682 times.
✓ Branch 20 taken 4140 times.
✓ Branch 21 taken 6824 times.
✓ Branch 22 taken 4278 times.
✓ Branch 23 taken 6614 times.
✓ Branch 24 taken 3222 times.
✓ Branch 25 taken 3554 times.
✓ Branch 26 taken 690 times.
✓ Branch 27 taken 2102 times.
✓ Branch 28 taken 2318 times.
✓ Branch 29 taken 4406 times.
✓ Branch 30 taken 2048 times.
✓ Branch 31 taken 2366 times.
✓ Branch 32 taken 46096 times.
✓ Branch 33 taken 5482 times.
✓ Branch 34 taken 11548 times.
✓ Branch 35 taken 5386 times.
✓ Branch 36 taken 3254 times.
✓ Branch 37 taken 1406 times.
✓ Branch 38 taken 3746 times.
✓ Branch 39 taken 1730 times.
✓ Branch 40 taken 23124 times.
✓ Branch 41 taken 1686 times.
✓ Branch 42 taken 3402 times.
✓ Branch 43 taken 1692 times.
✓ Branch 44 taken 3182 times.
✓ Branch 45 taken 1508 times.
✓ Branch 46 taken 3770 times.
✓ Branch 47 taken 1832 times.
✓ Branch 48 taken 50536 times.
✓ Branch 49 taken 12830 times.
✓ Branch 50 taken 14968 times.
✓ Branch 51 taken 11378 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.
814248 while (index_ < max_index) {
314 386749 callback(index_);
315 386749 index_ += n_step;
316 }
317 }
318
319 541717 return *this;
320 541717 }
321
322 size_t length_;
323 size_t step_;
324 size_t index_;
325 }; // end of class LoopUnroll2
326
327 // Check whether any of the arguments are null pointers.
328 template <typename... Pointers>
329 18220 bool any_null(Pointers... pointers) KLEIDICV_STREAMING {
330
12/12
✓ Branch 0 taken 296 times.
✓ Branch 1 taken 2724 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 260 times.
✓ Branch 4 taken 264 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 260 times.
✓ Branch 8 taken 260 times.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 256 times.
18220 return (... || (pointers == nullptr));
331 }
332
333 #define CHECK_POINTERS(...) \
334 do { \
335 if (KLEIDICV_TARGET_NAMESPACE::any_null(__VA_ARGS__)) { \
336 return KLEIDICV_ERROR_NULL_POINTER; \
337 } \
338 } while (false)
339
340 template <typename AlignType, typename Value>
341 70588 bool is_misaligned(Value v) KLEIDICV_STREAMING {
342 70588 constexpr size_t kMask = alignof(AlignType) - 1;
343 static_assert(kMask == 0b0001 || kMask == 0b0011 || kMask == 0b0111 ||
344 kMask == 0b1111);
345 141176 return (v & kMask) != 0;
346 70588 }
347
348 // Return value aligned up to the next multiple of alignment
349 // Assumes alignment is a power of two.
350 template <typename T>
351 13933 T align_up(T value, size_t alignment) KLEIDICV_STREAMING {
352 13933 return (value + alignment - 1) & ~(alignment - 1);
353 }
354
355 template <typename T>
356 6048 T *align_up(T *value, size_t alignment) KLEIDICV_STREAMING {
357 // NOLINTBEGIN(performance-no-int-to-ptr)
358 6048 return reinterpret_cast<T *>(
359 6048 align_up(reinterpret_cast<uintptr_t>(value), alignment));
360 // NOLINTEND(performance-no-int-to-ptr)
361 }
362
363 // Specialisation for when stride misalignment is possible.
364 template <typename T>
365 67533 std::enable_if_t<alignof(T) != 1, kleidicv_error_t> check_pointer_and_stride(
366 T *pointer, size_t stride, size_t height) KLEIDICV_STREAMING {
367
24/24
✓ Branch 0 taken 19146 times.
✓ Branch 1 taken 305 times.
✓ Branch 2 taken 12709 times.
✓ Branch 3 taken 241 times.
✓ Branch 4 taken 10096 times.
✓ Branch 5 taken 228 times.
✓ Branch 6 taken 5188 times.
✓ Branch 7 taken 192 times.
✓ Branch 8 taken 5364 times.
✓ Branch 9 taken 84 times.
✓ Branch 10 taken 3824 times.
✓ Branch 11 taken 68 times.
✓ Branch 12 taken 2112 times.
✓ Branch 13 taken 20 times.
✓ Branch 14 taken 1452 times.
✓ Branch 15 taken 12 times.
✓ Branch 16 taken 2612 times.
✓ Branch 17 taken 20 times.
✓ Branch 18 taken 1952 times.
✓ Branch 19 taken 12 times.
✓ Branch 20 taken 1264 times.
✓ Branch 21 taken 16 times.
✓ Branch 22 taken 608 times.
✓ Branch 23 taken 8 times.
67533 if (pointer == nullptr) {
368 1206 return KLEIDICV_ERROR_NULL_POINTER;
369 }
370
48/48
✓ Branch 0 taken 17141 times.
✓ Branch 1 taken 2005 times.
✓ Branch 2 taken 17001 times.
✓ Branch 3 taken 140 times.
✓ Branch 4 taken 11767 times.
✓ Branch 5 taken 942 times.
✓ Branch 6 taken 11671 times.
✓ Branch 7 taken 96 times.
✓ Branch 8 taken 9112 times.
✓ Branch 9 taken 984 times.
✓ Branch 10 taken 9016 times.
✓ Branch 11 taken 96 times.
✓ Branch 12 taken 4832 times.
✓ Branch 13 taken 356 times.
✓ Branch 14 taken 4756 times.
✓ Branch 15 taken 76 times.
✓ Branch 16 taken 4856 times.
✓ Branch 17 taken 508 times.
✓ Branch 18 taken 4768 times.
✓ Branch 19 taken 88 times.
✓ Branch 20 taken 3528 times.
✓ Branch 21 taken 296 times.
✓ Branch 22 taken 3456 times.
✓ Branch 23 taken 72 times.
✓ Branch 24 taken 1976 times.
✓ Branch 25 taken 136 times.
✓ Branch 26 taken 1960 times.
✓ Branch 27 taken 16 times.
✓ Branch 28 taken 1396 times.
✓ Branch 29 taken 56 times.
✓ Branch 30 taken 1388 times.
✓ Branch 31 taken 8 times.
✓ Branch 32 taken 2436 times.
✓ Branch 33 taken 176 times.
✓ Branch 34 taken 2420 times.
✓ Branch 35 taken 16 times.
✓ Branch 36 taken 1856 times.
✓ Branch 37 taken 96 times.
✓ Branch 38 taken 1848 times.
✓ Branch 39 taken 8 times.
✓ Branch 40 taken 1128 times.
✓ Branch 41 taken 136 times.
✓ Branch 42 taken 1112 times.
✓ Branch 43 taken 16 times.
✓ Branch 44 taken 552 times.
✓ Branch 45 taken 56 times.
✓ Branch 46 taken 544 times.
✓ Branch 47 taken 8 times.
66327 if (height > 1 && is_misaligned<T>(stride)) {
371 640 return KLEIDICV_ERROR_ALIGNMENT;
372 }
373 65687 return KLEIDICV_OK;
374 67533 }
375
376 // Specialisation for when stride misalignment is impossible.
377 template <typename T>
378 73272 std::enable_if_t<alignof(T) == 1, kleidicv_error_t> check_pointer_and_stride(
379 T *pointer, size_t /*stride*/, size_t /*height*/) KLEIDICV_STREAMING {
380
8/8
✓ Branch 0 taken 34947 times.
✓ Branch 1 taken 1232 times.
✓ Branch 2 taken 28967 times.
✓ Branch 3 taken 908 times.
✓ Branch 4 taken 4171 times.
✓ Branch 5 taken 40 times.
✓ Branch 6 taken 2983 times.
✓ Branch 7 taken 24 times.
73272 if (pointer == nullptr) {
381 2204 return KLEIDICV_ERROR_NULL_POINTER;
382 }
383 71068 return KLEIDICV_OK;
384 73272 }
385
386 #define CHECK_POINTER_AND_STRIDE(pointer, stride, height) \
387 do { \
388 if (kleidicv_error_t ptr_stride_err = \
389 KLEIDICV_TARGET_NAMESPACE::check_pointer_and_stride( \
390 pointer, stride, height)) { \
391 return ptr_stride_err; \
392 } \
393 } while (false)
394
395 #define MAKE_POINTER_CHECK_ALIGNMENT(ElementType, name, from) \
396 if constexpr (alignof(ElementType) > 1) { \
397 if (KLEIDICV_TARGET_NAMESPACE::is_misaligned<ElementType>( \
398 reinterpret_cast<uintptr_t>(from))) { \
399 return KLEIDICV_ERROR_ALIGNMENT; \
400 } \
401 } \
402 ElementType *name = reinterpret_cast<ElementType *>(from)
403
404 // Check whether the image size is acceptable by limiting it.
405 #define CHECK_IMAGE_SIZE(width, height) \
406 do { \
407 size_t image_size = 0; \
408 if (__builtin_mul_overflow(width, height, &image_size)) { \
409 return KLEIDICV_ERROR_RANGE; \
410 } \
411 \
412 if (image_size > KLEIDICV_MAX_IMAGE_PIXELS) { \
413 return KLEIDICV_ERROR_RANGE; \
414 } \
415 } while (false)
416
417 // Check whether the rectangle size is acceptable by limiting it.
418 #define CHECK_RECTANGLE_SIZE(rect) CHECK_IMAGE_SIZE(rect.width, rect.height)
419
420 } // namespace KLEIDICV_TARGET_NAMESPACE
421
422 #endif // KLEIDICV_UTILS_H
423