| /* |
| * 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. |
| */ |
| |
| #include "nir.h" |
| |
| /** |
| * \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. |
| */ |
| |
| #define steal_list(mem_ctx, type, list) \ |
| foreach_list_typed(type, obj, node, list) { \ |
| ralloc_steal(mem_ctx, obj); \ |
| } |
| |
| 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); |
| |
| /* sweep_impl will mark all metadata invalid. We can safely release all of |
| * this here. |
| */ |
| ralloc_free(block->live_in); |
| block->live_in = NULL; |
| |
| ralloc_free(block->live_out); |
| block->live_out = NULL; |
| |
| nir_foreach_instr(instr, block) { |
| gc_mark_live(nir->gctx, instr); |
| |
| 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; |
| case nir_instr_type_intrinsic: |
| ralloc_steal(nir, (void*)nir_instr_as_intrinsic(instr)->name); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| 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) |
| { |
| assert(!nir_loop_has_continue_construct(loop)); |
| 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: |
| unreachable("Invalid CF node type"); |
| } |
| } |
| |
| static void |
| sweep_impl(nir_shader *nir, nir_function_impl *impl) |
| { |
| ralloc_steal(nir, impl); |
| |
| steal_list(nir, nir_variable, &impl->locals); |
| |
| 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. */ |
| nir_metadata_preserve(impl, nir_metadata_none); |
| } |
| |
| static void |
| sweep_function(nir_shader *nir, nir_function *f) |
| { |
| ralloc_steal(nir, f); |
| ralloc_steal(nir, f->params); |
| |
| if (f->impl) |
| sweep_impl(nir, f->impl); |
| } |
| |
| void |
| nir_sweep(nir_shader *nir) |
| { |
| void *rubbish = ralloc_context(NULL); |
| |
| struct list_head instr_gc_list; |
| list_inithead(&instr_gc_list); |
| |
| /* First, move ownership of all the memory to a temporary context; assume dead. */ |
| ralloc_adopt(rubbish, nir); |
| |
| /* Start sweeping */ |
| gc_sweep_start(nir->gctx); |
| |
| ralloc_steal(nir, nir->gctx); |
| ralloc_steal(nir, (char *)nir->info.name); |
| if (nir->info.label) |
| ralloc_steal(nir, (char *)nir->info.label); |
| |
| /* Variables are not dead. Steal them back. */ |
| steal_list(nir, nir_variable, &nir->variables); |
| |
| /* Recurse into functions, stealing their contents back. */ |
| foreach_list_typed(nir_function, func, node, &nir->functions) { |
| sweep_function(nir, func); |
| } |
| |
| ralloc_steal(nir, nir->constant_data); |
| ralloc_steal(nir, nir->xfb_info); |
| 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); |
| } |
| |
| /* Free everything we didn't steal back. */ |
| gc_sweep_end(nir->gctx); |
| ralloc_free(rubbish); |
| } |