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