llvmpipe: implement some control-flow
implements if/else/endif constructs and lays down the code for looping and others. we create a conditional execution mask which decides which of the four inputs are enabled for any store. it's used only if an execution mask is present, otherwise we go through a direct store.
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
#include "lp_bld_swizzle.h"
|
||||
#include "lp_bld_flow.h"
|
||||
#include "lp_bld_tgsi.h"
|
||||
#include "lp_bld_debug.h"
|
||||
|
||||
|
||||
#define LP_MAX_TEMPS 256
|
||||
@@ -81,6 +82,23 @@
|
||||
#define QUAD_BOTTOM_LEFT 2
|
||||
#define QUAD_BOTTOM_RIGHT 3
|
||||
|
||||
#define LP_TGSI_MAX_NESTING 16
|
||||
|
||||
struct lp_exec_mask {
|
||||
struct lp_build_context *bld;
|
||||
|
||||
boolean has_mask;
|
||||
|
||||
LLVMTypeRef int_vec_type;
|
||||
|
||||
LLVMValueRef cond_stack[LP_TGSI_MAX_NESTING];
|
||||
int cond_stack_size;
|
||||
LLVMValueRef cond_mask;
|
||||
|
||||
LLVMValueRef exec_mask;
|
||||
|
||||
LLVMValueRef inv_mask;
|
||||
};
|
||||
|
||||
struct lp_build_tgsi_soa_context
|
||||
{
|
||||
@@ -97,9 +115,9 @@ struct lp_build_tgsi_soa_context
|
||||
LLVMValueRef temps[LP_MAX_TEMPS][NUM_CHANNELS];
|
||||
|
||||
struct lp_build_mask_context *mask;
|
||||
struct lp_exec_mask exec_mask;
|
||||
};
|
||||
|
||||
|
||||
static const unsigned char
|
||||
swizzle_left[4] = {
|
||||
QUAD_TOP_LEFT, QUAD_TOP_LEFT,
|
||||
@@ -124,6 +142,70 @@ swizzle_bottom[4] = {
|
||||
QUAD_BOTTOM_LEFT, QUAD_BOTTOM_RIGHT
|
||||
};
|
||||
|
||||
static void lp_exec_mask_init(struct lp_exec_mask *mask, struct lp_build_context *bld)
|
||||
{
|
||||
mask->bld = bld;
|
||||
mask->has_mask = FALSE;
|
||||
mask->cond_stack_size = 0;
|
||||
|
||||
mask->int_vec_type = lp_build_int_vec_type(mask->bld->type);
|
||||
mask->inv_mask =
|
||||
LLVMConstSub(LLVMConstNull(mask->int_vec_type),
|
||||
LLVMConstAllOnes(mask->int_vec_type));
|
||||
}
|
||||
|
||||
static void lp_exec_mask_update(struct lp_exec_mask *mask)
|
||||
{
|
||||
mask->exec_mask = mask->cond_mask;
|
||||
if (mask->cond_stack_size > 0)
|
||||
mask->has_mask = TRUE;
|
||||
}
|
||||
|
||||
static void lp_exec_mask_cond_push(struct lp_exec_mask *mask,
|
||||
LLVMValueRef val)
|
||||
{
|
||||
mask->cond_stack[mask->cond_stack_size++] = mask->cond_mask;
|
||||
mask->cond_mask = LLVMBuildBitCast(mask->bld->builder, val,
|
||||
mask->int_vec_type, "");
|
||||
|
||||
lp_exec_mask_update(mask);
|
||||
}
|
||||
|
||||
static void lp_exec_mask_cond_invert(struct lp_exec_mask *mask)
|
||||
{
|
||||
LLVMValueRef prev_mask = mask->cond_stack[mask->cond_stack_size - 1];
|
||||
LLVMValueRef inv_mask = LLVMBuildXor(mask->bld->builder,
|
||||
mask->cond_mask,
|
||||
mask->inv_mask, "");
|
||||
mask->cond_mask = LLVMBuildAnd(mask->bld->builder,
|
||||
inv_mask,
|
||||
prev_mask, "");
|
||||
lp_exec_mask_update(mask);
|
||||
}
|
||||
|
||||
static void lp_exec_mask_cond_pop(struct lp_exec_mask *mask)
|
||||
{
|
||||
mask->cond_mask = mask->cond_stack[--mask->cond_stack_size];
|
||||
lp_exec_mask_update(mask);
|
||||
}
|
||||
|
||||
static void lp_exec_mask_store(struct lp_exec_mask *mask,
|
||||
LLVMValueRef val,
|
||||
LLVMValueRef dst)
|
||||
{
|
||||
if (mask->has_mask) {
|
||||
LLVMValueRef real_val, dst_val;
|
||||
|
||||
dst_val = LLVMBuildLoad(mask->bld->builder, dst, "");
|
||||
real_val = lp_build_select(mask->bld,
|
||||
mask->exec_mask,
|
||||
val, dst_val);
|
||||
|
||||
LLVMBuildStore(mask->bld->builder, real_val, dst);
|
||||
} else
|
||||
LLVMBuildStore(mask->bld->builder, val, dst);
|
||||
}
|
||||
|
||||
|
||||
static LLVMValueRef
|
||||
emit_ddx(struct lp_build_tgsi_soa_context *bld,
|
||||
@@ -287,13 +369,13 @@ emit_store(
|
||||
|
||||
switch( reg->Register.File ) {
|
||||
case TGSI_FILE_OUTPUT:
|
||||
LLVMBuildStore(bld->base.builder, value,
|
||||
bld->outputs[reg->Register.Index][chan_index]);
|
||||
lp_exec_mask_store(&bld->exec_mask, value,
|
||||
bld->outputs[reg->Register.Index][chan_index]);
|
||||
break;
|
||||
|
||||
case TGSI_FILE_TEMPORARY:
|
||||
LLVMBuildStore(bld->base.builder, value,
|
||||
bld->temps[reg->Register.Index][chan_index]);
|
||||
lp_exec_mask_store(&bld->exec_mask, value,
|
||||
bld->temps[reg->Register.Index][chan_index]);
|
||||
break;
|
||||
|
||||
case TGSI_FILE_ADDRESS:
|
||||
@@ -1272,8 +1354,8 @@ emit_instruction(
|
||||
break;
|
||||
|
||||
case TGSI_OPCODE_IF:
|
||||
/* FIXME */
|
||||
return 0;
|
||||
tmp0 = emit_fetch(bld, inst, 0, CHAN_X);
|
||||
lp_exec_mask_cond_push(&bld->exec_mask, tmp0);
|
||||
break;
|
||||
|
||||
case TGSI_OPCODE_BGNFOR:
|
||||
@@ -1289,13 +1371,11 @@ emit_instruction(
|
||||
break;
|
||||
|
||||
case TGSI_OPCODE_ELSE:
|
||||
/* FIXME */
|
||||
return 0;
|
||||
lp_exec_mask_cond_invert(&bld->exec_mask);
|
||||
break;
|
||||
|
||||
case TGSI_OPCODE_ENDIF:
|
||||
/* FIXME */
|
||||
return 0;
|
||||
lp_exec_mask_cond_pop(&bld->exec_mask);
|
||||
break;
|
||||
|
||||
case TGSI_OPCODE_ENDFOR:
|
||||
@@ -1458,6 +1538,8 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
|
||||
bld.consts_ptr = consts_ptr;
|
||||
bld.sampler = sampler;
|
||||
|
||||
lp_exec_mask_init(&bld.exec_mask, &bld.base);
|
||||
|
||||
tgsi_parse_init( &parse, tokens );
|
||||
|
||||
while( !tgsi_parse_end_of_tokens( &parse ) ) {
|
||||
|
||||
Reference in New Issue
Block a user