gallivm: Fast implementation of iround(log2(x))
authorJosé Fonseca <jfonseca@vmware.com>
Wed, 6 Oct 2010 16:44:05 +0000 (17:44 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Wed, 6 Oct 2010 17:46:59 +0000 (18:46 +0100)
Not tested yet, but should be correct.

src/gallium/auxiliary/gallivm/lp_bld_arit.c
src/gallium/auxiliary/gallivm/lp_bld_arit.h

index ff94f498acf7180776b88bd90666d12f21d71184..15b74410188d9a4701f221c77b5f30950c0beb51 100644 (file)
@@ -2330,3 +2330,38 @@ lp_build_fast_log2(struct lp_build_context *bld,
    /* floor(log2(x)) + frac(x) */
    return LLVMBuildFAdd(bld->builder, ipart, fpart, "");
 }
+
+
+/**
+ * Fast implementation of iround(log2(x)).
+ *
+ * Not an approximation -- it should give accurate results all the time.
+ */
+LLVMValueRef
+lp_build_ilog2(struct lp_build_context *bld,
+               LLVMValueRef x)
+{
+   const struct lp_type type = bld->type;
+   LLVMTypeRef int_vec_type = bld->int_vec_type;
+
+   unsigned mantissa = lp_mantissa(type);
+   LLVMValueRef sqrt2 = lp_build_const_vec(type, 1.4142135623730951);
+
+   LLVMValueRef ipart;
+
+   assert(lp_check_value(bld->type, x));
+
+   assert(type.floating);
+
+   /* x * 2^(0.5)   i.e., add 0.5 to the log2(x) */
+   x = LLVMBuildFMul(bld->builder, x, sqrt2, "");
+
+   x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
+
+   /* ipart = floor(log2(x) + 0.5)  */
+   ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
+   ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), "");
+   ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 127), "");
+
+   return ipart;
+}
index 3ed4fec2333a99ee097b9e8c26ccd87250a3f1b1..f36197479f0f573da504c93eb6e0c895b57a0a9b 100644 (file)
@@ -216,6 +216,10 @@ LLVMValueRef
 lp_build_fast_log2(struct lp_build_context *bld,
                    LLVMValueRef a);
 
+LLVMValueRef
+lp_build_ilog2(struct lp_build_context *bld,
+               LLVMValueRef x);
+
 
 void
 lp_build_exp2_approx(struct lp_build_context *bld,