1/*
2 * Copyright (C) 2013-2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define ENTRY(f) .text; .align 4; .globl f; .type f,#function; f:
18#define END(f) .size f, .-f;
19
20#define BLEND_LIST(X) \
21    X(0, CLEAR) \
22    X(1, SRC) \
23    X(2, DST) \
24    X(3, SRC_OVER) \
25    X(4, DST_OVER) \
26    X(5, SRC_IN) \
27    X(6, DST_IN) \
28    X(7, SRC_OUT) \
29    X(8, DST_OUT) \
30    X(9, SRC_ATOP) \
31    X(10, DST_ATOP) \
32    X(11, XOR) \
33    X(14, MULTIPLY) \
34    X(21, DIFFERENCE) \
35    X(34, ADD) \
36    X(35, SUBTRACT)
37
38/* For every blend operation supported, define a macro with just the arithmetic
39 * component.  The rest can be handled later on.
40 *
41 * At entry q0-q3 contain the RGBA data from the destination buffer, and q8-q11
42 * contain the data from the source buffer.  Both have already been split out
43 * into one colour component per register (if necessary).  q3 and q11 contain
44 * the alpha components.
45 *
46 * At the same time as defining the assembly macro, define a corresponding
47 * preprocessor macro indicating any other requirements.
48 *    zipped=0 -- The macro does not require the RGBA components to be
49 *                separated.
50 *    lddst=0  -- The macro does not require data from the destination buffer.
51 *    ldsrc=0  -- The macro does not require data from the source buffer.
52 *    nowrap=1 -- The macro requires no wrapper at all, and should simply be
53 *                inserted without any surrounding load/store or loop code.
54 */
55
56#define params_CLEAR zipped=0, lddst=0, ldsrc=0
57.macro blend_kernel_CLEAR
58        movi    v0.16b, #0
59        movi    v1.16b, #0
60        movi    v2.16b, #0
61        movi    v3.16b, #0
62.endm
63
64#define params_SRC zipped=0, lddst=0
65.macro blend_kernel_SRC
66        mov     v0.16b, v8.16b
67        mov     v1.16b, v9.16b
68        mov     v2.16b, v10.16b
69        mov     v3.16b, v11.16b
70.endm
71
72#define params_DST nowrap=1
73.macro blend_kernel_DST
74        /* nop */
75.endm
76
77#define params_SRC_OVER zipped=1
78.macro blend_kernel_SRC_OVER
79        mvn         v7.16b, v11.16b
80
81        umull2      v12.8h, v7.16b, v0.16b
82        umull       v0.8h,  v7.8b,  v0.8b
83        umull2      v13.8h, v7.16b, v1.16b
84        umull       v1.8h,  v7.8b,  v1.8b
85        umull2      v14.8h, v7.16b, v2.16b
86        umull       v2.8h,  v7.8b,  v2.8b
87        umull2      v15.8h, v7.16b, v3.16b
88        umull       v3.8h,  v7.8b,  v3.8b
89
90        rshrn       v4.8b,  v0.8h,  #8
91        rshrn2      v4.16b, v12.8h, #8
92        rshrn       v5.8b,  v1.8h,  #8
93        rshrn2      v5.16b, v13.8h, #8
94        rshrn       v6.8b,  v2.8h,  #8
95        rshrn2      v6.16b, v14.8h, #8
96        rshrn       v7.8b,  v3.8h,  #8
97        rshrn2      v7.16b, v15.8h, #8
98
99        uaddw       v0.8h,  v0.8h,  v4.8b
100        uaddw2      v12.8h, v12.8h, v4.16b
101        uaddw       v1.8h,  v1.8h,  v5.8b
102        uaddw2      v13.8h, v13.8h, v5.16b
103        uaddw       v2.8h,  v2.8h,  v6.8b
104        uaddw2      v14.8h, v14.8h, v6.16b
105        uaddw       v3.8h,  v3.8h,  v7.8b
106        uaddw2      v15.8h, v15.8h, v7.16b
107
108        rshrn       v0.8b,  v0.8h,  #8
109        rshrn2      v0.16b, v12.8h, #8
110        rshrn       v1.8b,  v1.8h,  #8
111        rshrn2      v1.16b, v13.8h, #8
112        rshrn       v2.8b,  v2.8h,  #8
113        rshrn2      v2.16b, v14.8h, #8
114        rshrn       v3.8b,  v3.8h,  #8
115        rshrn2      v3.16b, v15.8h, #8
116
117        uqadd       v0.16b, v0.16b, v8.16b
118        uqadd       v1.16b, v1.16b, v9.16b
119        uqadd       v2.16b, v2.16b, v10.16b
120        uqadd       v3.16b, v3.16b, v11.16b
121.endm
122
123#define params_DST_OVER zipped=1
124.macro blend_kernel_DST_OVER
125        mvn         v7.16b, v3.16b
126
127        umull2      v12.8h, v7.16b, v8.16b
128        umull       v8.8h,  v7.8b,  v8.8b
129        umull2      v13.8h, v7.16b, v9.16b
130        umull       v9.8h,  v7.8b,  v9.8b
131        umull2      v14.8h, v7.16b, v10.16b
132        umull       v10.8h, v7.8b,  v10.8b
133        umull2      v15.8h, v7.16b, v11.16b
134        umull       v11.8h, v7.8b,  v11.8b
135
136        rshrn       v4.8b,  v8.8h,  #8
137        rshrn2      v4.16b, v12.8h, #8
138        rshrn       v5.8b,  v9.8h,  #8
139        rshrn2      v5.16b, v13.8h, #8
140        rshrn       v6.8b,  v10.8h, #8
141        rshrn2      v6.16b, v14.8h, #8
142        rshrn       v7.8b,  v11.8h, #8
143        rshrn2      v7.16b, v15.8h, #8
144
145        uaddw       v8.8h,  v8.8h,  v4.8b
146        uaddw2      v12.8h, v12.8h, v4.16b
147        uaddw       v9.8h,  v9.8h,  v5.8b
148        uaddw2      v13.8h, v13.8h, v5.16b
149        uaddw       v10.8h, v10.8h, v6.8b
150        uaddw2      v14.8h, v14.8h, v6.16b
151        uaddw       v11.8h, v11.8h, v7.8b
152        uaddw2      v15.8h, v15.8h, v7.16b
153
154        rshrn       v8.8b,  v8.8h,  #8
155        rshrn2      v8.16b, v12.8h, #8
156        rshrn       v9.8b,  v9.8h,  #8
157        rshrn2      v9.16b, v13.8h, #8
158        rshrn       v10.8b,  v10.8h, #8
159        rshrn2      v10.16b, v14.8h, #8
160        rshrn       v11.8b,  v11.8h, #8
161        rshrn2      v11.16b, v15.8h, #8
162
163        uqadd       v0.16b, v0.16b, v8.16b
164        uqadd       v1.16b, v1.16b, v9.16b
165        uqadd       v2.16b, v2.16b, v10.16b
166        uqadd       v3.16b, v3.16b, v11.16b
167.endm
168
169#define params_SRC_IN zipped=1
170.macro blend_kernel_SRC_IN
171        umull2      v12.8h, v3.16b, v8.16b
172        umull       v0.8h,  v3.8b,  v8.8b
173        umull2      v13.8h, v3.16b, v9.16b
174        umull       v1.8h,  v3.8b,  v9.8b
175        umull2      v14.8h, v3.16b, v10.16b
176        umull       v2.8h,  v3.8b,  v10.8b
177        umull2      v15.8h, v3.16b, v11.16b
178        umull       v3.8h,  v3.8b,  v11.8b
179
180        rshrn       v4.8b,  v0.8h,  #8
181        rshrn2      v4.16b, v12.8h, #8
182        rshrn       v5.8b,  v1.8h,  #8
183        rshrn2      v5.16b, v13.8h, #8
184        rshrn       v6.8b,  v2.8h,  #8
185        rshrn2      v6.16b, v14.8h, #8
186        rshrn       v7.8b,  v3.8h,  #8
187        rshrn2      v7.16b, v15.8h, #8
188
189        uaddw       v0.8h,  v0.8h,  v4.8b
190        uaddw2      v12.8h, v12.8h, v4.16b
191        uaddw       v1.8h,  v1.8h,  v5.8b
192        uaddw2      v13.8h, v13.8h, v5.16b
193        uaddw       v2.8h,  v2.8h,  v6.8b
194        uaddw2      v14.8h, v14.8h, v6.16b
195        uaddw       v3.8h,  v3.8h,  v7.8b
196        uaddw2      v15.8h, v15.8h, v7.16b
197
198        rshrn       v0.8b,  v0.8h,  #8
199        rshrn2      v0.16b, v12.8h, #8
200        rshrn       v1.8b,  v1.8h,  #8
201        rshrn2      v1.16b, v13.8h, #8
202        rshrn       v2.8b,  v2.8h,  #8
203        rshrn2      v2.16b, v14.8h, #8
204        rshrn       v3.8b,  v3.8h,  #8
205        rshrn2      v3.16b, v15.8h, #8
206.endm
207
208#define params_DST_IN zipped=1
209.macro blend_kernel_DST_IN
210        umull2      v12.8h, v0.16b, v11.16b
211        umull       v0.8h,  v0.8b,  v11.8b
212        umull2      v13.8h, v1.16b, v11.16b
213        umull       v1.8h,  v1.8b,  v11.8b
214        umull2      v14.8h, v2.16b, v11.16b
215        umull       v2.8h,  v2.8b,  v11.8b
216        umull2      v15.8h, v3.16b, v11.16b
217        umull       v3.8h,  v3.8b,  v11.8b
218
219        rshrn       v4.8b,  v0.8h,  #8
220        rshrn2      v4.16b, v12.8h, #8
221        rshrn       v5.8b,  v1.8h,  #8
222        rshrn2      v5.16b, v13.8h, #8
223        rshrn       v6.8b,  v2.8h,  #8
224        rshrn2      v6.16b, v14.8h, #8
225        rshrn       v7.8b,  v3.8h,  #8
226        rshrn2      v7.16b, v15.8h, #8
227
228        uaddw       v0.8h,  v0.8h,  v4.8b
229        uaddw2      v12.8h, v12.8h, v4.16b
230        uaddw       v1.8h,  v1.8h,  v5.8b
231        uaddw2      v13.8h, v13.8h, v5.16b
232        uaddw       v2.8h,  v2.8h,  v6.8b
233        uaddw2      v14.8h, v14.8h, v6.16b
234        uaddw       v3.8h,  v3.8h,  v7.8b
235        uaddw2      v15.8h, v15.8h, v7.16b
236
237        rshrn       v0.8b,  v0.8h,  #8
238        rshrn2      v0.16b, v12.8h, #8
239        rshrn       v1.8b,  v1.8h,  #8
240        rshrn2      v1.16b, v13.8h, #8
241        rshrn       v2.8b,  v2.8h,  #8
242        rshrn2      v2.16b, v14.8h, #8
243        rshrn       v3.8b,  v3.8h,  #8
244        rshrn2      v3.16b, v15.8h, #8
245.endm
246
247#define params_SRC_OUT zipped=1
248.macro blend_kernel_SRC_OUT
249        mvn         v3.16b, v3.16b
250        blend_kernel_SRC_IN
251.endm
252
253
254#define params_DST_OUT zipped=1
255.macro blend_kernel_DST_OUT
256        mvn         v11.16b, v11.16b
257        blend_kernel_DST_IN
258.endm
259
260#define params_SRC_ATOP zipped=1
261.macro blend_kernel_SRC_ATOP
262        mvn         v11.16b, v11.16b
263
264        umull2      v12.8h, v11.16b, v0.16b
265        umull       v0.8h,  v11.8b,  v0.8b
266        umull2      v13.8h, v11.16b, v1.16b
267        umull       v1.8h,  v11.8b,  v1.8b
268        umull2      v14.8h, v11.16b, v2.16b
269        umull       v2.8h,  v11.8b,  v2.8b
270
271        umull2      v4.8h,  v3.16b, v8.16b
272        umull       v8.8h,  v3.8b,  v8.8b
273        umull2      v5.8h,  v3.16b, v9.16b
274        umull       v9.8h,  v3.8b,  v9.8b
275        umull2      v6.8h,  v3.16b, v10.16b
276        umull       v10.8h, v3.8b,  v10.8b
277
278        uqadd       v12.8h, v12.8h, v4.8h
279        uqadd       v0.8h,  v0.8h,  v8.8h
280        uqadd       v13.8h, v13.8h, v5.8h
281        uqadd       v1.8h,  v1.8h,  v9.8h
282        uqadd       v14.8h, v14.8h, v6.8h
283        uqadd       v2.8h,  v2.8h,  v10.8h
284
285        urshr       v8.8h,  v0.8h,  #8
286        urshr       v4.8h,  v12.8h, #8
287        urshr       v9.8h,  v1.8h,  #8
288        urshr       v5.8h,  v13.8h, #8
289        urshr       v10.8h, v2.8h,  #8
290        urshr       v6.8h,  v14.8h, #8
291
292        uqadd       v0.8h,  v0.8h,  v8.8h
293        uqadd       v12.8h, v12.8h, v4.8h
294        uqadd       v1.8h,  v1.8h,  v9.8h
295        uqadd       v13.8h, v13.8h, v5.8h
296        uqadd       v2.8h,  v2.8h,  v10.8h
297        uqadd       v14.8h, v14.8h, v6.8h
298
299        uqrshrn     v0.8b,  v0.8h,  #8
300        uqrshrn2    v0.16b, v12.8h, #8
301        uqrshrn     v1.8b,  v1.8h,  #8
302        uqrshrn2    v1.16b, v13.8h, #8
303        uqrshrn     v2.8b,  v2.8h,  #8
304        uqrshrn2    v2.16b, v14.8h, #8
305.endm
306
307#define params_DST_ATOP zipped=1
308.macro blend_kernel_DST_ATOP
309        mvn         v3.16b, v3.16b
310
311        umull2      v12.8h, v11.16b, v0.16b
312        umull       v0.8h,  v11.8b,  v0.8b
313        umull2      v13.8h, v11.16b, v1.16b
314        umull       v1.8h,  v11.8b,  v1.8b
315        umull2      v14.8h, v11.16b, v2.16b
316        umull       v2.8h,  v11.8b,  v2.8b
317
318        umull2      v4.8h,  v3.16b, v8.16b
319        umull       v8.8h,  v3.8b,  v8.8b
320        umull2      v5.8h,  v3.16b, v9.16b
321        umull       v9.8h,  v3.8b,  v9.8b
322        umull2      v6.8h,  v3.16b, v10.16b
323        umull       v10.8h, v3.8b,  v10.8b
324
325        uqadd       v12.8h, v12.8h, v4.8h
326        uqadd       v0.8h,  v0.8h,  v8.8h
327        uqadd       v13.8h, v13.8h, v5.8h
328        uqadd       v1.8h,  v1.8h,  v9.8h
329        uqadd       v14.8h, v14.8h, v6.8h
330        uqadd       v2.8h,  v2.8h,  v10.8h
331
332        urshr       v8.8h,  v0.8h,  #8
333        urshr       v4.8h,  v12.8h, #8
334        urshr       v9.8h,  v1.8h,  #8
335        urshr       v5.8h,  v13.8h, #8
336        urshr       v10.8h, v2.8h,  #8
337        urshr       v6.8h,  v14.8h, #8
338
339        uqadd       v0.8h,  v0.8h,  v8.8h
340        uqadd       v12.8h, v12.8h, v4.8h
341        uqadd       v1.8h,  v1.8h,  v9.8h
342        uqadd       v13.8h, v13.8h, v5.8h
343        uqadd       v2.8h,  v2.8h,  v10.8h
344        uqadd       v14.8h, v14.8h, v6.8h
345
346        uqrshrn     v0.8b,  v0.8h,  #8
347        uqrshrn2    v0.16b, v12.8h, #8
348        uqrshrn     v1.8b,  v1.8h,  #8
349        uqrshrn2    v1.16b, v13.8h, #8
350        uqrshrn     v2.8b,  v2.8h,  #8
351        uqrshrn2    v2.16b, v14.8h, #8
352
353        mov         v3.16b, v11.16b
354.endm
355
356#define params_MULTIPLY zipped=0
357.macro blend_kernel_MULTIPLY
358        umull2      v12.8h, v0.16b, v8.16b
359        umull       v0.8h,  v0.8b,  v8.8b
360        umull2      v13.8h, v1.16b, v9.16b
361        umull       v1.8h,  v1.8b,  v9.8b
362        umull2      v14.8h, v2.16b, v10.16b
363        umull       v2.8h,  v2.8b,  v10.8b
364        umull2      v15.8h, v3.16b, v11.16b
365        umull       v3.8h,  v3.8b,  v11.8b
366
367        rshrn       v4.8b,  v0.8h,  #8
368        rshrn2      v4.16b, v12.8h, #8
369        rshrn       v5.8b,  v1.8h,  #8
370        rshrn2      v5.16b, v13.8h, #8
371        rshrn       v6.8b,  v2.8h,  #8
372        rshrn2      v6.16b, v14.8h, #8
373        rshrn       v7.8b,  v3.8h,  #8
374        rshrn2      v7.16b, v15.8h, #8
375
376        uaddw       v0.8h,  v0.8h,  v4.8b
377        uaddw2      v12.8h, v12.8h, v4.16b
378        uaddw       v1.8h,  v1.8h,  v5.8b
379        uaddw2      v13.8h, v13.8h, v5.16b
380        uaddw       v2.8h,  v2.8h,  v6.8b
381        uaddw2      v14.8h, v14.8h, v6.16b
382        uaddw       v3.8h,  v3.8h,  v7.8b
383        uaddw2      v15.8h, v15.8h, v7.16b
384
385        rshrn       v0.8b,  v0.8h,  #8
386        rshrn2      v0.16b, v12.8h, #8
387        rshrn       v1.8b,  v1.8h,  #8
388        rshrn2      v1.16b, v13.8h, #8
389        rshrn       v2.8b,  v2.8h,  #8
390        rshrn2      v2.16b, v14.8h, #8
391        rshrn       v3.8b,  v3.8h,  #8
392        rshrn2      v3.16b, v15.8h, #8
393.endm
394
395#define params_ADD zipped=0
396.macro blend_kernel_ADD
397        uqadd    v0.16b, v0.16b, v8.16b
398        uqadd    v1.16b, v1.16b, v9.16b
399        uqadd    v2.16b, v2.16b, v10.16b
400        uqadd    v3.16b, v3.16b, v11.16b
401.endm
402
403#define params_SUBTRACT zipped=0
404.macro blend_kernel_SUBTRACT
405        uqsub    v0.16b, v0.16b, v8.16b
406        uqsub    v1.16b, v1.16b, v9.16b
407        uqsub    v2.16b, v2.16b, v10.16b
408        uqsub    v3.16b, v3.16b, v11.16b
409.endm
410
411#define params_DIFFERENCE zipped=0
412.macro blend_kernel_DIFFERENCE
413        uabd    v0.16b, v0.16b, v8.16b
414        uabd    v1.16b, v1.16b, v9.16b
415        uabd    v2.16b, v2.16b, v10.16b
416        uabd    v3.16b, v3.16b, v11.16b
417.endm
418
419#define params_XOR zipped=0
420.macro blend_kernel_XOR
421        eor     v0.16b, v0.16b, v8.16b
422        eor     v1.16b, v1.16b, v9.16b
423        eor     v2.16b, v2.16b, v10.16b
424        eor     v3.16b, v3.16b, v11.16b
425.endm
426
427
428/* Define the wrapper code which will load and store the data, iterate the
429 * correct number of times, and safely handle the remainder at the end of the
430 * loop.  Various sections of assembly code are dropped or substituted for
431 * simpler operations if they're not needed.
432 */
433.macro wrap_line kernel, nowrap=0, zipped=1, lddst=1, ldsrc=1, pld=1
434.if \nowrap
435        \kernel
436.else
437        sub     x3, sp, #32
438        sub     sp, sp, #64
439        st1     {v8.1d - v11.1d}, [sp]
440        st1     {v12.1d - v15.1d}, [x3]
441        subs    x2, x2, #64
442        b       2f
443.align 4
4441:
445  .if \lddst
446    .if \zipped
447        ld4     {v0.16b - v3.16b}, [x0]
448    .else
449        ld1     {v0.16b - v3.16b}, [x0]
450    .endif
451  .endif
452  .if \ldsrc
453    .if \zipped
454        ld4     {v8.16b - v11.16b}, [x1], #64
455    .else
456        ld1     {v8.16b - v11.16b}, [x1], #64
457    .endif
458  .endif
459  .if \pld
460#if 0 /* TODO: test this on real hardware */
461    .if \lddst ; prfm PLDL1STRM, [x0, #192] ; .endif
462    .if \ldsrc ; prfm PLDL1STRM, [x1, #192] ; .endif
463#endif
464  .endif
465
466        \kernel
467
468        subs    x2, x2, #64
469  .if \zipped
470        st4     {v0.16b,v1.16b,v2.16b,v3.16b}, [x0], #64
471  .else
472        st1     {v0.16b,v1.16b,v2.16b,v3.16b}, [x0], #64
473  .endif
474
4752:      bge     1b
476        adds    x2, x2, #64
477        beq     2f
478
479        /* To handle the tail portion of the data (something less than 64
480         * bytes) load small power-of-two chunks into working registers.  It
481         * doesn't matter where they end up in the register; the same process
482         * will store them back out using the same positions and the operations
483         * don't require data to interact with its neighbours.
484         */
485        movi    v0.16b, #0
486        movi    v1.16b, #0
487        movi    v2.16b, #0
488        movi    v3.16b, #0
489
490        movi    v8.16b, #0
491        movi    v9.16b, #0
492        movi    v10.16b, #0
493        movi    v11.16b, #0
494
495        tbz     x2, #5, 1f
496  .if \lddst ; ld1     {v2.16b,v3.16b}, [x0], #32   ; .endif
497  .if \ldsrc ; ld1     {v10.16b,v11.16b}, [x1], #32 ; .endif
4981:      tbz     x2, #4, 1f
499  .if \lddst ; ld1     {v1.16b}, [x0], #16  ; .endif
500  .if \ldsrc ; ld1     {v9.16b}, [x1], #16  ; .endif
5011:      tbz     x2, #3, 1f
502  .if \lddst ; ld1     {v0.d}[1], [x0], #8 ; .endif
503  .if \ldsrc ; ld1     {v8.d}[1], [x1], #8 ; .endif
5041:      tbz     x2, #2, 1f
505  .if \lddst ; ld1     {v0.s}[1], [x0], #4 ; .endif
506  .if \ldsrc ; ld1     {v8.s}[1], [x1], #4 ; .endif
5071:      tbz     x2, #1, 1f
508  .if \lddst ; ld1     {v0.h}[1], [x0], #2 ; .endif
509  .if \ldsrc ; ld1     {v8.h}[1], [x1], #2 ; .endif
5101:      tbz     x2, #0, 1f
511  .if \lddst ; ld1     {v0.b}[1], [x0], #1 ; .endif
512  .if \ldsrc ; ld1     {v8.b}[1], [x1], #1 ; .endif
5131:
514  .if \lddst ; sub     x0, x0, x2           ; .endif
515
516.if \zipped
517        /* One small impediment in the process above is that some of the load
518         * operations can't perform byte-wise structure deinterleaving at the
519         * same time as loading only part of a register.  So the data is loaded
520         * linearly and unpacked manually at this point.
521         */
522        uzp1    v4.16b, v0.16b, v1.16b
523        uzp2    v5.16b, v0.16b, v1.16b
524        uzp1    v6.16b, v2.16b, v3.16b
525        uzp2    v7.16b, v2.16b, v3.16b
526        uzp1    v0.16b, v4.16b, v6.16b
527        uzp2    v2.16b, v4.16b, v6.16b
528        uzp1    v1.16b, v5.16b, v7.16b
529        uzp2    v3.16b, v5.16b, v7.16b
530
531        uzp1    v4.16b, v8.16b, v9.16b
532        uzp2    v5.16b, v8.16b, v9.16b
533        uzp1    v6.16b, v10.16b, v11.16b
534        uzp2    v7.16b, v10.16b, v11.16b
535        uzp1    v8.16b, v4.16b, v6.16b
536        uzp2    v10.16b, v4.16b, v6.16b
537        uzp1    v9.16b, v5.16b, v7.16b
538        uzp2    v11.16b, v5.16b, v7.16b
539
540        \kernel
541
542        zip1    v4.16b, v0.16b, v2.16b
543        zip2    v6.16b, v0.16b, v2.16b
544        zip1    v5.16b, v1.16b, v3.16b
545        zip2    v7.16b, v1.16b, v3.16b
546        zip1    v0.16b, v4.16b, v5.16b
547        zip2    v1.16b, v4.16b, v5.16b
548        zip1    v2.16b, v6.16b, v7.16b
549        zip2    v3.16b, v6.16b, v7.16b
550  .else
551        \kernel
552  .endif
553
554        tbz     x2, #5, 1f
555        st1     {v2.16b,v3.16b}, [x0], #32
5561:      tbz     x2, #4, 1f
557        st1     {v1.16b}, [x0], #16
5581:      tbz     x2, #3, 1f
559        st1     {v0.d}[1], [x0], #8
5601:      tbz     x2, #2, 1f
561        st1     {v0.s}[1], [x0], #4
5621:      tbz     x2, #1, 1f
563        st1     {v0.h}[1], [x0], #2
5641:      tbz     x2, #0, 2f
565        st1     {v0.b}[1], [x0], #1
5662:      ld1     {v8.1d - v11.1d}, [sp], #32
567        ld1     {v12.1d - v15.1d}, [sp], #32
568.endif
569        mov     x0, #0
570        ret
571.endm
572
573
574/* produce list of blend_line_XX() functions; each function uses the wrap_line
575 * macro, passing it the name of the operation macro it wants along with
576 * optional parameters to remove unnecessary operations.
577 */
578#define BLEND_X(d, n) ENTRY(blend_line_##n) ; wrap_line blend_kernel_##n, params_##n ; END(blend_line_##n) ;
579    BLEND_LIST(BLEND_X)
580#undef BLEND_X
581
582#define BLEND_X(d, n) .set tablesize, d+1 ;
583    BLEND_LIST(BLEND_X)
584#undef BLEND_X
585
586/*  int rsdIntrinsicBlend_K(
587 *          uchar4 *out,        // x0
588 *          uchar4 const *in,   // x1
589 *          int slot,           // x2
590 *          size_t xstart,      // x3
591 *          size_t xend);       // x4
592 */
593ENTRY(rsdIntrinsicBlend_K)
594    adrp    x5, blendtable
595    add     x5, x5, :lo12:blendtable
596    cmp     w2, tablesize >> 1
597    bhs     1f
598    ldrsh   x6, [x5, w2, uxtw #1]
599    add     x0, x0, w3, uxtw #2
600    add     x1, x1, w3, uxtw #2
601    sub     w2, w4, w3
602    ubfiz   x2, x2, #2, #32 /* TODO: fix */
603    cbz     x6, 1f
604    adr     x5, 2f
605    add     x6, x5, x6
6062:  br      x6
6071:  mov     x0, #-1
608    ret
609
610END(rsdIntrinsicBlend_K)
611
612.rodata
613.set off,0
614blendtable:
615#define BLEND_X(d, n) .rept d-off ; .hword 0 ; .endr ; .hword blend_line_##n - 2b ; .set off, d+1 ;
616        BLEND_LIST(BLEND_X)
617#undef BLEND_X
618
619