From 8783732c4d2b9162d996f678eb41e3eae3ac86c7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Mon, 27 Jul 2009 01:23:15 +0100 Subject: [PATCH] llvmpipe: Pixel packing/unpacking and loop code generators. Just a small proof of concept plus a standalone test app. Not integrated with the rest of the driver yet. --- src/gallium/drivers/llvmpipe/Makefile | 3 + src/gallium/drivers/llvmpipe/SConscript | 15 +- src/gallium/drivers/llvmpipe/lp_bld.h | 94 +++++++++ src/gallium/drivers/llvmpipe/lp_bld_loop.c | 91 +++++++++ src/gallium/drivers/llvmpipe/lp_bld_pack.c | 132 ++++++++++++ src/gallium/drivers/llvmpipe/lp_bld_test.c | 199 +++++++++++++++++++ src/gallium/drivers/llvmpipe/lp_bld_unpack.c | 156 +++++++++++++++ 7 files changed, 689 insertions(+), 1 deletion(-) create mode 100644 src/gallium/drivers/llvmpipe/lp_bld.h create mode 100644 src/gallium/drivers/llvmpipe/lp_bld_loop.c create mode 100644 src/gallium/drivers/llvmpipe/lp_bld_pack.c create mode 100644 src/gallium/drivers/llvmpipe/lp_bld_test.c create mode 100644 src/gallium/drivers/llvmpipe/lp_bld_unpack.c diff --git a/src/gallium/drivers/llvmpipe/Makefile b/src/gallium/drivers/llvmpipe/Makefile index c0c430628d4..a6556c57825 100644 --- a/src/gallium/drivers/llvmpipe/Makefile +++ b/src/gallium/drivers/llvmpipe/Makefile @@ -7,6 +7,9 @@ C_SOURCES = \ lp_fs_exec.c \ lp_fs_sse.c \ lp_fs_llvm.c \ + lp_bld_pack.c \ + lp_bld_unpack.c \ + lp_bld_loop.c \ lp_clear.c \ lp_flush.c \ lp_query.c \ diff --git a/src/gallium/drivers/llvmpipe/SConscript b/src/gallium/drivers/llvmpipe/SConscript index f021549c448..fa3047f1651 100644 --- a/src/gallium/drivers/llvmpipe/SConscript +++ b/src/gallium/drivers/llvmpipe/SConscript @@ -2,12 +2,17 @@ Import('*') env = env.Clone() +env.ParseConfig('llvm-config --cflags --libs jit interpreter nativecodegen') + llvmpipe = env.ConvenienceLibrary( target = 'llvmpipe', source = [ 'lp_fs_exec.c', 'lp_fs_sse.c', 'lp_fs_llvm.c', + 'lp_bld_pack.c', + 'lp_bld_unpack.c', + 'lp_bld_loop.c', 'lp_clear.c', 'lp_context.c', 'lp_draw_arrays.c', @@ -43,4 +48,12 @@ llvmpipe = env.ConvenienceLibrary( 'lp_tile_cache.c', ]) -Export('softpipe') \ No newline at end of file +env['LINK'] = env['CXX'] + +env.Program( + target = 'lp_bld_test', + source = ['lp_bld_test.c'], + LIBS = [llvmpipe] + auxiliaries + env['LIBS'], +) + +Export('llvmpipe') diff --git a/src/gallium/drivers/llvmpipe/lp_bld.h b/src/gallium/drivers/llvmpipe/lp_bld.h new file mode 100644 index 00000000000..88b70d74786 --- /dev/null +++ b/src/gallium/drivers/llvmpipe/lp_bld.h @@ -0,0 +1,94 @@ +/************************************************************************** + * + * Copyright 2009 Vmware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef LP_BLD_H +#define LP_BLD_H + + +/** + * @file + * LLVM IR building helpers interfaces. + * + * We use LLVM-C bindings for now. They are not documented, but follow the C++ + * interfaces very closely, and appear to be complete enough for code + * genration. See + * http://npcontemplation.blogspot.com/2008/06/secret-of-llvm-c-bindings.html + * for a standalone example. + */ + +#include + +#include "pipe/p_format.h" + + +/** + * Unpack a pixel into its RGBA components. + * + * @param ptr value with the pointer to the packed pixel. Pointer type is + * irrelevant. + * + * @return RGBA in a 4 floats vector. + */ +LLVMValueRef +lp_build_unpack_rgba(LLVMBuilderRef builder, + enum pipe_format format, + LLVMValueRef ptr); + + +/** + * Pack a pixel. + * + * @param rgba 4 float vector with the unpacked components. + */ +void +lp_build_pack_rgba(LLVMBuilderRef builder, + enum pipe_format format, + LLVMValueRef ptr, + LLVMValueRef rgba); + + +struct lp_build_loop_state +{ + LLVMBasicBlockRef block; + LLVMValueRef counter; +}; + + +void +lp_build_loop_begin(LLVMBuilderRef builder, + LLVMValueRef start, + struct lp_build_loop_state *state); + + +void +lp_build_loop_end(LLVMBuilderRef builder, + LLVMValueRef end, + LLVMValueRef step, + struct lp_build_loop_state *state); + + +#endif /* !LP_BLD_H */ diff --git a/src/gallium/drivers/llvmpipe/lp_bld_loop.c b/src/gallium/drivers/llvmpipe/lp_bld_loop.c new file mode 100644 index 00000000000..3c0a9a1ede2 --- /dev/null +++ b/src/gallium/drivers/llvmpipe/lp_bld_loop.c @@ -0,0 +1,91 @@ +/************************************************************************** + * + * Copyright 2009 Vmware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "lp_bld.h" + + +/** + * @file + * Auxiliaries to build loops. + * + * LLVM's IR doesn't represent for-loops directly. Furthermore it + * it requires creating code blocks, branches, phi variables, so it + * requires a fair amount of code. + * + * @sa http://www.llvm.org/docs/tutorial/LangImpl5.html#for + */ + + +void +lp_build_loop_begin(LLVMBuilderRef builder, + LLVMValueRef start, + struct lp_build_loop_state *state) +{ + LLVMBasicBlockRef block = LLVMGetInsertBlock(builder); + LLVMValueRef function = LLVMGetBasicBlockParent(block); + + state->block = LLVMAppendBasicBlock(function, "loop"); + + LLVMBuildBr(builder, state->block); + + LLVMPositionBuilderAtEnd(builder, state->block); + + state->counter = LLVMBuildPhi(builder, LLVMTypeOf(start), ""); + + LLVMAddIncoming(state->counter, &start, &block, 1); + +} + + +void +lp_build_loop_end(LLVMBuilderRef builder, + LLVMValueRef end, + LLVMValueRef step, + struct lp_build_loop_state *state) +{ + LLVMBasicBlockRef block = LLVMGetInsertBlock(builder); + LLVMValueRef function = LLVMGetBasicBlockParent(block); + LLVMValueRef next; + LLVMValueRef cond; + LLVMBasicBlockRef after_block; + + if (!step) + step = LLVMConstInt(LLVMTypeOf(end), 1, 0); + + next = LLVMBuildAdd(builder, state->counter, step, ""); + + cond = LLVMBuildICmp(builder, LLVMIntNE, next, end, ""); + + after_block = LLVMAppendBasicBlock(function, ""); + + LLVMBuildCondBr(builder, cond, after_block, state->block); + + LLVMAddIncoming(state->counter, &next, &block, 1); + + LLVMPositionBuilderAtEnd(builder, after_block); +} + diff --git a/src/gallium/drivers/llvmpipe/lp_bld_pack.c b/src/gallium/drivers/llvmpipe/lp_bld_pack.c new file mode 100644 index 00000000000..7c2c7a7c762 --- /dev/null +++ b/src/gallium/drivers/llvmpipe/lp_bld_pack.c @@ -0,0 +1,132 @@ +/************************************************************************** + * + * Copyright 2009 Vmware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "util/u_format.h" + +#include "lp_bld.h" + + +void +lp_build_pack_rgba(LLVMBuilderRef builder, + enum pipe_format format, + LLVMValueRef ptr, + LLVMValueRef rgba) +{ + const struct util_format_description *desc; + LLVMTypeRef type; + LLVMValueRef packed = NULL; + unsigned shift = 0; + unsigned i, j; + + desc = util_format_description(format); + + assert(desc->layout == UTIL_FORMAT_LAYOUT_RGBA); + assert(desc->block.width == 1); + assert(desc->block.height == 1); + + type = LLVMIntType(desc->block.bits); + + LLVMValueRef swizzles[4]; + LLVMValueRef shifted, casted, scaled, unswizzled; + + + /* Unswizzle the color components into the source vector. */ + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + if (desc->swizzle[j] == i) + break; + } + if (j < 4) + swizzles[i] = LLVMConstInt(LLVMInt32Type(), j, 0); + else + swizzles[i] = LLVMGetUndef(LLVMInt32Type()); + } + + unswizzled = LLVMBuildShuffleVector(builder, rgba, + LLVMGetUndef(LLVMVectorType(LLVMFloatType(), 4)), + LLVMConstVector(swizzles, 4), ""); + + LLVMValueRef shifts[4]; + LLVMValueRef scales[4]; + bool normalized = FALSE; + + for (i = 0; i < 4; ++i) { + unsigned bits = desc->channel[i].size; + + if (desc->channel[i].type == UTIL_FORMAT_TYPE_VOID) { + shifts[i] = LLVMGetUndef(LLVMInt32Type()); + scales[i] = LLVMGetUndef(LLVMFloatType()); + } + else { + unsigned mask = (1 << bits) - 1; + + assert(desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED); + assert(bits < 32); + + shifts[i] = LLVMConstInt(LLVMInt32Type(), shift, 0); + + if (desc->channel[i].normalized) { + scales[i] = LLVMConstReal(LLVMFloatType(), mask); + normalized = TRUE; + } + else + scales[i] = LLVMConstReal(LLVMFloatType(), 1.0); + } + + shift += bits; + } + + if (normalized) + scaled = LLVMBuildMul(builder, unswizzled, LLVMConstVector(scales, 4), ""); + else + scaled = unswizzled; + + casted = LLVMBuildFPToSI(builder, scaled, LLVMVectorType(LLVMInt32Type(), 4), ""); + + shifted = LLVMBuildShl(builder, casted, LLVMConstVector(shifts, 4), ""); + + /* Bitwise or all components */ + for (i = 0; i < 4; ++i) { + if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) { + LLVMValueRef component = LLVMBuildExtractElement(builder, shifted, LLVMConstInt(LLVMInt32Type(), i, 0), ""); + if (packed) + packed = LLVMBuildOr(builder, packed, component, ""); + else + packed = component; + } + } + + if (packed) { + + if (desc->block.bits < 32) + packed = LLVMBuildTrunc(builder, packed, type, ""); + + LLVMBuildStore(builder, packed, LLVMBuildBitCast(builder, ptr, LLVMPointerType(type, 0), "")); + } +} + diff --git a/src/gallium/drivers/llvmpipe/lp_bld_test.c b/src/gallium/drivers/llvmpipe/lp_bld_test.c new file mode 100644 index 00000000000..5325b7d3336 --- /dev/null +++ b/src/gallium/drivers/llvmpipe/lp_bld_test.c @@ -0,0 +1,199 @@ +/************************************************************************** + * + * Copyright 2009 Vmware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include +#include + +#include +#include +#include +#include +#include + +#include "lp_bld.h" + + +static LLVMValueRef +add_unpack_rgba_test(LLVMModuleRef module, + enum pipe_format format) +{ + LLVMTypeRef args[] = { + LLVMPointerType(LLVMInt8Type(), 0), + LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0) + }; + LLVMValueRef func = LLVMAddFunction(module, "unpack", LLVMFunctionType(LLVMVoidType(), args, 2, 0)); + LLVMSetFunctionCallConv(func, LLVMCCallConv); + LLVMValueRef ptr = LLVMGetParam(func, 0); + LLVMValueRef rgba_ptr = LLVMGetParam(func, 1); + + LLVMBasicBlockRef block = LLVMAppendBasicBlock(func, "entry"); + LLVMBuilderRef builder = LLVMCreateBuilder(); + LLVMPositionBuilderAtEnd(builder, block); + + LLVMValueRef rgba; + + struct lp_build_loop_state loop; + + lp_build_loop_begin(builder, LLVMConstInt(LLVMInt32Type(), 1, 0), &loop); + + rgba = lp_build_unpack_rgba(builder, format, ptr); + LLVMBuildStore(builder, rgba, rgba_ptr); + + lp_build_loop_end(builder, LLVMConstInt(LLVMInt32Type(), 4, 0), NULL, &loop); + + LLVMBuildRetVoid(builder); + + LLVMDisposeBuilder(builder); + return func; +} + + +static LLVMValueRef +add_pack_rgba_test(LLVMModuleRef module, + enum pipe_format format) +{ + LLVMTypeRef args[] = { + LLVMPointerType(LLVMInt8Type(), 0), + LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0) + }; + LLVMValueRef func = LLVMAddFunction(module, "pack", LLVMFunctionType(LLVMVoidType(), args, 2, 0)); + LLVMSetFunctionCallConv(func, LLVMCCallConv); + LLVMValueRef ptr = LLVMGetParam(func, 0); + LLVMValueRef rgba_ptr = LLVMGetParam(func, 1); + + LLVMBasicBlockRef block = LLVMAppendBasicBlock(func, "entry"); + LLVMBuilderRef builder = LLVMCreateBuilder(); + LLVMPositionBuilderAtEnd(builder, block); + + LLVMValueRef rgba; + + rgba = LLVMBuildLoad(builder, rgba_ptr, ""); + + lp_build_pack_rgba(builder, format, ptr, rgba); + + LLVMBuildRetVoid(builder); + + LLVMDisposeBuilder(builder); + return func; +} + + +int main(int argc, char **argv) +{ + char *error = NULL; + int n; + + if (argc > 1) + sscanf(argv[1], "%x", &n); + else + n = 0x0000f0f0; + + LLVMModuleRef module = LLVMModuleCreateWithName("test"); + + enum pipe_format format; + format = PIPE_FORMAT_R5G6B5_UNORM; + LLVMValueRef unpack = add_unpack_rgba_test(module, format); + LLVMValueRef pack = add_pack_rgba_test(module, format); + + LLVMVerifyModule(module, LLVMAbortProcessAction, &error); + LLVMDisposeMessage(error); + + LLVMExecutionEngineRef engine; + LLVMModuleProviderRef provider = LLVMCreateModuleProviderForExistingModule(module); + error = NULL; + LLVMCreateJITCompiler(&engine, provider, 1, &error); + if (error) { + fprintf(stderr, "%s\n", error); + LLVMDisposeMessage(error); + abort(); + } + + LLVMPassManagerRef pass = LLVMCreatePassManager(); +#if 0 + LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass); + /* These are the passes currently listed in llvm-c/Transforms/Scalar.h, + * but there are more on SVN. */ + LLVMAddConstantPropagationPass(pass); + LLVMAddInstructionCombiningPass(pass); + LLVMAddPromoteMemoryToRegisterPass(pass); + LLVMAddDemoteMemoryToRegisterPass(pass); + LLVMAddGVNPass(pass); + LLVMAddCFGSimplificationPass(pass); + LLVMRunPassManager(pass, module); +#endif + LLVMDumpModule(module); + + printf("Packed: %08x\n", n); + + float rgba[4] = {0, 0, 0, 0}; + + { +#if 1 + typedef void (*unpack_ptr_t)(void *, float *); + unpack_ptr_t unpack_ptr = (unpack_ptr_t)LLVMGetPointerToGlobal(engine, unpack); + + unpack_ptr(&n, rgba); +#else + LLVMGenericValueRef exec_args[] = { + LLVMCreateGenericValueOfPointer(n), + LLVMCreateGenericValueOfPointer(rgba) + }; + LLVMGenericValueRef exec_res = LLVMRunFunction(engine, unpack, 2, exec_args); +#endif + + printf("Unpacked: %f %f %f %f\n", + rgba[0], + rgba[1], + rgba[2], + rgba[3]); + } + + n = 0; + + { +#if 1 + typedef void (*pack_ptr_t)(void *, float *); + pack_ptr_t pack_ptr = (pack_ptr_t)LLVMGetPointerToGlobal(engine, pack); + + pack_ptr(&n, rgba); +#else + LLVMGenericValueRef exec_args[] = { + LLVMCreateGenericValueOfPointer(n), + LLVMCreateGenericValueOfPointer(rgba) + }; + LLVMGenericValueRef exec_res = LLVMRunFunction(engine, pack, 2, exec_args); +#endif + + printf("Packed: %08x\n", n); + } + + LLVMDisposePassManager(pass); + LLVMDisposeExecutionEngine(engine); + + return 0; +} diff --git a/src/gallium/drivers/llvmpipe/lp_bld_unpack.c b/src/gallium/drivers/llvmpipe/lp_bld_unpack.c new file mode 100644 index 00000000000..79022c68a67 --- /dev/null +++ b/src/gallium/drivers/llvmpipe/lp_bld_unpack.c @@ -0,0 +1,156 @@ +/************************************************************************** + * + * Copyright 2009 Vmware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "util/u_format.h" + +#include "lp_bld.h" + + +LLVMValueRef +lp_build_unpack_rgba(LLVMBuilderRef builder, + enum pipe_format format, + LLVMValueRef ptr) +{ + const struct util_format_description *desc; + LLVMTypeRef type; + LLVMValueRef deferred; + unsigned shift = 0; + unsigned i; + + desc = util_format_description(format); + + /* FIXME: Support more formats */ + assert(desc->layout == UTIL_FORMAT_LAYOUT_RGBA); + assert(desc->block.width == 1); + assert(desc->block.height == 1); + assert(desc->block.bits <= 32); + + type = LLVMIntType(desc->block.bits); + + deferred = LLVMBuildLoad(builder, LLVMBuildBitCast(builder, ptr, LLVMPointerType(type, 0), ""), ""); + + /* Do the intermediate integer computations with 32bit integers since it + * matches floating point size */ + if (desc->block.bits < 32) + deferred = LLVMBuildZExt(builder, deferred, LLVMInt32Type(), ""); + + /* Broadcast the packed value to all four channels */ + deferred = LLVMBuildInsertElement(builder, + LLVMGetUndef(LLVMVectorType(LLVMInt32Type(), 4)), + deferred, + LLVMConstNull(LLVMInt32Type()), + ""); + deferred = LLVMBuildShuffleVector(builder, + deferred, + LLVMGetUndef(LLVMVectorType(LLVMInt32Type(), 4)), + LLVMConstNull(LLVMVectorType(LLVMInt32Type(), 4)), + ""); + + LLVMValueRef shifted, casted, scaled, masked, swizzled; + LLVMValueRef shifts[4]; + LLVMValueRef masks[4]; + LLVMValueRef scales[4]; + bool normalized = FALSE; + int empty_channel = -1; + + /* Initialize vector constants */ + for (i = 0; i < 4; ++i) { + unsigned bits = desc->channel[i].size; + + if (desc->channel[i].type == UTIL_FORMAT_TYPE_VOID) { + shifts[i] = LLVMGetUndef(LLVMInt32Type()); + masks[i] = LLVMConstNull(LLVMInt32Type()); + scales[i] = LLVMConstNull(LLVMFloatType()); + empty_channel = i; + } + else { + unsigned mask = (1 << bits) - 1; + + assert(desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED); + assert(bits < 32); + + shifts[i] = LLVMConstInt(LLVMInt32Type(), shift, 0); + masks[i] = LLVMConstInt(LLVMInt32Type(), mask, 0); + + if (desc->channel[i].normalized) { + scales[i] = LLVMConstReal(LLVMFloatType(), 1.0/mask); + normalized = TRUE; + } + else + scales[i] = LLVMConstReal(LLVMFloatType(), 1.0); + } + + shift += bits; + } + + shifted = LLVMBuildLShr(builder, deferred, LLVMConstVector(shifts, 4), ""); + masked = LLVMBuildAnd(builder, shifted, LLVMConstVector(masks, 4), ""); + // UIToFP can't be expressed in SSE2 + casted = LLVMBuildSIToFP(builder, masked, LLVMVectorType(LLVMFloatType(), 4), ""); + + if (normalized) + scaled = LLVMBuildMul(builder, casted, LLVMConstVector(scales, 4), ""); + else + scaled = casted; + + LLVMValueRef swizzles[4]; + LLVMValueRef aux[4]; + + for (i = 0; i < 4; ++i) + aux[i] = LLVMGetUndef(LLVMFloatType()); + + for (i = 0; i < 4; ++i) { + enum util_format_swizzle swizzle = desc->swizzle[i]; + + switch (swizzle) { + case UTIL_FORMAT_SWIZZLE_X: + case UTIL_FORMAT_SWIZZLE_Y: + case UTIL_FORMAT_SWIZZLE_Z: + case UTIL_FORMAT_SWIZZLE_W: + swizzles[i] = LLVMConstInt(LLVMInt32Type(), swizzle, 0); + break; + case UTIL_FORMAT_SWIZZLE_0: + assert(empty_channel >= 0); + swizzles[i] = LLVMConstInt(LLVMInt32Type(), empty_channel, 0); + break; + case UTIL_FORMAT_SWIZZLE_1: + swizzles[i] = LLVMConstInt(LLVMInt32Type(), 4, 0); + aux[0] = LLVMConstReal(LLVMFloatType(), 1.0); + break; + case UTIL_FORMAT_SWIZZLE_NONE: + swizzles[i] = LLVMGetUndef(LLVMFloatType()); + assert(0); + break; + } + } + + swizzled = LLVMBuildShuffleVector(builder, scaled, LLVMConstVector(aux, 4), LLVMConstVector(swizzles, 4), ""); + + return swizzled; +} + -- 2.30.2