/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:strlen.s 12.0$ */
/* $ACIS:strlen.s 12.0$ */
/* $Source: /ibm/acis/usr/src/lib/libc/ca/gen/RCS/strlen.s,v $ */

	.data
rcsid:	.asciz	"$Header:strlen.s 12.0$"
	.text

#include "LINKG.h"

 #
 # version of strlen written in assembler for highest speed
 #	strlen(string) char *string;
 #
ENTRY(strlen)
	mr	r0,r2		# save starting location
	nilz	r5,r2,0x03	# Round string addr down to word boundary
	s	r2,r5		# More of the rounding
	sli	r5,3		# Calc offset into following switch statement
	get	r4,$0f		# Get address of beginning of switch statement
	a	r4,r5		# Add displacement of the case
	brx	r4		# Branch to calculated case and
	ls	r4,0(r2)	# get first word (possibly rounded down).
 # at this point:
 # r0 is the base of the string for calculating length just before return
 # r2 points to string or the nearest word boundary before string.
 # r4 contains 4 byes with string's initial bytes somewhere in r2
 # The following is a switch statement. Initially, control jumps to one of
 # the labels 0, 1, 2 or 3 depending on where string's first byte is in r2
 # 
9:	inc	r2,4		# point to next word
 # code at 0f, 1f, 2f must be exactly 8 bytes long to match switch above
 # The switch:
0:
	niuz	r5,r4,0xff00	# get byte 0 from r4
	beq	0f		# branch if byte 0 is null

1:
	niuz	r5,r4,0x00ff	# get byte 1 from r4
	beq	1f		# branch if byte 1 is null

2:
	nilz	r5,r4,0xff00	# get byte 2 from r4
	beq	2f		# branch if byte 2 is null

3:
	nilz	r5,r4,0x00ff	# get byte 3 from r4
	jeq	3f
	ls	r4,4(r2)
	b	9b		# null not found in byte 3, try next word 

 # Come to one of labels 0, 1, 2 or 3 when a null byte was found and
 # adjust r2 to point to the zero byte
3:	inc	r2,1
2:	inc	r2,1
1:	inc	r2,1
0:
 # calculate the length
	brx	r15		# and return
	s	r2,r0

	TTNOFRM
