Home | History | Annotate | Download | only in sb
      1 /*
      2  * Copyright 2013 Vadim Girlin <vadimgirlin (at) 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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    299 void dump::indent() {
    300 	sblog.print_wl("", level * 4);
    301 }
    302 
    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 
    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 
    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 
    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 
    382 void dump::dump_common(node& n) {
    383 }
    384 
    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 
    396 void dump::dump_val(value* v) {
    397 	sblog << *v;
    398 }
    399 
    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 
    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 		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 
    491 void 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 
    498 void 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 
    505 void 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