strcmp.s   [plain text]


/*
 * 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}         ;\
    add     r7,     sp, #12   ;\
    push   {r8}
#define CLEAR_FRAME            \
    pop    {r8}               ;\
    pop    {r4-r7,lr}

.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