diff options
Diffstat (limited to 'arch/xtensa/lib/memset.S')
-rw-r--r-- | arch/xtensa/lib/memset.S | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/arch/xtensa/lib/memset.S b/arch/xtensa/lib/memset.S new file mode 100644 index 000000000000..4de25134bc62 --- /dev/null +++ b/arch/xtensa/lib/memset.S | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * arch/xtensa/lib/memset.S | ||
3 | * | ||
4 | * ANSI C standard library function memset | ||
5 | * (Well, almost. .fixup code might return zero.) | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General | ||
8 | * Public License. See the file "COPYING" in the main directory of | ||
9 | * this archive for more details. | ||
10 | * | ||
11 | * Copyright (C) 2002 Tensilica Inc. | ||
12 | */ | ||
13 | |||
14 | #include <xtensa/coreasm.h> | ||
15 | |||
16 | /* | ||
17 | * void *memset(void *dst, int c, size_t length) | ||
18 | * | ||
19 | * The algorithm is as follows: | ||
20 | * Create a word with c in all byte positions | ||
21 | * If the destination is aligned, | ||
22 | * do 16B chucks with a loop, and then finish up with | ||
23 | * 8B, 4B, 2B, and 1B stores conditional on the length. | ||
24 | * If destination is unaligned, align it by conditionally | ||
25 | * setting 1B and 2B and then go to aligned case. | ||
26 | * This code tries to use fall-through branches for the common | ||
27 | * case of an aligned destination (except for the branches to | ||
28 | * the alignment labels). | ||
29 | */ | ||
30 | |||
31 | /* Load or store instructions that may cause exceptions use the EX macro. */ | ||
32 | |||
33 | #define EX(insn,reg1,reg2,offset,handler) \ | ||
34 | 9: insn reg1, reg2, offset; \ | ||
35 | .section __ex_table, "a"; \ | ||
36 | .word 9b, handler; \ | ||
37 | .previous | ||
38 | |||
39 | |||
40 | .text | ||
41 | .align 4 | ||
42 | .global memset | ||
43 | .type memset,@function | ||
44 | memset: | ||
45 | entry sp, 16 # minimal stack frame | ||
46 | # a2/ dst, a3/ c, a4/ length | ||
47 | extui a3, a3, 0, 8 # mask to just 8 bits | ||
48 | slli a7, a3, 8 # duplicate character in all bytes of word | ||
49 | or a3, a3, a7 # ... | ||
50 | slli a7, a3, 16 # ... | ||
51 | or a3, a3, a7 # ... | ||
52 | mov a5, a2 # copy dst so that a2 is return value | ||
53 | movi a6, 3 # for alignment tests | ||
54 | bany a2, a6, .Ldstunaligned # if dst is unaligned | ||
55 | .L0: # return here from .Ldstunaligned when dst is aligned | ||
56 | srli a7, a4, 4 # number of loop iterations with 16B | ||
57 | # per iteration | ||
58 | bnez a4, .Laligned | ||
59 | retw | ||
60 | |||
61 | /* | ||
62 | * Destination is word-aligned. | ||
63 | */ | ||
64 | # set 16 bytes per iteration for word-aligned dst | ||
65 | .align 4 # 1 mod 4 alignment for LOOPNEZ | ||
66 | .byte 0 # (0 mod 4 alignment for LBEG) | ||
67 | .Laligned: | ||
68 | #if XCHAL_HAVE_LOOPS | ||
69 | loopnez a7, .Loop1done | ||
70 | #else /* !XCHAL_HAVE_LOOPS */ | ||
71 | beqz a7, .Loop1done | ||
72 | slli a6, a7, 4 | ||
73 | add a6, a6, a5 # a6 = end of last 16B chunk | ||
74 | #endif /* !XCHAL_HAVE_LOOPS */ | ||
75 | .Loop1: | ||
76 | EX(s32i, a3, a5, 0, memset_fixup) | ||
77 | EX(s32i, a3, a5, 4, memset_fixup) | ||
78 | EX(s32i, a3, a5, 8, memset_fixup) | ||
79 | EX(s32i, a3, a5, 12, memset_fixup) | ||
80 | addi a5, a5, 16 | ||
81 | #if !XCHAL_HAVE_LOOPS | ||
82 | blt a5, a6, .Loop1 | ||
83 | #endif /* !XCHAL_HAVE_LOOPS */ | ||
84 | .Loop1done: | ||
85 | bbci.l a4, 3, .L2 | ||
86 | # set 8 bytes | ||
87 | EX(s32i, a3, a5, 0, memset_fixup) | ||
88 | EX(s32i, a3, a5, 4, memset_fixup) | ||
89 | addi a5, a5, 8 | ||
90 | .L2: | ||
91 | bbci.l a4, 2, .L3 | ||
92 | # set 4 bytes | ||
93 | EX(s32i, a3, a5, 0, memset_fixup) | ||
94 | addi a5, a5, 4 | ||
95 | .L3: | ||
96 | bbci.l a4, 1, .L4 | ||
97 | # set 2 bytes | ||
98 | EX(s16i, a3, a5, 0, memset_fixup) | ||
99 | addi a5, a5, 2 | ||
100 | .L4: | ||
101 | bbci.l a4, 0, .L5 | ||
102 | # set 1 byte | ||
103 | EX(s8i, a3, a5, 0, memset_fixup) | ||
104 | .L5: | ||
105 | .Lret1: | ||
106 | retw | ||
107 | |||
108 | /* | ||
109 | * Destination is unaligned | ||
110 | */ | ||
111 | |||
112 | .Ldstunaligned: | ||
113 | bltui a4, 8, .Lbyteset # do short copies byte by byte | ||
114 | bbci.l a5, 0, .L20 # branch if dst alignment half-aligned | ||
115 | # dst is only byte aligned | ||
116 | # set 1 byte | ||
117 | EX(s8i, a3, a5, 0, memset_fixup) | ||
118 | addi a5, a5, 1 | ||
119 | addi a4, a4, -1 | ||
120 | # now retest if dst aligned | ||
121 | bbci.l a5, 1, .L0 # if now aligned, return to main algorithm | ||
122 | .L20: | ||
123 | # dst half-aligned | ||
124 | # set 2 bytes | ||
125 | EX(s16i, a3, a5, 0, memset_fixup) | ||
126 | addi a5, a5, 2 | ||
127 | addi a4, a4, -2 | ||
128 | j .L0 # dst is now aligned, return to main algorithm | ||
129 | |||
130 | /* | ||
131 | * Byte by byte set | ||
132 | */ | ||
133 | .align 4 | ||
134 | .byte 0 # 1 mod 4 alignment for LOOPNEZ | ||
135 | # (0 mod 4 alignment for LBEG) | ||
136 | .Lbyteset: | ||
137 | #if XCHAL_HAVE_LOOPS | ||
138 | loopnez a4, .Lbytesetdone | ||
139 | #else /* !XCHAL_HAVE_LOOPS */ | ||
140 | beqz a4, .Lbytesetdone | ||
141 | add a6, a5, a4 # a6 = ending address | ||
142 | #endif /* !XCHAL_HAVE_LOOPS */ | ||
143 | .Lbyteloop: | ||
144 | EX(s8i, a3, a5, 0, memset_fixup) | ||
145 | addi a5, a5, 1 | ||
146 | #if !XCHAL_HAVE_LOOPS | ||
147 | blt a5, a6, .Lbyteloop | ||
148 | #endif /* !XCHAL_HAVE_LOOPS */ | ||
149 | .Lbytesetdone: | ||
150 | retw | ||
151 | |||
152 | |||
153 | .section .fixup, "ax" | ||
154 | .align 4 | ||
155 | |||
156 | /* We return zero if a failure occurred. */ | ||
157 | |||
158 | memset_fixup: | ||
159 | movi a2, 0 | ||
160 | retw | ||