brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.8 KiB · 0dc5031 Raw
172 lines · plain
1/*2 * strcmp - compare two strings3 *4 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5 * See https://llvm.org/LICENSE.txt for license information.6 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7 */8 9/* Assumptions:10 *11 * ARMv8-a, AArch6412 */13 14#include "../asmdefs.h"15 16#define REP8_01 0x010101010101010117#define REP8_7f 0x7f7f7f7f7f7f7f7f18#define REP8_80 0x808080808080808019 20/* Parameters and result.  */21#define src1		x022#define src2		x123#define result		x024 25/* Internal variables.  */26#define data1		x227#define data1w		w228#define data2		x329#define data2w		w330#define has_nul		x431#define diff		x532#define syndrome	x633#define tmp1		x734#define tmp2		x835#define tmp3		x936#define zeroones	x1037#define pos		x1138 39	/* Start of performance-critical section  -- one 64B cache line.  */40ENTRY (__strcmp_aarch64)41	eor	tmp1, src1, src242	mov	zeroones, #REP8_0143	tst	tmp1, #744	b.ne	L(misaligned8)45	ands	tmp1, src1, #746	b.ne	L(mutual_align)47	/* NUL detection works on the principle that (X - 1) & (~X) & 0x8048	   (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and49	   can be done in parallel across the entire word.  */50L(loop_aligned):51	ldr	data1, [src1], #852	ldr	data2, [src2], #853L(start_realigned):54	sub	tmp1, data1, zeroones55	orr	tmp2, data1, #REP8_7f56	eor	diff, data1, data2	/* Non-zero if differences found.  */57	bic	has_nul, tmp1, tmp2	/* Non-zero if NUL terminator.  */58	orr	syndrome, diff, has_nul59	cbz	syndrome, L(loop_aligned)60	/* End of performance-critical section  -- one 64B cache line.  */61 62L(end):63#ifndef	__AARCH64EB__64	rev	syndrome, syndrome65	rev	data1, data166	/* The MS-non-zero bit of the syndrome marks either the first bit67	   that is different, or the top bit of the first zero byte.68	   Shifting left now will bring the critical information into the69	   top bits.  */70	clz	pos, syndrome71	rev	data2, data272	lsl	data1, data1, pos73	lsl	data2, data2, pos74	/* But we need to zero-extend (char is unsigned) the value and then75	   perform a signed 32-bit subtraction.  */76	lsr	data1, data1, #5677	sub	result, data1, data2, lsr #5678	ret79#else80	/* For big-endian we cannot use the trick with the syndrome value81	   as carry-propagation can corrupt the upper bits if the trailing82	   bytes in the string contain 0x01.  */83	/* However, if there is no NUL byte in the dword, we can generate84	   the result directly.  We can't just subtract the bytes as the85	   MSB might be significant.  */86	cbnz	has_nul, 1f87	cmp	data1, data288	cset	result, ne89	cneg	result, result, lo90	ret911:92	/* Re-compute the NUL-byte detection, using a byte-reversed value.  */93	rev	tmp3, data194	sub	tmp1, tmp3, zeroones95	orr	tmp2, tmp3, #REP8_7f96	bic	has_nul, tmp1, tmp297	rev	has_nul, has_nul98	orr	syndrome, diff, has_nul99	clz	pos, syndrome100	/* The MS-non-zero bit of the syndrome marks either the first bit101	   that is different, or the top bit of the first zero byte.102	   Shifting left now will bring the critical information into the103	   top bits.  */104	lsl	data1, data1, pos105	lsl	data2, data2, pos106	/* But we need to zero-extend (char is unsigned) the value and then107	   perform a signed 32-bit subtraction.  */108	lsr	data1, data1, #56109	sub	result, data1, data2, lsr #56110	ret111#endif112 113L(mutual_align):114	/* Sources are mutually aligned, but are not currently at an115	   alignment boundary.  Round down the addresses and then mask off116	   the bytes that preceed the start point.  */117	bic	src1, src1, #7118	bic	src2, src2, #7119	lsl	tmp1, tmp1, #3		/* Bytes beyond alignment -> bits.  */120	ldr	data1, [src1], #8121	neg	tmp1, tmp1		/* Bits to alignment -64.  */122	ldr	data2, [src2], #8123	mov	tmp2, #~0124#ifdef __AARCH64EB__125	/* Big-endian.  Early bytes are at MSB.  */126	lsl	tmp2, tmp2, tmp1	/* Shift (tmp1 & 63).  */127#else128	/* Little-endian.  Early bytes are at LSB.  */129	lsr	tmp2, tmp2, tmp1	/* Shift (tmp1 & 63).  */130#endif131	orr	data1, data1, tmp2132	orr	data2, data2, tmp2133	b	L(start_realigned)134 135L(misaligned8):136	/* Align SRC1 to 8 bytes and then compare 8 bytes at a time, always137	   checking to make sure that we don't access beyond page boundary in138	   SRC2.  */139	tst	src1, #7140	b.eq	L(loop_misaligned)141L(do_misaligned):142	ldrb	data1w, [src1], #1143	ldrb	data2w, [src2], #1144	cmp	data1w, #1145	ccmp	data1w, data2w, #0, cs	/* NZCV = 0b0000.  */146	b.ne	L(done)147	tst	src1, #7148	b.ne	L(do_misaligned)149 150L(loop_misaligned):151	/* Test if we are within the last dword of the end of a 4K page.  If152	   yes then jump back to the misaligned loop to copy a byte at a time.  */153	and	tmp1, src2, #0xff8154	eor	tmp1, tmp1, #0xff8155	cbz	tmp1, L(do_misaligned)156	ldr	data1, [src1], #8157	ldr	data2, [src2], #8158 159	sub	tmp1, data1, zeroones160	orr	tmp2, data1, #REP8_7f161	eor	diff, data1, data2	/* Non-zero if differences found.  */162	bic	has_nul, tmp1, tmp2	/* Non-zero if NUL terminator.  */163	orr	syndrome, diff, has_nul164	cbz	syndrome, L(loop_misaligned)165	b	L(end)166 167L(done):168	sub	result, data1, data2169	ret170 171END (__strcmp_aarch64)172