diff options
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c | 24 | ||||
-rw-r--r-- | src/gallium/auxiliary/tgsi/tgsi_exec.c | 8 |
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 6dae3798a39..77948011ac7 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_exec.c +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c @@ -3343,10 +3343,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 |