clzsi2.S 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. //===-- clzsi2.c - Implement __clzsi2 -------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file implements count leading zeros for 32bit arguments.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "../assembly.h"
  13. .syntax unified
  14. .text
  15. DEFINE_CODE_STATE
  16. .p2align 2
  17. DEFINE_COMPILERRT_FUNCTION(__clzsi2)
  18. #ifdef __ARM_FEATURE_CLZ
  19. clz r0, r0
  20. JMP(lr)
  21. #else
  22. // Assumption: n != 0
  23. // r0: n
  24. // r1: count of leading zeros in n + 1
  25. // r2: scratch register for shifted r0
  26. mov r1, 1
  27. // Basic block:
  28. // if ((r0 >> SHIFT) == 0)
  29. // r1 += SHIFT;
  30. // else
  31. // r0 >>= SHIFT;
  32. // for descending powers of two as SHIFT.
  33. #define BLOCK(shift) \
  34. lsrs r2, r0, shift; \
  35. movne r0, r2; \
  36. addeq r1, shift \
  37. BLOCK(16)
  38. BLOCK(8)
  39. BLOCK(4)
  40. BLOCK(2)
  41. // The basic block invariants at this point are (r0 >> 2) == 0 and
  42. // r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
  43. //
  44. // r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
  45. // ---+----------------+----------------+------------+--------------
  46. // 1 | 1 | 0 | 0 | 1
  47. // 2 | 0 | 1 | -1 | 0
  48. // 3 | 0 | 1 | -1 | 0
  49. //
  50. // The r1's initial value of 1 compensates for the 1 here.
  51. sub r0, r1, r0, lsr #1
  52. JMP(lr)
  53. #endif // __ARM_FEATURE_CLZ
  54. END_COMPILERRT_FUNCTION(__clzsi2)
  55. NO_EXEC_STACK_DIRECTIVE