]> git.sesse.net Git - ffmpeg/blob - libavcodec/x86/dsputil.asm
Merge commit 'f1d8763a02b5fce9a7d9789e049d74a45b15e1e8'
[ffmpeg] / 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 0
37 ; int scalarproduct_int16(int16_t *v1, int16_t *v2, int order)
38 cglobal scalarproduct_int16, 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, 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 mmxext
111 SCALARPRODUCT
112 INIT_XMM sse2
113 SCALARPRODUCT
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 INIT_XMM ssse3
162 cglobal scalarproduct_and_madd_int16, 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 1-2
212 %if cpuflag(ssse3) && notcpuflag(atom)
213     pshufb  %1, %2
214 %elif cpuflag(sse2)
215     pshuflw  %1, %1, 0x1B
216     pshufhw  %1, %1, 0x1B
217     pshufd   %1, %1, 0x4E
218 %elif cpuflag(mmxext)
219     pshufw   %1, %1, 0x1B
220 %endif
221 %endmacro
222
223 %macro MUL16FIXED 3
224 %if cpuflag(ssse3) ; dst, src, unused
225 ; dst = ((dst * src) + (1<<14)) >> 15
226     pmulhrsw   %1, %2
227 %elif cpuflag(mmxext) ; dst, src, temp
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     mova    %3, %1
232     pmulhw  %1, %2
233     pmullw  %3, %2
234     psrlw   %3, 15
235     psllw   %1, 1
236     por     %1, %3
237 %endif
238 %endmacro
239
240 %macro APPLY_WINDOW_INT16 1 ; %1 bitexact version
241 %if %1
242 cglobal apply_window_int16, 4,5,6, output, input, window, offset, offset2
243 %else
244 cglobal apply_window_int16_round, 4,5,6, output, input, window, offset, offset2
245 %endif
246     lea     offset2q, [offsetq-mmsize]
247 %if cpuflag(ssse3) && notcpuflag(atom)
248     mova          m5, [pb_revwords]
249     ALIGN 16
250 %elif %1
251     mova          m5, [pd_16384]
252 %endif
253 .loop:
254 %if cpuflag(ssse3)
255     ; This version does the 16x16->16 multiplication in-place without expanding
256     ; to 32-bit. The ssse3 version is bit-identical.
257     mova          m0, [windowq+offset2q]
258     mova          m1, [ inputq+offset2q]
259     pmulhrsw      m1, m0
260     REVERSE_WORDS m0, m5
261     pmulhrsw      m0, [ inputq+offsetq ]
262     mova  [outputq+offset2q], m1
263     mova  [outputq+offsetq ], m0
264 %elif %1
265     ; This version expands 16-bit to 32-bit, multiplies by the window,
266     ; adds 16384 for rounding, right shifts 15, then repacks back to words to
267     ; save to the output. The window is reversed for the second half.
268     mova          m3, [windowq+offset2q]
269     mova          m4, [ inputq+offset2q]
270     pxor          m0, m0
271     punpcklwd     m0, m3
272     punpcklwd     m1, m4
273     pmaddwd       m0, m1
274     paddd         m0, m5
275     psrad         m0, 15
276     pxor          m2, m2
277     punpckhwd     m2, m3
278     punpckhwd     m1, m4
279     pmaddwd       m2, m1
280     paddd         m2, m5
281     psrad         m2, 15
282     packssdw      m0, m2
283     mova  [outputq+offset2q], m0
284     REVERSE_WORDS m3
285     mova          m4, [ inputq+offsetq]
286     pxor          m0, m0
287     punpcklwd     m0, m3
288     punpcklwd     m1, m4
289     pmaddwd       m0, m1
290     paddd         m0, m5
291     psrad         m0, 15
292     pxor          m2, m2
293     punpckhwd     m2, m3
294     punpckhwd     m1, m4
295     pmaddwd       m2, m1
296     paddd         m2, m5
297     psrad         m2, 15
298     packssdw      m0, m2
299     mova  [outputq+offsetq], m0
300 %else
301     ; This version does the 16x16->16 multiplication in-place without expanding
302     ; to 32-bit. The mmxext and sse2 versions do not use rounding, and
303     ; therefore are not bit-identical to the C version.
304     mova          m0, [windowq+offset2q]
305     mova          m1, [ inputq+offset2q]
306     mova          m2, [ inputq+offsetq ]
307     MUL16FIXED    m1, m0, m3
308     REVERSE_WORDS m0
309     MUL16FIXED    m2, m0, m3
310     mova  [outputq+offset2q], m1
311     mova  [outputq+offsetq ], m2
312 %endif
313     add      offsetd, mmsize
314     sub     offset2d, mmsize
315     jae .loop
316     REP_RET
317 %endmacro
318
319 INIT_MMX mmxext
320 APPLY_WINDOW_INT16 0
321 INIT_XMM sse2
322 APPLY_WINDOW_INT16 0
323
324 INIT_MMX mmxext
325 APPLY_WINDOW_INT16 1
326 INIT_XMM sse2
327 APPLY_WINDOW_INT16 1
328 INIT_XMM ssse3
329 APPLY_WINDOW_INT16 1
330 INIT_XMM ssse3, atom
331 APPLY_WINDOW_INT16 1
332
333
334 ; void add_hfyu_median_prediction_mmxext(uint8_t *dst, const uint8_t *top, const uint8_t *diff, int w, int *left, int *left_top)
335 INIT_MMX mmxext
336 cglobal add_hfyu_median_prediction, 6,6,0, dst, top, diff, w, left, left_top
337     movq    mm0, [topq]
338     movq    mm2, mm0
339     movd    mm4, [left_topq]
340     psllq   mm2, 8
341     movq    mm1, mm0
342     por     mm4, mm2
343     movd    mm3, [leftq]
344     psubb   mm0, mm4 ; t-tl
345     add    dstq, wq
346     add    topq, wq
347     add   diffq, wq
348     neg      wq
349     jmp .skip
350 .loop:
351     movq    mm4, [topq+wq]
352     movq    mm0, mm4
353     psllq   mm4, 8
354     por     mm4, mm1
355     movq    mm1, mm0 ; t
356     psubb   mm0, mm4 ; t-tl
357 .skip:
358     movq    mm2, [diffq+wq]
359 %assign i 0
360 %rep 8
361     movq    mm4, mm0
362     paddb   mm4, mm3 ; t-tl+l
363     movq    mm5, mm3
364     pmaxub  mm3, mm1
365     pminub  mm5, mm1
366     pminub  mm3, mm4
367     pmaxub  mm3, mm5 ; median
368     paddb   mm3, mm2 ; +residual
369 %if i==0
370     movq    mm7, mm3
371     psllq   mm7, 56
372 %else
373     movq    mm6, mm3
374     psrlq   mm7, 8
375     psllq   mm6, 56
376     por     mm7, mm6
377 %endif
378 %if i<7
379     psrlq   mm0, 8
380     psrlq   mm1, 8
381     psrlq   mm2, 8
382 %endif
383 %assign i i+1
384 %endrep
385     movq [dstq+wq], mm7
386     add      wq, 8
387     jl .loop
388     movzx   r2d, byte [dstq-1]
389     mov [leftq], r2d
390     movzx   r2d, byte [topq-1]
391     mov [left_topq], r2d
392     RET
393
394
395 %macro ADD_HFYU_LEFT_LOOP 2 ; %1 = dst_is_aligned, %2 = src_is_aligned
396     add     srcq, wq
397     add     dstq, wq
398     neg     wq
399 %%.loop:
400 %if %2
401     mova    m1, [srcq+wq]
402 %else
403     movu    m1, [srcq+wq]
404 %endif
405     mova    m2, m1
406     psllw   m1, 8
407     paddb   m1, m2
408     mova    m2, m1
409     pshufb  m1, m3
410     paddb   m1, m2
411     pshufb  m0, m5
412     mova    m2, m1
413     pshufb  m1, m4
414     paddb   m1, m2
415 %if mmsize == 16
416     mova    m2, m1
417     pshufb  m1, m6
418     paddb   m1, m2
419 %endif
420     paddb   m0, m1
421 %if %1
422     mova    [dstq+wq], m0
423 %else
424     movq    [dstq+wq], m0
425     movhps  [dstq+wq+8], m0
426 %endif
427     add     wq, mmsize
428     jl %%.loop
429     mov     eax, mmsize-1
430     sub     eax, wd
431     movd    m1, eax
432     pshufb  m0, m1
433     movd    eax, m0
434     RET
435 %endmacro
436
437 ; int add_hfyu_left_prediction(uint8_t *dst, const uint8_t *src, int w, int left)
438 INIT_MMX ssse3
439 cglobal add_hfyu_left_prediction, 3,3,7, dst, src, w, left
440 .skip_prologue:
441     mova    m5, [pb_7]
442     mova    m4, [pb_zzzz3333zzzzbbbb]
443     mova    m3, [pb_zz11zz55zz99zzdd]
444     movd    m0, leftm
445     psllq   m0, 56
446     ADD_HFYU_LEFT_LOOP 1, 1
447
448 INIT_XMM sse4
449 cglobal add_hfyu_left_prediction, 3,3,7, dst, src, w, left
450     mova    m5, [pb_f]
451     mova    m6, [pb_zzzzzzzz77777777]
452     mova    m4, [pb_zzzz3333zzzzbbbb]
453     mova    m3, [pb_zz11zz55zz99zzdd]
454     movd    m0, leftm
455     pslldq  m0, 15
456     test    srcq, 15
457     jnz .src_unaligned
458     test    dstq, 15
459     jnz .dst_unaligned
460     ADD_HFYU_LEFT_LOOP 1, 1
461 .dst_unaligned:
462     ADD_HFYU_LEFT_LOOP 0, 1
463 .src_unaligned:
464     ADD_HFYU_LEFT_LOOP 0, 0
465
466
467 ; float scalarproduct_float_sse(const float *v1, const float *v2, int len)
468 INIT_XMM sse
469 cglobal scalarproduct_float, 3,3,2, v1, v2, offset
470     neg offsetq
471     shl offsetq, 2
472     sub v1q, offsetq
473     sub v2q, offsetq
474     xorps xmm0, xmm0
475     .loop:
476         movaps   xmm1, [v1q+offsetq]
477         mulps    xmm1, [v2q+offsetq]
478         addps    xmm0, xmm1
479         add      offsetq, 16
480         js       .loop
481     movhlps xmm1, xmm0
482     addps   xmm0, xmm1
483     movss   xmm1, xmm0
484     shufps  xmm0, xmm0, 1
485     addss   xmm0, xmm1
486 %if ARCH_X86_64 == 0
487     movss   r0m,  xmm0
488     fld     dword r0m
489 %endif
490     RET
491
492 ; extern void ff_emu_edge_core(uint8_t *buf, const uint8_t *src, x86_reg linesize,
493 ;                              x86_reg start_y, x86_reg end_y, x86_reg block_h,
494 ;                              x86_reg start_x, x86_reg end_x, x86_reg block_w);
495 ;
496 ; The actual function itself is below. It basically wraps a very simple
497 ; w = end_x - start_x
498 ; if (w) {
499 ;   if (w > 22) {
500 ;     jump to the slow loop functions
501 ;   } else {
502 ;     jump to the fast loop functions
503 ;   }
504 ; }
505 ;
506 ; ... and then the same for left/right extend also. See below for loop
507 ; function implementations. Fast are fixed-width, slow is variable-width
508
509 %macro EMU_EDGE_FUNC 0
510 %if ARCH_X86_64
511 %define w_reg r7
512 cglobal emu_edge_core, 6, 9, 1
513     mov         r8, r5          ; save block_h
514 %else
515 %define w_reg r6
516 cglobal emu_edge_core, 2, 7, 0
517     mov         r4, r4m         ; end_y
518     mov         r5, r5m         ; block_h
519 %endif
520
521     ; start with vertical extend (top/bottom) and body pixel copy
522     mov      w_reg, r7m
523     sub      w_reg, r6m         ; w = start_x - end_x
524     sub         r5, r4
525 %if ARCH_X86_64
526     sub         r4, r3
527 %else
528     sub         r4, dword r3m
529 %endif
530     cmp      w_reg, 22
531     jg .slow_v_extend_loop
532 %if ARCH_X86_32
533     mov         r2, r2m         ; linesize
534 %endif
535     sal      w_reg, 7           ; w * 128
536 %ifdef PIC
537     lea        rax, [.emuedge_v_extend_1 - (.emuedge_v_extend_2 - .emuedge_v_extend_1)]
538     add      w_reg, rax
539 %else
540     lea      w_reg, [.emuedge_v_extend_1 - (.emuedge_v_extend_2 - .emuedge_v_extend_1)+w_reg]
541 %endif
542     call     w_reg              ; fast top extend, body copy and bottom extend
543 .v_extend_end:
544
545     ; horizontal extend (left/right)
546     mov      w_reg, r6m         ; start_x
547     sub         r0, w_reg
548 %if ARCH_X86_64
549     mov         r3, r0          ; backup of buf+block_h*linesize
550     mov         r5, r8
551 %else
552     mov        r0m, r0          ; backup of buf+block_h*linesize
553     mov         r5, r5m
554 %endif
555     test     w_reg, w_reg
556     jz .right_extend
557     cmp      w_reg, 22
558     jg .slow_left_extend_loop
559     mov         r1, w_reg
560     dec      w_reg
561     ; FIXME we can do a if size == 1 here if that makes any speed difference, test me
562     sar      w_reg, 1
563     sal      w_reg, 6
564     ; r0=buf+block_h*linesize,r7(64)/r6(32)=start_x offset for funcs
565     ; r6(rax)/r3(ebx)=val,r2=linesize,r1=start_x,r5=block_h
566 %ifdef PIC
567     lea        rax, [.emuedge_extend_left_2]
568     add      w_reg, rax
569 %else
570     lea      w_reg, [.emuedge_extend_left_2+w_reg]
571 %endif
572     call     w_reg
573
574     ; now r3(64)/r0(32)=buf,r2=linesize,r8/r5=block_h,r6/r3=val, r7/r6=end_x, r1=block_w
575 .right_extend:
576 %if ARCH_X86_32
577     mov         r0, r0m
578     mov         r5, r5m
579 %endif
580     mov      w_reg, r7m         ; end_x
581     mov         r1, r8m         ; block_w
582     mov         r4, r1
583     sub         r1, w_reg
584     jz .h_extend_end            ; if (end_x == block_w) goto h_extend_end
585     cmp         r1, 22
586     jg .slow_right_extend_loop
587     dec         r1
588     ; FIXME we can do a if size == 1 here if that makes any speed difference, test me
589     sar         r1, 1
590     sal         r1, 6
591 %ifdef PIC
592     lea        rax, [.emuedge_extend_right_2]
593     add         r1, rax
594 %else
595     lea         r1, [.emuedge_extend_right_2+r1]
596 %endif
597     call        r1
598 .h_extend_end:
599     RET
600
601 %if ARCH_X86_64
602 %define vall  al
603 %define valh  ah
604 %define valw  ax
605 %define valw2 r7w
606 %define valw3 r3w
607 %if WIN64
608 %define valw4 r7w
609 %else ; unix64
610 %define valw4 r3w
611 %endif
612 %define vald eax
613 %else
614 %define vall  bl
615 %define valh  bh
616 %define valw  bx
617 %define valw2 r6w
618 %define valw3 valw2
619 %define valw4 valw3
620 %define vald ebx
621 %define stack_offset 0x14
622 %endif
623
624 %endmacro
625
626 ; macro to read/write a horizontal number of pixels (%2) to/from registers
627 ; on x86-64, - fills xmm0-15 for consecutive sets of 16 pixels
628 ;            - if (%2 & 15 == 8) fills the last 8 bytes into rax
629 ;            - else if (%2 & 8)  fills 8 bytes into mm0
630 ;            - if (%2 & 7 == 4)  fills the last 4 bytes into rax
631 ;            - else if (%2 & 4)  fills 4 bytes into mm0-1
632 ;            - if (%2 & 3 == 3)  fills 2 bytes into r7/r3, and 1 into eax
633 ;              (note that we're using r3 for body/bottom because it's a shorter
634 ;               opcode, and then the loop fits in 128 bytes)
635 ;            - else              fills remaining bytes into rax
636 ; on x86-32, - fills mm0-7 for consecutive sets of 8 pixels
637 ;            - if (%2 & 7 == 4)  fills 4 bytes into ebx
638 ;            - else if (%2 & 4)  fills 4 bytes into mm0-7
639 ;            - if (%2 & 3 == 3)  fills 2 bytes into r6, and 1 into ebx
640 ;            - else              fills remaining bytes into ebx
641 ; writing data out is in the same way
642 %macro READ_NUM_BYTES 2
643 %assign %%src_off 0 ; offset in source buffer
644 %assign %%smidx   0 ; mmx register idx
645 %assign %%sxidx   0 ; xmm register idx
646
647 %if cpuflag(sse)
648 %rep %2/16
649     movups xmm %+ %%sxidx, [r1+%%src_off]
650 %assign %%src_off %%src_off+16
651 %assign %%sxidx   %%sxidx+1
652 %endrep ; %2/16
653 %endif
654
655 %if ARCH_X86_64
656 %if (%2-%%src_off) == 8
657     mov           rax, [r1+%%src_off]
658 %assign %%src_off %%src_off+8
659 %endif ; (%2-%%src_off) == 8
660 %endif ; x86-64
661
662 %rep (%2-%%src_off)/8
663     movq    mm %+ %%smidx, [r1+%%src_off]
664 %assign %%src_off %%src_off+8
665 %assign %%smidx   %%smidx+1
666 %endrep ; (%2-%%dst_off)/8
667
668 %if (%2-%%src_off) == 4
669     mov          vald, [r1+%%src_off]
670 %elif (%2-%%src_off) & 4
671     movd    mm %+ %%smidx, [r1+%%src_off]
672 %assign %%src_off %%src_off+4
673 %endif ; (%2-%%src_off) ==/& 4
674
675 %if (%2-%%src_off) == 1
676     mov          vall, [r1+%%src_off]
677 %elif (%2-%%src_off) == 2
678     mov          valw, [r1+%%src_off]
679 %elif (%2-%%src_off) == 3
680 %ifidn %1, top
681     mov         valw2, [r1+%%src_off]
682 %elifidn %1, body
683     mov         valw3, [r1+%%src_off]
684 %elifidn %1, bottom
685     mov         valw4, [r1+%%src_off]
686 %endif ; %1 ==/!= top
687     mov          vall, [r1+%%src_off+2]
688 %endif ; (%2-%%src_off) == 1/2/3
689 %endmacro ; READ_NUM_BYTES
690
691 %macro WRITE_NUM_BYTES 2
692 %assign %%dst_off 0 ; offset in destination buffer
693 %assign %%dmidx   0 ; mmx register idx
694 %assign %%dxidx   0 ; xmm register idx
695
696 %if cpuflag(sse)
697 %rep %2/16
698     movups [r0+%%dst_off], xmm %+ %%dxidx
699 %assign %%dst_off %%dst_off+16
700 %assign %%dxidx   %%dxidx+1
701 %endrep ; %2/16
702 %endif
703
704 %if ARCH_X86_64
705 %if (%2-%%dst_off) == 8
706     mov    [r0+%%dst_off], rax
707 %assign %%dst_off %%dst_off+8
708 %endif ; (%2-%%dst_off) == 8
709 %endif ; x86-64
710
711 %rep (%2-%%dst_off)/8
712     movq   [r0+%%dst_off], mm %+ %%dmidx
713 %assign %%dst_off %%dst_off+8
714 %assign %%dmidx   %%dmidx+1
715 %endrep ; (%2-%%dst_off)/8
716
717 %if (%2-%%dst_off) == 4
718     mov    [r0+%%dst_off], vald
719 %elif (%2-%%dst_off) & 4
720     movd   [r0+%%dst_off], mm %+ %%dmidx
721 %assign %%dst_off %%dst_off+4
722 %endif ; (%2-%%dst_off) ==/& 4
723
724 %if (%2-%%dst_off) == 1
725     mov    [r0+%%dst_off], vall
726 %elif (%2-%%dst_off) == 2
727     mov    [r0+%%dst_off], valw
728 %elif (%2-%%dst_off) == 3
729 %ifidn %1, top
730     mov    [r0+%%dst_off], valw2
731 %elifidn %1, body
732     mov    [r0+%%dst_off], valw3
733 %elifidn %1, bottom
734     mov    [r0+%%dst_off], valw4
735 %endif ; %1 ==/!= top
736     mov  [r0+%%dst_off+2], vall
737 %endif ; (%2-%%dst_off) == 1/2/3
738 %endmacro ; WRITE_NUM_BYTES
739
740 ; vertical top/bottom extend and body copy fast loops
741 ; these are function pointers to set-width line copy functions, i.e.
742 ; they read a fixed number of pixels into set registers, and write
743 ; those out into the destination buffer
744 ; r0=buf,r1=src,r2=linesize,r3(64)/r3m(32)=start_x,r4=end_y,r5=block_h
745 ; r6(eax/64)/r3(ebx/32)=val_reg
746 %macro VERTICAL_EXTEND 0
747 %assign %%n 1
748 %rep 22
749 ALIGN 128
750 .emuedge_v_extend_ %+ %%n:
751     ; extend pixels above body
752 %if ARCH_X86_64
753     test           r3 , r3                   ; if (!start_y)
754     jz .emuedge_copy_body_ %+ %%n %+ _loop   ;   goto body
755 %else ; ARCH_X86_32
756     cmp      dword r3m, 0
757     je .emuedge_copy_body_ %+ %%n %+ _loop
758 %endif ; ARCH_X86_64/32
759     READ_NUM_BYTES  top,    %%n              ; read bytes
760 .emuedge_extend_top_ %+ %%n %+ _loop:        ; do {
761     WRITE_NUM_BYTES top,    %%n              ;   write bytes
762     add            r0 , r2                   ;   dst += linesize
763 %if ARCH_X86_64
764     dec            r3d
765 %else ; ARCH_X86_32
766     dec      dword r3m
767 %endif ; ARCH_X86_64/32
768     jnz .emuedge_extend_top_ %+ %%n %+ _loop ; } while (--start_y)
769
770     ; copy body pixels
771 .emuedge_copy_body_ %+ %%n %+ _loop:         ; do {
772     READ_NUM_BYTES  body,   %%n              ;   read bytes
773     WRITE_NUM_BYTES body,   %%n              ;   write bytes
774     add            r0 , r2                   ;   dst += linesize
775     add            r1 , r2                   ;   src += linesize
776     dec            r4d
777     jnz .emuedge_copy_body_ %+ %%n %+ _loop  ; } while (--end_y)
778
779     ; copy bottom pixels
780     test           r5 , r5                   ; if (!block_h)
781     jz .emuedge_v_extend_end_ %+ %%n         ;   goto end
782     sub            r1 , r2                   ; src -= linesize
783     READ_NUM_BYTES  bottom, %%n              ; read bytes
784 .emuedge_extend_bottom_ %+ %%n %+ _loop:     ; do {
785     WRITE_NUM_BYTES bottom, %%n              ;   write bytes
786     add            r0 , r2                   ;   dst += linesize
787     dec            r5d
788     jnz .emuedge_extend_bottom_ %+ %%n %+ _loop ; } while (--block_h)
789
790 .emuedge_v_extend_end_ %+ %%n:
791 %if ARCH_X86_64
792     ret
793 %else ; ARCH_X86_32
794     rep ret
795 %endif ; ARCH_X86_64/32
796 %assign %%n %%n+1
797 %endrep
798 %endmacro VERTICAL_EXTEND
799
800 ; left/right (horizontal) fast extend functions
801 ; these are essentially identical to the vertical extend ones above,
802 ; just left/right separated because number of pixels to extend is
803 ; obviously not the same on both sides.
804 ; for reading, pixels are placed in eax (x86-64) or ebx (x86-64) in the
805 ; lowest two bytes of the register (so val*0x0101), and are splatted
806 ; into each byte of mm0 as well if n_pixels >= 8
807
808 %macro READ_V_PIXEL 2
809     mov        vall, %2
810     mov        valh, vall
811 %if %1 >= 8
812     movd        mm0, vald
813 %if cpuflag(mmxext)
814     pshufw      mm0, mm0, 0
815 %else ; mmx
816     punpcklwd   mm0, mm0
817     punpckldq   mm0, mm0
818 %endif ; sse
819 %endif ; %1 >= 8
820 %endmacro
821
822 %macro WRITE_V_PIXEL 2
823 %assign %%dst_off 0
824 %rep %1/8
825     movq [%2+%%dst_off], mm0
826 %assign %%dst_off %%dst_off+8
827 %endrep
828 %if %1 & 4
829 %if %1 >= 8
830     movd [%2+%%dst_off], mm0
831 %else ; %1 < 8
832     mov  [%2+%%dst_off]  , valw
833     mov  [%2+%%dst_off+2], valw
834 %endif ; %1 >=/< 8
835 %assign %%dst_off %%dst_off+4
836 %endif ; %1 & 4
837 %if %1&2
838     mov  [%2+%%dst_off], valw
839 %endif ; %1 & 2
840 %endmacro
841
842 ; r0=buf+block_h*linesize, r1=start_x, r2=linesize, r5=block_h, r6/r3=val
843 %macro LEFT_EXTEND 0
844 %assign %%n 2
845 %rep 11
846 ALIGN 64
847 .emuedge_extend_left_ %+ %%n:          ; do {
848     sub         r0, r2                 ;   dst -= linesize
849     READ_V_PIXEL  %%n, [r0+r1]         ;   read pixels
850     WRITE_V_PIXEL %%n, r0              ;   write pixels
851     dec         r5
852     jnz .emuedge_extend_left_ %+ %%n   ; } while (--block_h)
853 %if ARCH_X86_64
854     ret
855 %else ; ARCH_X86_32
856     rep ret
857 %endif ; ARCH_X86_64/32
858 %assign %%n %%n+2
859 %endrep
860 %endmacro ; LEFT_EXTEND
861
862 ; r3/r0=buf+block_h*linesize, r2=linesize, r8/r5=block_h, r0/r6=end_x, r6/r3=val
863 %macro RIGHT_EXTEND 0
864 %assign %%n 2
865 %rep 11
866 ALIGN 64
867 .emuedge_extend_right_ %+ %%n:          ; do {
868 %if ARCH_X86_64
869     sub        r3, r2                   ;   dst -= linesize
870     READ_V_PIXEL  %%n, [r3+w_reg-1]     ;   read pixels
871     WRITE_V_PIXEL %%n, r3+r4-%%n        ;   write pixels
872     dec       r8
873 %else ; ARCH_X86_32
874     sub        r0, r2                   ;   dst -= linesize
875     READ_V_PIXEL  %%n, [r0+w_reg-1]     ;   read pixels
876     WRITE_V_PIXEL %%n, r0+r4-%%n        ;   write pixels
877     dec     r5
878 %endif ; ARCH_X86_64/32
879     jnz .emuedge_extend_right_ %+ %%n   ; } while (--block_h)
880 %if ARCH_X86_64
881     ret
882 %else ; ARCH_X86_32
883     rep ret
884 %endif ; ARCH_X86_64/32
885 %assign %%n %%n+2
886 %endrep
887
888 %if ARCH_X86_32
889 %define stack_offset 0x10
890 %endif
891 %endmacro ; RIGHT_EXTEND
892
893 ; below follow the "slow" copy/extend functions, these act on a non-fixed
894 ; width specified in a register, and run a loop to copy the full amount
895 ; of bytes. They are optimized for copying of large amounts of pixels per
896 ; line, so they unconditionally splat data into mm registers to copy 8
897 ; bytes per loop iteration. It could be considered to use xmm for x86-64
898 ; also, but I haven't optimized this as much (i.e. FIXME)
899 %macro V_COPY_NPX 4-5
900 %if %0 == 4
901     test     w_reg, %4
902     jz .%1_skip_%4_px
903 %else ; %0 == 5
904 .%1_%4_px_loop:
905 %endif
906     %3          %2, [r1+cnt_reg]
907     %3 [r0+cnt_reg], %2
908     add    cnt_reg, %4
909 %if %0 == 5
910     sub      w_reg, %4
911     test     w_reg, %5
912     jnz .%1_%4_px_loop
913 %endif
914 .%1_skip_%4_px:
915 %endmacro
916
917 %macro V_COPY_ROW 2
918 %ifidn %1, bottom
919     sub         r1, linesize
920 %endif
921 .%1_copy_loop:
922     xor    cnt_reg, cnt_reg
923 %if notcpuflag(sse)
924 %define linesize r2m
925     V_COPY_NPX %1,  mm0, movq,    8, 0xFFFFFFF8
926 %else ; sse
927     V_COPY_NPX %1, xmm0, movups, 16, 0xFFFFFFF0
928 %if ARCH_X86_64
929 %define linesize r2
930     V_COPY_NPX %1, rax , mov,     8
931 %else ; ARCH_X86_32
932 %define linesize r2m
933     V_COPY_NPX %1,  mm0, movq,    8
934 %endif ; ARCH_X86_64/32
935 %endif ; sse
936     V_COPY_NPX %1, vald, mov,     4
937     V_COPY_NPX %1, valw, mov,     2
938     V_COPY_NPX %1, vall, mov,     1
939     mov      w_reg, cnt_reg
940 %ifidn %1, body
941     add         r1, linesize
942 %endif
943     add         r0, linesize
944     dec         %2
945     jnz .%1_copy_loop
946 %endmacro
947
948 %macro SLOW_V_EXTEND 0
949 .slow_v_extend_loop:
950 ; r0=buf,r1=src,r2(64)/r2m(32)=linesize,r3(64)/r3m(32)=start_x,r4=end_y,r5=block_h
951 ; r8(64)/r3(later-64)/r2(32)=cnt_reg,r6(64)/r3(32)=val_reg,r7(64)/r6(32)=w=end_x-start_x
952 %if ARCH_X86_64
953     push        r8              ; save old value of block_h
954     test        r3, r3
955 %define cnt_reg r8
956     jz .do_body_copy            ; if (!start_y) goto do_body_copy
957     V_COPY_ROW top, r3
958 %else
959     cmp  dword r3m, 0
960 %define cnt_reg r2
961     je .do_body_copy            ; if (!start_y) goto do_body_copy
962     V_COPY_ROW top, dword r3m
963 %endif
964
965 .do_body_copy:
966     V_COPY_ROW body, r4
967
968 %if ARCH_X86_64
969     pop         r8              ; restore old value of block_h
970 %define cnt_reg r3
971 %endif
972     test        r5, r5
973 %if ARCH_X86_64
974     jz .v_extend_end
975 %else
976     jz .skip_bottom_extend
977 %endif
978     V_COPY_ROW bottom, r5
979 %if ARCH_X86_32
980 .skip_bottom_extend:
981     mov         r2, r2m
982 %endif
983     jmp .v_extend_end
984 %endmacro
985
986 %macro SLOW_LEFT_EXTEND 0
987 .slow_left_extend_loop:
988 ; r0=buf+block_h*linesize,r2=linesize,r6(64)/r3(32)=val,r5=block_h,r4=cntr,r7/r6=start_x
989     mov         r4, 8
990     sub         r0, linesize
991     READ_V_PIXEL 8, [r0+w_reg]
992 .left_extend_8px_loop:
993     movq [r0+r4-8], mm0
994     add         r4, 8
995     cmp         r4, w_reg
996     jle .left_extend_8px_loop
997     sub         r4, 8
998     cmp         r4, w_reg
999     jge .left_extend_loop_end
1000 .left_extend_2px_loop:
1001     mov    [r0+r4], valw
1002     add         r4, 2
1003     cmp         r4, w_reg
1004     jl .left_extend_2px_loop
1005 .left_extend_loop_end:
1006     dec         r5
1007     jnz .slow_left_extend_loop
1008 %if ARCH_X86_32
1009     mov         r2, r2m
1010 %endif
1011     jmp .right_extend
1012 %endmacro
1013
1014 %macro SLOW_RIGHT_EXTEND 0
1015 .slow_right_extend_loop:
1016 ; r3(64)/r0(32)=buf+block_h*linesize,r2=linesize,r4=block_w,r8(64)/r5(32)=block_h,
1017 ; r7(64)/r6(32)=end_x,r6/r3=val,r1=cntr
1018 %if ARCH_X86_64
1019 %define buf_reg r3
1020 %define bh_reg r8
1021 %else
1022 %define buf_reg r0
1023 %define bh_reg r5
1024 %endif
1025     lea         r1, [r4-8]
1026     sub    buf_reg, linesize
1027     READ_V_PIXEL 8, [buf_reg+w_reg-1]
1028 .right_extend_8px_loop:
1029     movq [buf_reg+r1], mm0
1030     sub         r1, 8
1031     cmp         r1, w_reg
1032     jge .right_extend_8px_loop
1033     add         r1, 8
1034     cmp         r1, w_reg
1035     je .right_extend_loop_end
1036 .right_extend_2px_loop:
1037     sub         r1, 2
1038     mov [buf_reg+r1], valw
1039     cmp         r1, w_reg
1040     jg .right_extend_2px_loop
1041 .right_extend_loop_end:
1042     dec         bh_reg
1043     jnz .slow_right_extend_loop
1044     jmp .h_extend_end
1045 %endmacro
1046
1047 %macro emu_edge 1
1048 INIT_XMM %1
1049 EMU_EDGE_FUNC
1050 VERTICAL_EXTEND
1051 LEFT_EXTEND
1052 RIGHT_EXTEND
1053 SLOW_V_EXTEND
1054 SLOW_LEFT_EXTEND
1055 SLOW_RIGHT_EXTEND
1056 %endmacro
1057
1058 emu_edge sse
1059 %if ARCH_X86_32
1060 emu_edge mmx
1061 %endif
1062
1063 ;-----------------------------------------------------------------------------
1064 ; void ff_vector_clip_int32(int32_t *dst, const int32_t *src, int32_t min,
1065 ;                           int32_t max, unsigned int len)
1066 ;-----------------------------------------------------------------------------
1067
1068 ; %1 = number of xmm registers used
1069 ; %2 = number of inline load/process/store loops per asm loop
1070 ; %3 = process 4*mmsize (%3=0) or 8*mmsize (%3=1) bytes per loop
1071 ; %4 = CLIPD function takes min/max as float instead of int (CLIPD_SSE2)
1072 ; %5 = suffix
1073 %macro VECTOR_CLIP_INT32 4-5
1074 cglobal vector_clip_int32%5, 5,5,%1, dst, src, min, max, len
1075 %if %4
1076     cvtsi2ss  m4, minm
1077     cvtsi2ss  m5, maxm
1078 %else
1079     movd      m4, minm
1080     movd      m5, maxm
1081 %endif
1082     SPLATD    m4
1083     SPLATD    m5
1084 .loop:
1085 %assign %%i 1
1086 %rep %2
1087     mova      m0,  [srcq+mmsize*0*%%i]
1088     mova      m1,  [srcq+mmsize*1*%%i]
1089     mova      m2,  [srcq+mmsize*2*%%i]
1090     mova      m3,  [srcq+mmsize*3*%%i]
1091 %if %3
1092     mova      m7,  [srcq+mmsize*4*%%i]
1093     mova      m8,  [srcq+mmsize*5*%%i]
1094     mova      m9,  [srcq+mmsize*6*%%i]
1095     mova      m10, [srcq+mmsize*7*%%i]
1096 %endif
1097     CLIPD  m0,  m4, m5, m6
1098     CLIPD  m1,  m4, m5, m6
1099     CLIPD  m2,  m4, m5, m6
1100     CLIPD  m3,  m4, m5, m6
1101 %if %3
1102     CLIPD  m7,  m4, m5, m6
1103     CLIPD  m8,  m4, m5, m6
1104     CLIPD  m9,  m4, m5, m6
1105     CLIPD  m10, m4, m5, m6
1106 %endif
1107     mova  [dstq+mmsize*0*%%i], m0
1108     mova  [dstq+mmsize*1*%%i], m1
1109     mova  [dstq+mmsize*2*%%i], m2
1110     mova  [dstq+mmsize*3*%%i], m3
1111 %if %3
1112     mova  [dstq+mmsize*4*%%i], m7
1113     mova  [dstq+mmsize*5*%%i], m8
1114     mova  [dstq+mmsize*6*%%i], m9
1115     mova  [dstq+mmsize*7*%%i], m10
1116 %endif
1117 %assign %%i %%i+1
1118 %endrep
1119     add     srcq, mmsize*4*(%2+%3)
1120     add     dstq, mmsize*4*(%2+%3)
1121     sub     lend, mmsize*(%2+%3)
1122     jg .loop
1123     REP_RET
1124 %endmacro
1125
1126 INIT_MMX mmx
1127 %define CLIPD CLIPD_MMX
1128 VECTOR_CLIP_INT32 0, 1, 0, 0
1129 INIT_XMM sse2
1130 VECTOR_CLIP_INT32 6, 1, 0, 0, _int
1131 %define CLIPD CLIPD_SSE2
1132 VECTOR_CLIP_INT32 6, 2, 0, 1
1133 INIT_XMM sse4
1134 %define CLIPD CLIPD_SSE41
1135 %ifdef m8
1136 VECTOR_CLIP_INT32 11, 1, 1, 0
1137 %else
1138 VECTOR_CLIP_INT32 6, 1, 0, 0
1139 %endif
1140
1141 ;-----------------------------------------------------------------------------
1142 ; void vector_fmul_reverse(float *dst, const float *src0, const float *src1,
1143 ;                          int len)
1144 ;-----------------------------------------------------------------------------
1145 %macro VECTOR_FMUL_REVERSE 0
1146 cglobal vector_fmul_reverse, 4,4,2, dst, src0, src1, len
1147     lea       lenq, [lend*4 - 2*mmsize]
1148 ALIGN 16
1149 .loop:
1150 %if cpuflag(avx)
1151     vmovaps     xmm0, [src1q + 16]
1152     vinsertf128 m0, m0, [src1q], 1
1153     vshufps     m0, m0, m0, q0123
1154     vmovaps     xmm1, [src1q + mmsize + 16]
1155     vinsertf128 m1, m1, [src1q + mmsize], 1
1156     vshufps     m1, m1, m1, q0123
1157 %else
1158     mova    m0, [src1q]
1159     mova    m1, [src1q + mmsize]
1160     shufps  m0, m0, q0123
1161     shufps  m1, m1, q0123
1162 %endif
1163     mulps   m0, m0, [src0q + lenq + mmsize]
1164     mulps   m1, m1, [src0q + lenq]
1165     mova    [dstq + lenq + mmsize], m0
1166     mova    [dstq + lenq], m1
1167     add     src1q, 2*mmsize
1168     sub     lenq,  2*mmsize
1169     jge     .loop
1170     REP_RET
1171 %endmacro
1172
1173 INIT_XMM sse
1174 VECTOR_FMUL_REVERSE
1175 %if HAVE_AVX_EXTERNAL
1176 INIT_YMM avx
1177 VECTOR_FMUL_REVERSE
1178 %endif
1179
1180 ;-----------------------------------------------------------------------------
1181 ; vector_fmul_add(float *dst, const float *src0, const float *src1,
1182 ;                 const float *src2, int len)
1183 ;-----------------------------------------------------------------------------
1184 %macro VECTOR_FMUL_ADD 0
1185 cglobal vector_fmul_add, 5,5,2, dst, src0, src1, src2, len
1186     lea       lenq, [lend*4 - 2*mmsize]
1187 ALIGN 16
1188 .loop:
1189     mova    m0,   [src0q + lenq]
1190     mova    m1,   [src0q + lenq + mmsize]
1191     mulps   m0, m0, [src1q + lenq]
1192     mulps   m1, m1, [src1q + lenq + mmsize]
1193     addps   m0, m0, [src2q + lenq]
1194     addps   m1, m1, [src2q + lenq + mmsize]
1195     mova    [dstq + lenq], m0
1196     mova    [dstq + lenq + mmsize], m1
1197
1198     sub     lenq,   2*mmsize
1199     jge     .loop
1200     REP_RET
1201 %endmacro
1202
1203 INIT_XMM sse
1204 VECTOR_FMUL_ADD
1205 %if HAVE_AVX_EXTERNAL
1206 INIT_YMM avx
1207 VECTOR_FMUL_ADD
1208 %endif
1209
1210 ;-----------------------------------------------------------------------------
1211 ; void ff_butterflies_float_interleave(float *dst, const float *src0,
1212 ;                                      const float *src1, int len);
1213 ;-----------------------------------------------------------------------------
1214
1215 %macro BUTTERFLIES_FLOAT_INTERLEAVE 0
1216 cglobal butterflies_float_interleave, 4,4,3, dst, src0, src1, len
1217 %if ARCH_X86_64
1218     movsxd    lenq, lend
1219 %endif
1220     test      lenq, lenq
1221     jz .end
1222     shl       lenq, 2
1223     lea      src0q, [src0q +   lenq]
1224     lea      src1q, [src1q +   lenq]
1225     lea       dstq, [ dstq + 2*lenq]
1226     neg       lenq
1227 .loop:
1228     mova        m0, [src0q + lenq]
1229     mova        m1, [src1q + lenq]
1230     subps       m2, m0, m1
1231     addps       m0, m0, m1
1232     unpcklps    m1, m0, m2
1233     unpckhps    m0, m0, m2
1234 %if cpuflag(avx)
1235     vextractf128 [dstq + 2*lenq     ], m1, 0
1236     vextractf128 [dstq + 2*lenq + 16], m0, 0
1237     vextractf128 [dstq + 2*lenq + 32], m1, 1
1238     vextractf128 [dstq + 2*lenq + 48], m0, 1
1239 %else
1240     mova [dstq + 2*lenq         ], m1
1241     mova [dstq + 2*lenq + mmsize], m0
1242 %endif
1243     add       lenq, mmsize
1244     jl .loop
1245 .end:
1246     REP_RET
1247 %endmacro
1248
1249 INIT_XMM sse
1250 BUTTERFLIES_FLOAT_INTERLEAVE
1251 %if HAVE_AVX_EXTERNAL
1252 INIT_YMM avx
1253 BUTTERFLIES_FLOAT_INTERLEAVE
1254 %endif
1255
1256 ; %1 = aligned/unaligned
1257 %macro BSWAP_LOOPS  1
1258     mov      r3, r2
1259     sar      r2, 3
1260     jz       .left4_%1
1261 .loop8_%1:
1262     mov%1    m0, [r1 +  0]
1263     mov%1    m1, [r1 + 16]
1264 %if cpuflag(ssse3)
1265     pshufb   m0, m2
1266     pshufb   m1, m2
1267     mova     [r0 +  0], m0
1268     mova     [r0 + 16], m1
1269 %else
1270     pshuflw  m0, m0, 10110001b
1271     pshuflw  m1, m1, 10110001b
1272     pshufhw  m0, m0, 10110001b
1273     pshufhw  m1, m1, 10110001b
1274     mova     m2, m0
1275     mova     m3, m1
1276     psllw    m0, 8
1277     psllw    m1, 8
1278     psrlw    m2, 8
1279     psrlw    m3, 8
1280     por      m2, m0
1281     por      m3, m1
1282     mova     [r0 +  0], m2
1283     mova     [r0 + 16], m3
1284 %endif
1285     add      r0, 32
1286     add      r1, 32
1287     dec      r2
1288     jnz      .loop8_%1
1289 .left4_%1:
1290     mov      r2, r3
1291     and      r3, 4
1292     jz       .left
1293     mov%1    m0, [r1]
1294 %if cpuflag(ssse3)
1295     pshufb   m0, m2
1296     mova     [r0], m0
1297 %else
1298     pshuflw  m0, m0, 10110001b
1299     pshufhw  m0, m0, 10110001b
1300     mova     m2, m0
1301     psllw    m0, 8
1302     psrlw    m2, 8
1303     por      m2, m0
1304     mova     [r0], m2
1305 %endif
1306     add      r1, 16
1307     add      r0, 16
1308 %endmacro
1309
1310 ; void bswap_buf(uint32_t *dst, const uint32_t *src, int w);
1311 %macro BSWAP32_BUF 0
1312 %if cpuflag(ssse3)
1313 cglobal bswap32_buf, 3,4,3
1314     mov      r3, r1
1315     mova     m2, [pb_bswap32]
1316 %else
1317 cglobal bswap32_buf, 3,4,5
1318     mov      r3, r1
1319 %endif
1320     and      r3, 15
1321     jz       .start_align
1322     BSWAP_LOOPS  u
1323     jmp      .left
1324 .start_align:
1325     BSWAP_LOOPS  a
1326 .left:
1327 %if cpuflag(ssse3)
1328     mov      r3, r2
1329     and      r2, 2
1330     jz       .left1
1331     movq     m0, [r1]
1332     pshufb   m0, m2
1333     movq     [r0], m0
1334     add      r1, 8
1335     add      r0, 8
1336 .left1:
1337     and      r3, 1
1338     jz       .end
1339     mov      r2d, [r1]
1340     bswap    r2d
1341     mov      [r0], r2d
1342 %else
1343     and      r2, 3
1344     jz       .end
1345 .loop2:
1346     mov      r3d, [r1]
1347     bswap    r3d
1348     mov      [r0], r3d
1349     add      r1, 4
1350     add      r0, 4
1351     dec      r2
1352     jnz      .loop2
1353 %endif
1354 .end:
1355     RET
1356 %endmacro
1357
1358 INIT_XMM sse2
1359 BSWAP32_BUF
1360
1361 INIT_XMM ssse3
1362 BSWAP32_BUF
1363
1364 %macro op_avgh 3
1365     movh   %3, %2
1366     pavgb  %1, %3
1367     movh   %2, %1
1368 %endmacro
1369
1370 %macro op_avg 2
1371     pavgb  %1, %2
1372     mova   %2, %1
1373 %endmacro
1374
1375 %macro op_puth 2-3
1376     movh   %2, %1
1377 %endmacro
1378
1379 %macro op_put 2
1380     mova   %2, %1
1381 %endmacro
1382
1383 ; void pixels4_l2_mmxext(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
1384 %macro PIXELS4_L2 1
1385 %define OP op_%1h
1386 cglobal %1_pixels4_l2, 6,6
1387     movsxdifnidn r3, r3d
1388     movsxdifnidn r4, r4d
1389     test        r5d, 1
1390     je        .loop
1391     movd         m0, [r1]
1392     movd         m1, [r2]
1393     add          r1, r4
1394     add          r2, 4
1395     pavgb        m0, m1
1396     OP           m0, [r0], m3
1397     add          r0, r3
1398     dec         r5d
1399 .loop:
1400     mova         m0, [r1]
1401     mova         m1, [r1+r4]
1402     lea          r1, [r1+2*r4]
1403     pavgb        m0, [r2]
1404     pavgb        m1, [r2+4]
1405     OP           m0, [r0], m3
1406     OP           m1, [r0+r3], m3
1407     lea          r0, [r0+2*r3]
1408     mova         m0, [r1]
1409     mova         m1, [r1+r4]
1410     lea          r1, [r1+2*r4]
1411     pavgb        m0, [r2+8]
1412     pavgb        m1, [r2+12]
1413     OP           m0, [r0], m3
1414     OP           m1, [r0+r3], m3
1415     lea          r0, [r0+2*r3]
1416     add          r2, 16
1417     sub         r5d, 4
1418     jne       .loop
1419     REP_RET
1420 %endmacro
1421
1422 INIT_MMX mmxext
1423 PIXELS4_L2 put
1424 PIXELS4_L2 avg
1425
1426 ; void pixels8_l2_mmxext(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
1427 %macro PIXELS8_L2 1
1428 %define OP op_%1
1429 cglobal %1_pixels8_l2, 6,6
1430     movsxdifnidn r3, r3d
1431     movsxdifnidn r4, r4d
1432     test        r5d, 1
1433     je        .loop
1434     mova         m0, [r1]
1435     mova         m1, [r2]
1436     add          r1, r4
1437     add          r2, 8
1438     pavgb        m0, m1
1439     OP           m0, [r0]
1440     add          r0, r3
1441     dec         r5d
1442 .loop:
1443     mova         m0, [r1]
1444     mova         m1, [r1+r4]
1445     lea          r1, [r1+2*r4]
1446     pavgb        m0, [r2]
1447     pavgb        m1, [r2+8]
1448     OP           m0, [r0]
1449     OP           m1, [r0+r3]
1450     lea          r0, [r0+2*r3]
1451     mova         m0, [r1]
1452     mova         m1, [r1+r4]
1453     lea          r1, [r1+2*r4]
1454     pavgb        m0, [r2+16]
1455     pavgb        m1, [r2+24]
1456     OP           m0, [r0]
1457     OP           m1, [r0+r3]
1458     lea          r0, [r0+2*r3]
1459     add          r2, 32
1460     sub         r5d, 4
1461     jne       .loop
1462     REP_RET
1463 %endmacro
1464
1465 INIT_MMX mmxext
1466 PIXELS8_L2 put
1467 PIXELS8_L2 avg
1468
1469 ; void pixels16_l2_mmxext(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
1470 %macro PIXELS16_L2 1
1471 %define OP op_%1
1472 cglobal %1_pixels16_l2, 6,6
1473     movsxdifnidn r3, r3d
1474     movsxdifnidn r4, r4d
1475     test        r5d, 1
1476     je        .loop
1477     mova         m0, [r1]
1478     mova         m1, [r1+8]
1479     pavgb        m0, [r2]
1480     pavgb        m1, [r2+8]
1481     add          r1, r4
1482     add          r2, 16
1483     OP           m0, [r0]
1484     OP           m1, [r0+8]
1485     add          r0, r3
1486     dec         r5d
1487 .loop:
1488     mova         m0, [r1]
1489     mova         m1, [r1+8]
1490     add          r1, r4
1491     pavgb        m0, [r2]
1492     pavgb        m1, [r2+8]
1493     OP           m0, [r0]
1494     OP           m1, [r0+8]
1495     add          r0, r3
1496     mova         m0, [r1]
1497     mova         m1, [r1+8]
1498     add          r1, r4
1499     pavgb        m0, [r2+16]
1500     pavgb        m1, [r2+24]
1501     OP           m0, [r0]
1502     OP           m1, [r0+8]
1503     add          r0, r3
1504     add          r2, 32
1505     sub         r5d, 2
1506     jne       .loop
1507     REP_RET
1508 %endmacro
1509
1510 INIT_MMX mmxext
1511 PIXELS16_L2 put
1512 PIXELS16_L2 avg
1513
1514 INIT_MMX mmxext
1515 ; void pixels(uint8_t *block, const uint8_t *pixels, int line_size, int h)
1516 %macro PIXELS48 2
1517 %if %2 == 4
1518 %define OP movh
1519 %else
1520 %define OP mova
1521 %endif
1522 cglobal %1_pixels%2, 4,5
1523     movsxdifnidn r2, r2d
1524     lea          r4, [r2*3]
1525 .loop:
1526     OP           m0, [r1]
1527     OP           m1, [r1+r2]
1528     OP           m2, [r1+r2*2]
1529     OP           m3, [r1+r4]
1530     lea          r1, [r1+r2*4]
1531 %ifidn %1, avg
1532     pavgb        m0, [r0]
1533     pavgb        m1, [r0+r2]
1534     pavgb        m2, [r0+r2*2]
1535     pavgb        m3, [r0+r4]
1536 %endif
1537     OP         [r0], m0
1538     OP      [r0+r2], m1
1539     OP    [r0+r2*2], m2
1540     OP      [r0+r4], m3
1541     sub         r3d, 4
1542     lea          r0, [r0+r2*4]
1543     jne       .loop
1544     RET
1545 %endmacro
1546
1547 PIXELS48 put, 4
1548 PIXELS48 avg, 4
1549 PIXELS48 put, 8
1550 PIXELS48 avg, 8
1551
1552 INIT_XMM sse2
1553 ; void put_pixels16_sse2(uint8_t *block, const uint8_t *pixels, int line_size, int h)
1554 cglobal put_pixels16, 4,5,4
1555     movsxdifnidn r2, r2d
1556     lea          r4, [r2*3]
1557 .loop:
1558     movu         m0, [r1]
1559     movu         m1, [r1+r2]
1560     movu         m2, [r1+r2*2]
1561     movu         m3, [r1+r4]
1562     lea          r1, [r1+r2*4]
1563     mova       [r0], m0
1564     mova    [r0+r2], m1
1565     mova  [r0+r2*2], m2
1566     mova    [r0+r4], m3
1567     sub         r3d, 4
1568     lea          r0, [r0+r2*4]
1569     jnz       .loop
1570     REP_RET
1571
1572 ; void avg_pixels16_sse2(uint8_t *block, const uint8_t *pixels, int line_size, int h)
1573 cglobal avg_pixels16, 4,5,4
1574     movsxdifnidn r2, r2d
1575     lea          r4, [r2*3]
1576 .loop:
1577     movu         m0, [r1]
1578     movu         m1, [r1+r2]
1579     movu         m2, [r1+r2*2]
1580     movu         m3, [r1+r4]
1581     lea          r1, [r1+r2*4]
1582     pavgb        m0, [r0]
1583     pavgb        m1, [r0+r2]
1584     pavgb        m2, [r0+r2*2]
1585     pavgb        m3, [r0+r4]
1586     mova       [r0], m0
1587     mova    [r0+r2], m1
1588     mova  [r0+r2*2], m2
1589     mova    [r0+r4], m3
1590     sub         r3d, 4
1591     lea          r0, [r0+r2*4]
1592     jnz       .loop
1593     REP_RET