Mesa (gallium-llvmpipe): llvmpipe: Clamped float to unsigned norm via mantissa manipulation.

Jose Fonseca jrfonseca at kemper.freedesktop.org
Fri Aug 21 07:02:43 UTC 2009


Module: Mesa
Branch: gallium-llvmpipe
Commit: ce4cb74ee60c3a57cd0d0f635340c3ac15b7c4bd
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=ce4cb74ee60c3a57cd0d0f635340c3ac15b7c4bd

Author: José Fonseca <jfonseca at vmware.com>
Date:   Fri Aug 21 07:35:49 2009 +0100

llvmpipe: Clamped float to unsigned norm via mantissa manipulation.

---

 src/gallium/drivers/llvmpipe/lp_bld_conv.c |  119 ++++++++++++++++++++++++----
 src/gallium/drivers/llvmpipe/lp_bld_conv.h |    7 ++
 src/gallium/drivers/llvmpipe/lp_test.h     |    4 +
 3 files changed, 113 insertions(+), 17 deletions(-)

diff --git a/src/gallium/drivers/llvmpipe/lp_bld_conv.c b/src/gallium/drivers/llvmpipe/lp_bld_conv.c
index 10a8d61..520052c 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_conv.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_conv.c
@@ -46,6 +46,7 @@
 
 
 #include "util/u_debug.h"
+#include "util/u_math.h"
 
 #include "lp_bld_type.h"
 #include "lp_bld_const.h"
@@ -54,6 +55,79 @@
 #include "lp_bld_conv.h"
 
 
+LLVMValueRef
+lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
+                                        union lp_type src_type,
+                                        unsigned dst_width,
+                                        LLVMValueRef src)
+{
+   LLVMTypeRef int_vec_type = lp_build_int_vec_type(src_type);
+   LLVMValueRef res;
+   unsigned mantissa;
+   unsigned n;
+   unsigned long long ubound;
+   unsigned long long mask;
+   double scale;
+   double bias;
+
+   assert(src_type.floating);
+
+   switch(src_type.width) {
+   case 32:
+      mantissa = 23;
+      break;
+   case 64:
+      mantissa = 53;
+      break;
+   default:
+      assert(0);
+      return LLVMGetUndef(int_vec_type);
+   }
+
+   /* We cannot carry more bits than the mantissa */
+   n = MIN2(mantissa, dst_width);
+
+   /* This magic coefficients will make the desired result to appear in the
+    * lowest significant bits of the mantissa.
+    */
+   ubound = ((unsigned long long)1 << n);
+   mask = ubound - 1;
+   scale = (double)mask/ubound;
+   bias = (double)((unsigned long long)1 << (mantissa - n));
+
+   res = LLVMBuildMul(builder, src, lp_build_const_uni(src_type, scale), "");
+   res = LLVMBuildAdd(builder, res, lp_build_const_uni(src_type, bias), "");
+   res = LLVMBuildBitCast(builder, res, int_vec_type, "");
+
+   if(dst_width < src_type.width)
+      res = LLVMBuildAnd(builder, res, lp_build_int_const_uni(src_type, mask), "");
+
+   if(dst_width > n) {
+      int shift = dst_width - n;
+      res = LLVMBuildShl(builder, res, lp_build_int_const_uni(src_type, shift), "");
+
+      /* Fill in the empty lower bits for added precision? */
+#if 0
+      {
+         LLVMValueRef msb;
+         msb = LLVMBuildLShr(builder, res, lp_build_int_const_uni(src_type, dst_width - 1), "");
+         msb = LLVMBuildShl(builder, msb, lp_build_int_const_uni(src_type, shift), "");
+         msb = LLVMBuildSub(builder, msb, lp_build_int_const_uni(src_type, 1), "");
+         res = LLVMBuildOr(builder, res, msb, "");
+      }
+#elif 0
+      while(shift > 0) {
+         res = LLVMBuildOr(builder, res, LLVMBuildLShr(builder, res, lp_build_int_const_uni(src_type, n), ""), "");
+         shift -= n;
+         n *= 2;
+      }
+#endif
+   }
+
+   return res;
+}
+
+
 /**
  * Build shuffle vectors that match PUNPCKLxx and PUNPCKHxx instructions.
  */
@@ -259,28 +333,39 @@ lp_build_conv(LLVMBuilderRef builder,
       /* Nothing to do */
    }
    else if(tmp_type.floating) {
-      double dst_scale = lp_const_scale(dst_type);
-      LLVMTypeRef tmp_vec_type;
-
-      if (dst_scale != 1.0) {
-         LLVMValueRef scale = lp_build_const_uni(tmp_type, dst_scale);
-         for(i = 0; i < num_tmps; ++i)
-            tmp[i] = LLVMBuildMul(builder, tmp[i], scale, "");
+      if(!dst_type.fixed && !dst_type.sign && dst_type.norm) {
+         for(i = 0; i < num_tmps; ++i) {
+            tmp[i] = lp_build_clamped_float_to_unsigned_norm(builder,
+                                                             tmp_type,
+                                                             dst_type.width,
+                                                             tmp[i]);
+         }
+         tmp_type.floating = FALSE;
       }
+      else {
+         double dst_scale = lp_const_scale(dst_type);
+         LLVMTypeRef tmp_vec_type;
+
+         if (dst_scale != 1.0) {
+            LLVMValueRef scale = lp_build_const_uni(tmp_type, dst_scale);
+            for(i = 0; i < num_tmps; ++i)
+               tmp[i] = LLVMBuildMul(builder, tmp[i], scale, "");
+         }
 
-      /* Use an equally sized integer for intermediate computations */
-      tmp_type.floating = FALSE;
-      tmp_vec_type = lp_build_vec_type(tmp_type);
-      for(i = 0; i < num_tmps; ++i) {
+         /* Use an equally sized integer for intermediate computations */
+         tmp_type.floating = FALSE;
+         tmp_vec_type = lp_build_vec_type(tmp_type);
+         for(i = 0; i < num_tmps; ++i) {
 #if 0
-         if(dst_type.sign)
-            tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
-         else
-            tmp[i] = LLVMBuildFPToUI(builder, tmp[i], tmp_vec_type, "");
+            if(dst_type.sign)
+               tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
+            else
+               tmp[i] = LLVMBuildFPToUI(builder, tmp[i], tmp_vec_type, "");
 #else
-        /* FIXME: there is no SSE counterpart for LLVMBuildFPToUI */
-         tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
+           /* FIXME: there is no SSE counterpart for LLVMBuildFPToUI */
+            tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
 #endif
+         }
       }
    }
    else {
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_conv.h b/src/gallium/drivers/llvmpipe/lp_bld_conv.h
index 0ccd476..b1e3da7 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_conv.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld_conv.h
@@ -43,6 +43,13 @@
 union lp_type type;
 
 
+LLVMValueRef
+lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
+                                        union lp_type src_type,
+                                        unsigned dst_width,
+                                        LLVMValueRef src);
+
+
 void
 lp_build_conv(LLVMBuilderRef builder,
               union lp_type src_type,
diff --git a/src/gallium/drivers/llvmpipe/lp_test.h b/src/gallium/drivers/llvmpipe/lp_test.h
index c51399f..69aaae2 100644
--- a/src/gallium/drivers/llvmpipe/lp_test.h
+++ b/src/gallium/drivers/llvmpipe/lp_test.h
@@ -114,6 +114,10 @@ random_vec(union lp_type type, void *dst);
 
 
 boolean
+compare_vec_with_eps(union lp_type type, const void *res, const void *ref, double eps);
+
+
+boolean
 compare_vec(union lp_type type, const void *res, const void *ref);
 
 




More information about the mesa-commit mailing list