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