aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/r600/sb/sb_psi_ops.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/r600/sb/sb_psi_ops.cpp')
-rw-r--r--src/gallium/drivers/r600/sb/sb_psi_ops.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/gallium/drivers/r600/sb/sb_psi_ops.cpp b/src/gallium/drivers/r600/sb/sb_psi_ops.cpp
new file mode 100644
index 00000000000..7d0a31e511a
--- /dev/null
+++ b/src/gallium/drivers/r600/sb/sb_psi_ops.cpp
@@ -0,0 +1,189 @@
+/*
+ * 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_shader.h"
+
+#include "sb_pass.h"
+
+namespace r600_sb {
+
+bool r600_sb::psi_ops::visit(alu_node& n, bool enter) {
+ if (enter) {
+ }
+ return false;
+}
+
+bool psi_ops::visit(node& n, bool enter) {
+ if (enter) {
+ assert(n.subtype == NST_PSI);
+
+ try_inline(n);
+
+ // TODO eliminate predication until there is full support in all passes
+ // unpredicate instructions and replace psi-nodes with conditional moves
+ eliminate(n);
+ }
+ return false;
+}
+
+value* get_pred_val(node &n) {
+ value *pred_val = NULL;
+
+ for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; I += 3) {
+ value* &pred = *I;
+ if (pred) {
+ if (!pred_val)
+ pred_val = pred;
+ else {
+ assert(pred == pred_val);
+ }
+ }
+ }
+ return pred_val;
+}
+
+// for now we'll never inline psi's with different predicate values,
+// so psi node may only contain the refs to one predicate value.
+bool psi_ops::try_inline(node& n) {
+ assert(n.subtype == NST_PSI);
+
+ vvec &ns = n.src;
+
+ int sz = ns.size();
+ assert(sz && (sz % 3 == 0));
+
+ value *pred_val = get_pred_val(n);
+
+ int ps_mask = 0;
+
+ bool r = false;
+
+ for (int i = sz - 1; i >= 0; i -= 3) {
+
+ if (ps_mask == 3) {
+ ns.erase(ns.begin(), ns.begin() + i + 1);
+ return r;
+ }
+
+ value* val = ns[i];
+ value* predsel = ns[i-1];
+ int ps = !predsel ? 3 : predsel == sh.get_pred_sel(0) ? 1 : 2;
+
+ assert(val->def);
+
+ if (val->def->subtype == NST_PSI && ps == 3) {
+ if (get_pred_val(*val->def) != pred_val)
+ continue;
+
+ vvec &ds = val->def->src;
+
+ ns.insert(ns.begin() + i + 1, ds.begin(), ds.end());
+ ns.erase(ns.begin() + i - 2, ns.begin() + i + 1);
+ i += ds.size();
+ r = true;
+
+ } else {
+ if ((ps_mask & ps) == ps) {
+ // this predicate select is subsumed by already handled ops
+ ns.erase(ns.begin() + i - 2, ns.begin() + i + 1);
+ } else {
+ ps_mask |= ps;
+ }
+ }
+ }
+ return r;
+}
+
+bool psi_ops::try_reduce(node& n) {
+ assert(n.subtype == NST_PSI);
+ assert(n.src.size() % 3 == 0);
+
+ // TODO
+
+ return false;
+}
+
+void psi_ops::unpredicate(node *n) {
+
+ if (!n->is_alu_inst())
+ return;
+
+ alu_node *a = static_cast<alu_node*>(n);
+ a->pred = NULL;
+}
+
+bool psi_ops::eliminate(node& n) {
+ assert(n.subtype == NST_PSI);
+ assert(n.src.size() == 6);
+
+ value *d = n.dst[0];
+
+ value *s1 = n.src[2];
+ value *s2 = n.src[5];
+
+ value *pred = n.src[3];
+
+ bool psel = n.src[4] == sh.get_pred_sel(0);
+
+ value *sel = get_select_value_for_em(sh, pred);
+
+ if (s1->is_undef()) {
+ if (s2->is_undef()) {
+
+ } else {
+ n.insert_after(sh.create_mov(d, s2));
+ }
+ } else if (s2->is_undef()) {
+ n.insert_after(sh.create_mov(d, s1));
+ } else {
+ alu_node *a = sh.create_alu();
+ a->bc.set_op(ALU_OP3_CNDE_INT);
+
+ a->dst.push_back(d);
+ a->src.push_back(sel);
+
+ if (psel) {
+ a->src.push_back(s1);
+ a->src.push_back(s2);
+ } else {
+ a->src.push_back(s2);
+ a->src.push_back(s1);
+ }
+
+ n.insert_after(a);
+ }
+
+ n.remove();
+
+ if (s1->is_any_gpr() && !s1->is_undef() && s1->def)
+ unpredicate(s1->def);
+ if (s2->is_any_gpr() && !s2->is_undef() && s2->def)
+ unpredicate(s2->def);
+
+ return false;
+}
+
+} // namespace r600_sb