]> git.saurik.com Git - apple/libc.git/blob - arm/string/strcmp.s
e214c3f66171d26946629f88d287f7c61a4ab15c
[apple/libc.git] / arm / string / strcmp.s
1 /*
2 * Copyright (c) 2011 Apple, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 .text
25 .syntax unified
26 .code 32
27 .globl _strcmp
28 // int strcmp(const char *s1, const char *s2);
29 //
30 // Returns zero if the two NUL-terminated strings s1 and s2 are equal.
31 // Otherwise, returns the difference between the first two
32 // characters that do not match, interpreted as unsigned integers.
33
34 #define ESTABLISH_FRAME \
35 push {r4-r7,lr} ;\
36 add r7, sp, #12 ;\
37 push {r8}
38 #define CLEAR_FRAME \
39 pop {r8} ;\
40 pop {r4-r7,lr}
41
42 .align 3
43 .long 0, 0x01010101
44 _strcmp:
45 // Load a character from each string and advance the pointers. If the loaded
46 // characters are unequal or NUL, return their difference.
47 0: ldrb r2, [r0],#1
48 ldrb ip, [r1],#1
49 cmp r2, #1
50 cmphs r2, ip
51 bne L_earlyReturn
52 // If the address of the next character from s1 does not have word alignment,
53 // continue with the character-by-character comparison. Otherwise, fall
54 // through into the word-by-word comparison path.
55 tst r0, #3
56 bne 0b
57
58 // We have not encountered a NUL or a mismatch, and s1 has word alignment.
59 // Establish a frame, since we're going to need additional registers anyway.
60 ESTABLISH_FRAME
61 ldr lr, (_strcmp-4)
62
63 // Word align s2, and place the remainder in r8. Compute the right- and
64 // left-shifts to extract each word that we will compare to the other source
65 // from the aligned words that we load:
66 //
67 // aligned s2 to be loaded on next iteration
68 // | "true" s2 |
69 // v v v
70 // +---+---+---+---+ +---+---+---+---+
71 // | 0 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 |
72 // +---+---+---+---+ +---+---+---+---+
73 // ^-----------------^
74 // to be compared on next iteration
75 and r8, r1, #3
76 bic r1, r1, #3
77 mov r8, r8, lsl #3
78 rsb r5, r8, #32
79
80 // Load the first aligned word of s2. OR 0x01 into any bytes that preceed the
81 // "true s2", to prevent our check for NUL from generating a false positive.
82 // Then check for NUL, and jump to the byte-by-byte comparison loop after
83 // unwinding the pointers if we enounter one.
84 ldr r6, [r1],#4
85 orr r6, r6, lr, lsr r5
86 sub r2, r6, lr
87 bic r2, r2, r6
88 tst r2, lr, lsl #7
89 mov r4, r6, lsr r8
90 bne L_unwindLoopPreload
91
92 .align 3
93 L_wordCompareLoop:
94 // Load the next aligned word of s2 and check if it contains any NUL bytes.
95 // Load the next aligned word of s1, and extract the corresponding bytes from
96 // the two words of s2 loaded in this and the previous iteration of the loop.
97 // Compare these two words.
98 // If no NUL or mismatched words have been encountered, continue the loop.
99 ldr r6, [r1],#4
100 #if defined _ARM_ARCH_6
101 uqsub8 r2, lr, r6
102 tst r2, r2
103 ldr ip, [r0],#4
104 #else
105 sub r2, r6, lr
106 bic r2, r2, r6
107 ldr ip, [r0],#4
108 tst r2, lr, lsl #7
109 #endif
110 orr r3, r4, r6, lsl r5
111 cmpeq ip, r3
112 mov r4, r6, lsr r8
113 beq L_wordCompareLoop
114
115 // Either we have encountered a NUL, or we have found a mismatch between s1
116 // and s2. Unwind the pointers and use a byte-by-byte comparison loop.
117 sub r0, r0, #4
118 sub r1, r1, #4
119 L_unwindLoopPreload:
120 sub r1, r1, r5, lsr #3
121 CLEAR_FRAME
122
123 L_byteCompareLoop:
124 // Load a character from each string and advance the pointers. If the loaded
125 // characters are unequal or NUL, return their difference.
126 ldrb r2, [r0],#1
127 ldrb ip, [r1],#1
128 cmp r2, #1
129 cmpcs r2, ip
130 beq L_byteCompareLoop
131
132 L_earlyReturn:
133 // Return the difference between the last two characters loaded.
134 sub r0, r2, ip
135 bx lr