ac/llvm: add option to clamp division by zero
Replace div(x) by min(div(x), FLT_MAX)) to avoid getting a NaN result when x is 0. A cheaper alternative would be to use legacy mult instructions but they're not exposed by LLVM. Cc: mesa-stable Reviewed-by: Marek Olšák <marek.olsak@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6259>
This commit is contained in:
@@ -713,6 +713,9 @@ static void visit_alu(struct ac_nir_context *ctx, const nir_alu_instr *instr)
|
|||||||
result = emit_intrin_1f_param(&ctx->ac, "llvm.amdgcn.rcp",
|
result = emit_intrin_1f_param(&ctx->ac, "llvm.amdgcn.rcp",
|
||||||
ac_to_float_type(&ctx->ac, def_type), src[0]);
|
ac_to_float_type(&ctx->ac, def_type), src[0]);
|
||||||
}
|
}
|
||||||
|
if (ctx->abi->clamp_div_by_zero)
|
||||||
|
result = ac_build_fmin(&ctx->ac, result,
|
||||||
|
LLVMConstReal(ac_to_float_type(&ctx->ac, def_type), FLT_MAX));
|
||||||
break;
|
break;
|
||||||
case nir_op_iand:
|
case nir_op_iand:
|
||||||
result = LLVMBuildAnd(ctx->ac.builder, src[0], src[1], "");
|
result = LLVMBuildAnd(ctx->ac.builder, src[0], src[1], "");
|
||||||
@@ -859,6 +862,9 @@ static void visit_alu(struct ac_nir_context *ctx, const nir_alu_instr *instr)
|
|||||||
case nir_op_frsq:
|
case nir_op_frsq:
|
||||||
result = emit_intrin_1f_param(&ctx->ac, "llvm.amdgcn.rsq",
|
result = emit_intrin_1f_param(&ctx->ac, "llvm.amdgcn.rsq",
|
||||||
ac_to_float_type(&ctx->ac, def_type), src[0]);
|
ac_to_float_type(&ctx->ac, def_type), src[0]);
|
||||||
|
if (ctx->abi->clamp_div_by_zero)
|
||||||
|
result = ac_build_fmin(&ctx->ac, result,
|
||||||
|
LLVMConstReal(ac_to_float_type(&ctx->ac, def_type), FLT_MAX));
|
||||||
break;
|
break;
|
||||||
case nir_op_frexp_exp:
|
case nir_op_frexp_exp:
|
||||||
src[0] = ac_to_float(&ctx->ac, src[0]);
|
src[0] = ac_to_float(&ctx->ac, src[0]);
|
||||||
@@ -900,7 +906,7 @@ static void visit_alu(struct ac_nir_context *ctx, const nir_alu_instr *instr)
|
|||||||
case nir_op_ffma:
|
case nir_op_ffma:
|
||||||
/* FMA is better on GFX10, because it has FMA units instead of MUL-ADD units. */
|
/* FMA is better on GFX10, because it has FMA units instead of MUL-ADD units. */
|
||||||
result = emit_intrin_3f_param(&ctx->ac, ctx->ac.chip_class >= GFX10 ? "llvm.fma" : "llvm.fmuladd",
|
result = emit_intrin_3f_param(&ctx->ac, ctx->ac.chip_class >= GFX10 ? "llvm.fma" : "llvm.fmuladd",
|
||||||
ac_to_float_type(&ctx->ac, def_type), src[0], src[1], src[2]);
|
ac_to_float_type(&ctx->ac, def_type), src[0], src[1], src[2]);
|
||||||
break;
|
break;
|
||||||
case nir_op_ldexp:
|
case nir_op_ldexp:
|
||||||
src[0] = ac_to_float(&ctx->ac, src[0]);
|
src[0] = ac_to_float(&ctx->ac, src[0]);
|
||||||
|
@@ -192,6 +192,9 @@ struct ac_shader_abi {
|
|||||||
|
|
||||||
/* Whether undef values must be converted to zero */
|
/* Whether undef values must be converted to zero */
|
||||||
bool convert_undef_to_zero;
|
bool convert_undef_to_zero;
|
||||||
|
|
||||||
|
/* Clamp div by 0 (so it won't produce NaN) */
|
||||||
|
bool clamp_div_by_zero;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* AC_SHADER_ABI_H */
|
#endif /* AC_SHADER_ABI_H */
|
||||||
|
Reference in New Issue
Block a user