/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_RUNTIME_ARCH_ARM_MEMCMP16_ARM_S_ #define ART_RUNTIME_ARCH_ARM_MEMCMP16_ARM_S_ #include "asm_support_arm.S" /* * 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 */ ARM_ENTRY __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: push {r4, lr} .cfi_def_cfa_offset 8 .cfi_rel_offset r4, 0 .cfi_rel_offset lr, 4 /* 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 */ popne {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]! eorseq r0, r0, lr ldreq r0, [r3], #4 ldreq lr, [r1, #4]! eorseq r0, r0, ip ldreq r0, [r3], #4 ldreq ip, [r1, #4]! eorseq r0, r0, lr ldreq r0, [r3], #4 ldreq lr, [r1, #4]! eorseq r0, r0, ip ldreq r0, [r3], #4 ldreq ip, [r1, #4]! eorseq r0, r0, lr ldreq r0, [r3], #4 ldreq lr, [r1, #4]! eorseq r0, r0, ip ldreq r0, [r3], #4 ldreq ip, [r1, #4]! eorseq 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 pop {r4, lr} .cfi_restore r4 .cfi_restore lr .cfi_adjust_cfa_offset -8 bx lr 2: /* the last 2 words are different, restart them */ ldrh r0, [r3, #-4] ldrh ip, [r1, #-4] subs r0, r0, ip ldrheq r0, [r3, #-2] ldrheq ip, [r1, #-2] subseq r0, r0, ip /* restore registers and return */ pop {r4, lr} .cfi_restore r4 .cfi_restore lr .cfi_adjust_cfa_offset -8 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 */ pop {r4, lr} .cfi_restore r4 .cfi_restore lr .cfi_adjust_cfa_offset -8 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 eorseq r0, r0, ip moveq ip, lr, lsr #16 ldreq lr, [r1], #4 ldreq r0, [r3], #4 orreq ip, ip, lr, lsl #16 eorseq r0, r0, ip moveq ip, lr, lsr #16 ldreq lr, [r1], #4 ldreq r0, [r3], #4 orreq ip, ip, lr, lsl #16 eorseq 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 END __memcmp16 #endif // ART_RUNTIME_ARCH_ARM_MEMCMP16_ARM_S_