summaryrefslogtreecommitdiff
path: root/src/mesa/shader
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-07-13 12:22:05 -0700
committerEric Anholt <eric@anholt.net>2010-07-18 18:13:06 -0700
commit7b130149427019ac9ae6d39b6871c14fb6ba2dad (patch)
treeb253642996ebc3556257637bc81c3e839cecb0fc /src/mesa/shader
parent1f47245bdda2c85bf0f0174e6c24a50486b413aa (diff)
ir_to_mesa: Add support for function calls.
Unlike the previous compiler, in this case we emit only one copy of the function regardless of how many times it's called.
Diffstat (limited to 'src/mesa/shader')
-rw-r--r--src/mesa/shader/ir_to_mesa.cpp233
1 files changed, 227 insertions, 6 deletions
diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp
index f99a1fc450..6d1837f59e 100644
--- a/src/mesa/shader/ir_to_mesa.cpp
+++ b/src/mesa/shader/ir_to_mesa.cpp
@@ -87,6 +87,8 @@ public:
int sampler; /**< sampler index */
int tex_target; /**< One of TEXTURE_*_INDEX */
GLboolean tex_shadow;
+
+ class function_entry *function; /* Set on OPCODE_CAL or OPCODE_BGNSUB */
};
class temp_entry : public exec_node {
@@ -102,10 +104,45 @@ public:
ir_variable *var; /* variable that maps to this, if any */
};
+class function_entry : public exec_node {
+public:
+ ir_function_signature *sig;
+
+ /**
+ * identifier of this function signature used by the program.
+ *
+ * At the point that Mesa instructions for function calls are
+ * generated, we don't know the address of the first instruction of
+ * the function body. So we make the BranchTarget that is called a
+ * small integer and rewrite them during set_branchtargets().
+ */
+ int sig_id;
+
+ /**
+ * Pointer to first instruction of the function body.
+ *
+ * Set during function body emits after main() is processed.
+ */
+ ir_to_mesa_instruction *bgn_inst;
+
+ /**
+ * Index of the first instruction of the function body in actual
+ * Mesa IR.
+ *
+ * Set after convertion from ir_to_mesa_instruction to prog_instruction.
+ */
+ int inst;
+
+ /** Storage for the return value. */
+ ir_to_mesa_src_reg return_reg;
+};
+
class ir_to_mesa_visitor : public ir_visitor {
public:
ir_to_mesa_visitor();
+ function_entry *current_function;
+
GLcontext *ctx;
struct gl_program *prog;
@@ -113,6 +150,8 @@ public:
temp_entry *find_variable_storage(ir_variable *var);
+ function_entry *get_function_signature(ir_function_signature *sig);
+
ir_to_mesa_src_reg get_temp(const glsl_type *type);
void reladdr_to_temp(ir_instruction *ir,
ir_to_mesa_src_reg *reg, int *num_reladdr);
@@ -151,6 +190,10 @@ public:
/** List of temp_entry */
exec_list variable_storage;
+ /** List of function_entry */
+ exec_list function_signatures;
+ int next_signature_id;
+
/** List of ir_to_mesa_instruction */
exec_list instructions;
@@ -261,6 +304,8 @@ ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
inst->src_reg[2] = src2;
inst->ir = ir;
+ inst->function = NULL;
+
this->instructions.push_tail(inst);
return inst;
@@ -1396,12 +1441,128 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
this->result = src_reg;
}
+function_entry *
+ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig)
+{
+ function_entry *entry;
+
+ foreach_iter(exec_list_iterator, iter, this->function_signatures) {
+ entry = (function_entry *)iter.get();
+
+ if (entry->sig == sig)
+ return entry;
+ }
+
+ entry = talloc(mem_ctx, function_entry);
+ entry->sig = sig;
+ entry->sig_id = this->next_signature_id++;
+ entry->bgn_inst = NULL;
+
+ /* Allocate storage for all the parameters. */
+ foreach_iter(exec_list_iterator, iter, sig->parameters) {
+ ir_variable *param = (ir_variable *)iter.get();
+ temp_entry *storage;
+
+ storage = find_variable_storage(param);
+ assert(!storage);
+
+ storage = new(mem_ctx) temp_entry(param, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variable_storage.push_tail(storage);
+
+ this->next_temp += type_size(param->type);
+ break;
+ }
+
+ if (sig->return_type) {
+ entry->return_reg = get_temp(sig->return_type);
+ } else {
+ entry->return_reg = ir_to_mesa_undef;
+ }
+
+ this->function_signatures.push_tail(entry);
+ return entry;
+}
void
ir_to_mesa_visitor::visit(ir_call *ir)
{
- printf("Can't support call to %s\n", ir->callee_name());
- exit(1);
+ ir_to_mesa_instruction *call_inst;
+ ir_function_signature *sig = ir->get_callee();
+ function_entry *entry = get_function_signature(sig);
+ int i;
+
+ /* Process in parameters. */
+ exec_list_iterator sig_iter = sig->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *param = (ir_variable *)sig_iter.get();
+
+ if (param->mode == ir_var_in ||
+ param->mode == ir_var_inout) {
+ temp_entry *storage = find_variable_storage(param);
+ assert(storage);
+
+ param_rval->accept(this);
+ ir_to_mesa_src_reg r = this->result;
+
+ ir_to_mesa_dst_reg l;
+ l.file = storage->file;
+ l.index = storage->index;
+ l.reladdr = NULL;
+ l.writemask = WRITEMASK_XYZW;
+ l.cond_mask = COND_TR;
+
+ for (i = 0; i < type_size(param->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ sig_iter.next();
+ }
+ assert(!sig_iter.has_next());
+
+ /* Emit call instruction */
+ call_inst = ir_to_mesa_emit_op1(ir, OPCODE_CAL,
+ ir_to_mesa_undef_dst, ir_to_mesa_undef);
+ call_inst->function = entry;
+
+ /* Process out parameters. */
+ sig_iter = sig->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *param = (ir_variable *)sig_iter.get();
+
+ if (param->mode == ir_var_out ||
+ param->mode == ir_var_inout) {
+ temp_entry *storage = find_variable_storage(param);
+ assert(storage);
+
+ ir_to_mesa_src_reg r;
+ r.file = storage->file;
+ r.index = storage->index;
+ r.reladdr = NULL;
+ r.swizzle = SWIZZLE_NOOP;
+ r.negate = 0;
+
+ param_rval->accept(this);
+ ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result);
+
+ for (i = 0; i < type_size(param->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ sig_iter.next();
+ }
+ assert(!sig_iter.has_next());
+
+ /* Process return value. */
+ this->result = entry->return_reg;
}
@@ -1536,9 +1697,25 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
void
ir_to_mesa_visitor::visit(ir_return *ir)
{
- assert(0);
+ assert(current_function);
+
+ if (ir->get_value()) {
+ ir_to_mesa_dst_reg l;
+ int i;
+
+ ir->get_value()->accept(this);
+ ir_to_mesa_src_reg r = this->result;
- ir->get_value()->accept(this);
+ l = ir_to_mesa_dst_reg_from_src(current_function->return_reg);
+
+ for (i = 0; i < type_size(current_function->sig->return_type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ ir_to_mesa_emit_op0(ir, OPCODE_RET);
}
void
@@ -1600,8 +1777,10 @@ ir_to_mesa_visitor::ir_to_mesa_visitor()
{
result.file = PROGRAM_UNDEFINED;
next_temp = 1;
+ next_signature_id = 1;
sampler_map = NULL;
sampler_map_size = 0;
+ current_function = NULL;
}
static struct prog_src_register
@@ -1621,7 +1800,8 @@ mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
}
static void
-set_branchtargets(struct prog_instruction *mesa_instructions,
+set_branchtargets(ir_to_mesa_visitor *v,
+ struct prog_instruction *mesa_instructions,
int num_instructions)
{
int if_count = 0, loop_count = 0;
@@ -1684,6 +1864,17 @@ set_branchtargets(struct prog_instruction *mesa_instructions,
/* The loop ends point at each other. */
mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
+ break;
+ case OPCODE_CAL:
+ foreach_iter(exec_list_iterator, iter, v->function_signatures) {
+ function_entry *entry = (function_entry *)iter.get();
+
+ if (entry->sig_id == mesa_instructions[i].BranchTarget) {
+ mesa_instructions[i].BranchTarget = entry->inst;
+ break;
+ }
+ }
+ break;
default:
break;
}
@@ -1842,6 +2033,7 @@ get_mesa_program(GLcontext *ctx, void *mem_ctx, struct gl_shader *shader)
int i;
struct gl_program *prog;
GLenum target;
+ GLboolean progress;
switch (shader->Type) {
case GL_VERTEX_SHADER: target = GL_VERTEX_PROGRAM_ARB; break;
@@ -1859,9 +2051,33 @@ get_mesa_program(GLcontext *ctx, void *mem_ctx, struct gl_shader *shader)
v.prog = prog;
v.mem_ctx = talloc_new(NULL);
+
+ /* Emit Mesa IR for main(). */
visit_exec_list(shader->ir, &v);
v.ir_to_mesa_emit_op0(NULL, OPCODE_END);
+ /* Now emit bodies for any functions that were used. */
+ do {
+ progress = GL_FALSE;
+
+ foreach_iter(exec_list_iterator, iter, v.function_signatures) {
+ function_entry *entry = (function_entry *)iter.get();
+
+ if (!entry->bgn_inst) {
+ v.current_function = entry;
+
+ entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB);
+ entry->bgn_inst->function = entry;
+
+ visit_exec_list(&entry->sig->body, &v);
+
+ entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_RET);
+ entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB);
+ progress = GL_TRUE;
+ }
+ }
+ } while (progress);
+
prog->NumTemporaries = v.next_temp;
int num_instructions = 0;
@@ -1895,11 +2111,16 @@ get_mesa_program(GLcontext *ctx, void *mem_ctx, struct gl_shader *shader)
mesa_inst->TexShadow = inst->tex_shadow;
mesa_instruction_annotation[i] = inst->ir;
+ if (mesa_inst->Opcode == OPCODE_BGNSUB)
+ inst->function->inst = i;
+ else if (mesa_inst->Opcode == OPCODE_CAL)
+ mesa_inst->BranchTarget = inst->function->sig_id; /* rewritten later */
+
mesa_inst++;
i++;
}
- set_branchtargets(mesa_instructions, num_instructions);
+ set_branchtargets(&v, mesa_instructions, num_instructions);
if (0) {
print_program(mesa_instructions, mesa_instruction_annotation,
num_instructions);