diff options
author | Zack Rusin <[email protected]> | 2013-07-17 16:55:52 -0400 |
---|---|---|
committer | Zack Rusin <[email protected]> | 2013-07-19 16:29:17 -0400 |
commit | 192c68b85abb724079b98dde6cdd1edba2dbcb7c (patch) | |
tree | 10a8ec45cd66f6f14863ed64645b37809ef3a60b | |
parent | 13e2cd2f2ccb06cd6dc9acda0b6bbe268ee37879 (diff) |
gallivm: handle -inf, inf and nan's in sin/cos instructions
sin/cos for anything not finite is nan and everything else has
to be between [-1, 1].
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_arit.c | 44 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_arit.h | 5 |
2 files changed, 49 insertions, 0 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.c b/src/gallium/auxiliary/gallivm/lp_bld_arit.c index b3b3c925808..2ce287f938a 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_arit.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.c @@ -2803,6 +2803,15 @@ lp_build_sin(struct lp_build_context *bld, */ LLVMValueRef y_sign = LLVMBuildXor(b, y_combine, sign_bit_1, "y_sin"); LLVMValueRef y_result = LLVMBuildBitCast(b, y_sign, bld->vec_type, "y_result"); + LLVMValueRef isfinite = lp_build_isfinite(bld, a); + + /* clamp output to be within [-1, 1] */ + y_result = lp_build_clamp(bld, y_result, + lp_build_const_vec(bld->gallivm, bld->type, -1.f), + lp_build_const_vec(bld->gallivm, bld->type, 1.f)); + /* If a is -inf, inf or NaN then return NaN */ + y_result = lp_build_select(bld, isfinite, y_result, + lp_build_const_vec(bld->gallivm, bld->type, NAN)); return y_result; } @@ -3020,6 +3029,15 @@ lp_build_cos(struct lp_build_context *bld, */ LLVMValueRef y_sign = LLVMBuildXor(b, y_combine, sign_bit, "y_sin"); LLVMValueRef y_result = LLVMBuildBitCast(b, y_sign, bld->vec_type, "y_result"); + LLVMValueRef isfinite = lp_build_isfinite(bld, a); + + /* clamp output to be within [-1, 1] */ + y_result = lp_build_clamp(bld, y_result, + lp_build_const_vec(bld->gallivm, bld->type, -1.f), + lp_build_const_vec(bld->gallivm, bld->type, 1.f)); + /* If a is -inf, inf or NaN then return NaN */ + y_result = lp_build_select(bld, isfinite, y_result, + lp_build_const_vec(bld->gallivm, bld->type, NAN)); return y_result; } @@ -3610,3 +3628,29 @@ lp_build_isnan(struct lp_build_context *bld, mask = LLVMBuildSExt(bld->gallivm->builder, mask, int_vec_type, "isnan"); return mask; } + +/* Returns all 1's for floating point numbers that are + * finite numbers and returns all zeros for -inf, + * inf and nan's */ +LLVMValueRef +lp_build_isfinite(struct lp_build_context *bld, + LLVMValueRef x) +{ + LLVMBuilderRef builder = bld->gallivm->builder; + LLVMTypeRef int_vec_type = lp_build_int_vec_type(bld->gallivm, bld->type); + struct lp_type int_type = lp_int_type(bld->type); + LLVMValueRef intx = LLVMBuildBitCast(builder, x, int_vec_type, ""); + LLVMValueRef infornan32 = lp_build_const_int_vec(bld->gallivm, bld->type, + 0x7f800000); + + if (!bld->type.floating) { + return lp_build_const_int_vec(bld->gallivm, bld->type, 0); + } + assert(bld->type.floating); + assert(lp_check_value(bld->type, x)); + assert(bld->type.width == 32); + + intx = LLVMBuildAnd(builder, intx, infornan32, ""); + return lp_build_compare(bld->gallivm, int_type, PIPE_FUNC_NOTEQUAL, + intx, infornan32); +} diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.h b/src/gallium/auxiliary/gallivm/lp_bld_arit.h index ac06a2c0971..6b9e0d1caf6 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_arit.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.h @@ -344,4 +344,9 @@ LLVMValueRef lp_build_isnan(struct lp_build_context *bld, LLVMValueRef x); +LLVMValueRef +lp_build_isfinite(struct lp_build_context *bld, + LLVMValueRef x); + + #endif /* !LP_BLD_ARIT_H */ |