| 1 | /* Macro for explicit loop unrolling. |
| 2 | Copyright (C) 2019-2023 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 | |