Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jesse/openvswitch
[sfrench/cifs-2.6.git] / arch / hexagon / mm / strnlen_user.S
1 /*
2  * User string length functions for kernel
3  *
4  * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 and
8  * only version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA.
19  */
20
21 #define isrc    r0
22 #define max     r1      /*  Do not change!  */
23
24 #define end     r2
25 #define tmp1    r3
26
27 #define obo     r6      /*  off-by-one  */
28 #define start   r7
29 #define mod8    r8
30 #define dbuf    r15:14
31 #define dcmp    r13:12
32
33 /*
34  * The vector mask version of this turned out *really* badly.
35  * The hardware loop version also turned out *really* badly.
36  * Seems straight pointer arithmetic basically wins here.
37  */
38
39 #define fname __strnlen_user
40
41         .text
42         .global fname
43         .type fname, @function
44         .p2align 5  /*  why?  */
45 fname:
46         {
47                 mod8 = and(isrc,#7);
48                 end = add(isrc,max);
49                 start = isrc;
50         }
51         {
52                 P0 = cmp.eq(mod8,#0);
53                 mod8 = and(end,#7);
54                 dcmp = #0;
55                 if (P0.new) jump:t dw_loop;     /*  fire up the oven  */
56         }
57
58 alignment_loop:
59 fail_1: {
60                 tmp1 = memb(start++#1);
61         }
62         {
63                 P0 = cmp.eq(tmp1,#0);
64                 if (P0.new) jump:nt exit_found;
65                 P1 = cmp.gtu(end,start);
66                 mod8 = and(start,#7);
67         }
68         {
69                 if (!P1) jump exit_error;  /*  hit the end  */
70                 P0 = cmp.eq(mod8,#0);
71         }
72         {
73                 if (!P0) jump alignment_loop;
74         }
75
76
77
78 dw_loop:
79 fail_2: {
80                 dbuf = memd(start);
81                 obo = add(start,#1);
82         }
83         {
84                 P0 = vcmpb.eq(dbuf,dcmp);
85         }
86         {
87                 tmp1 = P0;
88                 P0 = cmp.gtu(end,start);
89         }
90         {
91                 tmp1 = ct0(tmp1);
92                 mod8 = and(end,#7);
93                 if (!P0) jump end_check;
94         }
95         {
96                 P0 = cmp.eq(tmp1,#32);
97                 if (!P0.new) jump:nt exit_found;
98                 if (!P0.new) start = add(obo,tmp1);
99         }
100         {
101                 start = add(start,#8);
102                 jump dw_loop;
103         }       /*  might be nice to combine these jumps...   */
104
105
106 end_check:
107         {
108                 P0 = cmp.gt(tmp1,mod8);
109                 if (P0.new) jump:nt exit_error; /*  neverfound!  */
110                 start = add(obo,tmp1);
111         }
112
113 exit_found:
114         {
115                 R0 = sub(start,isrc);
116                 jumpr R31;
117         }
118
119 exit_error:
120         {
121                 R0 = add(max,#1);
122                 jumpr R31;
123         }
124
125         /*  Uh, what does the "fixup" return here?  */
126         .falign
127 fix_1:
128         {
129                 R0 = #0;
130                 jumpr R31;
131         }
132
133         .size fname,.-fname
134
135
136 .section __ex_table,"a"
137 .long fail_1,fix_1
138 .long fail_2,fix_1
139 .previous