FFmpeg
Loading...
Searching...
No Matches
ops_static.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2026 Ramiro Polla
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <assert.h>
22#include <limits.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#ifdef _WIN32
29#include <io.h>
30#include <fcntl.h>
31#endif
32
33/**
34 * This file is compiled as a standalone build-time tool and must not depend
35 * on internal FFmpeg libraries. The necessary utils are redefined below using
36 * standard C equivalents.
37 */
38
39#define AVUTIL_AVASSERT_H
40#define AVUTIL_LOG_H
41#define AVUTIL_MACROS_H
42#define AVUTIL_MEM_H
43#define AV_STRINGIFY(s) AV_TOSTRING(s)
44#define AV_TOSTRING(s) #s
45#define av_assert0(cond) do { \
46 if (!(cond)) { \
47 fprintf(stderr, "Assertion %s failed at %s:%d\n", \
48 AV_STRINGIFY(cond), __FILE__, __LINE__); \
49 abort(); \
50 } \
51} while (0)
52#define av_malloc(s) malloc(s)
53#define av_mallocz(s) calloc(1, s)
54#define av_realloc(p, s) realloc(p, s)
55#define av_strdup(s) strdup(s)
56#define av_free(p) free(p)
57#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
58#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
59#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
60#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
61
62static void av_freep(void *ptr)
63{
64 void **pptr = (void **) ptr;
65 if (pptr) {
66 ptr = *pptr;
67 if (ptr)
68 free(ptr);
69 *pptr = NULL;
70 }
71}
72
73static void *av_memdup(const void *p, size_t size)
74{
75 void *ptr = NULL;
76 if (p) {
77 ptr = av_malloc(size);
78 if (ptr)
79 memcpy(ptr, p, size);
80 }
81 return ptr;
82}
83
84#include "libavutil/dynarray.h"
85
86static void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
87 const uint8_t *elem_data)
88{
89 uint8_t *tab_elem_data = NULL;
90
91 FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
92 tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
93 if (elem_data)
94 memcpy(tab_elem_data, elem_data, elem_size);
95 }, {
96 av_freep(tab_ptr);
97 *nb_ptr = 0;
98 });
99 return tab_elem_data;
100}
101
102#include "libavutil/bprint.c"
103
104/*********************************************************************/
105#include "rasm.c"
106#include "rasm_print.c"
107#include "ops_impl.h"
108
109/**
110 * Implementation parameters for all exported functions. This list is
111 * compiled by performing a dummy run of all conversions in sws_ops and
112 * collecting all functions that need to be generated. This is achieved
113 * by running:
114 * make fate-sws-ops-entries-aarch64 GEN=1
115 */
120
122#define ENTRY(fname, ...) { .name = #fname, .params = __VA_ARGS__ },
123#include "ops_entries.c"
124#undef ENTRY
125 { NULL }
126};
127
128#include "ops_asmgen.c"
129
130/*********************************************************************/
131#define IMPL_PRIV(s) a64op_off(s->impl, offsetof_impl_priv)
132
133/**
134 * Set node where the continuation address will be loaded and impl will
135 * be incremented. This should be done right after impl->priv has been
136 * used.
137 */
139{
140 RasmContext *r = s->rctx;
141 s->load_cont_node = rasm_get_current_node(r);
142}
143
144/*********************************************************************/
145/* gather raw pixels from planes */
146/* SWS_UOP_READ_BIT */
147/* SWS_UOP_READ_NIBBLE */
148/* SWS_UOP_READ_PACKED */
149/* SWS_UOP_READ_PLANAR */
150
152 SwsAArch64OpRegs *regs)
153{
154 RasmContext *r = s->rctx;
155 AArch64VecViews shift_vec = a64op_vec_views(regs->vk[0]);
156 AArch64VecViews bitmask_vec = a64op_vec_views(regs->vk[1]);
157
158 rasm_annotate_next(r, "v128 shift_vec = impl->priv.v128;");
159 i_ldr(r, shift_vec.q, IMPL_PRIV(s));
161 if (p->block_size == 16) {
162 i_movi(r, bitmask_vec.b16, IMM(1)); CMT("v128 bitmask_vec = {1 <repeats 16 times>};");
163 } else {
164 i_movi(r, bitmask_vec.b8, IMM(1)); CMT("v128 bitmask_vec = {1 <repeats 8 times>, 0 <repeats 8 times>};");
165 }
166}
167
169 SwsAArch64OpRegs *regs)
170{
171 RasmContext *r = s->rctx;
173
174 rasm_annotate_next(r, "v128 nibble_mask = {0xf <repeats 8 times>, 0x0 <repeats 8 times>};");
175 i_movi(r, nibble_mask.b8, IMM(0x0f));
176}
177
179 SwsAArch64OpRegs *regs)
180{
181 RasmContext *r = s->rctx;
182 AArch64VecViews shift_vec = a64op_vec_views(regs->vk[0]);
183
184 rasm_annotate_next(r, "v128 shift_vec = impl->priv.v128;");
185 i_ldr(r, shift_vec.q, IMPL_PRIV(s));
187}
188
190 SwsAArch64OpRegs *regs)
191{
192 RasmContext *r = s->rctx;
193 RasmOp *vmask = regs->vk;
194 RasmOp mask_gpr = a64op_w(s->tmp0);
195 uint32_t mask_val[4] = { 0 };
196
197 /* Generate masks. */
198 rasm_add_comment(r, "generate masks");
199 LOOP_MASK(p, i) {
200 uint32_t val = (1u << p->par.pack.pattern[i]) - 1;
201 for (int j = 0; j < 4; j++) {
202 if (mask_val[j] == val) {
203 mask_val[i] = mask_val[j];
204 vmask[i] = vmask[j];
205 break;
206 }
207 }
208 if (!mask_val[i]) {
209 /**
210 * All-one values in movi only work up to 8-bit, and then
211 * at full 16- or 32-bit, but not for intermediate values
212 * like 10-bit. In those cases, we use mov + dup instead.
213 */
214 if (val <= 0xff || val == 0xffff) {
215 i_movi(r, vmask[i], IMM(val));
216 } else {
217 i_mov (r, mask_gpr, IMM(val));
218 i_dup (r, vmask[i], mask_gpr);
219 }
220 mask_val[i] = val;
221 vmask[i] = v_16b(vmask[i]);
222 }
223 }
224}
225
227 SwsAArch64OpRegs *regs)
228{
229 RasmContext *r = s->rctx;
230 RasmOp *vk = regs->vk;
231
232 /**
233 * TODO
234 * - pack elements in impl->priv and perform smaller loads
235 * - if only 1 element and not vh, load directly with ld1r
236 */
237
238 bool load_priv = false;
239 LOOP_MASK(p, i) {
240 if (!((p->par.clear.zero | p->par.clear.one) & SWS_COMP(i)))
241 load_priv = true;
242 }
243 if (load_priv) {
244 i_ldr(r, v_q(vk[0]), IMPL_PRIV(s)); CMT("v128 clear_vec = impl->priv.v128;");
246 }
247}
248
250 SwsAArch64OpRegs *regs)
251{
252 RasmContext *r = s->rctx;
253 RasmOp *vk = regs->vk;
254
255 RasmOp min_vec = regs->vt[0];
256 i_ldr(r, v_q(min_vec), IMPL_PRIV(s)); CMT("v128 min_vec = impl->priv.v128;");
258 LOOP_MASK(p, i) { i_dup(r, vk[i], a64op_elem(min_vec, i)); CMTF("v128 vmin%u = min_vec[%u];", i, i); }
259}
260
262 SwsAArch64OpRegs *regs)
263{
264 RasmContext *r = s->rctx;
265 RasmOp *vk = regs->vk;
266
267 RasmOp max_vec = regs->vt[0];
268 i_ldr(r, v_q(max_vec), IMPL_PRIV(s)); CMT("v128 max_vec = impl->priv.v128;");
270 LOOP_MASK(p, i) { i_dup(r, vk[i], a64op_elem(max_vec, i)); CMTF("v128 vmax%u = max_vec[%u];", i, i); }
271}
272
274 SwsAArch64OpRegs *regs)
275{
276 RasmContext *r = s->rctx;
277 RasmOp scale_vec = regs->vk[0];
278
279 RasmOp priv_ptr = s->tmp0;
280 i_add (r, priv_ptr, s->impl, IMM(offsetof_impl_priv)); CMT("v128 *scale_vec_ptr = &impl->priv;");
282 i_ld1r(r, vv_1(scale_vec), a64op_base(priv_ptr)); CMT("v128 scale_vec = broadcast(*scale_vec_ptr);");
283}
284
286 SwsAArch64OpRegs *regs)
287{
288 RasmContext *r = s->rctx;
289 RasmOp *sl = regs->sl;
290 RasmOp *sh = regs->sh;
291 RasmOp *vc = regs->vk;
292 RasmOp *vt = regs->vt;
293
294 RasmOp ptr = s->tmp0;
295 RasmOp coeff_veclist;
296
297 /* Preload coefficients from impl->priv. */
298 const int num_vregs = linear_num_vregs(p);
299 av_assert0(num_vregs <= 4);
300 switch (num_vregs) {
301 case 1: coeff_veclist = vv_1(vc[0]); break;
302 case 2: coeff_veclist = vv_2(vc[0], vc[1]); break;
303 case 3: coeff_veclist = vv_3(vc[0], vc[1], vc[2]); break;
304 case 4: coeff_veclist = vv_4(vc[0], vc[1], vc[2], vc[3]); break;
305 }
306 i_ldr(r, ptr, IMPL_PRIV(s)); CMT("v128 *vcoeff_ptr = impl->priv.ptr;");
308 i_ld1(r, coeff_veclist, a64op_base(ptr)); CMT("coeff_veclist = *vcoeff_ptr;");
309
310 /**
311 * Populate operands matrix from packed data into linear_vcoeff matrix
312 * and compute mask for rows that must be saved before being overwritten.
313 */
314 SwsCompMask save_mask = 0;
315 bool overwritten[4] = { false, false, false, false };
316 int i_coeff = 0;
317 LOOP_MASK(p, i) {
318 for (int j = 0; j < 5; j++) {
319 bool is_offset = (j == 0);
320 int src_j = is_offset ? 4 : (j - 1);
321 if (p->par.lin.zero & SWS_MASK(i, src_j))
322 continue;
323 uint8_t vc_i = i_coeff / 4;
324 uint8_t vc_j = i_coeff & 3;
325 regs->linear_vcoeff[i][j] = a64op_elem(vc[vc_i], vc_j);
326 i_coeff++;
327 if (!is_offset && overwritten[src_j])
328 save_mask |= SWS_COMP(src_j);
329 overwritten[i] = true;
330 }
331 }
332
333 /**
334 * Save rows that need to be used as input after they have been already
335 * written to.
336 */
337 RasmOp *tl = &vt[0];
338 RasmOp *th = &vt[4];
339 LOOP (save_mask, i) { i_mov16b(r, tl[i], sl[i]); CMTF("vsrcl[%u] = vl[%u];", i, i); }
340 LOOP_VH(s, save_mask, i) { i_mov16b(r, th[i], sh[i]); CMTF("vsrch[%u] = vh[%u];", i, i); }
341 LOOP (save_mask, i) { sl[i] = tl[i]; }
342 LOOP_VH(s, save_mask, i) { sh[i] = th[i]; }
343}
344
346 SwsAArch64OpRegs *regs)
347{
348 RasmContext *r = s->rctx;
349 RasmOp src_ptr = s->tmp0;
350
351 regs->dither_ptr = src_ptr;
352 i_ldr(r, src_ptr, IMPL_PRIV(s)); CMT("void *ptr = impl->priv.ptr;");
354}
355
356/*********************************************************************/
357/**
358 * Register assignment for CPS functions.
359 *
360 * The entry point of the SwsOpFunc is the `process` function. The
361 * first kernel function is called from `process`, and subsequent
362 * kernel functions are chained by directly branching to the next
363 * operation, using a continuation-passing style design. The last
364 * operation must be a write operation, which returns from the call
365 * to the `process` function.
366 *
367 * The GPRs used by the entire call-chain are listed below.
368 *
369 * Function arguments are passed in r0-r5. After the parameters from
370 * `exec` have been read, r0 is reused to branch to the continuation
371 * functions. After the original parameters from `impl` have been
372 * computed, r1 is reused as the `impl` pointer for each operation.
373 *
374 * Loop iterators are r6 for `bx` and r3 for `y`, reused from
375 * `y_start`, which doesn't need to be preserved.
376 *
377 * The intra-procedure-call temporary registers (r16 and r17) are used
378 * as scratch registers. They may be used by call veneers and PLT code
379 * inserted by the linker, so we cannot expect them to persist across
380 * branches between functions.
381 *
382 * The Platform Register (r18) is not used.
383 *
384 * The read/write data pointers and padding values first use up the
385 * remaining free caller-saved registers, and only then are the
386 * callee-saved registers (r19-r29) used.
387 *
388 * The Link Register (r30) is used when calling the first kernel, so it
389 * must be saved.
390 */
391
392static const int rw_gprs[] = {
393 9, 10, 11, 12,
394 13, 14, 15, 19,
395 20, 21, 22, 23,
396 24, 25, 26, 27,
397};
398
400{
401 /* Loop iterator variables. */
402 s->bx = a64op_gpw(6);
403 s->y = a64op_gpw(3); /* Reused from SwsOpFunc.y_start argument. */
404
405 /* Scratch registers. */
406 s->tmp0 = a64op_gpx(16); /* IP0 */
407 s->tmp1 = a64op_gpx(17); /* IP1 */
408
409 /* Read/Write data pointers. */
410 LOOP(imask, i) { s->in [i] = a64op_gpx(rw_gprs[(i * 4) + 0]); }
411 LOOP(omask, i) { s->out[i] = a64op_gpx(rw_gprs[(i * 4) + 1]); }
412}
413
415{
416 asmgen_common_frame(s, imask, omask);
417
418 /* SwsOpFunc arguments. */
419 s->exec = a64op_gpx(0); // const SwsOpExec *exec
420 s->impl = a64op_gpx(1); // const void *priv
421 s->bx_start = a64op_gpw(2); // int bx_start
422 s->y_start = a64op_gpw(3); // int y_start
423 s->bx_end = a64op_gpw(4); // int bx_end
424 s->y_end = a64op_gpw(5); // int y_end
425
426 /* CPS-related variables. */
427 s->op0_func = a64op_gpx(7);
428 s->op1_impl = a64op_gpx(8);
429
430 /* Read/Write data pointer padding. */
431 LOOP(imask, i) { s->in_bump [i] = a64op_gpx(rw_gprs[(i * 4) + 2]); }
432 LOOP(omask, i) { s->out_bump[i] = a64op_gpx(rw_gprs[(i * 4) + 3]); }
433}
434
436{
437 asmgen_common_frame(s, imask, omask);
438
439 /* CPS-related variables. */
440 s->cont = a64op_gpx(0); /* Reused from SwsOpFunc.exec argument. */
441 s->impl = a64op_gpx(1); /* Same as SwsOpFunc.impl argument. */
442}
443
444/*********************************************************************/
445/* Vector register assignment. */
447{
448 regs->sl[ 0] = a64op_vec( 0);
449 regs->sl[ 1] = a64op_vec( 1);
450 regs->sl[ 2] = a64op_vec( 2);
451 regs->sl[ 3] = a64op_vec( 3);
452 regs->sh[ 0] = a64op_vec( 4);
453 regs->sh[ 1] = a64op_vec( 5);
454 regs->sh[ 2] = a64op_vec( 6);
455 regs->sh[ 3] = a64op_vec( 7);
456 regs->dl[ 0] = a64op_vec( 0);
457 regs->dl[ 1] = a64op_vec( 1);
458 regs->dl[ 2] = a64op_vec( 2);
459 regs->dl[ 3] = a64op_vec( 3);
460 regs->dh[ 0] = a64op_vec( 4);
461 regs->dh[ 1] = a64op_vec( 5);
462 regs->dh[ 2] = a64op_vec( 6);
463 regs->dh[ 3] = a64op_vec( 7);
464 regs->vt[ 0] = a64op_vec(16);
465 regs->vt[ 1] = a64op_vec(17);
466 regs->vt[ 2] = a64op_vec(18);
467 regs->vt[ 3] = a64op_vec(19);
468 regs->vt[ 4] = a64op_vec(20);
469 regs->vt[ 5] = a64op_vec(21);
470 regs->vt[ 6] = a64op_vec(22);
471 regs->vt[ 7] = a64op_vec(23);
472 regs->vt[ 8] = a64op_vec(24);
473 regs->vt[ 9] = a64op_vec(25);
474 regs->vt[10] = a64op_vec(26);
475 regs->vt[11] = a64op_vec(27);
476 regs->vk[ 0] = a64op_vec(28);
477 regs->vk[ 1] = a64op_vec(29);
478 regs->vk[ 2] = a64op_vec(30);
479 regs->vk[ 3] = a64op_vec(31);
480}
481
482/*********************************************************************/
484{
485 RasmContext *r = s->rctx;
486 char func_name[128];
487
488 snprintf(func_name, sizeof(func_name), "ff_sws_process_%04x_neon", nibble_mask(mask));
489 rasm_func_begin(r, func_name, true, false);
491
493
494 /* Load values from impl. */
495 rasm_set_current_node(r, s->setup);
496 RasmOp impl_cont = a64op_off(s->impl, offsetof_impl_cont);
497 i_ldr(r, s->op0_func, impl_cont); CMT("SwsFuncPtr op0_func = impl->cont;");
498 i_add(r, s->op1_impl, s->impl, IMM(sizeof_impl)); CMT("SwsOpImpl *op1_impl = impl + 1;");
499
500 /* Reset impl and call first kernel. */
501 rasm_set_current_node(r, s->loop);
502 i_mov(r, s->impl, s->op1_impl); CMT("impl = op1_impl;");
503 i_blr(r, s->op0_func); CMT("op0_func();");
504}
505
506/*********************************************************************/
508{
509 const SwsAArch64OpImplParams *p = &entry->params;
510 RasmContext *r = s->rctx;
511
512 bool is_read = false;
513 bool is_write = false;
514 switch (p->uop) {
515 case SWS_UOP_READ_BIT:
519 is_read = true;
520 break;
525 is_write = true;
526 break;
527 default:
528 break;
529 }
530
531 rasm_func_begin(r, entry->name, true, !is_read);
532 asmgen_op_frame(s, is_read ? p->mask : 0, is_write ? p->mask : 0);
533
534 /**
535 * Set up vector register dimensions and reshape all vectors
536 * accordingly.
537 */
538 size_t el_size = ff_sws_pixel_type_size(p->type);
539 size_t total_size = p->block_size * el_size;
540
541 s->vec_size = FFMIN(total_size, 16);
542 s->use_vh = (s->vec_size != total_size);
543
544 s->el_size = el_size;
545 s->el_count = s->vec_size / el_size;
546 init_vectors_cps(s, &s->regs);
547 reshape_io_vectors(&s->regs, s->el_count, el_size);
548 reshape_temp_vectors(&s->regs, s->el_count, el_size);
549 reshape_const_vectors(&s->regs, s->el_count, el_size);
550
551 /* Common start for continuation-passing style (CPS) functions. */
553
554 /* Set up constants. */
555 switch (p->uop) {
556 case SWS_UOP_READ_BIT: asmgen_setup_read_bit(s, p, &s->regs); break;
557 case SWS_UOP_READ_NIBBLE: asmgen_setup_read_nibble(s, p, &s->regs); break;
558 case SWS_UOP_WRITE_BIT: asmgen_setup_write_bit(s, p, &s->regs); break;
559 case SWS_UOP_UNPACK: asmgen_setup_unpack(s, p, &s->regs); break;
560 case SWS_UOP_CLEAR: asmgen_setup_clear(s, p, &s->regs); break;
561 case SWS_UOP_MIN: asmgen_setup_min(s, p, &s->regs); break;
562 case SWS_UOP_MAX: asmgen_setup_max(s, p, &s->regs); break;
563 case SWS_UOP_SCALE: asmgen_setup_scale(s, p, &s->regs); break;
564 case SWS_UOP_LINEAR: asmgen_setup_linear(s, p, &s->regs); break;
565 case SWS_UOP_LINEAR_FMA: asmgen_setup_linear(s, p, &s->regs); break;
566 case SWS_UOP_DITHER: asmgen_setup_dither(s, p, &s->regs); break;
567 default:
568 break;
569 }
570
571 /* Emit uop kernel. */
572 switch (p->uop) {
573 case SWS_UOP_READ_BIT: asmgen_op_read_bit(s, p, &s->regs); break;
574 case SWS_UOP_READ_NIBBLE: asmgen_op_read_nibble(s, p, &s->regs); break;
575 case SWS_UOP_READ_PACKED: asmgen_op_read_packed(s, p, &s->regs); break;
576 case SWS_UOP_READ_PLANAR: asmgen_op_read_planar(s, p, &s->regs); break;
577 case SWS_UOP_WRITE_BIT: asmgen_op_write_bit(s, p, &s->regs); break;
578 case SWS_UOP_WRITE_NIBBLE: asmgen_op_write_nibble(s, p, &s->regs); break;
579 case SWS_UOP_WRITE_PACKED: asmgen_op_write_packed(s, p, &s->regs); break;
580 case SWS_UOP_WRITE_PLANAR: asmgen_op_write_planar(s, p, &s->regs); break;
581 case SWS_UOP_SWAP_BYTES: asmgen_op_swap_bytes(s, p, &s->regs); break;
582 case SWS_UOP_PERMUTE: asmgen_op_move(s, p, &s->regs); break;
583 case SWS_UOP_COPY: asmgen_op_move(s, p, &s->regs); break;
584 case SWS_UOP_UNPACK: asmgen_op_unpack(s, p, &s->regs); break;
585 case SWS_UOP_PACK: asmgen_op_pack(s, p, &s->regs); break;
586 case SWS_UOP_LSHIFT: asmgen_op_lshift(s, p, &s->regs); break;
587 case SWS_UOP_RSHIFT: asmgen_op_rshift(s, p, &s->regs); break;
588 case SWS_UOP_CLEAR: asmgen_op_clear(s, p, &s->regs); break;
589 case SWS_UOP_TO_U8: asmgen_op_convert(s, p, &s->regs); break;
590 case SWS_UOP_TO_U16: asmgen_op_convert(s, p, &s->regs); break;
591 case SWS_UOP_TO_U32: asmgen_op_convert(s, p, &s->regs); break;
592 case SWS_UOP_TO_F32: asmgen_op_convert(s, p, &s->regs); break;
593 case SWS_UOP_EXPAND_PAIR: asmgen_op_expand(s, p, &s->regs); break;
594 case SWS_UOP_EXPAND_QUAD: asmgen_op_expand(s, p, &s->regs); break;
595 case SWS_UOP_MIN: asmgen_op_min(s, p, &s->regs); break;
596 case SWS_UOP_MAX: asmgen_op_max(s, p, &s->regs); break;
597 case SWS_UOP_SCALE: asmgen_op_scale(s, p, &s->regs); break;
598 case SWS_UOP_LINEAR: asmgen_op_linear(s, p, &s->regs); break;
599 case SWS_UOP_LINEAR_FMA: asmgen_op_linear(s, p, &s->regs); break;
600 case SWS_UOP_DITHER: asmgen_op_dither(s, p, &s->regs); break;
601 /* TODO implement SWS_UOP_SHUFFLE */
602 default:
603 break;
604 }
605
606 if (is_write) {
607 /* Write functions return directly. */
608 i_ret(r);
609 } else {
610 /* Load continuation address and increment impl pointer. */
611 RasmNode *node = rasm_set_current_node(r, s->load_cont_node);
612 RasmOp impl_post = a64op_post(s->impl, sizeof_impl);
613 i_ldr(r, s->cont, impl_post); CMT("SwsFuncPtr cont = (impl++)->cont;");
615 /* Common end for remaining CPS functions. */
616 i_br (r, s->cont); CMT("jump to cont");
617 }
618}
619
620/*********************************************************************/
621
622/* Generate all functions described by ops_entries.c */
623static int asmgen(void)
624{
625 RasmContext *rctx = rasm_alloc();
626 if (!rctx)
627 return AVERROR(ENOMEM);
628
629 SwsAArch64Context s = { .rctx = rctx };
630 AVBPrint bp;
631 int ret;
632
634
635 /* Generate all process functions using rasm. */
640
641 /* Generate all functions from ops_entries.c using rasm. */
642 const SwsAArch64OpEntry *entries = ops_entries;
643 while (entries->name) {
644 asmgen_op_cps(&s, entries++);
645 if (rctx->error) {
646 ret = rctx->error;
647 goto error;
648 }
649 }
650
651 /* Print all rasm functions to stdout. */
652 printf("#include \"libavutil/aarch64/asm.S\"\n");
653 printf("\n");
654 ret = rasm_print(s.rctx, &bp);
655 if (ret < 0)
656 goto error;
657 fputs(bp.str, stdout);
658
659error:
661 rasm_free(&s.rctx);
662 return ret;
663}
664
665/*********************************************************************/
666int main(int argc, char *argv[])
667{
668#ifdef _WIN32
669 _setmode(_fileno(stdout), _O_BINARY);
670#endif
671
672 return asmgen();
673}
static const struct @070174075374214234277303002223103136214276265127 ops_entries[]
static double val(void *priv, double ch)
Definition aeval.c:77
#define entry
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
#define AV_BPRINT_SIZE_UNLIMITED
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
__device__ int printf(const char *,...)
int main
Definition dovi_rpuenc.c:38
#define FF_DYNARRAY_ADD(av_size_max, av_elt_size, av_array, av_size, av_success, av_failure)
Add an element to a dynamic array.
Definition dynarray.h:45
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
#define AVERROR(e)
Definition error.h:45
#define r
Definition input.c:42
static const uint16_t mask[17]
Definition lzw.c:38
static void asmgen_op_write_planar(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:377
static void asmgen_op_clear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:612
static void asmgen_op_read_packed(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:277
static void asmgen_op_read_nibble(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:244
#define CMT(comment)
Definition ops_asmgen.c:32
static void reshape_io_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
Definition ops_asmgen.c:36
static void asmgen_op_write_nibble(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:334
static void asmgen_op_move(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:456
static void reshape_temp_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
Definition ops_asmgen.c:47
static void asmgen_op_unpack(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:467
static void reshape_const_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
Definition ops_asmgen.c:54
static void asmgen_op_dither(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:922
static void asmgen_process(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
Definition ops_asmgen.c:139
static void asmgen_op_lshift(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:557
static void asmgen_op_linear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:910
static void asmgen_op_min(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:771
static void asmgen_op_convert(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:630
static void asmgen_op_swap_bytes(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:398
static void asmgen_op_read_planar(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:286
static void asmgen_op_expand(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:728
static void asmgen_op_scale(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:817
#define LOOP_VH(s, mask, idx)
Definition ops_asmgen.c:27
static void asmgen_op_rshift(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:575
#define CMTF(fmt,...)
Definition ops_asmgen.c:33
static void asmgen_op_read_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:215
static void asmgen_op_write_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:310
static void asmgen_op_max(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:794
static void asmgen_op_write_packed(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:368
static void asmgen_op_pack(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_asmgen.c:509
#define LOOP(mask, idx)
Definition ops_impl.h:56
static uint16_t nibble_mask(SwsCompMask mask)
Definition ops_impl.h:34
static int linear_num_vregs(const SwsAArch64OpImplParams *params)
Definition ops_impl.h:67
#define sizeof_impl
Definition ops_impl.h:87
#define LOOP_MASK(p, idx)
Definition ops_impl.h:63
#define offsetof_impl_priv
Definition ops_impl.h:86
#define offsetof_impl_cont
Definition ops_impl.h:85
static void * av_memdup(const void *p, size_t size)
Definition ops_static.c:73
static void asmgen_setup_clear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:226
#define FFMIN(a, b)
Definition ops_static.c:58
static void asmgen_setup_scale(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:273
static void asmgen_setup_read_nibble(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:168
static void asmgen_setup_max(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:261
static void asmgen_setup_read_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:151
static void asmgen_common_frame(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
Definition ops_static.c:399
static void asmgen_setup_linear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:285
static void asmgen_setup_write_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:178
static void asmgen_op_frame(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
Definition ops_static.c:435
static void asmgen_setup_min(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:249
static void asmgen_process_frame(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
Definition ops_static.c:414
static void init_vectors_cps(SwsAArch64Context *s, SwsAArch64OpRegs *regs)
Definition ops_static.c:446
static void asmgen_set_load_cont_node(SwsAArch64Context *s)
Set node where the continuation address will be loaded and impl will be incremented.
Definition ops_static.c:138
static void asmgen_setup_unpack(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:189
#define av_assert0(cond)
Definition ops_static.c:45
static void asmgen_process_cps(SwsAArch64Context *s, SwsCompMask mask)
Definition ops_static.c:483
static void asmgen_setup_dither(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:345
#define IMPL_PRIV(s)
Definition ops_static.c:131
static void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Definition ops_static.c:86
#define av_malloc(s)
Definition ops_static.c:52
static int asmgen(void)
Definition ops_static.c:623
static void asmgen_op_cps(SwsAArch64Context *s, const SwsAArch64OpEntry *entry)
Definition ops_static.c:507
static const int rw_gprs[]
Register assignment for CPS functions.
Definition ops_static.c:392
RasmNode * rasm_get_current_node(RasmContext *rctx)
Definition rasm.c:194
AArch64VecViews a64op_vec_views(RasmOp op)
Definition rasm.c:330
void rasm_free(RasmContext **prctx)
Definition rasm.c:37
RasmContext * rasm_alloc(void)
Definition rasm.c:32
int rasm_func_begin(RasmContext *rctx, const char *name, bool export, bool jumpable)
Definition rasm.c:209
RasmNode * rasm_add_comment(RasmContext *rctx, const char *comment)
Definition rasm.c:117
void rasm_annotate_next(RasmContext *rctx, const char *comment)
Definition rasm.c:263
RasmNode * rasm_set_current_node(RasmContext *rctx, RasmNode *node)
Definition rasm.c:199
#define i_mov16b(rctx, op0, op1)
Definition rasm.h:627
#define i_br(rctx, op0)
Definition rasm.h:554
#define i_dup(rctx, op0, op1)
Definition rasm.h:557
static RasmOp a64op_base(RasmOp op)
Definition rasm.h:506
static RasmOp vv_4(RasmOp op0, RasmOp op1, RasmOp op2, RasmOp op3)
Definition rasm.h:449
static RasmOp a64op_vec(uint8_t n)
Definition rasm.h:383
#define i_movi(rctx, op0, op1)
Definition rasm.h:576
static RasmOp a64op_elem(RasmOp op, uint8_t idx)
Definition rasm.h:422
static RasmOp a64op_gpx(uint8_t n)
Definition rasm.h:355
#define i_ld1(rctx, op0, op1)
Definition rasm.h:565
static RasmOp v_q(RasmOp op)
Definition rasm.h:434
static RasmOp a64op_off(RasmOp op, int16_t imm)
Definition rasm.h:507
#define i_ldr(rctx, op0, op1)
Definition rasm.h:571
static RasmOp vv_2(RasmOp op0, RasmOp op1)
Definition rasm.h:447
static RasmOp v_16b(RasmOp op)
Definition rasm.h:438
static RasmOp a64op_post(RasmOp op, int16_t imm)
Definition rasm.h:509
#define i_add(rctx, op0, op1, op2)
Definition rasm.h:547
#define i_ld1r(rctx, op0, op1)
Definition rasm.h:566
void int rasm_print(RasmContext *rctx, AVBPrint *bp)
Definition rasm_print.c:422
#define i_blr(rctx, op0)
Definition rasm.h:553
static RasmOp vv_1(RasmOp op0)
Definition rasm.h:446
#define i_ret(rctx)
Definition rasm.h:579
static RasmOp vv_3(RasmOp op0, RasmOp op1, RasmOp op2)
Definition rasm.h:448
static RasmOp a64op_w(RasmOp op)
Definition rasm.h:360
#define i_mov(rctx, op0, op1)
Definition rasm.h:575
static RasmOp a64op_gpw(uint8_t n)
Definition rasm.h:354
#define IMM(val)
Definition rasm.h:92
#define snprintf
Definition snprintf.h:34
This helper structure is used to mimic the assembler syntax for vector register modifiers.
Definition rasm.h:456
RasmOp b16
Definition rasm.h:465
RasmOp b8
Definition rasm.h:464
RasmOp q
Definition rasm.h:462
int error
Definition rasm.h:192
Implementation parameters for all exported functions.
Definition ops_static.c:116
const char * name
Definition ops_static.c:117
SwsAArch64OpImplParams params
Definition ops_static.c:118
SwsAArch64OpImplParams describes the parameters for an SwsUOpType operation.
Definition ops_impl.h:47
RasmOp vt[12]
Definition ops_asmgen.h:32
RasmOp linear_vcoeff[4][5]
Definition ops_asmgen.h:38
#define av_freep(p)
static void error(const char *err)
int size
Runtime assembler for AArch64.
Definition rasm.h:44
#define SWS_COMP(X)
Definition uops.h:97
#define SWS_COMP_ELEMS(N)
Definition uops.h:100
#define SWS_MASK(I, J)
Definition uops.h:231
@ SWS_UOP_TO_U8
Definition uops.h:159
@ SWS_UOP_PACK
Definition uops.h:172
@ SWS_UOP_PERMUTE
Definition uops.h:151
@ SWS_UOP_EXPAND_QUAD
Definition uops.h:158
@ SWS_UOP_READ_PLANAR
Definition uops.h:133
@ SWS_UOP_WRITE_PLANAR
Definition uops.h:142
@ SWS_UOP_READ_NIBBLE
Definition uops.h:138
@ SWS_UOP_MAX
Definition uops.h:168
@ SWS_UOP_READ_BIT
Definition uops.h:139
@ SWS_UOP_SWAP_BYTES
Definition uops.h:155
@ SWS_UOP_MIN
Definition uops.h:167
@ SWS_UOP_LINEAR
Definition uops.h:176
@ SWS_UOP_RSHIFT
Definition uops.h:174
@ SWS_UOP_COPY
Definition uops.h:152
@ SWS_UOP_WRITE_NIBBLE
Definition uops.h:144
@ SWS_UOP_LINEAR_FMA
Definition uops.h:177
@ SWS_UOP_SCALE
Definition uops.h:165
@ SWS_UOP_WRITE_PACKED
Definition uops.h:143
@ SWS_UOP_WRITE_BIT
Definition uops.h:145
@ SWS_UOP_READ_PACKED
Definition uops.h:137
@ SWS_UOP_EXPAND_PAIR
Definition uops.h:157
@ SWS_UOP_TO_U16
Definition uops.h:160
@ SWS_UOP_DITHER
Definition uops.h:178
@ SWS_UOP_CLEAR
Definition uops.h:175
@ SWS_UOP_TO_U32
Definition uops.h:161
@ SWS_UOP_UNPACK
Definition uops.h:171
@ SWS_UOP_TO_F32
Definition uops.h:162
@ SWS_UOP_LSHIFT
Definition uops.h:173
uint8_t SwsCompMask
Bit-mask of components.
Definition uops.h:93
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition uops.h:50