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 * Integer mul/mla by element does not exist for 8-bit elements, and
312 * requires the element register to be in v0-v15 for 16-bit elements.
313 * For these types, the coefficients used as multiplication operands
314 * are broadcast into full temp vectors instead. Temp vectors 8-11
315 * are otherwise only used by the floating-point fmul+fadd path, so
316 * they are free for integer types.
317 */
318 const bool dup_coeffs = (p->type == SWS_PIXEL_U8 || p->type == SWS_PIXEL_U16);
319 const int nelems = linear_vreg_nelems(p->type);
320 RasmOp *vint = &vt[8];
321 int i_vint = 0;
322
323 /**
324 * Populate operands matrix from packed data into linear_vcoeff matrix
325 * and compute mask for rows that must be saved before being overwritten.
326 */
327 SwsCompMask save_mask = 0;
328 bool overwritten[4] = { false, false, false, false };
329 int i_coeff = 0;
330 LOOP_MASK(p, i) {
331 bool first = true;
332 for (int j = 0; j < 5; j++) {
333 bool is_offset = (j == 0);
334 int src_j = is_offset ? 4 : (j - 1);
335 if (p->par.lin.zero & SWS_MASK(i, src_j))
336 continue;
337 uint8_t vc_i = i_coeff / nelems;
338 uint8_t vc_j = i_coeff & (nelems - 1);
339 RasmOp vcoeff = a64op_elem(vc[vc_i], vc_j);
340 /**
341 * The first coefficient of a row is not used as a multiplication
342 * operand if it is either an offset (broadcast) or one (move).
343 */
344 bool is_one = !is_offset && (p->par.lin.one & SWS_MASK(i, src_j));
345 if (dup_coeffs && !(first && (is_offset || is_one))) {
346 av_assert0(i_vint < 4);
347 i_dup(r, vint[i_vint], vcoeff); CMTF("vcoeff%u = broadcast(coeff[%u][%u]);", i_vint, i, src_j);
348 vcoeff = vint[i_vint++];
349 }
350 regs->linear_vcoeff[i][j] = vcoeff;
351 i_coeff++;
352 first = false;
353 if (!is_offset && overwritten[src_j])
354 save_mask |= SWS_COMP(src_j);
355 overwritten[i] = true;
356 }
357 }
358
359 /**
360 * Save rows that need to be used as input after they have been already
361 * written to.
362 */
363 RasmOp *tl = &vt[0];
364 RasmOp *th = &vt[4];
365 LOOP (save_mask, i) { i_mov16b(r, tl[i], sl[i]); CMTF("vsrcl[%u] = vl[%u];", i, i); }
366 LOOP_VH(s, save_mask, i) { i_mov16b(r, th[i], sh[i]); CMTF("vsrch[%u] = vh[%u];", i, i); }
367 LOOP (save_mask, i) { sl[i] = tl[i]; }
368 LOOP_VH(s, save_mask, i) { sh[i] = th[i]; }
369}
370
372 SwsAArch64OpRegs *regs)
373{
374 RasmContext *r = s->rctx;
375 RasmOp src_ptr = s->tmp0;
376
377 regs->dither_ptr = src_ptr;
378 i_ldr(r, src_ptr, IMPL_PRIV(s)); CMT("void *ptr = impl->priv.ptr;");
380}
381
382/*********************************************************************/
383/**
384 * Register assignment for CPS functions.
385 *
386 * The entry point of the SwsOpFunc is the `process` function. The
387 * first kernel function is called from `process`, and subsequent
388 * kernel functions are chained by directly branching to the next
389 * operation, using a continuation-passing style design. The last
390 * operation must be a write operation, which returns from the call
391 * to the `process` function.
392 *
393 * The GPRs used by the entire call-chain are listed below.
394 *
395 * Function arguments are passed in r0-r5. After the parameters from
396 * `exec` have been read, r0 is reused to branch to the continuation
397 * functions. After the original parameters from `impl` have been
398 * computed, r1 is reused as the `impl` pointer for each operation.
399 *
400 * Loop iterators are r6 for `bx` and r3 for `y`, reused from
401 * `y_start`, which doesn't need to be preserved.
402 *
403 * The intra-procedure-call temporary registers (r16 and r17) are used
404 * as scratch registers. They may be used by call veneers and PLT code
405 * inserted by the linker, so we cannot expect them to persist across
406 * branches between functions.
407 *
408 * The Platform Register (r18) is not used.
409 *
410 * The read/write data pointers and padding values first use up the
411 * remaining free caller-saved registers, and only then are the
412 * callee-saved registers (r19-r29) used.
413 *
414 * The Link Register (r30) is used when calling the first kernel, so it
415 * must be saved.
416 */
417
418static const int rw_gprs[] = {
419 9, 10, 11, 12,
420 13, 14, 15, 19,
421 20, 21, 22, 23,
422 24, 25, 26, 27,
423};
424
426{
427 /* Loop iterator variables. */
428 s->bx = a64op_gpw(6);
429 s->y = a64op_gpw(3); /* Reused from SwsOpFunc.y_start argument. */
430
431 /* Scratch registers. */
432 s->tmp0 = a64op_gpx(16); /* IP0 */
433 s->tmp1 = a64op_gpx(17); /* IP1 */
434
435 /* Read/Write data pointers. */
436 LOOP(imask, i) { s->in [i] = a64op_gpx(rw_gprs[(i * 4) + 0]); }
437 LOOP(omask, i) { s->out[i] = a64op_gpx(rw_gprs[(i * 4) + 1]); }
438}
439
441{
442 asmgen_common_frame(s, imask, omask);
443
444 /* SwsOpFunc arguments. */
445 s->exec = a64op_gpx(0); // const SwsOpExec *exec
446 s->impl = a64op_gpx(1); // const void *priv
447 s->bx_start = a64op_gpw(2); // int bx_start
448 s->y_start = a64op_gpw(3); // int y_start
449 s->bx_end = a64op_gpw(4); // int bx_end
450 s->y_end = a64op_gpw(5); // int y_end
451
452 /* CPS-related variables. */
453 s->op0_func = a64op_gpx(7);
454 s->op1_impl = a64op_gpx(8);
455
456 /* Read/Write data pointer padding. */
457 LOOP(imask, i) { s->in_bump [i] = a64op_gpx(rw_gprs[(i * 4) + 2]); }
458 LOOP(omask, i) { s->out_bump[i] = a64op_gpx(rw_gprs[(i * 4) + 3]); }
459}
460
462{
463 asmgen_common_frame(s, imask, omask);
464
465 /* CPS-related variables. */
466 s->cont = a64op_gpx(0); /* Reused from SwsOpFunc.exec argument. */
467 s->impl = a64op_gpx(1); /* Same as SwsOpFunc.impl argument. */
468}
469
470/*********************************************************************/
471/* Vector register assignment. */
473{
474 regs->sl[ 0] = a64op_vec( 0);
475 regs->sl[ 1] = a64op_vec( 1);
476 regs->sl[ 2] = a64op_vec( 2);
477 regs->sl[ 3] = a64op_vec( 3);
478 regs->sh[ 0] = a64op_vec( 4);
479 regs->sh[ 1] = a64op_vec( 5);
480 regs->sh[ 2] = a64op_vec( 6);
481 regs->sh[ 3] = a64op_vec( 7);
482 regs->dl[ 0] = a64op_vec( 0);
483 regs->dl[ 1] = a64op_vec( 1);
484 regs->dl[ 2] = a64op_vec( 2);
485 regs->dl[ 3] = a64op_vec( 3);
486 regs->dh[ 0] = a64op_vec( 4);
487 regs->dh[ 1] = a64op_vec( 5);
488 regs->dh[ 2] = a64op_vec( 6);
489 regs->dh[ 3] = a64op_vec( 7);
490 regs->vt[ 0] = a64op_vec(16);
491 regs->vt[ 1] = a64op_vec(17);
492 regs->vt[ 2] = a64op_vec(18);
493 regs->vt[ 3] = a64op_vec(19);
494 regs->vt[ 4] = a64op_vec(20);
495 regs->vt[ 5] = a64op_vec(21);
496 regs->vt[ 6] = a64op_vec(22);
497 regs->vt[ 7] = a64op_vec(23);
498 regs->vt[ 8] = a64op_vec(24);
499 regs->vt[ 9] = a64op_vec(25);
500 regs->vt[10] = a64op_vec(26);
501 regs->vt[11] = a64op_vec(27);
502 regs->vk[ 0] = a64op_vec(28);
503 regs->vk[ 1] = a64op_vec(29);
504 regs->vk[ 2] = a64op_vec(30);
505 regs->vk[ 3] = a64op_vec(31);
506}
507
508/*********************************************************************/
510{
511 RasmContext *r = s->rctx;
512 char func_name[128];
513
514 snprintf(func_name, sizeof(func_name), "ff_sws_process_%04x_neon", nibble_mask(mask));
515 rasm_func_begin(r, func_name, true, false);
517
519
520 /* Load values from impl. */
521 rasm_set_current_node(r, s->setup);
522 RasmOp impl_cont = a64op_off(s->impl, offsetof_impl_cont);
523 i_ldr(r, s->op0_func, impl_cont); CMT("SwsFuncPtr op0_func = impl->cont;");
524 i_add(r, s->op1_impl, s->impl, IMM(sizeof_impl)); CMT("SwsOpImpl *op1_impl = impl + 1;");
525
526 /* Reset impl and call first kernel. */
527 rasm_set_current_node(r, s->loop);
528 i_mov(r, s->impl, s->op1_impl); CMT("impl = op1_impl;");
529 i_blr(r, s->op0_func); CMT("op0_func();");
530}
531
532/*********************************************************************/
534{
535 const SwsAArch64OpImplParams *p = &entry->params;
536 RasmContext *r = s->rctx;
537
538 bool is_read = false;
539 bool is_write = false;
540 switch (p->uop) {
541 case SWS_UOP_READ_BIT:
545 is_read = true;
546 break;
551 is_write = true;
552 break;
553 default:
554 break;
555 }
556
557 rasm_func_begin(r, entry->name, true, !is_read);
558 asmgen_op_frame(s, is_read ? p->mask : 0, is_write ? p->mask : 0);
559
560 /**
561 * Set up vector register dimensions and reshape all vectors
562 * accordingly.
563 */
564 size_t el_size = ff_sws_pixel_type_size(p->type);
565 size_t total_size = p->block_size * el_size;
566
567 s->vec_size = FFMIN(total_size, 16);
568 s->use_vh = (s->vec_size != total_size);
569
570 s->el_size = el_size;
571 s->el_count = s->vec_size / el_size;
572 init_vectors_cps(s, &s->regs);
573 reshape_io_vectors(&s->regs, s->el_count, el_size);
574 reshape_temp_vectors(&s->regs, s->el_count, el_size);
575 reshape_const_vectors(&s->regs, s->el_count, el_size);
576
577 /* Common start for continuation-passing style (CPS) functions. */
579
580 /* Set up constants. */
581 switch (p->uop) {
582 case SWS_UOP_READ_BIT: asmgen_setup_read_bit(s, p, &s->regs); break;
583 case SWS_UOP_READ_NIBBLE: asmgen_setup_read_nibble(s, p, &s->regs); break;
584 case SWS_UOP_WRITE_BIT: asmgen_setup_write_bit(s, p, &s->regs); break;
585 case SWS_UOP_UNPACK: asmgen_setup_unpack(s, p, &s->regs); break;
586 case SWS_UOP_CLEAR: asmgen_setup_clear(s, p, &s->regs); break;
587 case SWS_UOP_MIN: asmgen_setup_min(s, p, &s->regs); break;
588 case SWS_UOP_MAX: asmgen_setup_max(s, p, &s->regs); break;
589 case SWS_UOP_SCALE: asmgen_setup_scale(s, p, &s->regs); break;
590 case SWS_UOP_LINEAR: asmgen_setup_linear(s, p, &s->regs); break;
591 case SWS_UOP_LINEAR_FMA: asmgen_setup_linear(s, p, &s->regs); break;
592 case SWS_UOP_DITHER: asmgen_setup_dither(s, p, &s->regs); break;
593 default:
594 break;
595 }
596
597 /* Emit uop kernel. */
598 switch (p->uop) {
599 case SWS_UOP_READ_BIT: asmgen_op_read_bit(s, p, &s->regs); break;
600 case SWS_UOP_READ_NIBBLE: asmgen_op_read_nibble(s, p, &s->regs); break;
601 case SWS_UOP_READ_PACKED: asmgen_op_read_packed(s, p, &s->regs); break;
602 case SWS_UOP_READ_PLANAR: asmgen_op_read_planar(s, p, &s->regs); break;
603 case SWS_UOP_WRITE_BIT: asmgen_op_write_bit(s, p, &s->regs); break;
604 case SWS_UOP_WRITE_NIBBLE: asmgen_op_write_nibble(s, p, &s->regs); break;
605 case SWS_UOP_WRITE_PACKED: asmgen_op_write_packed(s, p, &s->regs); break;
606 case SWS_UOP_WRITE_PLANAR: asmgen_op_write_planar(s, p, &s->regs); break;
607 case SWS_UOP_SWAP_BYTES: asmgen_op_swap_bytes(s, p, &s->regs); break;
608 case SWS_UOP_PERMUTE: asmgen_op_move(s, p, &s->regs); break;
609 case SWS_UOP_COPY: asmgen_op_move(s, p, &s->regs); break;
610 case SWS_UOP_UNPACK: asmgen_op_unpack(s, p, &s->regs); break;
611 case SWS_UOP_PACK: asmgen_op_pack(s, p, &s->regs); break;
612 case SWS_UOP_LSHIFT: asmgen_op_lshift(s, p, &s->regs); break;
613 case SWS_UOP_RSHIFT: asmgen_op_rshift(s, p, &s->regs); break;
614 case SWS_UOP_CLEAR: asmgen_op_clear(s, p, &s->regs); break;
615 case SWS_UOP_TO_U8: asmgen_op_convert(s, p, &s->regs); break;
616 case SWS_UOP_TO_U16: asmgen_op_convert(s, p, &s->regs); break;
617 case SWS_UOP_TO_U32: asmgen_op_convert(s, p, &s->regs); break;
618 case SWS_UOP_TO_F32: asmgen_op_convert(s, p, &s->regs); break;
619 case SWS_UOP_EXPAND_PAIR: asmgen_op_expand(s, p, &s->regs); break;
620 case SWS_UOP_EXPAND_QUAD: asmgen_op_expand(s, p, &s->regs); break;
621 case SWS_UOP_MIN: asmgen_op_min(s, p, &s->regs); break;
622 case SWS_UOP_MAX: asmgen_op_max(s, p, &s->regs); break;
623 case SWS_UOP_SCALE: asmgen_op_scale(s, p, &s->regs); break;
624 case SWS_UOP_LINEAR: asmgen_op_linear(s, p, &s->regs); break;
625 case SWS_UOP_LINEAR_FMA: asmgen_op_linear(s, p, &s->regs); break;
626 case SWS_UOP_DITHER: asmgen_op_dither(s, p, &s->regs); break;
627 /* TODO implement SWS_UOP_SHUFFLE */
628 default:
629 break;
630 }
631
632 if (is_write) {
633 /* Write functions return directly. */
634 i_ret(r);
635 } else {
636 /* Load continuation address and increment impl pointer. */
637 RasmNode *node = rasm_set_current_node(r, s->load_cont_node);
638 RasmOp impl_post = a64op_post(s->impl, sizeof_impl);
639 i_ldr(r, s->cont, impl_post); CMT("SwsFuncPtr cont = (impl++)->cont;");
641 /* Common end for remaining CPS functions. */
642 i_br (r, s->cont); CMT("jump to cont");
643 }
644}
645
646/*********************************************************************/
647
648/* Generate all functions described by ops_entries.c */
649static int asmgen(void)
650{
651 RasmContext *rctx = rasm_alloc();
652 if (!rctx)
653 return AVERROR(ENOMEM);
654
655 SwsAArch64Context s = { .rctx = rctx };
656 AVBPrint bp;
657 int ret;
658
660
661 /* Generate all process functions using rasm. */
666
667 /* Generate all functions from ops_entries.c using rasm. */
668 const SwsAArch64OpEntry *entries = ops_entries;
669 while (entries->name) {
670 asmgen_op_cps(&s, entries++);
671 if (rctx->error) {
672 ret = rctx->error;
673 goto error;
674 }
675 }
676
677 /* Print all rasm functions to stdout. */
678 printf("#include \"libavutil/aarch64/asm.S\"\n");
679 printf("\n");
680 ret = rasm_print(s.rctx, &bp);
681 if (ret < 0)
682 goto error;
683 fputs(bp.str, stdout);
684
685error:
687 rasm_free(&s.rctx);
688 return ret;
689}
690
691/*********************************************************************/
692int main(int argc, char *argv[])
693{
694#ifdef _WIN32
695 _setmode(_fileno(stdout), _O_BINARY);
696#endif
697
698 return asmgen();
699}
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:68
#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 ret
Definition ffplay.c:391
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:234
#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:927
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:915
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_vreg_nelems(SwsPixelType type)
Definition ops_impl.h:67
static int linear_num_vregs(const SwsAArch64OpImplParams *params)
Definition ops_impl.h:73
#define sizeof_impl
Definition ops_impl.h:94
#define LOOP_MASK(p, idx)
Definition ops_impl.h:63
#define offsetof_impl_priv
Definition ops_impl.h:93
#define offsetof_impl_cont
Definition ops_impl.h:92
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:425
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:461
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:440
static void init_vectors_cps(SwsAArch64Context *s, SwsAArch64OpRegs *regs)
Definition ops_static.c:472
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:509
static void asmgen_setup_dither(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition ops_static.c:371
#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:649
static void asmgen_op_cps(SwsAArch64Context *s, const SwsAArch64OpEntry *entry)
Definition ops_static.c:533
static const int rw_gprs[]
Register assignment for CPS functions.
Definition ops_static.c:418
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:629
#define i_br(rctx, op0)
Definition rasm.h:555
#define i_dup(rctx, op0, op1)
Definition rasm.h:558
static RasmOp a64op_base(RasmOp op)
Definition rasm.h:507
static RasmOp vv_4(RasmOp op0, RasmOp op1, RasmOp op2, RasmOp op3)
Definition rasm.h:450
static RasmOp a64op_vec(uint8_t n)
Definition rasm.h:384
#define i_movi(rctx, op0, op1)
Definition rasm.h:578
static RasmOp a64op_elem(RasmOp op, uint8_t idx)
Definition rasm.h:423
static RasmOp a64op_gpx(uint8_t n)
Definition rasm.h:356
#define i_ld1(rctx, op0, op1)
Definition rasm.h:566
static RasmOp v_q(RasmOp op)
Definition rasm.h:435
static RasmOp a64op_off(RasmOp op, int16_t imm)
Definition rasm.h:508
#define i_ldr(rctx, op0, op1)
Definition rasm.h:572
static RasmOp vv_2(RasmOp op0, RasmOp op1)
Definition rasm.h:448
static RasmOp v_16b(RasmOp op)
Definition rasm.h:439
static RasmOp a64op_post(RasmOp op, int16_t imm)
Definition rasm.h:510
#define i_add(rctx, op0, op1, op2)
Definition rasm.h:548
#define i_ld1r(rctx, op0, op1)
Definition rasm.h:567
void int rasm_print(RasmContext *rctx, AVBPrint *bp)
Definition rasm_print.c:423
#define i_blr(rctx, op0)
Definition rasm.h:554
static RasmOp vv_1(RasmOp op0)
Definition rasm.h:447
#define i_ret(rctx)
Definition rasm.h:581
static RasmOp vv_3(RasmOp op0, RasmOp op1, RasmOp op2)
Definition rasm.h:449
static RasmOp a64op_w(RasmOp op)
Definition rasm.h:361
#define i_mov(rctx, op0, op1)
Definition rasm.h:577
static RasmOp a64op_gpw(uint8_t n)
Definition rasm.h:355
#define IMM(val)
Definition rasm.h:92
This helper structure is used to mimic the assembler syntax for vector register modifiers.
Definition rasm.h:457
RasmOp b16
Definition rasm.h:466
RasmOp b8
Definition rasm.h:465
RasmOp q
Definition rasm.h:463
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
@ SWS_PIXEL_U16
Definition uops.h:43
@ SWS_PIXEL_U8
Definition uops.h:42
#define SWS_COMP(X)
Definition uops.h:122
#define SWS_COMP_ELEMS(N)
Definition uops.h:125
#define SWS_MASK(I, J)
Definition uops.h:259
@ SWS_UOP_TO_U8
Definition uops.h:187
@ SWS_UOP_PACK
Definition uops.h:200
@ SWS_UOP_PERMUTE
Definition uops.h:179
@ SWS_UOP_EXPAND_QUAD
Definition uops.h:186
@ SWS_UOP_READ_PLANAR
Definition uops.h:161
@ SWS_UOP_WRITE_PLANAR
Definition uops.h:170
@ SWS_UOP_READ_NIBBLE
Definition uops.h:166
@ SWS_UOP_MAX
Definition uops.h:196
@ SWS_UOP_READ_BIT
Definition uops.h:167
@ SWS_UOP_SWAP_BYTES
Definition uops.h:183
@ SWS_UOP_MIN
Definition uops.h:195
@ SWS_UOP_LINEAR
Definition uops.h:204
@ SWS_UOP_RSHIFT
Definition uops.h:202
@ SWS_UOP_COPY
Definition uops.h:180
@ SWS_UOP_WRITE_NIBBLE
Definition uops.h:172
@ SWS_UOP_LINEAR_FMA
Definition uops.h:205
@ SWS_UOP_SCALE
Definition uops.h:193
@ SWS_UOP_WRITE_PACKED
Definition uops.h:171
@ SWS_UOP_WRITE_BIT
Definition uops.h:173
@ SWS_UOP_READ_PACKED
Definition uops.h:165
@ SWS_UOP_EXPAND_PAIR
Definition uops.h:185
@ SWS_UOP_TO_U16
Definition uops.h:188
@ SWS_UOP_DITHER
Definition uops.h:206
@ SWS_UOP_CLEAR
Definition uops.h:203
@ SWS_UOP_TO_U32
Definition uops.h:189
@ SWS_UOP_UNPACK
Definition uops.h:199
@ SWS_UOP_TO_F32
Definition uops.h:190
@ SWS_UOP_LSHIFT
Definition uops.h:201
uint8_t SwsCompMask
Bit-mask of components.
Definition uops.h:118
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition uops.h:51