and expression temporarires. Much better register utilization now.
Lots of other fixes.
The OpenGL GLSL "orange book" brick shader demo works now.
#include "slang_error.h"
#include "slang_simplify.h"
#include "slang_emit.h"
+#include "slang_vartable.h"
#include "slang_ir.h"
#include "mtypes.h"
#include "program.h"
* 4. other?
*/
static void
-slang_allocate_storage(slang_gen_context *gc, slang_ir_node *n,
- struct gl_program *prog)
+slang_allocate_storage(slang_assemble_ctx *A, slang_ir_node *n)
{
- assert(gc);
+ struct gl_program *prog = A->program;
+ assert(A->vartable);
assert(n);
assert(n->Opcode == IR_VAR_DECL || n->Opcode == IR_VAR);
assert(prog);
/* variable declaration */
assert(n->Var);
assert(!is_sampler_type(&n->Var->type));
- printf("Alloc storage for %p %s:\n", (void*) n->Var, (char*) n->Var->a_name);
- /*
- assert(n->Store->Index < 0);
- */
n->Store->File = PROGRAM_TEMPORARY;
n->Store->Size = _slang_sizeof_type_specifier(&n->Var->type.specifier);
assert(n->Store->Size > 0);
- if (n->Store->Index < 0)
- n->Store->Index = _slang_alloc_temporary(gc, n->Store->Size);
- printf(" Location = %d\n", n->Store->Index);
- /*
- printf("alloc var %s storage at %d (size %d)\n",
- (char *) n->Var->a_name,
- n->Store->Index,
- n->Store->Size);
- */
- assert(n->Store->Size > 0);
- n->Var->declared = GL_TRUE;
return;
}
+#if 00
if (n->Store->File == PROGRAM_UNDEFINED) {
printf("*** Var %s size %d\n", (char*) n->Var->a_name, n->Store->Size);
-
assert(n->Store->File != PROGRAM_UNDEFINED);
}
+#endif
+ /**
+ ** XXX this all has to be redone
+ **/
if (n->Store->Index < 0) {
/* determine storage location for this var */
}
else {
/* what's this??? */
- abort();
}
}
}
};
-#if 000 /* prototype for future symbol table scheme */
-
-#define MAX_DEPTH 100
-static slang_variable_scope *Stack[MAX_DEPTH];
-static int CurDepth;
-
-static void
-_slang_push_scope(slang_variable_scope *scope)
-{
- Stack[CurDepth++] = scope;
- assert(CurDepth < MAX_DEPTH);
-}
-
-static void
-_slang_pop_scope(void)
-{
- CurDepth--;
- assert(CurDepth >= 0);
-}
-
-static slang_variable_scope *
-_slang_current_scope(void)
-{
- if (CurDepth > 0)
- return Stack[CurDepth - 1];
- else
- return NULL;
-}
-
-static slang_variable *
-_slang_find_variable(slang_atom name)
-{
- int i;
- for (i = CurDepth - 1; i >= 0; i--) {
- int j;
- for (j = 0; j < Stack[i]->num_variables; j++) {
- if (Stack[i]->variables[j].a_name == name) {
- return Stack[i]->variables + j;
- }
- }
- }
- return NULL;
-}
-
-#endif
-
-
-
/**
* Recursively free an IR tree.
*/
printf("VAR NOT FOUND %s\n", (char *) name);
assert(v);
}
- /**
- assert(v->declared);
- **/
assert(!oper->var || oper->var == v);
v->used = GL_TRUE;
- oper->var = v;
+
n->Swizzle = swizzle;
n->Var = v;
- slang_allocate_storage(A->codegen, n, A->program);
+
+ slang_allocate_storage(A, n);
+
return n;
}
/**
- * Check if the given function is really just a wrapper for an
+ * Check if the given function is really just a wrapper for a
* basic assembly instruction.
*/
static GLboolean
slang_operation *inlined = slang_operation_new(1);
/*assert(oper->type == slang_oper_call); or vec4_add, etc */
-
+ printf("Inline asm %s\n", (char*) fun->header.a_name);
inlined->type = fun->body->children[0].type;
inlined->a_id = fun->body->children[0].a_id;
inlined->num_children = numArgs;
for (i = 0; i < substCount; i++) {
if (v == substOld[i]) {
/* OK, replace this slang_oper_identifier with a new expr */
- assert(substNew[i]->type == slang_oper_identifier ||
- substNew[i]->type == slang_oper_literal_float);
-#if 1 /* DEBUG only */
+#if 0 /* DEBUG only */
if (substNew[i]->type == slang_oper_identifier) {
assert(substNew[i]->var);
assert(substNew[i]->var->a_name);
(char*)v->a_name, (char*) substNew[i]->var->a_name,
(void*) oper);
}
- else
+ else {
printf("Substitute %s with %f in id node %p\n",
(char*)v->a_name, substNew[i]->literal[0],
(void*) oper);
substNew = (slang_operation **)
_mesa_calloc(totalArgs * sizeof(slang_operation *));
- printf("\nInline call to %s (total vars=%d nparams=%d)\n",
+ printf("Inline call to %s (total vars=%d nparams=%d)\n",
(char *) fun->header.a_name,
fun->parameters->num_variables, numArgs);
-
if (haveRetValue && !returnOper) {
- /* Create comma sequence for inlined code, the left child will be the
- * function body and the right child will be a variable (__retVal)
- * that will get the return value.
+ /* Create 3-child comma sequence for inlined code:
+ * child[0]: declare __resultTmp
+ * child[1]: inlined function body
+ * child[2]: __resultTmp
*/
slang_operation *commaSeq;
slang_operation *declOper = NULL;
/* allocate the return var */
resultVar = slang_variable_scope_grow(commaSeq->locals);
/*
- printf("Alloc __resultTemp in scope %p for retval of calling %s\n",
+ printf("Alloc __resultTmp in scope %p for retval of calling %s\n",
(void*)commaSeq->locals, (char *) fun->header.a_name);
*/
resultVar->a_name = slang_atom_pool_atom(A->atoms, "__resultTmp");
resultVar->type = fun->header.type; /* XXX copy? */
- /*resultVar->type.qualifier = slang_qual_out;*/
+ resultVar->isTemp = GL_TRUE;
/* child[0] = __resultTmp declaration */
declOper = &commaSeq->children[0];
*/
substCount = 0;
for (i = 0; i < totalArgs; i++) {
- slang_variable *p = &fun->parameters->variables[i];
-
+ slang_variable *p = fun->parameters->variables[i];
+ /*
printf("Param %d: %s %s \n", i,
slang_type_qual_string(p->type.qualifier),
(char *) p->a_name);
-
+ */
if (p->type.qualifier == slang_qual_inout ||
p->type.qualifier == slang_qual_out) {
/* an output param */
else
arg = returnOper;
paramMode[i] = SUBST;
- assert(arg->type == slang_oper_identifier
- /*||arg->type == slang_oper_variable_decl*/);
- slang_resolve_variable(arg);
+
+ if (arg->type == slang_oper_identifier)
+ slang_resolve_variable(arg);
+
/* replace parameter 'p' with argument 'arg' */
substOld[substCount] = p;
substNew[substCount] = arg; /* will get copied */
assert(paramMode[i]);
}
-#if 00
- printf("ABOUT to inline body %p with checksum %d\n",
- (char *) fun->body, slang_checksum_tree(fun->body));
-#endif
-
/* actual code inlining: */
slang_operation_copy(inlined, fun->body);
-#if 000
+ /*** XXX review this */
+ assert(inlined->type = slang_oper_block_no_new_scope);
+ inlined->type = slang_oper_block_new_scope;
+
+#if 0
printf("======================= orig body code ======================\n");
printf("=== params scope = %p\n", (void*) fun->parameters);
slang_print_tree(fun->body, 8);
/* do parameter substitution in inlined code: */
slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE);
-#if 000
+#if 0
printf("======================= subst code ==========================\n");
slang_print_tree(inlined, 8);
printf("=============================================================\n");
numCopyIn = 0;
for (i = 0; i < numArgs; i++) {
if (paramMode[i] == COPY_IN) {
- slang_variable *p = &fun->parameters->variables[i];
+ slang_variable *p = fun->parameters->variables[i];
/* declare parameter 'p' */
slang_operation *decl = slang_operation_insert(&inlined->num_children,
&inlined->children,
for (i = 0; i < totalArgs; i++) {
if (paramMode[i] == COPY_OUT) {
- const slang_variable *p = &fun->parameters->variables[i];
+ const slang_variable *p = fun->parameters->variables[i];
/* actualCallVar = outParam */
/*if (i > 0 || !haveRetValue)*/
slang_operation *ass = slang_operation_insert(&inlined->num_children,
printf("\n");
#endif
- /* assemble what we just made XXX here??? */
n = _slang_gen_operation(A, oper);
CurFunction->end_label = NULL;
dest_oper = &dest_oper->children[0];
}
- assert(dest_oper->type == slang_oper_identifier);
n0 = _slang_gen_operation(A, dest_oper);
assert(n0->Var);
assert(n0->Store);
return NULL;
varDecl->Var = v;
- v->declared = GL_TRUE;
- slang_allocate_storage(A->codegen, varDecl, A->program);
+ slang_allocate_storage(A, varDecl);
if (oper->num_children > 0) {
/* child is initializer */
*/
slang_atom aVar = oper->var ? oper->var->a_name : oper->a_id;
slang_ir_node *n = new_var(A, oper, aVar, SWIZZLE_NOOP);
+ /*
assert(oper->var);
+ */
return n;
}
/* new storage info since we don't want to change the original */
base->Store = _slang_clone_ir_storage(base->Store);
if (_slang_type_is_vector(array_ti.spec.type)) {
- /* scalar element (float) of a basic vector (vec3) */
+ /* scalar element (float) of a basic vector (ex: vec3) */
const GLuint max = _slang_type_dim(array_ti.spec.type);
if (index >= max) {
RETURN_ERROR("array index out of bounds", 0);
_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
{
switch (oper->type) {
- case slang_oper_block_no_new_scope:
case slang_oper_block_new_scope:
+ {
+ slang_ir_node *n;
+
+ A->vartable = _slang_push_var_table(A->vartable);
+
+ oper->type = slang_oper_block_no_new_scope; /* temp change */
+ n = _slang_gen_operation(A, oper);
+ oper->type = slang_oper_block_new_scope; /* restore */
+
+ A->vartable = _slang_pop_var_table(A->vartable);
+
+ if (n)
+ n = new_node(IR_SCOPE, n, NULL);
+ return n;
+ }
+ break;
+
+ case slang_oper_block_no_new_scope:
/* list of operations */
assert(oper->num_children > 0);
{
slang_ir_node *n, *tree = NULL;
GLuint i;
+
for (i = 0; i < oper->num_children; i++) {
n = _slang_gen_operation(A, &oper->children[i]);
- if (!n)
+ if (!n) {
+ _slang_free_ir_tree(tree);
return NULL; /* error must have occured */
+ }
tree = tree ? new_seq(tree, n) : n;
}
- if (oper->locals->num_variables > 0) {
- int i;
- /*
- printf("\n****** Deallocate vars in scope!\n");
- */
- for (i = 0; i < oper->locals->num_variables; i++) {
- slang_variable *v = oper->locals->variables + i;
- if (v->aux) {
- slang_ir_storage *store = (slang_ir_storage *) v->aux;
- /*
- printf(" Deallocate var %s\n", (char*) v->a_name);
- */
- assert(store->File == PROGRAM_TEMPORARY);
- assert(store->Index >= 0);
- _slang_free_temporary(A->codegen, store->Index, store->Size);
+#if 00
+ if (oper->locals->num_variables > 0) {
+ int i;
+ /*
+ printf("\n****** Deallocate vars in scope!\n");
+ */
+ for (i = 0; i < oper->locals->num_variables; i++) {
+ slang_variable *v = oper->locals->variables + i;
+ if (v->aux) {
+ slang_ir_storage *store = (slang_ir_storage *) v->aux;
+ /*
+ printf(" Deallocate var %s\n", (char*) v->a_name);
+ */
+ assert(store->File == PROGRAM_TEMPORARY);
+ assert(store->Index >= 0);
+ _slang_free_temp(A->vartable, store->Index, store->Size);
+ }
}
}
- }
-
+#endif
return tree;
}
break;
return _slang_gen_assignment(A, oper);
case slang_oper_addassign:
{
+ /* XXX this is broken */
slang_ir_node *n;
assert(oper->num_children == 2);
- n = _slang_gen_function_call_name(A, "+=", oper, NULL);
- /* The result of this operation should be stored back into child[0] */
- assert(n->Children[0]->Store);
- n->Store = n->Children[0]->Store;
+ n = _slang_gen_function_call_name(A, "+=", oper, &oper->children[0]);
return n;
}
case slang_oper_subassign:
/* We know it's a uniform, but don't allocate storage unless
* it's really used.
*/
-
store = _slang_new_ir_storage(PROGRAM_STATE_VAR, -1, size);
-
}
if (dbg) printf("UNIFORM ");
}
if (!n)
return GL_FALSE;
n->Var = var;
- var->declared = GL_TRUE;
store = _slang_new_ir_storage(PROGRAM_TEMPORARY, index, size);
var->aux = store; /* save var's storage info */
- slang_allocate_storage(A->codegen, n, A->program);
+
+ slang_allocate_storage(A, n);
+
+ _slang_add_variable(A->vartable, var);
/* IR code for the var's initializer, if present */
if (var->initializer) {
n = new_seq(n, init);
}
- success = _slang_emit_code(n, A->codegen, A->program, GL_FALSE);
+ success = _slang_emit_code(n, A->vartable, A->program, GL_FALSE);
_slang_free_ir_tree(n);
}
assert(A->program->Parameters );
assert(A->program->Varying);
- assert(A->codegen);
- /* A->codegen = _slang_new_codegen_context();*/
+ assert(A->vartable);
/* fold constant expressions, etc. */
slang_simplify(fun->body, &A->space, A->atoms);
if (!CurFunction->end_label)
CurFunction->end_label = slang_atom_pool_gen(A->atoms, "__endOfFunc_main_");
+ /* push new vartable scope */
+ A->vartable = _slang_push_var_table(A->vartable);
+
/* Generate IR tree for the function body code */
n = _slang_gen_operation(A, fun->body);
+ if (n)
+ n = new_node(IR_SCOPE, n, NULL);
+
+ /* pop vartable, restore previous */
+ A->vartable = _slang_pop_var_table(A->vartable);
if (!n) {
/* XXX record error */
#if 0
printf("************* IR for %s *******\n", (char*)fun->header.a_name);
slang_print_ir(n, 0);
+#endif
+#if 1
printf("************* End codegen function ************\n\n");
#endif
/* Emit program instructions */
- success = _slang_emit_code(n, A->codegen, A->program, GL_TRUE);
+ success = _slang_emit_code(n, A->vartable, A->program, GL_TRUE);
_slang_free_ir_tree(n);
/* free codegen context */
#include "slang_storage.h"
#include "slang_error.h"
#include "slang_emit.h"
+#include "slang_vartable.h"
#include "slang_print.h"
for (i = 0; i < SLANG_BUILTIN_TOTAL; i++)
_slang_code_unit_ctr(&self->builtin[i], self);
_slang_code_unit_ctr(&self->unit, self);
+#if 01
_slang_assembly_file_ctr(&self->assembly);
+#endif
slang_machine_ctr(&self->machine);
self->varpool.next_addr = 0;
slang_atom_pool_construct(&self->atompool);
for (i = 0; i < SLANG_BUILTIN_TOTAL; i++)
_slang_code_unit_dtr(&self->builtin[i]);
_slang_code_unit_dtr(&self->unit);
+#if 01
slang_assembly_file_destruct(&self->assembly);
+#endif
slang_machine_dtr(&self->machine);
slang_atom_pool_destruct(&self->atompool);
slang_export_data_table_dtr(&self->expdata);
slang_var_pool *global_pool;
slang_machine *machine;
struct gl_program *program;
- slang_gen_context *codegen;
+ slang_var_table *vartable;
} slang_output_ctx;
/* _slang_compile() */
slang_operation *o = &oper->children[i - first_var];
o->type = slang_oper_variable_decl;
o->locals->outer_scope = O->vars;
- o->a_id = O->vars->variables[i].a_name;
+ o->a_id = O->vars->variables[i]->a_name;
}
}
}
*/
oper->type = slang_oper_asm;
oper->a_id = parse_identifier(C);
- if (strcmp((char*)oper->a_id, "dot") == 0) {
- printf("Assemble dot! **************************\n");
- }
if (oper->a_id == SLANG_ATOM_NULL)
return 0;
while (*C->I != OP_END) {
static GLboolean
initialize_global(slang_assemble_ctx * A, slang_variable * var)
{
+#if 01
slang_assembly_file_restore_point point;
+#endif
slang_machine mach;
slang_assembly_local_info save_local = A->local;
slang_operation op_id, op_assign;
GLboolean result;
+#if 01
/* save the current assembly */
if (!slang_assembly_file_restore_point_save(A->file, &point))
return GL_FALSE;
+#endif
/* setup the machine */
mach = *A->mach;
/* put the variable into operation's scope */
op_id.locals->variables =
- (slang_variable *) slang_alloc_malloc(sizeof(slang_variable));
+ (slang_variable **) slang_alloc_malloc(sizeof(slang_variable *));
if (op_id.locals->variables == NULL) {
slang_operation_destruct(&op_id);
return GL_FALSE;
}
op_id.locals->num_variables = 1;
- op_id.locals->variables[0] = *var;
+ op_id.locals->variables[0] = var;
/* construct the assignment expression */
if (!slang_operation_construct(&op_assign)) {
op_assign.children[0] = op_id;
op_assign.children[1] = *var->initializer;
+#if 0 /* this should go away */
/* insert the actual expression */
result = _slang_assemble_operation(A, &op_assign, slang_ref_forbid);
+#else
+ result = 1;
+#endif
/* carefully destroy the operations */
op_assign.num_children = 0;
return GL_FALSE;
#endif
+#if 01
/* restore the old assembly */
if (!slang_assembly_file_restore_point_load(A->file, &point))
return GL_FALSE;
+#endif
A->local = save_local;
/* now we copy the contents of the initialized variable back to the original machine */
A.space.funcs = O->funs;
A.space.structs = O->structs;
A.space.vars = O->vars;
- A.codegen = O->codegen;
A.program = O->program;
+#if 0
+ A.codegen = O->codegen;
+#endif
+ A.vartable = O->vartable;
_slang_codegen_global_variable(&A, var, C->type);
}
A.space.structs = O->structs;
A.space.vars = O->vars;
A.program = O->program;
+#if 0
A.codegen = O->codegen;
+#endif
+ A.vartable = O->vartable;
_slang_reset_error();
(*parsed_func_ret)->param_count);
#endif
-
+#if 0
if (!_slang_assemble_function(&A, *parsed_func_ret)) {
/* propogate the error message back through the info log */
C->L->text = _mesa_strdup(_slang_error_text());
C->L->dont_free_text = GL_FALSE;
return GL_FALSE;
}
-
+#endif
#if 0
printf("**************************************\n");
struct gl_program *program)
{
slang_output_ctx o;
+ GLboolean success;
/* setup output context */
o.funs = &unit->funs;
o.global_pool = &unit->object->varpool;
o.machine = &unit->object->machine;
o.program = program;
- o.codegen = _slang_new_codegen_context();
+ o.vartable = _slang_push_var_table(NULL);
/* parse individual functions and declarations */
while (*C->I != EXTERNAL_NULL) {
case EXTERNAL_FUNCTION_DEFINITION:
{
slang_function *func;
-
- if (!parse_function(C, &o, 1, &func))
- return GL_FALSE;
+ success = parse_function(C, &o, 1, &func);
}
break;
case EXTERNAL_DECLARATION:
- if (!parse_declaration(C, &o))
- return GL_FALSE;
+ success = parse_declaration(C, &o);
break;
default:
+ success = GL_FALSE;
+ }
+
+ if (!success) {
+ /* xxx free codegen */
+ _slang_pop_var_table(o.vartable);
return GL_FALSE;
}
}
C->I++;
+
+ _slang_pop_var_table(o.vartable);
return GL_TRUE;
}
#include "program.h"
#include "prog_instruction.h"
#include "prog_parameter.h"
+#include "prog_print.h"
#include "slang_emit.h"
{ IR_COS, "IR_COS", OPCODE_COS, 1, 1 },
/* other */
{ IR_SEQ, "IR_SEQ", 0, 0, 0 },
+ { IR_SCOPE, "IR_SCOPE", 0, 0, 0 },
{ IR_LABEL, "IR_LABEL", 0, 0, 0 },
{ IR_JUMP, "IR_JUMP", 0, 0, 0 },
{ IR_CJUMP, "IR_CJUMP", 0, 0, 0 },
slang_print_ir(n->Children[0], indent + IND);
slang_print_ir(n->Children[1], indent + IND);
break;
+ case IR_SCOPE:
+ printf("NEW SCOPE\n");
+ assert(!n->Children[1]);
+ slang_print_ir(n->Children[0], indent + 3);
+ break;
case IR_MOVE:
printf("MOVE (writemask = %s)\n", writemask_string(n->Writemask));
slang_print_ir(n->Children[0], indent+3);
}
-GLint
-_slang_alloc_temporary(slang_gen_context *gc, GLint size)
-{
- const GLuint sz4 = (size + 3) / 4;
- GLuint i, j;
- ASSERT(size > 0); /* number of floats */
-
- for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
- GLuint found = 0;
- for (j = 0; j < sz4; j++) {
- if (!gc->TempUsed[i + j]) {
- found++;
- }
- }
- if (found == sz4) {
- /* found block of size/4 free regs */
- for (j = 0; j < sz4; j++)
- gc->TempUsed[i + j] = GL_TRUE;
- return i;
- }
- }
- return -1;
-}
-
-
-
-static GLboolean
-is_temporary(const slang_gen_context *gc, const slang_ir_storage *st)
-{
- if (st->File == PROGRAM_TEMPORARY && gc->TempUsed[st->Index])
- return gc->TempUsed[st->Index];
- else
- return GL_FALSE;
-}
-
-
-void
-_slang_free_temporary(slang_gen_context *gc, GLuint r, GLint size)
-{
- const GLuint sz4 = (size + 3) / 4;
- GLuint i;
- for (i = 0; i < sz4; i++) {
- if (gc->TempUsed[r + i])
- gc->TempUsed[r + i] = GL_FALSE;
- }
-}
-
-
/**
* Allocate temporary storage for an intermediate result (such as for
* a multiply or add, etc.
*/
static void
-slang_alloc_temp_storage(slang_gen_context *gc, slang_ir_node *n, GLint size)
+alloc_temp_storage(slang_var_table *vt, slang_ir_node *n, GLint size)
{
GLint indx;
assert(!n->Var);
assert(!n->Store);
assert(size > 0);
- printf("Allocate binop temp:\n");
- indx = _slang_alloc_temporary(gc, size);
+ indx = _slang_alloc_temp(vt, size);
n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, indx, size);
}
+static void
+free_temp_storage(slang_var_table *vt, slang_ir_node *n)
+{
+ if (n->Store->File == PROGRAM_TEMPORARY && n->Store->Index >= 0) {
+ if (_slang_is_temp(vt, n->Store->Index)) {
+ _slang_free_temp(vt, n->Store->Index, n->Store->Size);
+ /* XXX free(store)? */
+ n->Store->Index = -1;
+ n->Store->Size = -1;
+ }
+ }
+}
+
+
static slang_ir_storage *
alloc_constant(const GLfloat v[], GLuint size, struct gl_program *prog)
{
static struct prog_instruction *
-emit(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog);
+emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog);
/**
* Generate code for a simple binary-op instruction.
*/
static struct prog_instruction *
-emit_binop(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
+emit_binop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
{
struct prog_instruction *inst;
const slang_ir_info *info = slang_find_ir_info(n->Opcode);
assert(info->InstOpcode != OPCODE_NOP);
- emit(gc, n->Children[0], prog);
- emit(gc, n->Children[1], prog);
+ /* gen code for children */
+ emit(vt, n->Children[0], prog);
+ emit(vt, n->Children[1], prog);
+
+ /* gen this instruction */
inst = new_instruction(prog, info->InstOpcode);
- /* alloc temp storage for the result: */
- if (!n->Store || n->Store->File == PROGRAM_UNDEFINED) {
- slang_alloc_temp_storage(gc, n, info->ResultSize);
- }
- storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store,
n->Children[0]->Swizzle);
storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store,
n->Children[1]->Swizzle);
+ free_temp_storage(vt, n->Children[0]);
+ free_temp_storage(vt, n->Children[1]);
+
+ if (!n->Store) {
+ alloc_temp_storage(vt, n, info->ResultSize);
+ }
+ storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
+
inst->Comment = n->Comment;
+ /*_mesa_print_instruction(inst);*/
return inst;
}
static struct prog_instruction *
-emit_unop(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
+emit_unop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
{
struct prog_instruction *inst;
const slang_ir_info *info = slang_find_ir_info(n->Opcode);
assert(info->NumParams == 1);
- emit(gc, n->Children[0], prog);
+ /* gen code for child */
+ emit(vt, n->Children[0], prog);
+ /* gen this instruction */
inst = new_instruction(prog, info->InstOpcode);
-
- if (!n->Store)
- slang_alloc_temp_storage(gc, n, info->ResultSize);
-
- storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
-
storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store,
n->Children[0]->Swizzle);
+ free_temp_storage(vt, n->Children[0]);
- inst->Comment = n->Comment;
+ if (!n->Store) {
+ alloc_temp_storage(vt, n, info->ResultSize);
+ }
+ storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
+ inst->Comment = n->Comment;
+ /*_mesa_print_instruction(inst);*/
return inst;
}
static struct prog_instruction *
-emit_negation(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
+emit_negation(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
{
/* Implement as MOV dst, -src; */
/* XXX we could look at the previous instruction and in some circumstances
*/
struct prog_instruction *inst;
- emit(gc, n->Children[0], prog);
+ emit(vt, n->Children[0], prog);
if (!n->Store)
- slang_alloc_temp_storage(gc, n, n->Children[0]->Store->Size);
+ alloc_temp_storage(vt, n, n->Children[0]->Store->Size);
inst = new_instruction(prog, OPCODE_MOV);
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
static struct prog_instruction *
-emit_tex(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
+emit_tex(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
{
struct prog_instruction *inst;
if (n->Opcode == IR_TEX) {
}
if (!n->Store)
- slang_alloc_temp_storage(gc, n, 4);
+ alloc_temp_storage(vt, n, 4);
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
static struct prog_instruction *
-emit(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
+emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
{
struct prog_instruction *inst;
if (!n)
case IR_SEQ:
assert(n->Children[0]);
assert(n->Children[1]);
- emit(gc, n->Children[0], prog);
- inst = emit(gc, n->Children[1], prog);
+ emit(vt, n->Children[0], prog);
+ inst = emit(vt, n->Children[1], prog);
n->Store = n->Children[1]->Store;
return inst;
- break;
+
+ case IR_SCOPE:
+ /* new variable scope */
+ vt = _slang_push_var_table(vt);
+ inst = emit(vt, n->Children[0], prog);
+ vt = _slang_pop_var_table(vt);
+ return inst;
+
case IR_VAR_DECL:
+ /* Variable declaration - allocate a register for it */
+ assert(n->Store);
+ assert(n->Store->File != PROGRAM_UNDEFINED);
+ assert(n->Store->Size > 0);
+ if (n->Var->isTemp)
+ n->Store->Index = _slang_alloc_temp(vt, n->Store->Size);
+ else
+ n->Store->Index = _slang_alloc_var(vt, n->Store->Size);
+ break;
+
case IR_VAR:
- /* Storage should have already been resolved/allocated */
+ /* Reference to a variable
+ * Storage should have already been resolved/allocated.
+ */
assert(n->Store);
assert(n->Store->File != PROGRAM_UNDEFINED);
assert(n->Store->Index >= 0);
assert(n->Store->Size > 0);
break;
+
case IR_MOVE:
/* rhs */
assert(n->Children[1]);
- inst = emit(gc, n->Children[1], prog);
+ inst = emit(vt, n->Children[1], prog);
/* lhs */
- emit(gc, n->Children[0], prog);
+ emit(vt, n->Children[0], prog);
#if 1
- if (inst && is_temporary(gc, n->Children[1]->Store)) {
+ if (inst && _slang_is_temp(vt, n->Children[1]->Store->Index)) {
/* Peephole optimization:
* Just modify the RHS to put its result into the dest of this
* MOVE operation. Then, this MOVE is a no-op.
*/
- _slang_free_temporary(gc, n->Children[1]->Store->Index,
- n->Children[1]->Store->Size);
+ _slang_free_temp(vt, n->Children[1]->Store->Index,
+ n->Children[1]->Store->Size);
*n->Children[1]->Store = *n->Children[0]->Store;
/* fixup the prev (RHS) instruction */
storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
n->Children[1]->Swizzle);
}
/* XXX is this test correct? */
- if (n->Children[1]->Store->File == PROGRAM_TEMPORARY) {
- _slang_free_temporary(gc, n->Children[1]->Store->Index,
- n->Children[1]->Store->Size);
+ if (_slang_is_temp(vt, n->Children[1]->Store->Index)) {
+ _slang_free_temp(vt, n->Children[1]->Store->Index,
+ n->Children[1]->Store->Size);
}
/*inst->Comment = _mesa_strdup("IR_MOVE");*/
n->Store = n->Children[0]->Store; /*XXX new */
case IR_POW:
case IR_EXP:
case IR_EXP2:
- return emit_binop(gc, n, prog);
+ return emit_binop(vt, n, prog);
case IR_RSQ:
case IR_RCP:
case IR_FLOOR:
case IR_COS:
case IR_DDX:
case IR_DDY:
- return emit_unop(gc, n, prog);
+ return emit_unop(vt, n, prog);
case IR_TEX:
case IR_TEXB:
case IR_TEXP:
- return emit_tex(gc, n, prog);
+ return emit_tex(vt, n, prog);
case IR_NEG:
- return emit_negation(gc, n, prog);
+ return emit_negation(vt, n, prog);
case IR_LABEL:
return emit_label(n->Target, prog);
case IR_FLOAT:
* Next instruction is typically an IR_CJUMP.
*/
/* last child expr instruction: */
- struct prog_instruction *inst = emit(gc, n->Children[0], prog);
+ struct prog_instruction *inst = emit(vt, n->Children[0], prog);
if (inst) {
/* set inst's CondUpdate flag */
inst->CondUpdate = GL_TRUE;
* is normally generated for the expression "i".
* Generate a move instruction just to set condition codes.
*/
- slang_alloc_temp_storage(gc, n, 1);
+ alloc_temp_storage(vt, n, 1);
inst = new_instruction(prog, OPCODE_MOV);
inst->CondUpdate = GL_TRUE;
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store,
n->Children[0]->Swizzle);
- _slang_free_temporary(gc, n->Store->Index, n->Store->Size);
+ _slang_free_temp(vt, n->Store->Index, n->Store->Size);
return inst; /* XXX or null? */
}
}
}
-slang_gen_context *
-_slang_new_codegen_context(void)
-{
- slang_gen_context *gc = (slang_gen_context *) _mesa_calloc(sizeof(*gc));
- return gc;
-}
-
-
-
GLboolean
-_slang_emit_code(slang_ir_node *n, slang_gen_context *gc,
+_slang_emit_code(slang_ir_node *n, slang_var_table *vt,
struct gl_program *prog, GLboolean withEnd)
{
GLboolean success;
- if (emit(gc, n, prog)) {
- /* finish up by addeing the END opcode to program */
+ if (emit(vt, n, prog)) {
+ /* finish up by adding the END opcode to program */
if (withEnd) {
struct prog_instruction *inst;
inst = new_instruction(prog, OPCODE_END);
success = GL_FALSE;
}
-#if 0
printf("*********** End generate code (%u inst):\n", prog->NumInstructions);
+#if 0
_mesa_print_program(prog);
_mesa_print_program_parameters(ctx,prog);
#endif
#include "mtypes.h"
-extern slang_gen_context *
-_slang_new_codegen_context(void);
-
-
extern void
slang_print_ir(const slang_ir_node *n, int indent);
_slang_clone_ir_storage(slang_ir_storage *store);
-extern GLint
-_slang_alloc_temporary(slang_gen_context *gc, GLint size);
-
-extern void
-_slang_free_temporary(slang_gen_context *gc, GLuint r, GLint size);
-
-
extern GLboolean
-_slang_emit_code(slang_ir_node *n, slang_gen_context *gc,
+_slang_emit_code(slang_ir_node *n, slang_var_table *vartable,
struct gl_program *prog, GLboolean withEnd);
{
IR_NOP = 0,
IR_SEQ, /* sequence (eval left, then right) */
+ IR_SCOPE, /* new variable scope (one child) */
IR_LABEL, /* target of a jump or cjump */
IR_JUMP, /* unconditional jump */
IR_CJUMP, /* conditional jump */
if (inst->Opcode == OPCODE_TEX ||
inst->Opcode == OPCODE_TXB ||
inst->Opcode == OPCODE_TXP) {
+ /*
printf("====== remap sampler from %d to %d\n",
inst->Sampler, map[ inst->Sampler ]);
+ */
inst->Sampler = map[ inst->Sampler ];
}
}
{
GLuint i;
for (i = 0; i < s->num_variables; i++) {
- if (s->variables[i].a_name == name)
+ if (s->variables[i]->a_name == name)
return s;
}
if (s->outer_scope)
{
GLuint i;
for (i = 0; i < s->num_variables; i++) {
- if (s->variables[i].a_name == name)
- return &s->variables[i];
+ if (s->variables[i]->a_name == name)
+ return s->variables[i];
}
if (s->outer_scope)
return find_var(s->outer_scope, name);
(char *) f->header.a_name);
for (i = 0; i < f->param_count; i++) {
- print_variable(&f->parameters->variables[i], 3);
+ print_variable(f->parameters->variables[i], 3);
}
printf(")\n");
-/* operation */
-#define OP_END 0
-#define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1
-#define OP_BLOCK_BEGIN_NEW_SCOPE 2
-#define OP_DECLARE 3
-#define OP_ASM 4
-#define OP_BREAK 5
-#define OP_CONTINUE 6
-#define OP_DISCARD 7
-#define OP_RETURN 8
-#define OP_EXPRESSION 9
-#define OP_IF 10
-#define OP_WHILE 11
-#define OP_DO 12
-#define OP_FOR 13
-#define OP_PUSH_VOID 14
-#define OP_PUSH_BOOL 15
-#define OP_PUSH_INT 16
-#define OP_PUSH_FLOAT 17
-#define OP_PUSH_IDENTIFIER 18
-#define OP_SEQUENCE 19
-#define OP_ASSIGN 20
-#define OP_ADDASSIGN 21
-#define OP_SUBASSIGN 22
-#define OP_MULASSIGN 23
-#define OP_DIVASSIGN 24
-/*#define OP_MODASSIGN 25*/
-/*#define OP_LSHASSIGN 26*/
-/*#define OP_RSHASSIGN 27*/
-/*#define OP_ORASSIGN 28*/
-/*#define OP_XORASSIGN 29*/
-/*#define OP_ANDASSIGN 30*/
-#define OP_SELECT 31
-#define OP_LOGICALOR 32
-#define OP_LOGICALXOR 33
-#define OP_LOGICALAND 34
-/*#define OP_BITOR 35*/
-/*#define OP_BITXOR 36*/
-/*#define OP_BITAND 37*/
-#define OP_EQUAL 38
-#define OP_NOTEQUAL 39
-#define OP_LESS 40
-#define OP_GREATER 41
-#define OP_LESSEQUAL 42
-#define OP_GREATEREQUAL 43
-/*#define OP_LSHIFT 44*/
-/*#define OP_RSHIFT 45*/
-#define OP_ADD 46
-#define OP_SUBTRACT 47
-#define OP_MULTIPLY 48
-#define OP_DIVIDE 49
-/*#define OP_MODULUS 50*/
-#define OP_PREINCREMENT 51
-#define OP_PREDECREMENT 52
-#define OP_PLUS 53
-#define OP_MINUS 54
-/*#define OP_COMPLEMENT 55*/
-#define OP_NOT 56
-#define OP_SUBSCRIPT 57
-#define OP_CALL 58
-#define OP_FIELD 59
-#define OP_POSTINCREMENT 60
-#define OP_POSTDECREMENT 61
-
-
-void
-slang_print_opcode(unsigned int opcode)
-{
- switch (opcode) {
- case OP_PUSH_VOID:
- printf("OP_PUSH_VOID\n");
- break;
- case OP_PUSH_BOOL:
- printf("OP_PUSH_BOOL\n");
- break;
- case OP_PUSH_INT:
- printf("OP_PUSH_INT\n");
- break;
- case OP_PUSH_FLOAT:
- printf("OP_PUSH_FLOAT\n");
- break;
- case OP_PUSH_IDENTIFIER:
- printf("OP_PUSH_IDENTIFIER\n");
- break;
- case OP_SEQUENCE:
- printf("OP_SEQUENCE\n");
- break;
- case OP_ASSIGN:
- printf("OP_ASSIGN\n");
- break;
- case OP_ADDASSIGN:
- printf("OP_ADDASSIGN\n");
- break;
- case OP_SUBASSIGN:
- printf("OP_SUBASSIGN\n");
- break;
- case OP_MULASSIGN:
- printf("OP_MULASSIGN\n");
- break;
- case OP_DIVASSIGN:
- printf("OP_DIVASSIGN\n");
- break;
- /*case OP_MODASSIGN:*/
- /*case OP_LSHASSIGN:*/
- /*case OP_RSHASSIGN:*/
- /*case OP_ORASSIGN:*/
- /*case OP_XORASSIGN:*/
- /*case OP_ANDASSIGN:*/
- case OP_SELECT:
- printf("OP_SELECT\n");
- break;
- case OP_LOGICALOR:
- printf("OP_LOGICALOR\n");
- break;
- case OP_LOGICALXOR:
- printf("OP_LOGICALXOR\n");
- break;
- case OP_LOGICALAND:
- printf("OP_LOGICALAND\n");
- break;
- /*case OP_BITOR:*/
- /*case OP_BITXOR:*/
- /*case OP_BITAND:*/
- case OP_EQUAL:
- printf("OP_EQUAL\n");
- break;
- case OP_NOTEQUAL:
- printf("OP_NOTEQUAL\n");
- break;
- case OP_LESS:
- printf("OP_LESS\n");
- break;
- case OP_GREATER:
- printf("OP_GREATER\n");
- break;
- case OP_LESSEQUAL:
- printf("OP_LESSEQUAL\n");
- break;
- case OP_GREATEREQUAL:
- printf("OP_GREATEREQUAL\n");
- break;
- /*case OP_LSHIFT:*/
- /*case OP_RSHIFT:*/
- case OP_ADD:
- printf("OP_ADD\n");
- break;
- case OP_SUBTRACT:
- printf("OP_SUBTRACT\n");
- break;
- case OP_MULTIPLY:
- printf("OP_MULTIPLY\n");
- break;
- case OP_DIVIDE:
- printf("OP_DIVIDE\n");
- break;
- /*case OP_MODULUS:*/
- case OP_PREINCREMENT:
- printf("OP_PREINCREMENT\n");
- break;
- case OP_PREDECREMENT:
- printf("OP_PREDECREMENT\n");
- break;
- case OP_PLUS:
- printf("OP_PLUS\n");
- break;
- case OP_MINUS:
- printf("OP_MINUS\n");
- break;
- case OP_NOT:
- printf("OP_NOT\n");
- break;
- /*case OP_COMPLEMENT:*/
- case OP_SUBSCRIPT:
- printf("OP_SUBSCRIPT\n");
- break;
- case OP_CALL:
- printf("OP_CALL\n");
- break;
- case OP_FIELD:
- printf("OP_FIELD\n");
- break;
- case OP_POSTINCREMENT:
- printf("OP_POSTINCREMENT\n");
- break;
- case OP_POSTDECREMENT:
- printf("OP_POSTDECREMENT\n");
- break;
- default:
- printf("UNKNOWN OP %d\n", opcode);
- }
-}
-
-
const char *
slang_asm_string(slang_assembly_type t)
}
+#if 0
static char *
slang_var_string(const slang_variable *v)
{
slang_fq_type_string(&v->type));
return str;
}
+#endif
void
printf("Var scope %p %d vars:\n", (void *) vars, vars->num_variables);
for (i = 0; i < vars->num_variables; i++) {
spaces(indent + 3);
- printf("%s\n", (char *) vars->variables[i].a_name);
+ printf("%s (at %p)\n", (char *) vars->variables[i]->a_name, (void*) (vars->variables + i));
}
spaces(indent + 3);
printf("outer_scope = %p\n", (void*) vars->outer_scope);
if (vars->outer_scope) {
- spaces(indent + 3);
+ /*spaces(indent + 3);*/
_slang_print_var_scope(vars->outer_scope, indent + 3);
}
}
slang_print_tree(const slang_operation *op, int indent);
-extern void
-slang_print_opcode(unsigned int opcode);
-
-
extern const char *
slang_asm_string(slang_assembly_type t);
GLuint i;
for (i = 0; i < vars->num_variables; i++)
- if (!_slang_aggregate_variable (agg, &vars->variables[i].type.specifier,
- vars->variables[i].array_len, funcs, structs, globals, mach, file, atoms))
+ if (!_slang_aggregate_variable (agg, &vars->variables[i]->type.specifier,
+ vars->variables[i]->array_len, funcs, structs, globals, mach, file, atoms))
return GL_FALSE;
return GL_TRUE;
}
--- /dev/null
+
+#include "imports.h"
+#include "slang_compile.h"
+#include "slang_compile_variable.h"
+#include "slang_vartable.h"
+
+
+static int dbg = 0;
+
+
+typedef enum {
+ FREE,
+ VAR,
+ TEMP
+} TempState;
+
+static int Level = 0;
+
+struct slang_var_table_
+{
+ int level;
+ int num_entries;
+ slang_variable **vars; /* array [num_entries] */
+
+ TempState temps[MAX_PROGRAM_TEMPS];
+
+ struct slang_var_table_ *parent;
+};
+
+
+
+/**
+ * Create new table, put at head, return ptr to it.
+ */
+slang_var_table *
+_slang_push_var_table(slang_var_table *parent)
+{
+ slang_var_table *t
+ = (slang_var_table *) _mesa_calloc(sizeof(slang_var_table));
+ if (t) {
+ t->level = Level++;
+ t->parent = parent;
+ if (parent) {
+ /* copy the info indicating which temp regs are in use */
+ memcpy(t->temps, parent->temps, sizeof(t->temps));
+ }
+ if (dbg) printf("Pushing level %d\n", t->level);
+ }
+ return t;
+}
+
+
+/**
+ * Destroy given table, return ptr to parent
+ */
+slang_var_table *
+_slang_pop_var_table(slang_var_table *t)
+{
+ slang_var_table *parent = t->parent;
+ int i;
+ if (dbg) printf("Popping level %d\n", t->level);
+ if (t->parent) {
+ for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
+ if (t->temps[i] && !t->parent->temps[i])
+ if (dbg) printf(" Free reg %d\n", i);
+ }
+ }
+ for (i = 0; i < t->num_entries; i++) {
+ if (dbg) printf(" Free var %s\n", (char*) t->vars[i]->a_name);
+ }
+
+ if (t->vars)
+ free(t->vars);
+ free(t);
+ Level--;
+ return parent;
+}
+
+
+/**
+ * Add a new variable to the given symbol table.
+ */
+void
+_slang_add_variable(slang_var_table *t, slang_variable *v)
+{
+ assert(t);
+ t->vars = realloc(t->vars, (t->num_entries + 1) * sizeof(slang_variable *));
+ t->vars[t->num_entries] = v;
+ t->num_entries++;
+}
+
+
+/**
+ * Look for variable by name in given table.
+ * If not found, parent table will be searched.
+ */
+slang_variable *
+_slang_find_variable(const slang_var_table *t, slang_atom name)
+{
+ while (1) {
+ int i;
+ for (i = 0; i < t->num_entries; i++) {
+ if (t->vars[i]->a_name == name)
+ return t->vars[i];
+ }
+ if (t->parent)
+ t = t->parent;
+ else
+ return NULL;
+ }
+}
+
+
+static GLint
+alloc_reg(slang_var_table *t, GLint size, GLboolean isTemp)
+{
+ const GLuint sz4 = (size + 3) / 4;
+ GLuint i, j;
+ assert(size > 0); /* number of floats */
+
+ for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
+ GLuint found = 0;
+ for (j = 0; j < sz4; j++) {
+ if (!t->temps[i + j]) {
+ found++;
+ }
+ else {
+ break;
+ }
+ }
+ if (found == sz4) {
+ /* found block of size/4 free regs */
+ for (j = 0; j < sz4; j++)
+ t->temps[i + j] = isTemp ? TEMP : VAR;
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/**
+ * Allocate temp register(s) for storing a variable.
+ */
+GLint
+_slang_alloc_var(slang_var_table *t, GLint size)
+{
+ int i = alloc_reg(t, size, GL_FALSE);
+ if (dbg) printf("Alloc var %d (level %d)\n", i, t->level);
+ return i;
+}
+
+
+void
+_slang_reserve_var(slang_var_table *t, GLint r, GLint size)
+{
+ const GLint sz4 = (size + 3) / 4;
+ GLint i;
+ for (i = 0; i < sz4; i++) {
+ t->temps[r + i] = VAR;
+ }
+}
+
+
+/**
+ * Allocate temp register(s) for storing an unnamed intermediate value.
+ */
+GLint
+_slang_alloc_temp(slang_var_table *t, GLint size)
+{
+ int i = alloc_reg(t, size, GL_TRUE);
+ if (dbg) printf("Alloc temp %d (level %d)\n", i, t->level);
+ return i;
+}
+
+
+void
+_slang_free_temp(slang_var_table *t, GLint r, GLint size)
+{
+ const GLuint sz4 = (size + 3) / 4;
+ GLuint i;
+ assert(size > 0);
+ assert(r >= 0);
+ assert(r < MAX_PROGRAM_TEMPS);
+ if (dbg) printf("Free temp %d (level %d)\n", r, t->level);
+ for (i = 0; i < sz4; i++) {
+ assert(t->temps[r + i] == TEMP);
+ t->temps[r + i] = FREE;
+ }
+}
+
+
+GLboolean
+_slang_is_temp(slang_var_table *t, GLint r)
+{
+ assert(r >= 0);
+ assert(r < MAX_PROGRAM_TEMPS);
+ if (t->temps[r] == TEMP)
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
--- /dev/null
+
+#ifndef SLANG_VARTABLE_H
+#define SLANG_VARTABLE_H
+
+
+typedef struct slang_var_table_ slang_var_table;
+
+struct slang_variable_;
+
+extern slang_var_table *
+_slang_push_var_table(slang_var_table *parent);
+
+extern slang_var_table *
+_slang_pop_var_table(slang_var_table *t);
+
+extern void
+_slang_add_variable(slang_var_table *t, struct slang_variable_ *v);
+
+extern struct slang_variable_ *
+_slang_find_variable(const slang_var_table *t, slang_atom name);
+
+extern GLint
+_slang_alloc_var(slang_var_table *t, GLint size);
+
+extern void
+_slang_reserve_var(slang_var_table *t, GLint r, GLint size);
+
+extern GLint
+_slang_alloc_temp(slang_var_table *t, GLint size);
+
+extern void
+_slang_free_temp(slang_var_table *t, GLint r, GLint size);
+
+extern GLboolean
+_slang_is_temp(slang_var_table *t, GLint r);
+
+
+#endif /* SLANG_VARTABLE_H */
shader/slang/slang_preprocess.c \
shader/slang/slang_simplify.c \
shader/slang/slang_storage.c \
+ shader/slang/slang_vartable.c \
shader/slang/slang_print.c \
shader/slang/slang_utility.c