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
30namespace r600_sb {
31
32bool 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
56bool 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
86bool 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
102bool 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
120bool 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
151bool 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
167bool 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
188bool 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
202bool 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
232bool 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
255bool 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
277bool 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
299void dump::indent() {
300	sblog.print_wl("", level * 4);
301}
302
303void 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
320void 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
335void 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
373void 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
382void dump::dump_common(node& n) {
383}
384
385void 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
396void dump::dump_val(value* v) {
397	sblog << *v;
398}
399
400void 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
455void 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		dump_op(*n, static_cast<cf_node*>(n)->bc.op_ptr->name);
473		break;
474	case NST_ALU_PACKED_INST:
475		dump_op(*n, static_cast<alu_packed_node*>(n)->op_ptr()->name);
476		break;
477	case NST_PHI:
478		dump_op(*n, "PHI");
479		break;
480	case NST_PSI:
481		dump_op(*n, "PSI");
482		break;
483	case NST_COPY:
484		dump_op(*n, "COPY");
485		break;
486	default:
487		dump_op(*n, "??unknown_op");
488	}
489}
490
491void dump::dump_op_list(container_node* c) {
492	for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
493		dump_op(*I);
494		sblog << "\n";
495	}
496}
497
498void dump::dump_queue(sched_queue& q) {
499	for (sched_queue::iterator I = q.begin(), E = q.end(); I != E; ++I) {
500		dump_op(*I);
501		sblog << "\n";
502	}
503}
504
505void dump::dump_live_values(container_node &n, bool before) {
506	if (before) {
507		if (!n.live_before.empty()) {
508			sblog << "live_before: ";
509			dump_set(sh, n.live_before);
510		}
511	} else {
512		if (!n.live_after.empty()) {
513			sblog << "live_after: ";
514			dump_set(sh, n.live_after);
515		}
516	}
517	sblog << "\n";
518}
519
520} // namespace r600_sb
521