summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland Scheidegger <sroland@vmware.com>2013-03-16 02:55:43 +0100
committerAndreas Boll <andreas.boll.dev@gmail.com>2013-04-17 12:56:19 +0200
commit6b5662696645e71c64eba21511c7899de7af6bb1 (patch)
treed1c35654303466c7e32700baa4f5eccda01a322a
parent31ebe4004cacb34c738bf6954f50fff6c637411b (diff)
gallivm: fix return opcode handling in main function of a shader
If we're in some conditional or loop we must not return, or the code after the condition is never executed. (v2): And, we also can't just continue as nothing happened, since the mask update code would later check if we actually have a mask, so we need to remember that there was a return in main where we didn't exit (to illustrate this, a ret in a if clause would cause a mask update which is still ok as we're in a conditional, but after the endif the mask update code would drop the mask hence bringing execution back to pixels which should have their execution mask set to zero by the ret). Thanks to Christoph Bumiller for figuring this out. This fixes https://bugs.freedesktop.org/show_bug.cgi?id=62357. Note: This is a candidate for the stable branches. Reviewed-by: Jose Fonseca <jfonseca@vmware.com> (cherry picked from commit 5af7b45986d1b56c568ebe9c3a40d48853e2e9ff)
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi.h1
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c20
2 files changed, 18 insertions, 3 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
index e292420a61..22ff7ead3e 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
@@ -238,6 +238,7 @@ struct lp_exec_mask {
struct lp_build_context *bld;
boolean has_mask;
+ boolean ret_in_main;
LLVMTypeRef int_vec_type;
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
index 85a4401b53..d12b785e96 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
@@ -72,6 +72,7 @@ static void lp_exec_mask_init(struct lp_exec_mask *mask, struct lp_build_context
mask->bld = bld;
mask->has_mask = FALSE;
+ mask->ret_in_main = FALSE;
mask->cond_stack_size = 0;
mask->loop_stack_size = 0;
mask->call_stack_size = 0;
@@ -107,7 +108,7 @@ static void lp_exec_mask_update(struct lp_exec_mask *mask)
} else
mask->exec_mask = mask->cond_mask;
- if (mask->call_stack_size) {
+ if (mask->call_stack_size || mask->ret_in_main) {
mask->exec_mask = LLVMBuildAnd(builder,
mask->exec_mask,
mask->ret_mask,
@@ -116,7 +117,8 @@ static void lp_exec_mask_update(struct lp_exec_mask *mask)
mask->has_mask = (mask->cond_stack_size > 0 ||
mask->loop_stack_size > 0 ||
- mask->call_stack_size > 0);
+ mask->call_stack_size > 0 ||
+ mask->ret_in_main);
}
static void lp_exec_mask_cond_push(struct lp_exec_mask *mask,
@@ -347,11 +349,23 @@ static void lp_exec_mask_ret(struct lp_exec_mask *mask, int *pc)
LLVMBuilderRef builder = mask->bld->gallivm->builder;
LLVMValueRef exec_mask;
- if (mask->call_stack_size == 0) {
+ if (mask->cond_stack_size == 0 &&
+ mask->loop_stack_size == 0 &&
+ mask->call_stack_size == 0) {
/* returning from main() */
*pc = -1;
return;
}
+
+ if (mask->call_stack_size == 0) {
+ /*
+ * This requires special handling since we need to ensure
+ * we don't drop the mask even if we have no call stack
+ * (e.g. after a ret in a if clause after the endif)
+ */
+ mask->ret_in_main = TRUE;
+ }
+
exec_mask = LLVMBuildNot(builder,
mask->exec_mask,
"ret");