| /* |
| * 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 |