diff options
Diffstat (limited to 'src/mesa/shader/slang/slang_emit.c')
-rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 1027 |
1 files changed, 1027 insertions, 0 deletions
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c new file mode 100644 index 0000000000..0b4ef6dba1 --- /dev/null +++ b/src/mesa/shader/slang/slang_emit.c @@ -0,0 +1,1027 @@ +/* + * 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_emit.c + * Emit program instructions (PI code) from IR trees. + * \author Brian Paul + */ + +#include "imports.h" +#include "context.h" +#include "get.h" +#include "macros.h" +#include "program.h" +#include "program_instruction.h" +#include "slang_emit.h" + + +/** + * Assembly and IR info + */ +typedef struct +{ + slang_ir_opcode IrOpcode; + const char *IrName; + gl_inst_opcode InstOpcode; + GLuint ResultSize, NumParams; +} slang_ir_info; + + + +static slang_ir_info IrInfo[] = { + /* binary ops */ + { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 }, + { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 }, + { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 }, + { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */ + { IR_DOT4, "IR_DOT_4", OPCODE_DP4, 1, 2 }, + { IR_DOT3, "IR_DOT_3", OPCODE_DP3, 1, 2 }, + { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 }, + { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 }, + { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 }, + { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 }, + { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 }, + { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 }, + { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 }, + { IR_POW, "IR_POW", OPCODE_POW, 1, 2 }, + /* unary ops */ + { IR_I_TO_F, "IR_I_TO_F", OPCODE_NOP, 1, 1 }, + { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 }, + { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 }, + { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 }, + { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 }, + { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 }, + { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 }, + { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 }, + { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 }, + { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 }, + { IR_COS, "IR_COS", OPCODE_COS, 1, 1 }, + /* other */ + { IR_SEQ, "IR_SEQ", 0, 0, 0 }, + { IR_LABEL, "IR_LABEL", 0, 0, 0 }, + { IR_JUMP, "IR_JUMP", 0, 0, 0 }, + { IR_CJUMP, "IR_CJUMP", 0, 0, 0 }, + { IR_CALL, "IR_CALL", 0, 0, 0 }, + { IR_MOVE, "IR_MOVE", 0, 0, 1 }, + { IR_LESS, "IR_LESS", 0, 1, 2 }, + { IR_NOT, "IR_NOT", 0, 1, 1 }, + { IR_VAR, "IR_VAR", 0, 0, 0 }, + { IR_VAR_DECL, "IR_VAR_DECL", 0, 0, 0 }, + { IR_FLOAT, "IR_FLOAT", 0, 0, 0 }, + { IR_FIELD, "IR_FIELD", 0, 0, 0 }, + { IR_NOP, NULL, OPCODE_NOP, 0, 0 } +}; + + +static slang_ir_info * +slang_find_ir_info(slang_ir_opcode opcode) +{ + GLuint i; + for (i = 0; IrInfo[i].IrName; i++) { + if (IrInfo[i].IrOpcode == opcode) { + return IrInfo + i; + } + } + return NULL; +} + +static const char * +slang_ir_name(slang_ir_opcode opcode) +{ + return slang_find_ir_info(opcode)->IrName; +} + + +slang_ir_storage * +_slang_new_ir_storage(enum register_file file, GLint index, GLint size) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _mesa_calloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + } + return st; +} + + +static const char * +swizzle_string(GLuint swizzle) +{ + static char s[6]; + GLuint i; + s[0] = '.'; + for (i = 1; i < 5; i++) { + s[i] = "xyzw"[GET_SWZ(swizzle, i-1)]; + } + s[i] = 0; + return s; +} + +static const char * +writemask_string(GLuint writemask) +{ + static char s[6]; + GLuint i, j = 0; + s[j++] = '.'; + for (i = 0; i < 4; i++) { + if (writemask & (1 << i)) + s[j++] = "xyzw"[i]; + } + s[j] = 0; + return s; +} + +static const char * +storage_string(const slang_ir_storage *st) +{ + static const char *files[] = { + "TEMP", + "LOCAL_PARAM", + "ENV_PARAM", + "STATE", + "INPUT", + "OUTPUT", + "NAMED_PARAM", + "CONSTANT", + "UNIFORM", + "WRITE_ONLY", + "ADDRESS", + "UNDEFINED" + }; + static char s[100]; +#if 0 + if (st->Size == 1) + sprintf(s, "%s[%d]", files[st->File], st->Index); + else + sprintf(s, "%s[%d..%d]", files[st->File], st->Index, + st->Index + st->Size - 1); +#endif + sprintf(s, "%s", files[st->File]); + return s; +} + + +static GLuint +sizeof_struct(const slang_struct *s) +{ + return 0; +} + + +static GLuint +sizeof_type(const slang_fully_specified_type *t) +{ + switch (t->specifier.type) { + case slang_spec_void: + abort(); + return 0; + case slang_spec_bool: + return 1; + case slang_spec_bvec2: + return 2; + case slang_spec_bvec3: + return 3; + case slang_spec_bvec4: + return 4; + case slang_spec_int: + return 1; + case slang_spec_ivec2: + return 2; + case slang_spec_ivec3: + return 3; + case slang_spec_ivec4: + return 4; + case slang_spec_float: + return 1; + case slang_spec_vec2: + return 2; + case slang_spec_vec3: + return 3; + case slang_spec_vec4: + return 4; + case slang_spec_mat2: + return 2 * 2; + case slang_spec_mat3: + return 3 * 3; + case slang_spec_mat4: + return 4 * 4; + case slang_spec_sampler1D: + case slang_spec_sampler2D: + case slang_spec_sampler3D: + case slang_spec_samplerCube: + case slang_spec_sampler1DShadow: + case slang_spec_sampler2DShadow: + abort(); + return 0; + case slang_spec_struct: + return sizeof_struct(t->specifier._struct); + case slang_spec_array: + return 1; /* XXX */ + default: + abort(); + return 0; + } + return 0; +} + + +#define IND 0 +void +slang_print_ir(const slang_ir_node *n, int indent) +{ + int i; + if (!n) + return; +#if !IND + if (n->Opcode != IR_SEQ) +#else + printf("%3d:", indent); +#endif + for (i = 0; i < indent; i++) + printf(" "); + + switch (n->Opcode) { + case IR_SEQ: +#if IND + printf("SEQ store %p\n", (void*) n->Store); +#endif + assert(n->Children[0]); + assert(n->Children[1]); + slang_print_ir(n->Children[0], indent + IND); + slang_print_ir(n->Children[1], indent + IND); + break; + case IR_MOVE: + printf("MOVE (writemask = %s)\n", writemask_string(n->Writemask)); + slang_print_ir(n->Children[0], indent+3); + slang_print_ir(n->Children[1], indent+3); + break; + case IR_LABEL: + printf("LABEL: %s\n", n->Target); + break; + case IR_JUMP: + printf("JUMP %s\n", n->Target); + break; + case IR_CJUMP: + printf("CJUMP %s\n", n->Target); + slang_print_ir(n->Children[0], indent+3); + break; + case IR_VAR: + printf("VAR %s%s at %s store %p\n", + (char *) n->Var->a_name, swizzle_string(n->Swizzle), + storage_string(n->Store), (void*) n->Store); + break; + case IR_VAR_DECL: + printf("VAR_DECL %s (%p) at %s store %p\n", + (char *) n->Var->a_name, (void*) n->Var, storage_string(n->Store), + (void*) n->Store); + break; + case IR_FIELD: + printf("FIELD %s of\n", n->Target); + slang_print_ir(n->Children[0], indent+3); + break; + case IR_CALL: + printf("ASMCALL %s(%d args)\n", n->Target, n->Swizzle); + break; + case IR_FLOAT: + printf("FLOAT %f %f %f %f\n", + n->Value[0], n->Value[1], n->Value[2], n->Value[3]); + break; + case IR_I_TO_F: + printf("INT_TO_FLOAT %d\n", (int) n->Value[0]); + break; + default: + printf("%s (%p, %p)\n", slang_ir_name(n->Opcode), + (void*) n->Children[0], (void*) n->Children[1]); + slang_print_ir(n->Children[0], indent+3); + slang_print_ir(n->Children[1], indent+3); + } +} + + +static GLint +alloc_temporary(slang_gen_context *gc) +{ + GLuint i; + for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + if (!gc->TempUsed[i]) { + gc->TempUsed[i] = 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; +} + + +static void +free_temporary(slang_gen_context *gc, GLuint r) +{ + if (gc->TempUsed[r]) + gc->TempUsed[r] = GL_FALSE; +} + + + +static GLint +slang_find_input(GLenum target, const char *name, GLint index) +{ + struct input_info { + const char *Name; + GLuint Attrib; + }; + static const struct input_info vertInputs[] = { + { "gl_Vertex", VERT_ATTRIB_POS }, + { "gl_Normal", VERT_ATTRIB_NORMAL }, + { "gl_Color", VERT_ATTRIB_COLOR0 }, + { "gl_SecondaryColor", VERT_ATTRIB_COLOR1 }, + { NULL, 0 } + }; + static const struct input_info fragInputs[] = { + { NULL, 0 } + }; + const struct input_info *inputs; + GLuint i; + + if (target == GL_VERTEX_PROGRAM_ARB) { + inputs = vertInputs; + } + else { + assert(target == GL_FRAGMENT_PROGRAM_ARB); + inputs = fragInputs; + } + + for (i = 0; inputs[i].Name; i++) { + if (strcmp(inputs[i].Name, name) == 0) { + /* found */ + return inputs[i].Attrib; + } + } + return -1; +} + + +static GLint +slang_find_output(GLenum target, const char *name, GLint index) +{ + struct output_info { + const char *Name; + GLuint Attrib; + }; + static const struct output_info vertOutputs[] = { + { "gl_Position", VERT_RESULT_HPOS }, + { "gl_FrontColor", VERT_RESULT_COL0 }, + { "gl_BackColor", VERT_RESULT_BFC0 }, + { "gl_FrontSecondaryColor", VERT_RESULT_COL1 }, + { "gl_BackSecondaryColor", VERT_RESULT_BFC1 }, + { "gl_TexCoord", VERT_RESULT_TEX0 }, /* XXX indexed */ + { "gl_FogFragCoord", VERT_RESULT_FOGC }, + { NULL, 0 } + }; + static const struct output_info fragOutputs[] = { + { "gl_FragColor", FRAG_RESULT_COLR }, + { NULL, 0 } + }; + const struct output_info *outputs; + GLuint i; + + if (target == GL_VERTEX_PROGRAM_ARB) { + outputs = vertOutputs; + } + else { + assert(target == GL_FRAGMENT_PROGRAM_ARB); + outputs = fragOutputs; + } + + for (i = 0; outputs[i].Name; i++) { + if (strcmp(outputs[i].Name, name) == 0) { + /* found */ + return outputs[i].Attrib; + } + } + return -1; +} + + +/** + * Lookup a named constant and allocate storage for the parameter in + * the given parameter list. + * \return position of the constant in the paramList. + */ +static GLint +slang_lookup_constant(const char *name, GLint index, + struct gl_program_parameter_list *paramList) +{ + struct constant_info { + const char *Name; + const GLenum Token; + }; + static const struct constant_info info[] = { + { "gl_MaxLights", GL_MAX_LIGHTS }, + { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES }, + { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS }, + { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS }, + { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS }, + { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS }, + { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS }, + { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS }, + { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS }, + { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS }, + { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS }, + { NULL, 0 } + }; + GLuint i; + GLuint swizzle; /* XXX use this */ + + for (i = 0; info[i].Name; i++) { + if (strcmp(info[i].Name, name) == 0) { + /* found */ + GLfloat value = -1.0; + GLint pos; + _mesa_GetFloatv(info[i].Token, &value); + ASSERT(value >= 0.0); /* sanity check that glGetFloatv worked */ + pos = _mesa_add_unnamed_constant(paramList, &value, 1, &swizzle); + return pos; + } + } + return -1; +} + + +/** + * Determine if 'name' is a state variable. If so, create a new program + * parameter for it, and return the param's index. Else, return -1. + */ +static GLint +slang_lookup_statevar(const char *name, GLint index, + struct gl_program_parameter_list *paramList) +{ + struct state_info { + const char *Name; + const GLuint NumRows; /** for matrices */ + const GLuint Swizzle; + const GLint Indexes[6]; + }; + static const struct state_info state[] = { + { "gl_ModelViewMatrix", 4, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, STATE_MATRIX_TRANSPOSE } }, + { "gl_NormalMatrix", 3, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, STATE_MATRIX_INVTRANS } }, + { "gl_ProjectionMatrix", 4, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_PROJECTION, 0, 0, 0, STATE_MATRIX_TRANSPOSE } }, + { "gl_ModelViewProjectionMatrix", 4, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_MVP, 0, 0, 0, STATE_MATRIX_TRANSPOSE } }, + { "gl_TextureMatrix", 4, SWIZZLE_NOOP, + { STATE_MATRIX, STATE_TEXTURE, 0, 0, 0, STATE_MATRIX_TRANSPOSE } }, + { NULL, 0, 0, {0, 0, 0, 0, 0, 0} } + }; + GLuint i; + + for (i = 0; state[i].Name; i++) { + if (strcmp(state[i].Name, name) == 0) { + /* found */ + if (paramList) { + if (state[i].NumRows > 1) { + /* a matrix */ + GLuint j; + GLint pos[4], indexesCopy[6]; + /* make copy of state tokens */ + for (j = 0; j < 6; j++) + indexesCopy[j] = state[i].Indexes[j]; + /* load rows */ + for (j = 0; j < state[i].NumRows; j++) { + indexesCopy[3] = indexesCopy[4] = j; /* jth row of matrix */ + pos[j] = _mesa_add_state_reference(paramList, indexesCopy); + assert(pos[j] >= 0); + } + return pos[0]; + } + else { + /* non-matrix state */ + GLint pos + = _mesa_add_state_reference(paramList, state[i].Indexes); + assert(pos >= 0); + return pos; + } + } + } + } + return -1; +} + + +static GLint +slang_alloc_uniform(struct gl_program *prog, const char *name) +{ + GLint i = _mesa_add_uniform(prog->Parameters, name, 4); + return i; +} + + +static GLint +slang_alloc_varying(struct gl_program *prog, const char *name) +{ + GLint i = _mesa_add_varying(prog->Varying, name, 4); /* XXX fix size */ + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + i += VERT_RESULT_VAR0; + prog->OutputsWritten |= (1 << i); + } + else { + i += FRAG_ATTRIB_VAR0; + prog->InputsRead |= (1 << i); + } + return i; +} + + +/** + * 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) +{ + GLint indx; + assert(!n->Var); + assert(!n->Store); + assert(size > 0); + indx = alloc_temporary(gc); + n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, indx, size); +} + + +/** + * Allocate storage info for an IR node (n->Store). + * We may do any of the following: + * 1. Compute Store->File/Index for program inputs/outputs/uniforms/etc. + * 2. Allocate storage for user-declared variables. + * 3. Allocate intermediate/unnamed storage for complex expressions. + * 4. other? + * + * If gc or prog is NULL, we may only be able to determine the Store->File + * but not an Index (register). + */ +void +slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n, + struct gl_program *prog) +{ + int k = 0; + if (!n->Store) { + /**assert(n->Var);**/ + if (n->Var && n->Var->aux) { + /* node storage info = var storage info */ + n->Store = (slang_ir_storage *) n->Var->aux; + } + else { + /* alloc new storage info */ + n->Store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -1, -5); + k = 1; + /*XXX n->Store->Size = sizeof(var's type) */ + if (n->Var) + n->Var->aux = n->Store; + } + } + + if (n->Opcode == IR_VAR_DECL) { + /* allocate storage for a user's variable */ + assert(n->Var); + if (n->Store->Index < 0) { + assert(gc); + n->Store->File = PROGRAM_TEMPORARY; + n->Store->Index = alloc_temporary(gc); + n->Store->Size = sizeof_type(&n->Var->type); + 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 (n->Opcode == IR_VAR && n->Store->File == PROGRAM_UNDEFINED) { + /* try to determine the storage for this variable */ + GLint i; + + assert(n->Var); + assert(prog); + +#if 0 + assert(n->Var->declared || + n->Var->type.qualifier == slang_qual_uniform || + n->Var->type.qualifier == slang_qual_varying || + n->Var->type.qualifier == slang_qual_fixedoutput || + n->Var->type.qualifier == slang_qual_attribute || + n->Var->type.qualifier == slang_qual_out || + n->Var->type.qualifier == slang_qual_const); +#endif + + i = slang_find_input(prog->Target, (char *) n->Var->a_name, 0); + if (i >= 0) { + n->Store->File = PROGRAM_INPUT; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + assert(n->Store->Size > 0); + prog->InputsRead |= (1 << i); + return; + } + + i = slang_find_output(prog->Target, (char *) n->Var->a_name, 0); + if (i >= 0) { + n->Store->File = PROGRAM_OUTPUT; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + prog->OutputsWritten |= (1 << i); + return; + } + + i = slang_lookup_statevar((char *) n->Var->a_name, 0, prog->Parameters); + if (i >= 0) { + n->Store->File = PROGRAM_STATE_VAR; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + return; + } + + i = slang_lookup_constant((char *) n->Var->a_name, 0, prog->Parameters); + if (i >= 0) { + n->Store->File = PROGRAM_CONSTANT; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + return; + } + + /* probably a uniform or varying */ + if (n->Var->type.qualifier == slang_qual_uniform) { + i = slang_alloc_uniform(prog, (char *) n->Var->a_name); + if (i >= 0) { + n->Store->File = PROGRAM_UNIFORM; + n->Store->Index = i; + n->Store->Size = sizeof_type(&n->Var->type); + return; + } + } + else if (n->Var->type.qualifier == slang_qual_varying) { + i = slang_alloc_varying(prog, (char *) n->Var->a_name); + if (i >= 0) { + if (prog->Target == GL_VERTEX_PROGRAM_ARB) + n->Store->File = PROGRAM_OUTPUT; + else + n->Store->File = PROGRAM_INPUT; + n->Store->Size = sizeof_type(&n->Var->type); + n->Store->Index = i; + return; + } + } + + /* what is this?!? */ + /* + abort(); + */ + } + + if (n->Store->File == PROGRAM_TEMPORARY && n->Store->Index < 0) { + /* unnamed intermediate temporary */ + if (gc) + n->Store->Index = alloc_temporary(gc); + return; + } + + if (gc && n->Store->File == PROGRAM_UNDEFINED && n->Store->Size < 0) { + abort(); + } +} + + +static slang_ir_storage * +alloc_constant(const GLfloat v[], GLuint size, struct gl_program *prog) +{ + GLuint swizzle; + GLint ind = _mesa_add_unnamed_constant(prog->Parameters, v, size, &swizzle); + slang_ir_storage *st = _slang_new_ir_storage(PROGRAM_CONSTANT, ind, size); + return st; +} + + +/** + * Swizzle a swizzle. + */ +static GLuint +swizzle_compose(GLuint swz1, GLuint swz2) +{ + GLuint i, swz, s[4]; + for (i = 0; i < 4; i++) { + GLuint c = GET_SWZ(swz1, i); + s[i] = GET_SWZ(swz2, c); + } + swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]); + return swz; +} + + +/** + * Convert IR storage to an instruction dst register. + */ +static void +storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st, + GLuint writemask) +{ + static const GLuint defaultWritemask[4] = { + WRITEMASK_X, + WRITEMASK_X | WRITEMASK_Y, + WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z, + WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z | WRITEMASK_W + }; + dst->File = st->File; + dst->Index = st->Index; + assert(st->Size >= 1); + assert(st->Size <= 4); + dst->WriteMask = defaultWritemask[st->Size - 1] & writemask; +} + + +/** + * Convert IR storage to an instruction src register. + */ +static void +storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st, + GLuint swizzle) +{ + static const GLuint defaultSwizzle[4] = { + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W) + }; + + src->File = st->File; + src->Index = st->Index; + assert(st->Size >= 1); + assert(st->Size <= 4); + /* XXX swizzling logic here may need some work */ + /*src->Swizzle = swizzle_compose(swizzle, defaultSwizzle[st->Size - 1]);*/ + if (swizzle != SWIZZLE_NOOP) + src->Swizzle = swizzle; + else + src->Swizzle = defaultSwizzle[st->Size - 1]; +} + + + +/** + * Add new instruction at end of given program. + * \param prog the program to append instruction onto + * \param opcode opcode for the new instruction + * \return pointer to the new instruction + */ +static struct prog_instruction * +new_instruction(struct gl_program *prog, gl_inst_opcode opcode) +{ + struct prog_instruction *inst; + prog->Instructions = _mesa_realloc_instructions(prog->Instructions, + prog->NumInstructions, + prog->NumInstructions + 1); + inst = prog->Instructions + prog->NumInstructions; + prog->NumInstructions++; + _mesa_init_instructions(inst, 1); + inst->Opcode = opcode; + return inst; +} + + +static struct prog_instruction * +gen(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog); + + +/** + * Generate code for a simple binary-op instruction. + */ +static struct prog_instruction * +gen_binop(slang_gen_context *gc, 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); + + gen(gc, n->Children[0], prog); + gen(gc, n->Children[1], prog); + inst = new_instruction(prog, info->InstOpcode); + /* alloc temp storage for the result: */ + if (!n->Store || n->Store->File == PROGRAM_UNDEFINED) { +#if 1 + slang_alloc_temp_storage(gc, n, info->ResultSize); +#else + slang_resolve_storage(gc, n, prog); +#endif + } + 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); + inst->Comment = n->Comment; + return inst; +} + + +static struct prog_instruction * +gen_unop(slang_gen_context *gc, 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); + + assert(info->NumParams == 1); + + gen(gc, n->Children[0], prog); + + inst = new_instruction(prog, info->InstOpcode); + /*slang_resolve_storage(gc, n, prog);*/ + + 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); + + inst->Comment = n->Comment; + + return inst; +} + + +static struct prog_instruction * +gen(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog) +{ + struct prog_instruction *inst; + if (!n) + return NULL; + + switch (n->Opcode) { + case IR_SEQ: + assert(n->Children[0]); + assert(n->Children[1]); + gen(gc, n->Children[0], prog); + inst = gen(gc, n->Children[1], prog); + n->Store = n->Children[1]->Store; + return inst; + break; + case IR_VAR_DECL: + slang_resolve_storage(gc, n, prog); + assert(n->Store->Index >= 0); + assert(n->Store->Size > 0); + break; + case IR_VAR: + /*printf("Gen: var ref\n");*/ + { + int b = !n->Store || n->Store->Index < 0; + if (b) + slang_resolve_storage(gc, n, prog); + /*assert(n->Store->Index >= 0);*/ + assert(n->Store->Size > 0); + } + break; + case IR_MOVE: + /* rhs */ + assert(n->Children[1]); + inst = gen(gc, n->Children[1], prog); + /* lhs */ + gen(gc, n->Children[0], prog); + +#if 1 + if (inst && is_temporary(gc, n->Children[1]->Store)) { + /* Peephole optimization: + * Just modify the RHS to put its result into the dest of this + * MOVE operation. Then, this MOVE is a no-op. + */ + free_temporary(gc, n->Children[1]->Store->Index); + *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); + return inst; + } + else +#endif + { + inst = new_instruction(prog, OPCODE_MOV); + storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask); + storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store, + n->Children[1]->Swizzle); + if (n->Children[1]->Store->File == PROGRAM_TEMPORARY) { + free_temporary(gc, n->Children[1]->Store->Index); + } + inst->Comment = n->Comment; + n->Store = n->Children[0]->Store; /*XXX new */ + return inst; + } + break; + case IR_ADD: + case IR_SUB: + case IR_MUL: + case IR_DOT4: + case IR_DOT3: + case IR_CROSS: + case IR_MIN: + case IR_MAX: + case IR_SEQUAL: + case IR_SNEQUAL: + case IR_SGE: + case IR_SGT: + case IR_POW: + case IR_EXP: + case IR_EXP2: + return gen_binop(gc, n, prog); + break; + case IR_RSQ: + case IR_RCP: + case IR_FLOOR: + case IR_FRAC: + case IR_ABS: + case IR_SIN: + case IR_COS: + return gen_unop(gc, n, prog); + break; + case IR_LABEL: + /*printf("LAB: %s\n", n->Target);*/ + break; + case IR_JUMP: +#if 0 + inst = new_instruction(prog, OPCODE_BRA); + inst->Comment = _mesa_strdup(n->Target); +#endif + break; + case IR_FLOAT: + n->Store = alloc_constant(n->Value, 4, prog); /*XXX fix size */ + break; + default: + printf("gen: ?\n"); + abort(); + } + return NULL; +} + + + +GLboolean +_slang_emit_code(slang_ir_node *n, struct gl_program *prog) +{ + slang_gen_context *gc; + /*GET_CURRENT_CONTEXT(ctx);*/ + + gc = (slang_gen_context *) _mesa_calloc(sizeof(*gc)); + + printf("************ Begin generate code\n"); + + gen(gc, n, prog); + + { + struct prog_instruction *inst; + inst = new_instruction(prog, OPCODE_END); + } + + printf("************ End generate code (%u inst):\n", prog->NumInstructions); + +#if 0 + _mesa_print_program(prog); + _mesa_print_program_parameters(ctx,prog); +#endif + + _mesa_free(gc); + + return GL_FALSE; +} |