/* Copyright (C) 1996-2023 Free Software Foundation, Inc.
   Contributed by David Mosberger (davidm@cs.arizona.edu).
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library.  If not, see
   <http://www.gnu.org/licenses/>.  */

/* Finds length of a 0-terminated string.  Optimized for the Sw_64
   architecture:

      - memory accessed as aligned quadwords only
      - uses cmpgeb to compare 8 bytes in parallel
      - does binary search to find 0 byte in last quadword (HAKMEM
	needed 12 instructions to do this instead of the 8 instructions
	that the binary search needs).
*/
#include <sysdep.h>

	.set noreorder
	.set noat
ENTRY(strlen)
#ifdef PROF
	ldgp	gp, 0(pv)
	ldi	AT, _mcount
	call	AT, (AT), _mcount
	.prologue 1
#else
	.prologue 0
#endif

	ldl_u   $1, 0($16)	# load first quadword ($16 may be misaligned)
	ldi     $2, -1($31)
	ins7b   $2, $16, $2
	andnot  $16, 7, $0
	or      $2, $1, $1
	nop			# dual issue the next two on sw_64
	cmpgeb  $31, $1, $2	# $2 <- bitmask: bit i == 1 <==> i-th byte == 0
	bne     $2, $found

$loop:	ldl     $1, 8($0)
	cmpgeb  $31, $1, $2
	addl    $0, 8, $0	# addr += 8
	bne     $2, $found

	ldl     $1, 8($0)
	cmpgeb  $31, $1, $2
	addl    $0, 8, $0       # addr += 8
	bne     $2, $found

	ldl     $1, 8($0)
	cmpgeb  $31, $1, $2
	addl    $0, 8, $0       # addr += 8
	bne     $2, $found

	ldl     $1, 8($0)
	cmpgeb  $31, $1, $2
	addl    $0, 8, $0       # addr += 8
	bne     $2, $found

	ldl     $1, 8($0)
	cmpgeb  $31, $1, $2
	addl    $0, 8, $0       # addr += 8
	bne     $2, $found

	ldl     $1, 8($0)
	cmpgeb  $31, $1, $2
	addl    $0, 8, $0       # addr += 8
	bne     $2, $found

	ldl     $1, 8($0)
	cmpgeb  $31, $1, $2
	addl    $0, 8, $0       # addr += 8
	bne     $2, $found

	ldl     $1, 8($0)
	cmpgeb  $31, $1, $2
	addl    $0, 8, $0	# addr += 8
	beq     $2, $loop

$found:
	cttz    $2, $3
	addl    $0, $3, $0
	subl    $0, $16, $0
	/*negl    $2, $3	  # clear all but least set bit
	and     $2, $3, $2

	and     $2, 0xf0, $3    # binary search for that set bit
	and     $2, 0xcc, $4
	and     $2, 0xaa, $5
	selne   $3, 4, $3, $3
	selne   $4, 2, $4, $4
	selne   $5, 1, $5, $5
	addl    $3, $4, $3
	addl    $0, $5, $0
	addl    $0, $3, $0
	nop

	subl    $0, $16, $0*/
	ret
END(strlen)
libc_hidden_builtin_def (strlen)
