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
33bool r600_sb::psi_ops::visit(alu_node& n, bool enter) {
34	if (enter) {
35	}
36	return false;
37}
38
39bool 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
52value* 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.
70bool 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
120bool 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
129void 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
138bool 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