radeon/llvm: rework input fetch and output store

Cleanup the code and implement indirect addressing.

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Tom Stellard <thomas.stellard@amd.com>
This commit is contained in:
Christian König 2013-03-07 11:01:07 +01:00
parent b51f8593d8
commit c05483fc00
2 changed files with 156 additions and 127 deletions

View file

@ -35,6 +35,7 @@
#define RADEON_LLVM_MAX_OUTPUTS 32 * 4
#define RADEON_LLVM_MAX_BRANCH_DEPTH 16
#define RADEON_LLVM_MAX_LOOP_DEPTH 16
#define RADEON_LLVM_MAX_ARRAYS 16
#define RADEON_LLVM_MAX_SYSTEM_VALUES 4
@ -117,12 +118,32 @@ struct radeon_llvm_context {
unsigned branch_depth;
unsigned loop_depth;
struct tgsi_declaration_range arrays[RADEON_LLVM_MAX_ARRAYS];
unsigned num_arrays;
LLVMValueRef main_fn;
struct gallivm_state gallivm;
};
static inline LLVMTypeRef tgsi2llvmtype(
struct lp_build_tgsi_context * bld_base,
enum tgsi_opcode_type type)
{
LLVMContextRef ctx = bld_base->base.gallivm->context;
switch (type) {
case TGSI_TYPE_UNSIGNED:
case TGSI_TYPE_SIGNED:
return LLVMInt32TypeInContext(ctx);
case TGSI_TYPE_UNTYPED:
case TGSI_TYPE_FLOAT:
return LLVMFloatTypeInContext(ctx);
default: break;
}
return 0;
}
static inline LLVMValueRef bitcast(
struct lp_build_tgsi_context * bld_base,
enum tgsi_opcode_type type,
@ -130,22 +151,7 @@ static inline LLVMValueRef bitcast(
)
{
LLVMBuilderRef builder = bld_base->base.gallivm->builder;
LLVMContextRef ctx = bld_base->base.gallivm->context;
LLVMTypeRef dst_type;
switch (type) {
case TGSI_TYPE_UNSIGNED:
case TGSI_TYPE_SIGNED:
dst_type = LLVMInt32TypeInContext(ctx);
break;
case TGSI_TYPE_UNTYPED:
case TGSI_TYPE_FLOAT:
dst_type = LLVMFloatTypeInContext(ctx);
break;
default:
dst_type = 0;
break;
}
LLVMTypeRef dst_type = tgsi2llvmtype(bld_base, type);
if (dst_type)
return LLVMBuildBitCast(builder, value, dst_type, "");

View file

@ -80,136 +80,124 @@ static LLVMValueRef emit_swizzle(
LLVMConstVector(swizzles, 4), "");
}
static struct tgsi_declaration_range
get_array_range(struct lp_build_tgsi_context *bld_base,
unsigned File, const struct tgsi_ind_register *reg)
{
struct radeon_llvm_context * ctx = radeon_llvm_context(bld_base);
if (File != TGSI_FILE_TEMPORARY || reg->ArrayID == 0 ||
reg->ArrayID > RADEON_LLVM_MAX_ARRAYS) {
struct tgsi_declaration_range range;
range.First = 0;
range.Last = bld_base->info->file_max[File];
return range;
}
return ctx->arrays[reg->ArrayID - 1];
}
static LLVMValueRef
emit_array_index(
struct lp_build_tgsi_soa_context *bld,
const struct tgsi_full_src_register *reg,
unsigned swizzle)
const struct tgsi_ind_register *reg,
unsigned offset)
{
struct gallivm_state * gallivm = bld->bld_base.base.gallivm;
LLVMValueRef addr = LLVMBuildLoad(gallivm->builder,
bld->addr[reg->Indirect.Index][swizzle], "");
LLVMValueRef offset = lp_build_const_int32(gallivm, reg->Register.Index);
LLVMValueRef hw_index = LLVMBuildAdd(gallivm->builder, addr, offset, "");
LLVMValueRef soa_index = LLVMBuildMul(gallivm->builder, hw_index,
lp_build_const_int32(gallivm, 4), "");
LLVMValueRef array_index = LLVMBuildAdd(gallivm->builder, soa_index,
lp_build_const_int32(gallivm, swizzle), "");
return array_index;
LLVMValueRef addr = LLVMBuildLoad(gallivm->builder, bld->addr[reg->Index][reg->Swizzle], "");
return LLVMBuildAdd(gallivm->builder, addr, lp_build_const_int32(gallivm, offset), "");
}
static LLVMValueRef
emit_fetch_immediate(
emit_fetch(
struct lp_build_tgsi_context *bld_base,
const struct tgsi_full_src_register *reg,
enum tgsi_opcode_type type,
unsigned swizzle);
static LLVMValueRef
emit_array_fetch(
struct lp_build_tgsi_context *bld_base,
unsigned File, enum tgsi_opcode_type type,
struct tgsi_declaration_range range,
unsigned swizzle)
{
LLVMTypeRef ctype;
LLVMContextRef ctx = bld_base->base.gallivm->context;
switch (type) {
case TGSI_TYPE_UNSIGNED:
case TGSI_TYPE_SIGNED:
ctype = LLVMInt32TypeInContext(ctx);
break;
case TGSI_TYPE_UNTYPED:
case TGSI_TYPE_FLOAT:
ctype = LLVMFloatTypeInContext(ctx);
break;
default:
ctype = 0;
break;
}
struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
if (swizzle == ~0) {
LLVMValueRef values[TGSI_NUM_CHANNELS] = {};
unsigned chan;
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
values[chan] = LLVMConstBitCast(bld->immediates[reg->Register.Index][chan], ctype);
}
return lp_build_gather_values(bld_base->base.gallivm, values,
TGSI_NUM_CHANNELS);
} else {
return LLVMConstBitCast(bld->immediates[reg->Register.Index][swizzle], ctype);
struct gallivm_state * gallivm = bld->bld_base.base.gallivm;
LLVMBuilderRef builder = bld_base->base.gallivm->builder;
unsigned i, size = range.Last - range.First + 1;
LLVMTypeRef vec = LLVMVectorType(tgsi2llvmtype(bld_base, type), size);
LLVMValueRef result = LLVMGetUndef(vec);
struct tgsi_full_src_register tmp_reg = {};
tmp_reg.Register.File = File;
for (i = 0; i < size; ++i) {
tmp_reg.Register.Index = i + range.First;
LLVMValueRef temp = emit_fetch(bld_base, &tmp_reg, type, swizzle);
result = LLVMBuildInsertElement(builder, result, temp,
lp_build_const_int32(gallivm, i), "");
}
return result;
}
static LLVMValueRef
emit_fetch_input(
emit_fetch(
struct lp_build_tgsi_context *bld_base,
const struct tgsi_full_src_register *reg,
enum tgsi_opcode_type type,
unsigned swizzle)
{
struct radeon_llvm_context * ctx = radeon_llvm_context(bld_base);
if (swizzle == ~0) {
LLVMValueRef values[TGSI_NUM_CHANNELS] = {};
unsigned chan;
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
values[chan] = ctx->inputs[radeon_llvm_reg_index_soa(
reg->Register.Index, chan)];
}
return lp_build_gather_values(bld_base->base.gallivm, values,
TGSI_NUM_CHANNELS);
} else {
return bitcast(bld_base, type, ctx->inputs[radeon_llvm_reg_index_soa(reg->Register.Index, swizzle)]);
}
}
static LLVMValueRef
emit_fetch_temporary(
struct lp_build_tgsi_context *bld_base,
const struct tgsi_full_src_register *reg,
enum tgsi_opcode_type type,
unsigned swizzle)
{
struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
LLVMBuilderRef builder = bld_base->base.gallivm->builder;
LLVMValueRef result, ptr;
if (swizzle == ~0) {
LLVMValueRef values[TGSI_NUM_CHANNELS] = {};
LLVMValueRef values[TGSI_NUM_CHANNELS];
unsigned chan;
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
values[chan] = emit_fetch_temporary(bld_base, reg, type, chan);
values[chan] = emit_fetch(bld_base, reg, type, chan);
}
return lp_build_gather_values(bld_base->base.gallivm, values,
TGSI_NUM_CHANNELS);
TGSI_NUM_CHANNELS);
}
if (reg->Register.Indirect) {
LLVMValueRef array_index = emit_array_index(bld, reg, swizzle);
LLVMValueRef ptr = LLVMBuildGEP(builder, bld->temps_array, &array_index,
1, "");
return LLVMBuildLoad(builder, ptr, "");
} else {
LLVMValueRef temp_ptr;
temp_ptr = lp_get_temp_ptr_soa(bld, reg->Register.Index, swizzle);
return bitcast(bld_base,type,LLVMBuildLoad(builder, temp_ptr, ""));
struct tgsi_declaration_range range = get_array_range(bld_base,
reg->Register.File, &reg->Indirect);
return LLVMBuildExtractElement(builder,
emit_array_fetch(bld_base, reg->Register.File, type, range, swizzle),
emit_array_index(bld, &reg->Indirect, reg->Register.Index - range.First),
"");
}
}
static LLVMValueRef
emit_fetch_output(
struct lp_build_tgsi_context *bld_base,
const struct tgsi_full_src_register *reg,
enum tgsi_opcode_type type,
unsigned swizzle)
{
struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
LLVMBuilderRef builder = bld_base->base.gallivm->builder;
if (reg->Register.Indirect) {
LLVMValueRef array_index = emit_array_index(bld, reg, swizzle);
LLVMValueRef ptr = LLVMBuildGEP(builder, bld->outputs_array, &array_index,
1, "");
return LLVMBuildLoad(builder, ptr, "");
} else {
LLVMValueRef temp_ptr;
temp_ptr = lp_get_output_ptr(bld, reg->Register.Index, swizzle);
return LLVMBuildLoad(builder, temp_ptr, "");
}
switch(reg->Register.File) {
case TGSI_FILE_IMMEDIATE: {
LLVMTypeRef ctype = tgsi2llvmtype(bld_base, type);
return LLVMConstBitCast(bld->immediates[reg->Register.Index][swizzle], ctype);
}
case TGSI_FILE_INPUT:
result = ctx->inputs[radeon_llvm_reg_index_soa(reg->Register.Index, swizzle)];
break;
case TGSI_FILE_TEMPORARY:
ptr = lp_get_temp_ptr_soa(bld, reg->Register.Index, swizzle);
result = LLVMBuildLoad(builder, ptr, "");
break;
case TGSI_FILE_OUTPUT:
ptr = lp_get_output_ptr(bld, reg->Register.Index, swizzle);
result = LLVMBuildLoad(builder, ptr, "");
break;
default:
return LLVMGetUndef(tgsi2llvmtype(bld_base, type));
}
return bitcast(bld_base, type, result);
}
static void emit_declaration(
@ -233,6 +221,8 @@ static void emit_declaration(
}
case TGSI_FILE_TEMPORARY:
if (decl->Declaration.Array && decl->Array.ArrayID <= RADEON_LLVM_MAX_ARRAYS)
ctx->arrays[decl->Array.ArrayID - 1] = decl->Range;
lp_emit_declaration_soa(bld_base, decl);
break;
@ -291,6 +281,7 @@ emit_store(
LLVMValueRef temp_ptr;
unsigned chan, chan_index;
boolean is_vec_store = FALSE;
if (dst[0]) {
LLVMTypeKind k = LLVMGetTypeKind(LLVMTypeOf(dst[0]));
is_vec_store = (k == LLVMVectorTypeKind);
@ -333,26 +324,56 @@ emit_store(
&clamp_emit_data);
}
switch(reg->Register.File) {
case TGSI_FILE_ADDRESS:
if (reg->Register.File == TGSI_FILE_ADDRESS) {
temp_ptr = bld->addr[reg->Register.Index][chan_index];
LLVMBuildStore(builder, value, temp_ptr);
continue;
case TGSI_FILE_OUTPUT:
temp_ptr = bld->outputs[reg->Register.Index][chan_index];
break;
case TGSI_FILE_TEMPORARY:
temp_ptr = lp_get_temp_ptr_soa(bld, reg->Register.Index, chan_index);
break;
default:
return;
}
value = bitcast(bld_base, TGSI_TYPE_FLOAT, value);
LLVMBuildStore(builder, value, temp_ptr);
if (reg->Register.Indirect) {
struct tgsi_declaration_range range = get_array_range(bld_base,
reg->Register.File, &reg->Indirect);
unsigned i, size = range.Last - range.First + 1;
LLVMValueRef array = LLVMBuildInsertElement(builder,
emit_array_fetch(bld_base, reg->Register.File, TGSI_TYPE_FLOAT, range, chan_index),
value, emit_array_index(bld, &reg->Indirect, reg->Register.Index - range.First), "");
for (i = 0; i < size; ++i) {
switch(reg->Register.File) {
case TGSI_FILE_OUTPUT:
temp_ptr = bld->outputs[i + range.First][chan_index];
break;
case TGSI_FILE_TEMPORARY:
temp_ptr = lp_get_temp_ptr_soa(bld, i + range.First, chan_index);
break;
default:
return;
}
value = LLVMBuildExtractElement(builder, array,
lp_build_const_int32(gallivm, i), "");
LLVMBuildStore(builder, value, temp_ptr);
}
} else {
switch(reg->Register.File) {
case TGSI_FILE_OUTPUT:
temp_ptr = bld->outputs[reg->Register.Index][chan_index];
break;
case TGSI_FILE_TEMPORARY:
temp_ptr = lp_get_temp_ptr_soa(bld, reg->Register.Index, chan_index);
break;
default:
return;
}
LLVMBuildStore(builder, value, temp_ptr);
}
}
}
@ -1128,14 +1149,16 @@ void radeon_llvm_context_init(struct radeon_llvm_context * ctx)
bld_base->emit_declaration = emit_declaration;
bld_base->emit_immediate = emit_immediate;
bld_base->emit_fetch_funcs[TGSI_FILE_IMMEDIATE] = emit_fetch_immediate;
bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = emit_fetch_input;
bld_base->emit_fetch_funcs[TGSI_FILE_TEMPORARY] = emit_fetch_temporary;
bld_base->emit_fetch_funcs[TGSI_FILE_OUTPUT] = emit_fetch_output;
bld_base->emit_fetch_funcs[TGSI_FILE_IMMEDIATE] = emit_fetch;
bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = emit_fetch;
bld_base->emit_fetch_funcs[TGSI_FILE_TEMPORARY] = emit_fetch;
bld_base->emit_fetch_funcs[TGSI_FILE_OUTPUT] = emit_fetch;
/* Allocate outputs */
ctx->soa.outputs = ctx->outputs;
ctx->num_arrays = 0;
/* XXX: Is there a better way to initialize all this ? */
lp_set_default_actions(bld_base);