strlen.S 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. #include <linux/linkage.h>
  3. #include <asm/asm.h>
  4. #include <asm/alternative-macros.h>
  5. #include <asm/hwcap.h>
  6. /* int strlen(const char *s) */
  7. SYM_FUNC_START(strlen)
  8. ALTERNATIVE("nop", "j strlen_zbb", 0, RISCV_ISA_EXT_ZBB, CONFIG_RISCV_ISA_ZBB)
  9. /*
  10. * Returns
  11. * a0 - string length
  12. *
  13. * Parameters
  14. * a0 - String to measure
  15. *
  16. * Clobbers:
  17. * t0, t1
  18. */
  19. mv t1, a0
  20. 1:
  21. lbu t0, 0(t1)
  22. beqz t0, 2f
  23. addi t1, t1, 1
  24. j 1b
  25. 2:
  26. sub a0, t1, a0
  27. ret
  28. /*
  29. * Variant of strlen using the ZBB extension if available
  30. */
  31. #ifdef CONFIG_RISCV_ISA_ZBB
  32. strlen_zbb:
  33. #ifdef CONFIG_CPU_BIG_ENDIAN
  34. # define CZ clz
  35. # define SHIFT sll
  36. #else
  37. # define CZ ctz
  38. # define SHIFT srl
  39. #endif
  40. .option push
  41. .option arch,+zbb
  42. /*
  43. * Returns
  44. * a0 - string length
  45. *
  46. * Parameters
  47. * a0 - String to measure
  48. *
  49. * Clobbers
  50. * t0, t1, t2, t3
  51. */
  52. /* Number of irrelevant bytes in the first word. */
  53. andi t2, a0, SZREG-1
  54. /* Align pointer. */
  55. andi t0, a0, -SZREG
  56. li t3, SZREG
  57. sub t3, t3, t2
  58. slli t2, t2, 3
  59. /* Get the first word. */
  60. REG_L t1, 0(t0)
  61. /*
  62. * Shift away the partial data we loaded to remove the irrelevant bytes
  63. * preceding the string with the effect of adding NUL bytes at the
  64. * end of the string's first word.
  65. */
  66. SHIFT t1, t1, t2
  67. /* Convert non-NUL into 0xff and NUL into 0x00. */
  68. orc.b t1, t1
  69. /* Convert non-NUL into 0x00 and NUL into 0xff. */
  70. not t1, t1
  71. /*
  72. * Search for the first set bit (corresponding to a NUL byte in the
  73. * original chunk).
  74. */
  75. CZ t1, t1
  76. /*
  77. * The first chunk is special: compare against the number
  78. * of valid bytes in this chunk.
  79. */
  80. srli a0, t1, 3
  81. bgtu t3, a0, 2f
  82. /* Prepare for the word comparison loop. */
  83. addi t2, t0, SZREG
  84. li t3, -1
  85. /*
  86. * Our critical loop is 4 instructions and processes data in
  87. * 4 byte or 8 byte chunks.
  88. */
  89. .p2align 3
  90. 1:
  91. REG_L t1, SZREG(t0)
  92. addi t0, t0, SZREG
  93. orc.b t1, t1
  94. beq t1, t3, 1b
  95. not t1, t1
  96. CZ t1, t1
  97. srli t1, t1, 3
  98. /* Get number of processed bytes. */
  99. sub t2, t0, t2
  100. /* Add number of characters in the first word. */
  101. add a0, a0, t2
  102. /* Add number of characters in the last word. */
  103. add a0, a0, t1
  104. 2:
  105. ret
  106. .option pop
  107. #endif
  108. SYM_FUNC_END(strlen)
  109. SYM_FUNC_ALIAS(__pi_strlen, strlen)
  110. EXPORT_SYMBOL(strlen)