Hi Vadim,

I've been looking with Glenn's help into a bug in sb for a couple of
weeks now triggered by a change in how GLSL generates switch
statements.

I understand you probably aren't too interested in r600g but I believe
I'm hitting a design level problem and I would like some advice.

So it appears that GLSL can create loops that don't repeat for switch
statements, and it appears SB wasn't ready to handle such a thing.

sb has the ->is_loop() and it just checks !repeats.empty(), so this
meant in the finalizer code we'd fall into the if statement which
would then assert.

I hacked/fixed (more hacked), this in 7b0067d23a6f64cf83c42e7f11b2cd4100c569fe
which attempts to detect single pass loops and handle things that way.

However this lead to stack depth calculations being incorrectly done,
so I moved the single loop detect into the is_loop check, (see
attached patch).

This fixes the rendering in some places, but lead to a regression in
tests/shaders/glsl-vs-continue-in-switch-in-do-while.shader_test
error at : PHI     t76||FP@R3.x,       t128||FP@R3.x, t115||FP@R3.x,
t102||FP@R3.x, t89||FP@R3.x : expected
                operand value t115||FP@R3.x, gpr contains t17||FP@R3.x
error at : PHI     t76||FP@R3.x,       t128||FP@R3.x, t115||FP@R3.x,
t102||FP@R3.x, t89||FP@R3.x : expected
                operand value t102||FP@R3.x, gpr contains t17||FP@R3.x

Now Glenn suspected this was due to the is_loop check in
sb_shader.cpp:create_bbs,
and changing that check to only detect repeating loops removes that issue,
but introduces stack sizing issues again, resulting in lockups/random rendering.

So I just want to ask had you considered single loops with an always
break in sb design,
and perhaps some idea where things are going so wrong with the
register alloc above.

I suspect I'll keep digging into this, but its getting to the edges of
the brain space/time I can find!

Dave.
From 170184b712d9596f761acdee2c7cff2a2792d937 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airl...@redhat.com>
Date: Wed, 3 Dec 2014 13:05:18 +1000
Subject: [PATCH] r600g/sb: detect empty once iterated loops

Since GLSL changed to using loops for switches,
we've hit a bug in sb with single execution loops,

I previously attempted to fix this by changing where
we detected loops, however this isn't good enough
as SB gets the stack sizing wrong.

Fix this by checking inside the is_loop for
single execution loops.

This should fix lockups on rv635 and misrenderings
on cayman since the first fix:
7b0067d23a6f64cf83c42e7f11b2cd4100c569fe
fix issues cause by GLSL switching to loops for switch

Signed-off-by: Dave Airlie <airl...@redhat.com>
---
 src/gallium/drivers/r600/sb/sb_bc_finalize.cpp | 22 +++++++------------
 src/gallium/drivers/r600/sb/sb_ir.cpp          | 30 ++++++++++++++++++++++++++
 src/gallium/drivers/r600/sb/sb_ir.h            |  3 +--
 3 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/src/gallium/drivers/r600/sb/sb_bc_finalize.cpp b/src/gallium/drivers/r600/sb/sb_bc_finalize.cpp
index 0fa0910..56189c9 100644
--- a/src/gallium/drivers/r600/sb/sb_bc_finalize.cpp
+++ b/src/gallium/drivers/r600/sb/sb_bc_finalize.cpp
@@ -46,19 +46,7 @@ int bc_finalizer::run() {
 	for (regions_vec::reverse_iterator I = rv.rbegin(), E = rv.rend(); I != E;
 			++I) {
 		region_node *r = *I;
-		bool is_if = false;
-		assert(r);
-
-		assert(r->first);
-		if (r->first->is_container()) {
-			container_node *repdep1 = static_cast<container_node*>(r->first);
-			assert(repdep1->is_depart() || repdep1->is_repeat());
-			if_node *n_if = static_cast<if_node*>(repdep1->first);
-			if (n_if && n_if->is_if())
-				is_if = true;
-		}
-
-		if (is_if)
+		if (!r->is_loop())
 			finalize_if(r);
 		else
 			finalize_loop(r);
@@ -121,7 +109,13 @@ void bc_finalizer::finalize_loop(region_node* r) {
 	cf_node *loop_end = sh.create_cf(CF_OP_LOOP_END);
 	bool has_instr = false;
 
-	if (!r->is_loop()) {
+	/*
+	 * if we have repeats then we have instructions,
+	 * if we have no repeats for a single loops,
+	 * check if there are any instructions in the depart
+	 * nodes.
+	 */
+	if (r->repeats.empty()) {
 		for (depart_vec::iterator I = r->departs.begin(), E = r->departs.end();
 		     I != E; ++I) {
 			depart_node *dep = *I;
diff --git a/src/gallium/drivers/r600/sb/sb_ir.cpp b/src/gallium/drivers/r600/sb/sb_ir.cpp
index 5226893..a4c4e83 100644
--- a/src/gallium/drivers/r600/sb/sb_ir.cpp
+++ b/src/gallium/drivers/r600/sb/sb_ir.cpp
@@ -485,6 +485,36 @@ void container_node::collect_stats(node_stats& s) {
 	}
 }
 
+bool region_node::is_loop() {
+
+	if (!repeats.empty())
+		return true;
+
+	/*
+	 * single pass loops have no repeats, however we need to detect
+	 * them as loops.
+	 */
+
+	/* if we have no first in the region then it can't be a loop. */
+	if (!first)
+		return false;
+
+	/*
+	 * if the first is a container, see if it has an if node,
+	 * if nodes aren't loops, if there is no if node,
+	 * then this is a single pass loops.
+	 */
+	if (first->is_container()) {
+		container_node *repdep1 = static_cast<container_node*>(first);
+		assert(repdep1->is_depart() || repdep1->is_repeat());
+		if_node *n_if = static_cast<if_node*>(repdep1->first);
+		if (!n_if || !n_if->is_if())
+			return true;
+	}
+	return false;
+}
+
+
 void region_node::expand_depart(depart_node *d) {
 	depart_vec::iterator I = departs.begin() + d->dep_id, E;
 	I = departs.erase(I);
diff --git a/src/gallium/drivers/r600/sb/sb_ir.h b/src/gallium/drivers/r600/sb/sb_ir.h
index 85c3d06..7d1db3f 100644
--- a/src/gallium/drivers/r600/sb/sb_ir.h
+++ b/src/gallium/drivers/r600/sb/sb_ir.h
@@ -1106,8 +1106,7 @@ public:
 	unsigned dep_count() { return departs.size(); }
 	unsigned rep_count() { return repeats.size() + 1; }
 
-	bool is_loop() { return !repeats.empty(); }
-
+	bool is_loop();
 	container_node* get_entry_code_location() {
 		node *p = first;
 		while (p && (p->is_depart() || p->is_repeat()))
-- 
1.9.3

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to