Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / arch / m32r / lib / strlen.S
1 /*
2  *  linux/arch/m32r/strlen.S --  strlen code.
3  *
4  *  Copyright (C) 2001  Hirokazu Takata
5  *
6  *  size_t strlen(const char *s);
7  *
8  */
9
10 #include <linux/linkage.h>
11 #include <asm/assembler.h>
12
13 #ifdef CONFIG_ISA_DUAL_ISSUE
14
15         .text
16 ENTRY(strlen)
17         mv      r6, r0              ||  ldi     r2, #0
18         and3    r0, r0, #3
19         bnez    r0, strlen_byte
20 ;
21 strlen_word:
22         ld      r0, @r6+
23 ;
24         seth    r5, #high(0x01010101)
25         or3     r5, r5, #low(0x01010101)
26         sll3    r7, r5, #7
27 strlen_word_loop:
28         ld      r1, @r6+            ||  not     r4, r0
29         sub     r0, r5              ||  and     r4, r7
30         and     r4, r0
31         bnez    r4, strlen_last_bytes
32         ld      r0, @r6+            ||  not     r4, r1
33         sub     r1, r5              ||  and     r4, r7
34         and     r4, r1              ||  addi    r2, #4
35         bnez    r4, strlen_last_bytes
36         addi    r2, #4              ||  bra.s   strlen_word_loop
37
38         ; NOTE: If a null char. exists, return 0.
39         ; if ((x - 0x01010101) & ~x & 0x80808080)
40         ;     return 0;
41 ;
42 strlen_byte:
43         ldb     r1, @r6             ||  addi    r6, #1
44         beqz    r1, strlen_exit
45         addi    r2, #1              ||  bra.s   strlen_byte
46 ;
47 strlen_last_bytes:
48         ldi     r0, #4              ||  addi    r6, #-8
49 ;
50 strlen_byte_loop:
51         ldb     r1, @r6             ||  addi    r6, #1
52         addi    r0, #-1             ||  cmpz    r1
53         bc.s    strlen_exit         ||  cmpz    r0
54         addi    r2, #1              ||  bnc.s   strlen_byte_loop
55 ;
56 strlen_exit:
57         mv      r0, r2              ||  jmp     r14
58
59 #else /* not CONFIG_ISA_DUAL_ISSUE */
60
61         .text
62 ENTRY(strlen)
63         mv      r6, r0
64         ldi     r2, #0
65         and3    r0, r0, #3
66         bnez    r0, strlen_byte
67 ;
68 strlen_word:
69         ld      r0, @r6+
70 ;
71         seth    r5, #high(0x01010101)
72         or3     r5, r5, #low(0x01010101)
73         sll3    r7, r5, #7
74 strlen_word_loop:
75         ld      r1, @r6+
76         not     r4, r0          ; NOTE: If a null char. exists, return 0.
77         sub     r0, r5          ; if ((x - 0x01010101) & ~x & 0x80808080)
78         and     r4, r7          ;     return 0;
79         and     r4, r0
80         bnez    r4, strlen_last_bytes
81         addi    r2, #4
82 ;
83         ld      r0, @r6+
84         not     r4, r1          ; NOTE: If a null char. exists, return 0.
85         sub     r1, r5          ; if ((x - 0x01010101) & ~x & 0x80808080)
86         and     r4, r7          ;     return 0;
87         and     r4, r1
88         bnez    r4, strlen_last_bytes
89         addi    r2, #4
90         bra     strlen_word_loop
91 ;
92 strlen_byte:
93         ldb     r1, @r6
94         addi    r6, #1
95         beqz    r1, strlen_exit
96         addi    r2, #1
97         bra     strlen_byte
98 ;
99 strlen_last_bytes:
100         ldi     r0, #4
101         addi    r6, #-8
102 ;
103 strlen_byte_loop:
104         ldb     r1, @r6
105         addi    r6, #1
106         addi    r0, #-1
107         beqz    r1, strlen_exit
108         addi    r2, #1
109         bnez    r0, strlen_byte_loop
110 ;
111 strlen_exit:
112         mv      r0, r2
113         jmp     r14
114
115 #endif /* not CONFIG_ISA_DUAL_ISSUE */
116
117         .end