Home | History | Annotate | Download | only in nir
      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