ARM: 7668/1: fix memset-related crashes caused by recent GCC (4.7.2) optimizations
[pandora-kernel.git] / arch / arm / lib / memset.S
1 /*
2  *  linux/arch/arm/lib/memset.S
3  *
4  *  Copyright (C) 1995-2000 Russell King
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  *  ASM optimised string functions
11  */
12 #include <linux/linkage.h>
13 #include <asm/assembler.h>
14
15         .text
16         .align  5
17         .word   0
18
19 1:      subs    r2, r2, #4              @ 1 do we have enough
20         blt     5f                      @ 1 bytes to align with?
21         cmp     r3, #2                  @ 1
22         strltb  r1, [ip], #1            @ 1
23         strleb  r1, [ip], #1            @ 1
24         strb    r1, [ip], #1            @ 1
25         add     r2, r2, r3              @ 1 (r2 = r2 - (4 - r3))
26 /*
27  * The pointer is now aligned and the length is adjusted.  Try doing the
28  * memset again.
29  */
30
31 ENTRY(memset)
32 /*
33  * Preserve the contents of r0 for the return value.
34  */
35         mov     ip, r0
36         ands    r3, ip, #3              @ 1 unaligned?
37         bne     1b                      @ 1
38 /*
39  * we know that the pointer in ip is aligned to a word boundary.
40  */
41         orr     r1, r1, r1, lsl #8
42         orr     r1, r1, r1, lsl #16
43         mov     r3, r1
44         cmp     r2, #16
45         blt     4f
46
47 #if ! CALGN(1)+0
48
49 /*
50  * We need 2 extra registers for this loop - use r8 and the LR
51  */
52         stmfd   sp!, {r8, lr}
53         mov     r8, r1
54         mov     lr, r1
55
56 2:      subs    r2, r2, #64
57         stmgeia ip!, {r1, r3, r8, lr}   @ 64 bytes at a time.
58         stmgeia ip!, {r1, r3, r8, lr}
59         stmgeia ip!, {r1, r3, r8, lr}
60         stmgeia ip!, {r1, r3, r8, lr}
61         bgt     2b
62         ldmeqfd sp!, {r8, pc}           @ Now <64 bytes to go.
63 /*
64  * No need to correct the count; we're only testing bits from now on
65  */
66         tst     r2, #32
67         stmneia ip!, {r1, r3, r8, lr}
68         stmneia ip!, {r1, r3, r8, lr}
69         tst     r2, #16
70         stmneia ip!, {r1, r3, r8, lr}
71         ldmfd   sp!, {r8, lr}
72
73 #else
74
75 /*
76  * This version aligns the destination pointer in order to write
77  * whole cache lines at once.
78  */
79
80         stmfd   sp!, {r4-r8, lr}
81         mov     r4, r1
82         mov     r5, r1
83         mov     r6, r1
84         mov     r7, r1
85         mov     r8, r1
86         mov     lr, r1
87
88         cmp     r2, #96
89         tstgt   ip, #31
90         ble     3f
91
92         and     r8, ip, #31
93         rsb     r8, r8, #32
94         sub     r2, r2, r8
95         movs    r8, r8, lsl #(32 - 4)
96         stmcsia ip!, {r4, r5, r6, r7}
97         stmmiia ip!, {r4, r5}
98         tst     r8, #(1 << 30)
99         mov     r8, r1
100         strne   r1, [ip], #4
101
102 3:      subs    r2, r2, #64
103         stmgeia ip!, {r1, r3-r8, lr}
104         stmgeia ip!, {r1, r3-r8, lr}
105         bgt     3b
106         ldmeqfd sp!, {r4-r8, pc}
107
108         tst     r2, #32
109         stmneia ip!, {r1, r3-r8, lr}
110         tst     r2, #16
111         stmneia ip!, {r4-r7}
112         ldmfd   sp!, {r4-r8, lr}
113
114 #endif
115
116 4:      tst     r2, #8
117         stmneia ip!, {r1, r3}
118         tst     r2, #4
119         strne   r1, [ip], #4
120 /*
121  * When we get here, we've got less than 4 bytes to zero.  We
122  * may have an unaligned pointer as well.
123  */
124 5:      tst     r2, #2
125         strneb  r1, [ip], #1
126         strneb  r1, [ip], #1
127         tst     r2, #1
128         strneb  r1, [ip], #1
129         mov     pc, lr
130 ENDPROC(memset)