^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * arch/alpha/lib/ev67-strchr.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Return the address of a given character within a null-terminated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * string, or null if it is not found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Much of the information about 21264 scheduling/coding comes from:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Compiler Writer's Guide for the Alpha 21264
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * abbreviated as 'CWG' in other comments here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Scheduling notation:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * E - either cluster
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Try not to change the actual algorithm if possible for consistency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/regdef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) .set noreorder
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) .set noat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) .align 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) .globl strchr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) .ent strchr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) strchr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) .frame sp, 0, ra
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) .prologue 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) ldq_u t0, 0(a0) # L : load first quadword Latency=3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) and a1, 0xff, t3 # E : 00000000000000ch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) insbl a1, 1, t5 # U : 000000000000ch00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) insbl a1, 7, a2 # U : ch00000000000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) insbl t3, 6, a3 # U : 00ch000000000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) or t5, t3, a1 # E : 000000000000chch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) andnot a0, 7, v0 # E : align our loop pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) lda t4, -1 # E : build garbage mask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) mskqh t4, a0, t4 # U : only want relevant part of first quad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) or a2, a3, a2 # E : chch000000000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) inswl a1, 2, t5 # E : 00000000chch0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) inswl a1, 4, a3 # E : 0000chch00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) or a1, a2, a1 # E : chch00000000chch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) or a3, t5, t5 # E : 0000chchchch0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) cmpbge zero, t0, t2 # E : bits set iff byte == zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) cmpbge zero, t4, t4 # E : bits set iff byte is garbage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* This quad is _very_ serialized. Lots of stalling happens */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) or t5, a1, a1 # E : chchchchchchchch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) xor t0, a1, t1 # E : make bytes == c zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) cmpbge zero, t1, t3 # E : bits set iff byte == c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) or t2, t3, t0 # E : bits set iff char match or zero match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) andnot t0, t4, t0 # E : clear garbage bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) cttz t0, a2 # U0 : speculative (in case we get a match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) nop # E :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) bne t0, $found # U :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * Yuk. This loop is going to stall like crazy waiting for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * data to be loaded. Not much can be done about it unless it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * unrolled multiple times - is that safe to do in kernel space?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * Or would exception handling recovery code do the trick here?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) $loop: ldq t0, 8(v0) # L : Latency=3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) addq v0, 8, v0 # E :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) xor t0, a1, t1 # E :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) cmpbge zero, t0, t2 # E : bits set iff byte == 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) cmpbge zero, t1, t3 # E : bits set iff byte == c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) or t2, t3, t0 # E :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) cttz t3, a2 # U0 : speculative (in case we get a match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) beq t0, $loop # U :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) $found: negq t0, t1 # E : clear all but least set bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) and t0, t1, t0 # E :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) and t0, t3, t1 # E : bit set iff byte was the char
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) addq v0, a2, v0 # E : Add in the bit number from above
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) cmoveq t1, $31, v0 # E : Two mapping slots, latency = 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) nop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) nop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ret # L0 :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .end strchr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) EXPORT_SYMBOL(strchr)