Mesa (master): gallivm: handle -inf, inf and nan's in sin/cos instructions
Zack Rusin
zack at kemper.freedesktop.org
Fri Jul 19 20:34:23 UTC 2013
Module: Mesa
Branch: master
Commit: 192c68b85abb724079b98dde6cdd1edba2dbcb7c
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=192c68b85abb724079b98dde6cdd1edba2dbcb7c
Author: Zack Rusin <zackr at vmware.com>
Date: Wed Jul 17 16:55:52 2013 -0400
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 <zackr at vmware.com>
Reviewed-by: Jose Fonseca <jfonseca at vmware.com>
Reviewed-by: Roland Scheidegger <sroland at vmware.com>
---
src/gallium/auxiliary/gallivm/lp_bld_arit.c | 44 +++++++++++++++++++++++++++
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 b3b3c92..2ce287f 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 ac06a2c..6b9e0d1 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 */
More information about the mesa-commit
mailing list