[Mesa-dev] [PATCH 14/16] gallium/radeon: reduce alloca of temporaries based on usagemask
Nicolai Hähnle
nhaehnle at gmail.com
Wed Aug 10 19:23:39 UTC 2016
From: Nicolai Hähnle <nicolai.haehnle at amd.com>
v2: take actual writemasks into account
---
src/gallium/drivers/radeon/radeon_llvm.h | 2 +
.../drivers/radeon/radeon_setup_tgsi_llvm.c | 62 ++++++++++++++++++----
2 files changed, 54 insertions(+), 10 deletions(-)
diff --git a/src/gallium/drivers/radeon/radeon_llvm.h b/src/gallium/drivers/radeon/radeon_llvm.h
index 4ed2c97..0276ef3 100644
--- a/src/gallium/drivers/radeon/radeon_llvm.h
+++ b/src/gallium/drivers/radeon/radeon_llvm.h
@@ -92,20 +92,22 @@ struct radeon_llvm_context {
struct radeon_llvm_loop *loop;
unsigned branch_depth;
unsigned branch_depth_max;
unsigned loop_depth;
unsigned loop_depth_max;
struct tgsi_array_info *temp_arrays;
LLVMValueRef *temp_array_allocas;
+ LLVMValueRef undef_alloca;
+
LLVMValueRef main_fn;
LLVMTypeRef return_type;
unsigned fpmath_md_kind;
LLVMValueRef fpmath_md_2p5_ulp;
struct gallivm_state gallivm;
};
LLVMTypeRef tgsi2llvmtype(struct lp_build_tgsi_context *bld_base,
diff --git a/src/gallium/drivers/radeon/radeon_setup_tgsi_llvm.c b/src/gallium/drivers/radeon/radeon_setup_tgsi_llvm.c
index dac0594..dd7d60b 100644
--- a/src/gallium/drivers/radeon/radeon_setup_tgsi_llvm.c
+++ b/src/gallium/drivers/radeon/radeon_setup_tgsi_llvm.c
@@ -178,41 +178,55 @@ emit_array_index(struct lp_build_tgsi_soa_context *bld,
* must be used.
*/
static LLVMValueRef
get_pointer_into_array(struct radeon_llvm_context *ctx,
unsigned file,
unsigned swizzle,
unsigned reg_index,
const struct tgsi_ind_register *reg_indirect)
{
unsigned array_id;
+ struct tgsi_array_info *array;
struct gallivm_state *gallivm = ctx->soa.bld_base.base.gallivm;
LLVMBuilderRef builder = gallivm->builder;
LLVMValueRef idxs[2];
LLVMValueRef index;
LLVMValueRef alloca;
if (file != TGSI_FILE_TEMPORARY)
return NULL;
array_id = get_temp_array_id(&ctx->soa.bld_base, reg_index, reg_indirect);
if (!array_id)
return NULL;
alloca = ctx->temp_array_allocas[array_id - 1];
if (!alloca)
return NULL;
+ array = &ctx->temp_arrays[array_id - 1];
+
+ if (!(array->writemask & (1 << swizzle)))
+ return ctx->undef_alloca;
+
index = emit_array_index(&ctx->soa, reg_indirect,
reg_index - ctx->temp_arrays[array_id - 1].range.First);
- index = LLVMBuildMul(builder, index, lp_build_const_int32(gallivm, TGSI_NUM_CHANNELS), "");
- index = LLVMBuildAdd(builder, index, lp_build_const_int32(gallivm, swizzle), "");
+ index = LLVMBuildMul(
+ builder, index,
+ lp_build_const_int32(gallivm, util_bitcount(array->writemask)),
+ "");
+ index = LLVMBuildAdd(
+ builder, index,
+ lp_build_const_int32(
+ gallivm,
+ util_bitcount(array->writemask & ((1 << swizzle) - 1))),
+ "");
idxs[0] = ctx->soa.bld_base.uint_bld.zero;
idxs[1] = index;
return LLVMBuildGEP(builder, alloca, idxs, 2, "");
}
LLVMValueRef
radeon_llvm_emit_fetch_64bit(struct lp_build_tgsi_context *bld_base,
enum tgsi_opcode_type type,
LLVMValueRef ptr,
LLVMValueRef ptr2)
@@ -472,48 +486,56 @@ static void emit_declaration(struct lp_build_tgsi_context *bld_base,
}
}
break;
}
case TGSI_FILE_TEMPORARY:
{
char name[16] = "";
LLVMValueRef array_alloca = NULL;
unsigned decl_size;
+ unsigned writemask = decl->Declaration.UsageMask;
first = decl->Range.First;
last = decl->Range.Last;
decl_size = 4 * ((last - first) + 1);
+
if (decl->Declaration.Array) {
unsigned id = decl->Array.ArrayID - 1;
+ unsigned array_size;
+
+ writemask &= ctx->temp_arrays[id].writemask;
+ ctx->temp_arrays[id].writemask = writemask;
+ array_size = ((last - first) + 1) * util_bitcount(writemask);
/* If the array has more than 16 elements, store it
* in memory using an alloca that spans the entire
* array.
*
* Otherwise, store each array element individually.
* We will then generate vectors (per-channel, up to
- * <4 x float>) for indirect addressing.
+ * <16 x float> if the usagemask is a single bit) for
+ * indirect addressing.
*
* Note that 16 is the number of vector elements that
* LLVM will store in a register, so theoretically an
* array with up to 4 * 16 = 64 elements could be
* handled this way, but whether that's a good idea
* depends on VGPR register pressure elsewhere.
*
* FIXME: We shouldn't need to have the non-alloca
* code path for arrays. LLVM should be smart enough to
* promote allocas into registers when profitable.
*/
- if (decl_size > 16) {
+ if (array_size > 16) {
array_alloca = LLVMBuildAlloca(builder,
LLVMArrayType(bld_base->base.vec_type,
- decl_size), "array");
+ array_size), "array");
ctx->temp_array_allocas[id] = array_alloca;
}
}
if (!ctx->temps_count) {
ctx->temps_count = bld_base->info->file_max[TGSI_FILE_TEMPORARY] + 1;
ctx->temps = MALLOC(TGSI_NUM_CHANNELS * ctx->temps_count * sizeof(LLVMValueRef));
}
if (!array_alloca) {
for (i = 0; i < decl_size; ++i) {
@@ -524,28 +546,48 @@ static void emit_declaration(struct lp_build_tgsi_context *bld_base,
ctx->temps[first * TGSI_NUM_CHANNELS + i] =
si_build_alloca_undef(bld_base->base.gallivm,
bld_base->base.vec_type,
name);
}
} else {
LLVMValueRef idxs[2] = {
bld_base->uint_bld.zero,
NULL
};
+ unsigned j = 0;
+
+ if (writemask != TGSI_WRITEMASK_XYZW &&
+ !ctx->undef_alloca) {
+ /* Create a dummy alloca. We use it so that we
+ * have a pointer that is safe to load from if
+ * a shader ever reads from a channel that
+ * it never writes to.
+ */
+ ctx->undef_alloca = si_build_alloca_undef(
+ bld_base->base.gallivm,
+ bld_base->base.vec_type, "undef");
+ }
+
for (i = 0; i < decl_size; ++i) {
+ LLVMValueRef ptr;
+ if (writemask & (1 << (i % 4))) {
#ifdef DEBUG
- snprintf(name, sizeof(name), "TEMP%d.%c",
- first + i / 4, "xyzw"[i % 4]);
+ snprintf(name, sizeof(name), "TEMP%d.%c",
+ first + i / 4, "xyzw"[i % 4]);
#endif
- idxs[1] = lp_build_const_int32(bld_base->base.gallivm, i);
- ctx->temps[first * TGSI_NUM_CHANNELS + i] =
- LLVMBuildGEP(builder, array_alloca, idxs, 2, name);
+ idxs[1] = lp_build_const_int32(bld_base->base.gallivm, j);
+ ptr = LLVMBuildGEP(builder, array_alloca, idxs, 2, name);
+ j++;
+ } else {
+ ptr = ctx->undef_alloca;
+ }
+ ctx->temps[first * TGSI_NUM_CHANNELS + i] = ptr;
}
}
break;
}
case TGSI_FILE_INPUT:
{
unsigned idx;
for (idx = decl->Range.First; idx <= decl->Range.Last; idx++) {
if (ctx->load_input)
ctx->load_input(ctx, idx, decl);
--
2.7.4
More information about the mesa-dev
mailing list