FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/uops_macros_gen.c
Date: 2026-10-29 17:07:12
Exec Total Coverage
Lines: 225 252 89.3%
Functions: 17 18 94.4%
Branches: 104 130 80.0%

Line Branch Exec Source
1 /**
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <errno.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #ifdef _WIN32
25 #include <io.h>
26 #include <fcntl.h>
27 #endif
28
29 #include "libavutil/bprint.h"
30 #include "libavutil/error.h"
31 #include "libavutil/macros.h"
32 #include "libavutil/mem.h"
33 #include "libavutil/pixfmt.h"
34 #include "libavutil/thread.h"
35 #include "libavutil/tree.h"
36 #include "ops.h"
37 #include "ops_dispatch.h"
38 #include "op_list_gen_template.c"
39 #include "swscale.h"
40 #include "uops.h"
41 #include "uops_list.h"
42
43 static const struct {
44 char full[32];
45 char abbr[32];
46 } uop_names[SWS_UOP_TYPE_NB] = {
47 #define UOP_NAME(OP, ABBR) [OP] = { #OP, ABBR },
48 UOPS_LIST(UOP_NAME)
49 };
50
51 static const struct {
52 char full[16];
53 char prefix[8];
54 } pixel_types[SWS_PIXEL_TYPE_NB] = {
55 [SWS_PIXEL_NONE] = { "SWS_PIXEL_NONE", "" },
56 [SWS_PIXEL_U8] = { "SWS_PIXEL_U8", "U8_" },
57 [SWS_PIXEL_U16] = { "SWS_PIXEL_U16", "U16_" },
58 [SWS_PIXEL_U32] = { "SWS_PIXEL_U32", "U32_" },
59 [SWS_PIXEL_F32] = { "SWS_PIXEL_F32", "F32_" },
60 };
61
62 /* Print uop params either as C struct designators, or as plain values */
63 2120 static void print_params(AVBPrint *bp, const SwsUOp *uop, bool designated)
64 {
65 #define FMT(FIELD, VALUE, ...) av_bprintf(bp, designated ? ", ." FIELD " = " VALUE : ", " VALUE, __VA_ARGS__)
66 #define FMT_SUB(FIELD, VALUE, ...) av_bprintf(bp, designated ? ", ." FIELD " = {" VALUE "}" : ", " VALUE, __VA_ARGS__)
67
68 2120 const SwsUOpParams *par = &uop->par;
69
10/10
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 105 times.
✓ Branch 3 taken 434 times.
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 165 times.
✓ Branch 6 taken 219 times.
✓ Branch 7 taken 120 times.
✓ Branch 8 taken 20 times.
✓ Branch 9 taken 745 times.
2120 switch (uop->uop) {
70 156 case SWS_UOP_READ_PLANAR_FH:
71 case SWS_UOP_READ_PLANAR_FV:
72 case SWS_UOP_READ_PLANAR_FV_FMA:
73
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 96 times.
156 FMT("par.filter.type", "%s", pixel_types[par->filter.type].full);
74 156 break;
75 66 case SWS_UOP_RW_SHUFFLE:
76
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 44 times.
66 FMT("par.shuffle.clear_value", "0x%x", par->shuffle.clear_value);
77
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 44 times.
66 FMT("par.shuffle.read_size", "%u", par->shuffle.read_size);
78
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 44 times.
66 FMT("par.shuffle.write_size", "%u", par->shuffle.write_size);
79 66 break;
80 105 case SWS_UOP_LSHIFT:
81 case SWS_UOP_RSHIFT:
82
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 63 times.
105 FMT("par.shift.amount", "%u", par->shift.amount);
83 105 break;
84 434 case SWS_UOP_PERMUTE:
85 case SWS_UOP_COPY:
86
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 260 times.
434 FMT("par.move.num_moves", "%d", par->move.num_moves);
87
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 260 times.
434 FMT_SUB("par.move.dst", "%d, %d, %d, %d, %d, %d",
88 par->move.dst[0], par->move.dst[1], par->move.dst[2],
89 par->move.dst[3], par->move.dst[4], par->move.dst[5]);
90
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 260 times.
434 FMT_SUB("par.move.src", "%d, %d, %d, %d, %d, %d",
91 par->move.src[0], par->move.src[1], par->move.src[2],
92 par->move.src[3], par->move.src[4], par->move.src[5]);
93 434 break;
94 90 case SWS_UOP_PACK:
95 case SWS_UOP_UNPACK:
96
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 54 times.
90 FMT_SUB("par.pack.pattern", "%d, %d, %d, %d",
97 par->pack.pattern[0], par->pack.pattern[1],
98 par->pack.pattern[2], par->pack.pattern[3]);
99 90 break;
100 165 case SWS_UOP_CLEAR:
101
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 99 times.
165 FMT("par.clear.one", "0x%05x", par->clear.one);
102
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 99 times.
165 FMT("par.clear.zero", "0x%05x", par->clear.zero);
103 165 break;
104 219 case SWS_UOP_LINEAR:
105 case SWS_UOP_LINEAR_FMA:
106
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 137 times.
219 FMT("par.lin.one", "0x%05x", par->lin.one);
107
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 137 times.
219 FMT("par.lin.zero", "0x%05x", par->lin.zero);
108
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 135 times.
219 if (uop->uop == SWS_UOP_LINEAR_FMA)
109
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 56 times.
84 FMT("par.lin.exact", "0x%05x", par->lin.exact);
110 219 break;
111 120 case SWS_UOP_DITHER:
112
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 72 times.
120 FMT_SUB("par.dither.y_offset", "%u, %u, %u, %u",
113 par->dither.y_offset[0], par->dither.y_offset[1],
114 par->dither.y_offset[2], par->dither.y_offset[3]);
115
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 72 times.
120 FMT("par.dither.size_log2", "%u", par->dither.size_log2);
116 120 break;
117 20 case SWS_UOP_LUT_3D:
118
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
20 FMT("par.lut3d.dynamic", "%d", par->lut3d.dynamic);
119 20 break;
120 }
121
122 #undef FMT
123 #undef FMT_SUB
124 2120 }
125
126 836 static int generate_entry_struct(void *opaque, void *key)
127 {
128 836 const SwsUOp *ref = opaque;
129 836 const SwsUOp *uop = key;
130 836 AVBPrint *bp = ref->data.opaque;
131 char name[SWS_UOP_NAME_MAX];
132 836 ff_sws_uop_name(uop, name);
133 836 av_bprintf(bp, " \\\n MACRO(__VA_ARGS__, %-40s", name);
134 836 av_bprintf(bp, ", .type = %-13s, .uop = %-24s, .mask = 0x%x",
135 836 pixel_types[uop->type].full, uop_names[uop->uop].full, uop->mask);
136 836 print_params(bp, uop, true);
137 836 av_bprintf(bp, ")");
138 836 return 0;
139 }
140
141 836 static int generate_entry_args(void *opaque, void *key)
142 {
143 836 const SwsUOp *ref = opaque;
144 836 const SwsUOp *uop = key;
145 836 AVBPrint *bp = ref->data.opaque;
146 char name[SWS_UOP_NAME_MAX];
147 836 ff_sws_uop_name(uop, name);
148 836 av_bprintf(bp, " \\\n MACRO(__VA_ARGS__, %-40s, %-13s, %-24s, 0x%x",
149 836 name, pixel_types[uop->type].full, uop_names[uop->uop].full, uop->mask);
150 836 print_params(bp, uop, false);
151 836 av_bprintf(bp, ")");
152 836 return 0;
153 }
154
155 448 static int generate_entry_nasm(void *opaque, void *key)
156 {
157 448 const SwsUOp *ref = opaque;
158 448 const SwsUOp *uop = key;
159 448 AVBPrint *bp = ref->data.opaque;
160 char name[SWS_UOP_NAME_MAX];
161 448 ff_sws_uop_name(uop, name);
162 448 av_bprintf(bp, "\n DECL_OP %%1, %-40s, %-13s, %-24s, 0x%x",
163 448 name, pixel_types[uop->type].full, uop_names[uop->uop].full, uop->mask);
164 448 print_params(bp, uop, false);
165 448 return 0;
166 }
167
168 struct EnumPriv {
169 const struct Backend *backend;
170 struct AVTreeNode *root;
171 AVMutex lock;
172 };
173
174 13106504 static int register_uop(struct EnumPriv *s, const SwsUOp *uop)
175 {
176 13106504 SwsUOp *key = av_memdup(uop, sizeof(*uop));
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13106504 times.
13106504 if (!key)
178 ✗ return AVERROR(ENOMEM);
179 13106504 memset(&key->data, 0, sizeof(key->data));
180
181 13106504 struct AVTreeNode *node = av_tree_node_alloc();
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13106504 times.
13106504 if (!node) {
183 ✗ av_free(key);
184 ✗ return AVERROR(ENOMEM);
185 }
186
187 13106504 ff_mutex_lock(&s->lock);
188 13106504 av_tree_insert(&s->root, key, ff_sws_uop_cmp_v, &node);
189 13106504 ff_mutex_unlock(&s->lock);
190
2/2
✓ Branch 0 taken 13105668 times.
✓ Branch 1 taken 836 times.
13106504 if (node) {
191 13105668 av_free(node);
192 13105668 av_free(key);
193 }
194 13106504 return 0;
195 }
196
197 3092430 static int register_flags(SwsContext *ctx, const SwsOpList *ops, SwsUOpFlags flags)
198 {
199 3092430 SwsUOpList *uops = ff_sws_uop_list_alloc();
200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3092430 times.
3092430 if (!uops)
201 ✗ return AVERROR(ENOMEM);
202
203 3092430 int ret = ff_sws_ops_translate(ctx, ops, flags, uops);
204
2/2
✓ Branch 0 taken 690624 times.
✓ Branch 1 taken 2401806 times.
3092430 if (ret < 0)
205 690624 goto fail;
206
207
2/2
✓ Branch 0 taken 13106504 times.
✓ Branch 1 taken 2401806 times.
15508310 for (int i = 0; i < uops->num_ops; i++) {
208 13106504 ret = register_uop(ctx->opaque, &uops->ops[i]);
209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13106504 times.
13106504 if (ret < 0)
210 ✗ goto fail;
211 }
212
213 2401806 fail:
214 3092430 ff_sws_uop_list_free(&uops);
215 3092430 return ret;
216 }
217
218 enum {
219 COMMON_FLAGS = SWS_UOP_FLAG_EXPAND_BIT | SWS_UOP_FLAG_READ_PALETTE |
220 SWS_UOP_FLAG_ADD | SWS_UOP_FLAG_PUNNING,
221 };
222
223 typedef struct Backend {
224 const char *name;
225 const char *guard; /* include guard for the generated C header */
226 SwsUOpFlags flags[2]; /* all flag combinations used by the backend */
227 } Backend;
228
229 static const Backend backends[] = {
230 {
231 .name = "c",
232 .guard = "SWSCALE_UOPS_MACROS_H",
233 .flags = { COMMON_FLAGS },
234 }, {
235 .name = "x86",
236 .guard = "SWSCALE_X86_UOPS_MACROS_H",
237 .flags = {
238 COMMON_FLAGS | SWS_UOP_FLAG_PSHUFB,
239 COMMON_FLAGS | SWS_UOP_FLAG_PSHUFB | SWS_UOP_FLAG_FMA, /* FMA3 */
240 },
241 },
242 };
243
244 1 static const Backend *find_backend(const char *name)
245 {
246
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 for (int i = 0; i < FF_ARRAY_ELEMS(backends); i++) {
247
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!strcmp(backends[i].name, name))
248 1 return &backends[i];
249 }
250 ✗ return NULL;
251 }
252
253 2291828 static int register_uops(SwsContext *ctx, const SwsOpList *ops,
254 SwsCompiledOp *out)
255 {
256 2291828 const struct EnumPriv *s = ctx->opaque;
257
2/2
✓ Branch 0 taken 3893032 times.
✓ Branch 1 taken 800602 times.
4693634 for (int i = 0; i < FF_ARRAY_ELEMS(s->backend->flags); i++) {
258
2/2
✓ Branch 0 taken 800602 times.
✓ Branch 1 taken 3092430 times.
3893032 if (!s->backend->flags[i])
259 800602 break;
260 3092430 int ret = register_flags(ctx, ops, s->backend->flags[i]);
261
2/2
✓ Branch 0 taken 690624 times.
✓ Branch 1 taken 2401806 times.
3092430 if (ret < 0)
262 690624 return ret;
263 }
264
265 1601204 *out = (SwsCompiledOp) {0}; /* dummy value, will be immediately freed */
266 1601204 return 0;
267 }
268
269 /* Dummy backend that just registers all seen uops */
270 static const SwsOpBackend backend_uops = {
271 .name = "uops_gen",
272 .compile = register_uops,
273 };
274
275 842688 static int register_all_uops(SwsContext *ctx, void *graph, SwsOpList *ops)
276 {
277 /* ff_sws_compile_pass() takes over ownership of `ops` */
278 842688 SwsOpList *copy = ff_sws_op_list_duplicate(ops);
279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 842688 times.
842688 if (!copy)
280 ✗ return AVERROR(ENOMEM);
281
282 842688 const int flags = SWS_OP_FLAG_DRY_RUN | SWS_OP_FLAG_SPLIT_MEMCPY;
283 842688 return ff_sws_compile_pass(graph, &backend_uops, &copy, flags, NULL, NULL);
284 }
285
286 static const SwsFlags flags_list[] = {
287 0,
288 SWS_ACCURATE_RND, /* may insert extra 1x1 dither ops (for accurate rounding) */
289 SWS_BITEXACT, /* prevents some FMA optimizations */
290 SWS_ACCURATE_RND | SWS_BITEXACT,
291 };
292
293 /* Limit the range of av_tree_enumerate() to only matching uop and type */
294 8480 static int enum_type(void *opaque, void *elem)
295 {
296 8480 const SwsUOp *a = opaque, *b = elem;
297
2/2
✓ Branch 0 taken 1540 times.
✓ Branch 1 taken 6940 times.
8480 if (a->type != b->type)
298 1540 return (int) b->type - a->type;
299
2/2
✓ Branch 0 taken 4820 times.
✓ Branch 1 taken 2120 times.
6940 if (a->uop != b->uop)
300 4820 return (int) b->uop - a->uop;
301 2120 return 0;
302 }
303
304 836 static int free_uop_key(void *opaque, void *key)
305 {
306 836 av_free(key);
307 836 return 0;
308 }
309
310 4 static void free_uops(struct AVTreeNode **root)
311 {
312 4 av_tree_enumerate(*root, NULL, NULL, free_uop_key);
313 4 av_tree_destroy(*root);
314 4 *root = NULL;
315 4 }
316
317 /**
318 * Collect all unique SwsUOps used by `backend` into a newly allocated tree.
319 *
320 * This function can be quite slow as it iterates over every possible
321 * combination of pixel formats and flags.
322 *
323 * Returns 0 or a negative error code. On success, the tree is returned via
324 * `root`, and must be freed with free_uops() by the caller.
325 */
326 2 static int collect_uops(struct AVTreeNode **root, const Backend *backend)
327 {
328 2 struct EnumPriv s = { .backend = backend };
329 2 SwsLut3D *lut3d = NULL;
330 2 int ret = ff_mutex_init(&s.lock, NULL);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret)
332 ✗ return AVERROR(ENOSYS);
333
334 /* Allocate dummy graph and context for ff_sws_compile_pass() */
335 2 SwsGraph *graph = ff_sws_graph_alloc();
336 2 SwsContext *ctx = sws_alloc_context();
337
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!graph || !ctx) {
338 ✗ ret = AVERROR(ENOMEM);
339 ✗ goto fail;
340 }
341
342 /* Use this to plumb the enum state through all the layers of abstraction */
343 2 graph->ctx = ctx;
344 2 ctx->opaque = &s;
345 2 ctx->scaler = SWS_SCALE_BILINEAR; /* cheaper to generate filter kernels */
346 2 ctx->threads = 0; /* use slice threading to speed up tree building */
347
348 /* Allocate dummy 3DLUT to force generation of SWS_UOP_LUT_3D */
349 2 lut3d = ff_sws_lut3d_alloc();
350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!lut3d) {
351 ✗ ret = AVERROR(ENOMEM);
352 ✗ goto fail;
353 }
354 2 ret = ff_sws_enum_op_lists(ctx, graph, lut3d, AV_PIX_FMT_NONE,
355 AV_PIX_FMT_NONE, register_all_uops);
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
357 ✗ goto fail;
358
359 2 lut3d->dynamic = true;
360 2 ret = ff_sws_enum_op_lists(ctx, graph, lut3d, AV_PIX_FMT_NONE,
361 AV_PIX_FMT_NONE, register_all_uops);
362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
363 ✗ goto fail;
364
365 /* Register all unique uops over every relevant combination of flags */
366
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 for (int i = 0; i < FF_ARRAY_ELEMS(flags_list); i++) {
367 8 ctx->flags = flags_list[i];
368 8 ret = ff_sws_enum_op_lists(ctx, graph, NULL, AV_PIX_FMT_NONE,
369 AV_PIX_FMT_NONE, register_all_uops);
370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (ret < 0)
371 ✗ goto fail;
372 }
373
374 2 *root = s.root;
375 2 s.root = NULL;
376
377 2 fail:
378 2 av_refstruct_unref(&lut3d);
379 2 free_uops(&s.root);
380 2 ff_mutex_destroy(&s.lock);
381 2 ff_sws_graph_free(&graph);
382 2 sws_free_context(&ctx);
383 2 return ret;
384 }
385
386 #define BPRINT_STR(str) av_bprint_append_data(bp, str, strlen(str))
387
388 /**
389 * Generate a set of boilerplate C preprocessor macros for describing and
390 * programmatically iterating over all SwsUOps in the tree at `root`.
391 *
392 * Returns 0 or a negative error code. On success, an allocated string is
393 * returned via `out_str`, and must be av_free()'d by the caller.
394 */
395 2 static int print_macros(struct AVTreeNode *root, const Backend *backend,
396 char **out_str)
397 {
398 2 AVBPrint bprint, *const bp = &bprint;
399 2 av_bprint_init(bp, 0, AV_BPRINT_SIZE_UNLIMITED);
400
401 2 BPRINT_STR(
402 "/**\n"
403 " * This file is automatically generated. Do not edit manually.\n"
404 " * To regenerate, run: make fate-sws-uops-macros GEN=1\n"
405 " */\n"
406 "\n");
407 2 av_bprintf(bp, "#ifndef %s\n#define %s\n\n", backend->guard, backend->guard);
408 2 BPRINT_STR(
409 "/**\n"
410 " * Boilerplate helper macros, for template-based backends. These will be\n"
411 " * instantiated like this, with parameters in struct order:\n"
412 " * MACRO(__VA_ARGS__, NAME, TYPE, UOP, MASK, [PARAMS,])\n"
413 " * The _STRUCT variants pass all arguments in C struct syntax, while the\n"
414 " * plain variants give them as separate C values (e.g. for use in calls)\n"
415 " */\n"
416 "#define SWS_GLUE3(x, y, z) x ## _ ## y ## _ ## z\n"
417 "#define SWS_FOR(TYPE, UOP, MACRO, ...) \\\n"
418 " SWS_GLUE3(SWS_FOR, TYPE, UOP)(MACRO, __VA_ARGS__)\n"
419 "#define SWS_FOR_STRUCT(TYPE, UOP, MACRO, ...) \\\n"
420 " SWS_GLUE3(SWS_FOR_STRUCT, TYPE, UOP)(MACRO, __VA_ARGS__)\n"
421 "\n");
422
423 2 SwsUOp key = { .data.opaque = bp };
424
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 for (key.type = SWS_PIXEL_NONE + 1; key.type < SWS_PIXEL_TYPE_NB; key.type++) {
425
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 8 times.
296 for (key.uop = SWS_UOP_INVALID + 1; key.uop < SWS_UOP_TYPE_NB; key.uop++) {
426 288 const char *macro = uop_names[key.uop].full + sizeof("SWS_UOP_") - 1;
427 288 const char *prefix = pixel_types[key.type].prefix;
428 288 av_bprintf(bp, "#define SWS_FOR_%s%s(MACRO, ...)", prefix, macro);
429 288 av_tree_enumerate(root, &key, enum_type, generate_entry_args);
430 288 av_bprintf(bp, "\n");
431 288 av_bprintf(bp, "#define SWS_FOR_STRUCT_%s%s(MACRO, ...)", prefix, macro);
432 288 av_tree_enumerate(root, &key, enum_type, generate_entry_struct);
433 288 av_bprintf(bp, "\n");
434 }
435 }
436
437 2 av_bprintf(bp, "\n#endif /* %s */", backend->guard);
438 2 return av_bprint_finalize(bp, out_str);
439 }
440
441 /**
442 * Generate the equivalent NASM macros, as one DECL_<TYPE>_<UOP> macro per
443 * uop group. Same return semantics as print_macros().
444 */
445 1 static int print_nasm_macros(struct AVTreeNode *root, char **out_str)
446 {
447 1 AVBPrint bprint, *const bp = &bprint;
448 1 av_bprint_init(bp, 0, AV_BPRINT_SIZE_UNLIMITED);
449
450 1 BPRINT_STR(
451 ";******************************************************************************\n"
452 ";* This file is automatically generated. Do not edit manually.\n"
453 ";* To regenerate, run: make fate-sws-uops-macros GEN=1\n"
454 ";*\n"
455 ";* Boilerplate helper macros, for template-based backends. Invoking\n"
456 ";* DECL_<TYPE>_<UOP> MACRO will instantiate, for every matching uop:\n"
457 ";* DECL_OP MACRO, NAME, TYPE, UOP, MASK, [PARAMS]\n"
458 ";* with parameters in struct order.\n"
459 ";******************************************************************************");
460
461 1 SwsUOp key = { .data.opaque = bp };
462
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (key.type = SWS_PIXEL_NONE + 1; key.type < SWS_PIXEL_TYPE_NB; key.type++) {
463
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 4 times.
148 for (key.uop = SWS_UOP_INVALID + 1; key.uop < SWS_UOP_TYPE_NB; key.uop++) {
464 144 const char *macro = uop_names[key.uop].full + sizeof("SWS_UOP_") - 1;
465 144 const char *prefix = pixel_types[key.type].prefix;
466 144 av_bprintf(bp, "\n\n%%macro DECL_%s%s 1", prefix, macro);
467 144 av_tree_enumerate(root, &key, enum_type, generate_entry_nasm);
468 144 av_bprintf(bp, "\n%%endmacro");
469 }
470 }
471
472 1 return av_bprint_finalize(bp, out_str);
473 }
474
475 1 static int write_file(const char *path, const char *str)
476 {
477 1 FILE *out = fopen(path, "wb");
478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!out) {
479 ✗ int ret = AVERROR(errno);
480 ✗ fprintf(stderr, "Failed to open %s: %s\n", path, av_err2str(ret));
481 ✗ return ret;
482 }
483
484 1 int ret = 0;
485
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 if (fputs(str, out) < 0 || fputc('\n', out) < 0)
486 ✗ ret = AVERROR(EIO);
487
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 if (fclose(out) != 0 && ret >= 0)
488 ✗ ret = AVERROR(errno);
489 1 return ret;
490 }
491
492 ✗ static int usage(void)
493 {
494 ✗ fprintf(stderr, "Usage: uops_macros_gen [-backend BACKEND] [-nasm FILE]\n"
495 "Writes C macros to stdout, and optionally NASM macros to FILE\n"
496 "BACKEND is one of: c (default), x86\n");
497 ✗ return 1;
498 }
499
500 2 int main(int argc, char **argv)
501 {
502 #ifdef _WIN32
503 _setmode(_fileno(stdout), _O_BINARY);
504 #endif
505
506 2 const Backend *backend = &backends[0];
507 2 const char *nasm_path = NULL;
508
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (int i = 1; i < argc; i += 2) {
509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (i + 1 >= argc)
510 ✗ return usage();
511
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!strcmp(argv[i], "-backend")) {
512 1 backend = find_backend(argv[i + 1]);
513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!backend)
514 ✗ return usage();
515
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (!strcmp(argv[i], "-nasm")) {
516 1 nasm_path = argv[i + 1];
517 } else {
518 ✗ return usage();
519 }
520 }
521
522 2 struct AVTreeNode *root = NULL;
523 2 int ret = collect_uops(&root, backend);
524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
525 ✗ return ret;
526
527 2 char *macros = NULL;
528 2 ret = print_macros(root, backend, &macros);
529
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ret >= 0)
530 2 puts(macros);
531 2 av_free(macros);
532
533
3/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 if (ret >= 0 && nasm_path) {
534 1 ret = print_nasm_macros(root, &macros);
535
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ret >= 0)
536 1 ret = write_file(nasm_path, macros);
537 1 av_free(macros);
538 }
539
540 2 free_uops(&root);
541 2 return ret;
542 }
543