/**************************************************************************
*
* Copyright 2009 VMware, Inc.
- * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007-2008 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#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
/*
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)
+{
+ assert(mask->function_stack_size > 0);
+ assert(mask->function_stack_size <= LP_MAX_NUM_FUNCS);
+ return &mask->function_stack[mask->function_stack_size - 1];
+}
-static void lp_exec_mask_init(struct lp_exec_mask *mask, struct lp_build_context *bld)
+/*
+ * 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)
{
- LLVMTypeRef int_type = LLVMInt32TypeInContext(bld->gallivm->context);
- LLVMBuilderRef builder = bld->gallivm->builder;
+ 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;
+}
+
+/*
+ * 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;
- mask->cond_stack_size = 0;
- mask->loop_stack_size = 0;
- mask->call_stack_size = 0;
- mask->switch_stack_size = 0;
+ /* 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->loop_limiter = lp_build_alloca(bld->gallivm, int_type, "looplimiter");
+ mask->function_stack = CALLOC(LP_MAX_NUM_FUNCS,
+ sizeof(mask->function_stack[0]));
+ lp_exec_mask_function_init(mask, 0);
+}
- LLVMBuildStore(
- builder,
- LLVMConstInt(int_type, LP_MAX_TGSI_LOOP_ITERATIONS, false),
- mask->loop_limiter);
+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 (mask->loop_stack_size) {
+ if (has_loop_mask) {
/*for loops we need to update the entire mask at runtime */
LLVMValueRef tmp;
assert(mask->break_mask);
} else
mask->exec_mask = mask->cond_mask;
- if (mask->switch_stack_size) {
+ if (has_switch_mask) {
mask->exec_mask = LLVMBuildAnd(builder,
mask->exec_mask,
mask->switch_mask,
"switchmask");
}
- if (mask->call_stack_size || mask->ret_in_main) {
+ if (has_ret_mask) {
mask->exec_mask = LLVMBuildAnd(builder,
mask->exec_mask,
mask->ret_mask,
"callmask");
}
- mask->has_mask = (mask->cond_stack_size > 0 ||
- mask->loop_stack_size > 0 ||
- mask->call_stack_size > 0 ||
- mask->switch_stack_size > 0 ||
- mask->ret_in_main);
+ 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);
- assert(mask->cond_stack_size < LP_MAX_TGSI_NESTING);
- if (mask->cond_stack_size == 0) {
+ 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));
}
- mask->cond_stack[mask->cond_stack_size++] = mask->cond_mask;
+ 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,
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(mask->cond_stack_size);
- prev_mask = mask->cond_stack[mask->cond_stack_size - 1];
- if (mask->cond_stack_size == 1) {
+ 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));
}
static void lp_exec_mask_cond_pop(struct lp_exec_mask *mask)
{
- assert(mask->cond_stack_size);
- mask->cond_mask = mask->cond_stack[--mask->cond_stack_size];
+ 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 (mask->loop_stack_size == 0) {
- assert(mask->loop_block == NULL);
- assert(mask->cont_mask == LLVMConstAllOnes(mask->int_vec_type));
- assert(mask->break_mask == LLVMConstAllOnes(mask->int_vec_type));
- assert(mask->break_var == NULL);
+ if (ctx->loop_stack_size >= LP_MAX_TGSI_NESTING) {
+ ++ctx->loop_stack_size;
+ return;
}
- assert(mask->loop_stack_size < LP_MAX_TGSI_NESTING);
+ ctx->break_type_stack[ctx->loop_stack_size + ctx->switch_stack_size] =
+ ctx->break_type;
+ ctx->break_type = LP_EXEC_MASK_BREAK_TYPE_LOOP;
- mask->break_type_stack[mask->loop_stack_size + mask->switch_stack_size] =
- mask->break_type;
- mask->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;
- mask->loop_stack[mask->loop_stack_size].loop_block = mask->loop_block;
- mask->loop_stack[mask->loop_stack_size].cont_mask = mask->cont_mask;
- mask->loop_stack[mask->loop_stack_size].break_mask = mask->break_mask;
- mask->loop_stack[mask->loop_stack_size].break_var = mask->break_var;
- ++mask->loop_stack_size;
+ ctx->break_var = lp_build_alloca(mask->bld->gallivm, mask->int_vec_type, "");
+ LLVMBuildStore(builder, mask->break_mask, ctx->break_var);
- mask->break_var = lp_build_alloca(mask->bld->gallivm, mask->int_vec_type, "");
- LLVMBuildStore(builder, mask->break_mask, mask->break_var);
+ ctx->loop_block = lp_build_insert_new_block(mask->bld->gallivm, "bgnloop");
- mask->loop_block = lp_build_insert_new_block(mask->bld->gallivm, "bgnloop");
+ LLVMBuildBr(builder, ctx->loop_block);
+ LLVMPositionBuilderAtEnd(builder, ctx->loop_block);
- LLVMBuildBr(builder, mask->loop_block);
- LLVMPositionBuilderAtEnd(builder, mask->loop_block);
-
- mask->break_mask = LLVMBuildLoad(builder, mask->break_var, "");
+ mask->break_mask = LLVMBuildLoad(builder, ctx->break_var, "");
lp_exec_mask_update(mask);
}
struct lp_build_tgsi_context * bld_base)
{
LLVMBuilderRef builder = mask->bld->gallivm->builder;
+ struct function_ctx *ctx = func_ctx(mask);
- if (mask->break_type == LP_EXEC_MASK_BREAK_TYPE_LOOP) {
+ if (ctx->break_type == LP_EXEC_MASK_BREAK_TYPE_LOOP) {
LLVMValueRef exec_mask = LLVMBuildNot(builder,
mask->exec_mask,
"break");
opcode == TGSI_OPCODE_CASE);
- if (mask->switch_in_default) {
+ 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 && mask->switch_pc) {
- bld_base->pc = mask->switch_pc;
+ if(break_always && ctx->switch_pc) {
+ bld_base->pc = ctx->switch_pc;
return;
}
}
LLVMValueRef cond)
{
LLVMBuilderRef builder = mask->bld->gallivm->builder;
+ struct function_ctx *ctx = func_ctx(mask);
LLVMValueRef cond_mask = LLVMBuildAnd(builder,
mask->exec_mask,
cond, "cond_mask");
cond_mask = LLVMBuildNot(builder, cond_mask, "break_cond");
- if (mask->break_type == LP_EXEC_MASK_BREAK_TYPE_LOOP) {
+ if (ctx->break_type == LP_EXEC_MASK_BREAK_TYPE_LOOP) {
mask->break_mask = LLVMBuildAnd(builder,
mask->break_mask,
cond_mask, "breakc_full");
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,
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
*/
- assert(mask->loop_stack_size);
- mask->cont_mask = mask->loop_stack[mask->loop_stack_size - 1].cont_mask;
+ 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, mask->break_var);
+ LLVMBuildStore(builder, mask->break_mask, ctx->break_var);
/* Decrement the loop limiter */
- limiter = LLVMBuildLoad(builder, mask->loop_limiter, "");
+ limiter = LLVMBuildLoad(builder, ctx->loop_limiter, "");
limiter = LLVMBuildSub(
builder,
LLVMConstInt(int_type, 1, false),
"");
- LLVMBuildStore(builder, limiter, mask->loop_limiter);
+ LLVMBuildStore(builder, limiter, ctx->loop_limiter);
/* i1cond = (mask != 0) */
i1cond = LLVMBuildICmp(
endloop = lp_build_insert_new_block(mask->bld->gallivm, "endloop");
LLVMBuildCondBr(builder,
- icond, mask->loop_block, endloop);
+ icond, ctx->loop_block, endloop);
LLVMPositionBuilderAtEnd(builder, endloop);
- assert(mask->loop_stack_size);
- --mask->loop_stack_size;
- mask->loop_block = mask->loop_stack[mask->loop_stack_size].loop_block;
- mask->cont_mask = mask->loop_stack[mask->loop_stack_size].cont_mask;
- mask->break_mask = mask->loop_stack[mask->loop_stack_size].break_mask;
- mask->break_var = mask->loop_stack[mask->loop_stack_size].break_var;
- mask->break_type = mask->break_type_stack[mask->loop_stack_size + mask->switch_stack_size];
+ 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);
}
static void lp_exec_switch(struct lp_exec_mask *mask,
LLVMValueRef switchval)
{
- mask->break_type_stack[mask->loop_stack_size + mask->switch_stack_size] =
- mask->break_type;
- mask->break_type = LP_EXEC_MASK_BREAK_TYPE_SWITCH;
+ struct function_ctx *ctx = func_ctx(mask);
- mask->switch_stack[mask->switch_stack_size].switch_val = mask->switch_val;
- mask->switch_stack[mask->switch_stack_size].switch_mask = mask->switch_mask;
- mask->switch_stack[mask->switch_stack_size].switch_mask_default = mask->switch_mask_default;
- mask->switch_stack[mask->switch_stack_size].switch_in_default = mask->switch_in_default;
- mask->switch_stack[mask->switch_stack_size].switch_pc = mask->switch_pc;
- mask->switch_stack_size++;
+ if (ctx->switch_stack_size >= LP_MAX_TGSI_NESTING ||
+ ctx->loop_stack_size > LP_MAX_TGSI_NESTING) {
+ ctx->switch_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_SWITCH;
+
+ ctx->switch_stack[ctx->switch_stack_size].switch_mask = mask->switch_mask;
+ ctx->switch_stack[ctx->switch_stack_size].switch_val = ctx->switch_val;
+ ctx->switch_stack[ctx->switch_stack_size].switch_mask_default = ctx->switch_mask_default;
+ ctx->switch_stack[ctx->switch_stack_size].switch_in_default = ctx->switch_in_default;
+ ctx->switch_stack[ctx->switch_stack_size].switch_pc = ctx->switch_pc;
+ ctx->switch_stack_size++;
- mask->switch_val = switchval;
mask->switch_mask = LLVMConstNull(mask->int_vec_type);
- mask->switch_mask_default = LLVMConstNull(mask->int_vec_type);
- mask->switch_in_default = false;
- mask->switch_pc = 0;
+ ctx->switch_val = switchval;
+ ctx->switch_mask_default = LLVMConstNull(mask->int_vec_type);
+ ctx->switch_in_default = false;
+ ctx->switch_pc = 0;
lp_exec_mask_update(mask);
}
struct lp_build_tgsi_context * bld_base)
{
LLVMBuilderRef builder = mask->bld->gallivm->builder;
+ struct function_ctx *ctx = func_ctx(mask);
+
+ if (ctx->switch_stack_size > LP_MAX_TGSI_NESTING) {
+ ctx->switch_stack_size--;
+ return;
+ }
/* check if there's deferred default if so do it now */
- if (mask->switch_pc && !mask->switch_in_default) {
+ if (ctx->switch_pc && !ctx->switch_in_default) {
LLVMValueRef prevmask, defaultmask;
unsigned tmp_pc;
- prevmask = mask->switch_stack[mask->switch_stack_size - 1].switch_mask;
- defaultmask = LLVMBuildNot(builder, mask->switch_mask_default, "sw_default_mask");
+ prevmask = ctx->switch_stack[ctx->switch_stack_size - 1].switch_mask;
+ defaultmask = LLVMBuildNot(builder, ctx->switch_mask_default, "sw_default_mask");
mask->switch_mask = LLVMBuildAnd(builder, prevmask, defaultmask, "sw_mask");
- mask->switch_in_default = true;
+ ctx->switch_in_default = true;
lp_exec_mask_update(mask);
- assert(bld_base->instructions[mask->switch_pc - 1].Instruction.Opcode ==
+ assert(bld_base->instructions[ctx->switch_pc - 1].Instruction.Opcode ==
TGSI_OPCODE_DEFAULT);
tmp_pc = bld_base->pc;
- bld_base->pc = mask->switch_pc;
+ bld_base->pc = ctx->switch_pc;
/*
* re-purpose switch_pc to point to here again, since we stop execution of
* the deferred default after next break.
*/
- mask->switch_pc = tmp_pc - 1;
+ ctx->switch_pc = tmp_pc - 1;
return;
}
- else if (mask->switch_pc && mask->switch_in_default) {
- assert(bld_base->pc == mask->switch_pc + 1);
+ else if (ctx->switch_pc && ctx->switch_in_default) {
+ assert(bld_base->pc == ctx->switch_pc + 1);
}
- mask->switch_stack_size--;
- mask->switch_val = mask->switch_stack[mask->switch_stack_size].switch_val;
- mask->switch_mask = mask->switch_stack[mask->switch_stack_size].switch_mask;
- mask->switch_mask_default = mask->switch_stack[mask->switch_stack_size].switch_mask_default;
- mask->switch_in_default = mask->switch_stack[mask->switch_stack_size].switch_in_default;
- mask->switch_pc = mask->switch_stack[mask->switch_stack_size].switch_pc;
+ ctx->switch_stack_size--;
+ mask->switch_mask = ctx->switch_stack[ctx->switch_stack_size].switch_mask;
+ ctx->switch_val = ctx->switch_stack[ctx->switch_stack_size].switch_val;
+ ctx->switch_mask_default = ctx->switch_stack[ctx->switch_stack_size].switch_mask_default;
+ ctx->switch_in_default = ctx->switch_stack[ctx->switch_stack_size].switch_in_default;
+ ctx->switch_pc = ctx->switch_stack[ctx->switch_stack_size].switch_pc;
- mask->break_type = mask->break_type_stack[mask->loop_stack_size + mask->switch_stack_size];
+ ctx->break_type = ctx->break_type_stack[ctx->loop_stack_size + ctx->switch_stack_size];
lp_exec_mask_update(mask);
}
LLVMValueRef caseval)
{
LLVMBuilderRef builder = mask->bld->gallivm->builder;
+ struct function_ctx *ctx = func_ctx(mask);
LLVMValueRef casemask, prevmask;
+ if (ctx->switch_stack_size > LP_MAX_TGSI_NESTING) {
+ return;
+ }
+
/* skipping case mask evaluation here is NOT optional (not in all cases anyway). */
- if (!mask->switch_in_default) {
- prevmask = mask->switch_stack[mask->switch_stack_size - 1].switch_mask;
- casemask = lp_build_cmp(mask->bld, PIPE_FUNC_EQUAL, caseval, mask->switch_val);
- mask->switch_mask_default = LLVMBuildOr(builder, casemask,
- mask->switch_mask_default, "sw_default_mask");
+ if (!ctx->switch_in_default) {
+ prevmask = ctx->switch_stack[ctx->switch_stack_size - 1].switch_mask;
+ casemask = lp_build_cmp(mask->bld, PIPE_FUNC_EQUAL, caseval, ctx->switch_val);
+ ctx->switch_mask_default = LLVMBuildOr(builder, casemask,
+ ctx->switch_mask_default, "sw_default_mask");
casemask = LLVMBuildOr(builder, casemask, mask->switch_mask, "");
mask->switch_mask = LLVMBuildAnd(builder, casemask, prevmask, "sw_mask");
int *default_pc_start)
{
unsigned pc = bld_base->pc;
- unsigned curr_switch_stack = mask->switch_stack_size;
+ struct function_ctx *ctx = func_ctx(mask);
+ unsigned curr_switch_stack = ctx->switch_stack_size;
+
+ if (ctx->switch_stack_size > LP_MAX_TGSI_NESTING) {
+ return false;
+ }
/* skip over case statements which are together with default */
while (bld_base->instructions[pc].Instruction.Opcode == TGSI_OPCODE_CASE) {
unsigned opcode = bld_base->instructions[pc].Instruction.Opcode;
switch (opcode) {
case TGSI_OPCODE_CASE:
- if (curr_switch_stack == mask->switch_stack_size) {
+ if (curr_switch_stack == ctx->switch_stack_size) {
*default_pc_start = pc - 1;
return false;
}
curr_switch_stack++;
break;
case TGSI_OPCODE_ENDSWITCH:
- if (curr_switch_stack == mask->switch_stack_size) {
+ if (curr_switch_stack == ctx->switch_stack_size) {
*default_pc_start = pc - 1;
return true;
}
struct lp_build_tgsi_context * bld_base)
{
LLVMBuilderRef builder = mask->bld->gallivm->builder;
+ struct function_ctx *ctx = func_ctx(mask);
int default_exec_pc;
boolean default_is_last;
+ if (ctx->switch_stack_size > LP_MAX_TGSI_NESTING) {
+ return;
+ }
+
/*
* This is a messy opcode, because it may not be always at the end and
* there can be fallthrough in and out of it.
*/
if (default_is_last) {
LLVMValueRef prevmask, defaultmask;
- prevmask = mask->switch_stack[mask->switch_stack_size - 1].switch_mask;
- defaultmask = LLVMBuildNot(builder, mask->switch_mask_default, "sw_default_mask");
+ prevmask = ctx->switch_stack[ctx->switch_stack_size - 1].switch_mask;
+ defaultmask = LLVMBuildNot(builder, ctx->switch_mask_default, "sw_default_mask");
defaultmask = LLVMBuildOr(builder, defaultmask, mask->switch_mask, "");
mask->switch_mask = LLVMBuildAnd(builder, prevmask, defaultmask, "sw_mask");
- mask->switch_in_default = true;
+ ctx->switch_in_default = true;
lp_exec_mask_update(mask);
}
* default (or could do switch analysis at switch start time instead).
*/
unsigned opcode = bld_base->instructions[bld_base->pc - 1].Instruction.Opcode;
- boolean ft_into = (opcode != TGSI_OPCODE_BRK ||
+ boolean ft_into = (opcode != TGSI_OPCODE_BRK &&
opcode != TGSI_OPCODE_SWITCH);
/*
* If it is not last statement and there was no fallthrough into it,
* do the same as with the former case, except instead of skipping the code
* just execute it without updating the mask, then go back and re-execute.
*/
- mask->switch_pc = bld_base->pc;
+ ctx->switch_pc = bld_base->pc;
if (!ft_into) {
bld_base->pc = default_exec_pc;
}
int func,
int *pc)
{
- assert(mask->call_stack_size < LP_MAX_TGSI_NESTING);
- mask->call_stack[mask->call_stack_size].pc = *pc;
- mask->call_stack[mask->call_stack_size].ret_mask = mask->ret_mask;
- mask->call_stack_size++;
+ if (mask->function_stack_size >= LP_MAX_NUM_FUNCS) {
+ return;
+ }
+
+ lp_exec_mask_function_init(mask, mask->function_stack_size);
+ mask->function_stack[mask->function_stack_size].pc = *pc;
+ mask->function_stack[mask->function_stack_size].ret_mask = mask->ret_mask;
+ mask->function_stack_size++;
*pc = func;
}
static void lp_exec_mask_ret(struct lp_exec_mask *mask, int *pc)
{
LLVMBuilderRef builder = mask->bld->gallivm->builder;
+ struct function_ctx *ctx = func_ctx(mask);
LLVMValueRef exec_mask;
- if (mask->cond_stack_size == 0 &&
- mask->loop_stack_size == 0 &&
- mask->switch_stack_size == 0 &&
- mask->call_stack_size == 0) {
+ if (ctx->cond_stack_size == 0 &&
+ ctx->loop_stack_size == 0 &&
+ ctx->switch_stack_size == 0 &&
+ mask->function_stack_size == 1) {
/* returning from main() */
*pc = -1;
return;
}
- if (mask->call_stack_size == 0) {
+ if (mask->function_stack_size == 1) {
/*
* This requires special handling since we need to ensure
* we don't drop the mask even if we have no call stack
static void lp_exec_mask_endsub(struct lp_exec_mask *mask, int *pc)
{
- assert(mask->call_stack_size);
- mask->call_stack_size--;
- *pc = mask->call_stack[mask->call_stack_size].pc;
- mask->ret_mask = mask->call_stack[mask->call_stack_size].ret_mask;
+ struct function_ctx *ctx;
+
+ assert(mask->function_stack_size > 1);
+ assert(mask->function_stack_size <= LP_MAX_NUM_FUNCS);
+
+ ctx = func_ctx(mask);
+ mask->function_stack_size--;
+
+ *pc = ctx->pc;
+ mask->ret_mask = ctx->ret_mask;
+
lp_exec_mask_update(mask);
}
LLVMBuilderRef builder = gallivm->builder;
struct lp_build_context *uint_bld = &bld_base->uint_bld;
unsigned dimension = 0;
- LLVMValueRef dimension_index;
LLVMValueRef consts_ptr;
LLVMValueRef num_consts;
LLVMValueRef res;
assert(dimension < LP_MAX_TGSI_CONST_BUFFERS);
}
- dimension_index = lp_build_const_int32(gallivm, dimension);
- consts_ptr =
- lp_build_array_get(gallivm, bld->consts_ptr, dimension_index);
- num_consts =
- lp_build_array_get(gallivm, bld->const_sizes_ptr, dimension_index);
+ consts_ptr = bld->consts[dimension];
+ num_consts = bld->consts_sizes[dimension];
if (reg->Register.Indirect) {
LLVMValueRef indirect_index;
LLVMBuilderRef builder = gallivm->builder;
LLVMValueRef res = NULL;
- if (reg->Register.Indirect) {
- LLVMValueRef indirect_index;
- LLVMValueRef index_vec; /* index into the immediate register array */
+ if (bld->use_immediates_array || reg->Register.Indirect) {
LLVMValueRef imms_array;
LLVMTypeRef fptr_type;
- indirect_index = get_indirect_index(bld,
- reg->Register.File,
- reg->Register.Index,
- ®->Indirect);
- /*
- * Unlike for other reg classes, adding pixel offsets is unnecessary -
- * immediates are stored as full vectors (FIXME??? - might be better
- * to store them the same as constants) but all elements are the same
- * in any case.
- */
- index_vec = get_soa_array_offsets(&bld_base->uint_bld,
- indirect_index,
- swizzle,
- FALSE);
-
/* cast imms_array pointer to float* */
fptr_type = LLVMPointerType(LLVMFloatTypeInContext(gallivm->context), 0);
imms_array = LLVMBuildBitCast(builder, bld->imms_array, fptr_type, "");
- /* Gather values from the immediate register array */
- res = build_gather(&bld_base->base, imms_array, index_vec, NULL);
+ if (reg->Register.Indirect) {
+ LLVMValueRef indirect_index;
+ LLVMValueRef index_vec; /* index into the immediate register array */
+
+ indirect_index = get_indirect_index(bld,
+ reg->Register.File,
+ reg->Register.Index,
+ ®->Indirect);
+ /*
+ * Unlike for other reg classes, adding pixel offsets is unnecessary -
+ * immediates are stored as full vectors (FIXME??? - might be better
+ * to store them the same as constants) but all elements are the same
+ * in any case.
+ */
+ index_vec = get_soa_array_offsets(&bld_base->uint_bld,
+ indirect_index,
+ swizzle,
+ FALSE);
+
+ /* Gather values from the immediate register array */
+ res = build_gather(&bld_base->base, imms_array, index_vec, NULL);
+ } else {
+ LLVMValueRef lindex = lp_build_const_int32(gallivm,
+ reg->Register.Index * 4 + swizzle);
+ LLVMValueRef imms_ptr = LLVMBuildGEP(builder,
+ bld->imms_array, &lindex, 1, "");
+ res = LLVMBuildLoad(builder, imms_ptr, "");
+ }
}
else {
res = bld->immediates[reg->Register.Index][swizzle];
{
struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
struct gallivm_state *gallivm = bld->bld_base.base.gallivm;
+ const struct tgsi_shader_info *info = bld->bld_base.info;
LLVMBuilderRef builder = gallivm->builder;
LLVMValueRef attrib_index = NULL;
LLVMValueRef vertex_index = NULL;
LLVMValueRef swizzle_index = lp_build_const_int32(gallivm, swizzle);
LLVMValueRef res;
+ if (info->input_semantic_name[reg->Register.Index] == TGSI_SEMANTIC_PRIMID) {
+ /* This is really a system value not a regular input */
+ assert(!reg->Register.Indirect);
+ assert(!reg->Dimension.Indirect);
+ res = bld->system_values.prim_id;
+ if (stype != TGSI_TYPE_UNSIGNED && stype != TGSI_TYPE_SIGNED) {
+ res = LLVMBuildBitCast(builder, res, bld_base->base.vec_type, "");
+ }
+ return res;
+ }
+
if (reg->Register.Indirect) {
attrib_index = get_indirect_index(bld,
reg->Register.File,
assert(dtype == TGSI_TYPE_FLOAT ||
dtype == TGSI_TYPE_UNTYPED);
value = LLVMBuildBitCast(builder, value, float_bld->vec_type, "");
- /*Â This will give -1.0 for NaN which is probably not what we want. */
+ /* This will give -1.0 for NaN which is probably not what we want. */
value = lp_build_max_ext(float_bld, value,
lp_build_const_vec(gallivm, float_bld->type, -1.0),
GALLIVM_NAN_RETURN_OTHER_SECOND_NONNAN);
emit_tex( struct lp_build_tgsi_soa_context *bld,
const struct tgsi_full_instruction *inst,
enum lp_build_tex_modifier modifier,
- LLVMValueRef *texel)
+ LLVMValueRef *texel,
+ unsigned sampler_reg)
{
- unsigned unit;
+ unsigned unit = inst->Src[sampler_reg].Register.Index;
LLVMValueRef lod_bias, explicit_lod;
LLVMValueRef oow = NULL;
LLVMValueRef coords[5];
num_derivs = 3;
break;
case TGSI_TEXTURE_CUBE_ARRAY:
+ num_offsets = 2;
+ num_derivs = 3;
+ layer_coord = 3;
+ break;
case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
+ num_offsets = 2;
+ num_derivs = 3;
+ layer_coord = 3;
+ shadow_coord = 4; /* shadow coord special different reg */
+ break;
case TGSI_TEXTURE_2D_MSAA:
case TGSI_TEXTURE_2D_ARRAY_MSAA:
default:
/* Note lod and especially projected are illegal in a LOT of cases */
if (modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
- LLVMValueRef lod = lp_build_emit_fetch(&bld->bld_base, inst, 0, 3);
+ LLVMValueRef lod;
+ if (inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE ||
+ inst->Texture.Texture == TGSI_TEXTURE_CUBE_ARRAY) {
+ /* note that shadow cube array with bias/explicit lod does not exist */
+ lod = lp_build_emit_fetch(&bld->bld_base, inst, 1, 0);
+ }
+ else {
+ lod = lp_build_emit_fetch(&bld->bld_base, inst, 0, 3);
+ }
if (modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS) {
lod_bias = lod;
explicit_lod = NULL;
/* Layer coord always goes into 3rd slot, except for cube map arrays */
if (layer_coord) {
- coords[2] = lp_build_emit_fetch(&bld->bld_base, inst, 0, layer_coord);
+ if (layer_coord == 3) {
+ coords[3] = lp_build_emit_fetch(&bld->bld_base, inst, 0, layer_coord);
+ }
+ else {
+ coords[2] = lp_build_emit_fetch(&bld->bld_base, inst, 0, layer_coord);
+ }
if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED)
coords[2] = lp_build_mul(&bld->bld_base.base, coords[2], oow);
}
/* Shadow coord occupies always 5th slot. */
if (shadow_coord) {
- coords[4] = lp_build_emit_fetch(&bld->bld_base, inst, 0, shadow_coord);
+ if (shadow_coord == 4) {
+ coords[4] = lp_build_emit_fetch(&bld->bld_base, inst, 1, 0);
+ }
+ else {
+ coords[4] = lp_build_emit_fetch(&bld->bld_base, inst, 0, shadow_coord);
+ }
if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED)
coords[4] = lp_build_mul(&bld->bld_base.base, coords[4], oow);
}
derivs.ddy[dim] = lp_build_emit_fetch(&bld->bld_base, inst, 2, dim);
}
deriv_ptr = &derivs;
- unit = inst->Src[3].Register.Index;
/*
* could also check all src regs if constant but I doubt such
* cases exist in practice.
else {
lod_property = LP_SAMPLER_LOD_PER_ELEMENT;
}
- } else {
- unit = inst->Src[1].Register.Index;
}
/* some advanced gather instructions (txgo) would require 4 offsets */
bld->bld_base.base.gallivm,
bld->bld_base.int_bld.type,
unit, pipe_target,
- is_sviewinfo,
+ TRUE,
lod_property,
explicit_lod,
sizes_out);
static boolean
near_end_of_shader(struct lp_build_tgsi_soa_context *bld,
- int pc)
+ int pc)
{
int i;
unsigned opcode;
if (pc + i >= bld->bld_base.info->num_instructions)
- return TRUE;
+ return TRUE;
opcode = bld->bld_base.instructions[pc + i].Instruction.Opcode;
if (opcode == TGSI_OPCODE_END)
- return TRUE;
+ return TRUE;
if (opcode == TGSI_OPCODE_TEX ||
- opcode == TGSI_OPCODE_TXP ||
- opcode == TGSI_OPCODE_TXD ||
- opcode == TGSI_OPCODE_TXB ||
- opcode == TGSI_OPCODE_TXL ||
- opcode == TGSI_OPCODE_TXF ||
- opcode == TGSI_OPCODE_TXQ ||
- opcode == TGSI_OPCODE_CAL ||
- opcode == TGSI_OPCODE_CALLNZ ||
- opcode == TGSI_OPCODE_IF ||
- opcode == TGSI_OPCODE_UIF ||
- opcode == TGSI_OPCODE_BGNLOOP ||
- opcode == TGSI_OPCODE_SWITCH)
- return FALSE;
+ opcode == TGSI_OPCODE_TXP ||
+ opcode == TGSI_OPCODE_TXD ||
+ opcode == TGSI_OPCODE_TXB ||
+ opcode == TGSI_OPCODE_TXL ||
+ opcode == TGSI_OPCODE_TXF ||
+ opcode == TGSI_OPCODE_TXQ ||
+ opcode == TGSI_OPCODE_TEX2 ||
+ opcode == TGSI_OPCODE_TXB2 ||
+ opcode == TGSI_OPCODE_TXL2 ||
+ opcode == TGSI_OPCODE_SAMPLE ||
+ opcode == TGSI_OPCODE_SAMPLE_B ||
+ opcode == TGSI_OPCODE_SAMPLE_C ||
+ opcode == TGSI_OPCODE_SAMPLE_C_LZ ||
+ opcode == TGSI_OPCODE_SAMPLE_D ||
+ opcode == TGSI_OPCODE_SAMPLE_I ||
+ opcode == TGSI_OPCODE_SAMPLE_L ||
+ opcode == TGSI_OPCODE_SVIEWINFO ||
+ opcode == TGSI_OPCODE_CAL ||
+ opcode == TGSI_OPCODE_CALLNZ ||
+ opcode == TGSI_OPCODE_IF ||
+ opcode == TGSI_OPCODE_UIF ||
+ opcode == TGSI_OPCODE_BGNLOOP ||
+ opcode == TGSI_OPCODE_SWITCH)
+ return FALSE;
}
return TRUE;
const unsigned last = decl->Range.Last;
unsigned idx, i;
- for (idx = first; idx <= last; ++idx) {
- assert(last <= bld->bld_base.info->file_max[decl->Declaration.File]);
- switch (decl->Declaration.File) {
- case TGSI_FILE_TEMPORARY:
- assert(idx < LP_MAX_TGSI_TEMPS);
- if (!(bld->indirect_files & (1 << TGSI_FILE_TEMPORARY))) {
+ assert(last <= bld->bld_base.info->file_max[decl->Declaration.File]);
+
+ switch (decl->Declaration.File) {
+ case TGSI_FILE_TEMPORARY:
+ if (!(bld->indirect_files & (1 << TGSI_FILE_TEMPORARY))) {
+ assert(last < LP_MAX_INLINED_TEMPS);
+ for (idx = first; idx <= last; ++idx) {
for (i = 0; i < TGSI_NUM_CHANNELS; i++)
bld->temps[idx][i] = lp_build_alloca(gallivm, vec_type, "temp");
}
- break;
+ }
+ break;
- case TGSI_FILE_OUTPUT:
- if (!(bld->indirect_files & (1 << TGSI_FILE_OUTPUT))) {
+ case TGSI_FILE_OUTPUT:
+ if (!(bld->indirect_files & (1 << TGSI_FILE_OUTPUT))) {
+ for (idx = first; idx <= last; ++idx) {
for (i = 0; i < TGSI_NUM_CHANNELS; i++)
bld->outputs[idx][i] = lp_build_alloca(gallivm,
vec_type, "output");
}
- break;
+ }
+ break;
- case TGSI_FILE_ADDRESS:
- /* ADDR registers are only allocated with an integer LLVM IR type,
- * as they are guaranteed to always have integers.
- * XXX: Not sure if this exception is worthwhile (or the whole idea of
- * an ADDR register for that matter).
- */
+ case TGSI_FILE_ADDRESS:
+ /* ADDR registers are only allocated with an integer LLVM IR type,
+ * as they are guaranteed to always have integers.
+ * XXX: Not sure if this exception is worthwhile (or the whole idea of
+ * an ADDR register for that matter).
+ */
+ assert(last < LP_MAX_TGSI_ADDRS);
+ for (idx = first; idx <= last; ++idx) {
assert(idx < LP_MAX_TGSI_ADDRS);
for (i = 0; i < TGSI_NUM_CHANNELS; i++)
bld->addr[idx][i] = lp_build_alloca(gallivm, bld_base->base.int_vec_type, "addr");
- break;
+ }
+ break;
- case TGSI_FILE_PREDICATE:
- assert(idx < LP_MAX_TGSI_PREDS);
+ case TGSI_FILE_PREDICATE:
+ assert(last < LP_MAX_TGSI_PREDS);
+ for (idx = first; idx <= last; ++idx) {
for (i = 0; i < TGSI_NUM_CHANNELS; i++)
bld->preds[idx][i] = lp_build_alloca(gallivm, vec_type,
"predicate");
- break;
+ }
+ break;
- case TGSI_FILE_SAMPLER_VIEW:
- /*
- * The target stored here MUST match whatever there actually
- * is in the set sampler views (what about return type?).
- */
- assert(idx < PIPE_MAX_SHADER_SAMPLER_VIEWS);
+ case TGSI_FILE_SAMPLER_VIEW:
+ /*
+ * The target stored here MUST match whatever there actually
+ * is in the set sampler views (what about return type?).
+ */
+ assert(last < PIPE_MAX_SHADER_SAMPLER_VIEWS);
+ for (idx = first; idx <= last; ++idx) {
bld->sv[idx] = decl->SamplerView;
- break;
-
- default:
- /* don't need to declare other vars */
- break;
}
+ break;
+
+ case TGSI_FILE_CONSTANT:
+ {
+ /*
+ * We could trivially fetch the per-buffer pointer when fetching the
+ * constant, relying on llvm to figure out it's always the same pointer
+ * anyway. However, doing so results in a huge (more than factor of 10)
+ * slowdown in llvm compilation times for some (but not all) shaders
+ * (more specifically, the IR optimization spends way more time in
+ * DominatorTree::dominates). At least with llvm versions 3.1, 3.3.
+ */
+ unsigned idx2D = decl->Dim.Index2D;
+ LLVMValueRef index2D = lp_build_const_int32(gallivm, idx2D);
+ assert(idx2D < LP_MAX_TGSI_CONST_BUFFERS);
+ bld->consts[idx2D] =
+ lp_build_array_get(gallivm, bld->consts_ptr, index2D);
+ bld->consts_sizes[idx2D] =
+ lp_build_array_get(gallivm, bld->const_sizes_ptr, index2D);
+ }
+ break;
+
+ default:
+ /* don't need to declare other vars */
+ break;
}
}
{
struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
struct gallivm_state * gallivm = bld_base->base.gallivm;
-
- /* simply copy the immediate values into the next immediates[] slot */
+ LLVMValueRef imms[4];
unsigned i;
const uint size = imm->Immediate.NrTokens - 1;
assert(size <= 4);
- assert(bld->num_immediates < LP_MAX_TGSI_IMMEDIATES);
switch (imm->Immediate.DataType) {
case TGSI_IMM_FLOAT32:
for( i = 0; i < size; ++i )
- bld->immediates[bld->num_immediates][i] =
- lp_build_const_vec(gallivm, bld_base->base.type, imm->u[i].Float);
+ imms[i] =
+ lp_build_const_vec(gallivm, bld_base->base.type, imm->u[i].Float);
break;
case TGSI_IMM_UINT32:
for( i = 0; i < size; ++i ) {
LLVMValueRef tmp = lp_build_const_vec(gallivm, bld_base->uint_bld.type, imm->u[i].Uint);
- bld->immediates[bld->num_immediates][i] =
- LLVMConstBitCast(tmp, bld_base->base.vec_type);
+ imms[i] = LLVMConstBitCast(tmp, bld_base->base.vec_type);
}
break;
case TGSI_IMM_INT32:
for( i = 0; i < size; ++i ) {
LLVMValueRef tmp = lp_build_const_vec(gallivm, bld_base->int_bld.type, imm->u[i].Int);
- bld->immediates[bld->num_immediates][i] =
- LLVMConstBitCast(tmp, bld_base->base.vec_type);
+ imms[i] = LLVMConstBitCast(tmp, bld_base->base.vec_type);
}
-
+
break;
}
for( i = size; i < 4; ++i )
- bld->immediates[bld->num_immediates][i] = bld_base->base.undef;
+ imms[i] = bld_base->base.undef;
- if (bld->indirect_files & (1 << TGSI_FILE_IMMEDIATE)) {
+ if (bld->use_immediates_array) {
unsigned index = bld->num_immediates;
struct gallivm_state *gallivm = bld->bld_base.base.gallivm;
LLVMBuilderRef builder = gallivm->builder;
+
+ assert(bld->indirect_files & (1 << TGSI_FILE_IMMEDIATE));
for (i = 0; i < 4; ++i ) {
LLVMValueRef lindex = lp_build_const_int32(
- bld->bld_base.base.gallivm, index * 4 + i);
+ bld->bld_base.base.gallivm, index * 4 + i);
LLVMValueRef imm_ptr = LLVMBuildGEP(builder,
bld->imms_array, &lindex, 1, "");
- LLVMBuildStore(builder,
- bld->immediates[index][i],
- imm_ptr);
+ LLVMBuildStore(builder, imms[i], imm_ptr);
+ }
+ } else {
+ /* simply copy the immediate values into the next immediates[] slot */
+ unsigned i;
+ const uint size = imm->Immediate.NrTokens - 1;
+ assert(size <= 4);
+ assert(bld->num_immediates < LP_MAX_INLINED_IMMEDIATES);
+
+ for(i = 0; i < 4; ++i )
+ bld->immediates[bld->num_immediates][i] = imms[i];
+
+ if (bld->indirect_files & (1 << TGSI_FILE_IMMEDIATE)) {
+ unsigned index = bld->num_immediates;
+ struct gallivm_state *gallivm = bld->bld_base.base.gallivm;
+ LLVMBuilderRef builder = gallivm->builder;
+ for (i = 0; i < 4; ++i ) {
+ LLVMValueRef lindex = lp_build_const_int32(
+ bld->bld_base.base.gallivm, index * 4 + i);
+ LLVMValueRef imm_ptr = LLVMBuildGEP(builder,
+ bld->imms_array, &lindex, 1, "");
+ LLVMBuildStore(builder,
+ bld->immediates[index][i],
+ imm_ptr);
+ }
}
}
{
struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
- emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_NONE, emit_data->output);
+ emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_NONE,
+ emit_data->output, 1);
+}
+
+static void
+tex2_emit(
+ const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
+
+ emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_NONE,
+ emit_data->output, 2);
}
static void
struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_LOD_BIAS,
- emit_data->output);
+ emit_data->output, 1);
+}
+
+static void
+txb2_emit(
+ const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
+
+ emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_LOD_BIAS,
+ emit_data->output, 2);
}
static void
struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV,
- emit_data->output);
+ emit_data->output, 3);
}
static void
struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD,
- emit_data->output);
+ emit_data->output, 1);
+}
+
+static void
+txl2_emit(
+ const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
+
+ emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD,
+ emit_data->output, 2);
}
static void
struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_PROJECTED,
- emit_data->output);
+ emit_data->output, 1);
}
static void
if (DEBUG_EXECUTION) {
lp_build_printf(gallivm, "\n");
emit_dump_file(bld, TGSI_FILE_CONSTANT);
- emit_dump_file(bld, TGSI_FILE_INPUT);
+ if (!bld->gs_iface)
+ emit_dump_file(bld, TGSI_FILE_INPUT);
}
}
bld.bld_base.info = info;
bld.indirect_files = info->indirect_files;
+ /*
+ * If the number of temporaries is rather large then we just
+ * allocate them as an array right from the start and treat
+ * like indirect temporaries.
+ */
+ if (info->file_max[TGSI_FILE_TEMPORARY] >= LP_MAX_INLINED_TEMPS) {
+ bld.indirect_files |= (1 << TGSI_FILE_TEMPORARY);
+ }
+ /*
+ * For performance reason immediates are always backed in a static
+ * array, but if their number is too great, we have to use just
+ * a dynamically allocated array.
+ */
+ bld.use_immediates_array =
+ (info->file_max[TGSI_FILE_IMMEDIATE] >= LP_MAX_INLINED_IMMEDIATES);
+ if (bld.use_immediates_array) {
+ bld.indirect_files |= (1 << TGSI_FILE_IMMEDIATE);
+ }
+
+
bld.bld_base.soa = TRUE;
bld.bld_base.emit_debug = emit_debug;
bld.bld_base.emit_fetch_funcs[TGSI_FILE_CONSTANT] = emit_fetch_constant;
bld.bld_base.op_actions[TGSI_OPCODE_TXP].emit = txp_emit;
bld.bld_base.op_actions[TGSI_OPCODE_TXQ].emit = txq_emit;
bld.bld_base.op_actions[TGSI_OPCODE_TXF].emit = txf_emit;
+ bld.bld_base.op_actions[TGSI_OPCODE_TEX2].emit = tex2_emit;
+ bld.bld_base.op_actions[TGSI_OPCODE_TXB2].emit = txb2_emit;
+ bld.bld_base.op_actions[TGSI_OPCODE_TXL2].emit = txl2_emit;
/* DX10 sampling ops */
bld.bld_base.op_actions[TGSI_OPCODE_SAMPLE].emit = sample_emit;
bld.bld_base.op_actions[TGSI_OPCODE_SAMPLE_B].emit = sample_b_emit;
LLVMDumpModule(module);
}
+ lp_exec_mask_fini(&bld.exec_mask);
}