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