summaryrefslogtreecommitdiff
path: root/libc/string/metag/strchr.S
diff options
context:
space:
mode:
Diffstat (limited to 'libc/string/metag/strchr.S')
-rw-r--r--libc/string/metag/strchr.S167
1 files changed, 167 insertions, 0 deletions
diff --git a/libc/string/metag/strchr.S b/libc/string/metag/strchr.S
new file mode 100644
index 000000000..6b0f2ea43
--- /dev/null
+++ b/libc/string/metag/strchr.S
@@ -0,0 +1,167 @@
+! Copyright (C) 2013 Imagination Technologies Ltd.
+
+! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+
+
+#include <features.h>
+
+ .text
+ .global _strchr
+ .type _strchr, function
+! D1Ar1 src
+! D0Ar2 c
+_strchr:
+ AND D0Ar2,D0Ar2,#0xff ! Drop all but 8 bits of c
+ MOV D1Ar5, D1Ar1 ! Copy src to D1Ar5
+ AND D1Ar5, D1Ar5, #7 ! Check 64 bit alignment
+ CMP D1Ar5, #0
+ BZ $Laligned64bit ! Jump to 64 bit aligned strchr
+$Lalign64bit:
+ GETB D0Re0, [D1Ar1++] ! Get the next character
+ ADD D1Ar5, D1Ar5, #1 ! Increment alignment counter
+ CMP D0Re0, D0Ar2 ! Is the char c
+ BZ $Lcharatprevious ! If so exit returning position
+ CMP D0Re0, #0 ! End of string?
+ BZ $Lnotfound ! If so exit
+ CMP D1Ar5, #8 ! Are we aligned 64bit yet?
+ BNZ $Lalign64bit ! If not keep aligning
+$Laligned64bit: ! src is 64bit aligned
+ MOV D0Ar4, D0Ar2 ! put c into D0Ar4
+ LSL D0Ar4, D0Ar4, #8 ! Shift it up
+ ADD D0Ar4, D0Ar4, D0Ar2 ! another c
+ LSL D0Ar4, D0Ar4, #8 ! shift
+ ADD D0Ar4, D0Ar4, D0Ar2 ! another c
+ LSL D0Ar4, D0Ar4, #8 ! shift
+ ADD D0Ar4, D0Ar4, D0Ar2 ! 4 copies of c
+$Lcheck8bytes:
+ GETL D0Re0, D1Re0, [D1Ar1++] ! grab 16 bytes
+ MOV A0.3, D0Re0 ! save for later use
+ ! first word
+ ! check for \0
+ MOV D0Ar2, D0Re0 ! D0Ar2 is a scratch now
+ ADDT D0Re0, D0Re0, #HI(0xfefefeff) ! Do 4 1-byte compares
+ ADD D0Re0, D0Re0, #LO(0xfefefeff)
+ XOR D0Ar2, D0Ar2, #-1
+ AND D0Re0, D0Re0, D0Ar2
+ ANDMT D0Re0, D0Re0, #HI(0x80808080)
+ ANDMB D0Re0, D0Re0, #LO(0x80808080)
+ CMP D0Re0, #0
+ BNZ $Lnullinword1 ! found \0 (or c if c==\0)
+
+ ! Check for c
+ MOV D0Re0, A0.3 ! restore the first word
+ XOR D0Re0, D0Re0, D0Ar4
+ MOV D0Ar2, D0Re0 ! DO 4 1-byte compares
+ ADDT D0Re0, D0Re0, #HI(0xfefefeff)
+ ADD D0Re0, D0Re0, #LO(0xfefefeff)
+ XOR D0Ar2, D0Ar2, #-1
+ AND D0Re0, D0Re0, D0Ar2
+ ANDMT D0Re0, D0Re0, #HI(0x80808080)
+ ANDMB D0Re0, D0Re0, #LO(0x80808080)
+ CMP D0Re0, #0
+ BNZ $Lcharinword1 ! found c
+
+ ! second word
+ ! check for \0
+ MOV A0.3, D1Re0 ! save for later use
+ MOV D1Ar3, D1Re0
+ ADDT D1Re0, D1Re0, #HI(0xfefefeff) ! Do 4 1-byte compares
+ ADD D1Re0, D1Re0, #LO(0xfefefeff)
+ XOR D1Ar3, D1Ar3, #-1
+ AND D1Re0, D1Re0, D1Ar3
+ ANDMT D1Re0, D1Re0, #HI(0x80808080)
+ ANDMB D1Re0, D1Re0, #LO(0x80808080)
+ CMP D1Re0, #0
+ BNZ $Lnullinword2 ! Found \0 (or c if c==\0)
+
+ MOV D0.4, A0.3 ! restore the second word
+ XOR D1Re0, D0.4, D0Ar4 ! test c
+
+ MOV D1Ar3, D1Re0
+ ADDT D1Re0, D1Re0, #HI(0xfefefeff) ! Do 4 1-byte compares
+ ADD D1Re0, D1Re0, #LO(0xfefefeff)
+ XOR D1Ar3, D1Ar3, #-1
+ AND D1Re0, D1Re0, D1Ar3
+ ANDMT D1Re0, D1Re0, #HI(0x80808080)
+ ANDMB D1Re0, D1Re0, #LO(0x80808080)
+ CMP D1Re0, #0
+ BNZ $Lcharinword2 ! found c
+
+ B $Lcheck8bytes ! Keep checking
+
+$Lnullinword1: ! found \0 somewhere, check for c too
+ SUB D1Ar1, D1Ar1, #4
+$Lnullinword2:
+ SUB D1Ar1, D1Ar1, #4
+ AND D0Ar2, D0Ar4, #0xff ! restore c
+ MOV D0Re0, A0.3 ! restore the word
+ MOV D0.4, D0Re0 ! for shifting later
+ AND D0Re0, D0Re0, #0xff ! take first byte of word
+ CMP D0Re0, D0Ar2
+ BZ $Lcharatcurrent ! found c
+ CMP D0Re0, #0!
+ BZ $Lnotfound ! found \0
+
+ ADD D1Ar1, D1Ar1, #1
+ LSR D0.4, D0.4, #8
+ MOV D0Re0, D0.4
+ AND D0Re0, D0Re0, #0xff ! take second byte of word
+ CMP D0Re0, D0Ar2
+ BZ $Lcharatcurrent ! found c
+ CMP D0Re0, #0
+ BZ $Lnotfound ! found \0
+
+ ADD D1Ar1, D1Ar1, #1
+ LSR D0.4, D0.4, #8
+ MOV D0Re0, D0.4
+ AND D0Re0, D0Re0, #0xff ! take third byte of word
+ CMP D0Re0, D0Ar2
+ BZ $Lcharatcurrent ! found c
+ CMP D0Re0, #0
+ BZ $Lnotfound ! found \0
+
+ ADD D1Ar1, D1Ar1, #1 ! move to 4th byte
+ CMP D0Ar2, #0 ! If c was \0
+ BZ $Lcharatcurrent ! c has been found!
+
+$Lnotfound:
+ MOV D0Re0, #0 ! End of string c not found
+ B $Lend
+
+$Lcharinword1: ! found c in first word
+ MOV D1Re0, D0Re0
+ SUB D1Ar1, D1Ar1, #4
+$Lcharinword2: ! found c in second word
+ SUB D1Ar1, D1Ar1, #4
+
+ AND D0Re0, D1Re0, #0xff ! First byte
+ CMP D0Re0, #0 ! Test c (zero indicates c due
+ ! to the 4 1-byte compare code)
+ BNE $Lcharatcurrent
+ ADD D1Ar1, D1Ar1, #1
+
+ LSR D1Re0, D1Re0, #8
+ AND D0Re0, D1Re0, #0xff ! Second byte
+ CMP D0Re0, #0 ! Test c (indicated by zero)
+ BNE $Lcharatcurrent
+ ADD D1Ar1, D1Ar1, #1
+
+ LSR D1Re0, D1Re0, #8
+ AND D0Re0, D1Re0, #0xff ! Third byte
+ CMP D0Re0, #0 ! Test c (indicated by zero)
+ BNE $Lcharatcurrent
+ ADD D1Ar1, D1Ar1, #1 ! Must be the fourth byte
+ B $Lcharatcurrent
+
+$Lcharatprevious:
+ SUB D1Ar1, D1Ar1, #1 ! Fix-up pointer
+$Lcharatcurrent:
+ MOV D0Re0, D1Ar1 ! Return the string pointer
+$Lend:
+ MOV PC, D1RtP
+ .size _strchr,.-_strchr
+
+libc_hidden_def(strchr)
+#ifdef __UCLIBC_SUSV3_LEGACY__
+strong_alias(strchr,index)
+#endif