forked from Minki/linux
108 lines
2.5 KiB
ArmAsm
108 lines
2.5 KiB
ArmAsm
|
/*
|
||
|
* arch/alpha/lib/ev67-strlen_user.S
|
||
|
* 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
|
||
|
*
|
||
|
* Return the length of the string including the NULL terminator
|
||
|
* (strlen+1) or zero if an error occurred.
|
||
|
*
|
||
|
* In places where it is critical to limit the processing time,
|
||
|
* and the data is not trusted, strnlen_user() should be used.
|
||
|
* It will return a value greater than its second argument if
|
||
|
* that limit would be exceeded. This implementation is allowed
|
||
|
* to access memory beyond the limit, but will not cross a page
|
||
|
* boundary when doing so.
|
||
|
*
|
||
|
* Much of the information about 21264 scheduling/coding comes from:
|
||
|
* Compiler Writer's Guide for the Alpha 21264
|
||
|
* abbreviated as 'CWG' in other comments here
|
||
|
* ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
|
||
|
* Scheduling notation:
|
||
|
* E - either cluster
|
||
|
* U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
|
||
|
* L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
|
||
|
* Try not to change the actual algorithm if possible for consistency.
|
||
|
*/
|
||
|
|
||
|
#include <asm/regdef.h>
|
||
|
|
||
|
|
||
|
/* Allow an exception for an insn; exit if we get one. */
|
||
|
#define EX(x,y...) \
|
||
|
99: x,##y; \
|
||
|
.section __ex_table,"a"; \
|
||
|
.long 99b - .; \
|
||
|
lda v0, $exception-99b(zero); \
|
||
|
.previous
|
||
|
|
||
|
|
||
|
.set noreorder
|
||
|
.set noat
|
||
|
.text
|
||
|
|
||
|
.globl __strlen_user
|
||
|
.ent __strlen_user
|
||
|
.frame sp, 0, ra
|
||
|
|
||
|
.align 4
|
||
|
__strlen_user:
|
||
|
ldah a1, 32767(zero) # do not use plain strlen_user() for strings
|
||
|
# that might be almost 2 GB long; you should
|
||
|
# be using strnlen_user() instead
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
|
||
|
.globl __strnlen_user
|
||
|
|
||
|
.align 4
|
||
|
__strnlen_user:
|
||
|
.prologue 0
|
||
|
EX( ldq_u t0, 0(a0) ) # L : load first quadword (a0 may be misaligned)
|
||
|
lda t1, -1(zero) # E :
|
||
|
|
||
|
insqh t1, a0, t1 # U :
|
||
|
andnot a0, 7, v0 # E :
|
||
|
or t1, t0, t0 # E :
|
||
|
subq a0, 1, a0 # E : get our +1 for the return
|
||
|
|
||
|
cmpbge zero, t0, t1 # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0
|
||
|
subq a1, 7, t2 # E :
|
||
|
subq a0, v0, t0 # E :
|
||
|
bne t1, $found # U :
|
||
|
|
||
|
addq t2, t0, t2 # E :
|
||
|
addq a1, 1, a1 # E :
|
||
|
nop # E :
|
||
|
nop # E :
|
||
|
|
||
|
.align 4
|
||
|
$loop: ble t2, $limit # U :
|
||
|
EX( ldq t0, 8(v0) ) # L :
|
||
|
nop # E :
|
||
|
nop # E :
|
||
|
|
||
|
cmpbge zero, t0, t1 # E :
|
||
|
subq t2, 8, t2 # E :
|
||
|
addq v0, 8, v0 # E : addr += 8
|
||
|
beq t1, $loop # U :
|
||
|
|
||
|
$found: cttz t1, t2 # U0 :
|
||
|
addq v0, t2, v0 # E :
|
||
|
subq v0, a0, v0 # E :
|
||
|
ret # L0 :
|
||
|
|
||
|
$exception:
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
ret
|
||
|
|
||
|
.align 4 # currently redundant
|
||
|
$limit:
|
||
|
nop
|
||
|
nop
|
||
|
subq a1, t2, v0
|
||
|
ret
|
||
|
|
||
|
.end __strlen_user
|