GNU Linux-libre 6.8.7-gnu
[releases.git] / arch / riscv / lib / strncmp.S
1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <linux/linkage.h>
4 #include <asm/asm.h>
5 #include <asm/alternative-macros.h>
6 #include <asm/hwcap.h>
7
8 /* int strncmp(const char *cs, const char *ct, size_t count) */
9 SYM_FUNC_START(strncmp)
10
11         ALTERNATIVE("nop", "j strncmp_zbb", 0, RISCV_ISA_EXT_ZBB, CONFIG_RISCV_ISA_ZBB)
12
13         /*
14          * Returns
15          *   a0 - comparison result, value like strncmp
16          *
17          * Parameters
18          *   a0 - string1
19          *   a1 - string2
20          *   a2 - number of characters to compare
21          *
22          * Clobbers
23          *   t0, t1, t2
24          */
25         li      t2, 0
26 1:
27         beq     a2, t2, 2f
28         lbu     t0, 0(a0)
29         lbu     t1, 0(a1)
30         addi    a0, a0, 1
31         addi    a1, a1, 1
32         bne     t0, t1, 3f
33         addi    t2, t2, 1
34         bnez    t0, 1b
35 2:
36         li      a0, 0
37         ret
38 3:
39         /*
40          * strncmp only needs to return (< 0, 0, > 0) values
41          * not necessarily -1, 0, +1
42          */
43         sub     a0, t0, t1
44         ret
45
46 /*
47  * Variant of strncmp using the ZBB extension if available
48  */
49 #ifdef CONFIG_RISCV_ISA_ZBB
50 strncmp_zbb:
51
52 .option push
53 .option arch,+zbb
54
55         /*
56          * Returns
57          *   a0 - comparison result, like strncmp
58          *
59          * Parameters
60          *   a0 - string1
61          *   a1 - string2
62          *   a2 - number of characters to compare
63          *
64          * Clobbers
65          *   t0, t1, t2, t3, t4, t5, t6
66          */
67
68         or      t2, a0, a1
69         li      t5, -1
70         and     t2, t2, SZREG-1
71         add     t4, a0, a2
72         bnez    t2, 3f
73
74         /* Adjust limit for fast-path.  */
75         andi    t6, t4, -SZREG
76
77         /* Main loop for aligned string.  */
78         .p2align 3
79 1:
80         bge     a0, t6, 3f
81         REG_L   t0, 0(a0)
82         REG_L   t1, 0(a1)
83         orc.b   t3, t0
84         bne     t3, t5, 2f
85         orc.b   t3, t1
86         bne     t3, t5, 2f
87         addi    a0, a0, SZREG
88         addi    a1, a1, SZREG
89         beq     t0, t1, 1b
90
91         /*
92          * Words don't match, and no null byte in the first
93          * word. Get bytes in big-endian order and compare.
94          */
95 #ifndef CONFIG_CPU_BIG_ENDIAN
96         rev8    t0, t0
97         rev8    t1, t1
98 #endif
99
100         /* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence.  */
101         sltu    a0, t0, t1
102         neg     a0, a0
103         ori     a0, a0, 1
104         ret
105
106 2:
107         /*
108          * Found a null byte.
109          * If words don't match, fall back to simple loop.
110          */
111         bne     t0, t1, 3f
112
113         /* Otherwise, strings are equal.  */
114         li      a0, 0
115         ret
116
117         /* Simple loop for misaligned strings.  */
118         .p2align 3
119 3:
120         bge     a0, t4, 5f
121         lbu     t0, 0(a0)
122         lbu     t1, 0(a1)
123         addi    a0, a0, 1
124         addi    a1, a1, 1
125         bne     t0, t1, 4f
126         bnez    t0, 3b
127
128 4:
129         sub     a0, t0, t1
130         ret
131
132 5:
133         li      a0, 0
134         ret
135
136 .option pop
137 #endif
138 SYM_FUNC_END(strncmp)