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 #include "sb_pass.h"
29
30 namespace r600_sb {
31
visit(node & n,bool enter)32 bool dump::visit(node& n, bool enter) {
33 if (enter) {
34 indent();
35 dump_flags(n);
36
37 switch (n.subtype) {
38 case NST_PHI:
39 dump_op(n, "* phi");
40 break;
41 case NST_PSI:
42 dump_op(n, "* psi");
43 break;
44 case NST_COPY:
45 dump_op(n, "* copy");
46 break;
47 default:
48 assert(!"invalid node subtype");
49 break;
50 }
51 sblog << "\n";
52 }
53 return false;
54 }
55
visit(container_node & n,bool enter)56 bool dump::visit(container_node& n, bool enter) {
57 if (enter) {
58 if (!n.empty()) {
59 indent();
60 dump_flags(n);
61 sblog << "{ ";
62 if (!n.dst.empty()) {
63 sblog << " preloaded inputs [";
64 dump_vec(n.dst);
65 sblog << "] ";
66 }
67 dump_live_values(n, true);
68 }
69 ++level;
70 } else {
71 --level;
72 if (!n.empty()) {
73 indent();
74 sblog << "} ";
75 if (!n.src.empty()) {
76 sblog << " results [";
77 dump_vec(n.src);
78 sblog << "] ";
79 }
80 dump_live_values(n, false);
81 }
82 }
83 return true;
84 }
85
visit(bb_node & n,bool enter)86 bool dump::visit(bb_node& n, bool enter) {
87 if (enter) {
88 indent();
89 dump_flags(n);
90 sblog << "{ BB_" << n.id << " loop_level = " << n.loop_level << " ";
91 dump_live_values(n, true);
92 ++level;
93 } else {
94 --level;
95 indent();
96 sblog << "} end BB_" << n.id << " ";
97 dump_live_values(n, false);
98 }
99 return true;
100 }
101
visit(alu_group_node & n,bool enter)102 bool dump::visit(alu_group_node& n, bool enter) {
103 if (enter) {
104 indent();
105 dump_flags(n);
106 sblog << "[ ";
107 dump_live_values(n, true);
108
109 ++level;
110 } else {
111 --level;
112
113 indent();
114 sblog << "] ";
115 dump_live_values(n, false);
116 }
117 return true;
118 }
119
visit(cf_node & n,bool enter)120 bool dump::visit(cf_node& n, bool enter) {
121 if (enter) {
122 indent();
123 dump_flags(n);
124 dump_op(n, n.bc.op_ptr->name);
125
126 if (n.bc.op_ptr->flags & CF_BRANCH) {
127 sblog << " @" << (n.bc.addr << 1);
128 }
129
130 dump_common(n);
131 sblog << "\n";
132
133 if (!n.empty()) {
134 indent();
135 sblog << "< ";
136 dump_live_values(n, true);
137 }
138
139 ++level;
140 } else {
141 --level;
142 if (!n.empty()) {
143 indent();
144 sblog << "> ";
145 dump_live_values(n, false);
146 }
147 }
148 return true;
149 }
150
visit(alu_node & n,bool enter)151 bool dump::visit(alu_node& n, bool enter) {
152 if (enter) {
153 indent();
154 dump_flags(n);
155 dump_alu(&n);
156 dump_common(n);
157 sblog << "\n";
158
159 ++level;
160 } else {
161 --level;
162
163 }
164 return true;
165 }
166
visit(alu_packed_node & n,bool enter)167 bool dump::visit(alu_packed_node& n, bool enter) {
168 if (enter) {
169 indent();
170 dump_flags(n);
171 dump_op(n, n.op_ptr()->name);
172 sblog << " ";
173 dump_live_values(n, true);
174
175 ++level;
176 } else {
177 --level;
178 if (!n.live_after.empty()) {
179 indent();
180 dump_live_values(n, false);
181 }
182
183 }
184 // proccess children only if their src/dst aren't moved to this node yet
185 return n.src.empty();
186 }
187
visit(fetch_node & n,bool enter)188 bool dump::visit(fetch_node& n, bool enter) {
189 if (enter) {
190 indent();
191 dump_flags(n);
192 dump_op(n, n.bc.op_ptr->name);
193 sblog << "\n";
194
195 ++level;
196 } else {
197 --level;
198 }
199 return true;
200 }
201
visit(region_node & n,bool enter)202 bool dump::visit(region_node& n, bool enter) {
203 if (enter) {
204 indent();
205 dump_flags(n);
206 sblog << "region #" << n.region_id << " ";
207 dump_common(n);
208
209 if (!n.vars_defined.empty()) {
210 sblog << "vars_defined: ";
211 dump_set(sh, n.vars_defined);
212 }
213
214 dump_live_values(n, true);
215
216 ++level;
217
218 if (n.loop_phi)
219 run_on(*n.loop_phi);
220 } else {
221 --level;
222
223 if (n.phi)
224 run_on(*n.phi);
225
226 indent();
227 dump_live_values(n, false);
228 }
229 return true;
230 }
231
visit(repeat_node & n,bool enter)232 bool dump::visit(repeat_node& n, bool enter) {
233 if (enter) {
234 indent();
235 dump_flags(n);
236 sblog << "repeat region #" << n.target->region_id;
237 sblog << (n.empty() ? " " : " after { ");
238 dump_common(n);
239 sblog << " ";
240 dump_live_values(n, true);
241
242 ++level;
243 } else {
244 --level;
245
246 if (!n.empty()) {
247 indent();
248 sblog << "} end_repeat ";
249 dump_live_values(n, false);
250 }
251 }
252 return true;
253 }
254
visit(depart_node & n,bool enter)255 bool dump::visit(depart_node& n, bool enter) {
256 if (enter) {
257 indent();
258 dump_flags(n);
259 sblog << "depart region #" << n.target->region_id;
260 sblog << (n.empty() ? " " : " after { ");
261 dump_common(n);
262 sblog << " ";
263 dump_live_values(n, true);
264
265 ++level;
266 } else {
267 --level;
268 if (!n.empty()) {
269 indent();
270 sblog << "} end_depart ";
271 dump_live_values(n, false);
272 }
273 }
274 return true;
275 }
276
visit(if_node & n,bool enter)277 bool dump::visit(if_node& n, bool enter) {
278 if (enter) {
279 indent();
280 dump_flags(n);
281 sblog << "if " << *n.cond << " ";
282 dump_common(n);
283 sblog << " ";
284 dump_live_values(n, true);
285
286 indent();
287 sblog <<"{\n";
288
289 ++level;
290 } else {
291 --level;
292 indent();
293 sblog << "} endif ";
294 dump_live_values(n, false);
295 }
296 return true;
297 }
298
indent()299 void dump::indent() {
300 sblog.print_wl("", level * 4);
301 }
302
dump_vec(const vvec & vv)303 void dump::dump_vec(const vvec & vv) {
304 bool first = true;
305 for(vvec::const_iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
306 value *v = *I;
307 if (!first)
308 sblog << ", ";
309 else
310 first = false;
311
312 if (v) {
313 sblog << *v;
314 } else {
315 sblog << "__";
316 }
317 }
318 }
319
dump_rels(vvec & vv)320 void dump::dump_rels(vvec & vv) {
321 for(vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
322 value *v = *I;
323
324 if (!v || !v->is_rel())
325 continue;
326
327 sblog << "\n\t\t\t\t\t";
328 sblog << " rels: " << *v << " : ";
329 dump_vec(v->mdef);
330 sblog << " <= ";
331 dump_vec(v->muse);
332 }
333 }
334
dump_op(node & n,const char * name)335 void dump::dump_op(node &n, const char *name) {
336
337 if (n.pred) {
338 alu_node &a = static_cast<alu_node&>(n);
339 sblog << (a.bc.pred_sel-2) << " [" << *a.pred << "] ";
340 }
341
342 sblog << name;
343
344 bool has_dst = !n.dst.empty();
345
346 if (n.subtype == NST_CF_INST) {
347 cf_node *c = static_cast<cf_node*>(&n);
348 if (c->bc.op_ptr->flags & CF_EXP) {
349 static const char *exp_type[] = {"PIXEL", "POS ", "PARAM"};
350 sblog << " " << exp_type[c->bc.type] << " " << c->bc.array_base;
351 has_dst = false;
352 } else if (c->bc.op_ptr->flags & (CF_MEM)) {
353 static const char *exp_type[] = {"WRITE", "WRITE_IND", "WRITE_ACK",
354 "WRITE_IND_ACK"};
355 sblog << " " << exp_type[c->bc.type] << " " << c->bc.array_base
356 << " ES:" << c->bc.elem_size;
357 if (!(c->bc.op_ptr->flags & CF_EMIT)) {
358 has_dst = false;
359 }
360 }
361 }
362
363 sblog << " ";
364
365 if (has_dst) {
366 dump_vec(n.dst);
367 sblog << ", ";
368 }
369
370 if (n.subtype == NST_FETCH_INST) {
371 fetch_node *f = static_cast<fetch_node*>(&n);
372 if (f->bc.indexed)
373 dump_vec(n.src);
374 } else
375 dump_vec(n.src);
376 }
377
dump_set(shader & sh,val_set & v)378 void dump::dump_set(shader &sh, val_set& v) {
379 sblog << "[";
380 for(val_set::iterator I = v.begin(sh), E = v.end(sh); I != E; ++I) {
381 value *val = *I;
382 sblog << *val << " ";
383 }
384 sblog << "]";
385 }
386
dump_common(node & n)387 void dump::dump_common(node& n) {
388 }
389
dump_flags(node & n)390 void dump::dump_flags(node &n) {
391 if (n.flags & NF_DEAD)
392 sblog << "### DEAD ";
393 if (n.flags & NF_REG_CONSTRAINT)
394 sblog << "R_CONS ";
395 if (n.flags & NF_CHAN_CONSTRAINT)
396 sblog << "CH_CONS ";
397 if (n.flags & NF_ALU_4SLOT)
398 sblog << "4S ";
399 if (n.flags & NF_ALU_2SLOT)
400 sblog << "2S ";
401 }
402
dump_val(value * v)403 void dump::dump_val(value* v) {
404 sblog << *v;
405 }
406
dump_alu(alu_node * n)407 void dump::dump_alu(alu_node *n) {
408
409 if (n->is_copy_mov())
410 sblog << "(copy) ";
411
412 if (n->pred) {
413 sblog << (n->bc.pred_sel-2) << " [" << *n->pred << "] ";
414 }
415
416 sblog << n->bc.op_ptr->name;
417
418 if (n->bc.omod) {
419 static const char *omod_str[] = {"", "*2", "*4", "/2"};
420 sblog << omod_str[n->bc.omod];
421 }
422
423 if (n->bc.clamp) {
424 sblog << "_sat";
425 }
426
427 bool has_dst = !n->dst.empty();
428
429 sblog << " ";
430
431 if (has_dst) {
432 dump_vec(n->dst);
433 sblog << ", ";
434 }
435
436 unsigned s = 0;
437 for (vvec::iterator I = n->src.begin(), E = n->src.end(); I != E;
438 ++I, ++s) {
439
440 bc_alu_src &src = n->bc.src[s];
441
442 if (src.neg)
443 sblog << "-";
444
445 if (src.abs)
446 sblog << "|";
447
448 dump_val(*I);
449
450 if (src.abs)
451 sblog << "|";
452
453 if (I + 1 != E)
454 sblog << ", ";
455 }
456
457 dump_rels(n->dst);
458 dump_rels(n->src);
459
460 }
461
dump_op(node * n)462 void dump::dump_op(node* n) {
463 if (n->type == NT_IF) {
464 dump_op(*n, "IF ");
465 return;
466 }
467
468 switch(n->subtype) {
469 case NST_ALU_INST:
470 dump_alu(static_cast<alu_node*>(n));
471 break;
472 case NST_FETCH_INST:
473 dump_op(*n, static_cast<fetch_node*>(n)->bc.op_ptr->name);
474 break;
475 case NST_CF_INST:
476 case NST_ALU_CLAUSE:
477 case NST_TEX_CLAUSE:
478 case NST_VTX_CLAUSE:
479 case NST_GDS_CLAUSE:
480 dump_op(*n, static_cast<cf_node*>(n)->bc.op_ptr->name);
481 break;
482 case NST_ALU_PACKED_INST:
483 dump_op(*n, static_cast<alu_packed_node*>(n)->op_ptr()->name);
484 break;
485 case NST_PHI:
486 dump_op(*n, "PHI");
487 break;
488 case NST_PSI:
489 dump_op(*n, "PSI");
490 break;
491 case NST_COPY:
492 dump_op(*n, "COPY");
493 break;
494 default:
495 dump_op(*n, "??unknown_op");
496 }
497 }
498
dump_op_list(container_node * c)499 void dump::dump_op_list(container_node* c) {
500 for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
501 dump_op(*I);
502 sblog << "\n";
503 }
504 }
505
dump_queue(sched_queue & q)506 void dump::dump_queue(sched_queue& q) {
507 for (sched_queue::iterator I = q.begin(), E = q.end(); I != E; ++I) {
508 dump_op(*I);
509 sblog << "\n";
510 }
511 }
512
dump_live_values(container_node & n,bool before)513 void dump::dump_live_values(container_node &n, bool before) {
514 if (before) {
515 if (!n.live_before.empty()) {
516 sblog << "live_before: ";
517 dump_set(sh, n.live_before);
518 }
519 } else {
520 if (!n.live_after.empty()) {
521 sblog << "live_after: ";
522 dump_set(sh, n.live_after);
523 }
524 }
525 sblog << "\n";
526 }
527
528 } // namespace r600_sb
529