Loading...
arm/string/strncmp.s /dev/null Libc-825.26
--- /dev/null
+++ Libc/Libc-825.26/arm/string/strncmp.s
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2010, 2011 Apple, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+ 
+.text
+.syntax unified
+.code 32
+.globl _strncmp
+// int strncmp(const char *s1, const char *s2, size_t n);
+//
+// Returns zero if the two NUL-terminated strings s1 and s2 are equal up to
+// n characters.  Otherwise, returns the difference between the first two
+// characters that do not match, interpreted as unsigned integers.
+
+#define ESTABLISH_FRAME        \
+	push   {r4-r7,lr}         ;\
+	add     r7,     sp, #12   ;\
+	push   {r8,r10}
+#define CLEAR_FRAME            \
+	pop    {r8,r10}            ;\
+	pop    {r4-r7,lr}
+
+.align 3
+.long 0, 0x01010101
+_strncmp:
+//  If n < 16, jump straight to the byte-by-byte comparison loop.
+	cmp     r2,         #16
+	blo     L_byteCompareLoop
+//  Load a character from each string and advance the pointers.  If the loaded
+//  characters are unequal or NUL, return their difference.
+0:	ldrb    r3,    [r0],#1
+	ldrb    ip,    [r1],#1
+	sub     r2,         #1
+	cmp     r3,         #1
+	cmphs   r3,         ip
+	bne     L_earlyReturn
+//  If the address of the next character from s1 does not have word alignment,
+//  continue with the character-by-character comparison.  Otherwise, fall
+//  through into the word-by-word comparison path.
+	tst     r0,         #3
+	bne     0b
+	
+//  We have not encountered a NUL or a mismatch, and s1 has word alignment.
+//  Establish a frame, since we're going to need additional registers anyway.
+	ESTABLISH_FRAME
+	ldr     lr,    (_strncmp-4)
+
+//  Word align s2, and place the remainder in r10.  Compute the right- and
+//  left-shifts to extract each word that we will compare to the other source
+//  from the aligned words that we load:
+//
+//      aligned s2        to be loaded on next iteration
+//      |   "true" s2     |
+//      v   v             v
+//      +---+---+---+---+ +---+---+---+---+
+//      | 0 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 |
+//      +---+---+---+---+ +---+---+---+---+
+//          ^-----------------^
+//          to be compared on next iteration
+	and     r10,    r1, #3
+	bic     r1,     r1, #3
+	mov     r10,        r10, lsl #3
+	rsb     r6,     r10,#32
+	
+//  Subtract the number of bytes of the initial word load from s2 that will 
+//  actually be used from n.
+	sub     r2,     r2, r6, lsr #3
+	
+//  Load the first aligned word of s2.  OR 0x01 into any bytes that preceed the
+//  "true s2", to prevent our check for NUL from generating a false positive.
+//  Then check for NUL, and jump to the byte-by-byte comparison loop after
+//  unwinding the pointers if we enounter one.
+	ldr     r8,    [r1],#4
+	orr     r8,     r8, lr, lsr r6
+	sub     r3,     r8, lr
+	bic     r3,     r3, r8
+	tst     r3,         lr, lsl #7
+	mov     r5,         r8, lsr r10
+	bne     L_unwindLoopPreload
+	
+.align 3
+L_wordCompareLoop:
+//  If n < 4, abort the word compare loop before we load any more data.
+	subs    r2,     r2, #4
+	blo     L_nIsLessThanFour
+//  Load the next aligned word of s2 and check if it contains any NUL bytes.
+//  Load the next aligned word of s1, and extract the corresponding bytes from
+//  the two words of s2 loaded in this and the previous iteration of the loop.
+//  Compare these two words.
+//  If no NUL or mismatched words have been encountered, continue the loop.
+	ldr     r8,    [r1],#4
+#if defined _ARM_ARCH_6
+    uqsub8  r3,     lr, r8
+    tst     r3,         r3
+    ldr     ip,    [r0],#4
+#else
+	sub     r3,     r8, lr
+	bic     r3,     r3, r8
+	ldr     ip,    [r0],#4
+	tst     r3,         lr, lsl #7
+#endif
+	orr     r4,     r5, r8, lsl r6
+	cmpeq   ip,         r4
+	mov     r5,         r8, lsr r10
+	beq     L_wordCompareLoop
+
+//  Either we have encountered a NUL, or we have found a mismatch between s1
+//  and s2.  Unwind the pointers and use a byte-by-byte comparison loop.
+	sub     r0,     r0, #4
+	sub     r1,     r1, #4
+L_nIsLessThanFour:
+	add     r2,     r2, #4
+L_unwindLoopPreload:
+	sub     r1,     r1, r6, lsr #3
+	add     r2,     r2, r6, lsr #3
+	CLEAR_FRAME
+	
+L_byteCompareLoop:
+//  If n-- == 0, we have exhausted the allowed number of comparisons, and need
+//  to return zero without additional loads.
+	subs    r2,     r2, #1
+	movlo   r0,         #0
+	bxlo    lr
+//  Load a character from each string and advance the pointers.  If the loaded
+//  characters are unequal or NUL, return their difference.
+	ldrb    r3,    [r0],#1
+	ldrb    ip,    [r1],#1
+	cmp     r3,         #1
+	cmpcs   r3,         ip
+	beq     L_byteCompareLoop
+	
+L_earlyReturn:
+//  Return the difference between the last two characters loaded.
+	sub     r0,     r3, ip
+	bx      lr