From e25abacc1883f1b2e09c32230e35ffae7df5e61b Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Thu, 22 Nov 2012 13:48:45 -0600 Subject: [PATCH] gallivm: Fix format manipulation for big-endian This patch fixes various format manipulation for big-endian architectures. Reviewed-by: Roland Scheidegger Reviewed-by: Jose Fonseca --- .../auxiliary/gallivm/lp_bld_format_aos.c | 18 +++-- .../gallivm/lp_bld_format_aos_array.c | 70 +++++++++++++++++-- .../auxiliary/gallivm/lp_bld_format_yuv.c | 39 +++++++++++ src/gallium/auxiliary/gallivm/lp_bld_gather.c | 10 ++- .../auxiliary/gallivm/lp_bld_swizzle.c | 20 ++++++ 5 files changed, 145 insertions(+), 12 deletions(-) diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c index 9591bcfb2c7..750d54524c6 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c @@ -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); } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c b/src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c index 24fee640a82..cf296173c3e 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c @@ -32,11 +32,67 @@ #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) { diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c b/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c index f77eb1212b1..e542abce0cc 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c @@ -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, ""); diff --git a/src/gallium/auxiliary/gallivm/lp_bld_gather.c b/src/gallium/auxiliary/gallivm/lp_bld_gather.c index 1bdd4e4845a..eefb23a946f 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_gather.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_gather.c @@ -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; } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_swizzle.c b/src/gallium/auxiliary/gallivm/lp_bld_swizzle.c index ae4033b6086..08d817a28f5 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_swizzle.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_swizzle.c @@ -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; } -- 2.30.2