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