root/arch/riscv/lib/strcmp.S
/* 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 strcmp(const char *cs, const char *ct) */
SYM_FUNC_START(strcmp)

        __ALTERNATIVE_CFG("nop", "j strcmp_zbb", 0, RISCV_ISA_EXT_ZBB,
                IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB))

        /*
         * Returns
         *   a0 - comparison result, value like strcmp
         *
         * Parameters
         *   a0 - string1
         *   a1 - string2
         *
         * Clobbers
         *   t0, t1
         */
1:
        lbu     t0, 0(a0)
        lbu     t1, 0(a1)
        addi    a0, a0, 1
        addi    a1, a1, 1
        bne     t0, t1, 2f
        bnez    t0, 1b
        li      a0, 0
        ret
2:
        /*
         * strcmp only needs to return (< 0, 0, > 0) values
         * not necessarily -1, 0, +1
         */
        sub     a0, t0, t1
        ret

/*
 * Variant of strcmp using the ZBB extension if available.
 * The code was published as part of the bitmanip manual
 * in Appendix A.
 */
#if defined(CONFIG_RISCV_ISA_ZBB) && defined(CONFIG_TOOLCHAIN_HAS_ZBB)
strcmp_zbb:

.option push
.option arch,+zbb

        /*
         * Returns
         *   a0 - comparison result, value like strcmp
         *
         * Parameters
         *   a0 - string1
         *   a1 - string2
         *
         * Clobbers
         *   t0, t1, t2, t3, t4
         */

        or      t2, a0, a1
        li      t4, -1
        and     t2, t2, SZREG-1
        bnez    t2, 3f

        /* Main loop for aligned string.  */
        .p2align 3
1:
        REG_L   t0, 0(a0)
        REG_L   t1, 0(a1)
        orc.b   t3, t0
        bne     t3, t4, 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:
        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

.option pop
#endif
SYM_FUNC_END(strcmp)
SYM_FUNC_ALIAS(__pi_strcmp, strcmp)
EXPORT_SYMBOL(strcmp)