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:
Zack Rusin
2010-03-01 22:11:08 -05:00
parent d3f24ab33c
commit 80f3cc36c5
+93 -11
View File
@@ -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 ) ) {