x86: dsputil: port to cpuflags
[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 "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 SPLATD SPLATD_MMX
1128 %define CLIPD CLIPD_MMX
1129 VECTOR_CLIP_INT32 0, 1, 0, 0
1130 INIT_XMM sse2
1131 %define SPLATD SPLATD_SSE2
1132 VECTOR_CLIP_INT32 6, 1, 0, 0, _int
1133 %define CLIPD CLIPD_SSE2
1134 VECTOR_CLIP_INT32 6, 2, 0, 1
1135 INIT_XMM sse4
1136 %define CLIPD CLIPD_SSE41
1137 %ifdef m8
1138 VECTOR_CLIP_INT32 11, 1, 1, 0
1139 %else
1140 VECTOR_CLIP_INT32 6, 1, 0, 0
1141 %endif
1142
1143 ;-----------------------------------------------------------------------------
1144 ; void vector_fmul_reverse(float *dst, const float *src0, const float *src1,
1145 ;                          int len)
1146 ;-----------------------------------------------------------------------------
1147 %macro VECTOR_FMUL_REVERSE 0
1148 cglobal vector_fmul_reverse, 4,4,2, dst, src0, src1, len
1149     lea       lenq, [lend*4 - 2*mmsize]
1150 ALIGN 16
1151 .loop:
1152 %if cpuflag(avx)
1153     vmovaps     xmm0, [src1q + 16]
1154     vinsertf128 m0, m0, [src1q], 1
1155     vshufps     m0, m0, m0, q0123
1156     vmovaps     xmm1, [src1q + mmsize + 16]
1157     vinsertf128 m1, m1, [src1q + mmsize], 1
1158     vshufps     m1, m1, m1, q0123
1159 %else
1160     mova    m0, [src1q]
1161     mova    m1, [src1q + mmsize]
1162     shufps  m0, m0, q0123
1163     shufps  m1, m1, q0123
1164 %endif
1165     mulps   m0, m0, [src0q + lenq + mmsize]
1166     mulps   m1, m1, [src0q + lenq]
1167     mova    [dstq + lenq + mmsize], m0
1168     mova    [dstq + lenq], m1
1169     add     src1q, 2*mmsize
1170     sub     lenq,  2*mmsize
1171     jge     .loop
1172     REP_RET
1173 %endmacro
1174
1175 INIT_XMM sse
1176 VECTOR_FMUL_REVERSE
1177 INIT_YMM avx
1178 VECTOR_FMUL_REVERSE
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 INIT_YMM avx
1206 VECTOR_FMUL_ADD
1207
1208 ;-----------------------------------------------------------------------------
1209 ; void ff_butterflies_float_interleave(float *dst, const float *src0,
1210 ;                                      const float *src1, int len);
1211 ;-----------------------------------------------------------------------------
1212
1213 %macro BUTTERFLIES_FLOAT_INTERLEAVE 0
1214 cglobal butterflies_float_interleave, 4,4,3, dst, src0, src1, len
1215 %if ARCH_X86_64
1216     movsxd    lenq, lend
1217 %endif
1218     test      lenq, lenq
1219     jz .end
1220     shl       lenq, 2
1221     lea      src0q, [src0q +   lenq]
1222     lea      src1q, [src1q +   lenq]
1223     lea       dstq, [ dstq + 2*lenq]
1224     neg       lenq
1225 .loop:
1226     mova        m0, [src0q + lenq]
1227     mova        m1, [src1q + lenq]
1228     subps       m2, m0, m1
1229     addps       m0, m0, m1
1230     unpcklps    m1, m0, m2
1231     unpckhps    m0, m0, m2
1232 %if cpuflag(avx)
1233     vextractf128 [dstq + 2*lenq     ], m1, 0
1234     vextractf128 [dstq + 2*lenq + 16], m0, 0
1235     vextractf128 [dstq + 2*lenq + 32], m1, 1
1236     vextractf128 [dstq + 2*lenq + 48], m0, 1
1237 %else
1238     mova [dstq + 2*lenq         ], m1
1239     mova [dstq + 2*lenq + mmsize], m0
1240 %endif
1241     add       lenq, mmsize
1242     jl .loop
1243 .end:
1244     REP_RET
1245 %endmacro
1246
1247 INIT_XMM sse
1248 BUTTERFLIES_FLOAT_INTERLEAVE
1249 INIT_YMM avx
1250 BUTTERFLIES_FLOAT_INTERLEAVE
1251
1252 ; %1 = aligned/unaligned
1253 %macro BSWAP_LOOPS  1
1254     mov      r3, r2
1255     sar      r2, 3
1256     jz       .left4_%1
1257 .loop8_%1:
1258     mov%1    m0, [r1 +  0]
1259     mov%1    m1, [r1 + 16]
1260 %if cpuflag(ssse3)
1261     pshufb   m0, m2
1262     pshufb   m1, m2
1263     mova     [r0 +  0], m0
1264     mova     [r0 + 16], m1
1265 %else
1266     pshuflw  m0, m0, 10110001b
1267     pshuflw  m1, m1, 10110001b
1268     pshufhw  m0, m0, 10110001b
1269     pshufhw  m1, m1, 10110001b
1270     mova     m2, m0
1271     mova     m3, m1
1272     psllw    m0, 8
1273     psllw    m1, 8
1274     psrlw    m2, 8
1275     psrlw    m3, 8
1276     por      m2, m0
1277     por      m3, m1
1278     mova     [r0 +  0], m2
1279     mova     [r0 + 16], m3
1280 %endif
1281     add      r0, 32
1282     add      r1, 32
1283     dec      r2
1284     jnz      .loop8_%1
1285 .left4_%1:
1286     mov      r2, r3
1287     and      r3, 4
1288     jz       .left
1289     mov%1    m0, [r1]
1290 %if cpuflag(ssse3)
1291     pshufb   m0, m2
1292     mova     [r0], m0
1293 %else
1294     pshuflw  m0, m0, 10110001b
1295     pshufhw  m0, m0, 10110001b
1296     mova     m2, m0
1297     psllw    m0, 8
1298     psrlw    m2, 8
1299     por      m2, m0
1300     mova     [r0], m2
1301 %endif
1302     add      r1, 16
1303     add      r0, 16
1304 %endmacro
1305
1306 ; void bswap_buf(uint32_t *dst, const uint32_t *src, int w);
1307 %macro BSWAP32_BUF 0
1308 %if cpuflag(ssse3)
1309 cglobal bswap32_buf, 3,4,3
1310     mov      r3, r1
1311     mova     m2, [pb_bswap32]
1312 %else
1313 cglobal bswap32_buf, 3,4,5
1314     mov      r3, r1
1315 %endif
1316     and      r3, 15
1317     jz       .start_align
1318     BSWAP_LOOPS  u
1319     jmp      .left
1320 .start_align:
1321     BSWAP_LOOPS  a
1322 .left:
1323 %if cpuflag(ssse3)
1324     mov      r3, r2
1325     and      r2, 2
1326     jz       .left1
1327     movq     m0, [r1]
1328     pshufb   m0, m2
1329     movq     [r0], m0
1330     add      r1, 8
1331     add      r0, 8
1332 .left1:
1333     and      r3, 1
1334     jz       .end
1335     mov      r2d, [r1]
1336     bswap    r2d
1337     mov      [r0], r2d
1338 %else
1339     and      r2, 3
1340     jz       .end
1341 .loop2:
1342     mov      r3d, [r1]
1343     bswap    r3d
1344     mov      [r0], r3d
1345     add      r1, 4
1346     add      r0, 4
1347     dec      r2
1348     jnz      .loop2
1349 %endif
1350 .end:
1351     RET
1352 %endmacro
1353
1354 INIT_XMM sse2
1355 BSWAP32_BUF
1356
1357 INIT_XMM ssse3
1358 BSWAP32_BUF