libavfilter/x86/vf_gblur: correct the order of loop step
[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     .bscale_scalar:
528         OPTIMIZED_LOOP_STEP
529         sub ptrq, 4
530         sub localbufq, mmsize
531         mulps m3, m1
532         KXNOR m5, k7, maskq
533         VSCATTERDPS ptrq, strideq, m2, maskq, k7, 3, widthq, remainq
534
535     ; Filter leftwards
536     PUSH_MM m2
537     lea xq, [widthq - 1]
538     .loop_x_back:
539         sub localbufq, rows * mmsize
540         READ_LOCAL_BUFFER cols
541         PUSH_MM m2
542         TRANSPOSE
543         POP_MM m3
544         sub ptrq, mmsize
545         SCATTERPS
546
547         sub xq, cols
548         cmp xq, cols
549         jge .loop_x_back
550         POP_MM m2
551
552     cmp xq, 0
553     jle .end_loop_x
554     .loop_x_back_scalar:
555         sub ptrq, 0x4
556         sub localbufq, mmsize
557         FMULADD_PS m3, m3, m0, [localbufq], m3
558         KXNOR m5, k7, maskq
559         VSCATTERDPS ptrq, strideq, m2, maskq, k7, 3, widthq, remainq
560
561         dec xq
562         cmp xq, 0
563         jg .loop_x_back_scalar
564
565     .end_loop_x:
566
567     add yq, rows
568     cmp yq, heightq
569     jle .loop_y
570
571     add heightq, rows
572     cmp yq, heightq
573     jge .end_scalar
574
575     mov remainq, widthq
576     imul remainq, mmsize
577     add ptrq, remainq
578
579 .y_scalar:
580     mov remainq, heightq
581     sub remainq, yq
582     mov maskq, 1
583     shlx maskq, maskq, remainq
584     sub maskq, 1
585     mov remainq, maskq
586     PUSH_MASK m5, k1, remaind, xd, rsp + 0x20
587
588     mov ptrq, yq
589     imul ptrq, widthq
590     lea ptrq, [bufferq + ptrq * 4] ; ptrq = buffer + y * width
591     KMOVW m6, m5, k7, k1
592     VGATHERDPS m3, [ptrq + m2 * 4], m6, k7
593     mulps m3, m1 ; p0 *= bscale
594     movu [localbufq], m3
595     add localbufq, mmsize
596
597     ; Filter rightwards
598     lea xq, [widthq - 1]
599     .y_scalar_loop_x:
600         add ptrq, 4
601         KMOVW m6, m5, k7, k1
602         VGATHERDPS m4, [ptrq + m2 * 4], m6, k7
603         FMULADD_PS m3, m3, m0, m4, m3
604         movu [localbufq], m3
605         add localbufq, mmsize
606
607         dec xq
608         cmp xq, 0
609         jg .y_scalar_loop_x
610
611     OPTIMIZED_LOOP_STEP
612
613     sub localbufq, mmsize
614     mulps m3, m1 ; p0 *= bscale
615     KMOVW k7, k1
616     VSCATTERDPS ptrq, strideq, m2, maskq, k7, 3, widthq, remainq, heightq
617
618     ; Filter leftwards
619     lea xq, [widthq - 1]
620     .y_scalar_loop_x_back:
621         sub ptrq, 4
622         sub localbufq, mmsize
623         FMULADD_PS m3, m3, m0, [localbufq], m3
624         KMOVW k7, k1
625         VSCATTERDPS ptrq, strideq, m2, maskq, k7, 3, widthq, remainq, heightq
626         dec xq
627         cmp xq, 0
628         jg .y_scalar_loop_x_back
629
630 .end_scalar:
631     RET
632 %else
633 %if WIN64
634     movss m0, num
635     movss m1, bscalem
636     DEFINE_ARGS ptr, width, height, steps, x, y, step, stride, remain
637 %endif
638     movsxdifnidn widthq, widthd
639
640     mulss m2, m0, m0 ; nu ^ 2
641     mulss m3, m2, m0 ; nu ^ 3
642     mulss m4, m3, m0 ; nu ^ 4
643     xor   xq, xq
644     xor   yd, yd
645     mov   strideq, widthq
646     ; stride = width * 4
647     shl   strideq, 2
648     ; w = w - ((w - 1) & 3)
649     mov   remainq, widthq
650     sub   remainq, 1
651     and   remainq, 3
652     sub   widthq, remainq
653
654     shufps m0, m0, 0
655     shufps m2, m2, 0
656     shufps m3, m3, 0
657     shufps m4, m4, 0
658
659 .loop_y:
660     xor   stepd, stepd
661
662     .loop_step:
663         ; p0 *= bscale
664         mulss m5, m1, [ptrq + xq * 4]
665         movss [ptrq + xq * 4], m5
666         inc xq
667         ; filter rightwards
668         ; Here we are vectorizing the c version by 4
669         ;    for (x = 1; x < width; x++)
670         ;       ptr[x] += nu * ptr[x - 1];
671         ;   let p0 stands for ptr[x-1], the data from last loop
672         ;   and [p1,p2,p3,p4] be the vector data for this loop.
673         ; Unrolling the loop, we get:
674         ;   p1' = p1 + p0*nu
675         ;   p2' = p2 + p1*nu + p0*nu^2
676         ;   p3' = p3 + p2*nu + p1*nu^2 + p0*nu^3
677         ;   p4' = p4 + p3*nu + p2*nu^2 + p1*nu^3 + p0*nu^4
678         ; so we can do it in simd:
679         ; [p1',p2',p3',p4'] = [p1,p2,p3,p4] + [p0,p1,p2,p3]*nu +
680         ;                     [0,p0,p1,p2]*nu^2 + [0,0,p0,p1]*nu^3 +
681         ;                     [0,0,0,p0]*nu^4
682
683         .loop_x:
684             movu m6, [ptrq + xq * 4]         ; s  = [p1,p2,p3,p4]
685             pslldq m7, m6, 4                 ;      [0, p1,p2,p3]
686             movss  m7, m5                    ;      [p0,p1,p2,p3]
687             FMULADD_PS  m6, m7, m0, m6, m8   ; s += [p0,p1,p2,p3] * nu
688             pslldq m7, 4                     ;      [0,p0,p1,p2]
689             FMULADD_PS  m6, m7, m2, m6, m8   ; s += [0,p0,p1,p2]  * nu^2
690             pslldq m7, 4
691             FMULADD_PS  m6, m7, m3, m6, m8   ; s += [0,0,p0,p1]   * nu^3
692             pslldq m7, 4
693             FMULADD_PS  m6, m7, m4, m6, m8   ; s += [0,0,0,p0]    * nu^4
694             movu [ptrq + xq * 4], m6
695             shufps m5, m6, m6, q3333
696             add xq, 4
697             cmp xq, widthq
698             jl .loop_x
699
700         add widthq, remainq
701         cmp xq, widthq
702         jge .end_scalar
703
704         .loop_scalar:
705             ; ptr[x] += nu * ptr[x-1]
706             movss m5, [ptrq + 4*xq - 4]
707             mulss m5, m0
708             addss m5, [ptrq + 4*xq]
709             movss [ptrq + 4*xq], m5
710             inc xq
711             cmp xq, widthq
712             jl .loop_scalar
713         .end_scalar:
714             ; ptr[width - 1] *= bscale
715             dec xq
716             mulss m5, m1, [ptrq + 4*xq]
717             movss [ptrq + 4*xq], m5
718             shufps m5, m5, 0
719
720         ; filter leftwards
721         ;    for (; x > 0; x--)
722         ;        ptr[x - 1] += nu * ptr[x];
723         ; The idea here is basically the same as filter rightwards.
724         ; But we need to take care as the data layout is different.
725         ; Let p0 stands for the ptr[x], which is the data from last loop.
726         ; The way we do it in simd as below:
727         ; [p-4', p-3', p-2', p-1'] = [p-4, p-3, p-2, p-1]
728         ;                          + [p-3, p-2, p-1, p0] * nu
729         ;                          + [p-2, p-1, p0,  0]  * nu^2
730         ;                          + [p-1, p0,  0,   0]  * nu^3
731         ;                          + [p0,  0,   0,   0]  * nu^4
732         .loop_x_back:
733             sub xq, 4
734             movu m6, [ptrq + xq * 4]      ; s = [p-4, p-3, p-2, p-1]
735             psrldq m7, m6, 4              ;     [p-3, p-2, p-1, 0  ]
736             blendps m7, m5, 0x8           ;     [p-3, p-2, p-1, p0 ]
737             FMULADD_PS m6, m7, m0, m6, m8 ; s+= [p-3, p-2, p-1, p0 ] * nu
738             psrldq m7, 4                  ;
739             FMULADD_PS m6, m7, m2, m6, m8 ; s+= [p-2, p-1, p0,  0] * nu^2
740             psrldq m7, 4
741             FMULADD_PS m6, m7, m3, m6, m8 ; s+= [p-1, p0,   0,  0] * nu^3
742             psrldq m7, 4
743             FMULADD_PS m6, m7, m4, m6, m8 ; s+= [p0,  0,    0,  0] * nu^4
744             movu [ptrq + xq * 4], m6
745             shufps m5, m6, m6, 0          ; m5 = [p-4', p-4', p-4', p-4']
746             cmp xq, remainq
747             jg .loop_x_back
748
749         cmp xq, 0
750         jle .end_scalar_back
751
752         .loop_scalar_back:
753             ; ptr[x-1] += nu * ptr[x]
754             movss m5, [ptrq + 4*xq]
755             mulss m5, m0
756             addss m5, [ptrq + 4*xq - 4]
757             movss [ptrq + 4*xq - 4], m5
758             dec xq
759             cmp xq, 0
760             jg .loop_scalar_back
761         .end_scalar_back:
762
763         ; reset aligned width for next line
764         sub widthq, remainq
765
766         inc stepd
767         cmp stepd, stepsd
768         jl .loop_step
769
770     add ptrq, strideq
771     inc yd
772     cmp yd, heightd
773     jl .loop_y
774
775     RET
776 %endif
777 %endmacro
778
779 %if ARCH_X86_64
780 INIT_XMM sse4
781 HORIZ_SLICE
782
783 %if HAVE_AVX2_EXTERNAL
784 INIT_YMM avx2
785 %xdefine mmnum 16
786 HORIZ_SLICE
787 %endif
788
789 %if HAVE_AVX512_EXTERNAL
790 INIT_ZMM avx512
791 %xdefine mmnum 32
792 HORIZ_SLICE
793 %endif
794 %endif
795
796 %macro POSTSCALE_SLICE 0
797 cglobal postscale_slice, 2, 2, 4, ptr, length, postscale, min, max
798     shl lengthd, 2
799     add ptrq, lengthq
800     neg lengthq
801 %if ARCH_X86_32
802     VBROADCASTSS m0, postscalem
803     VBROADCASTSS m1, minm
804     VBROADCASTSS m2, maxm
805 %elif WIN64
806     VBROADCASTSS m0, xmm2
807     VBROADCASTSS m1, xmm3
808     VBROADCASTSS m2, maxm
809 %else ; UNIX
810     VBROADCASTSS m0, xmm0
811     VBROADCASTSS m1, xmm1
812     VBROADCASTSS m2, xmm2
813 %endif
814
815     .loop:
816 %if cpuflag(avx2) || cpuflag(avx512)
817     mulps         m3, m0, [ptrq + lengthq]
818 %else
819     movu          m3, [ptrq + lengthq]
820     mulps         m3, m0
821 %endif
822     maxps         m3, m1
823     minps         m3, m2
824     movu   [ptrq+lengthq], m3
825
826     add lengthq, mmsize
827     jl .loop
828
829     RET
830 %endmacro
831
832 INIT_XMM sse
833 POSTSCALE_SLICE
834
835 %if HAVE_AVX2_EXTERNAL
836 INIT_YMM avx2
837 POSTSCALE_SLICE
838 %endif
839
840 %if HAVE_AVX512_EXTERNAL
841 INIT_ZMM avx512
842 POSTSCALE_SLICE
843 %endif
844
845 ;*******************************************************************************
846 ; void ff_verti_slice(float *buffer, int width, int height, int column_begin,
847 ;                     int column_end, int steps, float nu, float bscale);
848 ;*******************************************************************************
849 %macro VERTI_SLICE 0
850 %if UNIX64
851 cglobal verti_slice, 6, 12, 9, 0-mmsize*2, buffer, width, height, cbegin, cend, \
852                                          steps, x, y, cwidth, step, ptr, stride
853 %else
854 cglobal verti_slice, 6, 12, 9, 0-mmsize*2, buffer, width, height, cbegin, cend, \
855                                          steps, nu, bscale, x, y, cwidth, step, \
856                                          ptr, stride
857 %endif
858 %assign cols mmsize/4
859 %if WIN64
860     VBROADCASTSS m0, num
861     VBROADCASTSS m1, bscalem
862     DEFINE_ARGS buffer, width, height, cbegin, cend, \
863                 steps, x, y, cwidth, step, ptr, stride
864 %else
865     VBROADCASTSS m0, xmm0 ; nu
866     VBROADCASTSS m1, xmm1 ; bscale
867 %endif
868     MOVSXDIFNIDN width, height, cbegin, cend, steps
869
870     mov cwidthq, cendq
871     sub cwidthq, cbeginq
872     lea strideq, [widthq * 4]
873
874     xor xq, xq ; x = 0
875     cmp cwidthq, cols
876     jl .x_scalar
877     cmp cwidthq, 0x0
878     je .end_scalar
879
880     sub cwidthq, cols
881 .loop_x:
882     xor stepq, stepq
883     .loop_step:
884         ; ptr = buffer + x + column_begin;
885         lea ptrq, [xq + cbeginq]
886         lea ptrq, [bufferq + ptrq*4]
887
888         ;  ptr[15:0] *= bcale;
889         movu m2, [ptrq]
890         mulps m2, m1
891         movu [ptrq], m2
892
893         ; Filter downwards
894         mov yq, 1
895         .loop_y_down:
896             add ptrq, strideq ; ptrq += width
897             movu m3, [ptrq]
898             FMULADD_PS m2, m2, m0, m3, m2
899             movu [ptrq], m2
900
901             inc yq
902             cmp yq, heightq
903             jl .loop_y_down
904
905         mulps m2, m1
906         movu [ptrq], m2
907
908         ; Filter upwards
909         dec yq
910         .loop_y_up:
911             sub ptrq, strideq
912             movu m3, [ptrq]
913             FMULADD_PS m2, m2, m0, m3, m2
914             movu [ptrq], m2
915
916             dec yq
917             cmp yq, 0
918             jg .loop_y_up
919
920         inc stepq
921         cmp stepq, stepsq
922         jl .loop_step
923
924     add xq, cols
925     cmp xq, cwidthq
926     jle .loop_x
927
928     add cwidthq, cols
929     cmp xq, cwidthq
930     jge .end_scalar
931
932 .x_scalar:
933     xor stepq, stepq
934     mov qword [rsp + 0x10], xq
935     sub cwidthq, xq
936     mov xq, 1
937     shlx cwidthq, xq, cwidthq
938     sub cwidthq, 1
939     PUSH_MASK m4, k1, cwidthd, xd, rsp + 0x20
940     mov xq, qword [rsp + 0x10]
941
942     .loop_step_scalar:
943         lea ptrq, [xq + cbeginq]
944         lea ptrq, [bufferq + ptrq*4]
945
946         VMASKMOVPS m2, [ptrq], m4, k1
947         mulps m2, m1
948         VMASKMOVPS [ptrq], m2, m4, k1
949
950         ; Filter downwards
951         mov yq, 1
952         .x_scalar_loop_y_down:
953             add ptrq, strideq
954             VMASKMOVPS m3, [ptrq], m4, k1
955             FMULADD_PS m2, m2, m0, m3, m2
956             VMASKMOVPS [ptrq], m2, m4, k1
957
958             inc yq
959             cmp yq, heightq
960             jl .x_scalar_loop_y_down
961
962         mulps m2, m1
963         VMASKMOVPS [ptrq], m2, m4, k1
964
965         ; Filter upwards
966         dec yq
967         .x_scalar_loop_y_up:
968             sub ptrq, strideq
969             VMASKMOVPS m3, [ptrq], m4, k1
970             FMULADD_PS m2, m2, m0, m3, m2
971             VMASKMOVPS [ptrq], m2, m4, k1
972
973             dec yq
974             cmp yq, 0
975             jg .x_scalar_loop_y_up
976
977         inc stepq
978         cmp stepq, stepsq
979         jl .loop_step_scalar
980
981 .end_scalar:
982     RET
983 %endmacro
984
985 %if ARCH_X86_64
986 %if HAVE_AVX2_EXTERNAL
987 INIT_YMM avx2
988 VERTI_SLICE
989 %endif
990
991 %if HAVE_AVX512_EXTERNAL
992 INIT_ZMM avx512
993 VERTI_SLICE
994 %endif
995 %endif