2015-03-27 19:50:29 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2015 Intel Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-02-07 14:20:44 +01:00
|
|
|
#include "util/u_printf.h"
|
2025-02-24 15:09:24 -05:00
|
|
|
#include "nir.h"
|
2015-03-27 19:50:29 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \file nir_sweep.c
|
|
|
|
|
*
|
|
|
|
|
* The nir_sweep() pass performs a mark and sweep pass over a nir_shader's associated
|
|
|
|
|
* memory - anything still connected to the program will be kept, and any dead memory
|
|
|
|
|
* we dropped on the floor will be freed.
|
|
|
|
|
*
|
|
|
|
|
* The expectation is that drivers should call this when finished compiling the shader
|
|
|
|
|
* (after any optimization, lowering, and so on). However, it's also fine to call it
|
|
|
|
|
* earlier, and even many times, trading CPU cycles for memory savings.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-08-01 23:10:18 -04:00
|
|
|
static void
|
|
|
|
|
sweep_constant(nir_shader *nir, nir_constant *c)
|
|
|
|
|
{
|
|
|
|
|
ralloc_steal(nir, c);
|
|
|
|
|
|
|
|
|
|
if (c->num_elements) {
|
|
|
|
|
assert(c->elements);
|
|
|
|
|
ralloc_steal(nir, c->elements);
|
|
|
|
|
for (unsigned i = 0; i < c->num_elements; i++)
|
|
|
|
|
sweep_constant(nir, c->elements[i]);
|
|
|
|
|
} else {
|
|
|
|
|
assert(!c->elements);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sweep_variable(nir_shader *nir, nir_variable *var)
|
|
|
|
|
{
|
2025-08-01 23:44:05 -04:00
|
|
|
gc_mark_live(nir->gctx, var);
|
2025-08-01 23:10:18 -04:00
|
|
|
nir_variable_steal_name(nir, var, var);
|
|
|
|
|
ralloc_steal(nir, var->max_ifc_array_access);
|
|
|
|
|
ralloc_steal(nir, var->state_slots);
|
|
|
|
|
if (var->constant_initializer)
|
|
|
|
|
sweep_constant(nir, var->constant_initializer);
|
|
|
|
|
if (var->pointer_initializer)
|
|
|
|
|
sweep_variable(nir, var->pointer_initializer);
|
|
|
|
|
ralloc_steal(nir, var->members);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sweep_var_list(nir_shader *nir, struct exec_list *list)
|
|
|
|
|
{
|
|
|
|
|
foreach_list_typed(nir_variable, var, node, list) {
|
|
|
|
|
sweep_variable(nir, var);
|
2023-08-08 12:00:35 -05:00
|
|
|
}
|
2025-08-01 23:10:18 -04:00
|
|
|
}
|
2015-03-27 19:50:29 -07:00
|
|
|
|
|
|
|
|
static void sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node);
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sweep_block(nir_shader *nir, nir_block *block)
|
|
|
|
|
{
|
|
|
|
|
ralloc_steal(nir, block);
|
|
|
|
|
|
2016-04-26 18:34:19 -07:00
|
|
|
nir_foreach_instr(instr, block) {
|
2025-02-24 19:50:13 +01:00
|
|
|
gc_mark_live(nir->gctx, nir_instr_get_gc_pointer(instr));
|
|
|
|
|
|
|
|
|
|
if (instr->has_debug_info) {
|
|
|
|
|
nir_instr_debug_info *debug_info = nir_instr_get_debug_info(instr);
|
|
|
|
|
ralloc_steal(nir, debug_info->filename);
|
|
|
|
|
ralloc_steal(nir, debug_info->variable_name);
|
|
|
|
|
}
|
2021-09-08 15:24:10 +01:00
|
|
|
|
|
|
|
|
switch (instr->type) {
|
|
|
|
|
case nir_instr_type_tex:
|
|
|
|
|
gc_mark_live(nir->gctx, nir_instr_as_tex(instr)->src);
|
|
|
|
|
break;
|
|
|
|
|
case nir_instr_type_phi:
|
|
|
|
|
nir_foreach_phi_src(src, nir_instr_as_phi(instr))
|
|
|
|
|
gc_mark_live(nir->gctx, src);
|
|
|
|
|
break;
|
2024-04-18 10:54:02 -04:00
|
|
|
case nir_instr_type_intrinsic:
|
2025-02-24 15:09:24 -05:00
|
|
|
ralloc_steal(nir, (void *)nir_instr_as_intrinsic(instr)->name);
|
2024-04-18 10:54:02 -04:00
|
|
|
break;
|
2021-09-08 15:24:10 +01:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-03-27 19:50:29 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sweep_if(nir_shader *nir, nir_if *iff)
|
|
|
|
|
{
|
|
|
|
|
ralloc_steal(nir, iff);
|
|
|
|
|
|
|
|
|
|
foreach_list_typed(nir_cf_node, cf_node, node, &iff->then_list) {
|
|
|
|
|
sweep_cf_node(nir, cf_node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach_list_typed(nir_cf_node, cf_node, node, &iff->else_list) {
|
|
|
|
|
sweep_cf_node(nir, cf_node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sweep_loop(nir_shader *nir, nir_loop *loop)
|
|
|
|
|
{
|
2021-12-02 10:31:56 +01:00
|
|
|
assert(!nir_loop_has_continue_construct(loop));
|
2015-03-27 19:50:29 -07:00
|
|
|
ralloc_steal(nir, loop);
|
|
|
|
|
|
|
|
|
|
foreach_list_typed(nir_cf_node, cf_node, node, &loop->body) {
|
|
|
|
|
sweep_cf_node(nir, cf_node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node)
|
|
|
|
|
{
|
|
|
|
|
switch (cf_node->type) {
|
|
|
|
|
case nir_cf_node_block:
|
|
|
|
|
sweep_block(nir, nir_cf_node_as_block(cf_node));
|
|
|
|
|
break;
|
|
|
|
|
case nir_cf_node_if:
|
|
|
|
|
sweep_if(nir, nir_cf_node_as_if(cf_node));
|
|
|
|
|
break;
|
|
|
|
|
case nir_cf_node_loop:
|
|
|
|
|
sweep_loop(nir, nir_cf_node_as_loop(cf_node));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2025-07-23 09:17:35 +02:00
|
|
|
UNREACHABLE("Invalid CF node type");
|
2015-03-27 19:50:29 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sweep_impl(nir_shader *nir, nir_function_impl *impl)
|
|
|
|
|
{
|
|
|
|
|
ralloc_steal(nir, impl);
|
|
|
|
|
|
2025-08-01 23:10:18 -04:00
|
|
|
sweep_var_list(nir, &impl->locals);
|
2015-03-27 19:50:29 -07:00
|
|
|
|
|
|
|
|
foreach_list_typed(nir_cf_node, cf_node, node, &impl->body) {
|
|
|
|
|
sweep_cf_node(nir, cf_node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sweep_block(nir, impl->end_block);
|
|
|
|
|
|
|
|
|
|
/* Wipe out all the metadata, if any. */
|
treewide: Switch to nir_progress
Via the Coccinelle patch at the end of the commit message, followed by
sed -ie 's/progress = progress | /progress |=/g' $(git grep -l 'progress = prog')
ninja -C ~/mesa/build clang-format
cd ~/mesa/src/compiler/nir && clang-format -i *.c
agxfmt
@@
identifier prog;
expression impl, metadata;
@@
-if (prog) {
-nir_metadata_preserve(impl, metadata);
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-}
-return prog;
+return nir_progress(prog, impl, metadata);
@@
expression prog_expr, impl, metadata;
@@
-if (prog_expr) {
-nir_metadata_preserve(impl, metadata);
-return true;
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-return false;
-}
+bool progress = prog_expr;
+return nir_progress(progress, impl, metadata);
@@
identifier prog;
expression impl, metadata;
@@
-nir_metadata_preserve(impl, prog ? (metadata) : nir_metadata_all);
-return prog;
+return nir_progress(prog, impl, metadata);
@@
identifier prog;
expression impl, metadata;
@@
-nir_metadata_preserve(impl, prog ? (metadata) : nir_metadata_all);
+nir_progress(prog, impl, metadata);
@@
expression impl, metadata;
@@
-nir_metadata_preserve(impl, metadata);
-return true;
+return nir_progress(true, impl, metadata);
@@
expression impl;
@@
-nir_metadata_preserve(impl, nir_metadata_all);
-return false;
+return nir_no_progress(impl);
@@
identifier other_prog, prog;
expression impl, metadata;
@@
-if (prog) {
-nir_metadata_preserve(impl, metadata);
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-}
-other_prog |= prog;
+other_prog = other_prog | nir_progress(prog, impl, metadata);
@@
identifier prog;
expression impl, metadata;
@@
-if (prog) {
-nir_metadata_preserve(impl, metadata);
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-}
+nir_progress(prog, impl, metadata);
@@
identifier other_prog, prog;
expression impl, metadata;
@@
-if (prog) {
-nir_metadata_preserve(impl, metadata);
-other_prog = true;
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-}
+other_prog = other_prog | nir_progress(prog, impl, metadata);
@@
expression prog_expr, impl, metadata;
identifier prog;
@@
-if (prog_expr) {
-nir_metadata_preserve(impl, metadata);
-prog = true;
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-}
+bool impl_progress = prog_expr;
+prog = prog | nir_progress(impl_progress, impl, metadata);
@@
identifier other_prog, prog;
expression impl, metadata;
@@
-if (prog) {
-other_prog = true;
-nir_metadata_preserve(impl, metadata);
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-}
+other_prog = other_prog | nir_progress(prog, impl, metadata);
@@
expression prog_expr, impl, metadata;
identifier prog;
@@
-if (prog_expr) {
-prog = true;
-nir_metadata_preserve(impl, metadata);
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-}
+bool impl_progress = prog_expr;
+prog = prog | nir_progress(impl_progress, impl, metadata);
@@
expression prog_expr, impl, metadata;
@@
-if (prog_expr) {
-nir_metadata_preserve(impl, metadata);
-} else {
-nir_metadata_preserve(impl, nir_metadata_all);
-}
+bool impl_progress = prog_expr;
+nir_progress(impl_progress, impl, metadata);
@@
identifier prog;
expression impl, metadata;
@@
-nir_metadata_preserve(impl, metadata);
-prog = true;
+prog = nir_progress(true, impl, metadata);
@@
identifier prog;
expression impl, metadata;
@@
-if (prog) {
-nir_metadata_preserve(impl, metadata);
-}
-return prog;
+return nir_progress(prog, impl, metadata);
@@
identifier prog;
expression impl, metadata;
@@
-if (prog) {
-nir_metadata_preserve(impl, metadata);
-}
+nir_progress(prog, impl, metadata);
@@
expression impl;
@@
-nir_metadata_preserve(impl, nir_metadata_all);
+nir_no_progress(impl);
@@
expression impl, metadata;
@@
-nir_metadata_preserve(impl, metadata);
+nir_progress(true, impl, metadata);
squashme! sed -ie 's/progress = progress | /progress |=/g' $(git grep -l 'progress = prog')
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: Georg Lehmann <dadschoorse@gmail.com>
Acked-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33722>
2025-02-24 15:10:33 -05:00
|
|
|
nir_progress(true, impl, nir_metadata_none);
|
2025-11-12 15:49:05 -05:00
|
|
|
|
|
|
|
|
/* These will be reallocated if needed. NULL them out so we don't
|
|
|
|
|
* use-after-free later.
|
|
|
|
|
*/
|
|
|
|
|
impl->dom_lca_info.table.table = NULL;
|
|
|
|
|
impl->dom_lca_info.block_from_idx = NULL;
|
2015-03-27 19:50:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sweep_function(nir_shader *nir, nir_function *f)
|
|
|
|
|
{
|
|
|
|
|
ralloc_steal(nir, f);
|
2015-12-26 10:00:47 -08:00
|
|
|
ralloc_steal(nir, f->params);
|
2015-03-27 19:50:29 -07:00
|
|
|
|
2025-05-21 23:09:44 +02:00
|
|
|
for (unsigned i = 0; i < f->num_params; i++)
|
|
|
|
|
ralloc_steal(nir, (char *)f->params[i].name);
|
|
|
|
|
|
2015-12-26 10:00:47 -08:00
|
|
|
if (f->impl)
|
|
|
|
|
sweep_impl(nir, f->impl);
|
2015-03-27 19:50:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nir_sweep(nir_shader *nir)
|
|
|
|
|
{
|
|
|
|
|
void *rubbish = ralloc_context(NULL);
|
|
|
|
|
|
2021-07-07 10:22:21 -07:00
|
|
|
struct list_head instr_gc_list;
|
|
|
|
|
list_inithead(&instr_gc_list);
|
|
|
|
|
|
2015-03-27 19:50:29 -07:00
|
|
|
/* First, move ownership of all the memory to a temporary context; assume dead. */
|
|
|
|
|
ralloc_adopt(rubbish, nir);
|
|
|
|
|
|
2021-09-08 15:24:10 +01:00
|
|
|
/* Start sweeping */
|
|
|
|
|
gc_sweep_start(nir->gctx);
|
|
|
|
|
|
|
|
|
|
ralloc_steal(nir, nir->gctx);
|
2017-05-08 09:20:21 -07:00
|
|
|
ralloc_steal(nir, (char *)nir->info.name);
|
|
|
|
|
if (nir->info.label)
|
|
|
|
|
ralloc_steal(nir, (char *)nir->info.label);
|
2015-10-05 17:16:02 -07:00
|
|
|
|
2023-08-01 11:03:10 -04:00
|
|
|
/* Variables are not dead. Steal them back. */
|
2025-08-01 23:10:18 -04:00
|
|
|
sweep_var_list(nir, &nir->variables);
|
2015-03-27 19:50:29 -07:00
|
|
|
|
|
|
|
|
/* Recurse into functions, stealing their contents back. */
|
|
|
|
|
foreach_list_typed(nir_function, func, node, &nir->functions) {
|
|
|
|
|
sweep_function(nir, func);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 19:16:19 -07:00
|
|
|
ralloc_steal(nir, nir->constant_data);
|
2022-05-17 10:16:55 -05:00
|
|
|
ralloc_steal(nir, nir->xfb_info);
|
2022-03-19 16:36:46 +01:00
|
|
|
ralloc_steal(nir, nir->printf_info);
|
|
|
|
|
for (int i = 0; i < nir->printf_info_count; i++) {
|
|
|
|
|
ralloc_steal(nir, nir->printf_info[i].arg_sizes);
|
|
|
|
|
ralloc_steal(nir, nir->printf_info[i].strings);
|
|
|
|
|
}
|
2018-06-28 19:16:19 -07:00
|
|
|
|
2015-03-27 19:50:29 -07:00
|
|
|
/* Free everything we didn't steal back. */
|
2021-09-08 15:24:10 +01:00
|
|
|
gc_sweep_end(nir->gctx);
|
2015-03-27 19:50:29 -07:00
|
|
|
ralloc_free(rubbish);
|
|
|
|
|
}
|