summaryrefslogtreecommitdiff
path: root/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2019-09-05 15:34:46 +1000
committerDave Airlie <airlied@redhat.com>2019-11-28 14:47:54 +1000
commitc879efec0973a4b1c9e6baa94351feb9aaeb3f36 (patch)
tree043cce432729ab9b5541d58a9d6ed93a7088cee4 /src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
parent754c7b893959d97483e6b5fccefbdbaa641c70ca (diff)
gallivm: split out the flow control ir to a common file.
We can share a bunch of flow control handling between NIR and TGSI. Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Diffstat (limited to 'src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c')
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c426
1 files changed, 8 insertions, 418 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
index 5a67f834c90..ca70a96302e 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
@@ -69,10 +69,6 @@
#include "lp_bld_sample.h"
#include "lp_bld_struct.h"
-/* SM 4.0 says that subroutines can nest 32 deep and
- * we need one more for our main function */
-#define LP_MAX_NUM_FUNCS 33
-
#define DUMP_GS_EMITS 0
/*
@@ -105,10 +101,6 @@ emit_dump_reg(struct gallivm_state *gallivm,
lp_build_print_value(gallivm, buf, value);
}
-/*
- * Return the context for the current function.
- * (always 'main', if shader doesn't do any function calls)
- */
static inline struct function_ctx *
func_ctx(struct lp_exec_mask *mask)
{
@@ -118,24 +110,6 @@ func_ctx(struct lp_exec_mask *mask)
}
/*
- * Returns true if we're in a loop.
- * It's global, meaning that it returns true even if there's
- * no loop inside the current function, but we were inside
- * a loop inside another function, from which this one was called.
- */
-static inline boolean
-mask_has_loop(struct lp_exec_mask *mask)
-{
- int i;
- for (i = mask->function_stack_size - 1; i >= 0; --i) {
- const struct function_ctx *ctx = &mask->function_stack[i];
- if (ctx->loop_stack_size > 0)
- return TRUE;
- }
- return FALSE;
-}
-
-/*
* combine the execution mask if there is one with the current mask.
*/
static LLVMValueRef
@@ -154,370 +128,14 @@ mask_vec(struct lp_build_tgsi_context *bld_base)
exec_mask->exec_mask, "");
}
-/*
- * Returns true if we're inside a switch statement.
- * It's global, meaning that it returns true even if there's
- * no switch in the current function, but we were inside
- * a switch inside another function, from which this one was called.
- */
-static inline boolean
-mask_has_switch(struct lp_exec_mask *mask)
-{
- int i;
- for (i = mask->function_stack_size - 1; i >= 0; --i) {
- const struct function_ctx *ctx = &mask->function_stack[i];
- if (ctx->switch_stack_size > 0)
- return TRUE;
- }
- return FALSE;
-}
-
-/*
- * Returns true if we're inside a conditional.
- * It's global, meaning that it returns true even if there's
- * no conditional in the current function, but we were inside
- * a conditional inside another function, from which this one was called.
- */
-static inline boolean
-mask_has_cond(struct lp_exec_mask *mask)
-{
- int i;
- for (i = mask->function_stack_size - 1; i >= 0; --i) {
- const struct function_ctx *ctx = &mask->function_stack[i];
- if (ctx->cond_stack_size > 0)
- return TRUE;
- }
- return FALSE;
-}
-
-
-/*
- * Initialize a function context at the specified index.
- */
-static void
-lp_exec_mask_function_init(struct lp_exec_mask *mask, int function_idx)
-{
- LLVMTypeRef int_type = LLVMInt32TypeInContext(mask->bld->gallivm->context);
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- struct function_ctx *ctx = &mask->function_stack[function_idx];
-
- ctx->cond_stack_size = 0;
- ctx->loop_stack_size = 0;
- ctx->switch_stack_size = 0;
-
- if (function_idx == 0) {
- ctx->ret_mask = mask->ret_mask;
- }
-
- ctx->loop_limiter = lp_build_alloca(mask->bld->gallivm,
- int_type, "looplimiter");
- LLVMBuildStore(
- builder,
- LLVMConstInt(int_type, LP_MAX_TGSI_LOOP_ITERATIONS, false),
- ctx->loop_limiter);
-}
-
-static void lp_exec_mask_init(struct lp_exec_mask *mask, struct lp_build_context *bld)
-{
- mask->bld = bld;
- mask->has_mask = FALSE;
- mask->ret_in_main = FALSE;
- /* For the main function */
- mask->function_stack_size = 1;
-
- mask->int_vec_type = lp_build_int_vec_type(bld->gallivm, mask->bld->type);
- mask->exec_mask = mask->ret_mask = mask->break_mask = mask->cont_mask =
- mask->cond_mask = mask->switch_mask =
- LLVMConstAllOnes(mask->int_vec_type);
-
- mask->function_stack = CALLOC(LP_MAX_NUM_FUNCS,
- sizeof(mask->function_stack[0]));
- lp_exec_mask_function_init(mask, 0);
-}
-
-static void
-lp_exec_mask_fini(struct lp_exec_mask *mask)
-{
- FREE(mask->function_stack);
-}
-
-static void lp_exec_mask_update(struct lp_exec_mask *mask)
-{
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- boolean has_loop_mask = mask_has_loop(mask);
- boolean has_cond_mask = mask_has_cond(mask);
- boolean has_switch_mask = mask_has_switch(mask);
- boolean has_ret_mask = mask->function_stack_size > 1 ||
- mask->ret_in_main;
-
- if (has_loop_mask) {
- /*for loops we need to update the entire mask at runtime */
- LLVMValueRef tmp;
- assert(mask->break_mask);
- tmp = LLVMBuildAnd(builder,
- mask->cont_mask,
- mask->break_mask,
- "maskcb");
- mask->exec_mask = LLVMBuildAnd(builder,
- mask->cond_mask,
- tmp,
- "maskfull");
- } else
- mask->exec_mask = mask->cond_mask;
-
- if (has_switch_mask) {
- mask->exec_mask = LLVMBuildAnd(builder,
- mask->exec_mask,
- mask->switch_mask,
- "switchmask");
- }
-
- if (has_ret_mask) {
- mask->exec_mask = LLVMBuildAnd(builder,
- mask->exec_mask,
- mask->ret_mask,
- "callmask");
- }
-
- mask->has_mask = (has_cond_mask ||
- has_loop_mask ||
- has_switch_mask ||
- has_ret_mask);
-}
-
-static void lp_exec_mask_cond_push(struct lp_exec_mask *mask,
- LLVMValueRef val)
-{
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- struct function_ctx *ctx = func_ctx(mask);
-
- if (ctx->cond_stack_size >= LP_MAX_TGSI_NESTING) {
- ctx->cond_stack_size++;
- return;
- }
- if (ctx->cond_stack_size == 0 && mask->function_stack_size == 1) {
- assert(mask->cond_mask == LLVMConstAllOnes(mask->int_vec_type));
- }
- ctx->cond_stack[ctx->cond_stack_size++] = mask->cond_mask;
- assert(LLVMTypeOf(val) == mask->int_vec_type);
- mask->cond_mask = LLVMBuildAnd(builder,
- mask->cond_mask,
- val,
- "");
- lp_exec_mask_update(mask);
-}
-
-static void lp_exec_mask_cond_invert(struct lp_exec_mask *mask)
-{
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- struct function_ctx *ctx = func_ctx(mask);
- LLVMValueRef prev_mask;
- LLVMValueRef inv_mask;
-
- assert(ctx->cond_stack_size);
- if (ctx->cond_stack_size >= LP_MAX_TGSI_NESTING)
- return;
- prev_mask = ctx->cond_stack[ctx->cond_stack_size - 1];
- if (ctx->cond_stack_size == 1 && mask->function_stack_size == 1) {
- assert(prev_mask == LLVMConstAllOnes(mask->int_vec_type));
- }
-
- inv_mask = LLVMBuildNot(builder, mask->cond_mask, "");
-
- mask->cond_mask = LLVMBuildAnd(builder,
- inv_mask,
- prev_mask, "");
- lp_exec_mask_update(mask);
-}
-
-static void lp_exec_mask_cond_pop(struct lp_exec_mask *mask)
-{
- struct function_ctx *ctx = func_ctx(mask);
- assert(ctx->cond_stack_size);
- --ctx->cond_stack_size;
- if (ctx->cond_stack_size >= LP_MAX_TGSI_NESTING)
- return;
- mask->cond_mask = ctx->cond_stack[ctx->cond_stack_size];
- lp_exec_mask_update(mask);
-}
-
-static void lp_exec_bgnloop(struct lp_exec_mask *mask)
-{
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- struct function_ctx *ctx = func_ctx(mask);
-
- if (ctx->loop_stack_size >= LP_MAX_TGSI_NESTING) {
- ++ctx->loop_stack_size;
- return;
- }
-
- ctx->break_type_stack[ctx->loop_stack_size + ctx->switch_stack_size] =
- ctx->break_type;
- ctx->break_type = LP_EXEC_MASK_BREAK_TYPE_LOOP;
-
- ctx->loop_stack[ctx->loop_stack_size].loop_block = ctx->loop_block;
- ctx->loop_stack[ctx->loop_stack_size].cont_mask = mask->cont_mask;
- ctx->loop_stack[ctx->loop_stack_size].break_mask = mask->break_mask;
- ctx->loop_stack[ctx->loop_stack_size].break_var = ctx->break_var;
- ++ctx->loop_stack_size;
-
- ctx->break_var = lp_build_alloca(mask->bld->gallivm, mask->int_vec_type, "");
- LLVMBuildStore(builder, mask->break_mask, ctx->break_var);
-
- ctx->loop_block = lp_build_insert_new_block(mask->bld->gallivm, "bgnloop");
-
- LLVMBuildBr(builder, ctx->loop_block);
- LLVMPositionBuilderAtEnd(builder, ctx->loop_block);
-
- mask->break_mask = LLVMBuildLoad(builder, ctx->break_var, "");
-
- lp_exec_mask_update(mask);
-}
-
-static void lp_exec_break(struct lp_exec_mask *mask,
+static void lp_exec_tgsi_break(struct lp_exec_mask *mask,
struct lp_build_tgsi_context * bld_base)
{
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- struct function_ctx *ctx = func_ctx(mask);
-
- if (ctx->break_type == LP_EXEC_MASK_BREAK_TYPE_LOOP) {
- LLVMValueRef exec_mask = LLVMBuildNot(builder,
- mask->exec_mask,
- "break");
-
- mask->break_mask = LLVMBuildAnd(builder,
- mask->break_mask,
- exec_mask, "break_full");
- }
- else {
- enum tgsi_opcode opcode =
- bld_base->instructions[bld_base->pc + 1].Instruction.Opcode;
- boolean break_always = (opcode == TGSI_OPCODE_ENDSWITCH ||
- opcode == TGSI_OPCODE_CASE);
-
-
- if (ctx->switch_in_default) {
- /*
- * stop default execution but only if this is an unconditional switch.
- * (The condition here is not perfect since dead code after break is
- * allowed but should be sufficient since false negatives are just
- * unoptimized - so we don't have to pre-evaluate that).
- */
- if(break_always && ctx->switch_pc) {
- bld_base->pc = ctx->switch_pc;
- return;
- }
- }
-
- if (break_always) {
- mask->switch_mask = LLVMConstNull(mask->bld->int_vec_type);
- }
- else {
- LLVMValueRef exec_mask = LLVMBuildNot(builder,
- mask->exec_mask,
- "break");
- mask->switch_mask = LLVMBuildAnd(builder,
- mask->switch_mask,
- exec_mask, "break_switch");
- }
- }
-
- lp_exec_mask_update(mask);
-}
-
-static void lp_exec_continue(struct lp_exec_mask *mask)
-{
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- LLVMValueRef exec_mask = LLVMBuildNot(builder,
- mask->exec_mask,
- "");
-
- mask->cont_mask = LLVMBuildAnd(builder,
- mask->cont_mask,
- exec_mask, "");
-
- lp_exec_mask_update(mask);
-}
-
-
-static void lp_exec_endloop(struct gallivm_state *gallivm,
- struct lp_exec_mask *mask)
-{
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- struct function_ctx *ctx = func_ctx(mask);
- LLVMBasicBlockRef endloop;
- LLVMTypeRef int_type = LLVMInt32TypeInContext(mask->bld->gallivm->context);
- LLVMTypeRef reg_type = LLVMIntTypeInContext(gallivm->context,
- mask->bld->type.width *
- mask->bld->type.length);
- LLVMValueRef i1cond, i2cond, icond, limiter;
-
- assert(mask->break_mask);
-
-
- assert(ctx->loop_stack_size);
- if (ctx->loop_stack_size > LP_MAX_TGSI_NESTING) {
- --ctx->loop_stack_size;
- return;
- }
-
- /*
- * Restore the cont_mask, but don't pop
- */
- mask->cont_mask = ctx->loop_stack[ctx->loop_stack_size - 1].cont_mask;
- lp_exec_mask_update(mask);
-
- /*
- * Unlike the continue mask, the break_mask must be preserved across loop
- * iterations
- */
- LLVMBuildStore(builder, mask->break_mask, ctx->break_var);
-
- /* Decrement the loop limiter */
- limiter = LLVMBuildLoad(builder, ctx->loop_limiter, "");
-
- limiter = LLVMBuildSub(
- builder,
- limiter,
- LLVMConstInt(int_type, 1, false),
- "");
-
- LLVMBuildStore(builder, limiter, ctx->loop_limiter);
-
- /* i1cond = (mask != 0) */
- i1cond = LLVMBuildICmp(
- builder,
- LLVMIntNE,
- LLVMBuildBitCast(builder, mask->exec_mask, reg_type, ""),
- LLVMConstNull(reg_type), "i1cond");
-
- /* i2cond = (looplimiter > 0) */
- i2cond = LLVMBuildICmp(
- builder,
- LLVMIntSGT,
- limiter,
- LLVMConstNull(int_type), "i2cond");
-
- /* if( i1cond && i2cond ) */
- icond = LLVMBuildAnd(builder, i1cond, i2cond, "");
-
- endloop = lp_build_insert_new_block(mask->bld->gallivm, "endloop");
-
- LLVMBuildCondBr(builder,
- icond, ctx->loop_block, endloop);
-
- LLVMPositionBuilderAtEnd(builder, endloop);
-
- assert(ctx->loop_stack_size);
- --ctx->loop_stack_size;
- mask->cont_mask = ctx->loop_stack[ctx->loop_stack_size].cont_mask;
- mask->break_mask = ctx->loop_stack[ctx->loop_stack_size].break_mask;
- ctx->loop_block = ctx->loop_stack[ctx->loop_stack_size].loop_block;
- ctx->break_var = ctx->loop_stack[ctx->loop_stack_size].break_var;
- ctx->break_type = ctx->break_type_stack[ctx->loop_stack_size +
- ctx->switch_stack_size];
-
- lp_exec_mask_update(mask);
+ enum tgsi_opcode opcode =
+ bld_base->instructions[bld_base->pc + 1].Instruction.Opcode;
+ bool break_always = (opcode == TGSI_OPCODE_ENDSWITCH ||
+ opcode == TGSI_OPCODE_CASE);
+ lp_exec_break(mask, &bld_base->pc, break_always);
}
static void lp_exec_switch(struct lp_exec_mask *mask,
@@ -748,34 +366,6 @@ static void lp_exec_default(struct lp_exec_mask *mask,
}
-/* stores val into an address pointed to by dst_ptr.
- * mask->exec_mask is used to figure out which bits of val
- * should be stored into the address
- * (0 means don't store this bit, 1 means do store).
- */
-static void lp_exec_mask_store(struct lp_exec_mask *mask,
- struct lp_build_context *bld_store,
- LLVMValueRef val,
- LLVMValueRef dst_ptr)
-{
- LLVMBuilderRef builder = mask->bld->gallivm->builder;
- LLVMValueRef exec_mask = mask->has_mask ? mask->exec_mask : NULL;
-
- assert(lp_check_value(bld_store->type, val));
- assert(LLVMGetTypeKind(LLVMTypeOf(dst_ptr)) == LLVMPointerTypeKind);
- assert(LLVMGetElementType(LLVMTypeOf(dst_ptr)) == LLVMTypeOf(val) ||
- LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(dst_ptr))) == LLVMArrayTypeKind);
-
- if (exec_mask) {
- LLVMValueRef res, dst;
-
- dst = LLVMBuildLoad(builder, dst_ptr, "");
- res = lp_build_select(bld_store, exec_mask, val, dst);
- LLVMBuildStore(builder, res, dst_ptr);
- } else
- LLVMBuildStore(builder, val, dst_ptr);
-}
-
static void lp_exec_mask_call(struct lp_exec_mask *mask,
int func,
int *pc)
@@ -4107,7 +3697,7 @@ brk_emit(
{
struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
- lp_exec_break(&bld->exec_mask, bld_base);
+ lp_exec_tgsi_break(&bld->exec_mask, bld_base);
}
static void
@@ -4191,7 +3781,7 @@ bgnloop_emit(
{
struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
- lp_exec_bgnloop(&bld->exec_mask);
+ lp_exec_bgnloop(&bld->exec_mask, true);
}
static void