[Mesa-dev] [PATCH v2] r600/sb: Check whether optimizations would result in reladdr conflict

Gert Wollny gw.fossdev at gmail.com
Thu Feb 8 14:11:58 UTC 2018


v2: * Check whether the node src and dst registers are NULL before using 
      them.
    * fix a type in the commit message. 

Two cases are handled with this patch:

1. If copy propagation tries to eliminated a move from a relative
   array access then it could optimize

     MOV R1, ARRAY[RELADDR_1]
     MOV R2, ARRAY[RELADDR_2]
     OP2 R3, R1 R2

   into

     OP2 R3, ARRAY[RELADDR_1], ARRAY[RELADDR_2]

   which is forbidden, because there is only one address register available.

2. When MULADD(x,a,MUL(x,c)) is handled

      MUL TMP, R1, ARRAY[RELADDR_1]
      MULLADD R3, R1, ARRAY[RELADDR_2], TMP

   by folding this into

      ADD TMP, ARRAY[RELADDR_2], ARRAY[RELADDR_1]
      MUL R3, R1, TMP
   
   which is also forbidden.

Test for these cases and reject the optimization if a forbidden combination
of relative access would be created.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103142
Signed-off-by: Gert Wollny <gw.fossdev at gmail.com>
---
 src/gallium/drivers/r600/sb/sb_expr.cpp     | 17 ++++++++++----
 src/gallium/drivers/r600/sb/sb_ir.h         |  6 +++++
 src/gallium/drivers/r600/sb/sb_valtable.cpp | 36 +++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/src/gallium/drivers/r600/sb/sb_expr.cpp b/src/gallium/drivers/r600/sb/sb_expr.cpp
index 7d43ef1d1d..1df78da660 100644
--- a/src/gallium/drivers/r600/sb/sb_expr.cpp
+++ b/src/gallium/drivers/r600/sb/sb_expr.cpp
@@ -412,7 +412,8 @@ bool expr_handler::fold_alu_op1(alu_node& n) {
 				n.bc.op == ALU_OP1_MOVA_GPR_INT)
 				&& n.bc.clamp == 0 && n.bc.omod == 0
 				&& n.bc.src[0].abs == 0 && n.bc.src[0].neg == 0 &&
-				n.src.size() == 1 /* RIM/SIM can be appended as additional values */) {
+				n.src.size() == 1 /* RIM/SIM can be appended as additional values */
+				&& n.dst[0]->no_reladdr_conflict_with(v0)) {
 			assign_source(n.dst[0], v0);
 			return true;
 		}
@@ -1027,9 +1028,17 @@ bool expr_handler::fold_alu_op3(alu_node& n) {
 				es1 = 1;
 			}
 
-			if (es0 != -1) {
-				value *va0 = es0 == 0 ? v1 : v0;
-				value *va1 = es1 == 0 ? mv1 : mv0;
+			value *va0 = es0 == 0 ? v1 : v0;
+			value *va1 = es1 == 0 ? mv1 : mv0;
+
+			/* Don't fold if no equal multipliers were found.
+			 * Also don#t fold if the operands of the to be created ADD are both
+			 * relatively accessed with different AR values because that would
+			 * create impossible code.
+			 */
+			if (es0 != -1 &&
+			    (!va0->is_rel() || !va1->is_rel() ||
+			     (va0->rel == va1->rel))) {
 
 				alu_node *add = sh.create_alu();
 				add->bc.set_op(ALU_OP2_ADD);
diff --git a/src/gallium/drivers/r600/sb/sb_ir.h b/src/gallium/drivers/r600/sb/sb_ir.h
index bee947504e..74a15900d1 100644
--- a/src/gallium/drivers/r600/sb/sb_ir.h
+++ b/src/gallium/drivers/r600/sb/sb_ir.h
@@ -612,6 +612,12 @@ public:
 		}
 	}
 
+	/* Check whether copy-propagation of src into this would create an access
+	 * conflict with relative addressing, i.e. an operation that tries to access
+	 * array elements with different address register values.
+	 */
+	bool no_reladdr_conflict_with(value *src);
+
 	val_set interferences;
 	unsigned uid;
 };
diff --git a/src/gallium/drivers/r600/sb/sb_valtable.cpp b/src/gallium/drivers/r600/sb/sb_valtable.cpp
index 41cfbf0946..b4e276a02d 100644
--- a/src/gallium/drivers/r600/sb/sb_valtable.cpp
+++ b/src/gallium/drivers/r600/sb/sb_valtable.cpp
@@ -295,6 +295,42 @@ void value::delete_uses() {
 	uses.erase(uses.begin(), uses.end());
 }
 
+bool value::no_reladdr_conflict_with(value *src)
+{
+	/*  if the register is not relative, it can't create an relative access conflict */
+	if (!src->is_rel())
+		return true;
+
+	/* If the destination is AR then we accept the copy propagation, because the
+	 * scheduler actually re-creates the address loading operation and will
+	 * signal interference if there is an address register load and it will fail
+	 * because of this.
+	 */
+	if (gvalue()->is_AR())
+		return true;
+
+	/* For all nodes that use this value test whether the operation uses another
+	 * relative access with a different address value. If found, signal conflict.
+	 */
+	for (uselist::const_iterator N = uses.begin(); N != uses.end(); ++N) {
+		for (vvec::const_iterator V = (*N)->src.begin(); V != (*N)->src.end(); ++V) {
+			if (*V) {
+				value *v = (*V)->gvalue();
+				if (v != src && v->is_rel() && v->rel != src->rel)
+					return false;
+			}
+		}
+		for (vvec::const_iterator V = (*N)->dst.begin(); V != (*N)->dst.end(); ++V) {
+			if (*V) {
+				value *v = (*V)->gvalue();
+				if (v && v != src && v->is_rel() && (v->rel != src->rel))
+					return false;
+			}
+		}
+	}
+	return true;
+}
+
 void ra_constraint::update_values() {
 	for (vvec::iterator I = values.begin(), E = values.end(); I != E; ++I) {
 		assert(!(*I)->constraint);
-- 
2.13.6



More information about the mesa-dev mailing list