diff options
Diffstat (limited to 'src/gallium/drivers/r600/sb/sb_ir.cpp')
-rw-r--r-- | src/gallium/drivers/r600/sb/sb_ir.cpp | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/src/gallium/drivers/r600/sb/sb_ir.cpp b/src/gallium/drivers/r600/sb/sb_ir.cpp new file mode 100644 index 00000000000..cbb32378f91 --- /dev/null +++ b/src/gallium/drivers/r600/sb/sb_ir.cpp @@ -0,0 +1,553 @@ +/* + * Copyright 2013 Vadim Girlin <[email protected]> + * + * 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_bc.h" +#include "sb_shader.h" +#include "sb_pass.h" + +namespace r600_sb { + +using std::cerr; + +bool node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } +bool container_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } +bool alu_group_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } +bool alu_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } +bool cf_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } +bool fetch_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } +bool region_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } + +bool repeat_node::accept(vpass& p, bool enter) { + return p.visit(*this, enter); +} + +bool depart_node::accept(vpass& p, bool enter) { + return p.visit(*this, enter); +} +bool if_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } +bool bb_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); } +bool alu_packed_node::accept(vpass& p, bool enter) { + return p.visit(*this, enter); +} + +void alu_packed_node::init_args() { + alu_node *p = static_cast<alu_node*>(first); + assert(p->is_valid()); + while (p) { + dst.insert(dst.end(), p->dst.begin(), p->dst.end()); + src.insert(src.end(), p->src.begin(), p->src.end()); + p = static_cast<alu_node*>(p->next); + } + + // if it's packed then it's always multislot, no need to check slot flags + bool repl = (op_ptr()->flags & AF_REPL); + value *replicated_value = NULL; + + for (vvec::iterator I = dst.begin(), E = dst.end(); I != E; ++I) { + value *v = *I; + if (v) { + if (repl) { + if (replicated_value) + v->assign_source(replicated_value); + else + replicated_value = v; + } + + v->def = this; + } + } +} + +void container_node::insert_node_before(node* s, node* n) { + if (s->prev) { + node *sp = s->prev; + sp->next = n; + n->prev = sp; + n->next = s; + s->prev = n; + } else { + n->next = s; + s->prev = n; + first = n; + } + n->parent = this; +} + +void container_node::insert_node_after(node* s, node* n) { + if (s->next) { + node *sn = s->next; + sn->prev = n; + n->next = sn; + n->prev = s; + s->next = n; + } else { + n->prev = s; + s->next = n; + last = n; + } + n->parent = this; +} + +void container_node::move(iterator b, iterator e) { + assert(b != e); + + container_node *source_container = b->parent; + node *l = source_container->cut(b, e); + + first = last = l; + first->parent = this; + + while (last->next) { + last = last->next; + last->parent = this; + } +} + +node* container_node::cut(iterator b, iterator e) { + assert(!*b || b->parent == this); + assert(!*e || e->parent == this); + assert(b != e); + + if (b->prev) { + b->prev->next = *e; + } else { + first = *e; + } + + if (*e) { + e->prev->next = NULL; + e->prev = b->prev; + } else { + last->next = NULL; + last = b->prev; + } + + b->prev = NULL; + + return *b; +} + +unsigned container_node::count() { + unsigned c = 0; + node *t = first; + while (t) { + t = t->next; + c++; + } + return c; +} + +void container_node::remove_node(node *n) { + if (n->prev) + n->prev->next = n->next; + else + first = n->next; + if (n->next) + n->next->prev = n->prev; + else + last = n->prev; + n->parent = NULL; +} + +void container_node::expand(container_node *n) { + if (!n->empty()) { + node *e0 = n->first; + node *e1 = n->last; + + e0->prev = n->prev; + if (e0->prev) { + e0->prev->next = e0; + } else { + first = e0; + } + + e1->next = n->next; + if (e1->next) + e1->next->prev = e1; + else + last = e1; + + do { + e0->parent = this; + e0 = e0->next; + } while (e0 != e1->next); + } else + remove_node(n); +} + +void container_node::push_back(node *n) { + if (last) { + last->next = n; + n->next = NULL; + n->prev = last; + last = n; + } else { + assert(!first); + first = last = n; + n->prev = n->next = NULL; + } + n->parent = this; +} +void container_node::push_front(node *n) { + if (first) { + first->prev = n; + n->prev = NULL; + n->next = first; + first = n; + } else { + assert(!last); + first = last = n; + n->prev = n->next = NULL; + } + n->parent = this; +} + +void node::insert_before(node* n) { + parent->insert_node_before(this, n); +} + +void node::insert_after(node* n) { + parent->insert_node_after(this, n); +} + +void node::replace_with(node* n) { + n->prev = prev; + n->next = next; + n->parent = parent; + if (prev) + prev->next = n; + if (next) + next->prev = n; + + if (parent->first == this) + parent->first = n; + + if (parent->last == this) + parent->last = n; + + parent = NULL; + next = prev = NULL; +} + +void container_node::expand() { + parent->expand(this); +} + +void node::remove() {parent->remove_node(this); +} + +value_hash node::hash_src() { + + value_hash h = 12345; + + for (int k = 0, e = src.size(); k < e; ++k) { + value *s = src[k]; + if (s) + h ^= (s->hash()); + } + + return h; +} + + +value_hash node::hash() { + + if (parent && parent->subtype == NST_LOOP_PHI_CONTAINER) + return 47451; + + return hash_src() ^ (subtype << 13) ^ (type << 3); +} + +void r600_sb::container_node::append_from(container_node* c) { + if (!c->first) + return; + + node *b = c->first; + + if (last) { + last->next = c->first; + last->next->prev = last; + } else { + first = c->first; + } + + last = c->last; + c->first = NULL; + c->last = NULL; + + while (b) { + b->parent = this; + b = b->next; + } +} + +bool node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); } +bool container_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); } +bool alu_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); } +bool alu_packed_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); } +bool fetch_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); } +bool cf_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); } + +unsigned alu_packed_node::get_slot_mask() { + unsigned mask = 0; + for (node_iterator I = begin(), E = end(); I != E; ++I) + mask |= 1 << static_cast<alu_node*>(*I)->bc.slot; + return mask; +} + +void alu_packed_node::update_packed_items(sb_context &ctx) { + + vvec::iterator SI(src.begin()), DI(dst.begin()); + + assert(first); + + alu_node *c = static_cast<alu_node*>(first); + unsigned flags = c->bc.op_ptr->flags; + unsigned slot_flags = c->bc.slot_flags; + + // fixup dst for instructions that replicate output + if (((flags & AF_REPL) && slot_flags == AF_4V) || + (ctx.is_cayman() && slot_flags == AF_S)) { + + value *swp[4] = {}; + + unsigned chan; + + for (vvec::iterator I2 = dst.begin(), E2 = dst.end(); + I2 != E2; ++I2) { + value *v = *I2; + if (v) { + chan = v->get_final_chan(); + assert(!swp[chan] || swp[chan] == v); + swp[chan] = v; + } + } + + chan = 0; + for (vvec::iterator I2 = dst.begin(), E2 = dst.end(); + I2 != E2; ++I2, ++chan) { + *I2 = swp[chan]; + } + } + + for (node_iterator I = begin(), E = end(); I != E; ++I) { + alu_node *n = static_cast<alu_node*>(*I); + assert(n); + + for (vvec::iterator I2 = n->src.begin(), E2 = n->src.end(); + I2 != E2; ++I2, ++SI) { + *I2 = *SI; + } + for (vvec::iterator I2 = n->dst.begin(), E2 = n->dst.end(); + I2 != E2; ++I2, ++DI) { + *I2 = *DI; + } + } +} + +bool node::is_cf_op(unsigned op) { + if (!is_cf_inst()) + return false; + cf_node *c = static_cast<cf_node*>(this); + return c->bc.op == op; +} + +bool node::is_alu_op(unsigned op) { + if (!is_alu_inst()) + return false; + alu_node *c = static_cast<alu_node*>(this); + return c->bc.op == op; +} + +bool node::is_fetch_op(unsigned op) { + if (!is_fetch_inst()) + return false; + fetch_node *c = static_cast<fetch_node*>(this); + return c->bc.op == op; +} + + + +bool node::is_mova() { + if (!is_alu_inst()) + return false; + alu_node *a = static_cast<alu_node*>(this); + return (a->bc.op_ptr->flags & AF_MOVA); +} + +bool node::is_pred_set() { + if (!is_alu_inst()) + return false; + alu_node *a = static_cast<alu_node*>(this); + return (a->bc.op_ptr->flags & AF_ANY_PRED); +} + +unsigned node::cf_op_flags() { + assert(is_cf_inst()); + cf_node *c = static_cast<cf_node*>(this); + return c->bc.op_ptr->flags; +} + +unsigned node::alu_op_flags() { + assert(is_alu_inst()); + alu_node *c = static_cast<alu_node*>(this); + return c->bc.op_ptr->flags; +} + +unsigned node::fetch_op_flags() { + assert(is_fetch_inst()); + fetch_node *c = static_cast<fetch_node*>(this); + return c->bc.op_ptr->flags; +} + +unsigned node::alu_op_slot_flags() { + assert(is_alu_inst()); + alu_node *c = static_cast<alu_node*>(this); + return c->bc.slot_flags; +} + +region_node* node::get_parent_region() { + node *p = this; + while ((p = p->parent)) + if (p->is_region()) + return static_cast<region_node*>(p); + return NULL; +} + +unsigned container_node::real_alu_count() { + unsigned c = 0; + node *t = first; + while (t) { + if (t->is_alu_inst()) + ++c; + else if (t->is_alu_packed()) + c += static_cast<container_node*>(t)->count(); + t = t->next; + } + return c; +} + +void container_node::collect_stats(node_stats& s) { + + for (node_iterator I = begin(), E = end(); I != E; ++I) { + node *n = *I; + if (n->is_container()) { + static_cast<container_node*>(n)->collect_stats(s); + } + + if (n->is_alu_inst()) { + ++s.alu_count; + alu_node *a = static_cast<alu_node*>(n); + if (a->bc.op_ptr->flags & AF_KILL) + ++s.alu_kill_count; + else if (a->is_copy_mov()) + ++s.alu_copy_mov_count; + } else if (n->is_fetch_inst()) + ++s.fetch_count; + else if (n->is_cf_inst()) + ++s.cf_count; + else if (n->is_region()) { + ++s.region_count; + region_node *r = static_cast<region_node*>(n); + if(r->is_loop()) + ++s.loop_count; + + if (r->phi) + s.phi_count += r->phi->count(); + if (r->loop_phi) + s.loop_phi_count += r->loop_phi->count(); + } + else if (n->is_depart()) + ++s.depart_count; + else if (n->is_repeat()) + ++s.repeat_count; + else if (n->is_if()) + ++s.if_count; + } +} + +void region_node::expand_depart(depart_node *d) { + depart_vec::iterator I = departs.begin() + d->dep_id, E; + I = departs.erase(I); + E = departs.end(); + while (I != E) { + --(*I)->dep_id; + ++I; + } + d->expand(); +} + +void region_node::expand_repeat(repeat_node *r) { + repeat_vec::iterator I = repeats.begin() + r->rep_id - 1, E; + I = repeats.erase(I); + E = repeats.end(); + while (I != E) { + --(*I)->rep_id; + ++I; + } + r->expand(); +} + +void node_stats::dump() { + cerr << " alu_count : " << alu_count << "\n"; + cerr << " alu_kill_count : " << alu_kill_count << "\n"; + cerr << " alu_copy_mov_count : " << alu_copy_mov_count << "\n"; + cerr << " cf_count : " << cf_count << "\n"; + cerr << " fetch_count : " << fetch_count << "\n"; + cerr << " region_count : " << region_count << "\n"; + cerr << " loop_count : " << loop_count << "\n"; + cerr << " phi_count : " << phi_count << "\n"; + cerr << " loop_phi_count : " << loop_phi_count << "\n"; + cerr << " depart_count : " << depart_count << "\n"; + cerr << " repeat_count : " << repeat_count << "\n"; + cerr << " if_count : " << if_count << "\n"; +} + +unsigned alu_node::interp_param() { + if (!(bc.op_ptr->flags & AF_INTERP)) + return 0; + unsigned param; + if (bc.op_ptr->src_count == 2) { + param = src[1]->select.sel(); + } else { + param = src[0]->select.sel(); + } + return param + 1; +} + +alu_group_node* alu_node::get_alu_group_node() { + node *p = parent; + if (p) { + if (p->subtype == NST_ALU_PACKED_INST) { + assert(p->parent && p->parent->subtype == NST_ALU_GROUP); + p = p->parent; + } + return static_cast<alu_group_node*>(p); + } + return NULL; +} + +} // namespace r600_sb |