openh264-sys2 0.9.7

Low-level bindings for OpenH264.
Documentation
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
/*!
 * \copy
 *     Copyright (c)  2009-2018, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * 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 HOLDER 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.
 *
 *
 * \file    vaa_mmi.c
 *
 * \brief   Loongson optimization
 *
 * \date    23/07/2018 Created
 *
 *************************************************************************************
 */
#include <stdint.h>
#include "asmdefs_mmi.h"

//f4 is 0x1, f6 is 0x8
#define WELS_MAX_REG_MMI(f0, f2, f4, f6) \
  "punpckhwd  $f4, "#f0", "#f0"    \n\t" \
  "punpckhwd  $f6, "#f2", "#f2"    \n\t" \
  "pmaxub     "#f0", "#f0", $f4    \n\t" \
  "pmaxub     "#f2", "#f2", $f6    \n\t" \
  "pshufh     $f4, "#f0", "#f4"    \n\t" \
  "pshufh     $f6, "#f2", "#f4"    \n\t" \
  "pmaxub     "#f0", "#f0", $f4    \n\t" \
  "pmaxub     "#f2", "#f2", $f6    \n\t" \
  "dsrl       $f4, "#f0", "#f6"    \n\t" \
  "dsrl       $f6, "#f2", "#f6"    \n\t" \
  "pmaxub     "#f0", "#f0", $f4    \n\t" \
  "pmaxub     "#f2", "#f2", $f6    \n\t"

#define WELS_SAD_SD_MAD_16x1_MMI(f0, f2, f4, f6, f8, f10, f12, f14, r0, r1, r2) \
  "gslqc1     $f6, $f4, 0x0("#r0")                \n\t" \
  "gslqc1     $f10, $f8, 0x0("#r1")               \n\t" \
  "pasubub    $f12, $f4, $f0                      \n\t" \
  "pasubub    $f14, $f6, $f2                      \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "paddw      "#f4", "#f4", $f12                  \n\t" \
  "paddw      "#f6", "#f6", $f14                  \n\t" \
  "pasubub    $f12, $f8, $f0                      \n\t" \
  "pasubub    $f14, $f10, $f2                     \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "paddw      "#f8", "#f8", $f12                  \n\t" \
  "paddw      "#f10", "#f10", $f14                \n\t" \
  "pasubub    $f12, $f4, $f8                      \n\t" \
  "pasubub    $f14, $f6, $f10                     \n\t" \
  "pmaxub     "#f12", "#f12", $f12                \n\t" \
  "pmaxub     "#f14", "#f14", $f14                \n\t" \
  "pasubub    $f12, $f12, $f0                     \n\t" \
  "pasubub    $f14, $f14, $f2                     \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "paddw      "#f0", "#f0", $f12                  \n\t" \
  "paddw      "#f2", "#f2", $f14                  \n\t" \
  PTR_ADDU   ""#r0", "#r0", "#r2"                 \n\t" \
  PTR_ADDU   ""#r1", "#r1", "#r2"                 \n\t"

#define WELS_SAD_16x2_MMI(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, r1, r2, r3) \
  "gslqc1     "#f1",  "#f2",  0x00("#r1")         \n\t" \
  "gslqc1     "#f3",  "#f4",  0x00("#r2")         \n\t" \
  PTR_ADDU    ""#r1", "#r1",  "#r3"               \n\t" \
  "gslqc1     "#f5",  "#f6",  0x00("#r1")         \n\t" \
  PTR_ADDU    ""#r2", "#r2",  "#r3"               \n\t" \
  "gslqc1     "#f7",  "#f8",  0x00("#r2")         \n\t" \
  "pasubub    "#f1",  "#f1",  "#f3"               \n\t" \
  "pasubub    "#f2",  "#f2",  "#f4"               \n\t" \
  "biadd      "#f1",  "#f1"                       \n\t" \
  "biadd      "#f2",  "#f2"                       \n\t" \
  "pasubub    "#f5",  "#f5",  "#f7"               \n\t" \
  "pasubub    "#f6",  "#f6",  "#f8"               \n\t" \
  "biadd      "#f5",  "#f5"                       \n\t" \
  "biadd      "#f6",  "#f6"                       \n\t" \
  "paddw      "#f9",  "#f9",  "#f1"               \n\t" \
  "paddw      "#f9",  "#f9",  "#f5"               \n\t" \
  "paddw      "#f10", "#f10", "#f2"               \n\t" \
  "paddw      "#f10", "#f10", "#f6"               \n\t" \
  PTR_ADDU    ""#r1", "#r1",  "#r3"               \n\t" \
  PTR_ADDU    ""#r2", "#r2",  "#r3"               \n\t"

#define WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI(r0, r1, r2) \
  "gslqc1     $f6, $f4, 0x0("#r0")                \n\t" \
  "gslqc1     $f10, $f8, 0x0("#r1")               \n\t" \
  "pasubub    $f12, $f4, $f8                      \n\t" \
  "pasubub    $f14, $f6, $f10                     \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "paddw      $f28, $f28, $f12                    \n\t" \
  "paddw      $f30, $f30, $f14                    \n\t" \
  "pasubub    $f12, $f4, $f8                      \n\t" \
  "pasubub    $f14, $f6, $f10                     \n\t" \
  "pasubub    $f8, $f4, $f0                       \n\t" \
  "pasubub    $f10, $f6, $f2                      \n\t" \
  "biadd      $f8, $f8                            \n\t" \
  "biadd      $f10, $f10                          \n\t" \
  "paddw      $f24, $f24, $f8                     \n\t" \
  "paddw      $f26, $f26, $f10                    \n\t" \
  "punpcklbh  $f8, $f6, $f2                       \n\t" \
  "punpckhbh  $f10, $f6, $f2                      \n\t" \
  "punpckhbh  $f6, $f4, $f0                       \n\t" \
  "punpcklbh  $f4, $f4, $f0                       \n\t" \
  "pmaddhw    $f4, $f4, $f4                       \n\t" \
  "pmaddhw    $f6, $f6, $f6                       \n\t" \
  "pmaddhw    $f8, $f8, $f8                       \n\t" \
  "pmaddhw    $f10, $f10, $f10                    \n\t" \
  "paddw      $f20, $f20, $f4                     \n\t" \
  "paddw      $f22, $f22, $f6                     \n\t" \
  "paddw      $f20, $f20, $f8                     \n\t" \
  "paddw      $f22, $f22, $f10                    \n\t" \
  "punpcklbh  $f4, $f12, $f0                      \n\t" \
  "punpckhbh  $f6, $f12, $f0                      \n\t" \
	"punpcklbh  $f12, $f14, $f2                     \n\t" \
	"punpckhbh  $f14, $f14, $f2                     \n\t" \
  "pmaddhw    $f4, $f4, $f4                       \n\t" \
  "pmaddhw    $f6, $f6, $f6                       \n\t" \
  "pmaddhw    $f12, $f12, $f12                    \n\t" \
  "pmaddhw    $f14, $f14, $f14                    \n\t" \
  "paddw      $f16, $f16, $f4                     \n\t" \
  "paddw      $f18, $f18, $f6                     \n\t" \
  "paddw      $f16, $f16, $f12                    \n\t" \
  "paddw      $f18, $f18, $f14                    \n\t" \
  PTR_ADDU   ""#r0", "#r0", "#r2"                 \n\t" \
  PTR_ADDU   ""#r1", "#r1", "#r2"                 \n\t"

#define WELS_SAD_BGD_SQDIFF_16x1_MMI(f0, f2, f4, f6, f8, f10, f12, f14, r0, r1, r2) \
  "gslqc1     $f6, $f4, 0x0("#r0")                \n\t" \
  "punpcklbh  $f8, $f4, $f0                       \n\t" \
  "punpckhbh  $f10, $f4, $f0                      \n\t" \
  "punpcklbh  $f12, $f6, $f2                      \n\t" \
  "punpckhbh  $f14, $f6, $f2                      \n\t" \
  "pmaddhw    $f8, $f8, $f8                       \n\t" \
  "pmaddhw    $f10, $f10, $f10                    \n\t" \
  "pmaddhw    $f12, $f12, $f12                    \n\t" \
  "pmaddhw    $f14, $f14, $f14                    \n\t" \
  "paddw      $f8, $f8, $f12                      \n\t" \
  "paddw      $f10, $f10, $f14                    \n\t" \
  "punpckhwd  $f12, $f0, $f8                      \n\t" \
  "punpckhwd  $f14, $f0, $f10                     \n\t" \
  "punpcklwd  $f8, $f0, $f8                       \n\t" \
  "punpcklwd  $f10, $f0, $f10                     \n\t" \
  "paddw      $f8, $f8, $f12                      \n\t" \
  "paddw      $f10, $f10, $f14                    \n\t" \
  "paddw      "#f0", "#f0", $f8                   \n\t" \
  "paddw      "#f2", "#f2", $f10                  \n\t" \
  "gslqc1     $f10, $f8, 0x0("#r1")               \n\t" \
  "pasubub    $f12, $f4, $f0                      \n\t" \
  "pasubub    $f14, $f6, $f2                      \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "paddw      "#f4", "#f4", $f12                  \n\t" \
  "paddw      "#f6", "#f6", $f14                  \n\t" \
  "pasubub    $f12, $f8, $f0                      \n\t" \
  "pasubub    $f14, $f10, $f2                     \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "punpcklwd  $f14, $f14, $f14                    \n\t" \
  "punpckhwd  $f14, $f12, $f14                    \n\t" \
  "punpcklwd  $f12, $f0, $f12                     \n\t" \
  "paddw      "#f4", "#f4", $f12                  \n\t" \
  "paddw      "#f6", "#f6", $f14                  \n\t" \
  "pasubub    $f12, $f4, $f8                      \n\t" \
  "pasubub    $f14, $f6, $f10                     \n\t" \
  "pmaxub     "#f8", "#f8", $f12                  \n\t" \
  "pmaxub     "#f10", "#f10", $f14                \n\t" \
  "paddw      $f4, $f0, $f12                      \n\t" \
  "paddw      $f6, $f0, $f14                      \n\t" \
  "pasubub    $f12, $f12, $f0                     \n\t" \
  "pasubub    $f14, $f14, $f2                     \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "paddw      "#f0", "#f0", $f12                  \n\t" \
  "paddw      "#f2", "#f2", $f14                  \n\t" \
  "paddw      $f12, $f0, $f4                      \n\t" \
  "paddw      $f14, $f0, $f6                      \n\t" \
  "punpcklbh  $f4, $f12, $f0                      \n\t" \
  "punpckhbh  $f6, $f12, $f0                      \n\t" \
  "punpcklbh  $f12, $f14, $f2                     \n\t" \
  "punpckhbh  $f14, $f14, $f2                     \n\t" \
  "pmaddhw    $f4, $f4, $f4                       \n\t" \
  "pmaddhw    $f6, $f6, $f6                       \n\t" \
  "pmaddhw    $f12, $f12, $f12                    \n\t" \
  "pmaddhw    $f14, $f14, $f14                    \n\t" \
  "paddw      "#f12", "#f12", $f4                 \n\t" \
  "paddw      "#f14", "#f14", $f6                 \n\t" \
  "paddw      "#f12", "#f12", $f12                \n\t" \
  "paddw      "#f14", "#f14", $f14                \n\t" \
  PTR_ADDU   ""#r0", "#r0", "#r2"                 \n\t" \
  PTR_ADDU   ""#r1", "#r1", "#r2"                 \n\t"

#define WELS_SAD_SUM_SQSUM_16x1_MMI(r0, r1, r2) \
  "gslqc1     $f6, $f4, 0x0("#r0")                \n\t" \
  "gslqc1     $f10, $f8, 0x0("#r1")               \n\t" \
  "pasubub    $f12, $f4, $f8                      \n\t" \
  "pasubub    $f14, $f6, $f10                     \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "paddw      $f24, $f24, $f12                    \n\t" \
  "paddw      $f26, $f26, $f14                    \n\t" \
  "pasubub    $f12, $f4, $f0                      \n\t" \
  "pasubub    $f14, $f6, $f2                      \n\t" \
  "biadd      $f12, $f12                          \n\t" \
  "biadd      $f14, $f14                          \n\t" \
  "paddw      $f20, $f20, $f12                    \n\t" \
  "paddw      $f22, $f22, $f14                    \n\t" \
  "punpcklbh  $f8, $f6, $f2                       \n\t" \
  "punpckhbh  $f10, $f6, $f2                      \n\t" \
  "punpckhbh  $f6, $f4, $f0                       \n\t" \
  "punpcklbh  $f4, $f4, $f0                       \n\t" \
  "pmaddhw    $f4, $f4, $f4                       \n\t" \
  "pmaddhw    $f6, $f6, $f6                       \n\t" \
  "pmaddhw    $f8, $f8, $f8                       \n\t" \
  "pmaddhw    $f10, $f10, $f10                    \n\t" \
  "paddw      $f16, $f16, $f4                     \n\t" \
  "paddw      $f18, $f18, $f6                     \n\t" \
  "paddw      $f16, $f16, $f8                     \n\t" \
  "paddw      $f18, $f18, $f10                    \n\t" \
  PTR_ADDU   ""#r0", "#r0", "#r2"                 \n\t" \
  PTR_ADDU   ""#r1", "#r1", "#r2"                 \n\t"

void VAACalcSad_mmi(const uint8_t* pCurData, const uint8_t* pRefData,
                    int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
                    int32_t* pFrameSad, int32_t* pSad8x8) {
  double ftmp[13];
  uint64_t tmp[2];
  mips_reg addr[3];

  __asm__ volatile (
    ".set       arch=loongson3a                                     \n\t"
    PTR_SRL    "%[iPicWidth],   %[iPicWidth],   0x04                \n\t"
    PTR_SRL    "%[iPicHeight],  %[iPicHeight],  0x04                \n\t"
    "move       %[addr2],       %[iPicStride]                       \n\t"
    PTR_SLL    "%[iPicStride],  %[iPicStride],  0x04                \n\t"
    "xor        %[ftmp0],       %[ftmp0],       %[ftmp0]            \n\t"
    "xor        %[ftmp11],      %[ftmp11],      %[ftmp11]           \n\t"
    "xor        %[ftmp12],      %[ftmp12],      %[ftmp12]           \n\t"
    "1:                                                             \n\t"
    "move       %[addr0],       %[pCurData]                         \n\t"
    "move       %[addr1],       %[pRefData]                         \n\t"
    "move       %[tmp0],        %[iPicWidth]                        \n\t"
    "2:                                                             \n\t"
    "xor        %[ftmp9],       %[ftmp9],       %[ftmp9]            \n\t"
    "xor        %[ftmp10],      %[ftmp10],      %[ftmp10]           \n\t"
    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
                      %[addr0], %[addr1], %[addr2])
    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
                      %[addr0], %[addr1], %[addr2])
    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
                      %[addr0], %[addr1], %[addr2])
    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
                      %[addr0], %[addr1], %[addr2])
    "paddw      %[ftmp11],      %[ftmp11],      %[ftmp9]            \n\t"
    "paddw      %[ftmp12],      %[ftmp12],      %[ftmp10]           \n\t"
    "swc1       %[ftmp10],      0x00(%[pSad8x8])                    \n\t"
    "swc1       %[ftmp9],       0x04(%[pSad8x8])                    \n\t"

    "xor        %[ftmp9],       %[ftmp9],       %[ftmp9]            \n\t"
    "xor        %[ftmp10],      %[ftmp10],      %[ftmp10]           \n\t"
    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
                      %[addr0], %[addr1], %[addr2])
    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
                      %[addr0], %[addr1], %[addr2])
    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
                      %[addr0], %[addr1], %[addr2])
    WELS_SAD_16x2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5],
                      %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10],
                      %[addr0], %[addr1], %[addr2])
    "paddw      %[ftmp11],      %[ftmp11],      %[ftmp9]            \n\t"
    "paddw      %[ftmp12],      %[ftmp12],      %[ftmp10]           \n\t"
    "swc1       %[ftmp10],      0x08(%[pSad8x8])                    \n\t"
    "swc1       %[ftmp9],       0x0c(%[pSad8x8])                    \n\t"

    PTR_ADDU   "%[pSad8x8],     %[pSad8x8],     0x10                \n\t"
    PTR_SUBU   "%[addr0],       %[addr0],       %[iPicStride]       \n\t"
    PTR_SUBU   "%[addr1],       %[addr1],       %[iPicStride]       \n\t"
    PTR_ADDI   "%[tmp0],        %[tmp0],        -0x01               \n\t"
    PTR_ADDU   "%[addr0],       %[addr0],       0x10                \n\t"
    PTR_ADDU   "%[addr1],       %[addr1],       0x10                \n\t"
    "bnez       %[tmp0],        2b                                  \n\t"

    PTR_ADDI   "%[iPicHeight],  %[iPicHeight],  -0x01               \n\t"
    PTR_ADDU   "%[pCurData],    %[pCurData],    %[iPicStride]       \n\t"
    PTR_ADDU   "%[pRefData],    %[pRefData],    %[iPicStride]       \n\t"
    "bnez       %[iPicHeight],  1b                                  \n\t"

    "paddw      %[ftmp11],      %[ftmp11],      %[ftmp12]           \n\t"
    "swc1       %[ftmp11],      0x00(%[pFrameSad])                  \n\t"
    : [ftmp0]"=&f"(ftmp[0]),            [ftmp1]"=&f"(ftmp[1]),
      [ftmp2]"=&f"(ftmp[2]),            [ftmp3]"=&f"(ftmp[3]),
      [ftmp4]"=&f"(ftmp[4]),            [ftmp5]"=&f"(ftmp[5]),
      [ftmp6]"=&f"(ftmp[6]),            [ftmp7]"=&f"(ftmp[7]),
      [ftmp8]"=&f"(ftmp[8]),            [ftmp9]"=&f"(ftmp[9]),
      [ftmp10]"=&f"(ftmp[10]),          [ftmp11]"=&f"(ftmp[11]),
      [ftmp12]"=&f"(ftmp[12]),          [tmp0]"=&r"(tmp[0]),
      [addr0]"=&r"(addr[0]),            [addr1]"=&r"(addr[1]),
      [pCurData]"+&r"(pCurData),        [pRefData]"+&r"(pRefData),
      [iPicHeight]"+&r"(iPicHeight),    [iPicWidth]"+&r"(iPicWidth),
      [pSad8x8]"+&r"(pSad8x8),          [iPicStride]"+&r"(iPicStride),
      [addr2]"=&r"(addr[2])
    : [pFrameSad]"r"(pFrameSad)
    : "memory"
  );
}

void VAACalcSadBgd_mmi(const uint8_t *cur_data, const uint8_t *ref_data,
                       int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
                       int32_t *psadframe, int32_t *psad8x8, int32_t *p_sd8x8,
                       uint8_t *p_mad8x8) {
  BACKUP_REG;
  __asm__ volatile (
    ".set       arch=loongson3a                           \n\t"
    "move       $15, %[cur_data]                          \n\t"
    "dsrl       %[iPicWidth], %[iPicWidth], 0x4           \n\t"
    "dsrl       %[iPicHeight], %[iPicHeight], 0x4         \n\t"
    "dsll       $13, %[iPicStride], 0x4                   \n\t"
    "xor        $f0, $f0, $f0                             \n\t"
    "xor        $f2, $f2, $f2                             \n\t"
    "xor        $14, $14, $14                             \n\t"
    "1:                                                   \n\t"
    "move       $9, %[iPicWidth]                          \n\t"
    "move       $10, $15                                  \n\t"
    "move       $11, %[ref_data]                          \n\t"
    "2:                                                   \n\t"
    "xor        $f28, $f28, $f28                          \n\t"
    "xor        $f30, $f30, $f30                          \n\t"
    "xor        $f24, $f24, $f24                          \n\t"
    "xor        $f26, $f26, $f26                          \n\t"
    "xor        $f20, $f20, $f20                          \n\t"
    "xor        $f22, $f22, $f22                          \n\t"
    "xor        $f16, $f16, $f16                          \n\t"
    "xor        $f18, $f18, $f18                          \n\t"
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])

    "dli        $8, 0x1                                   \n\t"
    "dmtc1      $8, $f8                                   \n\t"
    "dli        $8, 0x8                                   \n\t"
    "dmtc1      $8, $f10                                  \n\t"
    WELS_MAX_REG_MMI($f16, $f18, $f8, $f10)

    "dmfc1      $8, $f16                                  \n\t"
    "sb         $8, 0x0(%[p_mad8x8])                      \n\t"
    "dmfc1      $8, $f18                                  \n\t"
    "sb         $8, 0x1(%[p_mad8x8])                      \n\t"
    PTR_ADDIU  "%[p_mad8x8], %[p_mad8x8], 0x2             \n\t"

    "xor        $f16, $f16, $f16                          \n\t"
    "xor        $f18, $f18, $f18                          \n\t"
    "punpcklwd  $f30, $f30, $f30                          \n\t"
    "punpcklwd  $f26, $f26, $f26                          \n\t"
    "punpcklwd  $f22, $f22, $f22                          \n\t"

    "punpckhwd  $f30, $f28, $f30                          \n\t"
    "punpckhwd  $f26, $f24, $f26                          \n\t"
    "punpckhwd  $f22, $f20, $f22                          \n\t"

    "punpcklwd  $f28, $f16, $f28                          \n\t"
    "punpcklwd  $f24, $f16, $f24                          \n\t"
    "punpcklwd  $f20, $f16, $f20                          \n\t"

    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])
    WELS_SAD_SD_MAD_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16, $f18,
                             $15, %[ref_data], %[iPicStride])

    "dli        $8, 0x1                                   \n\t"
    "dmtc1      $8, $f8                                   \n\t"
    "dli        $8, 0x8                                   \n\t"
    "dmtc1      $8, $f10                                  \n\t"
    WELS_MAX_REG_MMI($f16, $f18, $f8, $f10)

    "dmfc1      $8, $f16                                  \n\t"
    "sb         $8, 0x0(%[p_mad8x8])                      \n\t"
    "dmfc1      $8, $f18                                  \n\t"
    "sb         $8, 0x1(%[p_mad8x8])                      \n\t"
    "punpckhwd  $f4, $f28, $f30                           \n\t"
    PTR_ADDIU  "%[p_mad8x8], %[p_mad8x8], 0x2             \n\t"

    "punpcklwd  $f6, $f28, $f30                           \n\t"
    "gssqc1     $f6, $f4, 0x0(%[psad8x8])                 \n\t"
    PTR_ADDIU  "%[psad8x8], %[psad8x8], 0x10              \n\t"

    "paddw      $f6, $f6, $f30                            \n\t"
    "paddw      $f4, $f4, $f28                            \n\t"
    "punpckhwd  $f8, $f6, $f6                             \n\t"
    "paddw      $f4, $f4, $f8                             \n\t"
    "dmtc1      $14, $f6                                  \n\t"
    "paddw      $f6, $f6, $f4                             \n\t"
    "dmfc1      $14, $f6                                  \n\t"

    "psubw      $f24, $f24, $f20                          \n\t"
    "psubw      $f26, $f26, $f22                          \n\t"
    "punpckhwd  $f4, $f24, $f26                           \n\t"
    "punpcklwd  $f6, $f24, $f26                           \n\t"
    "gssqc1     $f6, $f4, 0x0(%[p_sd8x8])                 \n\t"
    PTR_ADDIU  "%[p_sd8x8], %[p_sd8x8], 0x10              \n\t"

    PTR_SUBU   "$15, $15, $13                             \n\t"
    PTR_SUBU   "%[ref_data], %[ref_data], $13             \n\t"
    PTR_ADDIU  "$15, $15, 0x10                            \n\t"
    PTR_ADDIU  "%[ref_data], %[ref_data], 0x10            \n\t"

    PTR_ADDIU  "%[iPicWidth], %[iPicWidth], -0x1          \n\t"
    "bnez       %[iPicWidth], 2b                          \n\t"
    "move       %[iPicWidth], $9                          \n\t"
    "move       $15, $10                                  \n\t"
    "move       %[ref_data], $11                          \n\t"
    PTR_ADDU   "$15, $15, $13                             \n\t"
    PTR_ADDU   "%[ref_data], %[ref_data], $13             \n\t"

    PTR_ADDIU  "%[iPicHeight], %[iPicHeight], -0x1        \n\t"
    "bnez       %[iPicHeight], 1b                         \n\t"

    "swl        $14, 0x3(%[psadframe])                    \n\t"
    "swr        $14, 0x0(%[psadframe])                    \n\t"
    : [ref_data]"+&r"((unsigned char *)ref_data), [iPicWidth]"+&r"((int)iPicWidth),
      [iPicHeight]"+&r"((int)iPicHeight), [psad8x8]"+&r"((int *)psad8x8),
      [p_sd8x8]"+&r"((int *)p_sd8x8), [p_mad8x8]"+&r"((unsigned char *)p_mad8x8)
    : [cur_data]"r"((unsigned char *)cur_data), [iPicStride]"r"((int)iPicStride),
      [psadframe]"r"((int *)psadframe)
    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0", "$f2",
      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
      "$f24", "$f26", "$f28", "$f30"
  );
  RECOVER_REG;
}

void VAACalcSadSsd_mmi(const uint8_t *cur_data, const uint8_t *ref_data,
                       int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
                       int32_t *psadframe, int32_t *psad8x8, int32_t *psum16x16,
                       int32_t *psqsum16x16, int32_t *psqdiff16x16) {
  BACKUP_REG;
  __asm__ volatile (
    ".set       arch=loongson3a                           \n\t"
    "move       $15, %[cur_data]                          \n\t"
    "dsrl       %[iPicWidth], %[iPicWidth], 0x4           \n\t"
    "dsrl       %[iPicHeight], %[iPicHeight], 0x4         \n\t"
    "dsll       $13, %[iPicStride], 0x4                   \n\t"
    "xor        $f0, $f0, $f0                             \n\t"
    "xor        $f2, $f2, $f2                             \n\t"
    "xor        $12, $12, $12                             \n\t"
    "xor        $14, $14, $14                             \n\t"
    "1:                                                   \n\t"
    "move       $9, %[iPicWidth]                          \n\t"
    "move       $10, $15                                  \n\t"
    "move       $11, %[ref_data]                          \n\t"
    "2:                                                   \n\t"
    "xor        $f28, $f28, $f28                          \n\t"
    "xor        $f30, $f30, $f30                          \n\t"
    "xor        $f24, $f24, $f24                          \n\t"
    "xor        $f26, $f26, $f26                          \n\t"
    "xor        $f20, $f20, $f20                          \n\t"
    "xor        $f22, $f22, $f22                          \n\t"
    "xor        $f16, $f16, $f16                          \n\t"
    "xor        $f18, $f18, $f18                          \n\t"
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    "dmfc1      $8, $f28                                  \n\t"
    "sw         $8, 0x0(%[psad8x8])                       \n\t"
    "dmfc1      $8, $f30                                  \n\t"
    "sw         $8, 0x4(%[psad8x8])                       \n\t"
    "paddw      $f4, $f28, $f30                           \n\t"
    "dmfc1      $12, $f4                                  \n\t"
	  PTR_ADDU   "$14, $14, $12                             \n\t"

    "xor        $f28, $f28, $f28                          \n\t"
    "xor        $f30, $f30, $f30                          \n\t"
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_SQDIFF_16x1_MMI($15, %[ref_data], %[iPicStride])
    "dmfc1      $8, $f28                                  \n\t"
    "sw         $8, 0x8(%[psad8x8])                       \n\t"
    "dmfc1      $8, $f30                                  \n\t"
    "paddw      $f4, $f28, $f30                           \n\t"
    "sw         $8, 0xc(%[psad8x8])                       \n\t"
    "dmfc1      $12, $f4                                  \n\t"
	  PTR_ADDU   "$14, $14, $12                             \n\t"
    PTR_ADDIU  "%[psad8x8],   %[psad8x8],   0x10          \n\t"

    "paddw      $f24, $f24, $f26                          \n\t"
    "dmfc1      $8, $f24                                  \n\t"
    "sw         $8, 0x0(%[psum16x16])                     \n\t"
    PTR_ADDIU  "%[psum16x16], %[psum16x16], 0x4           \n\t"
    "paddw      $f24, $f20, $f22                          \n\t"
	  "punpcklwd  $f20, $f24, $f24                          \n\t"
	  "punpckhwd  $f22, $f24, $f24                          \n\t"
    "paddw      $f20, $f20, $f22                          \n\t"
    "dmfc1      $8, $f20                                  \n\t"
    "sw         $8, 0x0(%[psqsum16x16])                   \n\t"
    PTR_ADDIU  "%[psqsum16x16], %[psqsum16x16], 0x4       \n\t"

    "paddw      $f20, $f16, $f18                          \n\t"
	  "punpcklwd  $f16, $f20, $f20                          \n\t"
	  "punpckhwd  $f18, $f20, $f20                          \n\t"
    "paddw      $f16, $f16, $f18                          \n\t"
    "dmfc1      $8, $f16                                  \n\t"
    "sw         $8, 0x0(%[psqdiff16x16])                  \n\t"
    PTR_ADDIU  "%[psqdiff16x16], %[psqdiff16x16], 0x4     \n\t"

    PTR_SUBU   "$15, $15, $13                             \n\t"
    PTR_SUBU   "%[ref_data], %[ref_data], $13             \n\t"
    PTR_ADDIU  "$15, $15, 0x10                            \n\t"
    PTR_ADDIU  "%[ref_data], %[ref_data], 0x10            \n\t"

    PTR_ADDIU  "%[iPicWidth], %[iPicWidth], -0x1          \n\t"
    "bnez       %[iPicWidth], 2b                          \n\t"
    "nop                                                  \n\t"
    "move       %[iPicWidth], $9                          \n\t"
    "move       $15, $10                                  \n\t"
    "move       %[ref_data], $11                          \n\t"
    PTR_ADDU   "$15, $15, $13                             \n\t"
    PTR_ADDU   "%[ref_data], %[ref_data], $13             \n\t"

    PTR_ADDIU  "%[iPicHeight], %[iPicHeight], -0x1        \n\t"
    "bnez       %[iPicHeight], 1b                         \n\t"
    "nop                                                  \n\t"

    "sw         $14, 0x0(%[psadframe])                    \n\t"
    : [ref_data]"+&r"((unsigned char *)ref_data), [iPicWidth]"+&r"((int)iPicWidth),
      [iPicHeight]"+&r"((int)iPicHeight), [psum16x16]"+&r"((int *)psum16x16),
      [psqsum16x16]"+&r"((int *)psqsum16x16), [psqdiff16x16]"+&r"((int *)psqdiff16x16)
    : [cur_data]"r"((unsigned char *)cur_data), [iPicStride]"r"((int)iPicStride),
      [psadframe]"r"((int *)psadframe), [psad8x8]"r"((int *)psad8x8)
    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0", "$f2",
      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
      "$f24", "$f26", "$f28", "$f30"
  );
  RECOVER_REG;
}

void VAACalcSadSsdBgd_mmi(const uint8_t *cur_data, const uint8_t *ref_data,
                          int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
                          int32_t *psadframe, int32_t *psad8x8, int32_t *psum16x16,
                          int32_t *psqsum16x16, int32_t *psqdiff16x16, int32_t *p_sd8x8,
                          uint8_t *p_mad8x8) {
  BACKUP_REG;
  __asm__ volatile (
    ".set       arch=loongson3a                           \n\t"
    "move       $15, %[cur_data]                          \n\t"
    "dsrl       %[iPicWidth], %[iPicWidth], 0x4           \n\t"
    "dsrl       %[iPicHeight], %[iPicHeight], 0x4         \n\t"
    "dsll       $13, %[iPicStride], 0x4                   \n\t"
    "xor        $f0, $f0, $f0                             \n\t"
    "xor        $f2, $f2, $f2                             \n\t"
    "xor        $12, $12, $12                             \n\t"
    "xor        $14, $14, $14                             \n\t"
    "1:                                                   \n\t"
    "move       $9, %[iPicWidth]                          \n\t"
    "move       $10, $15                                  \n\t"
    "move       $11, %[ref_data]                          \n\t"
    "2:                                                   \n\t"
    "xor        $f28, $f28, $f28                          \n\t"
    "xor        $f30, $f30, $f30                          \n\t"
    "xor        $f24, $f24, $f24                          \n\t"
    "xor        $f26, $f26, $f26                          \n\t"
    "xor        $f20, $f20, $f20                          \n\t"
    "xor        $f22, $f22, $f22                          \n\t"
    "xor        $f16, $f16, $f16                          \n\t"
    "xor        $f18, $f18, $f18                          \n\t"
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])

    "dmfc1      $8, $f28                                  \n\t"
    "sw         $8, 0x0(%[psad8x8])                       \n\t"
    "dmfc1      $8, $f30                                  \n\t"
    "sw         $8, 0x4(%[psad8x8])                       \n\t"
    PTR_ADDIU  "%[psad8x8], %[psad8x8], 0x8               \n\t"

    "paddw      $f4, $f28, $f30                           \n\t"
    "dmfc1      $12, $f4                                  \n\t"
    PTR_ADDU   "$14, $14,  $12                            \n\t"

    "paddw      $f4, $f24, $f26                           \n\t"
    "dmfc1      $8, $f4                                   \n\t"
    "sw         $8, 0x0(%[psum16x16])                     \n\t"

    "punpckhwd  $f4, $f24, $f26                           \n\t"
    "punpcklwd  $f6, $f24, $f26                           \n\t"
    "psubw      $f6, $f6, $f4                             \n\t"
    "dmfc1      $8, $f6                                   \n\t"
    PTR_S      "$8, 0x0(%[p_sd8x8])                       \n\t"
    PTR_ADDIU  "%[p_sd8x8], %[p_sd8x8], 0x8               \n\t"

    "dli        $8, 0x1                                   \n\t"
    "dmtc1      $8, $f8                                   \n\t"
    "dli        $8, 0x8                                   \n\t"
    "dmtc1      $8, $f10                                  \n\t"
    WELS_MAX_REG_MMI($f20, $f22, $f8, $f10)

    "dmfc1      $8, $f20                                  \n\t"
    "sb         $8, 0x0(%[p_mad8x8])                      \n\t"
    "dmfc1      $8, $f22                                  \n\t"
    "sb         $8, 0x1(%[p_mad8x8])                      \n\t"
    PTR_ADDIU  "%[p_mad8x8], %[p_mad8x8], 0x2             \n\t"

    "xor        $f20, $f20, $f20                          \n\t"
    "xor        $f22, $f22, $f22                          \n\t"
    "punpckhwd  $f28, $f20, $f28                          \n\t"
    "xor        $f24, $f24, $f24                          \n\t"
    "xor        $f26, $f26, $f26                          \n\t"
    "punpckhwd  $f30, $f20, $f30                          \n\t"
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])
    WELS_SAD_BGD_SQDIFF_16x1_MMI($f28, $f30, $f24, $f26, $f20, $f22, $f16,
                                 $f18, $15, %[ref_data], %[iPicStride])

    "dmfc1      $8, $f28                                  \n\t"
    "sw         $8, 0x0(%[psad8x8])                       \n\t"
    "dmfc1      $8, $f30                                  \n\t"
    "sw         $8, 0x4(%[psad8x8])                       \n\t"
    PTR_ADDIU  "%[psad8x8], %[psad8x8], 0x8               \n\t"

    "paddw      $f4, $f28, $f30                           \n\t"
    "dmfc1      $12, $f4                                  \n\t"
    PTR_ADDU   "$14, $14, $12                             \n\t"

    "paddw      $f4, $f24, $f26                           \n\t"
    "dmfc1      $8, $f4                                   \n\t"
    "lw         $12, 0x0(%[psum16x16])                    \n\t"
    PTR_ADDU   "$8, $8, $12                               \n\t"
    "sw         $8, 0x0(%[psum16x16])                     \n\t"
    "xor        $f8, $f8, $f8                             \n\t"
    PTR_ADDIU  "%[psum16x16], %[psum16x16], 0x4           \n\t"

    "punpckhwd  $f30, $f30, $f8                           \n\t"
    "punpckhwd  $f28, $f28, $f8                           \n\t"
    "paddw      $f8, $f28, $f30                           \n\t"
    "dmfc1      $8, $f8                                   \n\t"
    "sw         $8, 0x0(%[psqsum16x16])                   \n\t"
    PTR_ADDIU  "%[psqsum16x16], %[psqsum16x16], 0x4       \n\t"

    "punpckhwd  $f4, $f24, $f26                           \n\t"
    "punpcklwd  $f6, $f24, $f26                           \n\t"
    "psubw      $f6, $f6, $f4                             \n\t"
    "dmfc1      $8, $f6                                   \n\t"
    PTR_S      "$8, 0x0(%[p_sd8x8])                       \n\t"
    PTR_ADDIU  "%[p_sd8x8], %[p_sd8x8], 0x8               \n\t"

    "dli        $8, 0x1                                   \n\t"
    "dmtc1      $8, $f8                                   \n\t"
    "dli        $8, 0x8                                   \n\t"
    "dmtc1      $8, $f10                                  \n\t"
    WELS_MAX_REG_MMI($f20, $f22, $f8, $f10)

    "dmfc1      $8, $f20                                  \n\t"
    "sb         $8, 0x0(%[p_mad8x8])                      \n\t"
    "dmfc1      $8, $f22                                  \n\t"
    "sb         $8, 0x1(%[p_mad8x8])                      \n\t"
    PTR_ADDIU  "%[p_mad8x8], %[p_mad8x8], 0x2             \n\t"

    "paddw      $f20, $f16, $f18                          \n\t"
	  "punpcklwd  $f16, $f20, $f20                          \n\t"
	  "punpckhwd  $f18, $f20, $f20                          \n\t"
    "paddw      $f16, $f16, $f18                          \n\t"
    "dmfc1      $8, $f16                                  \n\t"
    "sw         $8, 0x0(%[psqdiff16x16])                  \n\t"
    PTR_ADDIU  "%[psqdiff16x16], %[psqdiff16x16], 0x4     \n\t"

    PTR_SUBU   "$15, $15, $13                             \n\t"
    PTR_SUBU   "%[ref_data], %[ref_data], $13             \n\t"
    PTR_ADDIU  "$15, $15, 0x10                            \n\t"
    PTR_ADDIU  "%[ref_data], %[ref_data], 0x10            \n\t"

    PTR_ADDIU  "%[iPicWidth], %[iPicWidth], -0x1          \n\t"
    "bnez       %[iPicWidth], 2b                          \n\t"
    "nop                                                  \n\t"
    "move       %[iPicWidth], $9                          \n\t"
    "move       $15, $10                                  \n\t"
    "move       %[ref_data], $11                          \n\t"
    PTR_ADDU   "$15, $15, $13                             \n\t"
    PTR_ADDU   "%[ref_data], %[ref_data], $13             \n\t"

    PTR_ADDIU  "%[iPicHeight], %[iPicHeight], -0x1        \n\t"
    "bnez       %[iPicHeight], 1b                         \n\t"
    "nop                                                  \n\t"

    "sw         $14, 0x0(%[psadframe])                    \n\t"
    : [ref_data]"+&r"((unsigned char *)ref_data), [iPicWidth]"+&r"((int)iPicWidth),
      [iPicHeight]"+&r"((int)iPicHeight), [psad8x8]"+&r"((int *)psad8x8),
      [psum16x16]"+&r"((int *)psum16x16), [psqsum16x16]"+&r"((int *)psqsum16x16),
	    [psqdiff16x16]"+&r"((int *)psqdiff16x16), [p_sd8x8]"+&r"((int *)p_sd8x8),
      [p_mad8x8]"+&r"((unsigned char *)p_mad8x8)
    : [cur_data]"r"((unsigned char *)cur_data), [iPicStride]"r"((int)iPicStride),
      [psadframe]"r"((int *)psadframe)
    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0", "$f2",
      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
      "$f24", "$f26", "$f28", "$f30"
  );
  RECOVER_REG;
}

void VAACalcSadVar_mmi(const uint8_t *cur_data, const uint8_t *ref_data,
                       int32_t iPicWidth, int32_t iPicHeight, int32_t iPicStride,
                       int32_t *psadframe, int32_t *psad8x8, int32_t *psum16x16,
                       int32_t *psqsum16x16) {
  BACKUP_REG;
  __asm__ volatile (
    ".set       arch=loongson3a                           \n\t"
    "move       $15, %[cur_data]                          \n\t"
    "dsrl       %[iPicWidth], %[iPicWidth], 0x4           \n\t"
    "dsrl       %[iPicHeight], %[iPicHeight], 0x4         \n\t"
    "dsll       $13, %[iPicStride], 0x4                   \n\t"
    "xor        $f0, $f0, $f0                             \n\t"
    "xor        $f2, $f2, $f2                             \n\t"
    "xor        $f28, $f28, $f28                          \n\t"
    "xor        $f30, $f30, $f30                          \n\t"
    "xor        $14, $14, $14                             \n\t"
    "1:                                                   \n\t"
    "move       $9, %[iPicWidth]                          \n\t"
    "move       $10, $15                                  \n\t"
    "move       $11, %[ref_data]                          \n\t"
    "2:                                                   \n\t"
    "xor        $f24, $f24, $f24                          \n\t"
    "xor        $f26, $f26, $f26                          \n\t"
    "xor        $f20, $f20, $f20                          \n\t"
    "xor        $f22, $f22, $f22                          \n\t"
    "xor        $f16, $f16, $f16                          \n\t"
    "xor        $f18, $f18, $f18                          \n\t"
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    "paddw      $f28, $f24, $f28                          \n\t"
    "paddw      $f30, $f26, $f30                          \n\t"
    "dmfc1      $8, $f24                                  \n\t"
    "sw         $8, 0x0(%[psad8x8])                       \n\t"
    "dmfc1      $8, $f26                                  \n\t"
    "sw         $8, 0x4(%[psad8x8])                       \n\t"

    "xor        $f24, $f24, $f24                          \n\t"
    "xor        $f26, $f26, $f26                          \n\t"
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    WELS_SAD_SUM_SQSUM_16x1_MMI($15, %[ref_data], %[iPicStride])
    "paddw      $f28, $f24, $f28                          \n\t"
    "paddw      $f30, $f26, $f30                          \n\t"
    "dmfc1      $8, $f24                                  \n\t"
    "sw         $8, 0x8(%[psad8x8])                       \n\t"
    "dmfc1      $8, $f26                                  \n\t"
    "sw         $8, 0xc(%[psad8x8])                       \n\t"
    PTR_ADDIU  "%[psad8x8],   %[psad8x8],   0x10          \n\t"

    "paddw      $f20, $f20, $f22                          \n\t"
    "dmfc1      $8, $f20                                  \n\t"
    "sw         $8, 0x0(%[psum16x16])                     \n\t"
    PTR_ADDIU  "%[psum16x16], %[psum16x16], 0x4           \n\t"

    "paddw      $f20, $f16, $f18                          \n\t"
	  "punpcklwd  $f16, $f20, $f20                          \n\t"
	  "punpckhwd  $f18, $f20, $f20                          \n\t"
    "paddw      $f16, $f16, $f18                          \n\t"
    "dmfc1      $8, $f16                                  \n\t"
    "sw         $8, 0x0(%[psqsum16x16])                   \n\t"
    PTR_ADDIU  "%[psqsum16x16], %[psqsum16x16], 0x4       \n\t"

    PTR_SUBU   "$15, $15, $13                             \n\t"
    PTR_SUBU   "%[ref_data], %[ref_data], $13             \n\t"
    PTR_ADDIU  "$15, $15, 0x10                            \n\t"
    PTR_ADDIU  "%[ref_data], %[ref_data], 0x10            \n\t"

    PTR_ADDIU  "%[iPicWidth], %[iPicWidth], -0x1          \n\t"
    "bnez       %[iPicWidth], 2b                          \n\t"
    "nop                                                  \n\t"
    "move       %[iPicWidth], $9                          \n\t"
    "move       $15, $10                                  \n\t"
    "move       %[ref_data], $11                          \n\t"
    PTR_ADDU   "$15, $15, $13                             \n\t"
    PTR_ADDU   "%[ref_data], %[ref_data], $13             \n\t"

    PTR_ADDIU  "%[iPicHeight], %[iPicHeight], -0x1        \n\t"
    "bnez       %[iPicHeight], 1b                         \n\t"
    "nop                                                  \n\t"

    "paddw      $f28, $f28, $f30                          \n\t"
    "dmfc1      $8, $f28                                  \n\t"
    "sw         $8, 0x0(%[psadframe])                     \n\t"
    : [ref_data]"+&r"((unsigned char *)ref_data), [iPicWidth]"+&r"((int)iPicWidth),
      [iPicHeight]"+&r"((int)iPicHeight), [psum16x16]"+&r"((int *)psum16x16),
      [psqsum16x16]"+&r"((int *)psqsum16x16)
    : [cur_data]"r"((unsigned char *)cur_data), [iPicStride]"r"((int)iPicStride),
      [psadframe]"r"((int *)psadframe), [psad8x8]"r"((int *)psad8x8)
    : "memory", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$f0", "$f2",
      "$f4", "$f6", "$f8", "$f10", "$f12", "$f14", "$f16", "$f18", "$f20", "$f22",
      "$f24", "$f26", "$f28", "$f30"
  );
  RECOVER_REG;
}