/*
* Copyright (c) 2010, 2011 Apple, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_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. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* 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_OSREFERENCE_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} push {r8,r10}
#define CLEAR_FRAME \
pop {r8,r10}
.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