unroll.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. #ifndef __ASM_UNROLL_H__
  3. #define __ASM_UNROLL_H__
  4. /*
  5. * Explicitly unroll a loop, for use in cases where doing so is performance
  6. * critical.
  7. *
  8. * Ideally we'd rely upon the compiler to provide this but there's no commonly
  9. * available means to do so. For example GCC's "#pragma GCC unroll"
  10. * functionality would be ideal but is only available from GCC 8 onwards. Using
  11. * -funroll-loops is an option but GCC tends to make poor choices when
  12. * compiling our string functions. -funroll-all-loops leads to massive code
  13. * bloat, even if only applied to the string functions.
  14. */
  15. #define unroll(times, fn, ...) do { \
  16. extern void bad_unroll(void) \
  17. __compiletime_error("Unsupported unroll"); \
  18. \
  19. /* \
  20. * We can't unroll if the number of iterations isn't \
  21. * compile-time constant. Unfortunately clang versions \
  22. * up until 8.0 tend to miss obvious constants & cause \
  23. * this check to fail, even though they go on to \
  24. * generate reasonable code for the switch statement, \
  25. * so we skip the sanity check for those compilers. \
  26. */ \
  27. BUILD_BUG_ON(!__builtin_constant_p(times)); \
  28. \
  29. switch (times) { \
  30. case 32: fn(__VA_ARGS__); fallthrough; \
  31. case 31: fn(__VA_ARGS__); fallthrough; \
  32. case 30: fn(__VA_ARGS__); fallthrough; \
  33. case 29: fn(__VA_ARGS__); fallthrough; \
  34. case 28: fn(__VA_ARGS__); fallthrough; \
  35. case 27: fn(__VA_ARGS__); fallthrough; \
  36. case 26: fn(__VA_ARGS__); fallthrough; \
  37. case 25: fn(__VA_ARGS__); fallthrough; \
  38. case 24: fn(__VA_ARGS__); fallthrough; \
  39. case 23: fn(__VA_ARGS__); fallthrough; \
  40. case 22: fn(__VA_ARGS__); fallthrough; \
  41. case 21: fn(__VA_ARGS__); fallthrough; \
  42. case 20: fn(__VA_ARGS__); fallthrough; \
  43. case 19: fn(__VA_ARGS__); fallthrough; \
  44. case 18: fn(__VA_ARGS__); fallthrough; \
  45. case 17: fn(__VA_ARGS__); fallthrough; \
  46. case 16: fn(__VA_ARGS__); fallthrough; \
  47. case 15: fn(__VA_ARGS__); fallthrough; \
  48. case 14: fn(__VA_ARGS__); fallthrough; \
  49. case 13: fn(__VA_ARGS__); fallthrough; \
  50. case 12: fn(__VA_ARGS__); fallthrough; \
  51. case 11: fn(__VA_ARGS__); fallthrough; \
  52. case 10: fn(__VA_ARGS__); fallthrough; \
  53. case 9: fn(__VA_ARGS__); fallthrough; \
  54. case 8: fn(__VA_ARGS__); fallthrough; \
  55. case 7: fn(__VA_ARGS__); fallthrough; \
  56. case 6: fn(__VA_ARGS__); fallthrough; \
  57. case 5: fn(__VA_ARGS__); fallthrough; \
  58. case 4: fn(__VA_ARGS__); fallthrough; \
  59. case 3: fn(__VA_ARGS__); fallthrough; \
  60. case 2: fn(__VA_ARGS__); fallthrough; \
  61. case 1: fn(__VA_ARGS__); fallthrough; \
  62. case 0: break; \
  63. \
  64. default: \
  65. /* \
  66. * Either the iteration count is unreasonable \
  67. * or we need to add more cases above. \
  68. */ \
  69. bad_unroll(); \
  70. break; \
  71. } \
  72. } while (0)
  73. #endif /* __ASM_UNROLL_H__ */