From 272dadbe4ebeaeb4f942c0f3c2fd140285b0457c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Sun, 2 Aug 2009 13:52:40 +0100 Subject: [PATCH] llvmpipe: Introduce a custom typing system. Straightforward representation of floating-point/fixed-point/integer, normalized/scaled, signed/unsigned SIMD vector types. --- src/gallium/drivers/llvmpipe/lp_bld.h | 2 + src/gallium/drivers/llvmpipe/lp_bld_arit.c | 145 +++++++++++++++---- src/gallium/drivers/llvmpipe/lp_bld_arit.h | 92 +++++++++++- src/gallium/drivers/llvmpipe/lp_bld_blend.c | 19 ++- src/gallium/drivers/llvmpipe/lp_test_blend.c | 12 +- 5 files changed, 228 insertions(+), 42 deletions(-) diff --git a/src/gallium/drivers/llvmpipe/lp_bld.h b/src/gallium/drivers/llvmpipe/lp_bld.h index 86571374b60..e9d9c25a800 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld.h +++ b/src/gallium/drivers/llvmpipe/lp_bld.h @@ -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_, diff --git a/src/gallium/drivers/llvmpipe/lp_bld_arit.c b/src/gallium/drivers/llvmpipe/lp_bld_arit.c index 7e5af284aab..b5b4148ac2d 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_arit.c +++ b/src/gallium/drivers/llvmpipe/lp_bld_arit.c @@ -50,56 +50,143 @@ #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); } diff --git a/src/gallium/drivers/llvmpipe/lp_bld_arit.h b/src/gallium/drivers/llvmpipe/lp_bld_arit.h index 0d2636aed9b..f9a61be5168 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_arit.h +++ b/src/gallium/drivers/llvmpipe/lp_bld_arit.h @@ -25,6 +25,14 @@ * **************************************************************************/ +/** + * @file + * Helper arithmetic functions. + * + * @author Jose Fonseca + */ + + #ifndef LP_BLD_ARIT_H #define LP_BLD_ARIT_H @@ -32,7 +40,87 @@ #include -#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); /* @@ -40,7 +128,7 @@ */ 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); diff --git a/src/gallium/drivers/llvmpipe/lp_bld_blend.c b/src/gallium/drivers/llvmpipe/lp_bld_blend.c index d708047202f..48d1e0028ae 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_blend.c +++ b/src/gallium/drivers/llvmpipe/lp_bld_blend.c @@ -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); } } diff --git a/src/gallium/drivers/llvmpipe/lp_test_blend.c b/src/gallium/drivers/llvmpipe/lp_test_blend.c index 1621fa79abf..3becac18717 100644 --- a/src/gallium/drivers/llvmpipe/lp_test_blend.c +++ b/src/gallium/drivers/llvmpipe/lp_test_blend.c @@ -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"); -- 2.30.2