summaryrefslogtreecommitdiffstats
path: root/arch/hexagon/mm/strnlen_user.S
blob: 4b5574a7cc9cfac19eb953606db48147fae10e8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * User string length functions for kernel
 *
 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
 */

#define isrc	r0
#define max	r1	/*  Do not change!  */

#define end	r2
#define tmp1	r3

#define obo	r6	/*  off-by-one  */
#define start	r7
#define mod8	r8
#define dbuf    r15:14
#define dcmp	r13:12

/*
 * The vector mask version of this turned out *really* badly.
 * The hardware loop version also turned out *really* badly.
 * Seems straight pointer arithmetic basically wins here.
 */

#define fname __strnlen_user

	.text
	.global fname
	.type fname, @function
	.p2align 5  /*  why?  */
fname:
	{
		mod8 = and(isrc,#7);
		end = add(isrc,max);
		start = isrc;
	}
	{
		P0 = cmp.eq(mod8,#0);
		mod8 = and(end,#7);
		dcmp = #0;
		if (P0.new) jump:t dw_loop;	/*  fire up the oven  */
	}

alignment_loop:
fail_1:	{
		tmp1 = memb(start++#1);
	}
	{
		P0 = cmp.eq(tmp1,#0);
		if (P0.new) jump:nt exit_found;
		P1 = cmp.gtu(end,start);
		mod8 = and(start,#7);
	}
	{
		if (!P1) jump exit_error;  /*  hit the end  */
		P0 = cmp.eq(mod8,#0);
	}
	{
		if (!P0) jump alignment_loop;
	}



dw_loop:
fail_2:	{
		dbuf = memd(start);
		obo = add(start,#1);
	}
	{
		P0 = vcmpb.eq(dbuf,dcmp);
	}
	{
		tmp1 = P0;
		P0 = cmp.gtu(end,start);
	}
	{
		tmp1 = ct0(tmp1);
		mod8 = and(end,#7);
		if (!P0) jump end_check;
	}
	{
		P0 = cmp.eq(tmp1,#32);
		if (!P0.new) jump:nt exit_found;
		if (!P0.new) start = add(obo,tmp1);
	}
	{
		start = add(start,#8);
		jump dw_loop;
	}	/*  might be nice to combine these jumps...   */


end_check:
	{
		P0 = cmp.gt(tmp1,mod8);
		if (P0.new) jump:nt exit_error;	/*  neverfound!  */
		start = add(obo,tmp1);
	}

exit_found:
	{
		R0 = sub(start,isrc);
		jumpr R31;
	}

exit_error:
	{
		R0 = add(max,#1);
		jumpr R31;
	}

	/*  Uh, what does the "fixup" return here?  */
	.falign
fix_1:
	{
		R0 = #0;
		jumpr R31;
	}

	.size fname,.-fname


.section __ex_table,"a"
.long fail_1,fix_1
.long fail_2,fix_1
.previous