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