summaryrefslogtreecommitdiffstats
path: root/libc/arch-arm/bionic/memcmp16.S
diff options
context:
space:
mode:
Diffstat (limited to 'libc/arch-arm/bionic/memcmp16.S')
-rw-r--r--libc/arch-arm/bionic/memcmp16.S233
1 files changed, 233 insertions, 0 deletions
diff --git a/libc/arch-arm/bionic/memcmp16.S b/libc/arch-arm/bionic/memcmp16.S
new file mode 100644
index 0000000..c6e6d39
--- /dev/null
+++ b/libc/arch-arm/bionic/memcmp16.S
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+ .text
+
+ .global __memcmp16
+ .type __memcmp16, %function
+ .align 4
+
+/*
+ * Optimized memcmp16() for ARM9.
+ * This would not be optimal on XScale or ARM11, where more prefetching
+ * and use of PLD will be needed.
+ * The 2 major optimzations here are
+ * (1) The main loop compares 16 bytes at a time
+ * (2) The loads are scheduled in a way they won't stall
+ */
+
+__memcmp16:
+ pld [r0, #0]
+ pld [r1, #0]
+
+ /* take of the case where length is nul or the buffers are the same */
+ cmp r0, r1
+ cmpne r2, #0
+ moveq r0, #0
+ bxeq lr
+
+ /* since r0 hold the result, move the first source
+ * pointer somewhere else
+ */
+
+ mov r3, r0
+
+ /* make sure we have at least 12 words, this simplify things below
+ * and avoid some overhead for small blocks
+ */
+
+ cmp r2, #12
+ bpl 0f
+
+ /* small blocks (less then 12 words) */
+ pld [r0, #32]
+ pld [r1, #32]
+
+1: ldrh r0, [r3], #2
+ ldrh ip, [r1], #2
+ subs r0, r0, ip
+ bxne lr
+ subs r2, r2, #1
+ bne 1b
+ bx lr
+
+
+ /* save registers */
+0: stmfd sp!, {r4, lr}
+
+ /* align first pointer to word boundary */
+ tst r3, #2
+ beq 0f
+
+ ldrh r0, [r3], #2
+ ldrh ip, [r1], #2
+ sub r2, r2, #1
+ subs r0, r0, ip
+ /* restore registers and return */
+ ldmnefd sp!, {r4, lr}
+ bxne lr
+
+
+
+0: /* here the first pointer is aligned, and we have at least 3 words
+ * to process.
+ */
+
+ /* see if the pointers are congruent */
+ eor r0, r3, r1
+ ands r0, r0, #2
+ bne 5f
+
+ /* congruent case, 16 half-words per iteration
+ * We need to make sure there are at least 16+2 words left
+ * because we effectively read ahead one long word, and we could
+ * read past the buffer (and segfault) if we're not careful.
+ */
+
+ ldr ip, [r1]
+ subs r2, r2, #(16 + 2)
+ bmi 1f
+
+0:
+ pld [r3, #64]
+ pld [r1, #64]
+ ldr r0, [r3], #4
+ ldr lr, [r1, #4]!
+ eors r0, r0, ip
+ ldreq r0, [r3], #4
+ ldreq ip, [r1, #4]!
+ eoreqs r0, r0, lr
+ ldreq r0, [r3], #4
+ ldreq lr, [r1, #4]!
+ eoreqs r0, r0, ip
+ ldreq r0, [r3], #4
+ ldreq ip, [r1, #4]!
+ eoreqs r0, r0, lr
+ ldreq r0, [r3], #4
+ ldreq lr, [r1, #4]!
+ eoreqs r0, r0, ip
+ ldreq r0, [r3], #4
+ ldreq ip, [r1, #4]!
+ eoreqs r0, r0, lr
+ ldreq r0, [r3], #4
+ ldreq lr, [r1, #4]!
+ eoreqs r0, r0, ip
+ ldreq r0, [r3], #4
+ ldreq ip, [r1, #4]!
+ eoreqs r0, r0, lr
+ bne 2f
+ subs r2, r2, #16
+ bhs 0b
+
+ /* do we have at least 2 words left? */
+1: adds r2, r2, #(16 - 2 + 2)
+ bmi 4f
+
+ /* finish off 2 words at a time */
+3: ldr r0, [r3], #4
+ ldr ip, [r1], #4
+ eors r0, r0, ip
+ bne 2f
+ subs r2, r2, #2
+ bhs 3b
+
+ /* are we done? */
+4: adds r2, r2, #2
+ bne 8f
+ /* restore registers and return */
+ mov r0, #0
+ ldmfd sp!, {r4, lr}
+ bx lr
+
+2: /* the last 2 words are different, restart them */
+ ldrh r0, [r3, #-4]
+ ldrh ip, [r1, #-4]
+ subs r0, r0, ip
+ ldreqh r0, [r3, #-2]
+ ldreqh ip, [r1, #-2]
+ subeqs r0, r0, ip
+ /* restore registers and return */
+ ldmfd sp!, {r4, lr}
+ bx lr
+
+ /* process the last few words */
+8: ldrh r0, [r3], #2
+ ldrh ip, [r1], #2
+ subs r0, r0, ip
+ bne 9f
+ subs r2, r2, #1
+ bne 8b
+
+9: /* restore registers and return */
+ ldmfd sp!, {r4, lr}
+ bx lr
+
+
+5: /*************** non-congruent case ***************/
+
+ /* align the unaligned pointer */
+ bic r1, r1, #3
+ ldr lr, [r1], #4
+ sub r2, r2, #8
+
+6:
+ pld [r3, #64]
+ pld [r1, #64]
+ mov ip, lr, lsr #16
+ ldr lr, [r1], #4
+ ldr r0, [r3], #4
+ orr ip, ip, lr, lsl #16
+ eors r0, r0, ip
+ moveq ip, lr, lsr #16
+ ldreq lr, [r1], #4
+ ldreq r0, [r3], #4
+ orreq ip, ip, lr, lsl #16
+ eoreqs r0, r0, ip
+ moveq ip, lr, lsr #16
+ ldreq lr, [r1], #4
+ ldreq r0, [r3], #4
+ orreq ip, ip, lr, lsl #16
+ eoreqs r0, r0, ip
+ moveq ip, lr, lsr #16
+ ldreq lr, [r1], #4
+ ldreq r0, [r3], #4
+ orreq ip, ip, lr, lsl #16
+ eoreqs r0, r0, ip
+ bne 7f
+ subs r2, r2, #8
+ bhs 6b
+ sub r1, r1, #2
+ /* are we done? */
+ adds r2, r2, #8
+ moveq r0, #0
+ beq 9b
+ /* finish off the remaining bytes */
+ b 8b
+
+7: /* fix up the 2 pointers and fallthrough... */
+ sub r1, r1, #2
+ b 2b