gallivm: added lp_build_set_sign()
authorBrian Paul <brianp@vmware.com>
Thu, 4 Mar 2010 16:45:34 +0000 (09:45 -0700)
committerBrian Paul <brianp@vmware.com>
Thu, 4 Mar 2010 17:53:26 +0000 (10:53 -0700)
src/gallium/auxiliary/gallivm/lp_bld_arit.c
src/gallium/auxiliary/gallivm/lp_bld_arit.h

index f60a7a213accc1aa88f965a02d1e7de076551108..42ae9f6a22c3c76dd7530e4cd1f67f9e838db248 100644 (file)
@@ -717,6 +717,41 @@ lp_build_sgn(struct lp_build_context *bld,
 }
 
 
+/**
+ * Set the sign of float vector 'a' according to 'sign'.
+ * If sign==0, return abs(a).
+ * If sign==1, return -abs(a);
+ * Other values for sign produce undefined results.
+ */
+LLVMValueRef
+lp_build_set_sign(struct lp_build_context *bld,
+                  LLVMValueRef a, LLVMValueRef sign)
+{
+   const struct lp_type type = bld->type;
+   LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
+   LLVMTypeRef vec_type = lp_build_vec_type(type);
+   LLVMValueRef shift = lp_build_int_const_scalar(type, type.width - 1);
+   LLVMValueRef mask = lp_build_int_const_scalar(type,
+                             ~((unsigned long long) 1 << (type.width - 1)));
+   LLVMValueRef val, res;
+
+   assert(type.floating);
+
+   /* val = reinterpret_cast<int>(a) */
+   val = LLVMBuildBitCast(bld->builder, a, int_vec_type, "");
+   /* val = val & mask */
+   val = LLVMBuildAnd(bld->builder, val, mask, "");
+   /* sign = sign << shift */
+   sign = LLVMBuildShl(bld->builder, sign, shift, "");
+   /* res = val | sign */
+   res = LLVMBuildOr(bld->builder, val, sign, "");
+   /* res = reinterpret_cast<float>(res) */
+   res = LLVMBuildBitCast(bld->builder, res, vec_type, "");
+
+   return res;
+}
+
+
 /**
  * Convert vector of int to vector of float.
  */
index 2d19ec06b4348d7f6d258bd22a58380347eb7836..866349d8cbae1bf5d421850a511b7909770b4ce5 100644 (file)
@@ -124,6 +124,10 @@ LLVMValueRef
 lp_build_sgn(struct lp_build_context *bld,
              LLVMValueRef a);
 
+LLVMValueRef
+lp_build_set_sign(struct lp_build_context *bld,
+                  LLVMValueRef a, LLVMValueRef sign);
+
 LLVMValueRef
 lp_build_int_to_float(struct lp_build_context *bld,
                       LLVMValueRef a);