]> git.sesse.net Git - ffmpeg/blob - libavcodec/x86/dsputil_yasm.asm
Fix ff_emu_edge_core_sse() on Win64.
[ffmpeg] / libavcodec / x86 / dsputil_yasm.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 ;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 ;******************************************************************************
21
22 %include "x86inc.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
31 section .text align=16
32
33 %macro SCALARPRODUCT 1
34 ; int scalarproduct_int16(int16_t *v1, int16_t *v2, int order, int shift)
35 cglobal scalarproduct_int16_%1, 3,3,4, v1, v2, order, shift
36     shl orderq, 1
37     add v1q, orderq
38     add v2q, orderq
39     neg orderq
40     movd    m3, shiftm
41     pxor    m2, m2
42 .loop:
43     movu    m0, [v1q + orderq]
44     movu    m1, [v1q + orderq + mmsize]
45     pmaddwd m0, [v2q + orderq]
46     pmaddwd m1, [v2q + orderq + mmsize]
47     paddd   m2, m0
48     paddd   m2, m1
49     add     orderq, mmsize*2
50     jl .loop
51 %if mmsize == 16
52     movhlps m0, m2
53     paddd   m2, m0
54     psrad   m2, m3
55     pshuflw m0, m2, 0x4e
56 %else
57     psrad   m2, m3
58     pshufw  m0, m2, 0x4e
59 %endif
60     paddd   m2, m0
61     movd   eax, m2
62     RET
63
64 ; int scalarproduct_and_madd_int16(int16_t *v1, int16_t *v2, int16_t *v3, int order, int mul)
65 cglobal scalarproduct_and_madd_int16_%1, 4,4,8, v1, v2, v3, order, mul
66     shl orderq, 1
67     movd    m7, mulm
68 %if mmsize == 16
69     pshuflw m7, m7, 0
70     punpcklqdq m7, m7
71 %else
72     pshufw  m7, m7, 0
73 %endif
74     pxor    m6, m6
75     add v1q, orderq
76     add v2q, orderq
77     add v3q, orderq
78     neg orderq
79 .loop:
80     movu    m0, [v2q + orderq]
81     movu    m1, [v2q + orderq + mmsize]
82     mova    m4, [v1q + orderq]
83     mova    m5, [v1q + orderq + mmsize]
84     movu    m2, [v3q + orderq]
85     movu    m3, [v3q + orderq + mmsize]
86     pmaddwd m0, m4
87     pmaddwd m1, m5
88     pmullw  m2, m7
89     pmullw  m3, m7
90     paddd   m6, m0
91     paddd   m6, m1
92     paddw   m2, m4
93     paddw   m3, m5
94     mova    [v1q + orderq], m2
95     mova    [v1q + orderq + mmsize], m3
96     add     orderq, mmsize*2
97     jl .loop
98 %if mmsize == 16
99     movhlps m0, m6
100     paddd   m6, m0
101     pshuflw m0, m6, 0x4e
102 %else
103     pshufw  m0, m6, 0x4e
104 %endif
105     paddd   m6, m0
106     movd   eax, m6
107     RET
108 %endmacro
109
110 INIT_MMX
111 SCALARPRODUCT mmx2
112 INIT_XMM
113 SCALARPRODUCT sse2
114
115 %macro SCALARPRODUCT_LOOP 1
116 align 16
117 .loop%1:
118     sub     orderq, mmsize*2
119 %if %1
120     mova    m1, m4
121     mova    m4, [v2q + orderq]
122     mova    m0, [v2q + orderq + mmsize]
123     palignr m1, m0, %1
124     palignr m0, m4, %1
125     mova    m3, m5
126     mova    m5, [v3q + orderq]
127     mova    m2, [v3q + orderq + mmsize]
128     palignr m3, m2, %1
129     palignr m2, m5, %1
130 %else
131     mova    m0, [v2q + orderq]
132     mova    m1, [v2q + orderq + mmsize]
133     mova    m2, [v3q + orderq]
134     mova    m3, [v3q + orderq + mmsize]
135 %endif
136     %define t0  [v1q + orderq]
137     %define t1  [v1q + orderq + mmsize]
138 %ifdef ARCH_X86_64
139     mova    m8, t0
140     mova    m9, t1
141     %define t0  m8
142     %define t1  m9
143 %endif
144     pmaddwd m0, t0
145     pmaddwd m1, t1
146     pmullw  m2, m7
147     pmullw  m3, m7
148     paddw   m2, t0
149     paddw   m3, t1
150     paddd   m6, m0
151     paddd   m6, m1
152     mova    [v1q + orderq], m2
153     mova    [v1q + orderq + mmsize], m3
154     jg .loop%1
155 %if %1
156     jmp .end
157 %endif
158 %endmacro
159
160 ; int scalarproduct_and_madd_int16(int16_t *v1, int16_t *v2, int16_t *v3, int order, int mul)
161 cglobal scalarproduct_and_madd_int16_ssse3, 4,5,10, v1, v2, v3, order, mul
162     shl orderq, 1
163     movd    m7, mulm
164     pshuflw m7, m7, 0
165     punpcklqdq m7, m7
166     pxor    m6, m6
167     mov    r4d, v2d
168     and    r4d, 15
169     and    v2q, ~15
170     and    v3q, ~15
171     mova    m4, [v2q + orderq]
172     mova    m5, [v3q + orderq]
173     ; linear is faster than branch tree or jump table, because the branches taken are cyclic (i.e. predictable)
174     cmp    r4d, 0
175     je .loop0
176     cmp    r4d, 2
177     je .loop2
178     cmp    r4d, 4
179     je .loop4
180     cmp    r4d, 6
181     je .loop6
182     cmp    r4d, 8
183     je .loop8
184     cmp    r4d, 10
185     je .loop10
186     cmp    r4d, 12
187     je .loop12
188 SCALARPRODUCT_LOOP 14
189 SCALARPRODUCT_LOOP 12
190 SCALARPRODUCT_LOOP 10
191 SCALARPRODUCT_LOOP 8
192 SCALARPRODUCT_LOOP 6
193 SCALARPRODUCT_LOOP 4
194 SCALARPRODUCT_LOOP 2
195 SCALARPRODUCT_LOOP 0
196 .end:
197     movhlps m0, m6
198     paddd   m6, m0
199     pshuflw m0, m6, 0x4e
200     paddd   m6, m0
201     movd   eax, m6
202     RET
203
204
205
206 ; void add_hfyu_median_prediction_mmx2(uint8_t *dst, const uint8_t *top, const uint8_t *diff, int w, int *left, int *left_top)
207 cglobal add_hfyu_median_prediction_mmx2, 6,6,0, dst, top, diff, w, left, left_top
208     movq    mm0, [topq]
209     movq    mm2, mm0
210     movd    mm4, [left_topq]
211     psllq   mm2, 8
212     movq    mm1, mm0
213     por     mm4, mm2
214     movd    mm3, [leftq]
215     psubb   mm0, mm4 ; t-tl
216     add    dstq, wq
217     add    topq, wq
218     add   diffq, wq
219     neg      wq
220     jmp .skip
221 .loop:
222     movq    mm4, [topq+wq]
223     movq    mm0, mm4
224     psllq   mm4, 8
225     por     mm4, mm1
226     movq    mm1, mm0 ; t
227     psubb   mm0, mm4 ; t-tl
228 .skip:
229     movq    mm2, [diffq+wq]
230 %assign i 0
231 %rep 8
232     movq    mm4, mm0
233     paddb   mm4, mm3 ; t-tl+l
234     movq    mm5, mm3
235     pmaxub  mm3, mm1
236     pminub  mm5, mm1
237     pminub  mm3, mm4
238     pmaxub  mm3, mm5 ; median
239     paddb   mm3, mm2 ; +residual
240 %if i==0
241     movq    mm7, mm3
242     psllq   mm7, 56
243 %else
244     movq    mm6, mm3
245     psrlq   mm7, 8
246     psllq   mm6, 56
247     por     mm7, mm6
248 %endif
249 %if i<7
250     psrlq   mm0, 8
251     psrlq   mm1, 8
252     psrlq   mm2, 8
253 %endif
254 %assign i i+1
255 %endrep
256     movq [dstq+wq], mm7
257     add      wq, 8
258     jl .loop
259     movzx   r2d, byte [dstq-1]
260     mov [leftq], r2d
261     movzx   r2d, byte [topq-1]
262     mov [left_topq], r2d
263     RET
264
265
266 %macro ADD_HFYU_LEFT_LOOP 1 ; %1 = is_aligned
267     add     srcq, wq
268     add     dstq, wq
269     neg     wq
270 %%.loop:
271     mova    m1, [srcq+wq]
272     mova    m2, m1
273     psllw   m1, 8
274     paddb   m1, m2
275     mova    m2, m1
276     pshufb  m1, m3
277     paddb   m1, m2
278     pshufb  m0, m5
279     mova    m2, m1
280     pshufb  m1, m4
281     paddb   m1, m2
282 %if mmsize == 16
283     mova    m2, m1
284     pshufb  m1, m6
285     paddb   m1, m2
286 %endif
287     paddb   m0, m1
288 %if %1
289     mova    [dstq+wq], m0
290 %else
291     movq    [dstq+wq], m0
292     movhps  [dstq+wq+8], m0
293 %endif
294     add     wq, mmsize
295     jl %%.loop
296     mov     eax, mmsize-1
297     sub     eax, wd
298     movd    m1, eax
299     pshufb  m0, m1
300     movd    eax, m0
301     RET
302 %endmacro
303
304 ; int add_hfyu_left_prediction(uint8_t *dst, const uint8_t *src, int w, int left)
305 INIT_MMX
306 cglobal add_hfyu_left_prediction_ssse3, 3,3,7, dst, src, w, left
307 .skip_prologue:
308     mova    m5, [pb_7]
309     mova    m4, [pb_zzzz3333zzzzbbbb]
310     mova    m3, [pb_zz11zz55zz99zzdd]
311     movd    m0, leftm
312     psllq   m0, 56
313     ADD_HFYU_LEFT_LOOP 1
314
315 INIT_XMM
316 cglobal add_hfyu_left_prediction_sse4, 3,3,7, dst, src, w, left
317     mova    m5, [pb_f]
318     mova    m6, [pb_zzzzzzzz77777777]
319     mova    m4, [pb_zzzz3333zzzzbbbb]
320     mova    m3, [pb_zz11zz55zz99zzdd]
321     movd    m0, leftm
322     pslldq  m0, 15
323     test    srcq, 15
324     jnz add_hfyu_left_prediction_ssse3.skip_prologue
325     test    dstq, 15
326     jnz .unaligned
327     ADD_HFYU_LEFT_LOOP 1
328 .unaligned:
329     ADD_HFYU_LEFT_LOOP 0
330
331
332 ; float scalarproduct_float_sse(const float *v1, const float *v2, int len)
333 cglobal scalarproduct_float_sse, 3,3,2, v1, v2, offset
334     neg offsetq
335     shl offsetq, 2
336     sub v1q, offsetq
337     sub v2q, offsetq
338     xorps xmm0, xmm0
339     .loop:
340         movaps   xmm1, [v1q+offsetq]
341         mulps    xmm1, [v2q+offsetq]
342         addps    xmm0, xmm1
343         add      offsetq, 16
344         js       .loop
345     movhlps xmm1, xmm0
346     addps   xmm0, xmm1
347     movss   xmm1, xmm0
348     shufps  xmm0, xmm0, 1
349     addss   xmm0, xmm1
350 %ifndef ARCH_X86_64
351     movd    r0m,  xmm0
352     fld     dword r0m
353 %endif
354     RET
355
356 ; extern void ff_emu_edge_core(uint8_t *buf, const uint8_t *src, x86_reg linesize,
357 ;                              x86_reg start_y, x86_reg end_y, x86_reg block_h,
358 ;                              x86_reg start_x, x86_reg end_x, x86_reg block_w);
359 ;
360 ; The actual function itself is below. It basically wraps a very simple
361 ; w = end_x - start_x
362 ; if (w) {
363 ;   if (w > 22) {
364 ;     jump to the slow loop functions
365 ;   } else {
366 ;     jump to the fast loop functions
367 ;   }
368 ; }
369 ;
370 ; ... and then the same for left/right extend also. See below for loop
371 ; function implementations. Fast are fixed-width, slow is variable-width
372
373 %macro EMU_EDGE_FUNC 1
374 %ifdef ARCH_X86_64
375 %define w_reg r10
376 cglobal emu_edge_core_%1, 6, 7, 1
377     mov        r11, r5          ; save block_h
378 %else
379 %define w_reg r6
380 cglobal emu_edge_core_%1, 2, 7, 0
381     mov         r4, r4m         ; end_y
382     mov         r5, r5m         ; block_h
383 %endif
384
385     ; start with vertical extend (top/bottom) and body pixel copy
386     mov      w_reg, r7m
387     sub      w_reg, r6m         ; w = start_x - end_x
388     sub         r5, r4
389 %ifdef ARCH_X86_64
390     sub         r4, r3
391 %else
392     sub         r4, dword r3m
393 %endif
394     cmp      w_reg, 22
395     jg .slow_v_extend_loop
396 %ifdef ARCH_X86_32
397     mov         r2, r2m         ; linesize
398 %endif
399     sal      w_reg, 7           ; w * 128
400 %ifdef PIC
401     lea        rax, [.emuedge_v_extend_1 - (.emuedge_v_extend_2 - .emuedge_v_extend_1)]
402     add      w_reg, rax
403 %else
404     lea      w_reg, [.emuedge_v_extend_1 - (.emuedge_v_extend_2 - .emuedge_v_extend_1)+w_reg]
405 %endif
406     call     w_reg              ; fast top extend, body copy and bottom extend
407 .v_extend_end:
408
409     ; horizontal extend (left/right)
410     mov      w_reg, r6m         ; start_x
411     sub         r0, w_reg
412 %ifdef ARCH_X86_64
413     mov         r3, r0          ; backup of buf+block_h*linesize
414     mov         r5, r11
415 %else
416     mov        r0m, r0          ; backup of buf+block_h*linesize
417     mov         r5, r5m
418 %endif
419     test     w_reg, w_reg
420     jz .right_extend
421     cmp      w_reg, 22
422     jg .slow_left_extend_loop
423     mov         r1, w_reg
424     dec      w_reg
425     ; FIXME we can do a if size == 1 here if that makes any speed difference, test me
426     sar      w_reg, 1
427     sal      w_reg, 6
428     ; r0=buf+block_h*linesize,r10(64)/r6(32)=start_x offset for funcs
429     ; r6(rax)/r3(ebx)=val,r2=linesize,r1=start_x,r5=block_h
430 %ifdef PIC
431     lea        rax, [.emuedge_extend_left_2]
432     add      w_reg, rax
433 %else
434     lea      w_reg, [.emuedge_extend_left_2+w_reg]
435 %endif
436     call     w_reg
437
438     ; now r3(64)/r0(32)=buf,r2=linesize,r11/r5=block_h,r6/r3=val, r10/r6=end_x, r1=block_w
439 .right_extend:
440 %ifdef ARCH_X86_32
441     mov         r0, r0m
442     mov         r5, r5m
443 %endif
444     mov      w_reg, r7m         ; end_x
445     mov         r1, r8m         ; block_w
446     mov         r4, r1
447     sub         r1, w_reg
448     jz .h_extend_end            ; if (end_x == block_w) goto h_extend_end
449     cmp         r1, 22
450     jg .slow_right_extend_loop
451     dec         r1
452     ; FIXME we can do a if size == 1 here if that makes any speed difference, test me
453     sar         r1, 1
454     sal         r1, 6
455 %ifdef PIC
456     lea        rax, [.emuedge_extend_right_2]
457     add         r1, rax
458 %else
459     lea         r1, [.emuedge_extend_right_2+r1]
460 %endif
461     call        r1
462 .h_extend_end:
463     RET
464
465 %ifdef ARCH_X86_64
466 %define vall  al
467 %define valh  ah
468 %define valw  ax
469 %define valw2 r10w
470 %define valw3 r3w
471 %ifdef WIN64
472 %define valw4 r4w
473 %else ; unix64
474 %define valw4 r3w
475 %endif
476 %define vald eax
477 %else
478 %define vall  bl
479 %define valh  bh
480 %define valw  bx
481 %define valw2 r6w
482 %define valw3 valw2
483 %define valw4 valw3
484 %define vald ebx
485 %define stack_offset 0x14
486 %endif
487
488 %endmacro
489
490 ; macro to read/write a horizontal number of pixels (%2) to/from registers
491 ; on x86-64, - fills xmm0-15 for consecutive sets of 16 pixels
492 ;            - if (%2 & 15 == 8) fills the last 8 bytes into rax
493 ;            - else if (%2 & 8)  fills 8 bytes into mm0
494 ;            - if (%2 & 7 == 4)  fills the last 4 bytes into rax
495 ;            - else if (%2 & 4)  fills 4 bytes into mm0-1
496 ;            - if (%2 & 3 == 3)  fills 2 bytes into r10/r3, and 1 into eax
497 ;              (note that we're using r3 for body/bottom because it's a shorter
498 ;               opcode, and then the loop fits in 128 bytes)
499 ;            - else              fills remaining bytes into rax
500 ; on x86-32, - fills mm0-7 for consecutive sets of 8 pixels
501 ;            - if (%2 & 7 == 4)  fills 4 bytes into ebx
502 ;            - else if (%2 & 4)  fills 4 bytes into mm0-7
503 ;            - if (%2 & 3 == 3)  fills 2 bytes into r6, and 1 into ebx
504 ;            - else              fills remaining bytes into ebx
505 ; writing data out is in the same way
506 %macro READ_NUM_BYTES 3
507 %assign %%src_off 0 ; offset in source buffer
508 %assign %%smidx   0 ; mmx register idx
509 %assign %%sxidx   0 ; xmm register idx
510
511 %ifnidn %3, mmx
512 %rep %2/16
513     movdqu xmm %+ %%sxidx, [r1+%%src_off]
514 %assign %%src_off %%src_off+16
515 %assign %%sxidx   %%sxidx+1
516 %endrep ; %2/16
517 %endif ; !mmx
518
519 %ifdef ARCH_X86_64
520 %if (%2-%%src_off) == 8
521     mov           rax, [r1+%%src_off]
522 %assign %%src_off %%src_off+8
523 %endif ; (%2-%%src_off) == 8
524 %endif ; x86-64
525
526 %rep (%2-%%src_off)/8
527     movq    mm %+ %%smidx, [r1+%%src_off]
528 %assign %%src_off %%src_off+8
529 %assign %%smidx   %%smidx+1
530 %endrep ; (%2-%%dst_off)/8
531
532 %if (%2-%%src_off) == 4
533     mov          vald, [r1+%%src_off]
534 %elif (%2-%%src_off) & 4
535     movd    mm %+ %%smidx, [r1+%%src_off]
536 %assign %%src_off %%src_off+4
537 %endif ; (%2-%%src_off) ==/& 4
538
539 %if (%2-%%src_off) == 1
540     mov          vall, [r1+%%src_off]
541 %elif (%2-%%src_off) == 2
542     mov          valw, [r1+%%src_off]
543 %elif (%2-%%src_off) == 3
544 %ifidn %1, top
545     mov         valw2, [r1+%%src_off]
546 %elifidn %1, body
547     mov         valw3, [r1+%%src_off]
548 %elifidn %1, bottom
549     mov         valw4, [r1+%%src_off]
550 %endif ; %1 ==/!= top
551     mov          vall, [r1+%%src_off+2]
552 %endif ; (%2-%%src_off) == 1/2/3
553 %endmacro ; READ_NUM_BYTES
554
555 %macro WRITE_NUM_BYTES 3
556 %assign %%dst_off 0 ; offset in destination buffer
557 %assign %%dmidx   0 ; mmx register idx
558 %assign %%dxidx   0 ; xmm register idx
559
560 %ifnidn %3, mmx
561 %rep %2/16
562     movdqu [r0+%%dst_off], xmm %+ %%dxidx
563 %assign %%dst_off %%dst_off+16
564 %assign %%dxidx   %%dxidx+1
565 %endrep ; %2/16
566 %endif
567
568 %ifdef ARCH_X86_64
569 %if (%2-%%dst_off) == 8
570     mov    [r0+%%dst_off], rax
571 %assign %%dst_off %%dst_off+8
572 %endif ; (%2-%%dst_off) == 8
573 %endif ; x86-64
574
575 %rep (%2-%%dst_off)/8
576     movq   [r0+%%dst_off], mm %+ %%dmidx
577 %assign %%dst_off %%dst_off+8
578 %assign %%dmidx   %%dmidx+1
579 %endrep ; (%2-%%dst_off)/8
580
581 %if (%2-%%dst_off) == 4
582     mov    [r0+%%dst_off], vald
583 %elif (%2-%%dst_off) & 4
584     movd   [r0+%%dst_off], mm %+ %%dmidx
585 %assign %%dst_off %%dst_off+4
586 %endif ; (%2-%%dst_off) ==/& 4
587
588 %if (%2-%%dst_off) == 1
589     mov    [r0+%%dst_off], vall
590 %elif (%2-%%dst_off) == 2
591     mov    [r0+%%dst_off], valw
592 %elif (%2-%%dst_off) == 3
593 %ifidn %1, top
594     mov    [r0+%%dst_off], valw2
595 %elifidn %1, body
596     mov    [r0+%%dst_off], valw3
597 %elifidn %1, bottom
598     mov    [r0+%%dst_off], valw4
599 %endif ; %1 ==/!= top
600     mov  [r0+%%dst_off+2], vall
601 %endif ; (%2-%%dst_off) == 1/2/3
602 %endmacro ; WRITE_NUM_BYTES
603
604 ; vertical top/bottom extend and body copy fast loops
605 ; these are function pointers to set-width line copy functions, i.e.
606 ; they read a fixed number of pixels into set registers, and write
607 ; those out into the destination buffer
608 ; r0=buf,r1=src,r2=linesize,r3(64)/r3m(32)=start_x,r4=end_y,r5=block_h
609 ; r6(eax/64)/r3(ebx/32)=val_reg
610 %macro VERTICAL_EXTEND 1
611 %assign %%n 1
612 %rep 22
613 ALIGN 128
614 .emuedge_v_extend_ %+ %%n:
615     ; extend pixels above body
616 %ifdef ARCH_X86_64
617     test           r3 , r3                   ; if (!start_y)
618     jz .emuedge_copy_body_ %+ %%n %+ _loop   ;   goto body
619 %else ; ARCH_X86_32
620     cmp      dword r3m, 0
621     je .emuedge_copy_body_ %+ %%n %+ _loop
622 %endif ; ARCH_X86_64/32
623     READ_NUM_BYTES  top,    %%n, %1          ; read bytes
624 .emuedge_extend_top_ %+ %%n %+ _loop:        ; do {
625     WRITE_NUM_BYTES top,    %%n, %1          ;   write bytes
626     add            r0 , r2                   ;   dst += linesize
627 %ifdef ARCH_X86_64
628     dec            r3d
629 %else ; ARCH_X86_32
630     dec      dword r3m
631 %endif ; ARCH_X86_64/32
632     jnz .emuedge_extend_top_ %+ %%n %+ _loop ; } while (--start_y)
633
634     ; copy body pixels
635 .emuedge_copy_body_ %+ %%n %+ _loop:         ; do {
636     READ_NUM_BYTES  body,   %%n, %1          ;   read bytes
637     WRITE_NUM_BYTES body,   %%n, %1          ;   write bytes
638     add            r0 , r2                   ;   dst += linesize
639     add            r1 , r2                   ;   src += linesize
640     dec            r4d
641     jnz .emuedge_copy_body_ %+ %%n %+ _loop  ; } while (--end_y)
642
643     ; copy bottom pixels
644     test           r5 , r5                   ; if (!block_h)
645     jz .emuedge_v_extend_end_ %+ %%n         ;   goto end
646     sub            r1 , r2                   ; src -= linesize
647     READ_NUM_BYTES  bottom, %%n, %1          ; read bytes
648 .emuedge_extend_bottom_ %+ %%n %+ _loop:     ; do {
649     WRITE_NUM_BYTES bottom, %%n, %1          ;   write bytes
650     add            r0 , r2                   ;   dst += linesize
651     dec            r5d
652     jnz .emuedge_extend_bottom_ %+ %%n %+ _loop ; } while (--block_h)
653
654 .emuedge_v_extend_end_ %+ %%n:
655 %ifdef ARCH_X86_64
656     ret
657 %else ; ARCH_X86_32
658     rep ret
659 %endif ; ARCH_X86_64/32
660 %assign %%n %%n+1
661 %endrep
662 %endmacro VERTICAL_EXTEND
663
664 ; left/right (horizontal) fast extend functions
665 ; these are essentially identical to the vertical extend ones above,
666 ; just left/right separated because number of pixels to extend is
667 ; obviously not the same on both sides.
668 ; for reading, pixels are placed in eax (x86-64) or ebx (x86-64) in the
669 ; lowest two bytes of the register (so val*0x0101), and are splatted
670 ; into each byte of mm0 as well if n_pixels >= 8
671
672 %macro READ_V_PIXEL 3
673     mov        vall, %2
674     mov        valh, vall
675 %if %1 >= 8
676     movd        mm0, vald
677 %ifidn %3, mmx
678     punpcklwd   mm0, mm0
679     punpckldq   mm0, mm0
680 %else ; !mmx
681     pshufw      mm0, mm0, 0
682 %endif ; mmx
683 %endif ; %1 >= 8
684 %endmacro
685
686 %macro WRITE_V_PIXEL 2
687 %assign %%dst_off 0
688 %rep %1/8
689     movq [%2+%%dst_off], mm0
690 %assign %%dst_off %%dst_off+8
691 %endrep
692 %if %1 & 4
693 %if %1 >= 8
694     movd [%2+%%dst_off], mm0
695 %else ; %1 < 8
696     mov  [%2+%%dst_off]  , valw
697     mov  [%2+%%dst_off+2], valw
698 %endif ; %1 >=/< 8
699 %assign %%dst_off %%dst_off+4
700 %endif ; %1 & 4
701 %if %1&2
702     mov  [%2+%%dst_off], valw
703 %endif ; %1 & 2
704 %endmacro
705
706 ; r0=buf+block_h*linesize, r1=start_x, r2=linesize, r5=block_h, r6/r3=val
707 %macro LEFT_EXTEND 1
708 %assign %%n 2
709 %rep 11
710 ALIGN 64
711 .emuedge_extend_left_ %+ %%n:          ; do {
712     sub         r0, r2                 ;   dst -= linesize
713     READ_V_PIXEL  %%n, [r0+r1], %1     ;   read pixels
714     WRITE_V_PIXEL %%n, r0              ;   write pixels
715     dec         r5
716     jnz .emuedge_extend_left_ %+ %%n   ; } while (--block_h)
717 %ifdef ARCH_X86_64
718     ret
719 %else ; ARCH_X86_32
720     rep ret
721 %endif ; ARCH_X86_64/32
722 %assign %%n %%n+2
723 %endrep
724 %endmacro ; LEFT_EXTEND
725
726 ; r3/r0=buf+block_h*linesize, r2=linesize, r11/r5=block_h, r0/r6=end_x, r6/r3=val
727 %macro RIGHT_EXTEND 1
728 %assign %%n 2
729 %rep 11
730 ALIGN 64
731 .emuedge_extend_right_ %+ %%n:          ; do {
732 %ifdef ARCH_X86_64
733     sub        r3, r2                   ;   dst -= linesize
734     READ_V_PIXEL  %%n, [r3+w_reg-1], %1 ;   read pixels
735     WRITE_V_PIXEL %%n, r3+r4-%%n        ;   write pixels
736     dec       r11
737 %else ; ARCH_X86_32
738     sub        r0, r2                   ;   dst -= linesize
739     READ_V_PIXEL  %%n, [r0+w_reg-1], %1 ;   read pixels
740     WRITE_V_PIXEL %%n, r0+r4-%%n        ;   write pixels
741     dec     r5
742 %endif ; ARCH_X86_64/32
743     jnz .emuedge_extend_right_ %+ %%n   ; } while (--block_h)
744 %ifdef ARCH_X86_64
745     ret
746 %else ; ARCH_X86_32
747     rep ret
748 %endif ; ARCH_X86_64/32
749 %assign %%n %%n+2
750 %endrep
751
752 %ifdef ARCH_X86_32
753 %define stack_offset 0x10
754 %endif
755 %endmacro ; RIGHT_EXTEND
756
757 ; below follow the "slow" copy/extend functions, these act on a non-fixed
758 ; width specified in a register, and run a loop to copy the full amount
759 ; of bytes. They are optimized for copying of large amounts of pixels per
760 ; line, so they unconditionally splat data into mm registers to copy 8
761 ; bytes per loop iteration. It could be considered to use xmm for x86-64
762 ; also, but I haven't optimized this as much (i.e. FIXME)
763 %macro V_COPY_NPX 4-5
764 %if %0 == 4
765     test     w_reg, %4
766     jz .%1_skip_%4_px
767 %else ; %0 == 5
768 .%1_%4_px_loop:
769 %endif
770     %3          %2, [r1+cnt_reg]
771     %3 [r0+cnt_reg], %2
772     add    cnt_reg, %4
773 %if %0 == 5
774     sub      w_reg, %4
775     test     w_reg, %5
776     jnz .%1_%4_px_loop
777 %endif
778 .%1_skip_%4_px:
779 %endmacro
780
781 %macro V_COPY_ROW 3
782 %ifidn %1, bottom
783     sub         r1, linesize
784 %endif
785 .%1_copy_loop:
786     xor    cnt_reg, cnt_reg
787 %ifidn %3, mmx
788 %define linesize r2m
789     V_COPY_NPX %1,  mm0, movq,    8, 0xFFFFFFF8
790 %else ; !mmx
791     V_COPY_NPX %1, xmm0, movdqu, 16, 0xFFFFFFF0
792 %ifdef ARCH_X86_64
793 %define linesize r2
794     V_COPY_NPX %1, rax , mov,     8
795 %else ; ARCH_X86_32
796 %define linesize r2m
797     V_COPY_NPX %1,  mm0, movq,    8
798 %endif ; ARCH_X86_64/32
799 %endif ; mmx
800     V_COPY_NPX %1, vald, mov,     4
801     V_COPY_NPX %1, valw, mov,     2
802     V_COPY_NPX %1, vall, mov,     1
803     mov      w_reg, cnt_reg
804 %ifidn %1, body
805     add         r1, linesize
806 %endif
807     add         r0, linesize
808     dec         %2
809     jnz .%1_copy_loop
810 %endmacro
811
812 %macro SLOW_V_EXTEND 1
813 .slow_v_extend_loop:
814 ; r0=buf,r1=src,r2(64)/r2m(32)=linesize,r3(64)/r3m(32)=start_x,r4=end_y,r5=block_h
815 ; r11(64)/r3(later-64)/r2(32)=cnt_reg,r6(64)/r3(32)=val_reg,r10(64)/r6(32)=w=end_x-start_x
816 %ifdef ARCH_X86_64
817     push       r11              ; save old value of block_h
818     test        r3, r3
819 %define cnt_reg r11
820     jz .do_body_copy            ; if (!start_y) goto do_body_copy
821     V_COPY_ROW top, r3, %1
822 %else
823     cmp  dword r3m, 0
824 %define cnt_reg r2
825     je .do_body_copy            ; if (!start_y) goto do_body_copy
826     V_COPY_ROW top, dword r3m, %1
827 %endif
828
829 .do_body_copy:
830     V_COPY_ROW body, r4, %1
831
832 %ifdef ARCH_X86_64
833     pop        r11              ; restore old value of block_h
834 %define cnt_reg r3
835 %endif
836     test        r5, r5
837 %ifdef ARCH_X86_64
838     jz .v_extend_end
839 %else
840     jz .skip_bottom_extend
841 %endif
842     V_COPY_ROW bottom, r5, %1
843 %ifdef ARCH_X86_32
844 .skip_bottom_extend:
845     mov         r2, r2m
846 %endif
847     jmp .v_extend_end
848 %endmacro
849
850 %macro SLOW_LEFT_EXTEND 1
851 .slow_left_extend_loop:
852 ; r0=buf+block_h*linesize,r2=linesize,r6(64)/r3(32)=val,r5=block_h,r4=cntr,r10/r6=start_x
853     mov         r4, 8
854     sub         r0, linesize
855     READ_V_PIXEL 8, [r0+w_reg], %1
856 .left_extend_8px_loop:
857     movq [r0+r4-8], mm0
858     add         r4, 8
859     cmp         r4, w_reg
860     jle .left_extend_8px_loop
861     sub         r4, 8
862     cmp         r4, w_reg
863     jge .left_extend_loop_end
864 .left_extend_2px_loop:
865     mov    [r0+r4], valw
866     add         r4, 2
867     cmp         r4, w_reg
868     jl .left_extend_2px_loop
869 .left_extend_loop_end:
870     dec         r5
871     jnz .slow_left_extend_loop
872 %ifdef ARCH_X86_32
873     mov         r2, r2m
874 %endif
875     jmp .right_extend
876 %endmacro
877
878 %macro SLOW_RIGHT_EXTEND 1
879 .slow_right_extend_loop:
880 ; r3(64)/r0(32)=buf+block_h*linesize,r2=linesize,r4=block_w,r11(64)/r5(32)=block_h,
881 ; r10(64)/r6(32)=end_x,r6/r3=val,r1=cntr
882 %ifdef ARCH_X86_64
883 %define buf_reg r3
884 %define bh_reg r11
885 %else
886 %define buf_reg r0
887 %define bh_reg r5
888 %endif
889     lea         r1, [r4-8]
890     sub    buf_reg, linesize
891     READ_V_PIXEL 8, [buf_reg+w_reg-1], %1
892 .right_extend_8px_loop:
893     movq [buf_reg+r1], mm0
894     sub         r1, 8
895     cmp         r1, w_reg
896     jge .right_extend_8px_loop
897     add         r1, 8
898     cmp         r1, w_reg
899     je .right_extend_loop_end
900 .right_extend_2px_loop:
901     sub         r1, 2
902     mov [buf_reg+r1], valw
903     cmp         r1, w_reg
904     jg .right_extend_2px_loop
905 .right_extend_loop_end:
906     dec         bh_reg
907     jnz .slow_right_extend_loop
908     jmp .h_extend_end
909 %endmacro
910
911 %macro emu_edge 1
912 EMU_EDGE_FUNC     %1
913 VERTICAL_EXTEND   %1
914 LEFT_EXTEND       %1
915 RIGHT_EXTEND      %1
916 SLOW_V_EXTEND     %1
917 SLOW_LEFT_EXTEND  %1
918 SLOW_RIGHT_EXTEND %1
919 %endmacro
920
921 emu_edge sse
922 %ifdef ARCH_X86_32
923 emu_edge mmx
924 %endif