/*
* Copyright (c) 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 _strcmp
// int strcmp(const char *s1, const char *s2)// Returns zero if the two NUL-terminated strings s1 and s2 are equal.
// 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}
#define CLEAR_FRAME \
pop {r8}
.align 3
.long 0, 0x01010101
_strcmp:
// Load a character from each string and advance the pointers. If the loaded
// characters are unequal or NUL, return their difference.
0: ldrb r2, [r0],#1
ldrb ip, [r1],#1
cmp r2, #1
cmphs r2, 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, (_strcmp-4)
// Word align s2, and place the remainder in r8. 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 r8, r1, #3
bic r1, r1, #3
mov r8, r8, lsl #3
rsb r5, r8, #32
// 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 r6, [r1],#4
orr r6, r6, lr, lsr r5
sub r2, r6, lr
bic r2, r2, r6
tst r2, lr, lsl #7
mov r4, r6, lsr r8
bne L_unwindLoopPreload
.align 3
L_wordCompareLoop:
// 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 r6, [r1],#4
#if defined _ARM_ARCH_6
uqsub8 r2, lr, r6
tst r2, r2
ldr ip, [r0],#4
#else
sub r2, r6, lr
bic r2, r2, r6
ldr ip, [r0],#4
tst r2, lr, lsl #7
#endif
orr r3, r4, r6, lsl r5
cmpeq ip, r3
mov r4, r6, lsr r8
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_unwindLoopPreload:
sub r1, r1, r5, lsr #3
CLEAR_FRAME
L_byteCompareLoop:
// Load a character from each string and advance the pointers. If the loaded
// characters are unequal or NUL, return their difference.
ldrb r2, [r0],#1
ldrb ip, [r1],#1
cmp r2, #1
cmpcs r2, ip
beq L_byteCompareLoop
L_earlyReturn:
// Return the difference between the last two characters loaded.
sub r0, r2, ip
bx lr