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