/* * Copyright 2013 Vadim Girlin <vadimgirlin@gmail.com> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Vadim Girlin */ #include "sb_shader.h" #include "sb_pass.h" namespace r600_sb { bool dump::visit(node& n, bool enter) { if (enter) { indent(); dump_flags(n); switch (n.subtype) { case NST_PHI: dump_op(n, "* phi"); break; case NST_PSI: dump_op(n, "* psi"); break; case NST_COPY: dump_op(n, "* copy"); break; default: assert(!"invalid node subtype"); break; } sblog << "\n"; } return false; } bool dump::visit(container_node& n, bool enter) { if (enter) { if (!n.empty()) { indent(); dump_flags(n); sblog << "{ "; if (!n.dst.empty()) { sblog << " preloaded inputs ["; dump_vec(n.dst); sblog << "] "; } dump_live_values(n, true); } ++level; } else { --level; if (!n.empty()) { indent(); sblog << "} "; if (!n.src.empty()) { sblog << " results ["; dump_vec(n.src); sblog << "] "; } dump_live_values(n, false); } } return true; } bool dump::visit(bb_node& n, bool enter) { if (enter) { indent(); dump_flags(n); sblog << "{ BB_" << n.id << " loop_level = " << n.loop_level << " "; dump_live_values(n, true); ++level; } else { --level; indent(); sblog << "} end BB_" << n.id << " "; dump_live_values(n, false); } return true; } bool dump::visit(alu_group_node& n, bool enter) { if (enter) { indent(); dump_flags(n); sblog << "[ "; dump_live_values(n, true); ++level; } else { --level; indent(); sblog << "] "; dump_live_values(n, false); } return true; } bool dump::visit(cf_node& n, bool enter) { if (enter) { indent(); dump_flags(n); dump_op(n, n.bc.op_ptr->name); if (n.bc.op_ptr->flags & CF_BRANCH) { sblog << " @" << (n.bc.addr << 1); } dump_common(n); sblog << "\n"; if (!n.empty()) { indent(); sblog << "< "; dump_live_values(n, true); } ++level; } else { --level; if (!n.empty()) { indent(); sblog << "> "; dump_live_values(n, false); } } return true; } bool dump::visit(alu_node& n, bool enter) { if (enter) { indent(); dump_flags(n); dump_alu(&n); dump_common(n); sblog << "\n"; ++level; } else { --level; } return true; } bool dump::visit(alu_packed_node& n, bool enter) { if (enter) { indent(); dump_flags(n); dump_op(n, n.op_ptr()->name); sblog << " "; dump_live_values(n, true); ++level; } else { --level; if (!n.live_after.empty()) { indent(); dump_live_values(n, false); } } // proccess children only if their src/dst aren't moved to this node yet return n.src.empty(); } bool dump::visit(fetch_node& n, bool enter) { if (enter) { indent(); dump_flags(n); dump_op(n, n.bc.op_ptr->name); sblog << "\n"; ++level; } else { --level; } return true; } bool dump::visit(region_node& n, bool enter) { if (enter) { indent(); dump_flags(n); sblog << "region #" << n.region_id << " "; dump_common(n); if (!n.vars_defined.empty()) { sblog << "vars_defined: "; dump_set(sh, n.vars_defined); } dump_live_values(n, true); ++level; if (n.loop_phi) run_on(*n.loop_phi); } else { --level; if (n.phi) run_on(*n.phi); indent(); dump_live_values(n, false); } return true; } bool dump::visit(repeat_node& n, bool enter) { if (enter) { indent(); dump_flags(n); sblog << "repeat region #" << n.target->region_id; sblog << (n.empty() ? " " : " after { "); dump_common(n); sblog << " "; dump_live_values(n, true); ++level; } else { --level; if (!n.empty()) { indent(); sblog << "} end_repeat "; dump_live_values(n, false); } } return true; } bool dump::visit(depart_node& n, bool enter) { if (enter) { indent(); dump_flags(n); sblog << "depart region #" << n.target->region_id; sblog << (n.empty() ? " " : " after { "); dump_common(n); sblog << " "; dump_live_values(n, true); ++level; } else { --level; if (!n.empty()) { indent(); sblog << "} end_depart "; dump_live_values(n, false); } } return true; } bool dump::visit(if_node& n, bool enter) { if (enter) { indent(); dump_flags(n); sblog << "if " << *n.cond << " "; dump_common(n); sblog << " "; dump_live_values(n, true); indent(); sblog <<"{\n"; ++level; } else { --level; indent(); sblog << "} endif "; dump_live_values(n, false); } return true; } void dump::indent() { sblog.print_wl("", level * 4); } void dump::dump_vec(const vvec & vv) { bool first = true; for(vvec::const_iterator I = vv.begin(), E = vv.end(); I != E; ++I) { value *v = *I; if (!first) sblog << ", "; else first = false; if (v) { sblog << *v; } else { sblog << "__"; } } } void dump::dump_rels(vvec & vv) { for(vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) { value *v = *I; if (!v || !v->is_rel()) continue; sblog << "\n\t\t\t\t\t"; sblog << " rels: " << *v << " : "; dump_vec(v->mdef); sblog << " <= "; dump_vec(v->muse); } } void dump::dump_op(node &n, const char *name) { if (n.pred) { alu_node &a = static_cast<alu_node&>(n); sblog << (a.bc.pred_sel-2) << " [" << *a.pred << "] "; } sblog << name; bool has_dst = !n.dst.empty(); if (n.subtype == NST_CF_INST) { cf_node *c = static_cast<cf_node*>(&n); if (c->bc.op_ptr->flags & CF_EXP) { static const char *exp_type[] = {"PIXEL", "POS ", "PARAM"}; sblog << " " << exp_type[c->bc.type] << " " << c->bc.array_base; has_dst = false; } else if (c->bc.op_ptr->flags & (CF_MEM)) { static const char *exp_type[] = {"WRITE", "WRITE_IND", "WRITE_ACK", "WRITE_IND_ACK"}; sblog << " " << exp_type[c->bc.type] << " " << c->bc.array_base << " ES:" << c->bc.elem_size; if (!(c->bc.op_ptr->flags & CF_EMIT)) { has_dst = false; } } } sblog << " "; if (has_dst) { dump_vec(n.dst); sblog << ", "; } dump_vec(n.src); } void dump::dump_set(shader &sh, val_set& v) { sblog << "["; for(val_set::iterator I = v.begin(sh), E = v.end(sh); I != E; ++I) { value *val = *I; sblog << *val << " "; } sblog << "]"; } void dump::dump_common(node& n) { } void dump::dump_flags(node &n) { if (n.flags & NF_DEAD) sblog << "### DEAD "; if (n.flags & NF_REG_CONSTRAINT) sblog << "R_CONS "; if (n.flags & NF_CHAN_CONSTRAINT) sblog << "CH_CONS "; if (n.flags & NF_ALU_4SLOT) sblog << "4S "; } void dump::dump_val(value* v) { sblog << *v; } void dump::dump_alu(alu_node *n) { if (n->is_copy_mov()) sblog << "(copy) "; if (n->pred) { sblog << (n->bc.pred_sel-2) << " [" << *n->pred << "] "; } sblog << n->bc.op_ptr->name; if (n->bc.omod) { static const char *omod_str[] = {"", "*2", "*4", "/2"}; sblog << omod_str[n->bc.omod]; } if (n->bc.clamp) { sblog << "_sat"; } bool has_dst = !n->dst.empty(); sblog << " "; if (has_dst) { dump_vec(n->dst); sblog << ", "; } unsigned s = 0; for (vvec::iterator I = n->src.begin(), E = n->src.end(); I != E; ++I, ++s) { bc_alu_src &src = n->bc.src[s]; if (src.neg) sblog << "-"; if (src.abs) sblog << "|"; dump_val(*I); if (src.abs) sblog << "|"; if (I + 1 != E) sblog << ", "; } dump_rels(n->dst); dump_rels(n->src); } void dump::dump_op(node* n) { if (n->type == NT_IF) { dump_op(*n, "IF "); return; } switch(n->subtype) { case NST_ALU_INST: dump_alu(static_cast<alu_node*>(n)); break; case NST_FETCH_INST: dump_op(*n, static_cast<fetch_node*>(n)->bc.op_ptr->name); break; case NST_CF_INST: case NST_ALU_CLAUSE: case NST_TEX_CLAUSE: case NST_VTX_CLAUSE: case NST_GDS_CLAUSE: dump_op(*n, static_cast<cf_node*>(n)->bc.op_ptr->name); break; case NST_ALU_PACKED_INST: dump_op(*n, static_cast<alu_packed_node*>(n)->op_ptr()->name); break; case NST_PHI: dump_op(*n, "PHI"); break; case NST_PSI: dump_op(*n, "PSI"); break; case NST_COPY: dump_op(*n, "COPY"); break; default: dump_op(*n, "??unknown_op"); } } void dump::dump_op_list(container_node* c) { for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) { dump_op(*I); sblog << "\n"; } } void dump::dump_queue(sched_queue& q) { for (sched_queue::iterator I = q.begin(), E = q.end(); I != E; ++I) { dump_op(*I); sblog << "\n"; } } void dump::dump_live_values(container_node &n, bool before) { if (before) { if (!n.live_before.empty()) { sblog << "live_before: "; dump_set(sh, n.live_before); } } else { if (!n.live_after.empty()) { sblog << "live_after: "; dump_set(sh, n.live_after); } } sblog << "\n"; } } // namespace r600_sb