llvmpipe: Introduce a custom typing system.
authorJosé Fonseca <jfonseca@vmware.com>
Sun, 2 Aug 2009 12:52:40 +0000 (13:52 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Sat, 29 Aug 2009 08:21:22 +0000 (09:21 +0100)
Straightforward representation of floating-point/fixed-point/integer,
normalized/scaled, signed/unsigned SIMD vector types.

src/gallium/drivers/llvmpipe/lp_bld.h
src/gallium/drivers/llvmpipe/lp_bld_arit.c
src/gallium/drivers/llvmpipe/lp_bld_arit.h
src/gallium/drivers/llvmpipe/lp_bld_blend.c
src/gallium/drivers/llvmpipe/lp_test_blend.c

index 86571374b6077ae3746a99138ffe5ca17c843902..e9d9c25a8002051a7166a9119d005f81df96c9dd 100644 (file)
@@ -46,6 +46,7 @@
 
 
 struct pipe_blend_state;
+union lp_type;
 
 
 /**
@@ -134,6 +135,7 @@ lp_build_logicop(LLVMBuilderRef builder,
 LLVMValueRef
 lp_build_blend(LLVMBuilderRef builder,
                const struct pipe_blend_state *blend,
+               union lp_type type,
                LLVMValueRef src,
                LLVMValueRef dst,
                LLVMValueRef const_,
index 7e5af284aabc84c6ab4f038c41b107704c3e033d..b5b4148ac2d153c2b49c998a54be545316c72a82 100644 (file)
 #include "lp_bld_arit.h"
 
 
+LLVMTypeRef
+lp_build_elem_type(union lp_type type)
+{
+   if (type.kind == LP_TYPE_FLOAT) {
+      assert(type.sign);
+      switch(type.width) {
+         case 32:
+         return LLVMFloatType();
+         break;
+      case 64:
+         return LLVMDoubleType();
+         break;
+      default:
+         assert(0);
+         return LLVMFloatType();
+      }
+   }
+   else {
+      return LLVMIntType(type.width);
+   }
+}
+
+
+LLVMTypeRef
+lp_build_vec_type(union lp_type type)
+{
+   LLVMTypeRef elem_type = lp_build_elem_type(type);
+   return LLVMVectorType(elem_type, type.length);
+}
+
+
+/**
+ * This function is a mirrot of lp_build_elem_type() above.
+ *
+ * XXX: I'm not sure if it wouldn't be easier/efficient to just recreate the
+ * type and check for identity.
+ */
+boolean
+lp_check_elem_type(union lp_type type, LLVMTypeRef elem_type) 
+{
+   LLVMTypeKind elem_kind = LLVMGetTypeKind(elem_type);
+
+   if (type.kind == LP_TYPE_FLOAT) {
+      switch(type.width) {
+      case 32:
+         if(elem_kind != LLVMFloatTypeKind)
+            return FALSE;
+         break;
+      case 64:
+         if(elem_kind != LLVMDoubleTypeKind)
+            return FALSE;
+         break;
+      default:
+         assert(0);
+         return FALSE;
+      }
+   }
+   else {
+      if(elem_kind != LLVMIntegerTypeKind)
+         return FALSE;
+
+      if(LLVMGetIntTypeWidth(elem_type) != type.width)
+         return FALSE;
+   }
+
+   return TRUE; 
+}
+
+
+boolean
+lp_check_vec_type(union lp_type type, LLVMTypeRef vec_type) 
+{
+   LLVMTypeRef elem_type;
+
+   if(LLVMGetTypeKind(vec_type) != LLVMVectorTypeKind)
+      return FALSE;
+
+   if(LLVMGetVectorSize(vec_type) != type.length)
+      return FALSE;
+
+   elem_type = LLVMGetElementType(vec_type);
+
+   return lp_check_elem_type(type, elem_type);
+}
+
+
 LLVMValueRef
-lp_build_const_aos(LLVMTypeRef type, 
+lp_build_const_aos(union lp_type type, 
                    double r, double g, double b, double a, 
                    const unsigned char *swizzle)
 {
    const unsigned char default_swizzle[4] = {0, 1, 2, 3};
    LLVMTypeRef elem_type;
-   unsigned num_elems;
-   unsigned elem_width;
-   LLVMValueRef elems[LP_MAX_VECTOR_SIZE];
-   double scale;
+   LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
    unsigned i;
 
-   num_elems = LLVMGetVectorSize(type);
-   assert(num_elems % 4 == 0);
-   assert(num_elems < LP_MAX_VECTOR_SIZE);
+   assert(type.length % 4 == 0);
+   assert(type.length < LP_MAX_VECTOR_LENGTH);
 
-   elem_type = LLVMGetElementType(type);
+   elem_type = lp_build_elem_type(type);
 
    if(swizzle == NULL)
       swizzle = default_swizzle;
 
-   switch(LLVMGetTypeKind(elem_type)) {
-   case LLVMFloatTypeKind:
-      for(i = 0; i < num_elems; i += 4) {
+   if(type.kind == LP_TYPE_FLOAT) {
+      for(i = 0; i < type.length; i += 4) {
          elems[i + swizzle[0]] = LLVMConstReal(elem_type, r);
          elems[i + swizzle[1]] = LLVMConstReal(elem_type, g);
          elems[i + swizzle[2]] = LLVMConstReal(elem_type, b);
          elems[i + swizzle[3]] = LLVMConstReal(elem_type, a);
       }
-      break;
-
-   case LLVMIntegerTypeKind:
-      elem_width = LLVMGetIntTypeWidth(elem_type);
-      assert(elem_width <= 32);
-      scale = (double)((1 << elem_width) - 1);
-      for(i = 0; i < num_elems; i += 4) {
-         elems[i + swizzle[0]] = LLVMConstInt(elem_type, r*scale + 0.5, 0);
-         elems[i + swizzle[1]] = LLVMConstInt(elem_type, g*scale + 0.5, 0);
-         elems[i + swizzle[2]] = LLVMConstInt(elem_type, b*scale + 0.5, 0);
-         elems[i + swizzle[3]] = LLVMConstInt(elem_type, a*scale + 0.5, 0);
+   }
+   else {
+      unsigned shift;
+      long long llscale;
+      double dscale;
+
+      if(type.kind == LP_TYPE_FIXED)
+         shift = type.width/2;
+      else if(type.norm)
+         shift = type.sign ? type.width - 1 : type.width;
+      else
+         shift = 0;
+
+      llscale = (long long)1 << shift;
+      dscale = (double)llscale;
+      assert((long long)dscale == llscale);
+
+      for(i = 0; i < type.length; i += 4) {
+         elems[i + swizzle[0]] = LLVMConstInt(elem_type, r*dscale + 0.5, 0);
+         elems[i + swizzle[1]] = LLVMConstInt(elem_type, g*dscale + 0.5, 0);
+         elems[i + swizzle[2]] = LLVMConstInt(elem_type, b*dscale + 0.5, 0);
+         elems[i + swizzle[3]] = LLVMConstInt(elem_type, a*dscale + 0.5, 0);
       }
-      break;
-
-   default:
-      assert(0);
-      return LLVMGetUndef(type);
    }
 
-   return LLVMConstVector(elems, num_elems);
+   return LLVMConstVector(elems, type.length);
 }
                
 
index 0d2636aed9bdc8acd6d4c56e81d1b42d5694992c..f9a61be51685010d323a8d403c17942aae3ab707 100644 (file)
  *
  **************************************************************************/
 
+/**
+ * @file
+ * Helper arithmetic functions.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ */
+
+
 #ifndef LP_BLD_ARIT_H
 #define LP_BLD_ARIT_H
 
 #include <llvm-c/Core.h>  
 
  
-#define LP_MAX_VECTOR_SIZE 16
+#define LP_MAX_VECTOR_LENGTH 16
+
+
+/*
+ * Types
+ */
+
+
+enum lp_type_kind {
+   LP_TYPE_INTEGER = 0,
+   LP_TYPE_FLOAT = 1,
+   LP_TYPE_FIXED = 2
+};
+
+
+/**
+ * The LLVM type system can't conveniently express all the things we care about
+ * on the types used for intermediate computations, such as signed vs unsigned,
+ * normalized values, or fixed point.
+ */
+union lp_type {
+   struct {
+      /** 
+       * Integer. floating-point, or fixed point as established by the
+       * lp_build_type_kind enum above.
+       */
+      unsigned kind:2;
+      
+      /** 
+       * Whether it can represent negative values or not.
+       *
+       * Floating point values 
+       */
+      unsigned sign:1;
+
+      /**
+       * Whether values are normalized to fit [0, 1] interval, or [-1, 1] interval for
+       * signed types.
+       *
+       * For integer types
+       *
+       * It makes no sense to use this with fixed point values.
+       */
+      unsigned norm:1;
+
+      /**
+       * Element width.
+       *
+       * For fixed point values, the fixed point is assumed to be at half the width.
+       */
+      unsigned width:14;
+
+      /** 
+       * Vector length.
+       *
+       * width*length should be a power of two greater or equal to height.
+       *
+       * Several functions can only cope with vectors of length up to
+       * LP_MAX_VECTOR_LENGTH, so you may need to increase that value if you
+       * want to represent bigger vectors.
+       */
+      unsigned length:14;
+   };
+   uint32_t value;
+};
+
+
+LLVMTypeRef
+lp_build_elem_type(union lp_type type);
+
+
+LLVMTypeRef
+lp_build_vec_type(union lp_type type);
+
+
+boolean
+lp_check_elem_type(union lp_type type, LLVMTypeRef elem_type);
+
+
+boolean
+lp_check_vec_type(union lp_type type, LLVMTypeRef vec_type);
 
 
 /*
  */
 
 LLVMValueRef
-lp_build_const_aos(LLVMTypeRef type, 
+lp_build_const_aos(union lp_type type, 
                    double r, double g, double b, double a, 
                    const unsigned char *swizzle);
 
index d708047202f76361ff6f4055ee612b21565ec0b2..48d1e0028aed473a4d71b7ed561be7133df7a286 100644 (file)
@@ -182,7 +182,7 @@ lp_build_blend_swizzle(struct lp_build_blend_values *values,
                        unsigned alpha_swizzle,
                        unsigned n)
 {
-   LLVMValueRef swizzles[LP_MAX_VECTOR_SIZE];
+   LLVMValueRef swizzles[LP_MAX_VECTOR_LENGTH];
    unsigned i, j;
 
    if(rgb == alpha) {
@@ -268,6 +268,7 @@ lp_build_blend_func(struct lp_build_blend_values *values,
 LLVMValueRef
 lp_build_blend(LLVMBuilderRef builder,
                const struct pipe_blend_state *blend,
+               union lp_type type,
                LLVMValueRef src,
                LLVMValueRef dst,
                LLVMValueRef const_,
@@ -276,19 +277,17 @@ lp_build_blend(LLVMBuilderRef builder,
    struct lp_build_blend_values values;
    LLVMValueRef src_term;
    LLVMValueRef dst_term;
-   LLVMTypeRef type;
-   unsigned n;
+   LLVMTypeRef vec_type;
 
-   type = LLVMTypeOf(src);
-   n = LLVMGetVectorSize(type);
+   vec_type = lp_build_vec_type(type);
 
    /*
     * Compute constants
     */
    memset(&values, 0, sizeof values);
    values.builder = builder;
-   values.undef = LLVMGetUndef(type);
-   values.zero = LLVMConstNull(type);
+   values.undef = LLVMGetUndef(vec_type);
+   values.zero = LLVMConstNull(vec_type);
    values.one = lp_build_const_aos(type, 1.0, 1.0, 1.0, 1.0, NULL);
 
    values.src = src;
@@ -299,8 +298,8 @@ lp_build_blend(LLVMBuilderRef builder,
     * combinations it is possible to reorder the operations and therefor saving
     * some instructions. */
 
-   src_term = lp_build_blend_factor(&values, src, blend->rgb_src_factor, blend->alpha_src_factor, alpha_swizzle, n);
-   dst_term = lp_build_blend_factor(&values, dst, blend->rgb_dst_factor, blend->alpha_dst_factor, alpha_swizzle, n);
+   src_term = lp_build_blend_factor(&values, src, blend->rgb_src_factor, blend->alpha_src_factor, alpha_swizzle, type.length);
+   dst_term = lp_build_blend_factor(&values, dst, blend->rgb_dst_factor, blend->alpha_dst_factor, alpha_swizzle, type.length);
 
    if(blend->rgb_func == blend->alpha_func) {
       return lp_build_blend_func(&values, blend->rgb_func, src_term, dst_term);
@@ -314,6 +313,6 @@ lp_build_blend(LLVMBuilderRef builder,
       rgb   = lp_build_blend_func(&values, blend->rgb_func,   src_term, dst_term);
       alpha = lp_build_blend_func(&values, blend->alpha_func, src_term, dst_term);
 
-      return lp_build_blend_swizzle(&values, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle, n);
+      return lp_build_blend_swizzle(&values, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle, type.length);
    }
 }
index 1621fa79abf09ed1bc0e41c44e8ce6c8b7e8e617..3becac1871703e1d5cb1e743cbbbecad98a71e43 100644 (file)
@@ -52,6 +52,7 @@
 #include "util/u_math.h"
 
 #include "lp_bld.h"
+#include "lp_bld_arit.h"
 
 
 unsigned verbose = 0;
@@ -64,6 +65,8 @@ static LLVMValueRef
 add_blend_test(LLVMModuleRef module,
                const struct pipe_blend_state *blend)
 {
+   union lp_type type;
+
    LLVMTypeRef args[4];
    LLVMValueRef func;
    LLVMValueRef src_ptr;
@@ -77,6 +80,13 @@ add_blend_test(LLVMModuleRef module,
    LLVMValueRef const_;
    LLVMValueRef res;
 
+   type.value = 0;
+   type.kind = LP_TYPE_FLOAT;
+   type.sign = TRUE;
+   type.norm = TRUE;
+   type.width = 32;
+   type.length = 4;
+
    args[0] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
    args[1] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
    args[2] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
@@ -96,7 +106,7 @@ add_blend_test(LLVMModuleRef module,
    dst = LLVMBuildLoad(builder, dst_ptr, "dst");
    const_ = LLVMBuildLoad(builder, const_ptr, "const");
 
-   res = lp_build_blend(builder, blend, src, dst, const_, 3);
+   res = lp_build_blend(builder, blend, type, src, dst, const_, 3);
 
    LLVMSetValueName(res, "res");