64c067538a7cc748fac400ec48f8b1a181274981
[ffmpeg.git] / libavfilter / x86 / vf_gblur.asm
1 ;*****************************************************************************
2 ;* x86-optimized functions for gblur filter
3 ;*
4 ;* This file is part of FFmpeg.
5 ;*
6 ;* FFmpeg is free software; you can redistribute it and/or
7 ;* modify it under the terms of the GNU Lesser General Public
8 ;* License as published by the Free Software Foundation; either
9 ;* version 2.1 of the License, or (at your option) any later version.
10 ;*
11 ;* FFmpeg is distributed in the hope that it will be useful,
12 ;* but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ;* Lesser General Public License for more details.
15 ;*
16 ;* You should have received a copy of the GNU Lesser General Public
17 ;* License along with FFmpeg; if not, write to the Free Software
18 ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 ;******************************************************************************
20
21 %include "libavutil/x86/x86util.asm"
22
23 SECTION .data
24
25 gblur_transpose_16x16_indices1: dq 2, 3, 0, 1, 6, 7, 4, 5
26 gblur_transpose_16x16_indices2: dq 1, 0, 3, 2, 5, 4, 7, 6
27 gblur_transpose_16x16_indices3: dd 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14
28 gblur_transpose_16x16_mask: dw 0xcc, 0x33, 0xaa, 0x55, 0xaaaa, 0x5555
29 gblur_vindex_width: dd 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
30
31 SECTION .text
32
33 %xdefine AVX2_MMSIZE   32
34 %xdefine AVX512_MMSIZE 64
35
36 %macro MOVSXDIFNIDN 1-*
37     %rep %0
38         movsxdifnidn %1q, %1d
39         %rotate 1
40     %endrep
41 %endmacro
42
43 %macro KXNOR 2-*
44 %if mmsize == AVX512_MMSIZE
45     kxnorw %2, %2, %2
46 %else
47     %if %0 == 3
48         mov %3, -1
49     %else
50         vpcmpeqd %1, %1, %1
51     %endif
52 %endif
53 %endmacro
54
55 %macro KMOVW 2-4
56 %if mmsize == AVX2_MMSIZE && %0 == 4
57     mova %1, %2
58 %elif mmsize == AVX512_MMSIZE
59     %if %0 == 4
60         %rotate 2
61     %endif
62     kmovw %1, %2
63 %endif
64 %endmacro
65
66 %macro PUSH_MASK 5
67 %if mmsize == AVX2_MMSIZE
68     %assign %%n mmsize/4
69     %assign %%i 0
70     %rep %%n
71         mov %4, %3
72         and %4, 1
73         neg %4
74         mov dword [%5 + %%i*4], %4
75         sar %3, 1
76         %assign %%i %%i+1
77     %endrep
78     movu %1, [%5]
79 %else
80     kmovd %2, %3
81 %endif
82 %endmacro
83
84 %macro VMASKMOVPS 4
85 %if mmsize == AVX2_MMSIZE
86     vpmaskmovd %1, %3, %2
87 %else
88     kmovw k7, %4
89     vmovups %1{k7}, %2
90 %endif
91 %endmacro
92
93 %macro VGATHERDPS 4
94 %if mmsize == AVX2_MMSIZE
95     vgatherdps %1, %2, %3
96 %else
97     vgatherdps %1{%4}, %2
98 %endif
99 %endmacro
100
101 %macro VSCATTERDPS128 7
102     %rep 4
103         mov %7, %6
104         and %7, 1
105         cmp %7, 0
106         je %%end_scatter
107         movss [%2 + %3*%4], xm%1
108         vpshufd m%1, m%1, 0x39
109         add %3, %5
110         sar %6, 1
111     %endrep
112     %%end_scatter:
113 %endmacro
114
115 ; %1=register index
116 ; %2=base address   %3=vindex
117 ; %4=scale          %5=width
118 ; %6=mask           %7=tmp
119 ; m15=reserved
120 %macro VSCATTERDPS256 7
121     mova m15, m%1
122     xor %3, %3
123     VSCATTERDPS128 15, %2, %3, %4, %5, %6, %7
124     vextractf128 xm15, m%1, 1
125     VSCATTERDPS128 15, %2, %3, %4, %5, %6, %7
126 %endmacro
127
128 ; %1=base address  %2=avx2 vindex
129 ; %3=avx512 vindex %4=avx2 mask
130 ; %5=avx512 mask   %6=register index
131 ; %7=width         %8-*=tmp
132 %macro VSCATTERDPS 8-*
133 %if mmsize == AVX2_MMSIZE
134     %if %0 == 9
135         mov  %9, %4
136         VSCATTERDPS256 %6, %1, %2, 4, %7, %9, %8
137     %else
138         VSCATTERDPS256 %6, %1, %2, 4, %7, %4, %8
139     %endif
140 %else
141     vscatterdps [%1 + %3*4]{%5}, m%6
142 %endif
143 %endmacro
144
145 %macro INIT_WORD_MASK 1-*
146     %assign %%i 0
147     %rep %0
148         kmovw %1, [gblur_transpose_16x16_mask + %%i * 2]
149         %assign %%i %%i+1
150         %rotate 1
151     %endrep
152 %endmacro
153
154 %macro INIT_INDICES 1-*
155     %assign %%i 1
156     %rep %0
157         movu %1, [gblur_transpose_16x16_indices %+ %%i]
158         %assign %%i %%i+1
159         %rotate 1
160     %endrep
161 %endmacro
162
163 %assign stack_offset 0
164 %macro PUSH_MM 1
165 %if mmsize == AVX2_MMSIZE
166     movu [rsp + stack_offset], %1
167     %assign stack_offset stack_offset+mmsize
168 %endif
169 %endmacro
170
171 %macro POP_MM 1
172 %if mmsize == AVX2_MMSIZE
173     %assign stack_offset stack_offset-mmsize
174     movu %1, [rsp + stack_offset]
175 %endif
176 %endmacro
177
178 %macro READ_LOCAL_BUFFER 1
179     %if mmsize == AVX512_MMSIZE
180         %assign %%i 19
181     %else
182         %assign %%i 9
183     %endif
184     %assign  %%j %%i-1
185     %assign  %%k %1-1
186     %xdefine %%m m %+ %%i
187     mova %%m, m3
188     FMULADD_PS %%m, %%m, m0, [localbufq + %%k * mmsize], %%m
189     %assign %%k %%k-1
190     %rep %1-1
191         %xdefine %%m m %+ %%j
192         mova %%m, m %+ %%i
193         FMULADD_PS %%m, %%m, m0, [localbufq + %%k * mmsize], %%m
194         %assign %%i %%i-1
195         %assign %%j %%j-1
196         %assign %%k %%k-1
197     %endrep
198     %if mmsize == AVX512_MMSIZE
199         mova m3, m %+ %%i
200     %endif
201 %endmacro
202
203 %macro FMADD_WRITE 4
204     FMULADD_PS %1, %1, %2, %3, %1
205     mova %4, %1
206 %endmacro
207
208 %macro WRITE_LOCAL_BUFFER_INTERNAL 8-16
209     %assign %%i 0
210     %rep %0
211         FMADD_WRITE m3, m0, m %+ %1,  [localbufq + %%i * mmsize]
212         %assign %%i %%i+1
213         %rotate 1
214     %endrep
215 %endmacro
216
217 %macro GATHERPS 1
218     %if mmsize == AVX512_MMSIZE
219         %assign %%i 4
220     %else
221         %assign %%i 2
222     %endif
223     movu m %+ %%i, [ptrq]
224     mov strideq, widthq
225     %assign %%i %%i+1
226     %rep %1-2
227         movu m %+ %%i, [ptrq + strideq*4]
228         add strideq, widthq
229         %assign %%i %%i+1
230     %endrep
231     movu m %+ %%i, [ptrq + strideq*4]
232 %endmacro
233
234 %macro SCATTERPS_INTERNAL 8-16
235     movu [ptrq + strideq*0], m %+ %1
236     mov strideq, widthq
237     %rotate 1
238     %rep %0-2
239         movu [ptrq + strideq*4], m %+ %1
240         add strideq, widthq
241         %rotate 1
242     %endrep
243     movu [ptrq + strideq*4], m %+ %1
244 %endmacro
245
246 %macro BATCH_INSERT64X4 4-*
247     %assign %%imm8 %1
248     %rotate 1
249     %rep (%0-1)/3
250         vinserti64x4 m%1, m%2, ym%3, %%imm8
251         %rotate 3
252     %endrep
253 %endmacro
254
255 %macro BATCH_EXTRACT_INSERT 2-*
256     %assign %%imm8 %1
257     %rotate 1
258     %rep (%0-1)/2
259         vextractf64x4 ym%1, m%1,       %%imm8
260         vextractf64x4 ym%2, m%2,       %%imm8
261         vinserti64x4   m%1, m%1, ym%2, %%imm8
262         %rotate 2
263     %endrep
264 %endmacro
265
266 %macro BATCH_MOVE 2-*
267     %rep %0/2
268         mova m%1, m%2
269         %rotate 2
270     %endrep
271 %endmacro
272
273 %macro BATCH_PERMUTE 3-*
274     %xdefine %%decorator %1
275     %xdefine %%mask      %2
276     %assign  %%index     %3
277     %rotate 3
278     %rep (%0-3)/2
279         vperm %+ %%decorator m%1{%%mask}, m %+ %%index, m%2
280         %rotate 2
281     %endrep
282 %endmacro
283
284 ; input : m3-m19
285 ; output: m8 m5 m9 m15 m16 m7 m17 m27 m24 m21 m25 m19 m12 m23 m13 m11
286 %macro TRANSPOSE_16X16_AVX512 0
287     BATCH_INSERT64X4 0x1, 20,4,12, 21,5,13,  22,6,14,  23,7,15
288     BATCH_INSERT64X4 0x1, 24,8,16, 25,9,17, 26,10,18, 27,11,19
289
290     BATCH_EXTRACT_INSERT 0x1, 4,12, 5,13,  6,14,  7,15
291     BATCH_EXTRACT_INSERT 0x1, 8,16, 9,17, 10,18, 11,19
292
293     BATCH_MOVE 12,20, 13,21, 14,22, 15,23
294     BATCH_PERMUTE q, k6, 28, 12,24, 13,25, 14,26, 15,27
295     BATCH_PERMUTE q, k5, 28, 24,20, 25,21, 26,22, 27,23
296
297     BATCH_MOVE 16,4, 17,5, 18,6, 19,7
298     BATCH_PERMUTE q, k6, 28, 16,8, 17,9, 18,10, 19,11
299     BATCH_PERMUTE q, k5, 28,  8,4,  9,5,  10,6,  11,7
300
301     BATCH_MOVE  4,12,  5,13, 6,24, 7,25
302     BATCH_MOVE 20,16, 21,17, 22,8, 23,9
303
304     BATCH_PERMUTE q, k4, 29,  4,14,  5,15,  6,26,  7,27
305     BATCH_PERMUTE q, k3, 29, 14,12, 15,13, 26,24, 27,25
306     BATCH_PERMUTE q, k4, 29, 20,18, 21,19, 22,10, 23,11
307     BATCH_PERMUTE q, k3, 29, 18,16, 19,17,  10,8,  11,9
308
309     BATCH_MOVE   8,4,  9,14,  16,6, 17,26
310     BATCH_MOVE 24,20, 25,18, 12,22, 13,10
311
312     BATCH_PERMUTE d, k2, 30,   8,5,  9,15,  16,7, 17,27
313     BATCH_PERMUTE d, k1, 30,   5,4, 15,14,   7,6, 27,26
314     BATCH_PERMUTE d, k2, 30, 24,21, 25,19, 12,23, 13,11
315     BATCH_PERMUTE d, k1, 30, 21,20, 19,18, 23,22, 11,10
316 %endmacro
317
318 %macro INSERT_UNPACK 8
319     vinsertf128 m%5, m%1, xm%3, 0x1
320     vinsertf128 m%6, m%2, xm%4, 0x1
321     vunpcklpd   m%7, m%5,  m%6
322     vunpckhpd   m%8, m%5,  m%6
323 %endmacro
324
325 %macro SHUFFLE 4
326     vshufps m%3, m%1, m%2, 0x88
327     vshufps m%4, m%1, m%2, 0xDD
328     mova    m%1, m%3
329     mova    m%2, m%4
330 %endmacro
331
332 %macro EXTRACT_INSERT_UNPACK 6
333     vextractf128 xm%1, m%1,       0x1
334     vextractf128 xm%2, m%2,       0x1
335     vinsertf128   m%3, m%3, xm%1, 0x0
336     vinsertf128   m%4, m%4, xm%2, 0x0
337     vunpcklpd     m%5, m%3, m%4
338     vunpckhpd     m%6, m%3, m%4
339 %endmacro
340
341 ; Transpose 8x8 AVX2
342 ; Limit the number ym# register to 16 for compatibility
343 ; Used up registers instead of using stack memory
344 ; Input:  m2-m9
345 ; Output: m12, m14, m13, m15, m8, m10, m9, m11
346 %macro TRANSPOSE_8X8_AVX2 0
347     INSERT_UNPACK 2, 3, 6, 7, 10, 11, 12, 13
348     INSERT_UNPACK 4, 5, 8, 9, 10, 11, 14, 15
349
350     SHUFFLE 12, 14, 10, 11
351     SHUFFLE 13, 15, 10, 11
352
353     EXTRACT_INSERT_UNPACK 4, 5, 8, 9, 10, 11
354     EXTRACT_INSERT_UNPACK 2, 3, 6, 7,  8, 9
355
356     SHUFFLE 8, 10, 6, 7
357     SHUFFLE 9, 11, 6, 7
358 %endmacro
359
360 %macro TRANSPOSE 0
361     %if cpuflag(avx512)
362         TRANSPOSE_16X16_AVX512
363     %elif cpuflag(avx2)
364         TRANSPOSE_8X8_AVX2
365     %endif
366 %endmacro
367
368 %macro WRITE_LOCAL_BUFFER 0
369     %if cpuflag(avx512)
370         WRITE_LOCAL_BUFFER_INTERNAL 8, 5, 9, 15, 16, 7, 17, 27, \
371                                     24, 21, 25, 19, 12, 23, 13, 11
372     %elif cpuflag(avx2)
373         WRITE_LOCAL_BUFFER_INTERNAL 12, 14, 13, 15, 8, 10, 9, 11
374     %endif
375 %endmacro
376
377 %macro SCATTERPS 0
378     %if cpuflag(avx512)
379         SCATTERPS_INTERNAL 8, 5, 9, 15, 16, 7, 17, 27, \
380                            24, 21, 25, 19, 12, 23, 13, 11
381     %elif cpuflag(avx2)
382         SCATTERPS_INTERNAL 12, 14, 13, 15, 8, 10, 9, 11
383     %endif
384 %endmacro
385
386 %macro OPTIMIZED_LOOP_STEP 0
387     lea stepd, [stepsd - 1]
388     cmp stepd, 0
389     jle %%bscale_scalar
390 %%loop_step:
391     sub localbufq, mmsize
392     mulps m3, m1
393     movu [localbufq], m3
394
395     ; Filter leftwards
396     lea xq, [widthq - 1]
397     %%loop_step_x_back:
398         sub localbufq, mmsize
399         FMULADD_PS m3, m3, m0, [localbufq], m3
400         movu [localbufq], m3
401
402         dec xq
403         cmp xq, 0
404         jg %%loop_step_x_back
405
406     ; Filter rightwards
407     mulps m3, m1
408     movu [localbufq], m3
409     add localbufq, mmsize
410
411     lea xq, [widthq - 1]
412     %%loop_step_x:
413         FMULADD_PS m3, m3, m0, [localbufq], m3
414         movu [localbufq], m3
415         add localbufq, mmsize
416
417         dec xq
418         cmp xq, 0
419         jg %%loop_step_x
420
421     dec stepd
422     cmp stepd, 0
423     jg %%loop_step
424
425 %%bscale_scalar:
426 %endmacro
427
428 ;***************************************************************************
429 ; void ff_horiz_slice(float *ptr, int width, int height, int steps,
430 ;                          float nu, float bscale)
431 ;***************************************************************************
432 %macro HORIZ_SLICE 0
433 %if UNIX64
434 %if cpuflag(avx512) || cpuflag(avx2)
435 cglobal horiz_slice, 5, 12, mmnum, 0-mmsize*4, buffer, width, height, steps, \
436                                           localbuf, x, y, step, stride, remain, ptr, mask
437 %else
438 cglobal horiz_slice, 4, 9, 9, ptr, width, height, steps, x, y, step, stride, remain
439 %endif
440 %else
441 %if cpuflag(avx512) || cpuflag(avx2)
442 cglobal horiz_slice, 5, 12, mmnum, 0-mmsize*4, buffer, width, height, steps, nu, bscale, \
443                                           localbuf, x, y, step, stride, remain, ptr, mask
444 %else
445 cglobal horiz_slice, 4, 9, 9, ptr, width, height, steps, nu, bscale, x, y, step, stride, remain
446 %endif
447 %endif
448 %if cpuflag(avx512) || cpuflag(avx2)
449 %assign rows mmsize/4
450 %assign cols mmsize/4
451 %if WIN64
452     VBROADCASTSS    m0, num ; nu
453     VBROADCASTSS    m1, bscalem ; bscale
454
455     mov nuq, localbufm
456     DEFINE_ARGS buffer, width, height, steps, \
457                 localbuf, x, y, step, stride, remain, ptr, mask
458 %else
459     VBROADCASTSS    m0, xmm0 ; nu
460     VBROADCASTSS    m1, xmm1 ; bscale
461 %endif
462
463     MOVSXDIFNIDN width, height, steps
464
465 %if cpuflag(avx512)
466     vpbroadcastd    m2, widthd
467     INIT_WORD_MASK  k6, k5, k4, k3, k2, k1
468     INIT_INDICES   m28, m29, m30
469 %else
470     movd         xm2, widthd
471     VBROADCASTSS  m2, xm2
472 %endif
473
474     vpmulld m2, m2, [gblur_vindex_width] ; vindex width
475
476     xor yq, yq ; y = 0
477     xor xq, xq ; x = 0
478
479     cmp heightq, rows
480     jl .y_scalar
481     sub heightq, rows
482
483 .loop_y:
484     ; ptr = buffer + y * width;
485     mov  ptrq, yq
486     imul ptrq, widthq
487     lea  ptrq, [bufferq + ptrq*4]
488
489     KXNOR m5, k7
490     VGATHERDPS m3, [ptrq + m2*4], m5, k7
491     mulps m3, m1
492     movu [localbufq], m3
493     add ptrq, 4
494     add localbufq, mmsize
495
496     ; Filter rightwards
497     PUSH_MM m2
498     lea xq, [widthq - 1]
499     .loop_x:
500         PUSH_MM m3
501         GATHERPS cols
502         TRANSPOSE
503         POP_MM m3
504         WRITE_LOCAL_BUFFER
505
506         add ptrq,      mmsize
507         add localbufq, rows * mmsize
508         sub xq,        cols
509         cmp xq,        cols
510         jge .loop_x
511         POP_MM m2
512
513     cmp xq, 0
514     jle .bscale_scalar
515     .loop_x_scalar:
516         KXNOR m5, k7
517         VGATHERDPS m4, [ptrq + m2*4], m5, k7
518         FMULADD_PS m3, m3, m0, m4, m3
519         movu [localbufq], m3
520
521         add ptrq,      0x4
522         add localbufq, mmsize
523         dec xq
524         cmp xq,        0
525         jg .loop_x_scalar
526
527     OPTIMIZED_LOOP_STEP
528
529     .bscale_scalar:
530         sub ptrq, 4
531         sub localbufq, mmsize
532         mulps m3, m1
533         KXNOR m5, k7, maskq
534         VSCATTERDPS ptrq, strideq, m2, maskq, k7, 3, widthq, remainq
535
536     ; Filter leftwards
537     PUSH_MM m2
538     lea xq, [widthq - 1]
539     .loop_x_back:
540         sub localbufq, rows * mmsize
541         READ_LOCAL_BUFFER cols
542         PUSH_MM m2
543         TRANSPOSE
544         POP_MM m3
545         sub ptrq, mmsize
546         SCATTERPS
547
548         sub xq, cols
549         cmp xq, cols
550         jge .loop_x_back
551         POP_MM m2
552
553     cmp xq, 0
554     jle .end_loop_x
555     .loop_x_back_scalar:
556         sub ptrq, 0x4
557         sub localbufq, mmsize
558         FMULADD_PS m3, m3, m0, [localbufq], m3
559         KXNOR m5, k7, maskq
560         VSCATTERDPS ptrq, strideq, m2, maskq, k7, 3, widthq, remainq
561
562         dec xq
563         cmp xq, 0
564         jg .loop_x_back_scalar
565
566     .end_loop_x:
567
568     add yq, rows
569     cmp yq, heightq
570     jle .loop_y
571
572     add heightq, rows
573     cmp yq, heightq
574     jge .end_scalar
575
576     mov remainq, widthq
577     imul remainq, mmsize
578     add ptrq, remainq
579
580 .y_scalar:
581     mov remainq, heightq
582     sub remainq, yq
583     mov maskq, 1
584     shlx maskq, maskq, remainq
585     sub maskq, 1
586     mov remainq, maskq
587     PUSH_MASK m5, k1, remaind, xd, rsp + 0x20
588
589     mov ptrq, yq
590     imul ptrq, widthq
591     lea ptrq, [bufferq + ptrq * 4] ; ptrq = buffer + y * width
592     KMOVW m6, m5, k7, k1
593     VGATHERDPS m3, [ptrq + m2 * 4], m6, k7
594     mulps m3, m1 ; p0 *= bscale
595     movu [localbufq], m3
596     add localbufq, mmsize
597
598     ; Filter rightwards
599     lea xq, [widthq - 1]
600     .y_scalar_loop_x:
601         add ptrq, 4
602         KMOVW m6, m5, k7, k1
603         VGATHERDPS m4, [ptrq + m2 * 4], m6, k7
604         FMULADD_PS m3, m3, m0, m4, m3
605         movu [localbufq], m3
606         add localbufq, mmsize
607
608         dec xq
609         cmp xq, 0
610         jg .y_scalar_loop_x
611
612     OPTIMIZED_LOOP_STEP
613
614     sub localbufq, mmsize
615     mulps m3, m1 ; p0 *= bscale
616     KMOVW k7, k1
617     VSCATTERDPS ptrq, strideq, m2, maskq, k7, 3, widthq, remainq, heightq
618
619     ; Filter leftwards
620     lea xq, [widthq - 1]
621     .y_scalar_loop_x_back:
622         sub ptrq, 4
623         sub localbufq, mmsize
624         FMULADD_PS m3, m3, m0, [localbufq], m3
625         KMOVW k7, k1
626         VSCATTERDPS ptrq, strideq, m2, maskq, k7, 3, widthq, remainq, heightq
627         dec xq
628         cmp xq, 0
629         jg .y_scalar_loop_x_back
630
631 .end_scalar:
632     RET
633 %else
634 %if WIN64
635     movss m0, num
636     movss m1, bscalem
637     DEFINE_ARGS ptr, width, height, steps, x, y, step, stride, remain
638 %endif
639     movsxdifnidn widthq, widthd
640
641     mulss m2, m0, m0 ; nu ^ 2
642     mulss m3, m2, m0 ; nu ^ 3
643     mulss m4, m3, m0 ; nu ^ 4
644     xor   xq, xq
645     xor   yd, yd
646     mov   strideq, widthq
647     ; stride = width * 4
648     shl   strideq, 2
649     ; w = w - ((w - 1) & 3)
650     mov   remainq, widthq
651     sub   remainq, 1
652     and   remainq, 3
653     sub   widthq, remainq
654
655     shufps m0, m0, 0
656     shufps m2, m2, 0
657     shufps m3, m3, 0
658     shufps m4, m4, 0
659
660 .loop_y:
661     xor   stepd, stepd
662
663     .loop_step:
664         ; p0 *= bscale
665         mulss m5, m1, [ptrq + xq * 4]
666         movss [ptrq + xq * 4], m5
667         inc xq
668         ; filter rightwards
669         ; Here we are vectorizing the c version by 4
670         ;    for (x = 1; x < width; x++)
671         ;       ptr[x] += nu * ptr[x - 1];
672         ;   let p0 stands for ptr[x-1], the data from last loop
673         ;   and [p1,p2,p3,p4] be the vector data for this loop.
674         ; Unrolling the loop, we get:
675         ;   p1' = p1 + p0*nu
676         ;   p2' = p2 + p1*nu + p0*nu^2
677         ;   p3' = p3 + p2*nu + p1*nu^2 + p0*nu^3
678         ;   p4' = p4 + p3*nu + p2*nu^2 + p1*nu^3 + p0*nu^4
679         ; so we can do it in simd:
680         ; [p1',p2',p3',p4'] = [p1,p2,p3,p4] + [p0,p1,p2,p3]*nu +
681         ;                     [0,p0,p1,p2]*nu^2 + [0,0,p0,p1]*nu^3 +
682         ;                     [0,0,0,p0]*nu^4
683
684         .loop_x:
685             movu m6, [ptrq + xq * 4]         ; s  = [p1,p2,p3,p4]
686             pslldq m7, m6, 4                 ;      [0, p1,p2,p3]
687             movss  m7, m5                    ;      [p0,p1,p2,p3]
688             FMULADD_PS  m6, m7, m0, m6, m8   ; s += [p0,p1,p2,p3] * nu
689             pslldq m7, 4                     ;      [0,p0,p1,p2]
690             FMULADD_PS  m6, m7, m2, m6, m8   ; s += [0,p0,p1,p2]  * nu^2
691             pslldq m7, 4
692             FMULADD_PS  m6, m7, m3, m6, m8   ; s += [0,0,p0,p1]   * nu^3
693             pslldq m7, 4
694             FMULADD_PS  m6, m7, m4, m6, m8   ; s += [0,0,0,p0]    * nu^4
695             movu [ptrq + xq * 4], m6
696             shufps m5, m6, m6, q3333
697             add xq, 4
698             cmp xq, widthq
699             jl .loop_x
700
701         add widthq, remainq
702         cmp xq, widthq
703         jge .end_scalar
704
705         .loop_scalar:
706             ; ptr[x] += nu * ptr[x-1]
707             movss m5, [ptrq + 4*xq - 4]
708             mulss m5, m0
709             addss m5, [ptrq + 4*xq]
710             movss [ptrq + 4*xq], m5
711             inc xq
712             cmp xq, widthq
713             jl .loop_scalar
714         .end_scalar:
715             ; ptr[width - 1] *= bscale
716             dec xq
717             mulss m5, m1, [ptrq + 4*xq]
718             movss [ptrq + 4*xq], m5
719             shufps m5, m5, 0
720
721         ; filter leftwards
722         ;    for (; x > 0; x--)
723         ;        ptr[x - 1] += nu * ptr[x];
724         ; The idea here is basically the same as filter rightwards.
725         ; But we need to take care as the data layout is different.
726         ; Let p0 stands for the ptr[x], which is the data from last loop.
727         ; The way we do it in simd as below:
728         ; [p-4', p-3', p-2', p-1'] = [p-4, p-3, p-2, p-1]
729         ;                          + [p-3, p-2, p-1, p0] * nu
730         ;                          + [p-2, p-1, p0,  0]  * nu^2
731         ;                          + [p-1, p0,  0,   0]  * nu^3
732         ;                          + [p0,  0,   0,   0]  * nu^4
733         .loop_x_back:
734             sub xq, 4
735             movu m6, [ptrq + xq * 4]      ; s = [p-4, p-3, p-2, p-1]
736             psrldq m7, m6, 4              ;     [p-3, p-2, p-1, 0  ]
737             blendps m7, m5, 0x8           ;     [p-3, p-2, p-1, p0 ]
738             FMULADD_PS m6, m7, m0, m6, m8 ; s+= [p-3, p-2, p-1, p0 ] * nu
739             psrldq m7, 4                  ;
740             FMULADD_PS m6, m7, m2, m6, m8 ; s+= [p-2, p-1, p0,  0] * nu^2
741             psrldq m7, 4
742             FMULADD_PS m6, m7, m3, m6, m8 ; s+= [p-1, p0,   0,  0] * nu^3
743             psrldq m7, 4
744             FMULADD_PS m6, m7, m4, m6, m8 ; s+= [p0,  0,    0,  0] * nu^4
745             movu [ptrq + xq * 4], m6
746             shufps m5, m6, m6, 0          ; m5 = [p-4', p-4', p-4', p-4']
747             cmp xq, remainq
748             jg .loop_x_back
749
750         cmp xq, 0
751         jle .end_scalar_back
752
753         .loop_scalar_back:
754             ; ptr[x-1] += nu * ptr[x]
755             movss m5, [ptrq + 4*xq]
756             mulss m5, m0
757             addss m5, [ptrq + 4*xq - 4]
758             movss [ptrq + 4*xq - 4], m5
759             dec xq
760             cmp xq, 0
761             jg .loop_scalar_back
762         .end_scalar_back:
763
764         ; reset aligned width for next line
765         sub widthq, remainq
766
767         inc stepd
768         cmp stepd, stepsd
769         jl .loop_step
770
771     add ptrq, strideq
772     inc yd
773     cmp yd, heightd
774     jl .loop_y
775
776     RET
777 %endif
778 %endmacro
779
780 %if ARCH_X86_64
781 INIT_XMM sse4
782 HORIZ_SLICE
783
784 %if HAVE_AVX2_EXTERNAL
785 INIT_YMM avx2
786 %xdefine mmnum 16
787 HORIZ_SLICE
788 %endif
789
790 %if HAVE_AVX512_EXTERNAL
791 INIT_ZMM avx512
792 %xdefine mmnum 32
793 HORIZ_SLICE
794 %endif
795 %endif
796
797 %macro POSTSCALE_SLICE 0
798 cglobal postscale_slice, 2, 2, 4, ptr, length, postscale, min, max
799     shl lengthd, 2
800     add ptrq, lengthq
801     neg lengthq
802 %if ARCH_X86_32
803     VBROADCASTSS m0, postscalem
804     VBROADCASTSS m1, minm
805     VBROADCASTSS m2, maxm
806 %elif WIN64
807     VBROADCASTSS m0, xmm2
808     VBROADCASTSS m1, xmm3
809     VBROADCASTSS m2, maxm
810 %else ; UNIX
811     VBROADCASTSS m0, xmm0
812     VBROADCASTSS m1, xmm1
813     VBROADCASTSS m2, xmm2
814 %endif
815
816     .loop:
817 %if cpuflag(avx2) || cpuflag(avx512)
818     mulps         m3, m0, [ptrq + lengthq]
819 %else
820     movu          m3, [ptrq + lengthq]
821     mulps         m3, m0
822 %endif
823     maxps         m3, m1
824     minps         m3, m2
825     movu   [ptrq+lengthq], m3
826
827     add lengthq, mmsize
828     jl .loop
829
830     RET
831 %endmacro
832
833 INIT_XMM sse
834 POSTSCALE_SLICE
835
836 %if HAVE_AVX2_EXTERNAL
837 INIT_YMM avx2
838 POSTSCALE_SLICE
839 %endif
840
841 %if HAVE_AVX512_EXTERNAL
842 INIT_ZMM avx512
843 POSTSCALE_SLICE
844 %endif
845
846 ;*******************************************************************************
847 ; void ff_verti_slice(float *buffer, int width, int height, int column_begin,
848 ;                     int column_end, int steps, float nu, float bscale);
849 ;*******************************************************************************
850 %macro VERTI_SLICE 0
851 %if UNIX64
852 cglobal verti_slice, 6, 12, 9, 0-mmsize*2, buffer, width, height, cbegin, cend, \
853                                          steps, x, y, cwidth, step, ptr, stride
854 %else
855 cglobal verti_slice, 6, 12, 9, 0-mmsize*2, buffer, width, height, cbegin, cend, \
856                                          steps, nu, bscale, x, y, cwidth, step, \
857                                          ptr, stride
858 %endif
859 %assign cols mmsize/4
860 %if WIN64
861     VBROADCASTSS m0, num
862     VBROADCASTSS m1, bscalem
863     DEFINE_ARGS buffer, width, height, cbegin, cend, \
864                 steps, x, y, cwidth, step, ptr, stride
865 %else
866     VBROADCASTSS m0, xmm0 ; nu
867     VBROADCASTSS m1, xmm1 ; bscale
868 %endif
869     MOVSXDIFNIDN width, height, cbegin, cend, steps
870
871     mov cwidthq, cendq
872     sub cwidthq, cbeginq
873     lea strideq, [widthq * 4]
874
875     xor xq, xq ; x = 0
876     cmp cwidthq, cols
877     jl .x_scalar
878     cmp cwidthq, 0x0
879     je .end_scalar
880
881     sub cwidthq, cols
882 .loop_x:
883     xor stepq, stepq
884     .loop_step:
885         ; ptr = buffer + x + column_begin;
886         lea ptrq, [xq + cbeginq]
887         lea ptrq, [bufferq + ptrq*4]
888
889         ;  ptr[15:0] *= bcale;
890         movu m2, [ptrq]
891         mulps m2, m1
892         movu [ptrq], m2
893
894         ; Filter downwards
895         mov yq, 1
896         .loop_y_down:
897             add ptrq, strideq ; ptrq += width
898             movu m3, [ptrq]
899             FMULADD_PS m2, m2, m0, m3, m2
900             movu [ptrq], m2
901
902             inc yq
903             cmp yq, heightq
904             jl .loop_y_down
905
906         mulps m2, m1
907         movu [ptrq], m2
908
909         ; Filter upwards
910         dec yq
911         .loop_y_up:
912             sub ptrq, strideq
913             movu m3, [ptrq]
914             FMULADD_PS m2, m2, m0, m3, m2
915             movu [ptrq], m2
916
917             dec yq
918             cmp yq, 0
919             jg .loop_y_up
920
921         inc stepq
922         cmp stepq, stepsq
923         jl .loop_step
924
925     add xq, cols
926     cmp xq, cwidthq
927     jle .loop_x
928
929     add cwidthq, cols
930     cmp xq, cwidthq
931     jge .end_scalar
932
933 .x_scalar:
934     xor stepq, stepq
935     mov qword [rsp + 0x10], xq
936     sub cwidthq, xq
937     mov xq, 1
938     shlx cwidthq, xq, cwidthq
939     sub cwidthq, 1
940     PUSH_MASK m4, k1, cwidthd, xd, rsp + 0x20
941     mov xq, qword [rsp + 0x10]
942
943     .loop_step_scalar:
944         lea ptrq, [xq + cbeginq]
945         lea ptrq, [bufferq + ptrq*4]
946
947         VMASKMOVPS m2, [ptrq], m4, k1
948         mulps m2, m1
949         VMASKMOVPS [ptrq], m2, m4, k1
950
951         ; Filter downwards
952         mov yq, 1
953         .x_scalar_loop_y_down:
954             add ptrq, strideq
955             VMASKMOVPS m3, [ptrq], m4, k1
956             FMULADD_PS m2, m2, m0, m3, m2
957             VMASKMOVPS [ptrq], m2, m4, k1
958
959             inc yq
960             cmp yq, heightq
961             jl .x_scalar_loop_y_down
962
963         mulps m2, m1
964         VMASKMOVPS [ptrq], m2, m4, k1
965
966         ; Filter upwards
967         dec yq
968         .x_scalar_loop_y_up:
969             sub ptrq, strideq
970             VMASKMOVPS m3, [ptrq], m4, k1
971             FMULADD_PS m2, m2, m0, m3, m2
972             VMASKMOVPS [ptrq], m2, m4, k1
973
974             dec yq
975             cmp yq, 0
976             jg .x_scalar_loop_y_up
977
978         inc stepq
979         cmp stepq, stepsq
980         jl .loop_step_scalar
981
982 .end_scalar:
983     RET
984 %endmacro
985
986 %if ARCH_X86_64
987 %if HAVE_AVX2_EXTERNAL
988 INIT_YMM avx2
989 VERTI_SLICE
990 %endif
991
992 %if HAVE_AVX512_EXTERNAL
993 INIT_ZMM avx512
994 VERTI_SLICE
995 %endif
996 %endif