diff options
author | Zack Rusin <[email protected]> | 2013-04-09 03:28:48 -0700 |
---|---|---|
committer | Zack Rusin <[email protected]> | 2013-04-10 12:31:22 -0700 |
commit | 7466e0b6c84ce0c6029e60739daac8baeccb8b0b (patch) | |
tree | ab55213bdf4ee938bca1ac94f0bc6cfe5bbed3c3 | |
parent | 1ad4a4eeb3fe83ce3ce7336250d725bf0a28de7b (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.c | 37 |
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) */ |