summaryrefslogtreecommitdiffstats
path: root/third_party/dav1d/src/x86/refmvs.asm
blob: d95861fa17542b2310ee70f06dda0f40176b7ded (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
; Copyright © 2021, VideoLAN and dav1d authors
; Copyright © 2021, Two Orioles, LLC
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;
; 1. Redistributions of source code must retain the above copyright notice, this
;    list of conditions and the following disclaimer.
;
; 2. Redistributions in binary form must reproduce the above copyright notice,
;    this list of conditions and the following disclaimer in the documentation
;    and/or other materials provided with the distribution.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

%include "config.asm"
%include "ext/x86/x86inc.asm"

SECTION_RODATA 64

%macro JMP_TABLE 2-*
    %xdefine %%prefix mangle(private_prefix %+ _%1)
    %1_table:
    %xdefine %%base %1_table
    %rep %0 - 1
        dd %%prefix %+ .w%2 - %%base
        %rotate 1
    %endrep
%endmacro

%macro SAVE_TMVS_TABLE 3 ; num_entries, w, suffix
    %rep %1
        db %2*3
        db mangle(private_prefix %+ _save_tmvs_%3).write%2 - \
           mangle(private_prefix %+ _save_tmvs_%3).write1
    %endrep
%endmacro

%if ARCH_X86_64
mv_proj:       dw    0, 16384, 8192, 5461, 4096, 3276, 2730, 2340
               dw 2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092
               dw 1024,   963,  910,  862,  819,  780,  744,  712
               dw  682,   655,  630,  606,  585,  564,  546,  528
splat_mv_shuf: db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3
               db  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7
               db  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11
               db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3
%endif
save_pack0:    db  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0
               db  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1
save_pack1:    db  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2
               db  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3
save_ref_shuf: db  0, -1, -1, -1,  1, -1, -1, -1,  8, -1, -1, -1,  9, -1, -1, -1
cond_shuf512:  db  3,  3,  3,  3,  7,  7,  7,  7,  7,  7,  7,  7,  3,  3,  3,  3
save_cond0:    db  0x80, 0x81, 0x82, 0x83, 0x89, 0x84, 0x00, 0x00
save_cond1:    db  0x84, 0x85, 0x86, 0x87, 0x88, 0x80, 0x00, 0x00
pb_128:        times 16 db 128
pq_8192:       dq 8192

save_tmvs_ssse3_table: SAVE_TMVS_TABLE 2, 16, ssse3
                       SAVE_TMVS_TABLE 4,  8, ssse3
                       SAVE_TMVS_TABLE 4,  4, ssse3
                       SAVE_TMVS_TABLE 5,  2, ssse3
                       SAVE_TMVS_TABLE 7,  1, ssse3

%if ARCH_X86_64
save_tmvs_avx2_table: SAVE_TMVS_TABLE 2, 16, avx2
                      SAVE_TMVS_TABLE 4,  8, avx2
                      SAVE_TMVS_TABLE 4,  4, avx2
                      SAVE_TMVS_TABLE 5,  2, avx2
                      SAVE_TMVS_TABLE 7,  1, avx2

save_tmvs_avx512icl_table: SAVE_TMVS_TABLE 2, 16, avx512icl
                           SAVE_TMVS_TABLE 4,  8, avx512icl
                           SAVE_TMVS_TABLE 4,  4, avx512icl
                           SAVE_TMVS_TABLE 5,  2, avx512icl
                           SAVE_TMVS_TABLE 7,  1, avx512icl

JMP_TABLE splat_mv_avx512icl, 1, 2, 4, 8, 16, 32
JMP_TABLE splat_mv_avx2,      1, 2, 4, 8, 16, 32
%endif

JMP_TABLE splat_mv_sse2,      1, 2, 4, 8, 16, 32

SECTION .text

%macro movif32 2
%if ARCH_X86_32
    mov             %1, %2
%endif
%endmacro

INIT_XMM ssse3
; refmvs_temporal_block *rp, ptrdiff_t stride,
; refmvs_block **rr, uint8_t *ref_sign,
; int col_end8, int row_end8, int col_start8, int row_start8
%if ARCH_X86_64
cglobal save_tmvs, 4, 13, 11, rp, stride, rr, ref_sign, \
                             xend, yend, xstart, ystart
%define base_reg r12
%else
cglobal save_tmvs, 6, 7, 8, rp, stride, rr, ref_sign, \
                            xend, yend, xstart, ystart
    movq            m5, [ref_signq]
    lea        strided, [strided*5]
    mov        stridem, strided
    mov             r3, xstartm
    mov             r1, ystartm
 DEFINE_ARGS b, ystart, rr, cand, xend, x
%define stridemp r1m
%define m8  [base+pb_128]
%define m9  [base+save_pack0+ 0]
%define m10 [base+save_pack0+16]
%define base_reg r6
%endif
%define base base_reg-.write1
    LEA       base_reg, .write1
%if ARCH_X86_64
    movifnidn    xendd, xendm
    movifnidn    yendd, yendm
    mov        xstartd, xstartm
    mov        ystartd, ystartm
    movq            m5, [ref_signq]
%endif
    movu            m4, [base+save_ref_shuf]
    movddup         m6, [base+save_cond0]
    movddup         m7, [base+save_cond1]
%if ARCH_X86_64
    mova            m8, [base+pb_128]
    mova            m9, [base+save_pack0+ 0]
    mova           m10, [base+save_pack0+16]
%endif
    psllq           m5, 8
%if ARCH_X86_64
    lea            r9d, [xendq*5]
    lea        xstartd, [xstartq*5]
    sub          yendd, ystartd
    add        ystartd, ystartd
    lea        strideq, [strideq*5]
    sub        xstartq, r9
    add          xendd, r9d
    add            rpq, r9
 DEFINE_ARGS rp, stride, rr, x, xend, h, xstart, ystart, b, cand
%else
    lea             r0, [xendd*5]   ; xend5
    lea             r3, [r3*5]      ; xstart5
    sub             r3, r0          ; -w5
    mov            r6m, r3
%define xstartq r6m
    add          xendd, r0          ; xend6
    add            r0m, r0          ; rp+xend5
    mov          xendm, xendd
    sub             r5, r1          ; h
    add             r1, r1
    mov            r7m, r1
    mov            r5m, r5
%define hd r5mp
    jmp .loop_y_noload
%endif
.loop_y:
    movif32    ystartd, r7m
    movif32      xendd, xendm
.loop_y_noload:
    and        ystartd, 30
    mov             xq, xstartq
    mov             bq, [rrq+ystartq*gprsize]
    add        ystartd, 2
    movif32        r7m, ystartd
    lea             bq, [bq+xendq*4]
.loop_x:
%if ARCH_X86_32
%define rpq  r3
%define r10  r1
%define r10d r1
%define r11  r4
%define r11d r4
%endif
    imul         candq, xq, 0x9999  ; x / 5 * 3
    sar          candq, 16
    movzx         r10d, byte [bq+candq*8+22] ; cand_b->bs
    movu            m0, [bq+candq*8+12]      ; cand_b
    movzx         r11d, byte [base+save_tmvs_ssse3_table+r10*2+0]
    movzx         r10d, byte [base+save_tmvs_ssse3_table+r10*2+1]
    add            r10, base_reg
    add          candq, r11
    jge .calc
    movu            m1, [bq+candq*8+12]
    movzx         r11d, byte [bq+candq*8+22]
    movzx         r11d, byte [base+save_tmvs_ssse3_table+r11*2+1]
    add            r11, base_reg
.calc:
    movif32        rpq, r0m
    ; ref check
    punpckhqdq      m2, m0, m1
    pshufb          m2, m4      ; b0.ref0 b0.ref1 b1.ref0 b1.ref1 | ...
    pshufb          m3, m5, m2  ; ref > 0 && res_sign[ref - 1]
    ; mv check
    punpcklqdq      m2, m0, m1  ; b0.mv0 b0.mv1 b1.mv0 b1.mv1 | ...
    pabsw           m2, m2
    psrlw           m2, 12      ; (abs(mv.x) | abs(mv.y)) < 4096
    ; res
    pcmpgtd         m3, m2
    pshufd          m2, m3, q2301
    pand            m3, m6      ; b0c0 b0c1 b1c0 b1c1 | ...
    pand            m2, m7      ; b0c1 b0c0 b1c1 b1c0 | ...
    por             m3, m2      ; b0.shuf b1.shuf | ...
    pxor            m3, m8      ; if cond0|cond1 == 0 => zero out
    pshufb          m0, m3
    pshufb          m1, m3
    call           r10
    jge .next_line
    pshufd          m0, m1, q3232
    call           r11
    jl .loop_x
.next_line:
    add            rpq, stridemp
    movif32        r0m, rpq
    dec             hd
    jg .loop_y
    RET
.write1:
    movd    [rpq+xq+0], m0
    psrlq           m0, 8
    movd    [rpq+xq+1], m0
    add             xq, 5*1
    ret
.write2:
    movq    [rpq+xq+0], m0
    psrlq           m0, 8
    movd    [rpq+xq+6], m0
    add             xq, 5*2
    ret
.write4:
    pshufb          m0, m9
    movu   [rpq+xq+ 0], m0
    psrlq           m0, 8
    movd   [rpq+xq+16], m0
    add             xq, 5*4
    ret
.write8:
    pshufb          m2, m0, m9
    movu   [rpq+xq+ 0], m2
    pshufb          m0, m10
    movu   [rpq+xq+16], m0
    psrldq          m2, 2
    movq   [rpq+xq+32], m2
    add             xq, 5*8
    ret
.write16:
    pshufb          m2, m0, m9
    movu   [rpq+xq+ 0], m2
    pshufb          m0, m10
    movu   [rpq+xq+16], m0
    shufps          m2, m0, q1032
    movu   [rpq+xq+48], m2
    shufps          m2, m0, q2121
    movu   [rpq+xq+32], m2
    shufps          m0, m2, q1032
    movu   [rpq+xq+64], m0
    add             xq, 5*16
    ret

INIT_XMM sse2
; refmvs_block **rr, refmvs_block *a, int bx4, int bw4, int bh4
cglobal splat_mv, 4, 5, 3, rr, a, bx4, bw4, bh4
    add           bx4d, bw4d
    tzcnt         bw4d, bw4d
    mova            m2, [aq]
    LEA             aq, splat_mv_sse2_table
    lea           bx4q, [bx4q*3-32]
    movsxd        bw4q, [aq+bw4q*4]
    movifnidn     bh4d, bh4m
    pshufd          m0, m2, q0210
    pshufd          m1, m2, q1021
    pshufd          m2, m2, q2102
    add           bw4q, aq
.loop:
    mov             aq, [rrq]
    add            rrq, gprsize
    lea             aq, [aq+bx4q*4]
    jmp           bw4q
.w32:
    mova    [aq-16*16], m0
    mova    [aq-16*15], m1
    mova    [aq-16*14], m2
    mova    [aq-16*13], m0
    mova    [aq-16*12], m1
    mova    [aq-16*11], m2
    mova    [aq-16*10], m0
    mova    [aq-16* 9], m1
    mova    [aq-16* 8], m2
    mova    [aq-16* 7], m0
    mova    [aq-16* 6], m1
    mova    [aq-16* 5], m2
.w16:
    mova    [aq-16* 4], m0
    mova    [aq-16* 3], m1
    mova    [aq-16* 2], m2
    mova    [aq-16* 1], m0
    mova    [aq+16* 0], m1
    mova    [aq+16* 1], m2
.w8:
    mova    [aq+16* 2], m0
    mova    [aq+16* 3], m1
    mova    [aq+16* 4], m2
.w4:
    mova    [aq+16* 5], m0
    mova    [aq+16* 6], m1
    mova    [aq+16* 7], m2
    dec           bh4d
    jg .loop
    RET
.w2:
    movu      [aq+104], m0
    movq      [aq+120], m1
    dec           bh4d
    jg .loop
    RET
.w1:
    movq      [aq+116], m0
    movd      [aq+124], m2
    dec           bh4d
    jg .loop
    RET

%if ARCH_X86_64
INIT_XMM sse4
; refmvs_frame *rf, int tile_row_idx,
; int col_start8, int col_end8, int row_start8, int row_end8
cglobal load_tmvs, 6, 15, 4, -0x50, rf, tridx, xstart, xend, ystart, yend, \
                                    stride, rp_proj, roff, troff, \
                                    xendi, xstarti, iw8, ih8, dst
    xor           r14d, r14d
    cmp dword [rfq+212], 1          ; n_tile_threads
    mov           ih8d, [rfq+20]    ; rf->ih8
    mov           iw8d, [rfq+16]    ; rf->iw8
    mov        xstartd, xstartd
    mov          xendd, xendd
    cmove       tridxd, r14d
    lea       xstartid, [xstartq-8]
    lea         xendid, [xendq+8]
    mov        strideq, [rfq+184]
    mov       rp_projq, [rfq+176]
    cmp           ih8d, yendd
    mov     [rsp+0x30], strideq
    cmovs        yendd, ih8d
    test      xstartid, xstartid
    cmovs     xstartid, r14d
    cmp           iw8d, xendid
    cmovs       xendid, iw8d
    mov         troffq, strideq
    shl         troffq, 4
    imul        troffq, tridxq
    mov           dstd, ystartd
    and           dstd, 15
    imul          dstq, strideq
    add           dstq, troffq      ; (16 * tridx + (ystart & 15)) * stride
    lea           dstq, [dstq*5]
    add           dstq, rp_projq
    lea         troffq, [troffq*5]  ; 16 * tridx * stride * 5
    lea           r13d, [xendq*5]
    lea            r12, [strideq*5]
 DEFINE_ARGS rf, w5, xstart, xend, ystart, yend, h, x5, \
             _, troff, xendi, xstarti, stride5, _, dst
    lea            w5d, [xstartq*5]
    add             r7, troffq      ; rp_proj + tile_row_offset
    mov             hd, yendd
    mov     [rsp+0x28], r7
    add           dstq, r13
    sub            w5q, r13
    sub             hd, ystartd
.init_xloop_start:
    mov            x5q, w5q
    test           w5b, 1
    jz .init_2blk
    mov dword [dstq+x5q], 0x80008000
    add            x5q, 5
    jz .init_next_row
.init_2blk:
    mov dword [dstq+x5q+0], 0x80008000
    mov dword [dstq+x5q+5], 0x80008000
    add            x5q, 10
    jl .init_2blk
.init_next_row:
    add           dstq, stride5q
    dec             hd
    jg .init_xloop_start
 DEFINE_ARGS rf, _, xstart, xend, ystart, yend, n7, stride, \
             _, _, xendi, xstarti, stride5, _, n
    mov           r13d, [rfq+152]   ; rf->n_mfmvs
    test          r13d, r13d
    jz .ret
    mov     [rsp+0x0c], r13d
    mov        strideq, [rsp+0x30]
    movddup         m3, [pq_8192]
    mov            r9d, ystartd
    mov     [rsp+0x38], yendd
    mov     [rsp+0x20], xstartid
    xor             nd, nd
    xor            n7d, n7d
    imul            r9, strideq     ; ystart * stride
    mov     [rsp+0x48], rfq
    mov     [rsp+0x18], stride5q
    lea             r7, [r9*5]
    mov     [rsp+0x24], ystartd
    mov     [rsp+0x00], r7
.nloop:
 DEFINE_ARGS y, off, xstart, xend, ystart, rf, n7, refsign, \
             ref, rp_ref, xendi, xstarti, _, _, n
    mov            rfq, [rsp+0x48]
    mov           refd, [rfq+56+nq*4]       ; ref2cur
    cmp           refd, 0x80000000
    je .next_n
    mov     [rsp+0x40], refd
    mov           offq, [rsp+0x00]          ; ystart * stride * 5
    movzx         refd, byte [rfq+53+nq]    ; rf->mfmv_ref[n]
    lea       refsignq, [refq-4]
    mov        rp_refq, [rfq+168]
    movq            m2, refsignq
    add           offq, [rp_refq+refq*8]    ; r = rp_ref[ref] + row_offset
    mov     [rsp+0x14], nd
    mov             yd, ystartd
.yloop:
    mov           r11d, [rsp+0x24]          ; ystart
    mov           r12d, [rsp+0x38]          ; yend
    mov           r14d, yd
    and           r14d, ~7                  ; y_sb_align
    cmp           r11d, r14d
    cmovs         r11d, r14d                ; imax(y_sb_align, ystart)
    mov     [rsp+0x44], r11d                ; y_proj_start
    add           r14d, 8
    cmp           r12d, r14d
    cmovs         r14d, r12d                ; imin(y_sb_align + 8, yend)
    mov     [rsp+0x3c], r14d                ; y_proj_end
 DEFINE_ARGS y, src, xstart, xend, frac, rf, n7, mv, \
             ref, x, xendi, mvx, mvy, rb, ref2ref
    mov             xd, [rsp+0x20] ; xstarti
.xloop:
    lea            rbd, [xq*5]
    add            rbq, srcq
    movsx         refd, byte [rbq+4]
    test          refd, refd
    jz .next_x_bad_ref
    mov            rfq, [rsp+0x48]
    lea           r14d, [16+n7q+refq]
    mov       ref2refd, [rfq+r14*4]         ; rf->mfmv_ref2ref[n][b_ref-1]
    test      ref2refd, ref2refd
    jz .next_x_bad_ref
    lea          fracq, [mv_proj]
    movzx        fracd, word [fracq+ref2refq*2]
    mov            mvd, [rbq]
    imul         fracd, [rsp+0x40] ; ref2cur
    pmovsxwq        m0, [rbq]
    movd            m1, fracd
    punpcklqdq      m1, m1
    pmuldq          m0, m1          ; mv * frac
    pshufd          m1, m0, q3311
    paddd           m0, m3
    paddd           m0, m1
    psrad           m0, 14          ; offset = (xy + (xy >> 31) + 8192) >> 14
    pabsd           m1, m0
    packssdw        m0, m0
    psrld           m1, 6
    packuswb        m1, m1
    pxor            m0, m2          ; offset ^ ref_sign
    psignd          m1, m0          ; apply_sign(abs(offset) >> 6, offset ^ refsign)
    movq          mvxq, m1
    lea           mvyd, [mvxq+yq]   ; ypos
    sar           mvxq, 32
 DEFINE_ARGS y, src, xstart, xend, _, _, n7, mv, \
             ref, x, xendi, mvx, ypos, rb, ref2ref
    cmp          yposd, [rsp+0x44] ; y_proj_start
    jl .next_x_bad_pos_y
    cmp          yposd, [rsp+0x3c] ; y_proj_end
    jge .next_x_bad_pos_y
    and          yposd, 15
    add           mvxq, xq          ; xpos
    imul         yposq, [rsp+0x30]  ; pos = (ypos & 15) * stride
 DEFINE_ARGS y, src, xstart, xend, dst, _, n7, mv, \
             ref, x, xendi, xpos, pos, rb, ref2ref
    mov           dstq, [rsp+0x28]  ; dst = rp_proj + tile_row_offset
    add           posq, xposq       ; pos += xpos
    lea           posq, [posq*5]
    add           dstq, posq        ; dst += pos5
    jmp .write_loop_entry
.write_loop:
    add            rbq, 5
    cmp           refb, byte [rbq+4]
    jne .xloop
    cmp            mvd, [rbq]
    jne .xloop
    add           dstq, 5
    inc          xposd
.write_loop_entry:
    mov           r12d, xd
    and           r12d, ~7
    lea            r5d, [r12-8]
    cmp            r5d, xstartd
    cmovs          r5d, xstartd     ; x_proj_start
    cmp          xposd, r5d
    jl .next_xpos
    add           r12d, 16
    cmp          xendd, r12d
    cmovs         r12d, xendd       ; x_proj_end
    cmp          xposd, r12d
    jge .next_xpos
    mov       [dstq+0], mvd
    mov  byte [dstq+4], ref2refb
.next_xpos:
    inc             xd
    cmp             xd, xendid
    jl .write_loop
.next_y:
 DEFINE_ARGS y, src, xstart, xend, ystart, _, n7, _, _, x, xendi, _, _, _, n
    add           srcq, [rsp+0x18] ; stride5
    inc             yd
    cmp             yd, [rsp+0x38] ; yend
    jne .yloop
    mov             nd, [rsp+0x14]
    mov        ystartd, [rsp+0x24]
.next_n:
    add            n7d, 7
    inc             nd
    cmp             nd, [rsp+0x0c] ; n_mfmvs
    jne .nloop
.ret:
    RET
.next_x:
 DEFINE_ARGS y, src, xstart, xend, _, _, n7, mv, ref, x, xendi, _, _, rb, _
    add            rbq, 5
    cmp           refb, byte [rbq+4]
    jne .xloop
    cmp            mvd, [rbq]
    jne .xloop
.next_x_bad_pos_y:
    inc             xd
    cmp             xd, xendid
    jl .next_x
    jmp .next_y
.next_x_bad_ref:
    inc             xd
    cmp             xd, xendid
    jl .xloop
    jmp .next_y

INIT_YMM avx2
; refmvs_temporal_block *rp, ptrdiff_t stride,
; refmvs_block **rr, uint8_t *ref_sign,
; int col_end8, int row_end8, int col_start8, int row_start8
cglobal save_tmvs, 4, 13, 10, rp, stride, rr, ref_sign, \
                              xend, yend, xstart, ystart
%define base r12-.write1
    lea            r12, [.write1]
    movifnidn    xendd, xendm
    movifnidn    yendd, yendm
    mov        xstartd, xstartm
    mov        ystartd, ystartm
    vpbroadcastq    m4, [ref_signq]
    vpbroadcastq    m3, [base+save_ref_shuf+8]
    vpbroadcastq    m5, [base+save_cond0]
    vpbroadcastq    m6, [base+save_cond1]
    vpbroadcastd    m7, [base+pb_128]
    mova            m8, [base+save_pack0]
    mova            m9, [base+save_pack1]
    psllq           m4, 8
    lea            r9d, [xendq*5]
    lea        xstartd, [xstartq*5]
    sub          yendd, ystartd
    add        ystartd, ystartd
    lea        strideq, [strideq*5]
    sub        xstartq, r9
    add          xendd, r9d
    add            rpq, r9
 DEFINE_ARGS rp, stride, rr, x, xend, h, xstart, ystart, b, cand
.loop_y:
    and        ystartd, 30
    mov             xq, xstartq
    mov             bq, [rrq+ystartq*8]
    add        ystartd, 2
    lea             bq, [bq+xendq*4]
.loop_x:
    imul         candq, xq, 0x9999
    sar          candq, 16                   ; x / 5 * 3
    movzx         r10d, byte [bq+candq*8+22] ; cand_b->bs
    movu           xm0, [bq+candq*8+12]      ; cand_b
    movzx         r11d, byte [base+save_tmvs_avx2_table+r10*2+0]
    movzx         r10d, byte [base+save_tmvs_avx2_table+r10*2+1]
    add            r10, r12
    add          candq, r11
    jge .calc
    vinserti128     m0, [bq+candq*8+12], 1
    movzx         r11d, byte [bq+candq*8+22]
    movzx         r11d, byte [base+save_tmvs_avx2_table+r11*2+1]
    add            r11, r12
.calc:
    pshufb          m1, m0, m3
    pabsw           m2, m0
    pshufb          m1, m4, m1  ; ref > 0 && res_sign[ref - 1]
    psrlw           m2, 12      ; (abs(mv.x) | abs(mv.y)) < 4096
    pcmpgtd         m1, m2
    pshufd          m2, m1, q2301
    pand            m1, m5      ; b0.cond0 b1.cond0
    pand            m2, m6      ; b0.cond1 b1.cond1
    por             m1, m2      ; b0.shuf b1.shuf
    pxor            m1, m7      ; if cond0|cond1 == 0 => zero out
    pshufb          m0, m1
    call           r10
    jge .next_line
    vextracti128   xm0, m0, 1
    call           r11
    jl .loop_x
.next_line:
    add            rpq, strideq
    dec             hd
    jg .loop_y
    RET
.write1:
    movd   [rpq+xq+ 0], xm0
    pextrb [rpq+xq+ 4], xm0, 4
    add             xq, 5*1
    ret
.write2:
    movq    [rpq+xq+0], xm0
    psrlq          xm1, xm0, 8
    movd    [rpq+xq+6], xm1
    add             xq, 5*2
    ret
.write4:
    pshufb         xm1, xm0, xm8
    movu   [rpq+xq+ 0], xm1
    psrlq          xm1, 8
    movd   [rpq+xq+16], xm1
    add             xq, 5*4
    ret
.write8:
    vinserti128     m1, m0, xm0, 1
    pshufb          m1, m8
    movu   [rpq+xq+ 0], m1
    psrldq         xm1, 2
    movq   [rpq+xq+32], xm1
    add             xq, 5*8
    ret
.write16:
    vinserti128     m1, m0, xm0, 1
    pshufb          m2, m1, m8
    movu   [rpq+xq+ 0], m2
    pshufb          m1, m9
    movu   [rpq+xq+32], m1
    shufps         xm2, xm1, q1021
    movu   [rpq+xq+64], xm2
    add             xq, 5*16
    ret

cglobal splat_mv, 4, 5, 3, rr, a, bx4, bw4, bh4
    add           bx4d, bw4d
    tzcnt         bw4d, bw4d
    vbroadcasti128  m0, [aq]
    lea             aq, [splat_mv_avx2_table]
    lea           bx4q, [bx4q*3-32]
    movsxd        bw4q, [aq+bw4q*4]
    pshufb          m0, [splat_mv_shuf]
    movifnidn     bh4d, bh4m
    pshufd          m1, m0, q2102
    pshufd          m2, m0, q1021
    add           bw4q, aq
.loop:
    mov             aq, [rrq]
    add            rrq, gprsize
    lea             aq, [aq+bx4q*4]
    jmp           bw4q
.w32:
    mova     [aq-32*8], m0
    mova     [aq-32*7], m1
    mova     [aq-32*6], m2
    mova     [aq-32*5], m0
    mova     [aq-32*4], m1
    mova     [aq-32*3], m2
.w16:
    mova     [aq-32*2], m0
    mova     [aq-32*1], m1
    mova     [aq+32*0], m2
.w8:
    mova     [aq+32*1], m0
    mova     [aq+32*2], m1
    mova     [aq+32*3], m2
    dec           bh4d
    jg .loop
    RET
.w4:
    movu      [aq+ 80], m0
    mova      [aq+112], xm1
    dec           bh4d
    jg .loop
    RET
.w2:
    movu      [aq+104], xm0
    movq      [aq+120], xm2
    dec           bh4d
    jg .loop
    RET
.w1:
    movq      [aq+116], xm0
    movd      [aq+124], xm1
    dec           bh4d
    jg .loop
    RET

INIT_ZMM avx512icl
; refmvs_temporal_block *rp, ptrdiff_t stride,
; refmvs_block **rr, uint8_t *ref_sign,
; int col_end8, int row_end8, int col_start8, int row_start8
cglobal save_tmvs, 4, 15, 10, rp, stride, rr, ref_sign, \
                              xend, yend, xstart, ystart
%define base r14-.write1
    lea            r14, [.write1]
    movifnidn    xendd, xendm
    movifnidn    yendd, yendm
    mov        xstartd, xstartm
    mov        ystartd, ystartm
    psllq           m4, [ref_signq]{bcstq}, 8
    vpbroadcastq    m3, [base+save_ref_shuf+8]
    vbroadcasti32x4 m5, [base+cond_shuf512]
    vbroadcasti32x4 m6, [base+save_cond0]
    vpbroadcastd    m7, [base+pb_128]
    mova            m8, [base+save_pack0]
    movu           xm9, [base+save_pack0+4]
    lea            r9d, [xendq*5]
    lea        xstartd, [xstartq*5]
    sub          yendd, ystartd
    add        ystartd, ystartd
    lea        strideq, [strideq*5]
    sub        xstartq, r9
    add          xendd, r9d
    add            rpq, r9
    mov           r10d, 0x1f
    kmovb           k2, r10d
 DEFINE_ARGS rp, stride, rr, x, xend, h, xstart, ystart, b, cand
.loop_y:
    and        ystartd, 30
    mov             xq, xstartq
    mov             bq, [rrq+ystartq*8]
    add        ystartd, 2
    lea             bq, [bq+xendq*4]
.loop_x:
    imul         candq, xq, 0x9999
    sar          candq, 16                   ; x / 5 * 3
    movzx         r10d, byte [bq+candq*8+22] ; cand_b->bs
    movu           xm0, [bq+candq*8+12]      ; cand_b
    movzx         r11d, byte [base+save_tmvs_avx512icl_table+r10*2+0]
    movzx         r10d, byte [base+save_tmvs_avx512icl_table+r10*2+1]
    add            r10, r14
    add          candq, r11
    jge .calc
    movzx         r11d, byte [bq+candq*8+22]
    vinserti32x4   ym0, [bq+candq*8+12], 1
    movzx         r12d, byte [base+save_tmvs_avx512icl_table+r11*2+0]
    movzx         r11d, byte [base+save_tmvs_avx512icl_table+r11*2+1]
    add            r11, r14
    add          candq, r12
    jge .calc
    movzx         r12d, byte [bq+candq*8+22]
    vinserti32x4    m0, [bq+candq*8+12], 2
    movzx         r13d, byte [base+save_tmvs_avx512icl_table+r12*2+0]
    movzx         r12d, byte [base+save_tmvs_avx512icl_table+r12*2+1]
    add            r12, r14
    add          candq, r13
    jge .calc
    vinserti32x4    m0, [bq+candq*8+12], 3
    movzx         r13d, byte [bq+candq*8+22]
    movzx         r13d, byte [base+save_tmvs_avx512icl_table+r13*2+1]
    add            r13, r14
.calc:
    pshufb          m1, m0, m3
    pabsw           m2, m0
    pshufb          m1, m4, m1      ; ref > 0 && res_sign[ref - 1]
    psrlw           m2, 12          ; (abs(mv.x) | abs(mv.y)) < 4096
    psubd           m2, m1
    pshufb          m2, m5           ; c0 c1 c1 c0
    pand            m2, m6
    punpckhqdq      m1, m2, m2
    vpternlogd      m1, m2, m7, 0x56 ; (c0shuf | c1shuf) ^ 0x80
    pshufb          m2, m0, m1
    mova           xm0, xm2
    call           r10
    jge .next_line
    vextracti32x4  xm0, m2, 1
    call           r11
    jge .next_line
    vextracti32x4  xm0, m2, 2
    call           r12
    jge .next_line
    vextracti32x4  xm0, m2, 3
    call           r13
    jl .loop_x
.next_line:
    add            rpq, strideq
    dec             hd
    jg .loop_y
    RET
.write1:
    vmovdqu8 [rpq+xq]{k2}, xm0
    add             xq, 5*1
    ret
.write2:
    pshufb         xm0, xm8
    vmovdqu16 [rpq+xq]{k2}, xm0
    add             xq, 5*2
    ret
.write4:
    vpermb         ym0, ym8, ym0
    vmovdqu32 [rpq+xq]{k2}, ym0
    add             xq, 5*4
    ret
.write8:
    vpermb          m0, m8, m0
    vmovdqu64 [rpq+xq]{k2}, m0
    add             xq, 5*8
    ret
.write16:
    vpermb          m1, m8, m0
    movu   [rpq+xq+ 0], m1
    pshufb         xm0, xm9
    movu   [rpq+xq+64], xm0
    add             xq, 5*16
    ret

INIT_ZMM avx512icl
cglobal splat_mv, 4, 7, 3, rr, a, bx4, bw4, bh4
    vbroadcasti32x4    m0, [aq]
    lea                r1, [splat_mv_avx512icl_table]
    tzcnt            bw4d, bw4d
    lea              bx4d, [bx4q*3]
    pshufb             m0, [splat_mv_shuf]
    movsxd           bw4q, [r1+bw4q*4]
    mov               r6d, bh4m
    add              bw4q, r1
    lea               rrq, [rrq+r6*8]
    mov               r1d, 0x3f
    neg                r6
    kmovb              k1, r1d
    jmp              bw4q
.w1:
    mov                r1, [rrq+r6*8]
    vmovdqu16 [r1+bx4q*4]{k1}, xm0
    inc                r6
    jl .w1
    RET
.w2:
    mov                r1, [rrq+r6*8]
    vmovdqu32 [r1+bx4q*4]{k1}, ym0
    inc                r6
    jl .w2
    RET
.w4:
    mov                r1, [rrq+r6*8]
    vmovdqu64 [r1+bx4q*4]{k1}, m0
    inc                r6
    jl .w4
    RET
.w8:
    pshufd            ym1, ym0, q1021
.w8_loop:
    mov                r1, [rrq+r6*8+0]
    mov                r3, [rrq+r6*8+8]
    movu   [r1+bx4q*4+ 0], m0
    mova   [r1+bx4q*4+64], ym1
    movu   [r3+bx4q*4+ 0], m0
    mova   [r3+bx4q*4+64], ym1
    add                r6, 2
    jl .w8_loop
    RET
.w16:
    pshufd             m1, m0, q1021
    pshufd             m2, m0, q2102
.w16_loop:
    mov                r1, [rrq+r6*8+0]
    mov                r3, [rrq+r6*8+8]
    mova [r1+bx4q*4+64*0], m0
    mova [r1+bx4q*4+64*1], m1
    mova [r1+bx4q*4+64*2], m2
    mova [r3+bx4q*4+64*0], m0
    mova [r3+bx4q*4+64*1], m1
    mova [r3+bx4q*4+64*2], m2
    add                r6, 2
    jl .w16_loop
    RET
.w32:
    pshufd             m1, m0, q1021
    pshufd             m2, m0, q2102
.w32_loop:
    mov                r1, [rrq+r6*8]
    lea                r1, [r1+bx4q*4]
    mova        [r1+64*0], m0
    mova        [r1+64*1], m1
    mova        [r1+64*2], m2
    mova        [r1+64*3], m0
    mova        [r1+64*4], m1
    mova        [r1+64*5], m2
    inc                r6
    jl .w32_loop
    RET
%endif ; ARCH_X86_64