611f5c8a72d956edca09f32a01406446178b1a89
[ffmpeg.git] / libavcodec / x86 / dsputil_yasm.asm
1 ;******************************************************************************
2 ;* MMX optimized DSP utils
3 ;* Copyright (c) 2008 Loren Merritt
4 ;*
5 ;* This file is part of Libav.
6 ;*
7 ;* Libav is free software; you can redistribute it and/or
8 ;* modify it under the terms of the GNU Lesser General Public
9 ;* License as published by the Free Software Foundation; either
10 ;* version 2.1 of the License, or (at your option) any later version.
11 ;*
12 ;* Libav is distributed in the hope that it will be useful,
13 ;* but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 ;* Lesser General Public License for more details.
16 ;*
17 ;* You should have received a copy of the GNU Lesser General Public
18 ;* License along with Libav; if not, write to the Free Software
19 ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 ;******************************************************************************
21
22 %include "x86inc.asm"
23 %include "x86util.asm"
24
25 SECTION_RODATA
26 pb_f: times 16 db 15
27 pb_zzzzzzzz77777777: times 8 db -1
28 pb_7: times 8 db 7
29 pb_zzzz3333zzzzbbbb: db -1,-1,-1,-1,3,3,3,3,-1,-1,-1,-1,11,11,11,11
30 pb_zz11zz55zz99zzdd: db -1,-1,1,1,-1,-1,5,5,-1,-1,9,9,-1,-1,13,13
31 pb_revwords: db 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1
32 pd_16384: times 4 dd 16384
33 pb_bswap32: db 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
34
35 SECTION_TEXT
36
37 %macro SCALARPRODUCT 1
38 ; int scalarproduct_int16(int16_t *v1, int16_t *v2, int order, int shift)
39 cglobal scalarproduct_int16_%1, 3,3,4, v1, v2, order, shift
40     shl orderq, 1
41     add v1q, orderq
42     add v2q, orderq
43     neg orderq
44     movd    m3, shiftm
45     pxor    m2, m2
46 .loop:
47     movu    m0, [v1q + orderq]
48     movu    m1, [v1q + orderq + mmsize]
49     pmaddwd m0, [v2q + orderq]
50     pmaddwd m1, [v2q + orderq + mmsize]
51     paddd   m2, m0
52     paddd   m2, m1
53     add     orderq, mmsize*2
54     jl .loop
55 %if mmsize == 16
56     movhlps m0, m2
57     paddd   m2, m0
58     psrad   m2, m3
59     pshuflw m0, m2, 0x4e
60 %else
61     psrad   m2, m3
62     pshufw  m0, m2, 0x4e
63 %endif
64     paddd   m2, m0
65     movd   eax, m2
66     RET
67
68 ; int scalarproduct_and_madd_int16(int16_t *v1, int16_t *v2, int16_t *v3, int order, int mul)
69 cglobal scalarproduct_and_madd_int16_%1, 4,4,8, v1, v2, v3, order, mul
70     shl orderq, 1
71     movd    m7, mulm
72 %if mmsize == 16
73     pshuflw m7, m7, 0
74     punpcklqdq m7, m7
75 %else
76     pshufw  m7, m7, 0
77 %endif
78     pxor    m6, m6
79     add v1q, orderq
80     add v2q, orderq
81     add v3q, orderq
82     neg orderq
83 .loop:
84     movu    m0, [v2q + orderq]
85     movu    m1, [v2q + orderq + mmsize]
86     mova    m4, [v1q + orderq]
87     mova    m5, [v1q + orderq + mmsize]
88     movu    m2, [v3q + orderq]
89     movu    m3, [v3q + orderq + mmsize]
90     pmaddwd m0, m4
91     pmaddwd m1, m5
92     pmullw  m2, m7
93     pmullw  m3, m7
94     paddd   m6, m0
95     paddd   m6, m1
96     paddw   m2, m4
97     paddw   m3, m5
98     mova    [v1q + orderq], m2
99     mova    [v1q + orderq + mmsize], m3
100     add     orderq, mmsize*2
101     jl .loop
102 %if mmsize == 16
103     movhlps m0, m6
104     paddd   m6, m0
105     pshuflw m0, m6, 0x4e
106 %else
107     pshufw  m0, m6, 0x4e
108 %endif
109     paddd   m6, m0
110     movd   eax, m6
111     RET
112 %endmacro
113
114 INIT_MMX
115 SCALARPRODUCT mmx2
116 INIT_XMM
117 SCALARPRODUCT sse2
118
119 %macro SCALARPRODUCT_LOOP 1
120 align 16
121 .loop%1:
122     sub     orderq, mmsize*2
123 %if %1
124     mova    m1, m4
125     mova    m4, [v2q + orderq]
126     mova    m0, [v2q + orderq + mmsize]
127     palignr m1, m0, %1
128     palignr m0, m4, %1
129     mova    m3, m5
130     mova    m5, [v3q + orderq]
131     mova    m2, [v3q + orderq + mmsize]
132     palignr m3, m2, %1
133     palignr m2, m5, %1
134 %else
135     mova    m0, [v2q + orderq]
136     mova    m1, [v2q + orderq + mmsize]
137     mova    m2, [v3q + orderq]
138     mova    m3, [v3q + orderq + mmsize]
139 %endif
140     %define t0  [v1q + orderq]
141     %define t1  [v1q + orderq + mmsize]
142 %if ARCH_X86_64
143     mova    m8, t0
144     mova    m9, t1
145     %define t0  m8
146     %define t1  m9
147 %endif
148     pmaddwd m0, t0
149     pmaddwd m1, t1
150     pmullw  m2, m7
151     pmullw  m3, m7
152     paddw   m2, t0
153     paddw   m3, t1
154     paddd   m6, m0
155     paddd   m6, m1
156     mova    [v1q + orderq], m2
157     mova    [v1q + orderq + mmsize], m3
158     jg .loop%1
159 %if %1
160     jmp .end
161 %endif
162 %endmacro
163
164 ; int scalarproduct_and_madd_int16(int16_t *v1, int16_t *v2, int16_t *v3, int order, int mul)
165 cglobal scalarproduct_and_madd_int16_ssse3, 4,5,10, v1, v2, v3, order, mul
166     shl orderq, 1
167     movd    m7, mulm
168     pshuflw m7, m7, 0
169     punpcklqdq m7, m7
170     pxor    m6, m6
171     mov    r4d, v2d
172     and    r4d, 15
173     and    v2q, ~15
174     and    v3q, ~15
175     mova    m4, [v2q + orderq]
176     mova    m5, [v3q + orderq]
177     ; linear is faster than branch tree or jump table, because the branches taken are cyclic (i.e. predictable)
178     cmp    r4d, 0
179     je .loop0
180     cmp    r4d, 2
181     je .loop2
182     cmp    r4d, 4
183     je .loop4
184     cmp    r4d, 6
185     je .loop6
186     cmp    r4d, 8
187     je .loop8
188     cmp    r4d, 10
189     je .loop10
190     cmp    r4d, 12
191     je .loop12
192 SCALARPRODUCT_LOOP 14
193 SCALARPRODUCT_LOOP 12
194 SCALARPRODUCT_LOOP 10
195 SCALARPRODUCT_LOOP 8
196 SCALARPRODUCT_LOOP 6
197 SCALARPRODUCT_LOOP 4
198 SCALARPRODUCT_LOOP 2
199 SCALARPRODUCT_LOOP 0
200 .end:
201     movhlps m0, m6
202     paddd   m6, m0
203     pshuflw m0, m6, 0x4e
204     paddd   m6, m0
205     movd   eax, m6
206     RET
207
208
209 ;-----------------------------------------------------------------------------
210 ; void ff_apply_window_int16(int16_t *output, const int16_t *input,
211 ;                            const int16_t *window, unsigned int len)
212 ;-----------------------------------------------------------------------------
213
214 %macro REVERSE_WORDS_MMXEXT 1-2
215     pshufw   %1, %1, 0x1B
216 %endmacro
217
218 %macro REVERSE_WORDS_SSE2 1-2
219     pshuflw  %1, %1, 0x1B
220     pshufhw  %1, %1, 0x1B
221     pshufd   %1, %1, 0x4E
222 %endmacro
223
224 %macro REVERSE_WORDS_SSSE3 2
225     pshufb  %1, %2
226 %endmacro
227
228 ; dst = (dst * src) >> 15
229 ; pmulhw cuts off the bottom bit, so we have to lshift by 1 and add it back
230 ; in from the pmullw result.
231 %macro MUL16FIXED_MMXEXT 3 ; dst, src, temp
232     mova    %3, %1
233     pmulhw  %1, %2
234     pmullw  %3, %2
235     psrlw   %3, 15
236     psllw   %1, 1
237     por     %1, %3
238 %endmacro
239
240 ; dst = ((dst * src) + (1<<14)) >> 15
241 %macro MUL16FIXED_SSSE3 3 ; dst, src, unused
242     pmulhrsw   %1, %2
243 %endmacro
244
245 %macro APPLY_WINDOW_INT16 3 ; %1=instruction set, %2=mmxext/sse2 bit exact version, %3=has_ssse3
246 cglobal apply_window_int16_%1, 4,5,6, output, input, window, offset, offset2
247     lea     offset2q, [offsetq-mmsize]
248 %if %2
249     mova          m5, [pd_16384]
250 %elifidn %1, ssse3
251     mova          m5, [pb_revwords]
252     ALIGN 16
253 %endif
254 .loop:
255 %if %2
256     ; This version expands 16-bit to 32-bit, multiplies by the window,
257     ; adds 16384 for rounding, right shifts 15, then repacks back to words to
258     ; save to the output. The window is reversed for the second half.
259     mova          m3, [windowq+offset2q]
260     mova          m4, [ inputq+offset2q]
261     pxor          m0, m0
262     punpcklwd     m0, m3
263     punpcklwd     m1, m4
264     pmaddwd       m0, m1
265     paddd         m0, m5
266     psrad         m0, 15
267     pxor          m2, m2
268     punpckhwd     m2, m3
269     punpckhwd     m1, m4
270     pmaddwd       m2, m1
271     paddd         m2, m5
272     psrad         m2, 15
273     packssdw      m0, m2
274     mova  [outputq+offset2q], m0
275     REVERSE_WORDS m3
276     mova          m4, [ inputq+offsetq]
277     pxor          m0, m0
278     punpcklwd     m0, m3
279     punpcklwd     m1, m4
280     pmaddwd       m0, m1
281     paddd         m0, m5
282     psrad         m0, 15
283     pxor          m2, m2
284     punpckhwd     m2, m3
285     punpckhwd     m1, m4
286     pmaddwd       m2, m1
287     paddd         m2, m5
288     psrad         m2, 15
289     packssdw      m0, m2
290     mova  [outputq+offsetq], m0
291 %elif %3
292     ; This version does the 16x16->16 multiplication in-place without expanding
293     ; to 32-bit. The ssse3 version is bit-identical.
294     mova          m0, [windowq+offset2q]
295     mova          m1, [ inputq+offset2q]
296     pmulhrsw      m1, m0
297     REVERSE_WORDS m0, m5
298     pmulhrsw      m0, [ inputq+offsetq ]
299     mova  [outputq+offset2q], m1
300     mova  [outputq+offsetq ], m0
301 %else
302     ; This version does the 16x16->16 multiplication in-place without expanding
303     ; to 32-bit. The mmxext and sse2 versions do not use rounding, and
304     ; therefore are not bit-identical to the C version.
305     mova          m0, [windowq+offset2q]
306     mova          m1, [ inputq+offset2q]
307     mova          m2, [ inputq+offsetq ]
308     MUL16FIXED    m1, m0, m3
309     REVERSE_WORDS m0
310     MUL16FIXED    m2, m0, m3
311     mova  [outputq+offset2q], m1
312     mova  [outputq+offsetq ], m2
313 %endif
314     add      offsetd, mmsize
315     sub     offset2d, mmsize
316     jae .loop
317     REP_RET
318 %endmacro
319
320 INIT_MMX
321 %define REVERSE_WORDS REVERSE_WORDS_MMXEXT
322 %define MUL16FIXED MUL16FIXED_MMXEXT
323 APPLY_WINDOW_INT16 mmxext,     0, 0
324 APPLY_WINDOW_INT16 mmxext_ba,  1, 0
325 INIT_XMM
326 %define REVERSE_WORDS REVERSE_WORDS_SSE2
327 APPLY_WINDOW_INT16 sse2,       0, 0
328 APPLY_WINDOW_INT16 sse2_ba,    1, 0
329 APPLY_WINDOW_INT16 ssse3_atom, 0, 1
330 %define REVERSE_WORDS REVERSE_WORDS_SSSE3
331 APPLY_WINDOW_INT16 ssse3,      0, 1
332
333
334 ; void add_hfyu_median_prediction_mmx2(uint8_t *dst, const uint8_t *top, const uint8_t *diff, int w, int *left, int *left_top)
335 cglobal add_hfyu_median_prediction_mmx2, 6,6,0, dst, top, diff, w, left, left_top
336     movq    mm0, [topq]
337     movq    mm2, mm0
338     movd    mm4, [left_topq]
339     psllq   mm2, 8
340     movq    mm1, mm0
341     por     mm4, mm2
342     movd    mm3, [leftq]
343     psubb   mm0, mm4 ; t-tl
344     add    dstq, wq
345     add    topq, wq
346     add   diffq, wq
347     neg      wq
348     jmp .skip
349 .loop:
350     movq    mm4, [topq+wq]
351     movq    mm0, mm4
352     psllq   mm4, 8
353     por     mm4, mm1
354     movq    mm1, mm0 ; t
355     psubb   mm0, mm4 ; t-tl
356 .skip:
357     movq    mm2, [diffq+wq]
358 %assign i 0
359 %rep 8
360     movq    mm4, mm0
361     paddb   mm4, mm3 ; t-tl+l
362     movq    mm5, mm3
363     pmaxub  mm3, mm1
364     pminub  mm5, mm1
365     pminub  mm3, mm4
366     pmaxub  mm3, mm5 ; median
367     paddb   mm3, mm2 ; +residual
368 %if i==0
369     movq    mm7, mm3
370     psllq   mm7, 56
371 %else
372     movq    mm6, mm3
373     psrlq   mm7, 8
374     psllq   mm6, 56
375     por     mm7, mm6
376 %endif
377 %if i<7
378     psrlq   mm0, 8
379     psrlq   mm1, 8
380     psrlq   mm2, 8
381 %endif
382 %assign i i+1
383 %endrep
384     movq [dstq+wq], mm7
385     add      wq, 8
386     jl .loop
387     movzx   r2d, byte [dstq-1]
388     mov [leftq], r2d
389     movzx   r2d, byte [topq-1]
390     mov [left_topq], r2d
391     RET
392
393
394 %macro ADD_HFYU_LEFT_LOOP 1 ; %1 = is_aligned
395     add     srcq, wq
396     add     dstq, wq
397     neg     wq
398 %%.loop:
399     mova    m1, [srcq+wq]
400     mova    m2, m1
401     psllw   m1, 8
402     paddb   m1, m2
403     mova    m2, m1
404     pshufb  m1, m3
405     paddb   m1, m2
406     pshufb  m0, m5
407     mova    m2, m1
408     pshufb  m1, m4
409     paddb   m1, m2
410 %if mmsize == 16
411     mova    m2, m1
412     pshufb  m1, m6
413     paddb   m1, m2
414 %endif
415     paddb   m0, m1
416 %if %1
417     mova    [dstq+wq], m0
418 %else
419     movq    [dstq+wq], m0
420     movhps  [dstq+wq+8], m0
421 %endif
422     add     wq, mmsize
423     jl %%.loop
424     mov     eax, mmsize-1
425     sub     eax, wd
426     movd    m1, eax
427     pshufb  m0, m1
428     movd    eax, m0
429     RET
430 %endmacro
431
432 ; int add_hfyu_left_prediction(uint8_t *dst, const uint8_t *src, int w, int left)
433 INIT_MMX
434 cglobal add_hfyu_left_prediction_ssse3, 3,3,7, dst, src, w, left
435 .skip_prologue:
436     mova    m5, [pb_7]
437     mova    m4, [pb_zzzz3333zzzzbbbb]
438     mova    m3, [pb_zz11zz55zz99zzdd]
439     movd    m0, leftm
440     psllq   m0, 56
441     ADD_HFYU_LEFT_LOOP 1
442
443 INIT_XMM
444 cglobal add_hfyu_left_prediction_sse4, 3,3,7, dst, src, w, left
445     mova    m5, [pb_f]
446     mova    m6, [pb_zzzzzzzz77777777]
447     mova    m4, [pb_zzzz3333zzzzbbbb]
448     mova    m3, [pb_zz11zz55zz99zzdd]
449     movd    m0, leftm
450     pslldq  m0, 15
451     test    srcq, 15
452     jnz add_hfyu_left_prediction_ssse3.skip_prologue
453     test    dstq, 15
454     jnz .unaligned
455     ADD_HFYU_LEFT_LOOP 1
456 .unaligned:
457     ADD_HFYU_LEFT_LOOP 0
458
459
460 ; float scalarproduct_float_sse(const float *v1, const float *v2, int len)
461 cglobal scalarproduct_float_sse, 3,3,2, v1, v2, offset
462     neg offsetq
463     shl offsetq, 2
464     sub v1q, offsetq
465     sub v2q, offsetq
466     xorps xmm0, xmm0
467     .loop:
468         movaps   xmm1, [v1q+offsetq]
469         mulps    xmm1, [v2q+offsetq]
470         addps    xmm0, xmm1
471         add      offsetq, 16
472         js       .loop
473     movhlps xmm1, xmm0
474     addps   xmm0, xmm1
475     movss   xmm1, xmm0
476     shufps  xmm0, xmm0, 1
477     addss   xmm0, xmm1
478 %if ARCH_X86_64 == 0
479     movd    r0m,  xmm0
480     fld     dword r0m
481 %endif
482     RET
483
484 ; extern void ff_emu_edge_core(uint8_t *buf, const uint8_t *src, x86_reg linesize,
485 ;                              x86_reg start_y, x86_reg end_y, x86_reg block_h,
486 ;                              x86_reg start_x, x86_reg end_x, x86_reg block_w);
487 ;
488 ; The actual function itself is below. It basically wraps a very simple
489 ; w = end_x - start_x
490 ; if (w) {
491 ;   if (w > 22) {
492 ;     jump to the slow loop functions
493 ;   } else {
494 ;     jump to the fast loop functions
495 ;   }
496 ; }
497 ;
498 ; ... and then the same for left/right extend also. See below for loop
499 ; function implementations. Fast are fixed-width, slow is variable-width
500
501 %macro EMU_EDGE_FUNC 0
502 %if ARCH_X86_64
503 %define w_reg r10
504 cglobal emu_edge_core, 6, 7, 1
505     mov        r11, r5          ; save block_h
506 %else
507 %define w_reg r6
508 cglobal emu_edge_core, 2, 7, 0
509     mov         r4, r4m         ; end_y
510     mov         r5, r5m         ; block_h
511 %endif
512
513     ; start with vertical extend (top/bottom) and body pixel copy
514     mov      w_reg, r7m
515     sub      w_reg, r6m         ; w = start_x - end_x
516     sub         r5, r4
517 %if ARCH_X86_64
518     sub         r4, r3
519 %else
520     sub         r4, dword r3m
521 %endif
522     cmp      w_reg, 22
523     jg .slow_v_extend_loop
524 %if ARCH_X86_32
525     mov         r2, r2m         ; linesize
526 %endif
527     sal      w_reg, 7           ; w * 128
528 %ifdef PIC
529     lea        rax, [.emuedge_v_extend_1 - (.emuedge_v_extend_2 - .emuedge_v_extend_1)]
530     add      w_reg, rax
531 %else
532     lea      w_reg, [.emuedge_v_extend_1 - (.emuedge_v_extend_2 - .emuedge_v_extend_1)+w_reg]
533 %endif
534     call     w_reg              ; fast top extend, body copy and bottom extend
535 .v_extend_end:
536
537     ; horizontal extend (left/right)
538     mov      w_reg, r6m         ; start_x
539     sub         r0, w_reg
540 %if ARCH_X86_64
541     mov         r3, r0          ; backup of buf+block_h*linesize
542     mov         r5, r11
543 %else
544     mov        r0m, r0          ; backup of buf+block_h*linesize
545     mov         r5, r5m
546 %endif
547     test     w_reg, w_reg
548     jz .right_extend
549     cmp      w_reg, 22
550     jg .slow_left_extend_loop
551     mov         r1, w_reg
552     dec      w_reg
553     ; FIXME we can do a if size == 1 here if that makes any speed difference, test me
554     sar      w_reg, 1
555     sal      w_reg, 6
556     ; r0=buf+block_h*linesize,r10(64)/r6(32)=start_x offset for funcs
557     ; r6(rax)/r3(ebx)=val,r2=linesize,r1=start_x,r5=block_h
558 %ifdef PIC
559     lea        rax, [.emuedge_extend_left_2]
560     add      w_reg, rax
561 %else
562     lea      w_reg, [.emuedge_extend_left_2+w_reg]
563 %endif
564     call     w_reg
565
566     ; now r3(64)/r0(32)=buf,r2=linesize,r11/r5=block_h,r6/r3=val, r10/r6=end_x, r1=block_w
567 .right_extend:
568 %if ARCH_X86_32
569     mov         r0, r0m
570     mov         r5, r5m
571 %endif
572     mov      w_reg, r7m         ; end_x
573     mov         r1, r8m         ; block_w
574     mov         r4, r1
575     sub         r1, w_reg
576     jz .h_extend_end            ; if (end_x == block_w) goto h_extend_end
577     cmp         r1, 22
578     jg .slow_right_extend_loop
579     dec         r1
580     ; FIXME we can do a if size == 1 here if that makes any speed difference, test me
581     sar         r1, 1
582     sal         r1, 6
583 %ifdef PIC
584     lea        rax, [.emuedge_extend_right_2]
585     add         r1, rax
586 %else
587     lea         r1, [.emuedge_extend_right_2+r1]
588 %endif
589     call        r1
590 .h_extend_end:
591     RET
592
593 %if ARCH_X86_64
594 %define vall  al
595 %define valh  ah
596 %define valw  ax
597 %define valw2 r10w
598 %define valw3 r3w
599 %if WIN64
600 %define valw4 r4w
601 %else ; unix64
602 %define valw4 r3w
603 %endif
604 %define vald eax
605 %else
606 %define vall  bl
607 %define valh  bh
608 %define valw  bx
609 %define valw2 r6w
610 %define valw3 valw2
611 %define valw4 valw3
612 %define vald ebx
613 %define stack_offset 0x14
614 %endif
615
616 %endmacro
617
618 ; macro to read/write a horizontal number of pixels (%2) to/from registers
619 ; on x86-64, - fills xmm0-15 for consecutive sets of 16 pixels
620 ;            - if (%2 & 15 == 8) fills the last 8 bytes into rax
621 ;            - else if (%2 & 8)  fills 8 bytes into mm0
622 ;            - if (%2 & 7 == 4)  fills the last 4 bytes into rax
623 ;            - else if (%2 & 4)  fills 4 bytes into mm0-1
624 ;            - if (%2 & 3 == 3)  fills 2 bytes into r10/r3, and 1 into eax
625 ;              (note that we're using r3 for body/bottom because it's a shorter
626 ;               opcode, and then the loop fits in 128 bytes)
627 ;            - else              fills remaining bytes into rax
628 ; on x86-32, - fills mm0-7 for consecutive sets of 8 pixels
629 ;            - if (%2 & 7 == 4)  fills 4 bytes into ebx
630 ;            - else if (%2 & 4)  fills 4 bytes into mm0-7
631 ;            - if (%2 & 3 == 3)  fills 2 bytes into r6, and 1 into ebx
632 ;            - else              fills remaining bytes into ebx
633 ; writing data out is in the same way
634 %macro READ_NUM_BYTES 2
635 %assign %%src_off 0 ; offset in source buffer
636 %assign %%smidx   0 ; mmx register idx
637 %assign %%sxidx   0 ; xmm register idx
638
639 %if cpuflag(sse)
640 %rep %2/16
641     movups xmm %+ %%sxidx, [r1+%%src_off]
642 %assign %%src_off %%src_off+16
643 %assign %%sxidx   %%sxidx+1
644 %endrep ; %2/16
645 %endif
646
647 %if ARCH_X86_64
648 %if (%2-%%src_off) == 8
649     mov           rax, [r1+%%src_off]
650 %assign %%src_off %%src_off+8
651 %endif ; (%2-%%src_off) == 8
652 %endif ; x86-64
653
654 %rep (%2-%%src_off)/8
655     movq    mm %+ %%smidx, [r1+%%src_off]
656 %assign %%src_off %%src_off+8
657 %assign %%smidx   %%smidx+1
658 %endrep ; (%2-%%dst_off)/8
659
660 %if (%2-%%src_off) == 4
661     mov          vald, [r1+%%src_off]
662 %elif (%2-%%src_off) & 4
663     movd    mm %+ %%smidx, [r1+%%src_off]
664 %assign %%src_off %%src_off+4
665 %endif ; (%2-%%src_off) ==/& 4
666
667 %if (%2-%%src_off) == 1
668     mov          vall, [r1+%%src_off]
669 %elif (%2-%%src_off) == 2
670     mov          valw, [r1+%%src_off]
671 %elif (%2-%%src_off) == 3
672 %ifidn %1, top
673     mov         valw2, [r1+%%src_off]
674 %elifidn %1, body
675     mov         valw3, [r1+%%src_off]
676 %elifidn %1, bottom
677     mov         valw4, [r1+%%src_off]
678 %endif ; %1 ==/!= top
679     mov          vall, [r1+%%src_off+2]
680 %endif ; (%2-%%src_off) == 1/2/3
681 %endmacro ; READ_NUM_BYTES
682
683 %macro WRITE_NUM_BYTES 2
684 %assign %%dst_off 0 ; offset in destination buffer
685 %assign %%dmidx   0 ; mmx register idx
686 %assign %%dxidx   0 ; xmm register idx
687
688 %if cpuflag(sse)
689 %rep %2/16
690     movups [r0+%%dst_off], xmm %+ %%dxidx
691 %assign %%dst_off %%dst_off+16
692 %assign %%dxidx   %%dxidx+1
693 %endrep ; %2/16
694 %endif
695
696 %if ARCH_X86_64
697 %if (%2-%%dst_off) == 8
698     mov    [r0+%%dst_off], rax
699 %assign %%dst_off %%dst_off+8
700 %endif ; (%2-%%dst_off) == 8
701 %endif ; x86-64
702
703 %rep (%2-%%dst_off)/8
704     movq   [r0+%%dst_off], mm %+ %%dmidx
705 %assign %%dst_off %%dst_off+8
706 %assign %%dmidx   %%dmidx+1
707 %endrep ; (%2-%%dst_off)/8
708
709 %if (%2-%%dst_off) == 4
710     mov    [r0+%%dst_off], vald
711 %elif (%2-%%dst_off) & 4
712     movd   [r0+%%dst_off], mm %+ %%dmidx
713 %assign %%dst_off %%dst_off+4
714 %endif ; (%2-%%dst_off) ==/& 4
715
716 %if (%2-%%dst_off) == 1
717     mov    [r0+%%dst_off], vall
718 %elif (%2-%%dst_off) == 2
719     mov    [r0+%%dst_off], valw
720 %elif (%2-%%dst_off) == 3
721 %ifidn %1, top
722     mov    [r0+%%dst_off], valw2
723 %elifidn %1, body
724     mov    [r0+%%dst_off], valw3
725 %elifidn %1, bottom
726     mov    [r0+%%dst_off], valw4
727 %endif ; %1 ==/!= top
728     mov  [r0+%%dst_off+2], vall
729 %endif ; (%2-%%dst_off) == 1/2/3
730 %endmacro ; WRITE_NUM_BYTES
731
732 ; vertical top/bottom extend and body copy fast loops
733 ; these are function pointers to set-width line copy functions, i.e.
734 ; they read a fixed number of pixels into set registers, and write
735 ; those out into the destination buffer
736 ; r0=buf,r1=src,r2=linesize,r3(64)/r3m(32)=start_x,r4=end_y,r5=block_h
737 ; r6(eax/64)/r3(ebx/32)=val_reg
738 %macro VERTICAL_EXTEND 0
739 %assign %%n 1
740 %rep 22
741 ALIGN 128
742 .emuedge_v_extend_ %+ %%n:
743     ; extend pixels above body
744 %if ARCH_X86_64
745     test           r3 , r3                   ; if (!start_y)
746     jz .emuedge_copy_body_ %+ %%n %+ _loop   ;   goto body
747 %else ; ARCH_X86_32
748     cmp      dword r3m, 0
749     je .emuedge_copy_body_ %+ %%n %+ _loop
750 %endif ; ARCH_X86_64/32
751     READ_NUM_BYTES  top,    %%n              ; read bytes
752 .emuedge_extend_top_ %+ %%n %+ _loop:        ; do {
753     WRITE_NUM_BYTES top,    %%n              ;   write bytes
754     add            r0 , r2                   ;   dst += linesize
755 %if ARCH_X86_64
756     dec            r3d
757 %else ; ARCH_X86_32
758     dec      dword r3m
759 %endif ; ARCH_X86_64/32
760     jnz .emuedge_extend_top_ %+ %%n %+ _loop ; } while (--start_y)
761
762     ; copy body pixels
763 .emuedge_copy_body_ %+ %%n %+ _loop:         ; do {
764     READ_NUM_BYTES  body,   %%n              ;   read bytes
765     WRITE_NUM_BYTES body,   %%n              ;   write bytes
766     add            r0 , r2                   ;   dst += linesize
767     add            r1 , r2                   ;   src += linesize
768     dec            r4d
769     jnz .emuedge_copy_body_ %+ %%n %+ _loop  ; } while (--end_y)
770
771     ; copy bottom pixels
772     test           r5 , r5                   ; if (!block_h)
773     jz .emuedge_v_extend_end_ %+ %%n         ;   goto end
774     sub            r1 , r2                   ; src -= linesize
775     READ_NUM_BYTES  bottom, %%n              ; read bytes
776 .emuedge_extend_bottom_ %+ %%n %+ _loop:     ; do {
777     WRITE_NUM_BYTES bottom, %%n              ;   write bytes
778     add            r0 , r2                   ;   dst += linesize
779     dec            r5d
780     jnz .emuedge_extend_bottom_ %+ %%n %+ _loop ; } while (--block_h)
781
782 .emuedge_v_extend_end_ %+ %%n:
783 %if ARCH_X86_64
784     ret
785 %else ; ARCH_X86_32
786     rep ret
787 %endif ; ARCH_X86_64/32
788 %assign %%n %%n+1
789 %endrep
790 %endmacro VERTICAL_EXTEND
791
792 ; left/right (horizontal) fast extend functions
793 ; these are essentially identical to the vertical extend ones above,
794 ; just left/right separated because number of pixels to extend is
795 ; obviously not the same on both sides.
796 ; for reading, pixels are placed in eax (x86-64) or ebx (x86-64) in the
797 ; lowest two bytes of the register (so val*0x0101), and are splatted
798 ; into each byte of mm0 as well if n_pixels >= 8
799
800 %macro READ_V_PIXEL 2
801     mov        vall, %2
802     mov        valh, vall
803 %if %1 >= 8
804     movd        mm0, vald
805 %if cpuflag(mmx2)
806     pshufw      mm0, mm0, 0
807 %else ; mmx
808     punpcklwd   mm0, mm0
809     punpckldq   mm0, mm0
810 %endif ; sse
811 %endif ; %1 >= 8
812 %endmacro
813
814 %macro WRITE_V_PIXEL 2
815 %assign %%dst_off 0
816 %rep %1/8
817     movq [%2+%%dst_off], mm0
818 %assign %%dst_off %%dst_off+8
819 %endrep
820 %if %1 & 4
821 %if %1 >= 8
822     movd [%2+%%dst_off], mm0
823 %else ; %1 < 8
824     mov  [%2+%%dst_off]  , valw
825     mov  [%2+%%dst_off+2], valw
826 %endif ; %1 >=/< 8
827 %assign %%dst_off %%dst_off+4
828 %endif ; %1 & 4
829 %if %1&2
830     mov  [%2+%%dst_off], valw
831 %endif ; %1 & 2
832 %endmacro
833
834 ; r0=buf+block_h*linesize, r1=start_x, r2=linesize, r5=block_h, r6/r3=val
835 %macro LEFT_EXTEND 0
836 %assign %%n 2
837 %rep 11
838 ALIGN 64
839 .emuedge_extend_left_ %+ %%n:          ; do {
840     sub         r0, r2                 ;   dst -= linesize
841     READ_V_PIXEL  %%n, [r0+r1]         ;   read pixels
842     WRITE_V_PIXEL %%n, r0              ;   write pixels
843     dec         r5
844     jnz .emuedge_extend_left_ %+ %%n   ; } while (--block_h)
845 %if ARCH_X86_64
846     ret
847 %else ; ARCH_X86_32
848     rep ret
849 %endif ; ARCH_X86_64/32
850 %assign %%n %%n+2
851 %endrep
852 %endmacro ; LEFT_EXTEND
853
854 ; r3/r0=buf+block_h*linesize, r2=linesize, r11/r5=block_h, r0/r6=end_x, r6/r3=val
855 %macro RIGHT_EXTEND 0
856 %assign %%n 2
857 %rep 11
858 ALIGN 64
859 .emuedge_extend_right_ %+ %%n:          ; do {
860 %if ARCH_X86_64
861     sub        r3, r2                   ;   dst -= linesize
862     READ_V_PIXEL  %%n, [r3+w_reg-1]     ;   read pixels
863     WRITE_V_PIXEL %%n, r3+r4-%%n        ;   write pixels
864     dec       r11
865 %else ; ARCH_X86_32
866     sub        r0, r2                   ;   dst -= linesize
867     READ_V_PIXEL  %%n, [r0+w_reg-1]     ;   read pixels
868     WRITE_V_PIXEL %%n, r0+r4-%%n        ;   write pixels
869     dec     r5
870 %endif ; ARCH_X86_64/32
871     jnz .emuedge_extend_right_ %+ %%n   ; } while (--block_h)
872 %if ARCH_X86_64
873     ret
874 %else ; ARCH_X86_32
875     rep ret
876 %endif ; ARCH_X86_64/32
877 %assign %%n %%n+2
878 %endrep
879
880 %if ARCH_X86_32
881 %define stack_offset 0x10
882 %endif
883 %endmacro ; RIGHT_EXTEND
884
885 ; below follow the "slow" copy/extend functions, these act on a non-fixed
886 ; width specified in a register, and run a loop to copy the full amount
887 ; of bytes. They are optimized for copying of large amounts of pixels per
888 ; line, so they unconditionally splat data into mm registers to copy 8
889 ; bytes per loop iteration. It could be considered to use xmm for x86-64
890 ; also, but I haven't optimized this as much (i.e. FIXME)
891 %macro V_COPY_NPX 4-5
892 %if %0 == 4
893     test     w_reg, %4
894     jz .%1_skip_%4_px
895 %else ; %0 == 5
896 .%1_%4_px_loop:
897 %endif
898     %3          %2, [r1+cnt_reg]
899     %3 [r0+cnt_reg], %2
900     add    cnt_reg, %4
901 %if %0 == 5
902     sub      w_reg, %4
903     test     w_reg, %5
904     jnz .%1_%4_px_loop
905 %endif
906 .%1_skip_%4_px:
907 %endmacro
908
909 %macro V_COPY_ROW 2
910 %ifidn %1, bottom
911     sub         r1, linesize
912 %endif
913 .%1_copy_loop:
914     xor    cnt_reg, cnt_reg
915 %if notcpuflag(sse)
916 %define linesize r2m
917     V_COPY_NPX %1,  mm0, movq,    8, 0xFFFFFFF8
918 %else ; sse
919     V_COPY_NPX %1, xmm0, movups, 16, 0xFFFFFFF0
920 %if ARCH_X86_64
921 %define linesize r2
922     V_COPY_NPX %1, rax , mov,     8
923 %else ; ARCH_X86_32
924 %define linesize r2m
925     V_COPY_NPX %1,  mm0, movq,    8
926 %endif ; ARCH_X86_64/32
927 %endif ; sse
928     V_COPY_NPX %1, vald, mov,     4
929     V_COPY_NPX %1, valw, mov,     2
930     V_COPY_NPX %1, vall, mov,     1
931     mov      w_reg, cnt_reg
932 %ifidn %1, body
933     add         r1, linesize
934 %endif
935     add         r0, linesize
936     dec         %2
937     jnz .%1_copy_loop
938 %endmacro
939
940 %macro SLOW_V_EXTEND 0
941 .slow_v_extend_loop:
942 ; r0=buf,r1=src,r2(64)/r2m(32)=linesize,r3(64)/r3m(32)=start_x,r4=end_y,r5=block_h
943 ; r11(64)/r3(later-64)/r2(32)=cnt_reg,r6(64)/r3(32)=val_reg,r10(64)/r6(32)=w=end_x-start_x
944 %if ARCH_X86_64
945     push       r11              ; save old value of block_h
946     test        r3, r3
947 %define cnt_reg r11
948     jz .do_body_copy            ; if (!start_y) goto do_body_copy
949     V_COPY_ROW top, r3
950 %else
951     cmp  dword r3m, 0
952 %define cnt_reg r2
953     je .do_body_copy            ; if (!start_y) goto do_body_copy
954     V_COPY_ROW top, dword r3m
955 %endif
956
957 .do_body_copy:
958     V_COPY_ROW body, r4
959
960 %if ARCH_X86_64
961     pop        r11              ; restore old value of block_h
962 %define cnt_reg r3
963 %endif
964     test        r5, r5
965 %if ARCH_X86_64
966     jz .v_extend_end
967 %else
968     jz .skip_bottom_extend
969 %endif
970     V_COPY_ROW bottom, r5
971 %if ARCH_X86_32
972 .skip_bottom_extend:
973     mov         r2, r2m
974 %endif
975     jmp .v_extend_end
976 %endmacro
977
978 %macro SLOW_LEFT_EXTEND 0
979 .slow_left_extend_loop:
980 ; r0=buf+block_h*linesize,r2=linesize,r6(64)/r3(32)=val,r5=block_h,r4=cntr,r10/r6=start_x
981     mov         r4, 8
982     sub         r0, linesize
983     READ_V_PIXEL 8, [r0+w_reg]
984 .left_extend_8px_loop:
985     movq [r0+r4-8], mm0
986     add         r4, 8
987     cmp         r4, w_reg
988     jle .left_extend_8px_loop
989     sub         r4, 8
990     cmp         r4, w_reg
991     jge .left_extend_loop_end
992 .left_extend_2px_loop:
993     mov    [r0+r4], valw
994     add         r4, 2
995     cmp         r4, w_reg
996     jl .left_extend_2px_loop
997 .left_extend_loop_end:
998     dec         r5
999     jnz .slow_left_extend_loop
1000 %if ARCH_X86_32
1001     mov         r2, r2m
1002 %endif
1003     jmp .right_extend
1004 %endmacro
1005
1006 %macro SLOW_RIGHT_EXTEND 0
1007 .slow_right_extend_loop:
1008 ; r3(64)/r0(32)=buf+block_h*linesize,r2=linesize,r4=block_w,r11(64)/r5(32)=block_h,
1009 ; r10(64)/r6(32)=end_x,r6/r3=val,r1=cntr
1010 %if ARCH_X86_64
1011 %define buf_reg r3
1012 %define bh_reg r11
1013 %else
1014 %define buf_reg r0
1015 %define bh_reg r5
1016 %endif
1017     lea         r1, [r4-8]
1018     sub    buf_reg, linesize
1019     READ_V_PIXEL 8, [buf_reg+w_reg-1]
1020 .right_extend_8px_loop:
1021     movq [buf_reg+r1], mm0
1022     sub         r1, 8
1023     cmp         r1, w_reg
1024     jge .right_extend_8px_loop
1025     add         r1, 8
1026     cmp         r1, w_reg
1027     je .right_extend_loop_end
1028 .right_extend_2px_loop:
1029     sub         r1, 2
1030     mov [buf_reg+r1], valw
1031     cmp         r1, w_reg
1032     jg .right_extend_2px_loop
1033 .right_extend_loop_end:
1034     dec         bh_reg
1035     jnz .slow_right_extend_loop
1036     jmp .h_extend_end
1037 %endmacro
1038
1039 %macro emu_edge 1
1040 INIT_XMM %1
1041 EMU_EDGE_FUNC
1042 VERTICAL_EXTEND
1043 LEFT_EXTEND
1044 RIGHT_EXTEND
1045 SLOW_V_EXTEND
1046 SLOW_LEFT_EXTEND
1047 SLOW_RIGHT_EXTEND
1048 %endmacro
1049
1050 emu_edge sse
1051 %if ARCH_X86_32
1052 emu_edge mmx
1053 %endif
1054
1055 ;-----------------------------------------------------------------------------
1056 ; void ff_vector_clip_int32(int32_t *dst, const int32_t *src, int32_t min,
1057 ;                           int32_t max, unsigned int len)
1058 ;-----------------------------------------------------------------------------
1059
1060 ; %1 = number of xmm registers used
1061 ; %2 = number of inline load/process/store loops per asm loop
1062 ; %3 = process 4*mmsize (%3=0) or 8*mmsize (%3=1) bytes per loop
1063 ; %4 = CLIPD function takes min/max as float instead of int (CLIPD_SSE2)
1064 ; %5 = suffix
1065 %macro VECTOR_CLIP_INT32 4-5
1066 cglobal vector_clip_int32%5, 5,5,%2, dst, src, min, max, len
1067 %if %4
1068     cvtsi2ss  m4, minm
1069     cvtsi2ss  m5, maxm
1070 %else
1071     movd      m4, minm
1072     movd      m5, maxm
1073 %endif
1074     SPLATD    m4
1075     SPLATD    m5
1076 .loop:
1077 %assign %%i 1
1078 %rep %2
1079     mova      m0,  [srcq+mmsize*0*%%i]
1080     mova      m1,  [srcq+mmsize*1*%%i]
1081     mova      m2,  [srcq+mmsize*2*%%i]
1082     mova      m3,  [srcq+mmsize*3*%%i]
1083 %if %3
1084     mova      m7,  [srcq+mmsize*4*%%i]
1085     mova      m8,  [srcq+mmsize*5*%%i]
1086     mova      m9,  [srcq+mmsize*6*%%i]
1087     mova      m10, [srcq+mmsize*7*%%i]
1088 %endif
1089     CLIPD  m0,  m4, m5, m6
1090     CLIPD  m1,  m4, m5, m6
1091     CLIPD  m2,  m4, m5, m6
1092     CLIPD  m3,  m4, m5, m6
1093 %if %3
1094     CLIPD  m7,  m4, m5, m6
1095     CLIPD  m8,  m4, m5, m6
1096     CLIPD  m9,  m4, m5, m6
1097     CLIPD  m10, m4, m5, m6
1098 %endif
1099     mova  [dstq+mmsize*0*%%i], m0
1100     mova  [dstq+mmsize*1*%%i], m1
1101     mova  [dstq+mmsize*2*%%i], m2
1102     mova  [dstq+mmsize*3*%%i], m3
1103 %if %3
1104     mova  [dstq+mmsize*4*%%i], m7
1105     mova  [dstq+mmsize*5*%%i], m8
1106     mova  [dstq+mmsize*6*%%i], m9
1107     mova  [dstq+mmsize*7*%%i], m10
1108 %endif
1109 %assign %%i %%i+1
1110 %endrep
1111     add     srcq, mmsize*4*(%2+%3)
1112     add     dstq, mmsize*4*(%2+%3)
1113     sub     lend, mmsize*(%2+%3)
1114     jg .loop
1115     REP_RET
1116 %endmacro
1117
1118 INIT_MMX mmx
1119 %define SPLATD SPLATD_MMX
1120 %define CLIPD CLIPD_MMX
1121 VECTOR_CLIP_INT32 0, 1, 0, 0
1122 INIT_XMM sse2
1123 %define SPLATD SPLATD_SSE2
1124 VECTOR_CLIP_INT32 6, 1, 0, 0, _int
1125 %define CLIPD CLIPD_SSE2
1126 VECTOR_CLIP_INT32 6, 2, 0, 1
1127 INIT_XMM sse4
1128 %define CLIPD CLIPD_SSE41
1129 %ifdef m8
1130 VECTOR_CLIP_INT32 11, 1, 1, 0
1131 %else
1132 VECTOR_CLIP_INT32 6, 1, 0, 0
1133 %endif
1134
1135 ;-----------------------------------------------------------------------------
1136 ; void ff_butterflies_float_interleave(float *dst, const float *src0,
1137 ;                                      const float *src1, int len);
1138 ;-----------------------------------------------------------------------------
1139
1140 %macro BUTTERFLIES_FLOAT_INTERLEAVE 0
1141 cglobal butterflies_float_interleave, 4,4,3, dst, src0, src1, len
1142 %if ARCH_X86_64
1143     movsxd    lenq, lend
1144 %endif
1145     test      lenq, lenq
1146     jz .end
1147     shl       lenq, 2
1148     lea      src0q, [src0q +   lenq]
1149     lea      src1q, [src1q +   lenq]
1150     lea       dstq, [ dstq + 2*lenq]
1151     neg       lenq
1152 .loop:
1153     mova        m0, [src0q + lenq]
1154     mova        m1, [src1q + lenq]
1155     subps       m2, m0, m1
1156     addps       m0, m0, m1
1157     unpcklps    m1, m0, m2
1158     unpckhps    m0, m0, m2
1159 %if cpuflag(avx)
1160     vextractf128 [dstq + 2*lenq     ], m1, 0
1161     vextractf128 [dstq + 2*lenq + 16], m0, 0
1162     vextractf128 [dstq + 2*lenq + 32], m1, 1
1163     vextractf128 [dstq + 2*lenq + 48], m0, 1
1164 %else
1165     mova [dstq + 2*lenq         ], m1
1166     mova [dstq + 2*lenq + mmsize], m0
1167 %endif
1168     add       lenq, mmsize
1169     jl .loop
1170 %if mmsize == 32
1171     vzeroupper
1172     RET
1173 %endif
1174 .end:
1175     REP_RET
1176 %endmacro
1177
1178 INIT_XMM sse
1179 BUTTERFLIES_FLOAT_INTERLEAVE
1180 INIT_YMM avx
1181 BUTTERFLIES_FLOAT_INTERLEAVE
1182
1183 INIT_XMM sse2
1184 ; %1 = aligned/unaligned
1185 %macro BSWAP_LOOPS_SSE2  1
1186     mov      r3, r2
1187     sar      r2, 3
1188     jz       .left4_%1
1189 .loop8_%1:
1190     mov%1    m0, [r1 +  0]
1191     mov%1    m1, [r1 + 16]
1192     pshuflw  m0, m0, 10110001b
1193     pshuflw  m1, m1, 10110001b
1194     pshufhw  m0, m0, 10110001b
1195     pshufhw  m1, m1, 10110001b
1196     mova     m2, m0
1197     mova     m3, m1
1198     psllw    m0, 8
1199     psllw    m1, 8
1200     psrlw    m2, 8
1201     psrlw    m3, 8
1202     por      m2, m0
1203     por      m3, m1
1204     mova     [r0 +  0], m2
1205     mova     [r0 + 16], m3
1206     add      r1, 32
1207     add      r0, 32
1208     dec      r2
1209     jnz      .loop8_%1
1210 .left4_%1:
1211     mov      r2, r3
1212     and      r3, 4
1213     jz       .left
1214     mov%1    m0, [r1]
1215     pshuflw  m0, m0, 10110001b
1216     pshufhw  m0, m0, 10110001b
1217     mova     m2, m0
1218     psllw    m0, 8
1219     psrlw    m2, 8
1220     por      m2, m0
1221     mova     [r0], m2
1222     add      r1, 16
1223     add      r0, 16
1224 %endmacro
1225
1226 ; void bswap_buf(uint32_t *dst, const uint32_t *src, int w);
1227 cglobal bswap32_buf, 3,4,5
1228     mov      r3, r1
1229     and      r3, 15
1230     jz       .start_align
1231     BSWAP_LOOPS_SSE2  u
1232     jmp      .left
1233 .start_align:
1234     BSWAP_LOOPS_SSE2  a
1235 .left:
1236     and      r2, 3
1237     jz       .end
1238 .loop2:
1239     mov      r3d, [r1]
1240     bswap    r3d
1241     mov      [r0], r3d
1242     add      r1, 4
1243     add      r0, 4
1244     dec      r2
1245     jnz      .loop2
1246 .end
1247     RET
1248
1249 ; %1 = aligned/unaligned
1250 %macro BSWAP_LOOPS_SSSE3  1
1251     mov      r3, r2
1252     sar      r2, 3
1253     jz       .left4_%1
1254 .loop8_%1:
1255     mov%1    m0, [r1 +  0]
1256     mov%1    m1, [r1 + 16]
1257     pshufb   m0, m2
1258     pshufb   m1, m2
1259     mova     [r0 +  0], m0
1260     mova     [r0 + 16], m1
1261     add      r0, 32
1262     add      r1, 32
1263     dec      r2
1264     jnz      .loop8_%1
1265 .left4_%1:
1266     mov      r2, r3
1267     and      r3, 4
1268     jz       .left2
1269     mov%1    m0, [r1]
1270     pshufb   m0, m2
1271     mova     [r0], m0
1272     add      r1, 16
1273     add      r0, 16
1274 %endmacro
1275
1276 INIT_XMM ssse3
1277 ; void bswap_buf(uint32_t *dst, const uint32_t *src, int w);
1278 cglobal bswap32_buf, 3,4,3
1279     mov      r3, r1
1280     mova     m2, [pb_bswap32]
1281     and      r3, 15
1282     jz       .start_align
1283     BSWAP_LOOPS_SSSE3  u
1284     jmp      .left2
1285 .start_align:
1286     BSWAP_LOOPS_SSSE3  a
1287 .left2:
1288     mov      r3, r2
1289     and      r2, 2
1290     jz       .left1
1291     movq     m0, [r1]
1292     pshufb   m0, m2
1293     movq     [r0], m0
1294     add      r1, 8
1295     add      r0, 8
1296 .left1:
1297     and      r3, 1
1298     jz       .end
1299     mov      r2d, [r1]
1300     bswap    r2d
1301     mov      [r0], r2d
1302 .end:
1303     RET