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 void 44sweep_block(nir_shader *nir, nir_block *block) 45{ 46 ralloc_steal(nir, block); 47 48 /* sweep_impl will mark all metadata invalid. We can safely release all of 49 * this here. 50 */ 51 ralloc_free(block->live_in); 52 block->live_in = NULL; 53 54 ralloc_free(block->live_out); 55 block->live_out = NULL; 56 57 nir_foreach_instr(instr, block) { 58 list_del(&instr->gc_node); 59 list_add(&instr->gc_node, &nir->gc_list); 60 } 61} 62 63static void 64sweep_if(nir_shader *nir, nir_if *iff) 65{ 66 ralloc_steal(nir, iff); 67 68 foreach_list_typed(nir_cf_node, cf_node, node, &iff->then_list) { 69 sweep_cf_node(nir, cf_node); 70 } 71 72 foreach_list_typed(nir_cf_node, cf_node, node, &iff->else_list) { 73 sweep_cf_node(nir, cf_node); 74 } 75} 76 77static void 78sweep_loop(nir_shader *nir, nir_loop *loop) 79{ 80 ralloc_steal(nir, loop); 81 82 foreach_list_typed(nir_cf_node, cf_node, node, &loop->body) { 83 sweep_cf_node(nir, cf_node); 84 } 85} 86 87static void 88sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node) 89{ 90 switch (cf_node->type) { 91 case nir_cf_node_block: 92 sweep_block(nir, nir_cf_node_as_block(cf_node)); 93 break; 94 case nir_cf_node_if: 95 sweep_if(nir, nir_cf_node_as_if(cf_node)); 96 break; 97 case nir_cf_node_loop: 98 sweep_loop(nir, nir_cf_node_as_loop(cf_node)); 99 break; 100 default: 101 unreachable("Invalid CF node type"); 102 } 103} 104 105static void 106sweep_impl(nir_shader *nir, nir_function_impl *impl) 107{ 108 ralloc_steal(nir, impl); 109 110 steal_list(nir, nir_variable, &impl->locals); 111 steal_list(nir, nir_register, &impl->registers); 112 113 foreach_list_typed(nir_cf_node, cf_node, node, &impl->body) { 114 sweep_cf_node(nir, cf_node); 115 } 116 117 sweep_block(nir, impl->end_block); 118 119 /* Wipe out all the metadata, if any. */ 120 nir_metadata_preserve(impl, nir_metadata_none); 121} 122 123static void 124sweep_function(nir_shader *nir, nir_function *f) 125{ 126 ralloc_steal(nir, f); 127 ralloc_steal(nir, f->params); 128 129 if (f->impl) 130 sweep_impl(nir, f->impl); 131} 132 133void 134nir_sweep(nir_shader *nir) 135{ 136 void *rubbish = ralloc_context(NULL); 137 138 struct list_head instr_gc_list; 139 list_inithead(&instr_gc_list); 140 141 list_replace(&nir->gc_list, &instr_gc_list); 142 list_inithead(&nir->gc_list); 143 144 /* First, move ownership of all the memory to a temporary context; assume dead. */ 145 ralloc_adopt(rubbish, nir); 146 147 ralloc_steal(nir, (char *)nir->info.name); 148 if (nir->info.label) 149 ralloc_steal(nir, (char *)nir->info.label); 150 151 /* Variables and registers are not dead. Steal them back. */ 152 steal_list(nir, nir_variable, &nir->variables); 153 154 /* Recurse into functions, stealing their contents back. */ 155 foreach_list_typed(nir_function, func, node, &nir->functions) { 156 sweep_function(nir, func); 157 } 158 159 /* Sweep instrs not found while walking the shader. */ 160 list_for_each_entry_safe(nir_instr, instr, &instr_gc_list, gc_node) { 161 nir_instr_free(instr); 162 } 163 assert(list_is_empty(&instr_gc_list)); 164 165 ralloc_steal(nir, nir->constant_data); 166 ralloc_steal(nir, nir->xfb_info); 167 ralloc_steal(nir, nir->printf_info); 168 for (int i = 0; i < nir->printf_info_count; i++) { 169 ralloc_steal(nir, nir->printf_info[i].arg_sizes); 170 ralloc_steal(nir, nir->printf_info[i].strings); 171 } 172 173 /* Free everything we didn't steal back. */ 174 ralloc_free(rubbish); 175} 176