gallivm: Fix format manipulation for big-endian
authorAdhemerval Zanella <azanella@linux.vnet.ibm.com>
Thu, 22 Nov 2012 19:48:45 +0000 (13:48 -0600)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 29 Nov 2012 11:54:18 +0000 (11:54 +0000)
This patch fixes various format manipulation for big-endian
architectures.

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c
src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c
src/gallium/auxiliary/gallivm/lp_bld_gather.c
src/gallium/auxiliary/gallivm/lp_bld_swizzle.c

index 9591bcfb2c75c402f399aef320d33c780d125424..750d54524c6f95908deb0cf083d26ceadeabbdb9 100644 (file)
@@ -49,6 +49,7 @@
 #include "lp_bld_gather.h"
 #include "lp_bld_debug.h"
 #include "lp_bld_format.h"
+#include "lp_bld_intr.h"
 
 
 /**
@@ -171,6 +172,10 @@ lp_build_unpack_arith_rgba_aos(struct gallivm_state *gallivm,
     * matches floating point size */
    assert (LLVMTypeOf(packed) == LLVMInt32TypeInContext(gallivm->context));
 
+#ifdef PIPE_ARCH_BIG_ENDIAN
+   packed = lp_build_bswap(gallivm, packed, lp_type_uint(32));
+#endif
+
    /* Broadcast the packed value to all four channels
     * before: packed = BGRA
     * after: packed = {BGRA, BGRA, BGRA, BGRA}
@@ -396,6 +401,8 @@ lp_build_fetch_rgba_aos(struct gallivm_state *gallivm,
        format_desc->block.bits <= type.width * 4 &&
        util_is_power_of_two(format_desc->block.bits)) {
       LLVMValueRef packed;
+      LLVMTypeRef dst_vec_type = lp_build_vec_type(gallivm, type);
+      unsigned vec_len = type.width * type.length;
 
       /*
        * The format matches the type (apart of a swizzle) so no need for
@@ -406,11 +413,14 @@ lp_build_fetch_rgba_aos(struct gallivm_state *gallivm,
                                format_desc->block.bits, type.width*4,
                                base_ptr, offset);
 
-      assert(format_desc->block.bits <= type.width * type.length);
-
-      packed = LLVMBuildBitCast(gallivm->builder, packed,
-                                lp_build_vec_type(gallivm, type), "");
+      assert(format_desc->block.bits <= vec_len);
 
+      packed = LLVMBuildBitCast(gallivm->builder, packed, dst_vec_type, "");
+#ifdef PIPE_ARCH_BIG_ENDIAN
+      if (type.floating)
+         packed = lp_build_bswap_vec(gallivm, packed, type,
+                                    lp_type_float_vec(type.width, vec_len));
+#endif
       return lp_build_format_swizzle_aos(format_desc, &bld, packed);
    }
 
index 24fee640a8297e42486b2a27a9f06779fec59357..cf296173c3ee7999a05bf69e5aef0ba0c5e604f7 100644 (file)
 #include "lp_bld_type.h"
 #include "lp_bld_conv.h"
 #include "lp_bld_pack.h"
+#include "lp_bld_intr.h"
+#include "lp_bld_gather.h"
 
 #include "util/u_memory.h"
 #include "util/u_format.h"
 #include "pipe/p_state.h"
 
+
+#ifdef PIPE_ARCH_BIG_ENDIAN
+static LLVMValueRef
+lp_build_read_int_bswap(struct gallivm_state *gallivm,
+                        LLVMValueRef base_ptr,
+                        unsigned src_width,
+                        LLVMTypeRef src_type,
+                        unsigned i,
+                        LLVMTypeRef dst_type)
+{
+   LLVMBuilderRef builder = gallivm->builder;
+   LLVMValueRef index = lp_build_const_int32(gallivm, i);
+   LLVMValueRef ptr = LLVMBuildGEP(builder, base_ptr, &index, 1, "");
+   LLVMValueRef res = LLVMBuildLoad(builder, ptr, "");
+   res = lp_build_bswap(gallivm, res, lp_type_uint(src_width));
+   return LLVMBuildBitCast(builder, res, dst_type, "");
+}
+
+static LLVMValueRef
+lp_build_fetch_read_big_endian(struct gallivm_state *gallivm,
+                               struct lp_type src_type,
+                               LLVMValueRef base_ptr)
+{
+   LLVMBuilderRef builder = gallivm->builder;
+   unsigned src_width = src_type.width;
+   unsigned length = src_type.length;
+   LLVMTypeRef src_elem_type = LLVMIntTypeInContext(gallivm->context, src_width);
+   LLVMTypeRef dst_elem_type = lp_build_elem_type (gallivm, src_type);
+   LLVMTypeRef src_ptr_type = LLVMPointerType(src_elem_type, 0);
+   LLVMValueRef res;
+
+   base_ptr = LLVMBuildPointerCast(builder, base_ptr, src_ptr_type, "");
+   if (length == 1) {
+      /* Scalar */
+      res = lp_build_read_int_bswap(gallivm, base_ptr, src_width, src_elem_type,
+                                    0, dst_elem_type);
+   } else {
+      /* Vector */
+      LLVMTypeRef dst_vec_type = LLVMVectorType(dst_elem_type, length);
+      unsigned i;
+
+      res = LLVMGetUndef(dst_vec_type);
+      for (i = 0; i < length; ++i) {
+         LLVMValueRef index = lp_build_const_int32(gallivm, i);
+         LLVMValueRef elem = lp_build_read_int_bswap(gallivm, base_ptr, src_width,
+                                                     src_elem_type, i, dst_elem_type);
+         res = LLVMBuildInsertElement(builder, res, elem, index, "");
+      }
+   }
+
+   return res;
+}
+#endif
+
 /**
  * @brief lp_build_fetch_rgba_aos_array
  *
@@ -65,12 +121,14 @@ lp_build_fetch_rgba_aos_array(struct gallivm_state *gallivm,
    src_vec_type  = lp_build_vec_type(gallivm,  src_type);
 
    /* Read whole vector from memory, unaligned */
-   if (!res) {
-      ptr = LLVMBuildGEP(builder, base_ptr, &offset, 1, "");
-      ptr = LLVMBuildPointerCast(builder, ptr, LLVMPointerType(src_vec_type, 0), "");
-      res = LLVMBuildLoad(builder, ptr, "");
-      lp_set_load_alignment(res, src_type.width / 8);
-   }
+   ptr = LLVMBuildGEP(builder, base_ptr, &offset, 1, "");
+#ifdef PIPE_ARCH_BIG_ENDIAN
+   res = lp_build_fetch_read_big_endian(gallivm, src_type, ptr);
+#else
+   ptr = LLVMBuildPointerCast(builder, ptr, LLVMPointerType(src_vec_type, 0), "");
+   res = LLVMBuildLoad(builder, ptr, "");
+   lp_set_load_alignment(res, src_type.width / 8);
+#endif
 
    /* Truncate doubles to float */
    if (src_type.floating && src_type.width == 64) {
index f77eb1212b1462f9543510cfee3ca185c298cbce..e542abce0ccbac45b69e709f1f952d3307b3f75f 100644 (file)
@@ -72,9 +72,15 @@ uyvy_to_yuv_soa(struct gallivm_state *gallivm,
    assert(lp_check_value(type, i));
 
    /*
+    * Little endian:
     * y = (uyvy >> (16*i + 8)) & 0xff
     * u = (uyvy        ) & 0xff
     * v = (uyvy >> 16  ) & 0xff
+    *
+    * Big endian:
+    * y = (uyvy >> (-16*i + 16)) & 0xff
+    * u = (uyvy >> 24) & 0xff
+    * v = (uyvy >>  8) & 0xff
     */
 
 #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
@@ -98,13 +104,23 @@ uyvy_to_yuv_soa(struct gallivm_state *gallivm,
 #endif
    {
       LLVMValueRef shift;
+#ifdef PIPE_ARCH_LITTLE_ENDIAN
       shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, 16), "");
       shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(gallivm, type, 8), "");
+#else
+      shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, -16), "");
+      shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(gallivm, type, 16), "");
+#endif
       *y = LLVMBuildLShr(builder, packed, shift, "");
    }
 
+#ifdef PIPE_ARCH_LITTLE_ENDIAN
    *u = packed;
    *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 16), "");
+#else
+   *u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 24), "");
+   *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 8), "");
+#endif
 
    mask = lp_build_const_int_vec(gallivm, type, 0xff);
 
@@ -140,9 +156,15 @@ yuyv_to_yuv_soa(struct gallivm_state *gallivm,
    assert(lp_check_value(type, i));
 
    /*
+   * Little endian:
     * y = (yuyv >> 16*i) & 0xff
     * u = (yuyv >> 8   ) & 0xff
     * v = (yuyv >> 24  ) & 0xff
+    *
+    * Big endian:
+    * y = (yuyv >> (-16*i + 24) & 0xff
+    * u = (yuyv >> 16)          & 0xff
+    * v = (yuyv)                & 0xff
     */
 
 #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
@@ -165,12 +187,22 @@ yuyv_to_yuv_soa(struct gallivm_state *gallivm,
 #endif
    {
       LLVMValueRef shift;
+#ifdef PIPE_ARCH_LITTLE_ENDIAN
       shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, 16), "");
+#else
+      shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, -16), "");
+      shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(gallivm, type, 24), "");
+#endif
       *y = LLVMBuildLShr(builder, packed, shift, "");
    }
 
+#ifdef PIPE_ARCH_LITTLE_ENDIAN
    *u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 8), "");
    *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 24), "");
+#else
+   *u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 16), "");
+   *v = packed;
+#endif
 
    mask = lp_build_const_int_vec(gallivm, type, 0xff);
 
@@ -302,10 +334,17 @@ rgb_to_rgba_aos(struct gallivm_state *gallivm,
     * Make a 4 x unorm8 vector
     */
 
+#ifdef PIPE_ARCH_LITTLE_ENDIAN
    r = r;
    g = LLVMBuildShl(builder, g, lp_build_const_int_vec(gallivm, type, 8), "");
    b = LLVMBuildShl(builder, b, lp_build_const_int_vec(gallivm, type, 16), "");
    a = lp_build_const_int_vec(gallivm, type, 0xff000000);
+#else
+   r = LLVMBuildShl(builder, r, lp_build_const_int_vec(gallivm, type, 24), "");
+   g = LLVMBuildShl(builder, g, lp_build_const_int_vec(gallivm, type, 16), "");
+   b = LLVMBuildShl(builder, b, lp_build_const_int_vec(gallivm, type, 8), "");
+   a = lp_build_const_int_vec(gallivm, type, 0x000000ff);
+#endif
 
    rgba = r;
    rgba = LLVMBuildOr(builder, rgba, g, "");
index 1bdd4e4845afb8ee862fe2f8c0ff1073f3db2035..eefb23a946f03c6aa577f90b8402b7de250d6d88 100644 (file)
@@ -32,6 +32,7 @@
 #include "lp_bld_format.h"
 #include "lp_bld_gather.h"
 #include "lp_bld_init.h"
+#include "lp_bld_intr.h"
 
 
 /**
@@ -92,10 +93,15 @@ lp_build_gather_elem(struct gallivm_state *gallivm,
    res = LLVMBuildLoad(gallivm->builder, ptr, "");
 
    assert(src_width <= dst_width);
-   if (src_width > dst_width)
+   if (src_width > dst_width) {
       res = LLVMBuildTrunc(gallivm->builder, res, dst_elem_type, "");
-   if (src_width < dst_width)
+   } else if (src_width < dst_width) {
       res = LLVMBuildZExt(gallivm->builder, res, dst_elem_type, "");
+#ifdef PIPE_ARCH_BIG_ENDIAN
+      res = LLVMBuildShl(gallivm->builder, res,
+                         LLVMConstInt(dst_elem_type, dst_width - src_width, 0), "");
+#endif
+   }
 
    return res;
 }
index ae4033b60861012f09cfe27881b84c87657bfc83..08d817a28f5c512bbc9c16da1c96fda9dd42e0ee 100644 (file)
@@ -431,10 +431,16 @@ lp_build_swizzle_aos(struct lp_build_context *bld,
        *
        * For example, this will convert BGRA to RGBA by doing
        *
+       * Little endian:
        *   rgba = (bgra & 0x00ff0000) >> 16
        *        | (bgra & 0xff00ff00)
        *        | (bgra & 0x000000ff) << 16
        *
+       * Big endian:A
+       *   rgba = (bgra & 0x0000ff00) << 16
+       *        | (bgra & 0x00ff00ff)
+       *        | (bgra & 0xff000000) >> 16
+       *
        * This is necessary not only for faster cause, but because X86 backend
        * will refuse shuffles of <4 x i8> vectors
        */
@@ -479,7 +485,11 @@ lp_build_swizzle_aos(struct lp_build_context *bld,
             /* FIXME: big endian */
             if (swizzles[chan] < 4 &&
                 chan - swizzles[chan] == shift) {
+#ifdef PIPE_ARCH_LITTLE_ENDIAN
                mask |= ((1ULL << type.width) - 1) << (swizzles[chan] * type.width);
+#else
+               mask |= ((1ULL << type.width) - 1) << (type4.width - type.width) >> (swizzles[chan] * type.width);
+#endif
             }
          }
 
@@ -492,11 +502,21 @@ lp_build_swizzle_aos(struct lp_build_context *bld,
             masked = LLVMBuildAnd(builder, a,
                                   lp_build_const_int_vec(bld->gallivm, type4, mask), "");
             if (shift > 0) {
+#ifdef PIPE_ARCH_LITTLE_ENDIAN
                shifted = LLVMBuildShl(builder, masked,
                                       lp_build_const_int_vec(bld->gallivm, type4, shift*type.width), "");
+#else
+               shifted = LLVMBuildLShr(builder, masked,
+                                       lp_build_const_int_vec(bld->gallivm, type4, shift*type.width), "");
+#endif
             } else if (shift < 0) {
+#ifdef PIPE_ARCH_LITTLE_ENDIAN
                shifted = LLVMBuildLShr(builder, masked,
                                        lp_build_const_int_vec(bld->gallivm, type4, -shift*type.width), "");
+#else
+               shifted = LLVMBuildShl(builder, masked,
+                                      lp_build_const_int_vec(bld->gallivm, type4, -shift*type.width), "");
+#endif
             } else {
                shifted = masked;
             }