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 41 static void sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node); 42 43 static bool 44 sweep_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 52 static bool 53 sweep_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 61 static void 62 sweep_block(nir_shader *nir, nir_block *block) 63 { 64 ralloc_steal(nir, block); 65 66 nir_foreach_instr(instr, block) { 67 ralloc_steal(nir, instr); 68 69 nir_foreach_src(instr, sweep_src_indirect, nir); 70 nir_foreach_dest(instr, sweep_dest_indirect, nir); 71 } 72 } 73 74 static void 75 sweep_if(nir_shader *nir, nir_if *iff) 76 { 77 ralloc_steal(nir, iff); 78 79 foreach_list_typed(nir_cf_node, cf_node, node, &iff->then_list) { 80 sweep_cf_node(nir, cf_node); 81 } 82 83 foreach_list_typed(nir_cf_node, cf_node, node, &iff->else_list) { 84 sweep_cf_node(nir, cf_node); 85 } 86 } 87 88 static void 89 sweep_loop(nir_shader *nir, nir_loop *loop) 90 { 91 ralloc_steal(nir, loop); 92 93 foreach_list_typed(nir_cf_node, cf_node, node, &loop->body) { 94 sweep_cf_node(nir, cf_node); 95 } 96 } 97 98 static void 99 sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node) 100 { 101 switch (cf_node->type) { 102 case nir_cf_node_block: 103 sweep_block(nir, nir_cf_node_as_block(cf_node)); 104 break; 105 case nir_cf_node_if: 106 sweep_if(nir, nir_cf_node_as_if(cf_node)); 107 break; 108 case nir_cf_node_loop: 109 sweep_loop(nir, nir_cf_node_as_loop(cf_node)); 110 break; 111 default: 112 unreachable("Invalid CF node type"); 113 } 114 } 115 116 static void 117 sweep_impl(nir_shader *nir, nir_function_impl *impl) 118 { 119 ralloc_steal(nir, impl); 120 121 ralloc_steal(nir, impl->params); 122 for (unsigned i = 0; i < impl->num_params; i++) 123 ralloc_steal(nir, impl->params[i]); 124 ralloc_steal(nir, impl->return_var); 125 steal_list(nir, nir_variable, &impl->locals); 126 steal_list(nir, nir_register, &impl->registers); 127 128 foreach_list_typed(nir_cf_node, cf_node, node, &impl->body) { 129 sweep_cf_node(nir, cf_node); 130 } 131 132 sweep_block(nir, impl->end_block); 133 134 /* Wipe out all the metadata, if any. */ 135 nir_metadata_preserve(impl, nir_metadata_none); 136 } 137 138 static void 139 sweep_function(nir_shader *nir, nir_function *f) 140 { 141 ralloc_steal(nir, f); 142 ralloc_steal(nir, f->params); 143 144 if (f->impl) 145 sweep_impl(nir, f->impl); 146 } 147 148 void 149 nir_sweep(nir_shader *nir) 150 { 151 void *rubbish = ralloc_context(NULL); 152 153 /* The shader may not own shader_info so check first */ 154 bool steal_info = false; 155 if (nir == ralloc_parent(nir->info)) 156 steal_info = true; 157 158 /* First, move ownership of all the memory to a temporary context; assume dead. */ 159 ralloc_adopt(rubbish, nir); 160 161 if (steal_info) 162 ralloc_steal(nir, nir->info); 163 164 ralloc_steal(nir, (char *)nir->info->name); 165 if (nir->info->label) 166 ralloc_steal(nir, (char *)nir->info->label); 167 168 /* Variables and registers are not dead. Steal them back. */ 169 steal_list(nir, nir_variable, &nir->uniforms); 170 steal_list(nir, nir_variable, &nir->inputs); 171 steal_list(nir, nir_variable, &nir->outputs); 172 steal_list(nir, nir_variable, &nir->shared); 173 steal_list(nir, nir_variable, &nir->globals); 174 steal_list(nir, nir_variable, &nir->system_values); 175 steal_list(nir, nir_register, &nir->registers); 176 177 /* Recurse into functions, stealing their contents back. */ 178 foreach_list_typed(nir_function, func, node, &nir->functions) { 179 sweep_function(nir, func); 180 } 181 182 /* Free everything we didn't steal back. */ 183 ralloc_free(rubbish); 184 } 185