FFmpeg
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 
62 static 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 
73 static 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 
86 static 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  */
116 typedef struct SwsAArch64OpEntry {
117  const char *name;
120 
121 static const SwsAArch64OpEntry ops_entries[] = {
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 
392 static 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:
516  case SWS_UOP_READ_NIBBLE:
517  case SWS_UOP_READ_PACKED:
518  case SWS_UOP_READ_PLANAR:
519  is_read = true;
520  break;
521  case SWS_UOP_WRITE_BIT:
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;");
614  rasm_set_current_node(r, node);
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 */
623 static 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 
659 error:
660  av_bprint_finalize(&bp, NULL);
661  rasm_free(&s.rctx);
662  return ret;
663 }
664 
665 /*********************************************************************/
666 int main(int argc, char *argv[])
667 {
668 #ifdef _WIN32
669  _setmode(_fileno(stdout), _O_BINARY);
670 #endif
671 
672  return asmgen();
673 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
rasm_print.c
FF_DYNARRAY_ADD
#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
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
rasm_alloc
RasmContext * rasm_alloc(void)
Definition: rasm.c:32
SWS_UOP_SCALE
@ SWS_UOP_SCALE
Definition: uops.h:165
entry
#define entry
Definition: aom_film_grain_template.c:66
asmgen
static int asmgen(void)
Definition: ops_static.c:623
asmgen_setup_read_nibble
static void asmgen_setup_read_nibble(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:168
r
const char * r
Definition: vf_curves.c:127
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
printf
__device__ int printf(const char *,...)
i_ld1
#define i_ld1(rctx, op0, op1)
Definition: rasm.h:565
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
a64op_base
static RasmOp a64op_base(RasmOp op)
Definition: rasm.h:506
AArch64VecViews::b16
RasmOp b16
Definition: rasm.h:465
init_vectors_cps
static void init_vectors_cps(SwsAArch64Context *s, SwsAArch64OpRegs *regs)
Definition: ops_static.c:446
SWS_UOP_RSHIFT
@ SWS_UOP_RSHIFT
Definition: uops.h:174
a64op_gpx
static RasmOp a64op_gpx(uint8_t n)
Definition: rasm.h:355
a64op_w
static RasmOp a64op_w(RasmOp op)
Definition: rasm.h:360
RasmContext::error
int error
Definition: rasm.h:192
ops_impl.h
mask
int mask
Definition: mediacodecdec_common.c:154
rasm_free
void rasm_free(RasmContext **prctx)
Definition: rasm.c:37
i_blr
#define i_blr(rctx, op0)
Definition: rasm.h:553
rasm_set_current_node
RasmNode * rasm_set_current_node(RasmContext *rctx, RasmNode *node)
Definition: rasm.c:199
u
#define u(width, name, range_min, range_max)
Definition: cbs_apv.c:68
AArch64VecViews
This helper structure is used to mimic the assembler syntax for vector register modifiers.
Definition: rasm.h:456
rasm_get_current_node
RasmNode * rasm_get_current_node(RasmContext *rctx)
Definition: rasm.c:194
a64op_gpw
static RasmOp a64op_gpw(uint8_t n)
Definition: rasm.h:354
SwsAArch64OpRegs::vk
RasmOp vk[4]
Definition: ops_asmgen.h:33
vv_2
static RasmOp vv_2(RasmOp op0, RasmOp op1)
Definition: rasm.h:447
asmgen_op_read_bit
static void asmgen_op_read_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:215
vv_3
static RasmOp vv_3(RasmOp op0, RasmOp op1, RasmOp op2)
Definition: rasm.h:448
asmgen_setup_scale
static void asmgen_setup_scale(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:273
SWS_UOP_LINEAR_FMA
@ SWS_UOP_LINEAR_FMA
Definition: uops.h:177
CMTF
#define CMTF(fmt,...)
Definition: ops_asmgen.c:33
asmgen_setup_write_bit
static void asmgen_setup_write_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:178
reshape_temp_vectors
static void reshape_temp_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
Definition: ops_asmgen.c:47
i_dup
#define i_dup(rctx, op0, op1)
Definition: rasm.h:557
SWS_UOP_MAX
@ SWS_UOP_MAX
Definition: uops.h:168
FFMIN
#define FFMIN(a, b)
Definition: ops_static.c:58
RasmNode
Definition: rasm.h:145
SWS_UOP_LSHIFT
@ SWS_UOP_LSHIFT
Definition: uops.h:173
IMM
#define IMM(val)
Definition: rasm.h:92
asmgen_op_write_nibble
static void asmgen_op_write_nibble(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:334
reshape_const_vectors
static void reshape_const_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
Definition: ops_asmgen.c:54
av_assert0
#define av_assert0(cond)
Definition: ops_static.c:45
SwsAArch64Context
Definition: ops_asmgen.h:43
asmgen_op_write_bit
static void asmgen_op_write_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:310
RasmOp
Runtime assembler for AArch64.
Definition: rasm.h:44
SWS_UOP_TO_U16
@ SWS_UOP_TO_U16
Definition: uops.h:160
SWS_UOP_PACK
@ SWS_UOP_PACK
Definition: uops.h:172
SwsAArch64OpEntry
Implementation parameters for all exported functions.
Definition: ops_static.c:116
IMPL_PRIV
#define IMPL_PRIV(s)
Definition: ops_static.c:131
SWS_UOP_PERMUTE
@ SWS_UOP_PERMUTE
Definition: uops.h:151
SwsAArch64OpRegs::dither_ptr
RasmOp dither_ptr
Definition: ops_asmgen.h:37
asmgen_setup_read_bit
static void asmgen_setup_read_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:151
asmgen_op_convert
static void asmgen_op_convert(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:630
val
static double val(void *priv, double ch)
Definition: aeval.c:77
SwsAArch64OpRegs::vt
RasmOp vt[12]
Definition: ops_asmgen.h:32
SWS_COMP_ELEMS
#define SWS_COMP_ELEMS(N)
Definition: uops.h:100
SWS_UOP_COPY
@ SWS_UOP_COPY
Definition: uops.h:152
i_ld1r
#define i_ld1r(rctx, op0, op1)
Definition: rasm.h:566
av_memdup
static void * av_memdup(const void *p, size_t size)
Definition: ops_static.c:73
vv_1
static RasmOp vv_1(RasmOp op0)
Definition: rasm.h:446
a64op_elem
static RasmOp a64op_elem(RasmOp op, uint8_t idx)
Definition: rasm.h:422
SWS_UOP_WRITE_NIBBLE
@ SWS_UOP_WRITE_NIBBLE
Definition: uops.h:144
av_dynarray2_add
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
asmgen_op_lshift
static void asmgen_op_lshift(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:557
bprint.c
SwsAArch64OpRegs::sl
RasmOp sl[4]
Definition: ops_asmgen.h:28
asmgen_setup_unpack
static void asmgen_setup_unpack(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:189
LOOP
#define LOOP(mask, idx)
Definition: ops_impl.h:56
SWS_UOP_WRITE_PLANAR
@ SWS_UOP_WRITE_PLANAR
Definition: uops.h:142
SwsAArch64OpEntry::name
const char * name
Definition: ops_static.c:117
SWS_UOP_TO_F32
@ SWS_UOP_TO_F32
Definition: uops.h:162
offsetof_impl_cont
#define offsetof_impl_cont
Definition: ops_impl.h:85
CMT
#define CMT(comment)
Definition: ops_asmgen.c:32
SWS_UOP_MIN
@ SWS_UOP_MIN
Definition: uops.h:167
ops_entries.c
asmgen_op_rshift
static void asmgen_op_rshift(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:575
SwsCompMask
uint8_t SwsCompMask
Bit-mask of components.
Definition: uops.h:88
asmgen_op_swap_bytes
static void asmgen_op_swap_bytes(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:398
limits.h
SWS_UOP_READ_PACKED
@ SWS_UOP_READ_PACKED
Definition: uops.h:137
i_ldr
#define i_ldr(rctx, op0, op1)
Definition: rasm.h:571
reshape_io_vectors
static void reshape_io_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
Definition: ops_asmgen.c:36
ff_sws_pixel_type_size
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition: uops.h:50
asmgen_op_write_packed
static void asmgen_op_write_packed(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:368
i_br
#define i_br(rctx, op0)
Definition: rasm.h:554
asmgen_setup_linear
static void asmgen_setup_linear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:285
NULL
#define NULL
Definition: coverity.c:32
SwsAArch64OpEntry::params
SwsAArch64OpImplParams params
Definition: ops_static.c:118
asmgen_process_cps
static void asmgen_process_cps(SwsAArch64Context *s, SwsCompMask mask)
Definition: ops_static.c:483
asmgen_op_read_planar
static void asmgen_op_read_planar(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:286
a64op_post
static RasmOp a64op_post(RasmOp op, int16_t imm)
Definition: rasm.h:509
rasm_print
void int rasm_print(RasmContext *rctx, AVBPrint *bp)
Definition: rasm_print.c:422
SWS_UOP_READ_NIBBLE
@ SWS_UOP_READ_NIBBLE
Definition: uops.h:138
LOOP_VH
#define LOOP_VH(s, mask, idx)
Definition: ops_asmgen.c:27
SwsAArch64OpRegs::dh
RasmOp dh[4]
Definition: ops_asmgen.h:31
sizeof_impl
#define sizeof_impl
Definition: ops_impl.h:87
asmgen_setup_min
static void asmgen_setup_min(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:249
asmgen_op_clear
static void asmgen_op_clear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:612
i_add
#define i_add(rctx, op0, op1, op2)
Definition: rasm.h:547
rasm.c
SWS_UOP_TO_U32
@ SWS_UOP_TO_U32
Definition: uops.h:161
asmgen_op_pack
static void asmgen_op_pack(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:509
asmgen_setup_max
static void asmgen_setup_max(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:261
SWS_UOP_WRITE_BIT
@ SWS_UOP_WRITE_BIT
Definition: uops.h:145
asmgen_setup_clear
static void asmgen_setup_clear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:226
asmgen_op_frame
static void asmgen_op_frame(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
Definition: ops_static.c:435
asmgen_op_min
static void asmgen_op_min(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:771
SwsAArch64OpRegs::sh
RasmOp sh[4]
Definition: ops_asmgen.h:29
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
LOOP_MASK
#define LOOP_MASK(p, idx)
Definition: ops_impl.h:63
asmgen_setup_dither
static void asmgen_setup_dither(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_static.c:345
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
size
int size
Definition: twinvq_data.h:10344
asmgen_set_load_cont_node
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
av_freep
static void av_freep(void *ptr)
Definition: ops_static.c:62
av_malloc
#define av_malloc(s)
Definition: ops_static.c:52
SWS_UOP_UNPACK
@ SWS_UOP_UNPACK
Definition: uops.h:171
SWS_COMP
#define SWS_COMP(X)
Definition: uops.h:97
a64op_off
static RasmOp a64op_off(RasmOp op, int16_t imm)
Definition: rasm.h:507
asmgen_op_dither
static void asmgen_op_dither(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:922
a64op_vec_views
AArch64VecViews a64op_vec_views(RasmOp op)
Definition: rasm.c:330
asmgen_op_move
static void asmgen_op_move(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:456
asmgen_op_max
static void asmgen_op_max(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:794
vv_4
static RasmOp vv_4(RasmOp op0, RasmOp op1, RasmOp op2, RasmOp op3)
Definition: rasm.h:449
rasm_annotate_next
void rasm_annotate_next(RasmContext *rctx, const char *comment)
Definition: rasm.c:263
RasmContext
Definition: rasm.h:185
SWS_UOP_TO_U8
@ SWS_UOP_TO_U8
Definition: uops.h:159
SWS_UOP_READ_PLANAR
@ SWS_UOP_READ_PLANAR
Definition: uops.h:133
rw_gprs
static const int rw_gprs[]
Register assignment for CPS functions.
Definition: ops_static.c:392
s
uint8_t s
Definition: llvidencdsp.c:39
AArch64VecViews::q
RasmOp q
Definition: rasm.h:462
ops_entries
static const SwsAArch64OpEntry ops_entries[]
Definition: ops_static.c:121
offsetof_impl_priv
#define offsetof_impl_priv
Definition: ops_impl.h:86
SWS_UOP_SWAP_BYTES
@ SWS_UOP_SWAP_BYTES
Definition: uops.h:155
SwsAArch64OpRegs::linear_vcoeff
RasmOp linear_vcoeff[4][5]
Definition: ops_asmgen.h:38
ops_asmgen.c
SWS_UOP_LINEAR
@ SWS_UOP_LINEAR
Definition: uops.h:176
asmgen_op_unpack
static void asmgen_op_unpack(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:467
asmgen_op_scale
static void asmgen_op_scale(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:817
a64op_vec
static RasmOp a64op_vec(uint8_t n)
Definition: rasm.h:383
asmgen_op_expand
static void asmgen_op_expand(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:728
asmgen_process_frame
static void asmgen_process_frame(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
Definition: ops_static.c:414
ret
ret
Definition: filter_design.txt:187
asmgen_common_frame
static void asmgen_common_frame(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
Definition: ops_static.c:399
rasm_func_begin
int rasm_func_begin(RasmContext *rctx, const char *name, bool export, bool jumpable)
Definition: rasm.c:209
SwsAArch64OpRegs::dl
RasmOp dl[4]
Definition: ops_asmgen.h:30
asmgen_op_cps
static void asmgen_op_cps(SwsAArch64Context *s, const SwsAArch64OpEntry *entry)
Definition: ops_static.c:507
i_mov16b
#define i_mov16b(rctx, op0, op1)
Definition: rasm.h:627
dynarray.h
asmgen_op_linear
static void asmgen_op_linear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:910
asmgen_process
static void asmgen_process(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
Definition: ops_asmgen.c:139
v_16b
static RasmOp v_16b(RasmOp op)
Definition: rasm.h:438
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
SWS_UOP_DITHER
@ SWS_UOP_DITHER
Definition: uops.h:178
SWS_UOP_WRITE_PACKED
@ SWS_UOP_WRITE_PACKED
Definition: uops.h:143
SwsAArch64OpRegs
Definition: ops_asmgen.h:27
SwsAArch64OpImplParams
SwsAArch64OpImplParams describes the parameters for an SwsUOpType operation.
Definition: ops_impl.h:47
i_movi
#define i_movi(rctx, op0, op1)
Definition: rasm.h:576
main
int main(int argc, char *argv[])
Definition: ops_static.c:666
SWS_UOP_EXPAND_QUAD
@ SWS_UOP_EXPAND_QUAD
Definition: uops.h:158
i_ret
#define i_ret(rctx)
Definition: rasm.h:579
asmgen_op_write_planar
static void asmgen_op_write_planar(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:377
nibble_mask
static uint16_t nibble_mask(SwsCompMask mask)
Definition: ops_impl.h:34
linear_num_vregs
static int linear_num_vregs(const SwsAArch64OpImplParams *params)
Definition: ops_impl.h:67
SWS_UOP_READ_BIT
@ SWS_UOP_READ_BIT
Definition: uops.h:139
SWS_UOP_CLEAR
@ SWS_UOP_CLEAR
Definition: uops.h:175
asmgen_op_read_nibble
static void asmgen_op_read_nibble(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:244
SWS_MASK
#define SWS_MASK(I, J)
Definition: uops.h:231
snprintf
#define snprintf
Definition: snprintf.h:34
rasm_add_comment
RasmNode * rasm_add_comment(RasmContext *rctx, const char *comment)
Definition: rasm.c:117
SWS_UOP_EXPAND_PAIR
@ SWS_UOP_EXPAND_PAIR
Definition: uops.h:157
i_mov
#define i_mov(rctx, op0, op1)
Definition: rasm.h:575
v_q
static RasmOp v_q(RasmOp op)
Definition: rasm.h:434
AArch64VecViews::b8
RasmOp b8
Definition: rasm.h:464
asmgen_op_read_packed
static void asmgen_op_read_packed(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
Definition: ops_asmgen.c:277