gallivm: handle -inf, inf and nan's in sin/cos instructions
authorZack Rusin <zackr@vmware.com>
Wed, 17 Jul 2013 20:55:52 +0000 (16:55 -0400)
committerZack Rusin <zackr@vmware.com>
Fri, 19 Jul 2013 20:29:17 +0000 (16:29 -0400)
sin/cos for anything not finite is nan and everything else has
to be between [-1, 1].

Signed-off-by: Zack Rusin <zackr@vmware.com>
Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
src/gallium/auxiliary/gallivm/lp_bld_arit.c
src/gallium/auxiliary/gallivm/lp_bld_arit.h

index b3b3c9258088dd694f81832aaccb366cf1956138..2ce287f938aac2b30193d724b3f1e48cd835a5d4 100644 (file)
@@ -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);
+}
index ac06a2c09719093ba2cfd0b10a9e5d51080ada4f..6b9e0d1caf65e2ecff519c14d3a222567408b0f1 100644 (file)
@@ -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 */