xref: /openbmc/linux/arch/sparc/lib/NG4memcpy.S (revision f3a8b664)
1/* NG4memcpy.S: Niagara-4 optimized memcpy.
2 *
3 * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
4 */
5
6#ifdef __KERNEL__
7#include <linux/linkage.h>
8#include <asm/visasm.h>
9#include <asm/asi.h>
10#define GLOBAL_SPARE	%g7
11#else
12#define ASI_BLK_INIT_QUAD_LDD_P 0xe2
13#define FPRS_FEF  0x04
14
15/* On T4 it is very expensive to access ASRs like %fprs and
16 * %asi, avoiding a read or a write can save ~50 cycles.
17 */
18#define FPU_ENTER			\
19	rd	%fprs, %o5;		\
20	andcc	%o5, FPRS_FEF, %g0;	\
21	be,a,pn	%icc, 999f;		\
22	 wr	%g0, FPRS_FEF, %fprs;	\
23	999:
24
25#ifdef MEMCPY_DEBUG
26#define VISEntryHalf FPU_ENTER; \
27		     clr %g1; clr %g2; clr %g3; clr %g5; subcc %g0, %g0, %g0;
28#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
29#else
30#define VISEntryHalf FPU_ENTER
31#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
32#endif
33
34#define GLOBAL_SPARE	%g5
35#endif
36
37#ifndef STORE_ASI
38#ifndef SIMULATE_NIAGARA_ON_NON_NIAGARA
39#define STORE_ASI	ASI_BLK_INIT_QUAD_LDD_P
40#else
41#define STORE_ASI	0x80		/* ASI_P */
42#endif
43#endif
44
45#if !defined(EX_LD) && !defined(EX_ST)
46#define NON_USER_COPY
47#endif
48
49#ifndef EX_LD
50#define EX_LD(x,y)	x
51#endif
52#ifndef EX_LD_FP
53#define EX_LD_FP(x,y)	x
54#endif
55
56#ifndef EX_ST
57#define EX_ST(x,y)	x
58#endif
59#ifndef EX_ST_FP
60#define EX_ST_FP(x,y)	x
61#endif
62
63
64#ifndef LOAD
65#define LOAD(type,addr,dest)	type [addr], dest
66#endif
67
68#ifndef STORE
69#ifndef MEMCPY_DEBUG
70#define STORE(type,src,addr)	type src, [addr]
71#else
72#define STORE(type,src,addr)	type##a src, [addr] %asi
73#endif
74#endif
75
76#ifndef STORE_INIT
77#define STORE_INIT(src,addr)	stxa src, [addr] STORE_ASI
78#endif
79
80#ifndef FUNC_NAME
81#define FUNC_NAME	NG4memcpy
82#endif
83#ifndef PREAMBLE
84#define PREAMBLE
85#endif
86
87#ifndef XCC
88#define XCC xcc
89#endif
90
91	.register	%g2,#scratch
92	.register	%g3,#scratch
93
94	.text
95#ifndef EX_RETVAL
96#define EX_RETVAL(x)	x
97__restore_asi_fp:
98	VISExitHalf
99__restore_asi:
100	retl
101	 wr	%g0, ASI_AIUS, %asi
102
103ENTRY(NG4_retl_o2)
104	ba,pt	%xcc, __restore_asi
105	 mov	%o2, %o0
106ENDPROC(NG4_retl_o2)
107ENTRY(NG4_retl_o2_plus_1)
108	ba,pt	%xcc, __restore_asi
109	 add	%o2, 1, %o0
110ENDPROC(NG4_retl_o2_plus_1)
111ENTRY(NG4_retl_o2_plus_4)
112	ba,pt	%xcc, __restore_asi
113	 add	%o2, 4, %o0
114ENDPROC(NG4_retl_o2_plus_4)
115ENTRY(NG4_retl_o2_plus_o5)
116	ba,pt	%xcc, __restore_asi
117	 add	%o2, %o5, %o0
118ENDPROC(NG4_retl_o2_plus_o5)
119ENTRY(NG4_retl_o2_plus_o5_plus_4)
120	add	%o5, 4, %o5
121	ba,pt	%xcc, __restore_asi
122	 add	%o2, %o5, %o0
123ENDPROC(NG4_retl_o2_plus_o5_plus_4)
124ENTRY(NG4_retl_o2_plus_o5_plus_8)
125	add	%o5, 8, %o5
126	ba,pt	%xcc, __restore_asi
127	 add	%o2, %o5, %o0
128ENDPROC(NG4_retl_o2_plus_o5_plus_8)
129ENTRY(NG4_retl_o2_plus_o5_plus_16)
130	add	%o5, 16, %o5
131	ba,pt	%xcc, __restore_asi
132	 add	%o2, %o5, %o0
133ENDPROC(NG4_retl_o2_plus_o5_plus_16)
134ENTRY(NG4_retl_o2_plus_o5_plus_24)
135	add	%o5, 24, %o5
136	ba,pt	%xcc, __restore_asi
137	 add	%o2, %o5, %o0
138ENDPROC(NG4_retl_o2_plus_o5_plus_24)
139ENTRY(NG4_retl_o2_plus_o5_plus_32)
140	add	%o5, 32, %o5
141	ba,pt	%xcc, __restore_asi
142	 add	%o2, %o5, %o0
143ENDPROC(NG4_retl_o2_plus_o5_plus_32)
144ENTRY(NG4_retl_o2_plus_g1)
145	ba,pt	%xcc, __restore_asi
146	 add	%o2, %g1, %o0
147ENDPROC(NG4_retl_o2_plus_g1)
148ENTRY(NG4_retl_o2_plus_g1_plus_1)
149	add	%g1, 1, %g1
150	ba,pt	%xcc, __restore_asi
151	 add	%o2, %g1, %o0
152ENDPROC(NG4_retl_o2_plus_g1_plus_1)
153ENTRY(NG4_retl_o2_plus_g1_plus_8)
154	add	%g1, 8, %g1
155	ba,pt	%xcc, __restore_asi
156	 add	%o2, %g1, %o0
157ENDPROC(NG4_retl_o2_plus_g1_plus_8)
158ENTRY(NG4_retl_o2_plus_o4)
159	ba,pt	%xcc, __restore_asi
160	 add	%o2, %o4, %o0
161ENDPROC(NG4_retl_o2_plus_o4)
162ENTRY(NG4_retl_o2_plus_o4_plus_8)
163	add	%o4, 8, %o4
164	ba,pt	%xcc, __restore_asi
165	 add	%o2, %o4, %o0
166ENDPROC(NG4_retl_o2_plus_o4_plus_8)
167ENTRY(NG4_retl_o2_plus_o4_plus_16)
168	add	%o4, 16, %o4
169	ba,pt	%xcc, __restore_asi
170	 add	%o2, %o4, %o0
171ENDPROC(NG4_retl_o2_plus_o4_plus_16)
172ENTRY(NG4_retl_o2_plus_o4_plus_24)
173	add	%o4, 24, %o4
174	ba,pt	%xcc, __restore_asi
175	 add	%o2, %o4, %o0
176ENDPROC(NG4_retl_o2_plus_o4_plus_24)
177ENTRY(NG4_retl_o2_plus_o4_plus_32)
178	add	%o4, 32, %o4
179	ba,pt	%xcc, __restore_asi
180	 add	%o2, %o4, %o0
181ENDPROC(NG4_retl_o2_plus_o4_plus_32)
182ENTRY(NG4_retl_o2_plus_o4_plus_40)
183	add	%o4, 40, %o4
184	ba,pt	%xcc, __restore_asi
185	 add	%o2, %o4, %o0
186ENDPROC(NG4_retl_o2_plus_o4_plus_40)
187ENTRY(NG4_retl_o2_plus_o4_plus_48)
188	add	%o4, 48, %o4
189	ba,pt	%xcc, __restore_asi
190	 add	%o2, %o4, %o0
191ENDPROC(NG4_retl_o2_plus_o4_plus_48)
192ENTRY(NG4_retl_o2_plus_o4_plus_56)
193	add	%o4, 56, %o4
194	ba,pt	%xcc, __restore_asi
195	 add	%o2, %o4, %o0
196ENDPROC(NG4_retl_o2_plus_o4_plus_56)
197ENTRY(NG4_retl_o2_plus_o4_plus_64)
198	add	%o4, 64, %o4
199	ba,pt	%xcc, __restore_asi
200	 add	%o2, %o4, %o0
201ENDPROC(NG4_retl_o2_plus_o4_plus_64)
202ENTRY(NG4_retl_o2_plus_o4_fp)
203	ba,pt	%xcc, __restore_asi_fp
204	 add	%o2, %o4, %o0
205ENDPROC(NG4_retl_o2_plus_o4_fp)
206ENTRY(NG4_retl_o2_plus_o4_plus_8_fp)
207	add	%o4, 8, %o4
208	ba,pt	%xcc, __restore_asi_fp
209	 add	%o2, %o4, %o0
210ENDPROC(NG4_retl_o2_plus_o4_plus_8_fp)
211ENTRY(NG4_retl_o2_plus_o4_plus_16_fp)
212	add	%o4, 16, %o4
213	ba,pt	%xcc, __restore_asi_fp
214	 add	%o2, %o4, %o0
215ENDPROC(NG4_retl_o2_plus_o4_plus_16_fp)
216ENTRY(NG4_retl_o2_plus_o4_plus_24_fp)
217	add	%o4, 24, %o4
218	ba,pt	%xcc, __restore_asi_fp
219	 add	%o2, %o4, %o0
220ENDPROC(NG4_retl_o2_plus_o4_plus_24_fp)
221ENTRY(NG4_retl_o2_plus_o4_plus_32_fp)
222	add	%o4, 32, %o4
223	ba,pt	%xcc, __restore_asi_fp
224	 add	%o2, %o4, %o0
225ENDPROC(NG4_retl_o2_plus_o4_plus_32_fp)
226ENTRY(NG4_retl_o2_plus_o4_plus_40_fp)
227	add	%o4, 40, %o4
228	ba,pt	%xcc, __restore_asi_fp
229	 add	%o2, %o4, %o0
230ENDPROC(NG4_retl_o2_plus_o4_plus_40_fp)
231ENTRY(NG4_retl_o2_plus_o4_plus_48_fp)
232	add	%o4, 48, %o4
233	ba,pt	%xcc, __restore_asi_fp
234	 add	%o2, %o4, %o0
235ENDPROC(NG4_retl_o2_plus_o4_plus_48_fp)
236ENTRY(NG4_retl_o2_plus_o4_plus_56_fp)
237	add	%o4, 56, %o4
238	ba,pt	%xcc, __restore_asi_fp
239	 add	%o2, %o4, %o0
240ENDPROC(NG4_retl_o2_plus_o4_plus_56_fp)
241ENTRY(NG4_retl_o2_plus_o4_plus_64_fp)
242	add	%o4, 64, %o4
243	ba,pt	%xcc, __restore_asi_fp
244	 add	%o2, %o4, %o0
245ENDPROC(NG4_retl_o2_plus_o4_plus_64_fp)
246#endif
247	.align		64
248
249	.globl	FUNC_NAME
250	.type	FUNC_NAME,#function
251FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len */
252#ifdef MEMCPY_DEBUG
253	wr		%g0, 0x80, %asi
254#endif
255	srlx		%o2, 31, %g2
256	cmp		%g2, 0
257	tne		%XCC, 5
258	PREAMBLE
259	mov		%o0, %o3
260	brz,pn		%o2, .Lexit
261	 cmp		%o2, 3
262	ble,pn		%icc, .Ltiny
263	 cmp		%o2, 19
264	ble,pn		%icc, .Lsmall
265	 or		%o0, %o1, %g2
266	cmp		%o2, 128
267	bl,pn		%icc, .Lmedium
268	 nop
269
270.Llarge:/* len >= 0x80 */
271	/* First get dest 8 byte aligned.  */
272	sub		%g0, %o0, %g1
273	and		%g1, 0x7, %g1
274	brz,pt		%g1, 51f
275	 sub		%o2, %g1, %o2
276
277
2781:	EX_LD(LOAD(ldub, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
279	add		%o1, 1, %o1
280	subcc		%g1, 1, %g1
281	add		%o0, 1, %o0
282	bne,pt		%icc, 1b
283	 EX_ST(STORE(stb, %g2, %o0 - 0x01), NG4_retl_o2_plus_g1_plus_1)
284
28551:	LOAD(prefetch, %o1 + 0x040, #n_reads_strong)
286	LOAD(prefetch, %o1 + 0x080, #n_reads_strong)
287	LOAD(prefetch, %o1 + 0x0c0, #n_reads_strong)
288	LOAD(prefetch, %o1 + 0x100, #n_reads_strong)
289	LOAD(prefetch, %o1 + 0x140, #n_reads_strong)
290	LOAD(prefetch, %o1 + 0x180, #n_reads_strong)
291	LOAD(prefetch, %o1 + 0x1c0, #n_reads_strong)
292	LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
293
294	/* Check if we can use the straight fully aligned
295	 * loop, or we require the alignaddr/faligndata variant.
296	 */
297	andcc		%o1, 0x7, %o5
298	bne,pn		%icc, .Llarge_src_unaligned
299	 sub		%g0, %o0, %g1
300
301	/* Legitimize the use of initializing stores by getting dest
302	 * to be 64-byte aligned.
303	 */
304	and		%g1, 0x3f, %g1
305	brz,pt		%g1, .Llarge_aligned
306	 sub		%o2, %g1, %o2
307
3081:	EX_LD(LOAD(ldx, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
309	add		%o1, 8, %o1
310	subcc		%g1, 8, %g1
311	add		%o0, 8, %o0
312	bne,pt		%icc, 1b
313	 EX_ST(STORE(stx, %g2, %o0 - 0x08), NG4_retl_o2_plus_g1_plus_8)
314
315.Llarge_aligned:
316	/* len >= 0x80 && src 8-byte aligned && dest 8-byte aligned */
317	andn		%o2, 0x3f, %o4
318	sub		%o2, %o4, %o2
319
3201:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o4)
321	add		%o1, 0x40, %o1
322	EX_LD(LOAD(ldx, %o1 - 0x38, %g2), NG4_retl_o2_plus_o4)
323	subcc		%o4, 0x40, %o4
324	EX_LD(LOAD(ldx, %o1 - 0x30, %g3), NG4_retl_o2_plus_o4_plus_64)
325	EX_LD(LOAD(ldx, %o1 - 0x28, GLOBAL_SPARE), NG4_retl_o2_plus_o4_plus_64)
326	EX_LD(LOAD(ldx, %o1 - 0x20, %o5), NG4_retl_o2_plus_o4_plus_64)
327	EX_ST(STORE_INIT(%g1, %o0), NG4_retl_o2_plus_o4_plus_64)
328	add		%o0, 0x08, %o0
329	EX_ST(STORE_INIT(%g2, %o0), NG4_retl_o2_plus_o4_plus_56)
330	add		%o0, 0x08, %o0
331	EX_LD(LOAD(ldx, %o1 - 0x18, %g2), NG4_retl_o2_plus_o4_plus_48)
332	EX_ST(STORE_INIT(%g3, %o0), NG4_retl_o2_plus_o4_plus_48)
333	add		%o0, 0x08, %o0
334	EX_LD(LOAD(ldx, %o1 - 0x10, %g3), NG4_retl_o2_plus_o4_plus_40)
335	EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), NG4_retl_o2_plus_o4_plus_40)
336	add		%o0, 0x08, %o0
337	EX_LD(LOAD(ldx, %o1 - 0x08, GLOBAL_SPARE), NG4_retl_o2_plus_o4_plus_32)
338	EX_ST(STORE_INIT(%o5, %o0), NG4_retl_o2_plus_o4_plus_32)
339	add		%o0, 0x08, %o0
340	EX_ST(STORE_INIT(%g2, %o0), NG4_retl_o2_plus_o4_plus_24)
341	add		%o0, 0x08, %o0
342	EX_ST(STORE_INIT(%g3, %o0), NG4_retl_o2_plus_o4_plus_16)
343	add		%o0, 0x08, %o0
344	EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), NG4_retl_o2_plus_o4_plus_8)
345	add		%o0, 0x08, %o0
346	bne,pt		%icc, 1b
347	 LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
348
349	membar		#StoreLoad | #StoreStore
350
351	brz,pn		%o2, .Lexit
352	 cmp		%o2, 19
353	ble,pn		%icc, .Lsmall_unaligned
354	 nop
355	ba,a,pt		%icc, .Lmedium_noprefetch
356
357.Lexit:	retl
358	 mov		EX_RETVAL(%o3), %o0
359
360.Llarge_src_unaligned:
361#ifdef NON_USER_COPY
362	VISEntryHalfFast(.Lmedium_vis_entry_fail)
363#else
364	VISEntryHalf
365#endif
366	andn		%o2, 0x3f, %o4
367	sub		%o2, %o4, %o2
368	alignaddr	%o1, %g0, %g1
369	add		%o1, %o4, %o1
370	EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0), NG4_retl_o2_plus_o4)
3711:	EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2), NG4_retl_o2_plus_o4)
372	subcc		%o4, 0x40, %o4
373	EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4), NG4_retl_o2_plus_o4_plus_64)
374	EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6), NG4_retl_o2_plus_o4_plus_64)
375	EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8), NG4_retl_o2_plus_o4_plus_64)
376	EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10), NG4_retl_o2_plus_o4_plus_64)
377	EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12), NG4_retl_o2_plus_o4_plus_64)
378	EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14), NG4_retl_o2_plus_o4_plus_64)
379	faligndata	%f0, %f2, %f16
380	EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0), NG4_retl_o2_plus_o4_plus_64)
381	faligndata	%f2, %f4, %f18
382	add		%g1, 0x40, %g1
383	faligndata	%f4, %f6, %f20
384	faligndata	%f6, %f8, %f22
385	faligndata	%f8, %f10, %f24
386	faligndata	%f10, %f12, %f26
387	faligndata	%f12, %f14, %f28
388	faligndata	%f14, %f0, %f30
389	EX_ST_FP(STORE(std, %f16, %o0 + 0x00), NG4_retl_o2_plus_o4_plus_64)
390	EX_ST_FP(STORE(std, %f18, %o0 + 0x08), NG4_retl_o2_plus_o4_plus_56)
391	EX_ST_FP(STORE(std, %f20, %o0 + 0x10), NG4_retl_o2_plus_o4_plus_48)
392	EX_ST_FP(STORE(std, %f22, %o0 + 0x18), NG4_retl_o2_plus_o4_plus_40)
393	EX_ST_FP(STORE(std, %f24, %o0 + 0x20), NG4_retl_o2_plus_o4_plus_32)
394	EX_ST_FP(STORE(std, %f26, %o0 + 0x28), NG4_retl_o2_plus_o4_plus_24)
395	EX_ST_FP(STORE(std, %f28, %o0 + 0x30), NG4_retl_o2_plus_o4_plus_16)
396	EX_ST_FP(STORE(std, %f30, %o0 + 0x38), NG4_retl_o2_plus_o4_plus_8)
397	add		%o0, 0x40, %o0
398	bne,pt		%icc, 1b
399	 LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
400#ifdef NON_USER_COPY
401	VISExitHalfFast
402#else
403	VISExitHalf
404#endif
405	brz,pn		%o2, .Lexit
406	 cmp		%o2, 19
407	ble,pn		%icc, .Lsmall_unaligned
408	 nop
409	ba,a,pt		%icc, .Lmedium_unaligned
410
411#ifdef NON_USER_COPY
412.Lmedium_vis_entry_fail:
413	 or		%o0, %o1, %g2
414#endif
415.Lmedium:
416	LOAD(prefetch, %o1 + 0x40, #n_reads_strong)
417	andcc		%g2, 0x7, %g0
418	bne,pn		%icc, .Lmedium_unaligned
419	 nop
420.Lmedium_noprefetch:
421	andncc		%o2, 0x20 - 1, %o5
422	be,pn		%icc, 2f
423	 sub		%o2, %o5, %o2
4241:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
425	EX_LD(LOAD(ldx, %o1 + 0x08, %g2), NG4_retl_o2_plus_o5)
426	EX_LD(LOAD(ldx, %o1 + 0x10, GLOBAL_SPARE), NG4_retl_o2_plus_o5)
427	EX_LD(LOAD(ldx, %o1 + 0x18, %o4), NG4_retl_o2_plus_o5)
428	add		%o1, 0x20, %o1
429	subcc		%o5, 0x20, %o5
430	EX_ST(STORE(stx, %g1, %o0 + 0x00), NG4_retl_o2_plus_o5_plus_32)
431	EX_ST(STORE(stx, %g2, %o0 + 0x08), NG4_retl_o2_plus_o5_plus_24)
432	EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10), NG4_retl_o2_plus_o5_plus_24)
433	EX_ST(STORE(stx, %o4, %o0 + 0x18), NG4_retl_o2_plus_o5_plus_8)
434	bne,pt		%icc, 1b
435	 add		%o0, 0x20, %o0
4362:	andcc		%o2, 0x18, %o5
437	be,pt		%icc, 3f
438	 sub		%o2, %o5, %o2
439
4401:	EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
441	add		%o1, 0x08, %o1
442	add		%o0, 0x08, %o0
443	subcc		%o5, 0x08, %o5
444	bne,pt		%icc, 1b
445	 EX_ST(STORE(stx, %g1, %o0 - 0x08), NG4_retl_o2_plus_o5_plus_8)
4463:	brz,pt		%o2, .Lexit
447	 cmp		%o2, 0x04
448	bl,pn		%icc, .Ltiny
449	 nop
450	EX_LD(LOAD(lduw, %o1 + 0x00, %g1), NG4_retl_o2)
451	add		%o1, 0x04, %o1
452	add		%o0, 0x04, %o0
453	subcc		%o2, 0x04, %o2
454	bne,pn		%icc, .Ltiny
455	 EX_ST(STORE(stw, %g1, %o0 - 0x04), NG4_retl_o2_plus_4)
456	ba,a,pt		%icc, .Lexit
457.Lmedium_unaligned:
458	/* First get dest 8 byte aligned.  */
459	sub		%g0, %o0, %g1
460	and		%g1, 0x7, %g1
461	brz,pt		%g1, 2f
462	 sub		%o2, %g1, %o2
463
4641:	EX_LD(LOAD(ldub, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
465	add		%o1, 1, %o1
466	subcc		%g1, 1, %g1
467	add		%o0, 1, %o0
468	bne,pt		%icc, 1b
469	 EX_ST(STORE(stb, %g2, %o0 - 0x01), NG4_retl_o2_plus_g1_plus_1)
4702:
471	and		%o1, 0x7, %g1
472	brz,pn		%g1, .Lmedium_noprefetch
473	 sll		%g1, 3, %g1
474	mov		64, %g2
475	sub		%g2, %g1, %g2
476	andn		%o1, 0x7, %o1
477	EX_LD(LOAD(ldx, %o1 + 0x00, %o4), NG4_retl_o2)
478	sllx		%o4, %g1, %o4
479	andn		%o2, 0x08 - 1, %o5
480	sub		%o2, %o5, %o2
4811:	EX_LD(LOAD(ldx, %o1 + 0x08, %g3), NG4_retl_o2_plus_o5)
482	add		%o1, 0x08, %o1
483	subcc		%o5, 0x08, %o5
484	srlx		%g3, %g2, GLOBAL_SPARE
485	or		GLOBAL_SPARE, %o4, GLOBAL_SPARE
486	EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x00), NG4_retl_o2_plus_o5_plus_8)
487	add		%o0, 0x08, %o0
488	bne,pt		%icc, 1b
489	 sllx		%g3, %g1, %o4
490	srl		%g1, 3, %g1
491	add		%o1, %g1, %o1
492	brz,pn		%o2, .Lexit
493	 nop
494	ba,pt		%icc, .Lsmall_unaligned
495
496.Ltiny:
497	EX_LD(LOAD(ldub, %o1 + 0x00, %g1), NG4_retl_o2)
498	subcc		%o2, 1, %o2
499	be,pn		%icc, .Lexit
500	 EX_ST(STORE(stb, %g1, %o0 + 0x00), NG4_retl_o2_plus_1)
501	EX_LD(LOAD(ldub, %o1 + 0x01, %g1), NG4_retl_o2)
502	subcc		%o2, 1, %o2
503	be,pn		%icc, .Lexit
504	 EX_ST(STORE(stb, %g1, %o0 + 0x01), NG4_retl_o2_plus_1)
505	EX_LD(LOAD(ldub, %o1 + 0x02, %g1), NG4_retl_o2)
506	ba,pt		%icc, .Lexit
507	 EX_ST(STORE(stb, %g1, %o0 + 0x02), NG4_retl_o2)
508
509.Lsmall:
510	andcc		%g2, 0x3, %g0
511	bne,pn		%icc, .Lsmall_unaligned
512	 andn		%o2, 0x4 - 1, %o5
513	sub		%o2, %o5, %o2
5141:
515	EX_LD(LOAD(lduw, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
516	add		%o1, 0x04, %o1
517	subcc		%o5, 0x04, %o5
518	add		%o0, 0x04, %o0
519	bne,pt		%icc, 1b
520	 EX_ST(STORE(stw, %g1, %o0 - 0x04), NG4_retl_o2_plus_o5_plus_4)
521	brz,pt		%o2, .Lexit
522	 nop
523	ba,a,pt		%icc, .Ltiny
524
525.Lsmall_unaligned:
5261:	EX_LD(LOAD(ldub, %o1 + 0x00, %g1), NG4_retl_o2)
527	add		%o1, 1, %o1
528	add		%o0, 1, %o0
529	subcc		%o2, 1, %o2
530	bne,pt		%icc, 1b
531	 EX_ST(STORE(stb, %g1, %o0 - 0x01), NG4_retl_o2_plus_1)
532	ba,a,pt		%icc, .Lexit
533	.size		FUNC_NAME, .-FUNC_NAME
534