strcmp.S 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* Copyright (C) 2012-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library. If not, see
  13. <https://www.gnu.org/licenses/>. */
  14. /* Assumptions:
  15. *
  16. * ARMv8-a, AArch64.
  17. * MTE compatible.
  18. */
  19. #include <sysdep.h>
  20. #define REP8_01 0x0101010101010101
  21. #define REP8_7f 0x7f7f7f7f7f7f7f7f
  22. /* Parameters and result. */
  23. #define src1 x0
  24. #define src2 x1
  25. #define result x0
  26. /* Internal variables. */
  27. #define data1 x2
  28. #define data1w w2
  29. #define data2 x3
  30. #define data2w w3
  31. #define has_nul x4
  32. #define diff x5
  33. #define off1 x5
  34. #define syndrome x6
  35. #define tmp x6
  36. #define data3 x7
  37. #define zeroones x8
  38. #define shift x9
  39. #define off2 x10
  40. /* On big-endian early bytes are at MSB and on little-endian LSB.
  41. LS_FW means shifting towards early bytes. */
  42. #ifdef __AARCH64EB__
  43. # define LS_FW lsl
  44. #else
  45. # define LS_FW lsr
  46. #endif
  47. /* NUL detection works on the principle that (X - 1) & (~X) & 0x80
  48. (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
  49. can be done in parallel across the entire word.
  50. Since carry propagation makes 0x1 bytes before a NUL byte appear
  51. NUL too in big-endian, byte-reverse the data before the NUL check. */
  52. ENTRY(strcmp)
  53. sub off2, src2, src1
  54. mov zeroones, REP8_01
  55. and tmp, src1, 7
  56. tst off2, 7
  57. b.ne L(misaligned8)
  58. cbnz tmp, L(mutual_align)
  59. .p2align 4
  60. L(loop_aligned):
  61. ldr data2, [src1, off2]
  62. ldr data1, [src1], 8
  63. L(start_realigned):
  64. #ifdef __AARCH64EB__
  65. rev tmp, data1
  66. sub has_nul, tmp, zeroones
  67. orr tmp, tmp, REP8_7f
  68. #else
  69. sub has_nul, data1, zeroones
  70. orr tmp, data1, REP8_7f
  71. #endif
  72. bics has_nul, has_nul, tmp /* Non-zero if NUL terminator. */
  73. ccmp data1, data2, 0, eq
  74. b.eq L(loop_aligned)
  75. #ifdef __AARCH64EB__
  76. rev has_nul, has_nul
  77. #endif
  78. eor diff, data1, data2
  79. orr syndrome, diff, has_nul
  80. L(end):
  81. #ifndef __AARCH64EB__
  82. rev syndrome, syndrome
  83. rev data1, data1
  84. rev data2, data2
  85. #endif
  86. clz shift, syndrome
  87. /* The most-significant-non-zero bit of the syndrome marks either the
  88. first bit that is different, or the top bit of the first zero byte.
  89. Shifting left now will bring the critical information into the
  90. top bits. */
  91. lsl data1, data1, shift
  92. lsl data2, data2, shift
  93. /* But we need to zero-extend (char is unsigned) the value and then
  94. perform a signed 32-bit subtraction. */
  95. lsr data1, data1, 56
  96. sub result, data1, data2, lsr 56
  97. ret
  98. .p2align 4
  99. L(mutual_align):
  100. /* Sources are mutually aligned, but are not currently at an
  101. alignment boundary. Round down the addresses and then mask off
  102. the bytes that precede the start point. */
  103. bic src1, src1, 7
  104. ldr data2, [src1, off2]
  105. ldr data1, [src1], 8
  106. neg shift, src2, lsl 3 /* Bits to alignment -64. */
  107. mov tmp, -1
  108. LS_FW tmp, tmp, shift
  109. orr data1, data1, tmp
  110. orr data2, data2, tmp
  111. b L(start_realigned)
  112. L(misaligned8):
  113. /* Align SRC1 to 8 bytes and then compare 8 bytes at a time, always
  114. checking to make sure that we don't access beyond the end of SRC2. */
  115. cbz tmp, L(src1_aligned)
  116. L(do_misaligned):
  117. ldrb data1w, [src1], 1
  118. ldrb data2w, [src2], 1
  119. cmp data1w, 0
  120. ccmp data1w, data2w, 0, ne /* NZCV = 0b0000. */
  121. b.ne L(done)
  122. tst src1, 7
  123. b.ne L(do_misaligned)
  124. L(src1_aligned):
  125. neg shift, src2, lsl 3
  126. bic src2, src2, 7
  127. ldr data3, [src2], 8
  128. #ifdef __AARCH64EB__
  129. rev data3, data3
  130. #endif
  131. lsr tmp, zeroones, shift
  132. orr data3, data3, tmp
  133. sub has_nul, data3, zeroones
  134. orr tmp, data3, REP8_7f
  135. bics has_nul, has_nul, tmp
  136. b.ne L(tail)
  137. sub off1, src2, src1
  138. .p2align 4
  139. L(loop_unaligned):
  140. ldr data3, [src1, off1]
  141. ldr data2, [src1, off2]
  142. #ifdef __AARCH64EB__
  143. rev data3, data3
  144. #endif
  145. sub has_nul, data3, zeroones
  146. orr tmp, data3, REP8_7f
  147. ldr data1, [src1], 8
  148. bics has_nul, has_nul, tmp
  149. ccmp data1, data2, 0, eq
  150. b.eq L(loop_unaligned)
  151. lsl tmp, has_nul, shift
  152. #ifdef __AARCH64EB__
  153. rev tmp, tmp
  154. #endif
  155. eor diff, data1, data2
  156. orr syndrome, diff, tmp
  157. cbnz syndrome, L(end)
  158. L(tail):
  159. ldr data1, [src1]
  160. neg shift, shift
  161. lsr data2, data3, shift
  162. lsr has_nul, has_nul, shift
  163. #ifdef __AARCH64EB__
  164. rev data2, data2
  165. rev has_nul, has_nul
  166. #endif
  167. eor diff, data1, data2
  168. orr syndrome, diff, has_nul
  169. b L(end)
  170. L(done):
  171. sub result, data1, data2
  172. ret
  173. END(strcmp)
  174. libc_hidden_builtin_def (strcmp)