1 /* Macro for explicit loop unrolling.
2    Copyright (C) 2019-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #ifndef _LOOP_UNROLL_H
20 #define _LOOP_UNROLL_H
21 
22 /* Loop unroll macro to be used for explicit force loop unrolling with a
23    configurable number of iterations.  The idea is to make the loop unrolling
24    independent of whether the compiler is able to unroll through specific
25    optimizations options (-funroll-loops or -funroll-all-loops).
26 
27    For instance, to implement strcpy with SRC being the source input and
28    DEST the destination buffer, it is expected the macro to be used in this
29    way:
30 
31      #define ITERATION(index)	\
32        ({ char c = *str++; *dest++ = c; c != '\0' })
33 
34      while (1)
35        UNROLL_REPEAT (4, ITERATION)
36 
37    The loop will be manually unrolled 4 times.  Another option is to do
38    the index update after the tests:
39 
40      #define ITERATION(index)	\
41        ({ char c = *(str + index); *(dest + index) = c; c != '\0' })
42      #define UPDATE(n)		\
43        str += n; dst += n
44 
45      while (1)
46        UNROLL_REPEAT_UPDATE (4, ITERATION, UPDATE)
47 
48    The loop will be manually unrolled 4 times and the SRC and DEST pointers
49    will be updated only after the last iteration.
50 
51    Currently, both macros unroll the loop 8 times at maximum.  */
52 
53 #define UNROLL_REPEAT_1(X)    if (!X(0)) break;
54 #define UNROLL_REPEAT_2(X)    UNROLL_REPEAT_1 (X) if (!X (1)) break;
55 #define UNROLL_REPEAT_3(X)    UNROLL_REPEAT_2 (X) if (!X (2)) break;
56 #define UNROLL_REPEAT_4(X)    UNROLL_REPEAT_3 (X) if (!X (3)) break;
57 #define UNROLL_REPEAT_5(X)    UNROLL_REPEAT_4 (X) if (!X (4)) break;
58 #define UNROLL_REPEAT_6(X)    UNROLL_REPEAT_5 (X) if (!X (5)) break;
59 #define UNROLL_REPEAT_7(X)    UNROLL_REPEAT_6 (X) if (!X (6)) break;
60 #define UNROLL_REPEAT_8(X)    UNROLL_REPEAT_7 (X) if (!X (7)) break;
61 
62 #define UNROLL_EXPAND(...)    __VA_ARGS__
63 
64 #define UNROLL_REPEAT__(N, X) UNROLL_EXPAND(UNROLL_REPEAT_ ## N) (X)
65 #define UNROLL_REPEAT_(N, X)  UNROLL_REPEAT__ (N, X)
66 
67 #define UNROLL_REPEAT(N, X)                \
68   (void) ({                                \
69     UNROLL_REPEAT_ (UNROLL_EXPAND(N), X);  \
70   })
71 
72 #define UNROLL_REPEAT_UPDATE(N, X, U)      \
73   (void) ({                                \
74     UNROLL_REPEAT_ (UNROLL_EXPAND(N), X);  \
75     UPDATE (N);                            \
76   })
77 
78 #endif
79