diff options
author | Brian <brian@yutani.localnet.net> | 2006-12-13 14:48:36 -0700 |
---|---|---|
committer | Brian <brian@yutani.localnet.net> | 2006-12-13 14:48:36 -0700 |
commit | aff8e204d205b5d424d2c39a5d9e004caaa1eab1 (patch) | |
tree | 91d06d422f8900af461233186bcc79351c3025f6 /src/mesa/shader/slang/slang_codegen.c | |
parent | 5b35132b41427798e02a66a8e39583fffbe9d232 (diff) |
Checkpoint new GLSL compiler back-end to produce fp/vp-style assembly instructions.
Diffstat (limited to 'src/mesa/shader/slang/slang_codegen.c')
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 1272 |
1 files changed, 1272 insertions, 0 deletions
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c new file mode 100644 index 0000000000..e428209ec4 --- /dev/null +++ b/src/mesa/shader/slang/slang_codegen.c @@ -0,0 +1,1272 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL 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. + */ + +/** + * \file slang_codegen.c + * Mesa GLSL code generator. Convert AST to IR tree. + * \author Brian Paul + */ + +#include "imports.h" +#include "macros.h" +#include "slang_assemble.h" +#include "slang_codegen.h" +#include "slang_compile.h" +#include "slang_storage.h" +#include "slang_error.h" +#include "slang_simplify.h" +#include "slang_emit.h" +#include "slang_ir.h" +#include "mtypes.h" +#include "program.h" +#include "slang_print.h" + + +static slang_function *CurFunction = NULL; + + +static slang_ir_node * +slang_assemble_operation(slang_assemble_ctx * A, slang_operation *oper); + + + +/** + * Allocate storage for given variable, attach it to 'ir'. + */ +static GLboolean +slang_alloc_var_storage(slang_variable *variable, slang_ir_node *ir) +{ + slang_ir_storage *store; + + assert(variable); + + /*assert(!variable->aux);*/ + + if (variable->aux) { + store = (slang_ir_storage *) variable->aux; + ir->Store = store; + if (store) + store->Size = -12; + } + else { + /* alloc storage */ + store = (slang_ir_storage *) _mesa_calloc(sizeof(*store)); + store->File = PROGRAM_TEMPORARY; + store->Index = -1; + store->Size = -10; + variable->aux = store; + ir->Store = store; + } + return GL_TRUE; +} + + +static slang_ir_node * +new_node(slang_ir_opcode op, slang_ir_node *left, slang_ir_node *right) +{ + slang_ir_node *n = (slang_ir_node *) calloc(1, sizeof(slang_ir_node)); + if (n) { + n->Opcode = op; + n->Children[0] = left; + n->Children[1] = right; + n->Swizzle = SWIZZLE_NOOP; + n->Writemask = WRITEMASK_XYZW; + } + return n; +} + +static slang_ir_node * +new_seq(slang_ir_node *left, slang_ir_node *right) +{ + assert(left); + assert(right); + return new_node(IR_SEQ, left, right); +} + +static slang_ir_node * +new_label(const char *name) +{ + slang_ir_node *n = new_node(IR_LABEL, NULL, NULL); + n->Target = _mesa_strdup(name); + return n; +} + +static slang_ir_node * +new_float_literal(float x, float y, float z, float w) +{ + slang_ir_node *n = new_node(IR_FLOAT, NULL, NULL); + n->Value[0] = x; + n->Value[1] = y; + n->Value[2] = z; + n->Value[3] = w; + return n; +} + +static slang_ir_node * +new_cjump(slang_ir_node *cond, const char *target) +{ + slang_ir_node *n = new_node(IR_CJUMP, cond, NULL); + n->Target = _mesa_strdup(target); + return n; +} + +static slang_ir_node * +new_jump(const char *target) +{ + slang_ir_node *n = new_node(IR_JUMP, NULL, NULL); + if (n) { + n->Target = _mesa_strdup(target); + } + return n; +} + + +/** + * New IR_VAR_DECL node - allocate storage for a new variable. + */ +static slang_ir_node * +new_var_decl(slang_assemble_ctx *A, slang_variable *v) +{ + slang_ir_node *n = new_node(IR_VAR_DECL, NULL, NULL); + if (n) { + n->Var = v; + v->declared = GL_TRUE; + } + return n; +} + + +/** + * New IR_VAR node - a reference to a previously declared variable. + */ +static slang_ir_node * +new_var(slang_assemble_ctx *A, slang_operation *oper, + slang_atom name, GLuint swizzle) +{ + slang_variable *v = _slang_locate_variable(oper->locals, name, GL_TRUE); + slang_ir_node *n = new_node(IR_VAR, NULL, NULL); + if (!v) { + 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_resolve_storage(NULL, n, A->program); + return n; +} + + +static GLboolean +slang_is_writemask(const char *field, GLuint *mask) +{ + const GLuint n = 4; + GLuint i, bit, c = 0; + + for (i = 0; i < n && field[i]; i++) { + switch (field[i]) { + case 'x': + case 'r': + bit = WRITEMASK_X; + break; + case 'y': + case 'g': + bit = WRITEMASK_Y; + break; + case 'z': + case 'b': + bit = WRITEMASK_Z; + break; + case 'w': + case 'a': + bit = WRITEMASK_W; + break; + default: + return GL_FALSE; + } + if (c & bit) + return GL_FALSE; + c |= bit; + } + *mask = c; + return GL_TRUE; +} + + +static slang_ir_node * +slang_assemble_return(slang_assemble_ctx * A, slang_operation *oper) +{ + if (oper->num_children == 0) { + /* Convert to: + * goto __endOfFunction; + */ + oper->type = slang_oper_goto; + oper->a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label); + } + else { + /* + * Convert from: + * return expr; + * To: + * __retVal = expr; + * goto __endOfFunction; + */ + slang_operation *block, *assign, *jump; + slang_atom a_retVal; + + a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); + assert(a_retVal); + +#if 1 + { + slang_variable *v + = _slang_locate_variable(oper->locals, a_retVal, GL_TRUE); + assert(v); + } +#endif + + block = slang_operation_new(1); + block->type = slang_oper_block_no_new_scope; + block->num_children = 2; + block->children = slang_operation_new(2); + assert(block->locals); + block->locals->outer_scope = oper->locals->outer_scope; + + /* child[0]: __retVal = expr; */ + assign = &block->children[0]; + assign->type = slang_oper_assign; + assign->locals->outer_scope = block->locals; + assign->num_children = 2; + assign->children = slang_operation_new(2); + /* lhs */ + assign->children[0].type = slang_oper_identifier; + assign->children[0].a_id = a_retVal; + assign->children[0].locals->outer_scope = assign->locals; + /* rhs */ +#if 0 + assign->children[1] = oper->children[0]; /* XXX copy */ +#else + slang_operation_copy(&assign->children[1], &oper->children[0]); +#endif + + + /* child[1]: goto __endOfFunction */ + jump = &block->children[1]; + jump->type = slang_oper_goto; + assert(CurFunction->end_label); + jump->a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label); + +#if 00 + printf("NEW RETURN:\n"); + slang_print_tree(block, 0); +#endif + + slang_operation_copy(oper, block); + /* XXX destruct block */ + } + + /* assemble the new code */ + return slang_assemble_operation(A, oper); +} + + + +/** + * Check if the given function is really just a wrapper for an + * basic assembly instruction. + */ +static GLboolean +slang_is_asm_function(const slang_function *fun) +{ + if (fun->body->type == slang_oper_block_no_new_scope && + fun->body->num_children == 1 && + fun->body->children[0].type == slang_oper_asm) { + return GL_TRUE; + } + return GL_FALSE; +} + + +/** + * Produce inline code for a call to an assembly instruction. + */ +static slang_operation * +slang_inline_asm_function(slang_assemble_ctx *A, + slang_function *fun, slang_operation *oper) +{ + const int numArgs = oper->num_children; + const slang_operation *args = oper->children; + GLuint i; + slang_operation *inlined = slang_operation_new(1); + + /*assert(oper->type == slang_oper_call); or vec4_add, etc */ + + inlined->type = fun->body->children[0].type; + inlined->a_id = fun->body->children[0].a_id; + inlined->num_children = numArgs; + inlined->children = slang_operation_new(numArgs); +#if 0 + inlined->locals = slang_variable_scope_copy(oper->locals); +#else + assert(inlined->locals); + inlined->locals->outer_scope = oper->locals->outer_scope; +#endif + + for (i = 0; i < numArgs; i++) { + slang_operation_copy(inlined->children + i, args + i); + } + + return inlined; +} + + +static void +slang_resolve_variable(slang_operation *oper) +{ + if (oper->type != slang_oper_identifier) + return; + if (!oper->var) { + oper->var = _slang_locate_variable(oper->locals, + (const slang_atom) oper->a_id, + GL_TRUE); + if (oper->var) + oper->var->used = GL_TRUE; + } +} + + +/** + * Replace particular variables (slang_oper_identifier) with new expressions. + */ +static void +slang_substitute(slang_assemble_ctx *A, slang_operation *oper, + GLuint substCount, slang_variable **substOld, + slang_operation **substNew, GLboolean isLHS) +{ + switch (oper->type) { + case slang_oper_variable_decl: + { + slang_variable *v = _slang_locate_variable(oper->locals, + oper->a_id, GL_TRUE); + assert(v); + if (v->initializer && oper->num_children == 0) { + /* set child of oper to copy of initializer */ + oper->num_children = 1; + oper->children = slang_operation_new(1); + slang_operation_copy(&oper->children[0], v->initializer); + } + if (oper->num_children == 1) { + /* the initializer */ + slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_FALSE); + } + } + break; + case slang_oper_identifier: + assert(oper->num_children == 0); + if (1/**!isLHS XXX FIX */) { + slang_atom id = oper->a_id; + slang_variable *v; + GLuint i; + v = _slang_locate_variable(oper->locals, id, GL_TRUE); + if (!v) { + printf("var %s not found!\n", (char *) oper->a_id); + break; + } + + /* look for a substitution */ + 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 (substNew[i]->type == slang_oper_identifier) { + assert(substNew[i]->var); + assert(substNew[i]->var->a_name); + printf("Substitute %s with %s in id node %p\n", + (char*)v->a_name, (char*) substNew[i]->var->a_name, + (void*) oper); + } + else + printf("Substitute %s with %f in id node %p\n", + (char*)v->a_name, substNew[i]->literal[0], + (void*) oper); +#endif + slang_operation_copy(oper, substNew[i]); + break; + } + } + } + break; + case slang_oper_return: + /* do return replacement here too */ + slang_assemble_return(A, oper); + slang_substitute(A, oper, substCount, substOld, substNew, GL_FALSE); + break; + case slang_oper_assign: + case slang_oper_subscript: + /* special case: + * child[0] can't have substitutions but child[1] can. + */ + slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_TRUE); + slang_substitute(A, &oper->children[1], substCount, substOld, substNew, GL_FALSE); + break; + case slang_oper_field: + /* XXX NEW - test */ + slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_TRUE); + break; + default: + { + GLuint i; + for (i = 0; i < oper->num_children; i++) + slang_substitute(A, &oper->children[i], substCount, substOld, substNew, GL_FALSE); + } + } +} + + + +/** + * Inline the given function call operation. + * Return a new slang_operation that corresponds to the inlined code. + */ +static slang_operation * +slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, + slang_operation *oper, slang_operation *returnOper) +{ + typedef enum { + SUBST = 1, + COPY_IN, + COPY_OUT + } ParamMode; + ParamMode *paramMode; + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + const GLuint numArgs = oper->num_children; + const GLuint totalArgs = numArgs + haveRetValue; + slang_operation *args = oper->children; + slang_operation *inlined, *top; + slang_variable **substOld; + slang_operation **substNew; + GLuint substCount, numCopyIn, i; + + /*assert(oper->type == slang_oper_call); (or (matrix) multiply, etc) */ + assert(fun->param_count == totalArgs); + + /* allocate temporary arrays */ + paramMode = (ParamMode *) + _mesa_calloc(totalArgs * sizeof(ParamMode)); + substOld = (slang_variable **) + _mesa_calloc(totalArgs * sizeof(slang_variable *)); + substNew = (slang_operation **) + _mesa_calloc(totalArgs * sizeof(slang_operation *)); + + printf("\nInline 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. + */ + slang_operation *commaSeq; + slang_operation *declOper = NULL; + slang_variable *resultVar; + + commaSeq = slang_operation_new(1); + commaSeq->type = slang_oper_sequence; + assert(commaSeq->locals); + commaSeq->locals->outer_scope = oper->locals->outer_scope; + commaSeq->num_children = 3; + commaSeq->children = slang_operation_new(3); + /* allocate the return var */ + resultVar = slang_variable_scope_grow(commaSeq->locals); + /* + printf("ALLOC __retVal from scope %p\n", (void*) commaSeq->locals); + */ + printf("Alloc __resultTemp 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;*/ + + /* child[0] = __resultTmp declaration */ + declOper = &commaSeq->children[0]; + declOper->type = slang_oper_variable_decl; + declOper->a_id = resultVar->a_name; + declOper->locals->outer_scope = commaSeq->locals; /*** ??? **/ + + /* child[1] = function body */ + inlined = &commaSeq->children[1]; + /* XXXX this may be inappropriate!!!!: */ + inlined->locals->outer_scope = commaSeq->locals; + + /* child[2] = __resultTmp reference */ + returnOper = &commaSeq->children[2]; + returnOper->type = slang_oper_identifier; + returnOper->a_id = resultVar->a_name; + returnOper->locals->outer_scope = commaSeq->locals; + declOper->locals->outer_scope = commaSeq->locals; + + top = commaSeq; + } + else { + top = inlined = slang_operation_new(1); + /* XXXX this may be inappropriate!!!! */ + inlined->locals->outer_scope = oper->locals->outer_scope; + } + + + assert(inlined->locals); + + /* Examine the parameters, look for inout/out params, look for possible + * substitutions, etc: + * param type behaviour + * in copy actual to local + * const in substitute param with actual + * out copy out + */ + substCount = 0; + for (i = 0; i < totalArgs; 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 */ + slang_operation *arg; + if (i < numArgs) + arg = &args[i]; + else + arg = returnOper; + paramMode[i] = SUBST; + assert(arg->type == slang_oper_identifier + /*||arg->type == slang_oper_variable_decl*/); + slang_resolve_variable(arg); + /* replace parameter 'p' with argument 'arg' */ + substOld[substCount] = p; + substNew[substCount] = arg; /* will get copied */ + substCount++; + } + else if (p->type.qualifier == slang_qual_const) { + /* a constant input param */ + if (args[i].type == slang_oper_identifier || + args[i].type == slang_oper_literal_float) { + /* replace all occurances of this parameter variable with the + * actual argument variable or a literal. + */ + paramMode[i] = SUBST; + slang_resolve_variable(&args[i]); + substOld[substCount] = p; + substNew[substCount] = &args[i]; /* will get copied */ + substCount++; + } + else { + paramMode[i] = COPY_IN; + } + } + else { + paramMode[i] = COPY_IN; + } + 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 + printf("======================= orig body code ======================\n"); + printf("=== params scope = %p\n", (void*) fun->parameters); + slang_print_tree(fun->body, 8); + printf("======================= copied code =========================\n"); + slang_print_tree(inlined, 8); +#endif + + /* do parameter substitution in inlined code: */ + slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE); + +#if 000 + printf("======================= subst code ==========================\n"); + slang_print_tree(inlined, 8); + printf("=============================================================\n"); +#endif + + /* New prolog statements: (inserted before the inlined code) + * Copy the 'in' arguments. + */ + numCopyIn = 0; + for (i = 0; i < numArgs; i++) { + if (paramMode[i] == COPY_IN) { + slang_variable *p = &fun->parameters->variables[i]; + /* declare parameter 'p' */ + slang_operation *decl = slang_operation_insert(&inlined->num_children, + &inlined->children, + numCopyIn); + printf("COPY_IN %s from expr\n", (char*)p->a_name); + decl->type = slang_oper_variable_decl; + assert(decl->locals); + decl->locals = fun->parameters; + decl->a_id = p->a_name; + decl->num_children = 1; + decl->children = slang_operation_new(1); + + /* child[0] is the var's initializer */ + slang_operation_copy(&decl->children[0], args + i); + + numCopyIn++; + } + } + + /* New epilog statements: + * 1. Create end of function label to jump to from return statements. + * 2. Copy the 'out' parameter vars + */ + { + slang_operation *lab = slang_operation_insert(&inlined->num_children, + &inlined->children, + inlined->num_children); + lab->type = slang_oper_label; + lab->a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label); + } + + for (i = 0; i < totalArgs; i++) { + if (paramMode[i] == COPY_OUT) { + const slang_variable *p = &fun->parameters->variables[i]; + /* actualCallVar = outParam */ + /*if (i > 0 || !haveRetValue)*/ + slang_operation *ass = slang_operation_insert(&inlined->num_children, + &inlined->children, + inlined->num_children); + ass->type = slang_oper_assign; + ass->num_children = 2; + ass->locals = _slang_variable_scope_new(inlined->locals); + assert(ass->locals); + ass->children = slang_operation_new(2); + ass->children[0] = args[i]; /*XXX copy */ + ass->children[1].type = slang_oper_identifier; + ass->children[1].a_id = p->a_name; + ass->children[1].locals = _slang_variable_scope_new(ass->locals); + } + } + + _mesa_free(paramMode); + _mesa_free(substOld); + _mesa_free(substNew); + + printf("Done Inline call to %s (total vars=%d nparams=%d)\n", + (char *) fun->header.a_name, + fun->parameters->num_variables, numArgs); + + return top; +} + + +static slang_ir_node * +slang_assemble_function_call(slang_assemble_ctx *A, slang_function *fun, + slang_operation *oper, slang_operation *dest) +{ + slang_ir_node *n; + slang_operation *inlined; + slang_function *prevFunc; + + prevFunc = CurFunction; + CurFunction = fun; + + if (!CurFunction->end_label) { + char name[200]; + sprintf(name, "__endOfFunc_%s_", (char *) CurFunction->header.a_name); + CurFunction->end_label = slang_atom_pool_gen(A->atoms, name); + } + + if (slang_is_asm_function(fun) && !dest) { + /* assemble assembly function - tree style */ + inlined = slang_inline_asm_function(A, fun, oper); + } + else { + /* non-assembly function */ + inlined = slang_inline_function_call(A, fun, oper, dest); + } + + /* Replace the function call with the inlined block */ +#if 0 + slang_operation_construct(oper); + slang_operation_copy(oper, inlined); +#else + *oper = *inlined; +#endif + + +#if 1 + assert(inlined->locals); + printf("*** Inlined code for call to %s:\n", + (char*) fun->header.a_name); + + slang_print_tree(oper, 10); + printf("\n"); +#endif + + /* assemble what we just made XXX here??? */ + n = slang_assemble_operation(A, oper); + + CurFunction = prevFunc; + + return n; +} + + +/** + * Map "_asm foo" to IR_FOO, etc. + */ +typedef struct +{ + const char *Name; + slang_ir_opcode Opcode; + GLuint HaveRetValue, NumParams; +} slang_asm_info; + + +static slang_asm_info AsmInfo[] = { + /* vec4 binary op */ + { "vec4_add", IR_ADD, 1, 2 }, + { "vec4_multiply", IR_MUL, 1, 2 }, + { "vec4_dot", IR_DOT4, 1, 2 }, + { "vec3_dot", IR_DOT3, 1, 2 }, + { "vec3_cross", IR_CROSS, 1, 2 }, + { "vec4_min", IR_MIN, 1, 2 }, + { "vec4_max", IR_MAX, 1, 2 }, + { "vec4_seq", IR_SEQ, 1, 2 }, + { "vec4_sge", IR_SGE, 1, 2 }, + { "vec4_sgt", IR_SGT, 1, 2 }, + /* vec4 unary */ + { "vec4_floor", IR_FLOOR, 1, 1 }, + { "vec4_frac", IR_FRAC, 1, 1 }, + { "vec4_abs", IR_ABS, 1, 1 }, + /* float binary op */ + { "float_add", IR_ADD, 1, 2 }, + { "float_subtract", IR_SUB, 1, 2 }, + { "float_multiply", IR_MUL, 1, 2 }, + { "float_divide", IR_DIV, 1, 2 }, + { "float_power", IR_POW, 1, 2 }, + /* unary op */ + { "int_to_float", IR_I_TO_F, 1, 1 }, + { "float_exp", IR_EXP, 1, 1 }, + { "float_exp2", IR_EXP2, 1, 1 }, + { "float_log2", IR_LOG2, 1, 1 }, + { "float_rsq", IR_RSQ, 1, 1 }, + { "float_rcp", IR_RCP, 1, 1 }, + { "float_sine", IR_SIN, 1, 1 }, + { "float_cosine", IR_COS, 1, 1 }, + { NULL, IR_NOP, 0, 0 } +}; + + +static slang_asm_info * +slang_find_asm_info(const char *name) +{ + GLuint i; + for (i = 0; AsmInfo[i].Name; i++) { + if (_mesa_strcmp(AsmInfo[i].Name, name) == 0) { + return AsmInfo + i; + } + } + return NULL; +} + + +static GLuint +make_writemask(char *field) +{ + GLuint mask = 0x0; + while (*field) { + switch (*field) { + case 'x': + mask |= WRITEMASK_X; + break; + case 'y': + mask |= WRITEMASK_Y; + break; + case 'z': + mask |= WRITEMASK_Z; + break; + case 'w': + mask |= WRITEMASK_W; + break; + default: + abort(); + } + field++; + } + if (mask == 0x0) + return WRITEMASK_XYZW; + else + return mask; +} + + +/** + * Generate IR code for an instruction/operation such as: + * __asm vec4_dot __retVal.x, v1, v2; + */ +static slang_ir_node * +slang_assemble_asm(slang_assemble_ctx *A, slang_operation *oper, + slang_operation *dest) +{ + const slang_asm_info *info; + slang_ir_node *kids[2], *n; + GLuint j, firstOperand; + + assert(oper->type == slang_oper_asm); + + info = slang_find_asm_info((char *) oper->a_id); + assert(info); + assert(info->NumParams <= 2); + + if (info->NumParams == oper->num_children) { + /* storage for result not specified */ + firstOperand = 0; + } + else { + /* storage for result (child[0]) is specified */ + firstOperand = 1; + } + + /* assemble child(ren) */ + kids[0] = kids[1] = NULL; + for (j = 0; j < info->NumParams; j++) { + kids[j] = slang_assemble_operation(A, &oper->children[firstOperand + j]); + } + + n = new_node(info->Opcode, kids[0], kids[1]); + + if (firstOperand) { + /* Setup n->Store to be a particular location. Otherwise, storage + * for the result (a temporary) will be allocated later. + */ + GLuint writemask = WRITEMASK_XYZW; + slang_operation *dest_oper; + slang_ir_node *n0; + + dest_oper = &oper->children[0]; + if (dest_oper->type == slang_oper_field) { + /* writemask */ + writemask = make_writemask((char*) dest_oper->a_id); + dest_oper = &dest_oper->children[0]; + } + + assert(dest_oper->type == slang_oper_identifier); + n0 = slang_assemble_operation(A, dest_oper); + assert(n0->Var); + assert(n0->Store); + free(n0); + + n->Store = n0->Store; + n->Writemask = writemask; + } + + return n; +} + + + + + +/** + * Assemble a function call, given a particular function name. + * \param name the function's name (operators like '*' are possible). + */ +static slang_ir_node * +slang_assemble_function_call_name(slang_assemble_ctx *A, const char *name, + slang_operation *oper, slang_operation *dest) +{ + slang_operation *params = oper->children; + const GLuint param_count = oper->num_children; + slang_atom atom; + slang_function *fun; + + atom = slang_atom_pool_atom(A->atoms, name); + if (atom == SLANG_ATOM_NULL) + return NULL; + + fun = _slang_locate_function(A->space.funcs, atom, params, param_count, + &A->space, A->atoms); + if (!fun) { + RETURN_ERROR2("Undefined function", name, 0); + } + + return slang_assemble_function_call(A, fun, oper, dest); +} + + +static slang_ir_node * +slang_assemble_operation(slang_assemble_ctx * A, slang_operation *oper) +{ + switch (oper->type) { + case slang_oper_block_no_new_scope: + case slang_oper_block_new_scope: + /* list of operations */ + assert(oper->num_children > 0); + { + slang_ir_node *n, *first = NULL; + GLuint i; + for (i = 0; i < oper->num_children; i++) { + n = slang_assemble_operation(A, &oper->children[i]); + first = first ? new_seq(first, n) : n; + } + return first; + } + break; + case slang_oper_expression: + return slang_assemble_operation(A, &oper->children[0]); + break; + case slang_oper_while: + { + slang_ir_node *nStartLabel = new_label("while-start"); + slang_ir_node *nCond = slang_assemble_operation(A, &oper->children[0]); + slang_ir_node *nNotCond = new_node(IR_NOT, nCond, NULL); + slang_ir_node *nBody = slang_assemble_operation(A, &oper->children[1]); + slang_ir_node *nEndLabel = new_label("while-end"); + slang_ir_node *nCJump = new_cjump(nNotCond, "while-end"); + slang_ir_node *nJump = new_jump("while-start"); + + return new_seq(nStartLabel, + new_seq(nCJump, + new_seq(nBody, + new_seq(nJump, + nEndLabel) + ) + ) + ); + } + break; + case slang_oper_less: + return new_node(IR_LESS, + slang_assemble_operation(A, &oper->children[0]), + slang_assemble_operation(A, &oper->children[1])); + case slang_oper_add: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = slang_assemble_function_call_name(A, "+", oper, NULL); + return n; + } + case slang_oper_subtract: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = slang_assemble_function_call_name(A, "-", oper, NULL); + return n; + } + case slang_oper_multiply: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = slang_assemble_function_call_name(A, "*", oper, NULL); + return n; + } + case slang_oper_divide: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = slang_assemble_function_call_name(A, "/", oper, NULL); + return n; + } + + case slang_oper_variable_decl: + { + slang_ir_node *n; + slang_ir_node *varDecl; + slang_variable *v; + + assert(oper->num_children == 0 || oper->num_children == 1); + + v = _slang_locate_variable(oper->locals, + oper->a_id, GL_TRUE); + assert(v); + varDecl = new_var_decl(A, v); + slang_alloc_var_storage(v, varDecl); + + if (oper->num_children > 0) { + /* child is initializer */ + slang_ir_node *var, *init, *rhs; + assert(oper->num_children == 1); + var = new_var(A, oper, oper->a_id, SWIZZLE_NOOP); + /* XXX make copy of this initializer? */ + printf("\n*** ASSEMBLE INITIALIZER %p\n", (void*) v->initializer); + rhs = slang_assemble_operation(A, &oper->children[0]); + init = new_node(IR_MOVE, var, rhs); + n = new_seq(varDecl, init); + } + else if (v->initializer) { + slang_ir_node *var, *init, *rhs; + var = new_var(A, oper, oper->a_id, SWIZZLE_NOOP); + /* XXX make copy of this initializer? */ + printf("\n*** ASSEMBLE INITIALIZER %p\n", (void*) v->initializer); + rhs = slang_assemble_operation(A, v->initializer); + init = new_node(IR_MOVE, var, rhs); + n = new_seq(varDecl, init); + } + else { + n = varDecl; + } + return n; + } + break; + case slang_oper_assign: + /* assignment */ + /* XXX look for special case of: x = f(a, b) + * and replace with f(a, b, x) (where x == hidden __retVal out param) + */ + if (oper->children[0].type == slang_oper_identifier && + oper->children[1].type == slang_oper_call) { + /* special case */ + slang_ir_node *n; + printf(">>>>>>>>>>>>>> Assign function call\n"); + n = slang_assemble_function_call_name(A, + (const char *) oper->children[1].a_id, + &oper->children[1], &oper->children[0]); + return n; + } + else + { + slang_operation *lhs = &oper->children[0]; + slang_ir_node *n, *c0, *c1; + GLuint mask = WRITEMASK_XYZW; + if (lhs->type == slang_oper_field) { + /* writemask */ + if (!slang_is_writemask((char *) lhs->a_id, &mask)) + mask = WRITEMASK_XYZW; + lhs = &lhs->children[0]; + } + c0 = slang_assemble_operation(A, lhs); + c1 = slang_assemble_operation(A, &oper->children[1]); + + n = new_node(IR_MOVE, c0, c1); + n->Writemask = mask; + return n; + } + break; + case slang_oper_asm: + return slang_assemble_asm(A, oper, NULL); + case slang_oper_call: + return slang_assemble_function_call_name(A, (const char *) oper->a_id, + oper, NULL); + break; + case slang_oper_return: + return slang_assemble_return(A, oper); + case slang_oper_goto: + return new_jump((char*) oper->a_id); + case slang_oper_label: + return new_label((char*) oper->a_id); + case slang_oper_identifier: + { + /* If there's a variable associated with this oper (from inlining) + * use it. Otherwise, use the oper's var id. + */ + 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; + } + break; + case slang_oper_field: + { + slang_assembly_typeinfo ti; + slang_assembly_typeinfo_construct(&ti); + _slang_typeof_operation(A, &oper->children[0], &ti); + if (_slang_type_is_vector(ti.spec.type)) { + /* the field should be a swizzle */ + const GLuint rows = _slang_type_dim(ti.spec.type); + slang_swizzle swz; + slang_ir_node *n; + if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { + RETURN_ERROR("Bad swizzle", 0); + } + n = slang_assemble_operation(A, &oper->children[0]); + n->Swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + return n; + } + else if (ti.spec.type == slang_spec_float) { + const GLuint rows = 1; + slang_swizzle swz; + slang_ir_node *n; + if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { + RETURN_ERROR("Bad swizzle", 0); + } + n = slang_assemble_operation(A, &oper->children[0]); + n->Swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + return n; + } + else { + /* the field is a structure member */ + abort(); + } + } + break; + case slang_oper_subscript: + /* array dereference */ + if (oper->children[1].type == slang_oper_literal_int) { + /* compile-time constant index - OK */ + slang_assembly_typeinfo ti; + slang_ir_node *base; + slang_ir_storage *store2; + GLint index; + slang_assembly_typeinfo_construct(&ti); + _slang_typeof_operation(A, &oper->children[0], &ti); + + base = slang_assemble_operation(A, &oper->children[0]); + assert(base->Opcode == IR_VAR); + + index = (GLint) oper->children[1].literal[0]; + /* + printf("element[%d]\n", index); + */ +#if 1 + store2 = (slang_ir_storage *) _mesa_calloc(sizeof(*store2)); + *store2 = *base->Store; + base->Store = store2; + base->Store->Size = -15; +#endif + assert(base->Store); + base->Store->Index += index; + base->Store->Size = 1; + return base; + } + else { + /* run-time index - TBD */ + abort(); + } + return NULL; + case slang_oper_literal_float: + return new_float_literal(oper->literal[0], oper->literal[1], + oper->literal[2], oper->literal[3]); + case slang_oper_literal_int: + return new_float_literal(oper->literal[0], 0, 0, 0); + case slang_oper_literal_bool: + return new_float_literal(oper->literal[0], 0, 0, 0); + case slang_oper_postincrement: + /* XXX not 100% about this */ + { + slang_ir_node *var = slang_assemble_operation(A, &oper->children[0]); + slang_ir_node *one = new_float_literal(1.0, 1.0, 1.0, 1.0); + slang_ir_node *sum = new_node(IR_ADD, var, one); + slang_ir_node *assign = new_node(IR_MOVE, var, sum); + return assign; + } + break; + case slang_oper_sequence: + { + slang_ir_node *top = NULL; + GLuint i; + for (i = 0; i < oper->num_children; i++) { + slang_ir_node *n = slang_assemble_operation(A, &oper->children[i]); + top = top ? new_seq(top, n) : n; + } + return top; + } + break; + case slang_oper_none: + return NULL; + default: + printf("Unhandled node type %d\n", oper->type); + abort(); + return new_node(IR_NOP, NULL, NULL); + } + abort(); + return NULL; +} + + +/** + * Produce an IR tree from a function AST. + * Then call the code emitter to convert the IR tree into a gl_program. + */ +struct slang_ir_node_ * +_slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) +{ + slang_ir_node *n, *endLabel; + + if (_mesa_strcmp((char *) fun->header.a_name, "main") != 0 && + _mesa_strcmp((char *) fun->header.a_name, "foo") != 0 && + _mesa_strcmp((char *) fun->header.a_name, "bar") != 0) + return 0; + + printf("\n*********** Assemble function2(%s)\n", (char*)fun->header.a_name); + + slang_print_function(fun, 1); + + A->program->Parameters = _mesa_new_parameter_list(); + A->program->Varying = _mesa_new_parameter_list(); + + /*printf("** Begin Simplify\n");*/ + slang_simplify(fun->body, &A->space, A->atoms); + /*printf("** End Simplify\n");*/ + + CurFunction = fun; + + n = slang_assemble_operation(A, fun->body); + + if (!CurFunction->end_label) + CurFunction->end_label = slang_atom_pool_gen(A->atoms, "__endOfFunction_Main"); + + endLabel = new_label(fun->end_label); + n = new_seq(n, endLabel); + + CurFunction = NULL; + + + printf("************* New body for %s *****\n", (char*)fun->header.a_name); + slang_print_function(fun, 1); + + printf("************* IR for %s *******\n", (char*)fun->header.a_name); + slang_print_ir(n, 0); + + if (_mesa_strcmp((char*) fun->header.a_name, "main") == 0) { + _slang_emit_code(n, A->program); + } + + printf("************* End assemble function2 ************\n\n"); + + return n; +} + + |