aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/r600/sb/sb_ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/r600/sb/sb_ir.cpp')
-rw-r--r--src/gallium/drivers/r600/sb/sb_ir.cpp553
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