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) |
139 | |