root/arch/sparc/lib/memscan_32.S
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * memscan.S: Optimized memscan for the Sparc.
 *
 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
 */

#include <linux/export.h>

/* In essence, this is just a fancy strlen. */

#define LO_MAGIC 0x01010101
#define HI_MAGIC 0x80808080

        .text
        .align  4
        .globl  __memscan_zero, __memscan_generic
        .globl  memscan
EXPORT_SYMBOL(__memscan_zero)
EXPORT_SYMBOL(__memscan_generic)
__memscan_zero:
        /* %o0 = addr, %o1 = size */
        cmp     %o1, 0
        bne,a   1f
         andcc  %o0, 3, %g0

        retl
         nop

1:
        be      mzero_scan_word
         sethi  %hi(HI_MAGIC), %g2

        ldsb    [%o0], %g3
mzero_still_not_word_aligned:
        cmp     %g3, 0
        bne     1f
         add    %o0, 1, %o0

        retl
         sub    %o0, 1, %o0

1:
        subcc   %o1, 1, %o1
        bne,a   1f
         andcc  %o0, 3, %g0

        retl
         nop

1:
        bne,a   mzero_still_not_word_aligned
         ldsb   [%o0], %g3

        sethi   %hi(HI_MAGIC), %g2
mzero_scan_word:
        or      %g2, %lo(HI_MAGIC), %o3
        sethi   %hi(LO_MAGIC), %g3
        or      %g3, %lo(LO_MAGIC), %o2
mzero_next_word:
        ld      [%o0], %g2
mzero_next_word_preloaded:
        sub     %g2, %o2, %g2
mzero_next_word_preloaded_next:
        andcc   %g2, %o3, %g0
        bne     mzero_byte_zero
         add    %o0, 4, %o0

mzero_check_out_of_fuel:
        subcc   %o1, 4, %o1
        bg,a    1f
         ld     [%o0], %g2

        retl
         nop

1:
        b       mzero_next_word_preloaded_next
         sub    %g2, %o2, %g2

        /* Check every byte. */
mzero_byte_zero:
        ldsb    [%o0 - 4], %g2
        cmp     %g2, 0
        bne     mzero_byte_one
         sub    %o0, 4, %g3

        retl
         mov    %g3, %o0

mzero_byte_one:
        ldsb    [%o0 - 3], %g2
        cmp     %g2, 0
        bne,a   mzero_byte_two_and_three
         ldsb   [%o0 - 2], %g2

        retl
         sub    %o0, 3, %o0

mzero_byte_two_and_three:
        cmp     %g2, 0
        bne,a   1f
         ldsb   [%o0 - 1], %g2

        retl
         sub    %o0, 2, %o0

1:
        cmp     %g2, 0
        bne,a   mzero_next_word_preloaded
         ld     [%o0], %g2

        retl
         sub    %o0, 1, %o0

mzero_found_it:
        retl
         sub    %o0, 2, %o0

memscan:
__memscan_generic:
        /* %o0 = addr, %o1 = c, %o2 = size */
        cmp     %o2, 0
        bne,a   0f
         ldub   [%o0], %g2

        b,a     2f
1:
        ldub    [%o0], %g2
0:
        cmp     %g2, %o1
        be      2f
         addcc  %o2, -1, %o2
        bne     1b
         add    %o0, 1, %o0
2:
        retl
         nop