diff --git a/src/gallium/drivers/llvmpipe/lp_bld_blend_aos.c b/src/gallium/drivers/llvmpipe/lp_bld_blend_aos.c index abdad3edbae..880235bc009 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_blend_aos.c +++ b/src/gallium/drivers/llvmpipe/lp_bld_blend_aos.c @@ -39,6 +39,7 @@ #include "lp_bld_type.h" #include "lp_bld_const.h" #include "lp_bld_arit.h" +#include "lp_bld_logic.h" #include "lp_bld_swizzle.h" #include "lp_bld_blend.h" diff --git a/src/gallium/drivers/llvmpipe/lp_bld_logic.c b/src/gallium/drivers/llvmpipe/lp_bld_logic.c index dbca2921e65..95d7f8c5ba4 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_logic.c +++ b/src/gallium/drivers/llvmpipe/lp_bld_logic.c @@ -28,6 +28,7 @@ #include "pipe/p_defines.h" #include "lp_bld_type.h" +#include "lp_bld_const.h" #include "lp_bld_intr.h" #include "lp_bld_logic.h" @@ -172,3 +173,105 @@ lp_build_cmp(struct lp_build_context *bld, return LLVMBuildSelect(bld->builder, cond, ones, zeros, ""); } + + +LLVMValueRef +lp_build_select(struct lp_build_context *bld, + LLVMValueRef mask, + LLVMValueRef a, + LLVMValueRef b) +{ + union lp_type type = bld->type; + LLVMValueRef res; + + if(a == b) + return a; + + if(type.floating) { + LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); + a = LLVMBuildBitCast(bld->builder, a, int_vec_type, ""); + b = LLVMBuildBitCast(bld->builder, b, int_vec_type, ""); + } + + /* TODO: On SSE4 we could do this with a single instruction -- PBLENDVB */ + + a = LLVMBuildAnd(bld->builder, a, mask, ""); + + /* This often gets translated to PANDN, but sometimes the NOT is + * pre-computed and stored in another constant. The best strategy depends + * on available registers, so it is not a big deal -- hopefully LLVM does + * the right decision attending the rest of the program. + */ + b = LLVMBuildAnd(bld->builder, b, LLVMBuildNot(bld->builder, mask, ""), ""); + + res = LLVMBuildOr(bld->builder, a, b, ""); + + if(type.floating) { + LLVMTypeRef vec_type = lp_build_vec_type(type); + res = LLVMBuildBitCast(bld->builder, res, vec_type, ""); + } + + return res; +} + + +LLVMValueRef +lp_build_select_aos(struct lp_build_context *bld, + LLVMValueRef a, + LLVMValueRef b, + boolean cond[4]) +{ + const union lp_type type = bld->type; + const unsigned n = type.length; + unsigned i, j; + + if(a == b) + return a; + if(cond[0] && cond[1] && cond[2] && cond[3]) + return a; + if(!cond[0] && !cond[1] && !cond[2] && !cond[3]) + return b; + if(a == bld->undef || b == bld->undef) + return bld->undef; + + /* + * There are three major ways of accomplishing this: + * - with a shuffle, + * - with a select, + * - or with a bit mask. + * + * Select isn't supported for vector types yet. + * The flip between these is empirical and might need to be. + */ + if (n <= 4) { + /* + * Shuffle. + */ + LLVMTypeRef elem_type = LLVMInt32Type(); + LLVMValueRef shuffles[LP_MAX_VECTOR_LENGTH]; + + for(j = 0; j < n; j += 4) + for(i = 0; i < 4; ++i) + shuffles[j + i] = LLVMConstInt(elem_type, (cond[i] ? 0 : n) + j + i, 0); + + return LLVMBuildShuffleVector(bld->builder, a, b, LLVMConstVector(shuffles, n), ""); + } +#if 0 + else if(0) { + /* FIXME: Unfortunately select of vectors do not work */ + /* Use a select */ + LLVMTypeRef elem_type = LLVMInt1Type(); + LLVMValueRef cond[LP_MAX_VECTOR_LENGTH]; + + for(j = 0; j < n; j += 4) + for(i = 0; i < 4; ++i) + cond[j + i] = LLVMConstInt(elem_type, cond[i] ? 1 : 0, 0); + + return LLVMBuildSelect(bld->builder, LLVMConstVector(cond, n), a, b, ""); + } +#endif + else { + LLVMValueRef mask = lp_build_const_mask_aos(type, cond); + return lp_build_select(bld, mask, a, b); + } +} diff --git a/src/gallium/drivers/llvmpipe/lp_bld_logic.h b/src/gallium/drivers/llvmpipe/lp_bld_logic.h index a8c10d670a0..0989f9f2078 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_logic.h +++ b/src/gallium/drivers/llvmpipe/lp_bld_logic.h @@ -54,4 +54,17 @@ lp_build_cmp(struct lp_build_context *bld, LLVMValueRef b); +LLVMValueRef +lp_build_select(struct lp_build_context *bld, + LLVMValueRef mask, + LLVMValueRef a, + LLVMValueRef b); + +LLVMValueRef +lp_build_select_aos(struct lp_build_context *bld, + LLVMValueRef a, + LLVMValueRef b, + boolean cond[4]); + + #endif /* !LP_BLD_LOGIC_H */ diff --git a/src/gallium/drivers/llvmpipe/lp_bld_swizzle.c b/src/gallium/drivers/llvmpipe/lp_bld_swizzle.c index 185df4a3429..3402d4f5d94 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_swizzle.c +++ b/src/gallium/drivers/llvmpipe/lp_bld_swizzle.c @@ -30,6 +30,7 @@ #include "lp_bld_type.h" #include "lp_bld_const.h" +#include "lp_bld_logic.h" #include "lp_bld_swizzle.h" @@ -131,108 +132,6 @@ lp_build_broadcast_aos(struct lp_build_context *bld, } -LLVMValueRef -lp_build_select(struct lp_build_context *bld, - LLVMValueRef mask, - LLVMValueRef a, - LLVMValueRef b) -{ - union lp_type type = bld->type; - LLVMValueRef res; - - if(a == b) - return a; - - if(type.floating) { - LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); - a = LLVMBuildBitCast(bld->builder, a, int_vec_type, ""); - b = LLVMBuildBitCast(bld->builder, b, int_vec_type, ""); - } - - /* TODO: On SSE4 we could do this with a single instruction -- PBLENDVB */ - - a = LLVMBuildAnd(bld->builder, a, mask, ""); - - /* This often gets translated to PANDN, but sometimes the NOT is - * pre-computed and stored in another constant. The best strategy depends - * on available registers, so it is not a big deal -- hopefully LLVM does - * the right decision attending the rest of the program. - */ - b = LLVMBuildAnd(bld->builder, b, LLVMBuildNot(bld->builder, mask, ""), ""); - - res = LLVMBuildOr(bld->builder, a, b, ""); - - if(type.floating) { - LLVMTypeRef vec_type = lp_build_vec_type(type); - res = LLVMBuildBitCast(bld->builder, res, vec_type, ""); - } - - return res; -} - - -LLVMValueRef -lp_build_select_aos(struct lp_build_context *bld, - LLVMValueRef a, - LLVMValueRef b, - boolean cond[4]) -{ - const union lp_type type = bld->type; - const unsigned n = type.length; - unsigned i, j; - - if(a == b) - return a; - if(cond[0] && cond[1] && cond[2] && cond[3]) - return a; - if(!cond[0] && !cond[1] && !cond[2] && !cond[3]) - return b; - if(a == bld->undef || b == bld->undef) - return bld->undef; - - /* - * There are three major ways of accomplishing this: - * - with a shuffle, - * - with a select, - * - or with a bit mask. - * - * Select isn't supported for vector types yet. - * The flip between these is empirical and might need to be. - */ - if (n <= 4) { - /* - * Shuffle. - */ - LLVMTypeRef elem_type = LLVMInt32Type(); - LLVMValueRef shuffles[LP_MAX_VECTOR_LENGTH]; - - for(j = 0; j < n; j += 4) - for(i = 0; i < 4; ++i) - shuffles[j + i] = LLVMConstInt(elem_type, (cond[i] ? 0 : n) + j + i, 0); - - return LLVMBuildShuffleVector(bld->builder, a, b, LLVMConstVector(shuffles, n), ""); - } -#if 0 - else if(0) { - /* FIXME: Unfortunately select of vectors do not work */ - /* Use a select */ - LLVMTypeRef elem_type = LLVMInt1Type(); - LLVMValueRef cond[LP_MAX_VECTOR_LENGTH]; - - for(j = 0; j < n; j += 4) - for(i = 0; i < 4; ++i) - cond[j + i] = LLVMConstInt(elem_type, cond[i] ? 1 : 0, 0); - - return LLVMBuildSelect(bld->builder, LLVMConstVector(cond, n), a, b, ""); - } -#endif - else { - LLVMValueRef mask = lp_build_const_mask_aos(type, cond); - return lp_build_select(bld, mask, a, b); - } -} - - LLVMValueRef lp_build_swizzle1_aos(struct lp_build_context *bld, LLVMValueRef a, diff --git a/src/gallium/drivers/llvmpipe/lp_bld_swizzle.h b/src/gallium/drivers/llvmpipe/lp_bld_swizzle.h index fe53e86786d..ceaaabf9ecf 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_swizzle.h +++ b/src/gallium/drivers/llvmpipe/lp_bld_swizzle.h @@ -59,19 +59,6 @@ lp_build_broadcast_aos(struct lp_build_context *bld, unsigned channel); -LLVMValueRef -lp_build_select(struct lp_build_context *bld, - LLVMValueRef mask, - LLVMValueRef a, - LLVMValueRef b); - -LLVMValueRef -lp_build_select_aos(struct lp_build_context *bld, - LLVMValueRef a, - LLVMValueRef b, - boolean cond[4]); - - /** * Swizzle a vector consisting of an array of XYZW structs. *