1/*
2 * Copyright 2013 Vadim Girlin <vadimgirlin@gmail.com>
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 *      Vadim Girlin
25 */
26
27#include "sb_shader.h"
28
29#include "sb_pass.h"
30
31namespace r600_sb {
32
33int dce_cleanup::run() {
34	int r;
35
36	// Run cleanup for as long as there are unused nodes.
37	do {
38		nodes_changed = false;
39		r = vpass::run();
40	} while (r == 0 && nodes_changed);
41
42	return r;
43}
44
45bool dce_cleanup::visit(node& n, bool enter) {
46	if (enter) {
47	} else {
48		if (n.flags & NF_DEAD)
49			n.remove();
50		else
51			cleanup_dst(n);
52	}
53	return true;
54}
55
56bool dce_cleanup::visit(alu_group_node& n, bool enter) {
57	if (enter) {
58	} else {
59		n.expand();
60	}
61	return true;
62}
63
64bool dce_cleanup::visit(cf_node& n, bool enter) {
65	if (enter) {
66		if (n.flags & NF_DEAD)
67			n.remove();
68		else
69			cleanup_dst(n);
70	} else {
71		if ((sh.dce_flags & DF_EXPAND) &&
72				(n.bc.op_ptr->flags & (CF_CLAUSE | CF_BRANCH | CF_LOOP)))
73			n.expand();
74	}
75	return true;
76}
77
78bool dce_cleanup::visit(alu_node& n, bool enter) {
79	if (enter) {
80	} else {
81		if (n.flags & NF_DEAD)
82			n.remove();
83		else
84			cleanup_dst(n);
85	}
86	return true;
87}
88
89bool dce_cleanup::visit(alu_packed_node& n, bool enter) {
90	if (enter) {
91	} else {
92		if (n.flags & NF_DEAD)
93			n.remove();
94		else
95			cleanup_dst(n);
96	}
97	return false;
98}
99
100bool dce_cleanup::visit(fetch_node& n, bool enter) {
101	if (enter) {
102	} else {
103		if (n.flags & NF_DEAD)
104			n.remove();
105		else
106			cleanup_dst(n);
107	}
108	return true;
109}
110
111bool dce_cleanup::visit(region_node& n, bool enter) {
112	if (enter) {
113		if (n.loop_phi)
114			run_on(*n.loop_phi);
115	} else {
116		if (n.phi)
117			run_on(*n.phi);
118	}
119	return true;
120}
121
122void dce_cleanup::cleanup_dst(node& n) {
123	if (!cleanup_dst_vec(n.dst) && remove_unused &&
124			!n.dst.empty() && !(n.flags & NF_DONT_KILL) && n.parent)
125	{
126		// Delete use references to the removed node from the src values.
127		for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; ++I) {
128			value* v = *I;
129			if (v && v->def && v->uses.size())
130			{
131				v->remove_use(&n);
132			}
133		}
134		n.remove();
135		nodes_changed = true;
136	}
137}
138
139bool dce_cleanup::visit(container_node& n, bool enter) {
140	if (enter)
141		cleanup_dst(n);
142	return true;
143}
144
145bool dce_cleanup::cleanup_dst_vec(vvec& vv) {
146	bool alive = false;
147
148	for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
149		value* &v = *I;
150		if (!v)
151			continue;
152
153		if (v->gvn_source && v->gvn_source->is_dead())
154			v->gvn_source = NULL;
155
156		if (v->is_dead() || (remove_unused && !v->is_rel() && !v->uses.size()))
157			v = NULL;
158		else
159			alive = true;
160	}
161
162	return alive;
163}
164
165} // namespace r600_sb
166