8b264b4f039fb9b22c59348dacd56952bf3e3588
[platform/upstream/libjpeg-turbo.git] / simd / x86_64 / jdmrgext-avx2.asm
1 ;
2 ; jdmrgext.asm - merged upsampling/color conversion (64-bit AVX2)
3 ;
4 ; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
5 ; Copyright (C) 2009, 2012, 2016, D. R. Commander.
6 ; Copyright (C) 2015, Intel Corporation.
7 ; Copyright (C) 2018, Matthias Räncker.
8 ;
9 ; Based on the x86 SIMD extension for IJG JPEG library
10 ; Copyright (C) 1999-2006, MIYASAKA Masaru.
11 ; For conditions of distribution and use, see copyright notice in jsimdext.inc
12 ;
13 ; This file should be assembled with NASM (Netwide Assembler),
14 ; can *not* be assembled with Microsoft's MASM or any compatible
15 ; assembler (including Borland's Turbo Assembler).
16 ; NASM is available from http://nasm.sourceforge.net/ or
17 ; http://sourceforge.net/project/showfiles.php?group_id=6208
18
19 %include "jcolsamp.inc"
20
21 ; --------------------------------------------------------------------------
22 ;
23 ; Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
24 ;
25 ; GLOBAL(void)
26 ; jsimd_h2v1_merged_upsample_avx2(JDIMENSION output_width,
27 ;                                 JSAMPIMAGE input_buf,
28 ;                                 JDIMENSION in_row_group_ctr,
29 ;                                 JSAMPARRAY output_buf);
30 ;
31
32 ; r10d = JDIMENSION output_width
33 ; r11 = JSAMPIMAGE input_buf
34 ; r12d = JDIMENSION in_row_group_ctr
35 ; r13 = JSAMPARRAY output_buf
36
37 %define wk(i)   rbp - (WK_NUM - (i)) * SIZEOF_YMMWORD  ; ymmword wk[WK_NUM]
38 %define WK_NUM  3
39
40     align       32
41     GLOBAL_FUNCTION(jsimd_h2v1_merged_upsample_avx2)
42
43 EXTN(jsimd_h2v1_merged_upsample_avx2):
44     push        rbp
45     mov         rax, rsp                     ; rax = original rbp
46     sub         rsp, byte 4
47     and         rsp, byte (-SIZEOF_YMMWORD)  ; align to 256 bits
48     mov         [rsp], rax
49     mov         rbp, rsp                     ; rbp = aligned rbp
50     lea         rsp, [wk(0)]
51     collect_args 4
52     push        rbx
53
54     mov         ecx, r10d               ; col
55     test        rcx, rcx
56     jz          near .return
57
58     push        rcx
59
60     mov         rdi, r11
61     mov         ecx, r12d
62     mov         rsip, JSAMPARRAY [rdi+0*SIZEOF_JSAMPARRAY]
63     mov         rbxp, JSAMPARRAY [rdi+1*SIZEOF_JSAMPARRAY]
64     mov         rdxp, JSAMPARRAY [rdi+2*SIZEOF_JSAMPARRAY]
65     mov         rdi, r13
66     mov         rsip, JSAMPROW [rsi+rcx*SIZEOF_JSAMPROW]  ; inptr0
67     mov         rbxp, JSAMPROW [rbx+rcx*SIZEOF_JSAMPROW]  ; inptr1
68     mov         rdxp, JSAMPROW [rdx+rcx*SIZEOF_JSAMPROW]  ; inptr2
69     mov         rdip, JSAMPROW [rdi]                      ; outptr
70
71     pop         rcx                     ; col
72
73 .columnloop:
74
75     vmovdqu     ymm6, YMMWORD [rbx]     ; ymm6=Cb(0123456789ABCDEFGHIJKLMNOPQRSTUV)
76     vmovdqu     ymm7, YMMWORD [rdx]     ; ymm7=Cr(0123456789ABCDEFGHIJKLMNOPQRSTUV)
77
78     vpxor       ymm1, ymm1, ymm1        ; ymm1=(all 0's)
79     vpcmpeqw    ymm3, ymm3, ymm3
80     vpsllw      ymm3, ymm3, 7           ; ymm3={0xFF80 0xFF80 0xFF80 0xFF80 ..}
81
82     vpermq      ymm6, ymm6, 0xd8        ; ymm6=Cb(01234567GHIJKLMN89ABCDEFOPQRSTUV)
83     vpermq      ymm7, ymm7, 0xd8        ; ymm7=Cr(01234567GHIJKLMN89ABCDEFOPQRSTUV)
84     vpunpcklbw  ymm4, ymm6, ymm1        ; ymm4=Cb(0123456789ABCDEF)=CbL
85     vpunpckhbw  ymm6, ymm6, ymm1        ; ymm6=Cb(GHIJKLMNOPQRSTUV)=CbH
86     vpunpcklbw  ymm0, ymm7, ymm1        ; ymm0=Cr(0123456789ABCDEF)=CrL
87     vpunpckhbw  ymm7, ymm7, ymm1        ; ymm7=Cr(GHIJKLMNOPQRSTUV)=CrH
88
89     vpaddw      ymm5, ymm6, ymm3
90     vpaddw      ymm2, ymm4, ymm3
91     vpaddw      ymm1, ymm7, ymm3
92     vpaddw      ymm3, ymm0, ymm3
93
94     ; (Original)
95     ; R = Y                + 1.40200 * Cr
96     ; G = Y - 0.34414 * Cb - 0.71414 * Cr
97     ; B = Y + 1.77200 * Cb
98     ;
99     ; (This implementation)
100     ; R = Y                + 0.40200 * Cr + Cr
101     ; G = Y - 0.34414 * Cb + 0.28586 * Cr - Cr
102     ; B = Y - 0.22800 * Cb + Cb + Cb
103
104     vpaddw      ymm6, ymm5, ymm5             ; ymm6=2*CbH
105     vpaddw      ymm4, ymm2, ymm2             ; ymm4=2*CbL
106     vpaddw      ymm7, ymm1, ymm1             ; ymm7=2*CrH
107     vpaddw      ymm0, ymm3, ymm3             ; ymm0=2*CrL
108
109     vpmulhw     ymm6, ymm6, [rel PW_MF0228]  ; ymm6=(2*CbH * -FIX(0.22800))
110     vpmulhw     ymm4, ymm4, [rel PW_MF0228]  ; ymm4=(2*CbL * -FIX(0.22800))
111     vpmulhw     ymm7, ymm7, [rel PW_F0402]   ; ymm7=(2*CrH * FIX(0.40200))
112     vpmulhw     ymm0, ymm0, [rel PW_F0402]   ; ymm0=(2*CrL * FIX(0.40200))
113
114     vpaddw      ymm6, ymm6, [rel PW_ONE]
115     vpaddw      ymm4, ymm4, [rel PW_ONE]
116     vpsraw      ymm6, ymm6, 1                ; ymm6=(CbH * -FIX(0.22800))
117     vpsraw      ymm4, ymm4, 1                ; ymm4=(CbL * -FIX(0.22800))
118     vpaddw      ymm7, ymm7, [rel PW_ONE]
119     vpaddw      ymm0, ymm0, [rel PW_ONE]
120     vpsraw      ymm7, ymm7, 1                ; ymm7=(CrH * FIX(0.40200))
121     vpsraw      ymm0, ymm0, 1                ; ymm0=(CrL * FIX(0.40200))
122
123     vpaddw      ymm6, ymm6, ymm5
124     vpaddw      ymm4, ymm4, ymm2
125     vpaddw      ymm6, ymm6, ymm5             ; ymm6=(CbH * FIX(1.77200))=(B-Y)H
126     vpaddw      ymm4, ymm4, ymm2             ; ymm4=(CbL * FIX(1.77200))=(B-Y)L
127     vpaddw      ymm7, ymm7, ymm1             ; ymm7=(CrH * FIX(1.40200))=(R-Y)H
128     vpaddw      ymm0, ymm0, ymm3             ; ymm0=(CrL * FIX(1.40200))=(R-Y)L
129
130     vmovdqa     YMMWORD [wk(0)], ymm6        ; wk(0)=(B-Y)H
131     vmovdqa     YMMWORD [wk(1)], ymm7        ; wk(1)=(R-Y)H
132
133     vpunpckhwd  ymm6, ymm5, ymm1
134     vpunpcklwd  ymm5, ymm5, ymm1
135     vpmaddwd    ymm5, ymm5, [rel PW_MF0344_F0285]
136     vpmaddwd    ymm6, ymm6, [rel PW_MF0344_F0285]
137     vpunpckhwd  ymm7, ymm2, ymm3
138     vpunpcklwd  ymm2, ymm2, ymm3
139     vpmaddwd    ymm2, ymm2, [rel PW_MF0344_F0285]
140     vpmaddwd    ymm7, ymm7, [rel PW_MF0344_F0285]
141
142     vpaddd      ymm5, ymm5, [rel PD_ONEHALF]
143     vpaddd      ymm6, ymm6, [rel PD_ONEHALF]
144     vpsrad      ymm5, ymm5, SCALEBITS
145     vpsrad      ymm6, ymm6, SCALEBITS
146     vpaddd      ymm2, ymm2, [rel PD_ONEHALF]
147     vpaddd      ymm7, ymm7, [rel PD_ONEHALF]
148     vpsrad      ymm2, ymm2, SCALEBITS
149     vpsrad      ymm7, ymm7, SCALEBITS
150
151     vpackssdw   ymm5, ymm5, ymm6        ; ymm5=CbH*-FIX(0.344)+CrH*FIX(0.285)
152     vpackssdw   ymm2, ymm2, ymm7        ; ymm2=CbL*-FIX(0.344)+CrL*FIX(0.285)
153     vpsubw      ymm5, ymm5, ymm1        ; ymm5=CbH*-FIX(0.344)+CrH*-FIX(0.714)=(G-Y)H
154     vpsubw      ymm2, ymm2, ymm3        ; ymm2=CbL*-FIX(0.344)+CrL*-FIX(0.714)=(G-Y)L
155
156     vmovdqa     YMMWORD [wk(2)], ymm5   ; wk(2)=(G-Y)H
157
158     mov         al, 2                   ; Yctr
159     jmp         short .Yloop_1st
160
161 .Yloop_2nd:
162     vmovdqa     ymm0, YMMWORD [wk(1)]   ; ymm0=(R-Y)H
163     vmovdqa     ymm2, YMMWORD [wk(2)]   ; ymm2=(G-Y)H
164     vmovdqa     ymm4, YMMWORD [wk(0)]   ; ymm4=(B-Y)H
165
166 .Yloop_1st:
167     vmovdqu     ymm7, YMMWORD [rsi]     ; ymm7=Y(0123456789ABCDEFGHIJKLMNOPQRSTUV)
168
169     vpcmpeqw    ymm6, ymm6, ymm6
170     vpsrlw      ymm6, ymm6, BYTE_BIT    ; ymm6={0xFF 0x00 0xFF 0x00 ..}
171     vpand       ymm6, ymm6, ymm7        ; ymm6=Y(02468ACEGIKMOQSU)=YE
172     vpsrlw      ymm7, ymm7, BYTE_BIT    ; ymm7=Y(13579BDFHJLNPRTV)=YO
173
174     vmovdqa     ymm1, ymm0              ; ymm1=ymm0=(R-Y)(L/H)
175     vmovdqa     ymm3, ymm2              ; ymm3=ymm2=(G-Y)(L/H)
176     vmovdqa     ymm5, ymm4              ; ymm5=ymm4=(B-Y)(L/H)
177
178     vpaddw      ymm0, ymm0, ymm6        ; ymm0=((R-Y)+YE)=RE=R(02468ACEGIKMOQSU)
179     vpaddw      ymm1, ymm1, ymm7        ; ymm1=((R-Y)+YO)=RO=R(13579BDFHJLNPRTV)
180     vpackuswb   ymm0, ymm0, ymm0        ; ymm0=R(02468ACE********GIKMOQSU********)
181     vpackuswb   ymm1, ymm1, ymm1        ; ymm1=R(13579BDF********HJLNPRTV********)
182
183     vpaddw      ymm2, ymm2, ymm6        ; ymm2=((G-Y)+YE)=GE=G(02468ACEGIKMOQSU)
184     vpaddw      ymm3, ymm3, ymm7        ; ymm3=((G-Y)+YO)=GO=G(13579BDFHJLNPRTV)
185     vpackuswb   ymm2, ymm2, ymm2        ; ymm2=G(02468ACE********GIKMOQSU********)
186     vpackuswb   ymm3, ymm3, ymm3        ; ymm3=G(13579BDF********HJLNPRTV********)
187
188     vpaddw      ymm4, ymm4, ymm6        ; ymm4=((B-Y)+YE)=BE=B(02468ACEGIKMOQSU)
189     vpaddw      ymm5, ymm5, ymm7        ; ymm5=((B-Y)+YO)=BO=B(13579BDFHJLNPRTV)
190     vpackuswb   ymm4, ymm4, ymm4        ; ymm4=B(02468ACE********GIKMOQSU********)
191     vpackuswb   ymm5, ymm5, ymm5        ; ymm5=B(13579BDF********HJLNPRTV********)
192
193 %if RGB_PIXELSIZE == 3  ; ---------------
194
195     ; ymmA=(00 02 04 06 08 0A 0C 0E ** 0G 0I 0K 0M 0O 0Q 0S 0U **)
196     ; ymmB=(01 03 05 07 09 0B 0D 0F ** 0H 0J 0L 0N 0P 0R 0T 0V **)
197     ; ymmC=(10 12 14 16 18 1A 1C 1E ** 1G 1I 1K 1M 1O 1Q 1S 1U **)
198     ; ymmD=(11 13 15 17 19 1B 1D 1F ** 1H 1J 1L 1N 1P 1R 1T 1V **)
199     ; ymmE=(20 22 24 26 28 2A 2C 2E ** 2G 2I 2K 2M 2O 2Q 2S 2U **)
200     ; ymmF=(21 23 25 27 29 2B 2D 2F ** 2H 2J 2L 2N 2P 2R 2T 2V **)
201     ; ymmG=(** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **)
202     ; ymmH=(** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **)
203
204     vpunpcklbw  ymmA, ymmA, ymmC        ; ymmA=(00 10 02 12 04 14 06 16 08 18 0A 1A 0C 1C 0E 1E
205                                         ;       0G 1G 0I 1I 0K 1K 0M 1M 0O 1O 0Q 1Q 0S 1S 0U 1U)
206     vpunpcklbw  ymmE, ymmE, ymmB        ; ymmE=(20 01 22 03 24 05 26 07 28 09 2A 0B 2C 0D 2E 0F
207                                         ;       2G 0H 2I 0J 2K 0L 2M 0N 2O 0P 2Q 0R 2S 0T 2U 0V)
208     vpunpcklbw  ymmD, ymmD, ymmF        ; ymmD=(11 21 13 23 15 25 17 27 19 29 1B 2B 1D 2D 1F 2F
209                                         ;       1H 2H 1J 2J 1L 2L 1N 2N 1P 2P 1R 2R 1T 2T 1V 2V)
210
211     vpsrldq     ymmH, ymmA, 2           ; ymmH=(02 12 04 14 06 16 08 18 0A 1A 0C 1C 0E 1E 0G 1G
212                                         ;       0I 1I 0K 1K 0M 1M 0O 1O 0Q 1Q 0S 1S 0U 1U -- --)
213     vpunpckhwd  ymmG, ymmA, ymmE        ; ymmG=(08 18 28 09 0A 1A 2A 0B 0C 1C 2C 0D 0E 1E 2E 0F
214                                         ;       0O 1O 2O 0P 0Q 1Q 2Q 0R 0S 1S 2S 0T 0U 1U 2U 0V)
215     vpunpcklwd  ymmA, ymmA, ymmE        ; ymmA=(00 10 20 01 02 12 22 03 04 14 24 05 06 16 26 07
216                                         ;       0G 1G 2G 0H 0I 1I 2I 0J 0K 1K 2K 0L 0M 1M 2M 0N)
217
218     vpsrldq     ymmE, ymmE, 2           ; ymmE=(22 03 24 05 26 07 28 09 2A 0B 2C 0D 2E 0F 2G 0H
219                                         ;       2I 0J 2K 0L 2M 0N 2O 0P 2Q 0R 2S 0T 2U 0V -- --)
220
221     vpsrldq     ymmB, ymmD, 2           ; ymmB=(13 23 15 25 17 27 19 29 1B 2B 1D 2D 1F 2F 1H 2H
222                                         ;       1J 2J 1L 2L 1N 2N 1P 2P 1R 2R 1T 2T 1V 2V -- --)
223     vpunpckhwd  ymmC, ymmD, ymmH        ; ymmC=(19 29 0A 1A 1B 2B 0C 1C 1D 2D 0E 1E 1F 2F 0G 1G
224                                         ;       1P 2P 0Q 1Q 1R 2R 0S 1S 1T 2T 0U 1U 1V 2V -- --)
225     vpunpcklwd  ymmD, ymmD, ymmH        ; ymmD=(11 21 02 12 13 23 04 14 15 25 06 16 17 27 08 18
226                                         ;       1H 2H 0I 1I 1J 2J 0K 1K 1L 2L 0M 1M 1N 2N 0O 1O)
227
228     vpunpckhwd  ymmF, ymmE, ymmB        ; ymmF=(2A 0B 1B 2B 2C 0D 1D 2D 2E 0F 1F 2F 2G 0H 1H 2H
229                                         ;       2Q 0R 1R 2R 2S 0T 1T 2T 2U 0V 1V 2V -- -- -- --)
230     vpunpcklwd  ymmE, ymmE, ymmB        ; ymmE=(22 03 13 23 24 05 15 25 26 07 17 27 28 09 19 29
231                                         ;       2I 0J 1J 2J 2K 0L 1L 2L 2M 0N 1N 2N 2O 0P 1P 2P)
232
233     vpshufd     ymmH, ymmA, 0x4E        ; ymmH=(04 14 24 05 06 16 26 07 00 10 20 01 02 12 22 03
234                                         ;       0K 1K 2K 0L 0M 1M 2M 0N 0G 1G 2G 0H 0I 1I 2I 0J)
235     vpunpckldq  ymmA, ymmA, ymmD        ; ymmA=(00 10 20 01 11 21 02 12 02 12 22 03 13 23 04 14
236                                         ;       0G 1G 2G 0H 1H 2H 0I 1I 0I 1I 2I 0J 1J 2J 0K 1K)
237     vpunpckhdq  ymmD, ymmD, ymmE        ; ymmD=(15 25 06 16 26 07 17 27 17 27 08 18 28 09 19 29
238                                         ;       1L 2L 0M 1M 2M 0N 1N 2N 1N 2N 0O 1O 2O 0P 1P 2P)
239     vpunpckldq  ymmE, ymmE, ymmH        ; ymmE=(22 03 13 23 04 14 24 05 24 05 15 25 06 16 26 07
240                                         ;       2I 0J 1J 2J 0K 1K 2K 0L 2K 0L 1L 2L 0M 1M 2M 0N)
241
242     vpshufd     ymmH, ymmG, 0x4E        ; ymmH=(0C 1C 2C 0D 0E 1E 2E 0F 08 18 28 09 0A 1A 2A 0B
243                                         ;       0S 1S 2S 0T 0U 1U 2U 0V 0O 1O 2O 0P 0Q 1Q 2Q 0R)
244     vpunpckldq  ymmG, ymmG, ymmC        ; ymmG=(08 18 28 09 19 29 0A 1A 0A 1A 2A 0B 1B 2B 0C 1C
245                                         ;       0O 1O 2O 0P 1P 2P 0Q 1Q 0Q 1Q 2Q 0R 1R 2R 0S 1S)
246     vpunpckhdq  ymmC, ymmC, ymmF        ; ymmC=(1D 2D 0E 1E 2E 0F 1F 2F 1F 2F 0G 1G 2G 0H 1H 2H
247                                         ;       1T 2T 0U 1U 2U 0V 1V 2V 1V 2V -- -- -- -- -- --)
248     vpunpckldq  ymmF, ymmF, ymmH        ; ymmF=(2A 0B 1B 2B 0C 1C 2C 0D 2C 0D 1D 2D 0E 1E 2E 0F
249                                         ;       2Q 0R 1R 2R 0S 1S 2S 0T 2S 0T 1T 2T 0U 1U 2U 0V)
250
251     vpunpcklqdq ymmH, ymmA, ymmE        ; ymmH=(00 10 20 01 11 21 02 12 22 03 13 23 04 14 24 05
252                                         ;       0G 1G 2G 0H 1H 2H 0I 1I 2I 0J 1J 2J 0K 1K 2K 0L)
253     vpunpcklqdq ymmG, ymmD, ymmG        ; ymmG=(15 25 06 16 26 07 17 27 08 18 28 09 19 29 0A 1A
254                                         ;       1L 2L 0M 1M 2M 0N 1N 2N 0O 1O 2O 0P 1P 2P 0Q 1Q)
255     vpunpcklqdq ymmC, ymmF, ymmC        ; ymmC=(2A 0B 1B 2B 0C 1C 2C 0D 1D 2D 0E 1E 2E 0F 1F 2F
256                                         ;       2Q 0R 1R 2R 0S 1S 2S 0T 1T 2T 0U 1U 2U 0V 1V 2V)
257
258     vperm2i128  ymmA, ymmH, ymmG, 0x20  ; ymmA=(00 10 20 01 11 21 02 12 22 03 13 23 04 14 24 05
259                                         ;       15 25 06 16 26 07 17 27 08 18 28 09 19 29 0A 1A)
260     vperm2i128  ymmD, ymmC, ymmH, 0x30  ; ymmD=(2A 0B 1B 2B 0C 1C 2C 0D 1D 2D 0E 1E 2E 0F 1F 2F
261                                         ;       0G 1G 2G 0H 1H 2H 0I 1I 2I 0J 1J 2J 0K 1K 2K 0L)
262     vperm2i128  ymmF, ymmG, ymmC, 0x31  ; ymmF=(1L 2L 0M 1M 2M 0N 1N 2N 0O 1O 2O 0P 1P 2P 0Q 1Q
263                                         ;       2Q 0R 1R 2R 0S 1S 2S 0T 1T 2T 0U 1U 2U 0V 1V 2V)
264
265     cmp         rcx, byte SIZEOF_YMMWORD
266     jb          short .column_st64
267
268     test        rdi, SIZEOF_YMMWORD-1
269     jnz         short .out1
270     ; --(aligned)-------------------
271     vmovntdq    YMMWORD [rdi+0*SIZEOF_YMMWORD], ymmA
272     vmovntdq    YMMWORD [rdi+1*SIZEOF_YMMWORD], ymmD
273     vmovntdq    YMMWORD [rdi+2*SIZEOF_YMMWORD], ymmF
274     jmp         short .out0
275 .out1:  ; --(unaligned)-----------------
276     vmovdqu     YMMWORD [rdi+0*SIZEOF_YMMWORD], ymmA
277     vmovdqu     YMMWORD [rdi+1*SIZEOF_YMMWORD], ymmD
278     vmovdqu     YMMWORD [rdi+2*SIZEOF_YMMWORD], ymmF
279 .out0:
280     add         rdi, byte RGB_PIXELSIZE*SIZEOF_YMMWORD  ; outptr
281     sub         rcx, byte SIZEOF_YMMWORD
282     jz          near .endcolumn
283
284     add         rsi, byte SIZEOF_YMMWORD  ; inptr0
285     dec         al                        ; Yctr
286     jnz         near .Yloop_2nd
287
288     add         rbx, byte SIZEOF_YMMWORD  ; inptr1
289     add         rdx, byte SIZEOF_YMMWORD  ; inptr2
290     jmp         near .columnloop
291
292 .column_st64:
293     lea         rcx, [rcx+rcx*2]            ; imul ecx, RGB_PIXELSIZE
294     cmp         rcx, byte 2*SIZEOF_YMMWORD
295     jb          short .column_st32
296     vmovdqu     YMMWORD [rdi+0*SIZEOF_YMMWORD], ymmA
297     vmovdqu     YMMWORD [rdi+1*SIZEOF_YMMWORD], ymmD
298     add         rdi, byte 2*SIZEOF_YMMWORD  ; outptr
299     vmovdqa     ymmA, ymmF
300     sub         rcx, byte 2*SIZEOF_YMMWORD
301     jmp         short .column_st31
302 .column_st32:
303     cmp         rcx, byte SIZEOF_YMMWORD
304     jb          short .column_st31
305     vmovdqu     YMMWORD [rdi+0*SIZEOF_YMMWORD], ymmA
306     add         rdi, byte SIZEOF_YMMWORD    ; outptr
307     vmovdqa     ymmA, ymmD
308     sub         rcx, byte SIZEOF_YMMWORD
309     jmp         short .column_st31
310 .column_st31:
311     cmp         rcx, byte SIZEOF_XMMWORD
312     jb          short .column_st15
313     vmovdqu     XMMWORD [rdi+0*SIZEOF_XMMWORD], xmmA
314     add         rdi, byte SIZEOF_XMMWORD    ; outptr
315     vperm2i128  ymmA, ymmA, ymmA, 1
316     sub         rcx, byte SIZEOF_XMMWORD
317 .column_st15:
318     ; Store the lower 8 bytes of xmmA to the output when it has enough
319     ; space.
320     cmp         rcx, byte SIZEOF_MMWORD
321     jb          short .column_st7
322     vmovq       XMM_MMWORD [rdi], xmmA
323     add         rdi, byte SIZEOF_MMWORD
324     sub         rcx, byte SIZEOF_MMWORD
325     vpsrldq     xmmA, xmmA, SIZEOF_MMWORD
326 .column_st7:
327     ; Store the lower 4 bytes of xmmA to the output when it has enough
328     ; space.
329     cmp         rcx, byte SIZEOF_DWORD
330     jb          short .column_st3
331     vmovd       XMM_DWORD [rdi], xmmA
332     add         rdi, byte SIZEOF_DWORD
333     sub         rcx, byte SIZEOF_DWORD
334     vpsrldq     xmmA, xmmA, SIZEOF_DWORD
335 .column_st3:
336     ; Store the lower 2 bytes of rax to the output when it has enough
337     ; space.
338     vmovd       eax, xmmA
339     cmp         rcx, byte SIZEOF_WORD
340     jb          short .column_st1
341     mov         word [rdi], ax
342     add         rdi, byte SIZEOF_WORD
343     sub         rcx, byte SIZEOF_WORD
344     shr         rax, 16
345 .column_st1:
346     ; Store the lower 1 byte of rax to the output when it has enough
347     ; space.
348     test        rcx, rcx
349     jz          short .endcolumn
350     mov         byte [rdi], al
351
352 %else  ; RGB_PIXELSIZE == 4 ; -----------
353
354 %ifdef RGBX_FILLER_0XFF
355     vpcmpeqb    ymm6, ymm6, ymm6        ; ymm6=XE=X(02468ACE********GIKMOQSU********)
356     vpcmpeqb    ymm7, ymm7, ymm7        ; ymm7=XO=X(13579BDF********HJLNPRTV********)
357 %else
358     vpxor       ymm6, ymm6, ymm6        ; ymm6=XE=X(02468ACE********GIKMOQSU********)
359     vpxor       ymm7, ymm7, ymm7        ; ymm7=XO=X(13579BDF********HJLNPRTV********)
360 %endif
361     ; ymmA=(00 02 04 06 08 0A 0C 0E ** 0G 0I 0K 0M 0O 0Q 0S 0U **)
362     ; ymmB=(01 03 05 07 09 0B 0D 0F ** 0H 0J 0L 0N 0P 0R 0T 0V **)
363     ; ymmC=(10 12 14 16 18 1A 1C 1E ** 1G 1I 1K 1M 1O 1Q 1S 1U **)
364     ; ymmD=(11 13 15 17 19 1B 1D 1F ** 1H 1J 1L 1N 1P 1R 1T 1V **)
365     ; ymmE=(20 22 24 26 28 2A 2C 2E ** 2G 2I 2K 2M 2O 2Q 2S 2U **)
366     ; ymmF=(21 23 25 27 29 2B 2D 2F ** 2H 2J 2L 2N 2P 2R 2T 2V **)
367     ; ymmG=(30 32 34 36 38 3A 3C 3E ** 3G 3I 3K 3M 3O 3Q 3S 3U **)
368     ; ymmH=(31 33 35 37 39 3B 3D 3F ** 3H 3J 3L 3N 3P 3R 3T 3V **)
369
370     vpunpcklbw  ymmA, ymmA, ymmC        ; ymmA=(00 10 02 12 04 14 06 16 08 18 0A 1A 0C 1C 0E 1E
371                                         ;       0G 1G 0I 1I 0K 1K 0M 1M 0O 1O 0Q 1Q 0S 1S 0U 1U)
372     vpunpcklbw  ymmE, ymmE, ymmG        ; ymmE=(20 30 22 32 24 34 26 36 28 38 2A 3A 2C 3C 2E 3E
373                                         ;       2G 3G 2I 3I 2K 3K 2M 3M 2O 3O 2Q 3Q 2S 3S 2U 3U)
374     vpunpcklbw  ymmB, ymmB, ymmD        ; ymmB=(01 11 03 13 05 15 07 17 09 19 0B 1B 0D 1D 0F 1F
375                                         ;       0H 1H 0J 1J 0L 1L 0N 1N 0P 1P 0R 1R 0T 1T 0V 1V)
376     vpunpcklbw  ymmF, ymmF, ymmH        ; ymmF=(21 31 23 33 25 35 27 37 29 39 2B 3B 2D 3D 2F 3F
377                                         ;       2H 3H 2J 3J 2L 3L 2N 3N 2P 3P 2R 3R 2T 3T 2V 3V)
378
379     vpunpckhwd  ymmC, ymmA, ymmE        ; ymmC=(08 18 28 38 0A 1A 2A 3A 0C 1C 2C 3C 0E 1E 2E 3E
380                                         ;       0O 1O 2O 3O 0Q 1Q 2Q 3Q 0S 1S 2S 3S 0U 1U 2U 3U)
381     vpunpcklwd  ymmA, ymmA, ymmE        ; ymmA=(00 10 20 30 02 12 22 32 04 14 24 34 06 16 26 36
382                                         ;       0G 1G 2G 3G 0I 1I 2I 3I 0K 1K 2K 3K 0M 1M 2M 3M)
383     vpunpckhwd  ymmG, ymmB, ymmF        ; ymmG=(09 19 29 39 0B 1B 2B 3B 0D 1D 2D 3D 0F 1F 2F 3F
384                                         ;       0P 1P 2P 3P 0R 1R 2R 3R 0T 1T 2T 3T 0V 1V 2V 3V)
385     vpunpcklwd  ymmB, ymmB, ymmF        ; ymmB=(01 11 21 31 03 13 23 33 05 15 25 35 07 17 27 37
386                                         ;       0H 1H 2H 3H 0J 1J 2J 3J 0L 1L 2L 3L 0N 1N 2N 3N)
387
388     vpunpckhdq  ymmE, ymmA, ymmB        ; ymmE=(04 14 24 34 05 15 25 35 06 16 26 36 07 17 27 37
389                                         ;       0K 1K 2K 3K 0L 1L 2L 3L 0M 1M 2M 3M 0N 1N 2N 3N)
390     vpunpckldq  ymmB, ymmA, ymmB        ; ymmB=(00 10 20 30 01 11 21 31 02 12 22 32 03 13 23 33
391                                         ;       0G 1G 2G 3G 0H 1H 2H 3H 0I 1I 2I 3I 0J 1J 2J 3J)
392     vpunpckhdq  ymmF, ymmC, ymmG        ; ymmF=(0C 1C 2C 3C 0D 1D 2D 3D 0E 1E 2E 3E 0F 1F 2F 3F
393                                         ;       0S 1S 2S 3S 0T 1T 2T 3T 0U 1U 2U 3U 0V 1V 2V 3V)
394     vpunpckldq  ymmG, ymmC, ymmG        ; ymmG=(08 18 28 38 09 19 29 39 0A 1A 2A 3A 0B 1B 2B 3B
395                                         ;       0O 1O 2O 3O 0P 1P 2P 3P 0Q 1Q 2Q 3Q 0R 1R 2R 3R)
396
397     vperm2i128  ymmA, ymmB, ymmE, 0x20  ; ymmA=(00 10 20 30 01 11 21 31 02 12 22 32 03 13 23 33
398                                         ;       04 14 24 34 05 15 25 35 06 16 26 36 07 17 27 37)
399     vperm2i128  ymmD, ymmG, ymmF, 0x20  ; ymmD=(08 18 28 38 09 19 29 39 0A 1A 2A 3A 0B 1B 2B 3B
400                                         ;       0C 1C 2C 3C 0D 1D 2D 3D 0E 1E 2E 3E 0F 1F 2F 3F)
401     vperm2i128  ymmC, ymmB, ymmE, 0x31  ; ymmC=(0G 1G 2G 3G 0H 1H 2H 3H 0I 1I 2I 3I 0J 1J 2J 3J
402                                         ;       0K 1K 2K 3K 0L 1L 2L 3L 0M 1M 2M 3M 0N 1N 2N 3N)
403     vperm2i128  ymmH, ymmG, ymmF, 0x31  ; ymmH=(0O 1O 2O 3O 0P 1P 2P 3P 0Q 1Q 2Q 3Q 0R 1R 2R 3R
404                                         ;       0S 1S 2S 3S 0T 1T 2T 3T 0U 1U 2U 3U 0V 1V 2V 3V)
405
406     cmp         rcx, byte SIZEOF_YMMWORD
407     jb          short .column_st64
408
409     test        rdi, SIZEOF_YMMWORD-1
410     jnz         short .out1
411     ; --(aligned)-------------------
412     vmovntdq    YMMWORD [rdi+0*SIZEOF_YMMWORD], ymmA
413     vmovntdq    YMMWORD [rdi+1*SIZEOF_YMMWORD], ymmD
414     vmovntdq    YMMWORD [rdi+2*SIZEOF_YMMWORD], ymmC
415     vmovntdq    YMMWORD [rdi+3*SIZEOF_YMMWORD], ymmH
416     jmp         short .out0
417 .out1:  ; --(unaligned)-----------------
418     vmovdqu     YMMWORD [rdi+0*SIZEOF_YMMWORD], ymmA
419     vmovdqu     YMMWORD [rdi+1*SIZEOF_YMMWORD], ymmD
420     vmovdqu     YMMWORD [rdi+2*SIZEOF_YMMWORD], ymmC
421     vmovdqu     YMMWORD [rdi+3*SIZEOF_YMMWORD], ymmH
422 .out0:
423     add         rdi, RGB_PIXELSIZE*SIZEOF_YMMWORD  ; outptr
424     sub         rcx, byte SIZEOF_YMMWORD
425     jz          near .endcolumn
426
427     add         rsi, byte SIZEOF_YMMWORD  ; inptr0
428     dec         al
429     jnz         near .Yloop_2nd
430
431     add         rbx, byte SIZEOF_YMMWORD  ; inptr1
432     add         rdx, byte SIZEOF_YMMWORD  ; inptr2
433     jmp         near .columnloop
434
435 .column_st64:
436     cmp         rcx, byte SIZEOF_YMMWORD/2
437     jb          short .column_st32
438     vmovdqu     YMMWORD [rdi+0*SIZEOF_YMMWORD], ymmA
439     vmovdqu     YMMWORD [rdi+1*SIZEOF_YMMWORD], ymmD
440     add         rdi, byte 2*SIZEOF_YMMWORD  ; outptr
441     vmovdqa     ymmA, ymmC
442     vmovdqa     ymmD, ymmH
443     sub         rcx, byte SIZEOF_YMMWORD/2
444 .column_st32:
445     cmp         rcx, byte SIZEOF_YMMWORD/4
446     jb          short .column_st16
447     vmovdqu     YMMWORD [rdi+0*SIZEOF_YMMWORD], ymmA
448     add         rdi, byte SIZEOF_YMMWORD    ; outptr
449     vmovdqa     ymmA, ymmD
450     sub         rcx, byte SIZEOF_YMMWORD/4
451 .column_st16:
452     cmp         rcx, byte SIZEOF_YMMWORD/8
453     jb          short .column_st15
454     vmovdqu     XMMWORD [rdi+0*SIZEOF_XMMWORD], xmmA
455     add         rdi, byte SIZEOF_XMMWORD    ; outptr
456     vperm2i128  ymmA, ymmA, ymmA, 1
457     sub         rcx, byte SIZEOF_YMMWORD/8
458 .column_st15:
459     ; Store two pixels (8 bytes) of ymmA to the output when it has enough
460     ; space.
461     cmp         rcx, byte SIZEOF_YMMWORD/16
462     jb          short .column_st7
463     vmovq       MMWORD [rdi], xmmA
464     add         rdi, byte SIZEOF_YMMWORD/16*4
465     sub         rcx, byte SIZEOF_YMMWORD/16
466     vpsrldq     xmmA, SIZEOF_YMMWORD/16*4
467 .column_st7:
468     ; Store one pixel (4 bytes) of ymmA to the output when it has enough
469     ; space.
470     test        rcx, rcx
471     jz          short .endcolumn
472     vmovd       XMM_DWORD [rdi], xmmA
473
474 %endif  ; RGB_PIXELSIZE ; ---------------
475
476 .endcolumn:
477     sfence                              ; flush the write buffer
478
479 .return:
480     pop         rbx
481     vzeroupper
482     uncollect_args 4
483     mov         rsp, rbp                ; rsp <- aligned rbp
484     pop         rsp                     ; rsp <- original rbp
485     pop         rbp
486     ret
487
488 ; --------------------------------------------------------------------------
489 ;
490 ; Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
491 ;
492 ; GLOBAL(void)
493 ; jsimd_h2v2_merged_upsample_avx2(JDIMENSION output_width,
494 ;                                 JSAMPIMAGE input_buf,
495 ;                                 JDIMENSION in_row_group_ctr,
496 ;                                 JSAMPARRAY output_buf);
497 ;
498
499 ; r10d = JDIMENSION output_width
500 ; r11 = JSAMPIMAGE input_buf
501 ; r12d = JDIMENSION in_row_group_ctr
502 ; r13 = JSAMPARRAY output_buf
503
504     align       32
505     GLOBAL_FUNCTION(jsimd_h2v2_merged_upsample_avx2)
506
507 EXTN(jsimd_h2v2_merged_upsample_avx2):
508     push        rbp
509     mov         rax, rsp
510     mov         rbp, rsp
511     collect_args 4
512     push        rbx
513
514     mov         eax, r10d
515
516     mov         rdi, r11
517     mov         ecx, r12d
518     mov         rsip, JSAMPARRAY [rdi+0*SIZEOF_JSAMPARRAY]
519     mov         rbxp, JSAMPARRAY [rdi+1*SIZEOF_JSAMPARRAY]
520     mov         rdxp, JSAMPARRAY [rdi+2*SIZEOF_JSAMPARRAY]
521     mov         rdi, r13
522     lea         rsi, [rsi+rcx*SIZEOF_JSAMPROW]
523
524     sub         rsp, SIZEOF_JSAMPARRAY*4
525     mov         JSAMPARRAY [rsp+0*SIZEOF_JSAMPARRAY], rsip  ; intpr00
526     mov         JSAMPARRAY [rsp+1*SIZEOF_JSAMPARRAY], rbxp  ; intpr1
527     mov         JSAMPARRAY [rsp+2*SIZEOF_JSAMPARRAY], rdxp  ; intpr2
528     mov         rbx, rsp
529
530     push        rdi
531     push        rcx
532     push        rax
533
534     %ifdef WIN64
535     mov         r8, rcx
536     mov         r9, rdi
537     mov         rcx, rax
538     mov         rdx, rbx
539     %else
540     mov         rdx, rcx
541     mov         rcx, rdi
542     mov         rdi, rax
543     mov         rsi, rbx
544     %endif
545
546     call        EXTN(jsimd_h2v1_merged_upsample_avx2)
547
548     pop         rax
549     pop         rcx
550     pop         rdi
551     mov         rsip, JSAMPARRAY [rsp+0*SIZEOF_JSAMPARRAY]
552     mov         rbxp, JSAMPARRAY [rsp+1*SIZEOF_JSAMPARRAY]
553     mov         rdxp, JSAMPARRAY [rsp+2*SIZEOF_JSAMPARRAY]
554
555     add         rdi, byte SIZEOF_JSAMPROW  ; outptr1
556     add         rsi, byte SIZEOF_JSAMPROW  ; inptr01
557
558     mov         JSAMPARRAY [rsp+0*SIZEOF_JSAMPARRAY], rsip  ; intpr00
559     mov         JSAMPARRAY [rsp+1*SIZEOF_JSAMPARRAY], rbxp  ; intpr1
560     mov         JSAMPARRAY [rsp+2*SIZEOF_JSAMPARRAY], rdxp  ; intpr2
561     mov         rbx, rsp
562
563     push        rdi
564     push        rcx
565     push        rax
566
567     %ifdef WIN64
568     mov         r8, rcx
569     mov         r9, rdi
570     mov         rcx, rax
571     mov         rdx, rbx
572     %else
573     mov         rdx, rcx
574     mov         rcx, rdi
575     mov         rdi, rax
576     mov         rsi, rbx
577     %endif
578
579     call        EXTN(jsimd_h2v1_merged_upsample_avx2)
580
581     pop         rax
582     pop         rcx
583     pop         rdi
584     mov         rsip, JSAMPARRAY [rsp+0*SIZEOF_JSAMPARRAY]
585     mov         rbxp, JSAMPARRAY [rsp+1*SIZEOF_JSAMPARRAY]
586     mov         rdxp, JSAMPARRAY [rsp+2*SIZEOF_JSAMPARRAY]
587     add         rsp, SIZEOF_JSAMPARRAY*4
588
589     pop         rbx
590     uncollect_args 4
591     pop         rbp
592     ret
593
594 ; For some reason, the OS X linker does not honor the request to align the
595 ; segment unless we do this.
596     align       32