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 }
400
dump_val(value * v)401 void dump::dump_val(value* v) {
402 sblog << *v;
403 }
404
dump_alu(alu_node * n)405 void dump::dump_alu(alu_node *n) {
406
407 if (n->is_copy_mov())
408 sblog << "(copy) ";
409
410 if (n->pred) {
411 sblog << (n->bc.pred_sel-2) << " [" << *n->pred << "] ";
412 }
413
414 sblog << n->bc.op_ptr->name;
415
416 if (n->bc.omod) {
417 static const char *omod_str[] = {"", "*2", "*4", "/2"};
418 sblog << omod_str[n->bc.omod];
419 }
420
421 if (n->bc.clamp) {
422 sblog << "_sat";
423 }
424
425 bool has_dst = !n->dst.empty();
426
427 sblog << " ";
428
429 if (has_dst) {
430 dump_vec(n->dst);
431 sblog << ", ";
432 }
433
434 unsigned s = 0;
435 for (vvec::iterator I = n->src.begin(), E = n->src.end(); I != E;
436 ++I, ++s) {
437
438 bc_alu_src &src = n->bc.src[s];
439
440 if (src.neg)
441 sblog << "-";
442
443 if (src.abs)
444 sblog << "|";
445
446 dump_val(*I);
447
448 if (src.abs)
449 sblog << "|";
450
451 if (I + 1 != E)
452 sblog << ", ";
453 }
454
455 dump_rels(n->dst);
456 dump_rels(n->src);
457
458 }
459
dump_op(node * n)460 void dump::dump_op(node* n) {
461 if (n->type == NT_IF) {
462 dump_op(*n, "IF ");
463 return;
464 }
465
466 switch(n->subtype) {
467 case NST_ALU_INST:
468 dump_alu(static_cast<alu_node*>(n));
469 break;
470 case NST_FETCH_INST:
471 dump_op(*n, static_cast<fetch_node*>(n)->bc.op_ptr->name);
472 break;
473 case NST_CF_INST:
474 case NST_ALU_CLAUSE:
475 case NST_TEX_CLAUSE:
476 case NST_VTX_CLAUSE:
477 case NST_GDS_CLAUSE:
478 dump_op(*n, static_cast<cf_node*>(n)->bc.op_ptr->name);
479 break;
480 case NST_ALU_PACKED_INST:
481 dump_op(*n, static_cast<alu_packed_node*>(n)->op_ptr()->name);
482 break;
483 case NST_PHI:
484 dump_op(*n, "PHI");
485 break;
486 case NST_PSI:
487 dump_op(*n, "PSI");
488 break;
489 case NST_COPY:
490 dump_op(*n, "COPY");
491 break;
492 default:
493 dump_op(*n, "??unknown_op");
494 }
495 }
496
dump_op_list(container_node * c)497 void dump::dump_op_list(container_node* c) {
498 for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
499 dump_op(*I);
500 sblog << "\n";
501 }
502 }
503
dump_queue(sched_queue & q)504 void dump::dump_queue(sched_queue& q) {
505 for (sched_queue::iterator I = q.begin(), E = q.end(); I != E; ++I) {
506 dump_op(*I);
507 sblog << "\n";
508 }
509 }
510
dump_live_values(container_node & n,bool before)511 void dump::dump_live_values(container_node &n, bool before) {
512 if (before) {
513 if (!n.live_before.empty()) {
514 sblog << "live_before: ";
515 dump_set(sh, n.live_before);
516 }
517 } else {
518 if (!n.live_after.empty()) {
519 sblog << "live_after: ";
520 dump_set(sh, n.live_after);
521 }
522 }
523 sblog << "\n";
524 }
525
526 } // namespace r600_sb
527