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