FFmpeg
Loading...
Searching...
No Matches
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
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) {
49 av_freep(&node->comment.text);
50 break;
52 av_freep(&node->directive.text);
53 break;
54 default:
55 break;
56 }
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
137RasmNode *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
174RasmNode *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
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
209int 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/*********************************************************************/
243void 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
254void 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
263void rasm_annotate_next(RasmContext *rctx, const char *comment)
264{
265 if (rctx->error)
266 return;
267 av_freep(&rctx->comment_next);
269 if (!rctx->comment_next)
270 rctx->error = AVERROR(ENOMEM);
271}
272
273void 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
282int 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
310error:
311 if (ret < 0) {
312 av_free(dup);
313 rctx->error = ret;
314 }
315 return ret;
316}
317
318int 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);
334 .b = a64op_vecb (n),
335 .h = a64op_vech (n),
336 .s = a64op_vecs (n),
337 .d = a64op_vecd (n),
338 .q = a64op_vecq (n),
339 .b8 = a64op_vec8b (n),
340 .b16 = a64op_vec16b(n),
341 .h4 = a64op_vec4h (n),
342 .h8 = a64op_vec8h (n),
343 .s2 = a64op_vec2s (n),
344 .s4 = a64op_vec4s (n),
345 .d2 = a64op_vec2d (n),
346 };
347 for (int i = 0; i < 2; i++)
348 out.be[i] = a64op_elem(out.b, i);
349 for (int i = 0; i < 2; i++)
350 out.de[i] = a64op_elem(out.d, i);
351 return out;
352}
#define entry
static FILE * out
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
static int FUNC comment(CodedBitstreamContext *ctx, RWContext *rw, JPEGRawComment *current)
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
enum AVCodecID id
Definition dts2pts.c:607
error code definitions
#define AVERROR(e)
Definition error.h:45
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:341
cl_device_type type
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
Utility Preprocessor macros.
Memory handling functions.
#define av_strdup(s)
Definition ops_static.c:55
const char * name
Definition qsvenc.c:142
RasmNode * rasm_get_current_node(RasmContext *rctx)
Definition rasm.c:194
RasmNode * rasm_add_func(RasmContext *rctx, int id, bool export, bool jumpable)
Definition rasm.c:155
static RasmNode * add_node(RasmContext *rctx, RasmNodeType type)
Definition rasm.c:74
RasmNode * rasm_add_insn(RasmContext *rctx, int id, RasmOp op0, RasmOp op1, RasmOp op2, RasmOp op3)
Definition rasm.c:101
AArch64VecViews a64op_vec_views(RasmOp op)
Definition rasm.c:330
void rasm_annotatef(RasmContext *rctx, char *s, size_t n, const char *fmt,...)
Definition rasm.c:254
void rasm_free(RasmContext **prctx)
Definition rasm.c:37
RasmNode * rasm_add_commentf(RasmContext *rctx, char *s, size_t n, const char *fmt,...)
Definition rasm.c:137
RasmContext * rasm_alloc(void)
Definition rasm.c:32
void rasm_annotate(RasmContext *rctx, const char *comment)
Definition rasm.c:243
RasmNode * rasm_add_directive(RasmContext *rctx, const char *text)
Definition rasm.c:174
int rasm_func_begin(RasmContext *rctx, const char *name, bool export, bool jumpable)
Definition rasm.c:209
RasmNode * rasm_add_label(RasmContext *rctx, int id)
Definition rasm.c:146
RasmNode * rasm_add_comment(RasmContext *rctx, const char *comment)
Definition rasm.c:117
RasmNode * rasm_add_endfunc(RasmContext *rctx)
Definition rasm.c:168
int rasm_new_label(RasmContext *rctx, const char *name)
Allocate a new label ID with the given name.
Definition rasm.c:282
void rasm_annotate_next(RasmContext *rctx, const char *comment)
Definition rasm.c:263
int rasm_new_labelf(RasmContext *rctx, char *s, size_t n, const char *fmt,...)
Definition rasm.c:318
RasmNode * rasm_set_current_node(RasmContext *rctx, RasmNode *node)
Definition rasm.c:199
void rasm_annotate_nextf(RasmContext *rctx, char *s, size_t n, const char *fmt,...)
Definition rasm.c:273
RasmNodeType
Definition rasm.h:111
@ RASM_NODE_DIRECTIVE
Definition rasm.h:117
@ RASM_NODE_FUNCTION
Definition rasm.h:115
@ RASM_NODE_ENDFUNC
Definition rasm.h:116
@ RASM_NODE_LABEL
Definition rasm.h:114
@ RASM_NODE_INSN
Definition rasm.h:112
@ RASM_NODE_COMMENT
Definition rasm.h:113
static RasmOp a64op_vech(uint8_t n)
Definition rasm.h:385
static RasmOp a64op_vecq(uint8_t n)
Definition rasm.h:388
static RasmOp a64op_vec8h(uint8_t n)
Definition rasm.h:392
static RasmOp a64op_vec2d(uint8_t n)
Definition rasm.h:395
static RasmOp a64op_elem(RasmOp op, uint8_t idx)
Definition rasm.h:422
static RasmOp a64op_vecb(uint8_t n)
Definition rasm.h:384
static RasmOp a64op_vecd(uint8_t n)
Definition rasm.h:387
static RasmOp a64op_vec2s(uint8_t n)
Definition rasm.h:393
static RasmOp a64op_vec8b(uint8_t n)
Definition rasm.h:389
static RasmOp a64op_vec4h(uint8_t n)
Definition rasm.h:391
static uint8_t a64op_vec_n(RasmOp op)
Definition rasm.h:377
static RasmOp a64op_vec4s(uint8_t n)
Definition rasm.h:394
@ RASM_ENTRY_FUNC
Definition rasm.h:163
static RasmOp a64op_vec16b(uint8_t n)
Definition rasm.h:390
static RasmOp a64op_vecs(uint8_t n)
Definition rasm.h:386
#define vsnprintf
Definition snprintf.h:36
This helper structure is used to mimic the assembler syntax for vector register modifiers.
Definition rasm.h:456
RasmNode * current_node
Definition rasm.h:190
int num_labels
Definition rasm.h:189
int error
Definition rasm.h:192
char * comment_next
Definition rasm.h:191
int num_entries
Definition rasm.h:187
RasmEntry * entries
Definition rasm.h:186
char ** labels
Definition rasm.h:188
char * text
Definition rasm.h:127
char * text
Definition rasm.h:141
bool export
Definition rasm.h:136
char * name
Definition rasm.h:135
bool jumpable
Definition rasm.h:137
RasmOp op[4]
Definition rasm.h:123
RasmNodeComment comment
Definition rasm.h:149
RasmNodeLabel label
Definition rasm.h:150
RasmNodeType type
Definition rasm.h:146
RasmNodeInsn insn
Definition rasm.h:148
struct RasmNode * next
Definition rasm.h:156
char * inline_comment
Definition rasm.h:154
struct RasmNode * prev
Definition rasm.h:155
RasmNodeFunc func
Definition rasm.h:151
RasmNodeDirective directive
Definition rasm.h:152
#define av_free(p)
#define av_mallocz(s)
#define av_freep(p)
static void error(const char *err)
Runtime assembler for AArch64.
Definition rasm.h:44
static int export(AVFilterContext *ctx, StreamContext *sc, int input)