r600g/sb: fix issues cause by GLSL switching to loops for switch
[mesa.git] / src / gallium / drivers / r600 / sb / sb_gvn.cpp
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 #define GVN_DEBUG 0
28
29 #if GVN_DEBUG
30 #define GVN_DUMP(q) do { q } while (0)
31 #else
32 #define GVN_DUMP(q)
33 #endif
34
35 #include "sb_shader.h"
36 #include "sb_pass.h"
37 #include "sb_sched.h"
38
39 namespace r600_sb {
40
41 bool gvn::visit(node& n, bool enter) {
42 if (enter) {
43
44
45 bool rewrite = true;
46
47 if (n.dst[0]->is_agpr()) {
48 rewrite = false;
49 }
50
51
52 process_op(n, rewrite);
53
54 assert(n.parent);
55
56 if (n.parent->subtype == NST_LOOP_PHI_CONTAINER) {
57 // There is a problem - sometimes with nested loops
58 // loop counter initialization for inner loop is incorrectly hoisted
59 // out of the outer loop
60
61 // FIXME not sure if this is enough to fix a problem completely,
62 // possibly more complete fix is needed (anyway, the
63 // problem was seen only in relatively complex
64 // case involving nested loops and
65 // indirect access to loop counters (without proper array info
66 // loop counters may be considered as array elements too),
67 // was not seen in any tests
68 // or real apps when proper array information is available in TGSI).
69
70 // For now just mark the instructions that initialize loop counters
71 // with DONT_HOIST flag to prevent the insts like MOV r, 0
72 // (initialization of inner loop's counter with const)
73 // from being hoisted out of the outer loop
74
75 assert(!n.src.empty());
76 value *v = n.src[0];
77
78 if (v->is_any_gpr() && v->def)
79 v->def->flags |= NF_DONT_HOIST;
80 }
81
82 } else {
83 }
84 return true;
85 }
86
87 bool gvn::visit(cf_node& n, bool enter) {
88 if (enter) {
89 process_op(n);
90 } else {
91 }
92 return true;
93 }
94
95 bool gvn::visit(alu_node& n, bool enter) {
96 if (enter) {
97 process_op(n);
98 } else {
99 }
100 return true;
101 }
102
103 bool gvn::visit(alu_packed_node& n, bool enter) {
104 if (enter) {
105 process_op(n);
106 } else {
107 }
108 return false;
109 }
110
111 bool gvn::visit(fetch_node& n, bool enter) {
112 if (enter) {
113 process_op(n);
114 } else {
115 }
116 return true;
117 }
118
119 bool gvn::visit(region_node& n, bool enter) {
120 if (enter) {
121 // FIXME: loop_phi sources are undefined yet (except theone from the preceding
122 // code), can we handle that somehow?
123 // if (n.loop_phi)
124 // run_on(*n.loop_phi);
125 } else {
126 if (n.loop_phi)
127 run_on(*n.loop_phi);
128
129 if (n.phi)
130 run_on(*n.phi);
131 }
132 return true;
133 }
134
135 bool gvn::process_src(value* &v, bool rewrite) {
136 if (!v->gvn_source)
137 sh.vt.add_value(v);
138
139 if (rewrite && !v->gvn_source->is_rel()) {
140 v = v->gvn_source;
141 return true;
142 }
143 return false;
144 }
145
146 // FIXME: maybe handle it in the scheduler?
147 void gvn::process_alu_src_constants(node &n, value* &v) {
148 if (n.src.size() < 3) {
149 process_src(v, true);
150 return;
151 }
152
153 if (!v->gvn_source)
154 sh.vt.add_value(v);
155
156 rp_kcache_tracker kc(sh);
157
158 if (v->gvn_source->is_kcache())
159 kc.try_reserve(v->gvn_source->select);
160
161 // don't propagate 3rd constant to the trans-only instruction
162 if (!n.is_alu_packed()) {
163 alu_node *a = static_cast<alu_node*>(&n);
164 if (a->bc.op_ptr->src_count == 3 && !(a->bc.slot_flags & AF_V)) {
165 unsigned const_count = 0;
166 for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E;
167 ++I) {
168 value *c = (*I);
169 if (c && c->is_readonly() && ++const_count == 2) {
170 process_src(v, false);
171 return;
172 }
173 }
174 }
175 }
176
177 for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; ++I) {
178 value *c = (*I);
179
180 if (c->is_kcache() && !kc.try_reserve(c->select)) {
181 process_src(v, false);
182 return;
183 }
184 }
185 process_src(v, true);
186 }
187
188 void gvn::process_op(node& n, bool rewrite) {
189
190 for(vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; ++I) {
191 value* &v = *I;
192 if (v) {
193 if (v->rel) {
194 process_src(v->rel, rewrite);
195 }
196
197 if (rewrite && v->gvn_source && v->gvn_source->is_readonly() &&
198 n.is_any_alu()) {
199 process_alu_src_constants(n, v);
200 } else if (rewrite && v->gvn_source && v->gvn_source->is_const() &&
201 (n.is_fetch_op(FETCH_OP_VFETCH) ||
202 n.is_fetch_op(FETCH_OP_SEMFETCH)))
203 process_src(v, false);
204 else
205 process_src(v, rewrite);
206 }
207 }
208 if (n.pred)
209 process_src(n.pred, false);
210
211 if (n.type == NT_IF) {
212 if_node &i = (if_node&)n;
213 if (i.cond)
214 process_src(i.cond, false);
215 }
216
217 for(vvec::iterator I = n.dst.begin(), E = n.dst.end(); I != E; ++I) {
218 value *v = *I;
219 if (v) {
220 if (v->rel)
221 process_src(v->rel, rewrite);
222 sh.vt.add_value(v);
223 }
224 }
225 }
226
227 } // namespace r600_sb