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