| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| #include <linux/linkage.h> | |
| #include <asm/asm.h> | |
| #include <asm/alternative-macros.h> | |
| #include <asm/hwcap.h> | |
| /* int strncmp(const char *cs, const char *ct, size_t count) */ | |
| SYM_FUNC_START(strncmp) | |
| ALTERNATIVE("nop", "j strncmp_zbb", 0, RISCV_ISA_EXT_ZBB, CONFIG_RISCV_ISA_ZBB) | |
| /* | |
| * Returns | |
| * a0 - comparison result, value like strncmp | |
| * | |
| * Parameters | |
| * a0 - string1 | |
| * a1 - string2 | |
| * a2 - number of characters to compare | |
| * | |
| * Clobbers | |
| * t0, t1, t2 | |
| */ | |
| li t2, 0 | |
| 1: | |
| beq a2, t2, 2f | |
| lbu t0, 0(a0) | |
| lbu t1, 0(a1) | |
| addi a0, a0, 1 | |
| addi a1, a1, 1 | |
| bne t0, t1, 3f | |
| addi t2, t2, 1 | |
| bnez t0, 1b | |
| 2: | |
| li a0, 0 | |
| ret | |
| 3: | |
| /* | |
| * strncmp only needs to return (< 0, 0, > 0) values | |
| * not necessarily -1, 0, +1 | |
| */ | |
| sub a0, t0, t1 | |
| ret | |
| /* | |
| * Variant of strncmp using the ZBB extension if available | |
| */ | |
| #ifdef CONFIG_RISCV_ISA_ZBB | |
| strncmp_zbb: | |
| .option push | |
| .option arch,+zbb | |
| /* | |
| * Returns | |
| * a0 - comparison result, like strncmp | |
| * | |
| * Parameters | |
| * a0 - string1 | |
| * a1 - string2 | |
| * a2 - number of characters to compare | |
| * | |
| * Clobbers | |
| * t0, t1, t2, t3, t4, t5, t6 | |
| */ | |
| or t2, a0, a1 | |
| li t5, -1 | |
| and t2, t2, SZREG-1 | |
| add t4, a0, a2 | |
| bnez t2, 3f | |
| /* Adjust limit for fast-path. */ | |
| andi t6, t4, -SZREG | |
| /* Main loop for aligned string. */ | |
| .p2align 3 | |
| 1: | |
| bge a0, t6, 3f | |
| REG_L t0, 0(a0) | |
| REG_L t1, 0(a1) | |
| orc.b t3, t0 | |
| bne t3, t5, 2f | |
| orc.b t3, t1 | |
| bne t3, t5, 2f | |
| addi a0, a0, SZREG | |
| addi a1, a1, SZREG | |
| beq t0, t1, 1b | |
| /* | |
| * Words don't match, and no null byte in the first | |
| * word. Get bytes in big-endian order and compare. | |
| */ | |
| #ifndef CONFIG_CPU_BIG_ENDIAN | |
| rev8 t0, t0 | |
| rev8 t1, t1 | |
| #endif | |
| /* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence. */ | |
| sltu a0, t0, t1 | |
| neg a0, a0 | |
| ori a0, a0, 1 | |
| ret | |
| 2: | |
| /* | |
| * Found a null byte. | |
| * If words don't match, fall back to simple loop. | |
| */ | |
| bne t0, t1, 3f | |
| /* Otherwise, strings are equal. */ | |
| li a0, 0 | |
| ret | |
| /* Simple loop for misaligned strings. */ | |
| .p2align 3 | |
| 3: | |
| bge a0, t4, 5f | |
| lbu t0, 0(a0) | |
| lbu t1, 0(a1) | |
| addi a0, a0, 1 | |
| addi a1, a1, 1 | |
| bne t0, t1, 4f | |
| bnez t0, 3b | |
| 4: | |
| sub a0, t0, t1 | |
| ret | |
| 5: | |
| li a0, 0 | |
| ret | |
| .option pop | |
| #endif | |
| SYM_FUNC_END(strncmp) | |
| SYM_FUNC_ALIAS(__pi_strncmp, strncmp) | |
| EXPORT_SYMBOL(strncmp) |