Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 #ifndef __ASM_UNROLL_H__
0003 #define __ASM_UNROLL_H__
0004 
0005 /*
0006  * Explicitly unroll a loop, for use in cases where doing so is performance
0007  * critical.
0008  *
0009  * Ideally we'd rely upon the compiler to provide this but there's no commonly
0010  * available means to do so. For example GCC's "#pragma GCC unroll"
0011  * functionality would be ideal but is only available from GCC 8 onwards. Using
0012  * -funroll-loops is an option but GCC tends to make poor choices when
0013  * compiling our string functions. -funroll-all-loops leads to massive code
0014  * bloat, even if only applied to the string functions.
0015  */
0016 #define unroll(times, fn, ...) do {             \
0017     extern void bad_unroll(void)                \
0018         __compiletime_error("Unsupported unroll");  \
0019                                 \
0020     /*                          \
0021      * We can't unroll if the number of iterations isn't    \
0022      * compile-time constant. Unfortunately clang versions  \
0023      * up until 8.0 tend to miss obvious constants & cause  \
0024      * this check to fail, even though they go on to    \
0025      * generate reasonable code for the switch statement,   \
0026      * so we skip the sanity check for those compilers. \
0027      */                         \
0028     BUILD_BUG_ON(!__builtin_constant_p(times));     \
0029                                 \
0030     switch (times) {                    \
0031     case 32: fn(__VA_ARGS__); fallthrough;          \
0032     case 31: fn(__VA_ARGS__); fallthrough;          \
0033     case 30: fn(__VA_ARGS__); fallthrough;          \
0034     case 29: fn(__VA_ARGS__); fallthrough;          \
0035     case 28: fn(__VA_ARGS__); fallthrough;          \
0036     case 27: fn(__VA_ARGS__); fallthrough;          \
0037     case 26: fn(__VA_ARGS__); fallthrough;          \
0038     case 25: fn(__VA_ARGS__); fallthrough;          \
0039     case 24: fn(__VA_ARGS__); fallthrough;          \
0040     case 23: fn(__VA_ARGS__); fallthrough;          \
0041     case 22: fn(__VA_ARGS__); fallthrough;          \
0042     case 21: fn(__VA_ARGS__); fallthrough;          \
0043     case 20: fn(__VA_ARGS__); fallthrough;          \
0044     case 19: fn(__VA_ARGS__); fallthrough;          \
0045     case 18: fn(__VA_ARGS__); fallthrough;          \
0046     case 17: fn(__VA_ARGS__); fallthrough;          \
0047     case 16: fn(__VA_ARGS__); fallthrough;          \
0048     case 15: fn(__VA_ARGS__); fallthrough;          \
0049     case 14: fn(__VA_ARGS__); fallthrough;          \
0050     case 13: fn(__VA_ARGS__); fallthrough;          \
0051     case 12: fn(__VA_ARGS__); fallthrough;          \
0052     case 11: fn(__VA_ARGS__); fallthrough;          \
0053     case 10: fn(__VA_ARGS__); fallthrough;          \
0054     case 9: fn(__VA_ARGS__); fallthrough;           \
0055     case 8: fn(__VA_ARGS__); fallthrough;           \
0056     case 7: fn(__VA_ARGS__); fallthrough;           \
0057     case 6: fn(__VA_ARGS__); fallthrough;           \
0058     case 5: fn(__VA_ARGS__); fallthrough;           \
0059     case 4: fn(__VA_ARGS__); fallthrough;           \
0060     case 3: fn(__VA_ARGS__); fallthrough;           \
0061     case 2: fn(__VA_ARGS__); fallthrough;           \
0062     case 1: fn(__VA_ARGS__); fallthrough;           \
0063     case 0: break;                      \
0064                                 \
0065     default:                        \
0066         /*                      \
0067          * Either the iteration count is unreasonable   \
0068          * or we need to add more cases above.      \
0069          */                     \
0070         bad_unroll();                   \
0071         break;                      \
0072     }                           \
0073 } while (0)
0074 
0075 #endif /* __ASM_UNROLL_H__ */