1/* 2 * Copyright © 2015 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "nir.h" 25 26/** 27 * \file nir_sweep.c 28 * 29 * The nir_sweep() pass performs a mark and sweep pass over a nir_shader's associated 30 * memory - anything still connected to the program will be kept, and any dead memory 31 * we dropped on the floor will be freed. 32 * 33 * The expectation is that drivers should call this when finished compiling the shader 34 * (after any optimization, lowering, and so on). However, it's also fine to call it 35 * earlier, and even many times, trading CPU cycles for memory savings. 36 */ 37 38#define steal_list(mem_ctx, type, list) \ 39 foreach_list_typed(type, obj, node, list) { ralloc_steal(mem_ctx, obj); } 40 41static void sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node); 42 43static bool 44sweep_src_indirect(nir_src *src, void *nir) 45{ 46 if (!src->is_ssa && src->reg.indirect) 47 ralloc_steal(nir, src->reg.indirect); 48 49 return true; 50} 51 52static bool 53sweep_dest_indirect(nir_dest *dest, void *nir) 54{ 55 if (!dest->is_ssa && dest->reg.indirect) 56 ralloc_steal(nir, dest->reg.indirect); 57 58 return true; 59} 60 61static void 62sweep_block(nir_shader *nir, nir_block *block) 63{ 64 ralloc_steal(nir, block); 65 66 /* sweep_impl will mark all metadata invalid. We can safely release all of 67 * this here. 68 */ 69 ralloc_free(block->live_in); 70 block->live_in = NULL; 71 72 ralloc_free(block->live_out); 73 block->live_out = NULL; 74 75 nir_foreach_instr(instr, block) { 76 ralloc_steal(nir, instr); 77 78 nir_foreach_src(instr, sweep_src_indirect, nir); 79 nir_foreach_dest(instr, sweep_dest_indirect, nir); 80 } 81} 82 83static void 84sweep_if(nir_shader *nir, nir_if *iff) 85{ 86 ralloc_steal(nir, iff); 87 88 foreach_list_typed(nir_cf_node, cf_node, node, &iff->then_list) { 89 sweep_cf_node(nir, cf_node); 90 } 91 92 foreach_list_typed(nir_cf_node, cf_node, node, &iff->else_list) { 93 sweep_cf_node(nir, cf_node); 94 } 95} 96 97static void 98sweep_loop(nir_shader *nir, nir_loop *loop) 99{ 100 ralloc_steal(nir, loop); 101 102 foreach_list_typed(nir_cf_node, cf_node, node, &loop->body) { 103 sweep_cf_node(nir, cf_node); 104 } 105} 106 107static void 108sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node) 109{ 110 switch (cf_node->type) { 111 case nir_cf_node_block: 112 sweep_block(nir, nir_cf_node_as_block(cf_node)); 113 break; 114 case nir_cf_node_if: 115 sweep_if(nir, nir_cf_node_as_if(cf_node)); 116 break; 117 case nir_cf_node_loop: 118 sweep_loop(nir, nir_cf_node_as_loop(cf_node)); 119 break; 120 default: 121 unreachable("Invalid CF node type"); 122 } 123} 124 125static void 126sweep_impl(nir_shader *nir, nir_function_impl *impl) 127{ 128 ralloc_steal(nir, impl); 129 130 steal_list(nir, nir_variable, &impl->locals); 131 steal_list(nir, nir_register, &impl->registers); 132 133 foreach_list_typed(nir_cf_node, cf_node, node, &impl->body) { 134 sweep_cf_node(nir, cf_node); 135 } 136 137 sweep_block(nir, impl->end_block); 138 139 /* Wipe out all the metadata, if any. */ 140 nir_metadata_preserve(impl, nir_metadata_none); 141} 142 143static void 144sweep_function(nir_shader *nir, nir_function *f) 145{ 146 ralloc_steal(nir, f); 147 ralloc_steal(nir, f->params); 148 149 if (f->impl) 150 sweep_impl(nir, f->impl); 151} 152 153void 154nir_sweep(nir_shader *nir) 155{ 156 void *rubbish = ralloc_context(NULL); 157 158 /* First, move ownership of all the memory to a temporary context; assume dead. */ 159 ralloc_adopt(rubbish, nir); 160 161 ralloc_steal(nir, (char *)nir->info.name); 162 if (nir->info.label) 163 ralloc_steal(nir, (char *)nir->info.label); 164 165 /* Variables and registers are not dead. Steal them back. */ 166 steal_list(nir, nir_variable, &nir->uniforms); 167 steal_list(nir, nir_variable, &nir->inputs); 168 steal_list(nir, nir_variable, &nir->outputs); 169 steal_list(nir, nir_variable, &nir->shared); 170 steal_list(nir, nir_variable, &nir->globals); 171 steal_list(nir, nir_variable, &nir->system_values); 172 173 /* Recurse into functions, stealing their contents back. */ 174 foreach_list_typed(nir_function, func, node, &nir->functions) { 175 sweep_function(nir, func); 176 } 177 178 ralloc_steal(nir, nir->constant_data); 179 180 /* Free everything we didn't steal back. */ 181 ralloc_free(rubbish); 182} 183