summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZack Rusin <[email protected]>2013-04-09 03:28:48 -0700
committerZack Rusin <[email protected]>2013-04-10 12:31:22 -0700
commit7466e0b6c84ce0c6029e60739daac8baeccb8b0b (patch)
treeab55213bdf4ee938bca1ac94f0bc6cfe5bbed3c3
parent1ad4a4eeb3fe83ce3ce7336250d725bf0a28de7b (diff)
gallivm: fix unsigned divide and remainder opcodes
We want to both make sure we never divide by zero to not generate sigfpe and that divide by zero is guaranteed to return 0xffffffff. Based on José idea. Signed-off-by: Zack Rusin <[email protected]> Reviewed-by: Jose Fonseca <[email protected]> Reviewed-by: Roland Scheidegger <[email protected]>
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
index f3ae7b6b6d8..c71c1f111bd 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
@@ -1543,8 +1543,23 @@ udiv_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->uint_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);
+ /* udiv by zero is guaranteed to return 0xffffffff */
+ emit_data->output[emit_data->chan] = LLVMBuildOr(builder,
+ div_mask,
+ result, "");
}
/* TGSI_OPCODE_UMAX (CPU Only) */
@@ -1576,8 +1591,22 @@ umod_emit_cpu(
struct lp_build_tgsi_context * bld_base,
struct lp_build_emit_data * emit_data)
{
- emit_data->output[emit_data->chan] = lp_build_mod(&bld_base->uint_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_mod(&bld_base->uint_bld,
+ emit_data->args[0], divisor);
+ /* umod by zero is guaranteed to return 0xffffffff */
+ emit_data->output[emit_data->chan] = LLVMBuildOr(builder,
+ div_mask,
+ result, "");
}
/* TGSI_OPCODE_USET Helper (CPU Only) */