summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrconde <[email protected]>2014-09-17 18:30:23 +0200
committerEmil Velikov <[email protected]>2014-09-23 00:52:51 +0100
commit04a9d7d44a48afb8f81f16d325ea5f00201a053b (patch)
tree429f442a85da5a377e8aea42fb9264f8faef76b7
parentd4289fc37b6c2224e98a6032f0b93c134559de0d (diff)
gallivm,tgsi: fix idiv by zero crash
While the result of signed integer division by zero is undefined by glsl (and doesn't exist with d3d10), we must not crash, so need to make sure we don't get sigfpe much like udiv already does. Unlike udiv where we return 0xffffffff (as required by d3d10) there is no requirement right now to return anything specific so we use zero. (cherry picked from commit ffeb77c7b0552a8624e46e65d6347240ac5ae84d) Nominated-by: Roland Scheidegger <[email protected]> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=83570
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c24
-rw-r--r--src/gallium/auxiliary/tgsi/tgsi_exec.c8
2 files changed, 25 insertions, 7 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
index b9546dbc661..4a9bc1f0ebe 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
@@ -1248,8 +1248,26 @@ idiv_emit_cpu(
struct lp_build_tgsi_context * bld_base,
struct lp_build_emit_data * emit_data)
{
- emit_data->output[emit_data->chan] = lp_build_div(&bld_base->int_bld,
- emit_data->args[0], emit_data->args[1]);
+ LLVMBuilderRef builder = bld_base->base.gallivm->builder;
+ LLVMValueRef div_mask = lp_build_cmp(&bld_base->uint_bld,
+ PIPE_FUNC_EQUAL, emit_data->args[1],
+ bld_base->uint_bld.zero);
+ /* We want to make sure that we never divide/mod by zero to not
+ * generate sigfpe. We don't want to crash just because the
+ * shader is doing something weird. */
+ LLVMValueRef divisor = LLVMBuildOr(builder,
+ div_mask,
+ emit_data->args[1], "");
+ LLVMValueRef result = lp_build_div(&bld_base->uint_bld,
+ emit_data->args[0], divisor);
+
+ LLVMValueRef not_div_mask = LLVMBuildNot(builder,
+ div_mask,"");
+
+ /* idiv by zero doesn't have a guaranteed return value chose 0 for now. */
+ emit_data->output[emit_data->chan] = LLVMBuildAnd(builder,
+ not_div_mask,
+ result, "");
}
/* TGSI_OPCODE_INEG (CPU Only) */
@@ -1683,7 +1701,7 @@ udiv_emit_cpu(
emit_data->args[1], "");
LLVMValueRef result = lp_build_div(&bld_base->uint_bld,
emit_data->args[0], divisor);
- /* udiv by zero is guaranteed to return 0xffffffff */
+ /* udiv by zero is guaranteed to return 0xffffffff at least with d3d10 */
emit_data->output[emit_data->chan] = LLVMBuildOr(builder,
div_mask,
result, "");
diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c
index d848348a03b..dc20b4e5bd5 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c
@@ -3340,10 +3340,10 @@ micro_idiv(union tgsi_exec_channel *dst,
const union tgsi_exec_channel *src0,
const union tgsi_exec_channel *src1)
{
- dst->i[0] = src0->i[0] / src1->i[0];
- dst->i[1] = src0->i[1] / src1->i[1];
- dst->i[2] = src0->i[2] / src1->i[2];
- dst->i[3] = src0->i[3] / src1->i[3];
+ dst->i[0] = src1->i[0] ? src0->i[0] / src1->i[0] : 0;
+ dst->i[1] = src1->i[1] ? src0->i[1] / src1->i[1] : 0;
+ dst->i[2] = src1->i[2] ? src0->i[2] / src1->i[2] : 0;
+ dst->i[3] = src1->i[3] ? src0->i[3] / src1->i[3] : 0;
}
static void