FFmpeg
rasm.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 "rasm.h"
22 
23 #include <stdarg.h>
24 
25 #include "libavutil/error.h"
26 #include "libavutil/macros.h"
27 #include "libavutil/mem.h"
28 
29 /*********************************************************************/
30 /* Main runtime assembler context */
31 
33 {
34  return av_mallocz(sizeof(RasmContext));
35 }
36 
37 void rasm_free(RasmContext **prctx)
38 {
39  if (!prctx || !*prctx)
40  return;
41 
42  RasmContext *rctx = *prctx;
43  for (int i = 0; i < rctx->num_entries; i++) {
44  RasmEntry *entry = &rctx->entries[i];
45  RasmNode *node = entry->start;
46  while (node != NULL) {
47  switch (node->type) {
48  case RASM_NODE_COMMENT:
49  av_freep(&node->comment.text);
50  break;
52  av_freep(&node->directive.text);
53  break;
54  default:
55  break;
56  }
57  av_freep(&node->inline_comment);
58  RasmNode *current_node = node;
59  node = node->next;
60  av_free(current_node);
61  }
62  }
63  av_freep(&rctx->entries);
64  for (int i = 0; i < rctx->num_labels; i++)
65  av_freep(&rctx->labels[i]);
66  av_freep(&rctx->labels);
67  av_freep(&rctx->comment_next);
68  av_freep(prctx);
69 }
70 
71 /*********************************************************************/
72 /* IR Nodes */
73 
75 {
76  if (rctx->error)
77  return NULL;
78 
79  RasmNode *node = av_mallocz(sizeof(RasmNode));
80  if (!node) {
81  rctx->error = AVERROR(ENOMEM);
82  return NULL;
83  }
84 
85  node->type = type;
86 
87  if (rctx->current_node) {
88  RasmNode *next = rctx->current_node->next;
89  node->prev = rctx->current_node;
90  node->next = next;
91  rctx->current_node->next = node;
92  if (next)
93  next->prev = node;
94  }
95 
96  rctx->current_node = node;
97 
98  return node;
99 }
100 
102  RasmOp op0, RasmOp op1, RasmOp op2, RasmOp op3)
103 {
104  RasmNode *node = add_node(rctx, RASM_NODE_INSN);
105  if (node) {
106  node->insn.id = id;
107  node->insn.op[0] = op0;
108  node->insn.op[1] = op1;
109  node->insn.op[2] = op2;
110  node->insn.op[3] = op3;
111  node->inline_comment = rctx->comment_next;
112  rctx->comment_next = NULL;
113  }
114  return node;
115 }
116 
118 {
119  if (rctx->error)
120  return NULL;
121 
122  char *dup = av_strdup(comment);
123  if (!dup) {
124  rctx->error = AVERROR(ENOMEM);
125  return NULL;
126  }
127 
128  RasmNode *node = add_node(rctx, RASM_NODE_COMMENT);
129  if (node) {
130  node->comment.text = dup;
131  } else {
132  av_freep(&dup);
133  }
134  return node;
135 }
136 
137 RasmNode *rasm_add_commentf(RasmContext *rctx, char *s, size_t n, const char *fmt, ...)
138 {
139  va_list args;
140  va_start(args, fmt);
141  vsnprintf(s, n, fmt, args);
142  va_end(args);
143  return rasm_add_comment(rctx, s);
144 }
145 
147 {
148  RasmNode *node = add_node(rctx, RASM_NODE_LABEL);
149  if (node) {
150  node->label.id = id;
151  }
152  return node;
153 }
154 
156  bool jumpable)
157 {
158  RasmNode *node = add_node(rctx, RASM_NODE_FUNCTION);
159  if (node) {
160  av_assert0(id >= 0 && id < rctx->num_labels);
161  node->func.name = rctx->labels[id];
162  node->func.export = export;
163  node->func.jumpable = jumpable;
164  }
165  return node;
166 }
167 
169 {
170  RasmNode *node = add_node(rctx, RASM_NODE_ENDFUNC);
171  return node;
172 }
173 
174 RasmNode *rasm_add_directive(RasmContext *rctx, const char *text)
175 {
176  if (rctx->error)
177  return NULL;
178 
179  char *dup = av_strdup(text);
180  if (!dup) {
181  rctx->error = AVERROR(ENOMEM);
182  return NULL;
183  }
184 
185  RasmNode *node = add_node(rctx, RASM_NODE_DIRECTIVE);
186  if (node) {
187  node->directive.text = dup;
188  } else {
189  av_freep(&dup);
190  }
191  return node;
192 }
193 
195 {
196  return rctx->current_node;
197 }
198 
200 {
201  RasmNode *current_node = rctx->current_node;
202  rctx->current_node = node;
203  return current_node;
204 }
205 
206 /*********************************************************************/
207 /* Top-level IR entries */
208 
209 int rasm_func_begin(RasmContext *rctx, const char *name, bool export,
210  bool jumpable)
211 {
212  if (rctx->error)
213  return rctx->error;
214 
215  /* Grow entries array. */
216  RasmEntry *entry = av_dynarray2_add((void **) &rctx->entries,
217  &rctx->num_entries,
218  sizeof(*rctx->entries), NULL);
219  if (!entry) {
220  rctx->error = AVERROR(ENOMEM);
221  return rctx->error;
222  }
223 
224  entry->type = RASM_ENTRY_FUNC;
225 
226  int id = rasm_new_label(rctx, name);
227 
229  entry->start = rasm_add_func(rctx, id, export, jumpable);
230  entry->end = rasm_add_endfunc(rctx);
231  rasm_set_current_node(rctx, entry->start);
232 
233  entry->func.export = export;
234  entry->func.label_id = id;
235 
236  if (rctx->error)
237  return rctx->error;
238 
239  return id;
240 }
241 
242 /*********************************************************************/
243 void rasm_annotate(RasmContext *rctx, const char *comment)
244 {
245  if (rctx->error || !rctx->current_node)
246  return;
247  RasmNode *current_node = rctx->current_node;
248  av_freep(&current_node->inline_comment);
249  current_node->inline_comment = av_strdup(comment);
250  if (!current_node->inline_comment)
251  rctx->error = AVERROR(ENOMEM);
252 }
253 
254 void rasm_annotatef(RasmContext *rctx, char *s, size_t n, const char *fmt, ...)
255 {
256  va_list args;
257  va_start(args, fmt);
258  vsnprintf(s, n, fmt, args);
259  va_end(args);
260  rasm_annotate(rctx, s);
261 }
262 
263 void rasm_annotate_next(RasmContext *rctx, const char *comment)
264 {
265  if (rctx->error)
266  return;
267  av_freep(&rctx->comment_next);
268  rctx->comment_next = av_strdup(comment);
269  if (!rctx->comment_next)
270  rctx->error = AVERROR(ENOMEM);
271 }
272 
273 void rasm_annotate_nextf(RasmContext *rctx, char *s, size_t n, const char *fmt, ...)
274 {
275  va_list args;
276  va_start(args, fmt);
277  vsnprintf(s, n, fmt, args);
278  va_end(args);
279  rasm_annotate_next(rctx, s);
280 }
281 
282 int rasm_new_label(RasmContext *rctx, const char *name)
283 {
284  if (rctx->error)
285  return rctx->error;
286 
287  char *dup = NULL;
288  int ret;
289 
290  if (name) {
291  dup = av_strdup(name);
292  if (!dup) {
293  ret = AVERROR(ENOMEM);
294  goto error;
295  }
296  }
297 
298  /* Get current label number. */
299  ret = rctx->num_labels;
300 
301  /* Grow labels array. */
302  char **p = av_dynarray2_add((void **) &rctx->labels, &rctx->num_labels,
303  sizeof(*rctx->labels), NULL);
304  if (!p) {
305  ret = AVERROR(ENOMEM);
306  goto error;
307  }
308  *p = dup;
309 
310 error:
311  if (ret < 0) {
312  av_free(dup);
313  rctx->error = ret;
314  }
315  return ret;
316 }
317 
318 int rasm_new_labelf(RasmContext *rctx, char *s, size_t n, const char *fmt, ...)
319 {
320  va_list args;
321  va_start(args, fmt);
322  vsnprintf(s, n, fmt, args);
323  va_end(args);
324  return rasm_new_label(rctx, s);
325 }
326 
327 /*********************************************************************/
328 /* AArch64-specific */
329 
331 {
332  uint8_t n = a64op_vec_n(op);
333  out->b = a64op_vecb (n);
334  out->h = a64op_vech (n);
335  out->s = a64op_vecs (n);
336  out->d = a64op_vecd (n);
337  out->q = a64op_vecq (n);
338  out->b8 = a64op_vec8b (n);
339  out->b16 = a64op_vec16b(n);
340  out->h4 = a64op_vec4h (n);
341  out->h8 = a64op_vec8h (n);
342  out->s2 = a64op_vec2s (n);
343  out->s4 = a64op_vec4s (n);
344  out->d2 = a64op_vec2d (n);
345  for (int i = 0; i < 2; i++)
346  out->be[i] = a64op_elem(out->b, i);
347  for (int i = 0; i < 2; i++)
348  out->de[i] = a64op_elem(out->d, i);
349 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
rasm_alloc
RasmContext * rasm_alloc(void)
Definition: rasm.c:32
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
RasmNode::label
RasmNodeLabel label
Definition: rasm.h:149
entry
#define entry
Definition: aom_film_grain_template.c:66
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
rasm_new_labelf
int rasm_new_labelf(RasmContext *rctx, char *s, size_t n, const char *fmt,...)
Definition: rasm.c:318
out
static FILE * out
Definition: movenc.c:55
a64op_vecd
static RasmOp a64op_vecd(uint8_t n)
Definition: rasm.h:383
a64op_vecq
static RasmOp a64op_vecq(uint8_t n)
Definition: rasm.h:384
RASM_NODE_DIRECTIVE
@ RASM_NODE_DIRECTIVE
Definition: rasm.h:116
RasmContext::entries
RasmEntry * entries
Definition: rasm.h:185
RASM_NODE_LABEL
@ RASM_NODE_LABEL
Definition: rasm.h:113
RasmContext::error
int error
Definition: rasm.h:191
rasm_free
void rasm_free(RasmContext **prctx)
Definition: rasm.c:37
rasm_set_current_node
RasmNode * rasm_set_current_node(RasmContext *rctx, RasmNode *node)
Definition: rasm.c:199
AArch64VecViews
This helper structure is used to mimic the assembler syntax for vector register modifiers.
Definition: rasm.h:452
rasm_get_current_node
RasmNode * rasm_get_current_node(RasmContext *rctx)
Definition: rasm.c:194
av_dynarray2_add
void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Add an element of size elem_size to a dynamic array.
Definition: mem.c:343
rasm_annotate
void rasm_annotate(RasmContext *rctx, const char *comment)
Definition: rasm.c:243
RASM_NODE_INSN
@ RASM_NODE_INSN
Definition: rasm.h:111
RasmNode::prev
struct RasmNode * prev
Definition: rasm.h:154
RasmNode
Definition: rasm.h:144
rasm_add_commentf
RasmNode * rasm_add_commentf(RasmContext *rctx, char *s, size_t n, const char *fmt,...)
Definition: rasm.c:137
a64op_vec_n
static uint8_t a64op_vec_n(RasmOp op)
Definition: rasm.h:373
a64op_vec_views
void a64op_vec_views(RasmOp op, AArch64VecViews *out)
Definition: rasm.c:330
RasmOp
Runtime assembler for AArch64.
Definition: rasm.h:43
macros.h
RasmContext::labels
char ** labels
Definition: rasm.h:187
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
rasm_add_label
RasmNode * rasm_add_label(RasmContext *rctx, int id)
Definition: rasm.c:146
rasm_add_func
RasmNode * rasm_add_func(RasmContext *rctx, int id, bool export, bool jumpable)
Definition: rasm.c:155
RasmContext::num_labels
int num_labels
Definition: rasm.h:188
RasmNode::insn
RasmNodeInsn insn
Definition: rasm.h:147
a64op_elem
static RasmOp a64op_elem(RasmOp op, uint8_t idx)
Definition: rasm.h:418
a64op_vec8b
static RasmOp a64op_vec8b(uint8_t n)
Definition: rasm.h:385
s
#define s(width, name)
Definition: cbs_vp9.c:198
a64op_vec4h
static RasmOp a64op_vec4h(uint8_t n)
Definition: rasm.h:387
RasmNode::next
struct RasmNode * next
Definition: rasm.h:155
op
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
Definition: anm.c:76
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
RasmNode::inline_comment
char * inline_comment
Definition: rasm.h:153
export
static int export(AVFilterContext *ctx, StreamContext *sc, int input)
Definition: vf_signature.c:558
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
RasmNodeDirective::text
char * text
Definition: rasm.h:140
RasmNodeInsn::op
RasmOp op[4]
Definition: rasm.h:122
RASM_NODE_ENDFUNC
@ RASM_NODE_ENDFUNC
Definition: rasm.h:115
RasmNode::func
RasmNodeFunc func
Definition: rasm.h:150
rasm.h
NULL
#define NULL
Definition: coverity.c:32
a64op_vec2d
static RasmOp a64op_vec2d(uint8_t n)
Definition: rasm.h:391
RasmNodeFunc::jumpable
bool jumpable
Definition: rasm.h:136
RasmNode::comment
RasmNodeComment comment
Definition: rasm.h:148
a64op_vecs
static RasmOp a64op_vecs(uint8_t n)
Definition: rasm.h:382
RASM_NODE_FUNCTION
@ RASM_NODE_FUNCTION
Definition: rasm.h:114
a64op_vecb
static RasmOp a64op_vecb(uint8_t n)
Definition: rasm.h:380
rasm_add_insn
RasmNode * rasm_add_insn(RasmContext *rctx, int id, RasmOp op0, RasmOp op1, RasmOp op2, RasmOp op3)
Definition: rasm.c:101
a64op_vech
static RasmOp a64op_vech(uint8_t n)
Definition: rasm.h:381
a64op_vec4s
static RasmOp a64op_vec4s(uint8_t n)
Definition: rasm.h:390
RasmEntry
Definition: rasm.h:172
error.h
rasm_new_label
int rasm_new_label(RasmContext *rctx, const char *name)
Allocate a new label ID with the given name.
Definition: rasm.c:282
rasm_annotatef
void rasm_annotatef(RasmContext *rctx, char *s, size_t n, const char *fmt,...)
Definition: rasm.c:254
RasmContext::comment_next
char * comment_next
Definition: rasm.h:190
RasmNode::type
RasmNodeType type
Definition: rasm.h:145
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
RASM_NODE_COMMENT
@ RASM_NODE_COMMENT
Definition: rasm.h:112
RasmNodeFunc::name
char * name
Definition: rasm.h:134
RasmNodeLabel::id
int id
Definition: rasm.h:130
a64op_vec2s
static RasmOp a64op_vec2s(uint8_t n)
Definition: rasm.h:389
rasm_annotate_next
void rasm_annotate_next(RasmContext *rctx, const char *comment)
Definition: rasm.c:263
RasmNodeType
RasmNodeType
Definition: rasm.h:110
RasmContext
Definition: rasm.h:184
a64op_vec16b
static RasmOp a64op_vec16b(uint8_t n)
Definition: rasm.h:386
vsnprintf
#define vsnprintf
Definition: snprintf.h:36
RasmContext::num_entries
int num_entries
Definition: rasm.h:186
RasmNodeInsn::id
int id
Definition: rasm.h:121
rasm_add_directive
RasmNode * rasm_add_directive(RasmContext *rctx, const char *text)
Definition: rasm.c:174
rasm_annotate_nextf
void rasm_annotate_nextf(RasmContext *rctx, char *s, size_t n, const char *fmt,...)
Definition: rasm.c:273
RasmNodeComment::text
char * text
Definition: rasm.h:126
ret
ret
Definition: filter_design.txt:187
comment
static int FUNC() comment(CodedBitstreamContext *ctx, RWContext *rw, JPEGRawComment *current)
Definition: cbs_jpeg_syntax_template.c:174
rasm_func_begin
int rasm_func_begin(RasmContext *rctx, const char *name, bool export, bool jumpable)
Definition: rasm.c:209
id
enum AVCodecID id
Definition: dts2pts.c:549
RASM_ENTRY_FUNC
@ RASM_ENTRY_FUNC
Definition: rasm.h:162
RasmNode::directive
RasmNodeDirective directive
Definition: rasm.h:151
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
add_node
static RasmNode * add_node(RasmContext *rctx, RasmNodeType type)
Definition: rasm.c:74
RasmNodeFunc::export
bool export
Definition: rasm.h:135
mem.h
av_strdup
#define av_strdup(s)
Definition: ops_asmgen.c:47
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
RasmContext::current_node
RasmNode * current_node
Definition: rasm.h:189
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
rasm_add_endfunc
RasmNode * rasm_add_endfunc(RasmContext *rctx)
Definition: rasm.c:168
a64op_vec8h
static RasmOp a64op_vec8h(uint8_t n)
Definition: rasm.h:388
rasm_add_comment
RasmNode * rasm_add_comment(RasmContext *rctx, const char *comment)
Definition: rasm.c:117