18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci#ifndef __ASM_UNROLL_H__
38c2ecf20Sopenharmony_ci#define __ASM_UNROLL_H__
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci * Explicitly unroll a loop, for use in cases where doing so is performance
78c2ecf20Sopenharmony_ci * critical.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Ideally we'd rely upon the compiler to provide this but there's no commonly
108c2ecf20Sopenharmony_ci * available means to do so. For example GCC's "#pragma GCC unroll"
118c2ecf20Sopenharmony_ci * functionality would be ideal but is only available from GCC 8 onwards. Using
128c2ecf20Sopenharmony_ci * -funroll-loops is an option but GCC tends to make poor choices when
138c2ecf20Sopenharmony_ci * compiling our string functions. -funroll-all-loops leads to massive code
148c2ecf20Sopenharmony_ci * bloat, even if only applied to the string functions.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci#define unroll(times, fn, ...) do {				\
178c2ecf20Sopenharmony_ci	extern void bad_unroll(void)				\
188c2ecf20Sopenharmony_ci		__compiletime_error("Unsupported unroll");	\
198c2ecf20Sopenharmony_ci								\
208c2ecf20Sopenharmony_ci	/*							\
218c2ecf20Sopenharmony_ci	 * We can't unroll if the number of iterations isn't	\
228c2ecf20Sopenharmony_ci	 * compile-time constant. Unfortunately clang versions	\
238c2ecf20Sopenharmony_ci	 * up until 8.0 tend to miss obvious constants & cause	\
248c2ecf20Sopenharmony_ci	 * this check to fail, even though they go on to	\
258c2ecf20Sopenharmony_ci	 * generate reasonable code for the switch statement,	\
268c2ecf20Sopenharmony_ci	 * so we skip the sanity check for those compilers.	\
278c2ecf20Sopenharmony_ci	 */							\
288c2ecf20Sopenharmony_ci	BUILD_BUG_ON(!__builtin_constant_p(times));		\
298c2ecf20Sopenharmony_ci								\
308c2ecf20Sopenharmony_ci	switch (times) {					\
318c2ecf20Sopenharmony_ci	case 32: fn(__VA_ARGS__); fallthrough;			\
328c2ecf20Sopenharmony_ci	case 31: fn(__VA_ARGS__); fallthrough;			\
338c2ecf20Sopenharmony_ci	case 30: fn(__VA_ARGS__); fallthrough;			\
348c2ecf20Sopenharmony_ci	case 29: fn(__VA_ARGS__); fallthrough;			\
358c2ecf20Sopenharmony_ci	case 28: fn(__VA_ARGS__); fallthrough;			\
368c2ecf20Sopenharmony_ci	case 27: fn(__VA_ARGS__); fallthrough;			\
378c2ecf20Sopenharmony_ci	case 26: fn(__VA_ARGS__); fallthrough;			\
388c2ecf20Sopenharmony_ci	case 25: fn(__VA_ARGS__); fallthrough;			\
398c2ecf20Sopenharmony_ci	case 24: fn(__VA_ARGS__); fallthrough;			\
408c2ecf20Sopenharmony_ci	case 23: fn(__VA_ARGS__); fallthrough;			\
418c2ecf20Sopenharmony_ci	case 22: fn(__VA_ARGS__); fallthrough;			\
428c2ecf20Sopenharmony_ci	case 21: fn(__VA_ARGS__); fallthrough;			\
438c2ecf20Sopenharmony_ci	case 20: fn(__VA_ARGS__); fallthrough;			\
448c2ecf20Sopenharmony_ci	case 19: fn(__VA_ARGS__); fallthrough;			\
458c2ecf20Sopenharmony_ci	case 18: fn(__VA_ARGS__); fallthrough;			\
468c2ecf20Sopenharmony_ci	case 17: fn(__VA_ARGS__); fallthrough;			\
478c2ecf20Sopenharmony_ci	case 16: fn(__VA_ARGS__); fallthrough;			\
488c2ecf20Sopenharmony_ci	case 15: fn(__VA_ARGS__); fallthrough;			\
498c2ecf20Sopenharmony_ci	case 14: fn(__VA_ARGS__); fallthrough;			\
508c2ecf20Sopenharmony_ci	case 13: fn(__VA_ARGS__); fallthrough;			\
518c2ecf20Sopenharmony_ci	case 12: fn(__VA_ARGS__); fallthrough;			\
528c2ecf20Sopenharmony_ci	case 11: fn(__VA_ARGS__); fallthrough;			\
538c2ecf20Sopenharmony_ci	case 10: fn(__VA_ARGS__); fallthrough;			\
548c2ecf20Sopenharmony_ci	case 9: fn(__VA_ARGS__); fallthrough;			\
558c2ecf20Sopenharmony_ci	case 8: fn(__VA_ARGS__); fallthrough;			\
568c2ecf20Sopenharmony_ci	case 7: fn(__VA_ARGS__); fallthrough;			\
578c2ecf20Sopenharmony_ci	case 6: fn(__VA_ARGS__); fallthrough;			\
588c2ecf20Sopenharmony_ci	case 5: fn(__VA_ARGS__); fallthrough;			\
598c2ecf20Sopenharmony_ci	case 4: fn(__VA_ARGS__); fallthrough;			\
608c2ecf20Sopenharmony_ci	case 3: fn(__VA_ARGS__); fallthrough;			\
618c2ecf20Sopenharmony_ci	case 2: fn(__VA_ARGS__); fallthrough;			\
628c2ecf20Sopenharmony_ci	case 1: fn(__VA_ARGS__); fallthrough;			\
638c2ecf20Sopenharmony_ci	case 0: break;						\
648c2ecf20Sopenharmony_ci								\
658c2ecf20Sopenharmony_ci	default:						\
668c2ecf20Sopenharmony_ci		/*						\
678c2ecf20Sopenharmony_ci		 * Either the iteration count is unreasonable	\
688c2ecf20Sopenharmony_ci		 * or we need to add more cases above.		\
698c2ecf20Sopenharmony_ci		 */						\
708c2ecf20Sopenharmony_ci		bad_unroll();					\
718c2ecf20Sopenharmony_ci		break;						\
728c2ecf20Sopenharmony_ci	}							\
738c2ecf20Sopenharmony_ci} while (0)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#endif /* __ASM_UNROLL_H__ */
76