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