/* 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)