memchr.S 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. ! Copyright (C) 2013 Imagination Technologies Ltd.
  2. !
  3. ! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
  4. .text
  5. .global _memchr
  6. .type _memchr,function
  7. ! D0Ar6 src
  8. ! D0Ar2 c
  9. ! D1Ar3 n
  10. _memchr:
  11. CMP D1Ar3, #0
  12. BEQ $Lexit_fail
  13. !! convert c to unsigned char
  14. AND D0Ar2,D0Ar2,#0xff
  15. MOV D0Ar6, D1Ar1
  16. MOV D1Ar5, D0Ar6
  17. !! test alignment
  18. AND D1Ar5, D1Ar5, #7
  19. CMP D1Ar5, #0
  20. BNZ $Lunaligned_loop
  21. !! length must be greater than or equal to 8 for aligned loop
  22. CMP D1Ar3, #8
  23. BGE $Laligned_setup
  24. $Lunaligned_loop:
  25. !! get 1 char from s
  26. GETB D0Re0, [D0Ar6++]
  27. !! increase alignment counter
  28. ADD D1Ar5, D1Ar5, #1
  29. !! decrement n
  30. SUB D1Ar3, D1Ar3, #1
  31. !! exit if we have a match
  32. CMP D0Re0, D0Ar2
  33. BZ $Lexit_success1
  34. !! exit if we have hit the end of the string
  35. CMP D1Ar3, #0
  36. BZ $Lexit_fail
  37. !! fall through if the buffer is aligned now
  38. CMP D1Ar5, #8
  39. BNE $Lunaligned_loop
  40. !! fall through if there is more than 8 bytes left
  41. CMP D1Ar3, #8
  42. BLT $Lunaligned_loop
  43. $Laligned_setup:
  44. !! fill the c into 4 bytes
  45. MOV D0Ar4, D0Ar2
  46. LSL D0Ar4, D0Ar4, #8
  47. ADD D0Ar4, D0Ar4, D0Ar2
  48. LSL D0Ar4, D0Ar4, #8
  49. ADD D0Ar4, D0Ar4, D0Ar2
  50. LSL D0Ar4, D0Ar4, #8
  51. ADD D0Ar4, D0Ar4, D0Ar2
  52. !! divide n by 8
  53. MOV D1Ar5, D1Ar3
  54. LSR D1Ar5, D1Ar5, #3
  55. $Laligned_loop:
  56. !! get 8 chars from s
  57. GETL D0Re0, D1Re0, [D0Ar6++]
  58. !! decrement loop counter
  59. SUB D1Ar5, D1Ar5, #1
  60. !! test first 4 chars
  61. XOR D0Re0, D0Re0, D0Ar4
  62. !! test second 4 chars
  63. MOV D0Ar2, D1Re0
  64. XOR D1Re0, D0Ar2, D0Ar4
  65. !! check for matches in the first 4 chars
  66. MOV D0Ar2, D0Re0
  67. ADDT D0Re0, D0Re0, #HI(0xfefefeff)
  68. ADD D0Re0, D0Re0, #LO(0xfefefeff)
  69. XOR D0Ar2, D0Ar2, #-1
  70. AND D0Re0, D0Re0, D0Ar2
  71. ANDMT D0Re0, D0Re0, #HI(0x80808080)
  72. ANDMB D0Re0, D0Re0, #LO(0x80808080)
  73. CMP D0Re0, #0
  74. BNZ $Lmatch_word1
  75. !! check for matches in the second 4 chars
  76. MOV D1Ar1, D1Re0
  77. ADDT D1Re0, D1Re0, #HI(0xfefefeff)
  78. ADD D1Re0, D1Re0, #LO(0xfefefeff)
  79. XOR D1Ar1, D1Ar1, #-1
  80. AND D1Re0, D1Re0, D1Ar1
  81. ANDMT D1Re0, D1Re0, #HI(0x80808080)
  82. ANDMB D1Re0, D1Re0, #LO(0x80808080)
  83. CMP D1Re0, #0
  84. BNZ $Lmatch_word2
  85. !! check if we have reached the end of the buffer
  86. CMP D1Ar5, #0
  87. BNE $Laligned_loop
  88. !! exit if there are no chars left to check
  89. AND D1Ar3, D1Ar3, #7
  90. CMP D1Ar3, #0
  91. BZ $Lexit_fail
  92. !! recover c
  93. AND D0Ar2, D0Ar4, #0xff
  94. $Lbyte_loop:
  95. !! get 1 char from s
  96. GETB D0Re0, [D0Ar6++]
  97. !! decrement n
  98. SUB D1Ar3, D1Ar3, #1
  99. !! exit if we have a match
  100. CMP D0Re0, D0Ar2
  101. BZ $Lexit_success1
  102. !! fall through if we have run out of chars
  103. CMP D1Ar3, #0
  104. BNE $Lbyte_loop
  105. $Lexit_fail:
  106. MOV D0Re0, #0
  107. B $Lend
  108. $Lmatch_word1:
  109. !! move the match word into D1Re0
  110. MOV D1Re0, D0Re0
  111. !! roll back the buffer pointer by 4 chars
  112. SUB D0Ar6, D0Ar6, #4
  113. $Lmatch_word2:
  114. !! roll back the buffer pointer by 4 chars
  115. SUB D0Ar6, D0Ar6, #4
  116. !! exit if lowest byte is 0
  117. MOV D1Ar1, D1Re0
  118. AND D1Ar1, D1Ar1, #0xff
  119. CMP D1Ar1, #0
  120. BNE $Lexit_success2
  121. !! advance buffer pointer to the next char
  122. ADD D0Ar6, D0Ar6, #1
  123. !! shift in the next lowest byte
  124. LSR D1Re0, D1Re0, #8
  125. !! exit if lowest byte is 0
  126. MOV D1Ar1, D1Re0
  127. AND D1Ar1, D1Ar1, #0xff
  128. CMP D1Ar1, #0
  129. BNE $Lexit_success2
  130. !! advance buffer pointer to the next char
  131. ADD D0Ar6, D0Ar6, #1
  132. !! shift in the next lowest byte
  133. LSR D1Re0, D1Re0, #8
  134. !! exit if lowest byte is 0
  135. MOV D1Ar1, D1Re0
  136. AND D1Ar1, D1Ar1, #0xff
  137. CMP D1Ar1, #0
  138. BNE $Lexit_success2
  139. !! the match must be in the last byte, exit
  140. ADD D0Ar6, D0Ar6, #1
  141. B $Lexit_success2
  142. $Lexit_success1:
  143. SUB D0Ar6, D0Ar6, #1
  144. $Lexit_success2:
  145. !! return the buffer pointer
  146. MOV D0Re0, D0Ar6
  147. $Lend:
  148. MOV PC, D1RtP
  149. .size _memchr,.-_memchr
  150. libc_hidden_def(memchr)