root/arch/arm64/lib/memchr.S
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (C) 2021 Arm Ltd.
 */

#include <linux/linkage.h>
#include <asm/assembler.h>

/*
 * Find a character in an area of memory.
 *
 * Parameters:
 *      x0 - buf
 *      x1 - c
 *      x2 - n
 * Returns:
 *      x0 - address of first occurrence of 'c' or 0
 */

#define L(label) .L ## label

#define REP8_01 0x0101010101010101
#define REP8_7f 0x7f7f7f7f7f7f7f7f

#define srcin           x0
#define chrin           w1
#define cntin           x2

#define result          x0

#define wordcnt         x3
#define rep01           x4
#define repchr          x5
#define cur_word        x6
#define cur_byte        w6
#define tmp             x7
#define tmp2            x8

        .p2align 4
        nop
SYM_FUNC_START(__pi_memchr)
        and     chrin, chrin, #0xff
        lsr     wordcnt, cntin, #3
        cbz     wordcnt, L(byte_loop)
        mov     rep01, #REP8_01
        mul     repchr, x1, rep01
        and     cntin, cntin, #7
L(word_loop):
        ldr     cur_word, [srcin], #8
        sub     wordcnt, wordcnt, #1
        eor     cur_word, cur_word, repchr
        sub     tmp, cur_word, rep01
        orr     tmp2, cur_word, #REP8_7f
        bics    tmp, tmp, tmp2
        b.ne    L(found_word)
        cbnz    wordcnt, L(word_loop)
L(byte_loop):
        cbz     cntin, L(not_found)
        ldrb    cur_byte, [srcin], #1
        sub     cntin, cntin, #1
        cmp     cur_byte, chrin
        b.ne    L(byte_loop)
        sub     srcin, srcin, #1
        ret
L(found_word):
CPU_LE( rev     tmp, tmp)
        clz     tmp, tmp
        sub     tmp, tmp, #64
        add     result, srcin, tmp, asr #3
        ret
L(not_found):
        mov     result, #0
        ret
SYM_FUNC_END(__pi_memchr)
SYM_FUNC_ALIAS_WEAK(memchr, __pi_memchr)
EXPORT_SYMBOL_NOKASAN(memchr)