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 
31 namespace r600_sb {
32 
visit(alu_node & n,bool enter)33 bool r600_sb::psi_ops::visit(alu_node& n, bool enter) {
34 	if (enter) {
35 	}
36 	return false;
37 }
38 
visit(node & n,bool enter)39 bool psi_ops::visit(node& n, bool enter) {
40 	if (enter) {
41 		assert(n.subtype == NST_PSI);
42 
43 		try_inline(n);
44 
45 		// TODO eliminate predication until there is full support in all passes
46 		// unpredicate instructions and replace psi-nodes with conditional moves
47 		eliminate(n);
48 	}
49 	return false;
50 }
51 
get_pred_val(node & n)52 value* get_pred_val(node &n) {
53 	value *pred_val = NULL;
54 
55 	for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; I += 3) {
56 		value* &pred = *I;
57 		if (pred) {
58 			if (!pred_val)
59 				pred_val = pred;
60 			else {
61 				assert(pred == pred_val);
62 			}
63 		}
64 	}
65 	return pred_val;
66 }
67 
68 // for now we'll never inline psi's with different predicate values,
69 // so psi node may only contain the refs to one predicate value.
try_inline(node & n)70 bool psi_ops::try_inline(node& n) {
71 	assert(n.subtype == NST_PSI);
72 
73 	vvec &ns = n.src;
74 
75 	int sz = ns.size();
76 	assert(sz && (sz % 3 == 0));
77 
78 	value *pred_val = get_pred_val(n);
79 
80 	int ps_mask = 0;
81 
82 	bool r = false;
83 
84 	for (int i = sz - 1; i >= 0; i -= 3) {
85 
86 		if (ps_mask == 3) {
87 			ns.erase(ns.begin(), ns.begin() + i + 1);
88 			return r;
89 		}
90 
91 		value* val = ns[i];
92 		value* predsel = ns[i-1];
93 		int ps = !predsel ? 3 : predsel == sh.get_pred_sel(0) ? 1 : 2;
94 
95 		assert(val->def);
96 
97 		if (val->def->subtype == NST_PSI && ps == 3) {
98 			if (get_pred_val(*val->def) != pred_val)
99 				continue;
100 
101 			vvec &ds = val->def->src;
102 
103 			ns.insert(ns.begin() + i + 1, ds.begin(), ds.end());
104 			ns.erase(ns.begin() + i - 2, ns.begin() + i + 1);
105 			i += ds.size();
106 			r = true;
107 
108 		} else {
109 			if ((ps_mask & ps) == ps) {
110 				// this predicate select is subsumed by already handled ops
111 				ns.erase(ns.begin() + i - 2, ns.begin() + i + 1);
112 			} else {
113 				ps_mask |= ps;
114 			}
115 		}
116 	}
117 	return r;
118 }
119 
try_reduce(node & n)120 bool psi_ops::try_reduce(node& n) {
121 	assert(n.subtype == NST_PSI);
122 	assert(n.src.size() % 3 == 0);
123 
124 	// TODO
125 
126 	return false;
127 }
128 
unpredicate(node * n)129 void psi_ops::unpredicate(node *n) {
130 
131 	if (!n->is_alu_inst())
132 		return;
133 
134 	alu_node *a = static_cast<alu_node*>(n);
135 	a->pred = NULL;
136 }
137 
eliminate(node & n)138 bool psi_ops::eliminate(node& n) {
139 	assert(n.subtype == NST_PSI);
140 	assert(n.src.size() == 6);
141 
142 	value *d = n.dst[0];
143 
144 	value *s1 = n.src[2];
145 	value *s2 = n.src[5];
146 
147 	value *pred = n.src[3];
148 
149 	bool psel = n.src[4] == sh.get_pred_sel(0);
150 
151 	value *sel = get_select_value_for_em(sh, pred);
152 
153 	if (s1->is_undef()) {
154 		if (s2->is_undef()) {
155 
156 		} else {
157 			n.insert_after(sh.create_mov(d, s2));
158 		}
159 	} else if (s2->is_undef()) {
160 		n.insert_after(sh.create_mov(d, s1));
161 	} else {
162 		alu_node *a = sh.create_alu();
163 		a->bc.set_op(ALU_OP3_CNDE_INT);
164 
165 		a->dst.push_back(d);
166 		a->src.push_back(sel);
167 
168 		if (psel) {
169 			a->src.push_back(s1);
170 			a->src.push_back(s2);
171 		} else {
172 			a->src.push_back(s2);
173 			a->src.push_back(s1);
174 		}
175 
176 		n.insert_after(a);
177 	}
178 
179 	n.remove();
180 
181 	if (s1->is_any_gpr() && !s1->is_undef() && s1->def)
182 		unpredicate(s1->def);
183 	if (s2->is_any_gpr() && !s2->is_undef() && s2->def)
184 		unpredicate(s2->def);
185 
186 	return false;
187 }
188 
189 } // namespace r600_sb
190