/*
* Mesa 3-D graphics library
- * Version: 6.5.3
+ * Version: 7.1
*
* Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
*
/**
* \file slang_codegen.c
- * Mesa GLSL code generator. Convert AST to IR tree.
+ * Generate IR tree from AST.
* \author Brian Paul
*/
-#include "imports.h"
-#include "macros.h"
+
+/***
+ *** NOTES:
+ *** The new_() functions return a new instance of a simple IR node.
+ *** The gen_() functions generate larger IR trees from the simple nodes.
+ ***/
+
+
+
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "shader/program.h"
+#include "shader/prog_instruction.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_statevars.h"
#include "slang_typeinfo.h"
#include "slang_codegen.h"
#include "slang_compile.h"
-#include "slang_storage.h"
-#include "slang_error.h"
+#include "slang_label.h"
+#include "slang_mem.h"
#include "slang_simplify.h"
#include "slang_emit.h"
#include "slang_vartable.h"
#include "slang_ir.h"
-#include "mtypes.h"
-#include "program.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_statevars.h"
#include "slang_print.h"
_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper);
-
-
-/**
- * Lookup a named constant and allocate storage for the parameter in
- * the given parameter list.
- * \param swizzleOut returns swizzle mask for accessing the constant
- * \return position of the constant in the paramList.
- */
-static GLint
-slang_lookup_constant(const char *name,
- struct gl_program_parameter_list *paramList,
- GLuint *swizzleOut)
-{
- GLint value = _slang_lookup_constant(name);
- if (value >= 0) {
- /* XXX named constant! */
- GLfloat fvalue = (GLfloat) value;
- GLint pos;
- pos = _mesa_add_unnamed_constant(paramList, &fvalue, 1, swizzleOut);
- 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[STATE_LENGTH];
- };
- static const struct state_info state[] = {
- { "gl_ModelViewMatrix", 4, SWIZZLE_NOOP,
- { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, 0 } },
- { "gl_NormalMatrix", 3, SWIZZLE_NOOP,
- { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, 0 } },
- { "gl_ProjectionMatrix", 4, SWIZZLE_NOOP,
- { STATE_MATRIX, STATE_PROJECTION, 0, 0, 0, 0 } },
- { "gl_ModelViewProjectionMatrix", 4, SWIZZLE_NOOP,
- { STATE_MATRIX, STATE_MVP, 0, 0, 0, 0 } },
- { "gl_TextureMatrix", 4, SWIZZLE_NOOP,
- { STATE_MATRIX, STATE_TEXTURE, 0, 0, 0, 0 } },
- { 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[STATE_LENGTH];
- /* make copy of state tokens */
- for (j = 0; j < STATE_LENGTH; 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 GLboolean
is_sampler_type(const slang_fully_specified_type *t)
{
switch (t->specifier.type) {
- case slang_spec_sampler1D:
- case slang_spec_sampler2D:
- case slang_spec_sampler3D:
- case slang_spec_samplerCube:
- case slang_spec_sampler1DShadow:
- case slang_spec_sampler2DShadow:
+ case SLANG_SPEC_SAMPLER1D:
+ case SLANG_SPEC_SAMPLER2D:
+ case SLANG_SPEC_SAMPLER3D:
+ case SLANG_SPEC_SAMPLERCUBE:
+ case SLANG_SPEC_SAMPLER1DSHADOW:
+ case SLANG_SPEC_SAMPLER2DSHADOW:
+ case SLANG_SPEC_SAMPLER2DRECT:
+ case SLANG_SPEC_SAMPLER2DRECTSHADOW:
return GL_TRUE;
default:
return GL_FALSE;
}
-static GLuint
-_slang_sizeof_struct(const slang_struct *s)
+/**
+ * Return the offset (in floats or ints) of the named field within
+ * the given struct. Return -1 if field not found.
+ * If field is NULL, return the size of the struct instead.
+ */
+static GLint
+_slang_field_offset(const slang_type_specifier *spec, slang_atom field)
{
- /* XXX TBD */
- return 0;
+ GLint offset = 0;
+ GLuint i;
+ for (i = 0; i < spec->_struct->fields->num_variables; i++) {
+ const slang_variable *v = spec->_struct->fields->variables[i];
+ const GLuint sz = _slang_sizeof_type_specifier(&v->type.specifier);
+ if (sz > 1) {
+ /* types larger than 1 float are register (4-float) aligned */
+ offset = (offset + 3) & ~3;
+ }
+ if (field && v->a_name == field) {
+ return offset;
+ }
+ offset += sz;
+ }
+ if (field)
+ return -1; /* field not found */
+ else
+ return offset; /* struct size */
}
+/**
+ * Return the size (in floats) of the given type specifier.
+ * If the size is greater than 4, the size should be a multiple of 4
+ * so that the correct number of 4-float registers are allocated.
+ * For example, a mat3x2 is size 12 because we want to store the
+ * 3 columns in 3 float[4] registers.
+ */
GLuint
_slang_sizeof_type_specifier(const slang_type_specifier *spec)
{
+ GLuint sz;
switch (spec->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:
- return 1; /* special case */
- case slang_spec_struct:
- return _slang_sizeof_struct(spec->_struct);
- case slang_spec_array:
- return 1; /* XXX */
+ case SLANG_SPEC_VOID:
+ sz = 0;
+ break;
+ case SLANG_SPEC_BOOL:
+ sz = 1;
+ break;
+ case SLANG_SPEC_BVEC2:
+ sz = 2;
+ break;
+ case SLANG_SPEC_BVEC3:
+ sz = 3;
+ break;
+ case SLANG_SPEC_BVEC4:
+ sz = 4;
+ break;
+ case SLANG_SPEC_INT:
+ sz = 1;
+ break;
+ case SLANG_SPEC_IVEC2:
+ sz = 2;
+ break;
+ case SLANG_SPEC_IVEC3:
+ sz = 3;
+ break;
+ case SLANG_SPEC_IVEC4:
+ sz = 4;
+ break;
+ case SLANG_SPEC_FLOAT:
+ sz = 1;
+ break;
+ case SLANG_SPEC_VEC2:
+ sz = 2;
+ break;
+ case SLANG_SPEC_VEC3:
+ sz = 3;
+ break;
+ case SLANG_SPEC_VEC4:
+ sz = 4;
+ break;
+ case SLANG_SPEC_MAT2:
+ sz = 2 * 4; /* 2 columns (regs) */
+ break;
+ case SLANG_SPEC_MAT3:
+ sz = 3 * 4;
+ break;
+ case SLANG_SPEC_MAT4:
+ sz = 4 * 4;
+ break;
+ case SLANG_SPEC_MAT23:
+ sz = 2 * 4; /* 2 columns (regs) */
+ break;
+ case SLANG_SPEC_MAT32:
+ sz = 3 * 4; /* 3 columns (regs) */
+ break;
+ case SLANG_SPEC_MAT24:
+ sz = 2 * 4;
+ break;
+ case SLANG_SPEC_MAT42:
+ sz = 4 * 4; /* 4 columns (regs) */
+ break;
+ case SLANG_SPEC_MAT34:
+ sz = 3 * 4;
+ break;
+ case SLANG_SPEC_MAT43:
+ sz = 4 * 4; /* 4 columns (regs) */
+ break;
+ case SLANG_SPEC_SAMPLER1D:
+ case SLANG_SPEC_SAMPLER2D:
+ case SLANG_SPEC_SAMPLER3D:
+ case SLANG_SPEC_SAMPLERCUBE:
+ case SLANG_SPEC_SAMPLER1DSHADOW:
+ case SLANG_SPEC_SAMPLER2DSHADOW:
+ case SLANG_SPEC_SAMPLER2DRECT:
+ case SLANG_SPEC_SAMPLER2DRECTSHADOW:
+ sz = 1; /* a sampler is basically just an integer index */
+ break;
+ case SLANG_SPEC_STRUCT:
+ sz = _slang_field_offset(spec, 0); /* special use */
+ if (sz > 4) {
+ sz = (sz + 3) & ~0x3; /* round up to multiple of four */
+ }
+ break;
+ case SLANG_SPEC_ARRAY:
+ sz = _slang_sizeof_type_specifier(spec->_array);
+ break;
default:
- abort();
- return 0;
+ _mesa_problem(NULL, "Unexpected type in _slang_sizeof_type_specifier()");
+ sz = 0;
}
- return 0;
+
+ if (sz > 4) {
+ /* if size is > 4, it should be a multiple of four */
+ assert((sz & 0x3) == 0);
+ }
+ return sz;
}
/**
- * Allocate storage info for an IR node (n->Store).
- * If n is an IR_VAR_DECL, allocate a temporary for the variable.
- * Otherwise, if n is an IR_VAR, check if it's a uniform or constant
- * that needs to have storage allocated.
+ * Establish the binding between a slang_ir_node and a slang_variable.
+ * Then, allocate/attach a slang_ir_storage object to the IR node if needed.
+ * The IR node must be a IR_VAR or IR_VAR_DECL node.
+ * \param n the IR node
+ * \param var the variable to associate with the IR node
*/
static void
-slang_allocate_storage(slang_assemble_ctx *A, slang_ir_node *n)
+_slang_attach_storage(slang_ir_node *n, slang_variable *var)
{
- assert(A->vartable);
assert(n);
+ assert(var);
+ assert(n->Opcode == IR_VAR || n->Opcode == IR_VAR_DECL);
+ assert(!n->Var || n->Var == var);
+
+ n->Var = var;
if (!n->Store) {
- /* allocate storage info for this node */
+ /* need to setup storage */
if (n->Var && n->Var->aux) {
/* node storage info = var storage info */
n->Store = (slang_ir_storage *) n->Var->aux;
assert(n->Var->aux);
}
}
-
- if (n->Opcode == IR_VAR_DECL) {
- /* variable declaration */
- assert(n->Var);
- assert(!is_sampler_type(&n->Var->type));
- n->Store->File = PROGRAM_TEMPORARY;
- n->Store->Size = _slang_sizeof_type_specifier(&n->Var->type.specifier);
- assert(n->Store->Size > 0);
- return;
- }
- else {
- assert(n->Opcode == IR_VAR);
- assert(n->Var);
-
- if (n->Store->Index < 0) {
- const char *varName = (char *) n->Var->a_name;
- struct gl_program *prog = A->program;
- assert(prog);
-
- /* determine storage location for this var.
- * This is probably a pre-defined uniform or constant.
- * We don't allocate storage for these until they're actually
- * used to avoid wasting registers.
- */
- if (n->Store->File == PROGRAM_STATE_VAR) {
- GLint i = slang_lookup_statevar(varName, 0, prog->Parameters);
- assert(i >= 0);
- n->Store->Index = i;
- }
- else if (n->Store->File == PROGRAM_CONSTANT) {
- /* XXX compile-time constants should be converted to literals */
- GLint i = slang_lookup_constant(varName, prog->Parameters,
- &n->Store->Swizzle);
- assert(i >= 0);
- assert(n->Store->Size == 1);
- n->Store->Index = i;
- }
- }
- }
}
sampler_to_texture_index(const slang_type_specifier_type type)
{
switch (type) {
- case slang_spec_sampler1D:
+ case SLANG_SPEC_SAMPLER1D:
return TEXTURE_1D_INDEX;
- case slang_spec_sampler2D:
+ case SLANG_SPEC_SAMPLER2D:
return TEXTURE_2D_INDEX;
- case slang_spec_sampler3D:
+ case SLANG_SPEC_SAMPLER3D:
return TEXTURE_3D_INDEX;
- case slang_spec_samplerCube:
+ case SLANG_SPEC_SAMPLERCUBE:
return TEXTURE_CUBE_INDEX;
- case slang_spec_sampler1DShadow:
+ case SLANG_SPEC_SAMPLER1DSHADOW:
return TEXTURE_1D_INDEX; /* XXX fix */
- case slang_spec_sampler2DShadow:
+ case SLANG_SPEC_SAMPLER2DSHADOW:
return TEXTURE_2D_INDEX; /* XXX fix */
+ case SLANG_SPEC_SAMPLER2DRECT:
+ return TEXTURE_RECT_INDEX;
+ case SLANG_SPEC_SAMPLER2DRECTSHADOW:
+ return TEXTURE_RECT_INDEX; /* XXX fix */
default:
return -1;
}
* XXX return size too
*/
static GLint
-_slang_input_index(const char *name, GLenum target)
+_slang_input_index(const char *name, GLenum target, GLuint *swizzleOut)
{
struct input_info {
const char *Name;
GLuint Attrib;
+ GLuint Swizzle;
};
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 },
- { "gl_FogCoord", VERT_ATTRIB_FOG },
- { "gl_MultiTexCoord0", VERT_ATTRIB_TEX0 },
- { "gl_MultiTexCoord1", VERT_ATTRIB_TEX1 },
- { "gl_MultiTexCoord2", VERT_ATTRIB_TEX2 },
- { "gl_MultiTexCoord3", VERT_ATTRIB_TEX3 },
- { "gl_MultiTexCoord4", VERT_ATTRIB_TEX4 },
- { "gl_MultiTexCoord5", VERT_ATTRIB_TEX5 },
- { "gl_MultiTexCoord6", VERT_ATTRIB_TEX6 },
- { "gl_MultiTexCoord7", VERT_ATTRIB_TEX7 },
- { NULL, 0 }
+ { "gl_Vertex", VERT_ATTRIB_POS, SWIZZLE_NOOP },
+ { "gl_Normal", VERT_ATTRIB_NORMAL, SWIZZLE_NOOP },
+ { "gl_Color", VERT_ATTRIB_COLOR0, SWIZZLE_NOOP },
+ { "gl_SecondaryColor", VERT_ATTRIB_COLOR1, SWIZZLE_NOOP },
+ { "gl_FogCoord", VERT_ATTRIB_FOG, SWIZZLE_XXXX },
+ { "gl_MultiTexCoord0", VERT_ATTRIB_TEX0, SWIZZLE_NOOP },
+ { "gl_MultiTexCoord1", VERT_ATTRIB_TEX1, SWIZZLE_NOOP },
+ { "gl_MultiTexCoord2", VERT_ATTRIB_TEX2, SWIZZLE_NOOP },
+ { "gl_MultiTexCoord3", VERT_ATTRIB_TEX3, SWIZZLE_NOOP },
+ { "gl_MultiTexCoord4", VERT_ATTRIB_TEX4, SWIZZLE_NOOP },
+ { "gl_MultiTexCoord5", VERT_ATTRIB_TEX5, SWIZZLE_NOOP },
+ { "gl_MultiTexCoord6", VERT_ATTRIB_TEX6, SWIZZLE_NOOP },
+ { "gl_MultiTexCoord7", VERT_ATTRIB_TEX7, SWIZZLE_NOOP },
+ { NULL, 0, SWIZZLE_NOOP }
};
static const struct input_info fragInputs[] = {
- { "gl_FragCoord", FRAG_ATTRIB_WPOS },
- { "gl_Color", FRAG_ATTRIB_COL0 },
- { "gl_SecondaryColor", FRAG_ATTRIB_COL1 },
- { "gl_FogFragCoord", FRAG_ATTRIB_FOGC },
- { "gl_TexCoord", FRAG_ATTRIB_TEX0 },
- { NULL, 0 }
+ { "gl_FragCoord", FRAG_ATTRIB_WPOS, SWIZZLE_NOOP },
+ { "gl_Color", FRAG_ATTRIB_COL0, SWIZZLE_NOOP },
+ { "gl_SecondaryColor", FRAG_ATTRIB_COL1, SWIZZLE_NOOP },
+ { "gl_FogFragCoord", FRAG_ATTRIB_FOGC, SWIZZLE_XXXX },
+ { "gl_TexCoord", FRAG_ATTRIB_TEX0, SWIZZLE_NOOP },
+ { "gl_FrontFacing", FRAG_ATTRIB_FOGC, SWIZZLE_YYYY }, /*XXX*/
+ { NULL, 0, SWIZZLE_NOOP }
};
GLuint i;
const struct input_info *inputs
for (i = 0; inputs[i].Name; i++) {
if (strcmp(inputs[i].Name, name) == 0) {
/* found */
+ *swizzleOut = inputs[i].Swizzle;
return inputs[i].Attrib;
}
}
{ "gl_BackColor", VERT_RESULT_BFC0 },
{ "gl_FrontSecondaryColor", VERT_RESULT_COL1 },
{ "gl_BackSecondaryColor", VERT_RESULT_BFC1 },
- { "gl_TexCoord", VERT_RESULT_TEX0 }, /* XXX indexed */
+ { "gl_TexCoord", VERT_RESULT_TEX0 },
{ "gl_FogFragCoord", VERT_RESULT_FOGC },
{ "gl_PointSize", VERT_RESULT_PSIZ },
{ NULL, 0 }
static const struct output_info fragOutputs[] = {
{ "gl_FragColor", FRAG_RESULT_COLR },
{ "gl_FragDepth", FRAG_RESULT_DEPR },
+ { "gl_FragData", FRAG_RESULT_DATA0 },
{ NULL, 0 }
};
GLuint i;
{ "vec4_min", IR_MIN, 1, 2 },
{ "vec4_max", IR_MAX, 1, 2 },
{ "vec4_clamp", IR_CLAMP, 1, 3 },
- { "vec4_seq", IR_SEQ, 1, 2 },
+ { "vec4_seq", IR_SEQUAL, 1, 2 },
+ { "vec4_sne", IR_SNEQUAL, 1, 2 },
{ "vec4_sge", IR_SGE, 1, 2 },
{ "vec4_sgt", IR_SGT, 1, 2 },
+ { "vec4_sle", IR_SLE, 1, 2 },
+ { "vec4_slt", IR_SLT, 1, 2 },
/* vec4 unary */
{ "vec4_floor", IR_FLOOR, 1, 1 },
{ "vec4_frac", IR_FRAC, 1, 1 },
{ "vec4_ddx", IR_DDX, 1, 1 },
{ "vec4_ddy", IR_DDY, 1, 1 },
/* float binary op */
- { "float_add", IR_ADD, 1, 2 },
- { "float_multiply", IR_MUL, 1, 2 },
- { "float_divide", IR_DIV, 1, 2 },
{ "float_power", IR_POW, 1, 2 },
/* texture / sampler */
{ "vec4_tex1d", IR_TEX, 1, 2 },
{ "vec4_texb3d", IR_TEXB, 1, 2 }, /* 3d w/ bias */
{ "vec4_texp3d", IR_TEXP, 1, 2 }, /* 3d w/ projection */
{ "vec4_texcube", IR_TEX, 1, 2 }, /* cubemap */
+ { "vec4_tex_rect", IR_TEX, 1, 2 }, /* rectangle */
+ { "vec4_texp_rect", IR_TEX, 1, 2 },/* rectangle w/ projection */
/* unary op */
{ "int_to_float", IR_I_TO_F, 1, 1 },
};
-/**
- * Recursively free an IR tree.
- */
-static void
-_slang_free_ir_tree(slang_ir_node *n)
-{
-#if 0
- GLuint i;
- if (!n)
- return;
- for (i = 0; i < 3; i++)
- _slang_free_ir_tree(n->Children[i]);
- /* Do not free n->BranchNode since it's a child elsewhere */
- free(n);
-#endif
-}
-
-
static slang_ir_node *
new_node3(slang_ir_opcode op,
slang_ir_node *c0, slang_ir_node *c1, slang_ir_node *c2)
{
- slang_ir_node *n = (slang_ir_node *) calloc(1, sizeof(slang_ir_node));
+ slang_ir_node *n = (slang_ir_node *) _slang_alloc(sizeof(slang_ir_node));
if (n) {
n->Opcode = op;
n->Children[0] = c0;
}
static slang_ir_node *
-new_label(slang_atom labName)
+new_label(slang_label *label)
{
slang_ir_node *n = new_node0(IR_LABEL);
- n->Target = (char *) labName; /*_mesa_strdup(name);*/
+ assert(label);
+ if (n)
+ n->Label = label;
return n;
}
static slang_ir_node *
-new_float_literal(const float v[4])
+new_float_literal(const float v[4], GLuint size)
{
- const GLuint size = (v[0] == v[1] && v[0] == v[2] && v[0] == v[3]) ? 1 : 4;
slang_ir_node *n = new_node0(IR_FLOAT);
+ assert(size <= 4);
COPY_4V(n->Value, v);
/* allocate a storage object, but compute actual location (Index) later */
n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size);
return n;
}
+
+static slang_ir_node *
+new_not(slang_ir_node *n)
+{
+ return new_node1(IR_NOT, n);
+}
+
+
/**
- * Conditional jump.
- * \param zeroOrOne indicates if the jump is to be taken on zero, or non-zero
- * condition code state.
- * XXX maybe pass an IR node as second param to indicate the jump target???
+ * Inlined subroutine.
*/
static slang_ir_node *
-new_cjump(slang_atom target, GLuint zeroOrOne)
+new_inlined_function_call(slang_ir_node *code, slang_label *name)
{
- slang_ir_node *n = new_node0(zeroOrOne ? IR_CJUMP1 : IR_CJUMP0);
+ slang_ir_node *n = new_node1(IR_FUNC, code);
+ assert(name);
if (n)
- n->Target = (char *) target;
+ n->Label = name;
return n;
}
+
/**
* Unconditional jump.
- * XXX maybe pass an IR node as second param to indicate the jump target???
*/
static slang_ir_node *
-new_jump(slang_atom target)
+new_return(slang_label *dest)
{
- slang_ir_node *n = new_node0(IR_JUMP);
+ slang_ir_node *n = new_node0(IR_RETURN);
+ assert(dest);
if (n)
- n->Target = (char *) target;
+ n->Label = dest;
return n;
}
assert(loopNode->Opcode == IR_LOOP);
if (n) {
/* insert this node at head of linked list */
- n->BranchNode = loopNode->BranchNode;
- loopNode->BranchNode = n;
+ n->List = loopNode->List;
+ loopNode->List = n;
}
return n;
}
/**
- * Make new IR_BREAK_IF_TRUE or IR_BREAK_IF_FALSE node.
+ * Make new IR_BREAK_IF_TRUE.
*/
static slang_ir_node *
-new_break_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean breakTrue)
+new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond)
{
slang_ir_node *n;
assert(loopNode);
assert(loopNode->Opcode == IR_LOOP);
- n = new_node1(breakTrue ? IR_BREAK_IF_TRUE : IR_BREAK_IF_FALSE, cond);
+ n = new_node1(IR_BREAK_IF_TRUE, cond);
if (n) {
/* insert this node at head of linked list */
- n->BranchNode = loopNode->BranchNode;
- loopNode->BranchNode = n;
+ n->List = loopNode->List;
+ loopNode->List = n;
}
return n;
}
/**
- * Make new IR_CONT_IF_TRUE or IR_CONT_IF_FALSE node.
+ * Make new IR_CONT_IF_TRUE node.
*/
static slang_ir_node *
-new_cont_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean contTrue)
+new_cont_if_true(slang_ir_node *loopNode, slang_ir_node *cond)
{
slang_ir_node *n;
assert(loopNode);
assert(loopNode->Opcode == IR_LOOP);
- n = new_node1(contTrue ? IR_CONT_IF_TRUE : IR_CONT_IF_FALSE, cond);
- if (n) {
- /* insert this node at head of linked list */
- n->BranchNode = loopNode->BranchNode;
- loopNode->BranchNode = n;
- }
- return n;
-}
-
-
-static slang_ir_node *
-new_cont(slang_ir_node *loopNode)
-{
- slang_ir_node *n = new_node0(IR_CONT);
- assert(loopNode);
- assert(loopNode->Opcode == IR_LOOP);
+ n = new_node1(IR_CONT_IF_TRUE, cond);
if (n) {
/* insert this node at head of linked list */
- n->BranchNode = loopNode->BranchNode;
- loopNode->BranchNode = n;
+ n->List = loopNode->List;
+ loopNode->List = n;
}
return n;
}
static slang_ir_node *
new_var(slang_assemble_ctx *A, slang_operation *oper, slang_atom name)
{
- slang_variable *v = _slang_locate_variable(oper->locals, name, GL_TRUE);
- slang_ir_node *n = new_node0(IR_VAR);
- if (!v)
+ slang_ir_node *n;
+ slang_variable *var = _slang_locate_variable(oper->locals, name, GL_TRUE);
+ if (!var)
return NULL;
- assert(!oper->var || oper->var == v);
- v->used = GL_TRUE;
- n->Var = v;
- slang_allocate_storage(A, n);
+ assert(!oper->var || oper->var == var);
+
+ n = new_node0(IR_VAR);
+ if (n) {
+ _slang_attach_storage(n, var);
+ }
return n;
}
static GLboolean
slang_is_asm_function(const slang_function *fun)
{
- if (fun->body->type == slang_oper_block_no_new_scope &&
+ if (fun->body->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE &&
fun->body->num_children == 1 &&
- fun->body->children[0].type == slang_oper_asm) {
+ fun->body->children[0].type == SLANG_OPER_ASM) {
return GL_TRUE;
}
return GL_FALSE;
}
+static GLboolean
+_slang_is_noop(const slang_operation *oper)
+{
+ if (!oper ||
+ oper->type == SLANG_OPER_VOID ||
+ (oper->num_children == 1 && oper->children[0].type == SLANG_OPER_VOID))
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
+
+
/**
- * Produce inline code for a call to an assembly instruction.
+ * Recursively search tree for a node of the given type.
*/
static slang_operation *
-slang_inline_asm_function(slang_assemble_ctx *A,
- slang_function *fun, slang_operation *oper)
+_slang_find_node_type(slang_operation *oper, slang_operation_type type)
{
- const GLuint 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 */
- /*
- 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;
- 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);
+ if (oper->type == type)
+ return oper;
+ for (i = 0; i < oper->num_children; i++) {
+ slang_operation *p = _slang_find_node_type(&oper->children[i], type);
+ if (p)
+ return p;
}
-
- return inlined;
+ return NULL;
}
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;
+ if (oper->type == SLANG_OPER_IDENTIFIER && !oper->var) {
+ oper->var = _slang_locate_variable(oper->locals, oper->a_id, GL_TRUE);
}
}
/**
- * Replace particular variables (slang_oper_identifier) with new expressions.
+ * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions.
*/
static void
slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
slang_operation **substNew, GLboolean isLHS)
{
switch (oper->type) {
- case slang_oper_variable_decl:
+ case SLANG_OPER_VARIABLE_DECL:
{
slang_variable *v = _slang_locate_variable(oper->locals,
oper->a_id, GL_TRUE);
}
if (oper->num_children == 1) {
/* the initializer */
- slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_FALSE);
+ slang_substitute(A, &oper->children[0], substCount,
+ substOld, substNew, GL_FALSE);
}
}
break;
- case slang_oper_identifier:
+ case SLANG_OPER_IDENTIFIER:
assert(oper->num_children == 0);
if (1/**!isLHS XXX FIX */) {
slang_atom id = oper->a_id;
GLuint i;
v = _slang_locate_variable(oper->locals, id, GL_TRUE);
if (!v) {
- printf("var %s not found!\n", (char *) oper->a_id);
- _slang_print_var_scope(oper->locals, 6);
-
- abort();
- break;
+ _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id);
+ return;
}
/* look for a substitution */
for (i = 0; i < substCount; i++) {
if (v == substOld[i]) {
- /* OK, replace this slang_oper_identifier with a new expr */
+ /* OK, replace this SLANG_OPER_IDENTIFIER with a new expr */
#if 0 /* DEBUG only */
- if (substNew[i]->type == slang_oper_identifier) {
+ 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",
}
}
break;
-#if 1 /* XXX rely on default case below */
- case slang_oper_return:
+
+ case SLANG_OPER_RETURN:
/* do return replacement here too */
assert(oper->num_children == 0 || oper->num_children == 1);
- if (oper->num_children == 1) {
+ if (oper->num_children == 1 && !_slang_is_noop(&oper->children[0])) {
/* replace:
* return expr;
* with:
* then do substitutions on the assignment.
*/
slang_operation *blockOper, *assignOper, *returnOper;
+
+ /* check if function actually has a return type */
+ assert(A->CurFunction);
+ if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) {
+ slang_info_log_error(A->log, "illegal return expression");
+ return;
+ }
+
blockOper = slang_operation_new(1);
- blockOper->type = slang_oper_block_no_new_scope;
+ blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE;
blockOper->num_children = 2;
+ blockOper->locals->outer_scope = oper->locals->outer_scope;
blockOper->children = slang_operation_new(2);
assignOper = blockOper->children + 0;
returnOper = blockOper->children + 1;
- assignOper->type = slang_oper_assign;
+ assignOper->type = SLANG_OPER_ASSIGN;
assignOper->num_children = 2;
+ assignOper->locals->outer_scope = blockOper->locals;
assignOper->children = slang_operation_new(2);
- assignOper->children[0].type = slang_oper_identifier;
+ assignOper->children[0].type = SLANG_OPER_IDENTIFIER;
assignOper->children[0].a_id = slang_atom_pool_atom(A->atoms, "__retVal");
- assignOper->children[0].locals->outer_scope = oper->locals;
- assignOper->locals = oper->locals;
+ assignOper->children[0].locals->outer_scope = assignOper->locals;
+
slang_operation_copy(&assignOper->children[1],
&oper->children[0]);
- returnOper->type = slang_oper_return;
+ returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */
assert(returnOper->num_children == 0);
/* do substitutions on the "__retVal = expr" sub-tree */
slang_operation_copy(oper, blockOper);
slang_operation_destruct(blockOper);
}
+ else {
+ /* check if return value was expected */
+ assert(A->CurFunction);
+ if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
+ slang_info_log_error(A->log, "return statement requires an expression");
+ return;
+ }
+ }
break;
-#endif
- case slang_oper_assign:
- case slang_oper_subscript:
+
+ 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[1],
substCount, substOld, substNew, GL_FALSE);
break;
- case slang_oper_field:
+ case SLANG_OPER_FIELD:
/* XXX NEW - test */
slang_substitute(A, &oper->children[0],
substCount, substOld, substNew, GL_TRUE);
+/**
+ * Produce inline code for a call to an assembly instruction.
+ * This is typically used to compile a call to a built-in function like this:
+ *
+ * vec4 mix(const vec4 x, const vec4 y, const vec4 a)
+ * {
+ * __asm vec4_lrp __retVal, a, y, x;
+ * }
+ *
+ * We basically translate a SLANG_OPER_CALL into a SLANG_OPER_ASM.
+ */
+static slang_operation *
+slang_inline_asm_function(slang_assemble_ctx *A,
+ slang_function *fun, slang_operation *oper)
+{
+ const GLuint numArgs = oper->num_children;
+ GLuint i;
+ slang_operation *inlined;
+ const GLboolean haveRetValue = _slang_function_has_return_value(fun);
+ slang_variable **substOld;
+ slang_operation **substNew;
+
+ ASSERT(slang_is_asm_function(fun));
+ ASSERT(fun->param_count == numArgs + haveRetValue);
+
+ /*
+ printf("Inline %s as %s\n",
+ (char*) fun->header.a_name,
+ (char*) fun->body->children[0].a_id);
+ */
+
+ /*
+ * We'll substitute formal params with actual args in the asm call.
+ */
+ substOld = (slang_variable **)
+ _slang_alloc(numArgs * sizeof(slang_variable *));
+ substNew = (slang_operation **)
+ _slang_alloc(numArgs * sizeof(slang_operation *));
+ for (i = 0; i < numArgs; i++) {
+ substOld[i] = fun->parameters->variables[i];
+ substNew[i] = oper->children + i;
+ }
+
+ /* make a copy of the code to inline */
+ inlined = slang_operation_new(1);
+ slang_operation_copy(inlined, &fun->body->children[0]);
+ if (haveRetValue) {
+ /* get rid of the __retVal child */
+ for (i = 0; i < numArgs; i++) {
+ inlined->children[i] = inlined->children[i + 1];
+ }
+ inlined->num_children--;
+ }
+
+ /* now do formal->actual substitutions */
+ slang_substitute(A, inlined, numArgs, substOld, substNew, GL_FALSE);
+
+ _slang_free(substOld);
+ _slang_free(substNew);
+
+ return inlined;
+}
+
+
/**
* Inline the given function call operation.
* Return a new slang_operation that corresponds to the inlined code.
slang_variable **substOld;
slang_operation **substNew;
GLuint substCount, numCopyIn, i;
+ slang_function *prevFunction;
- /*assert(oper->type == slang_oper_call); (or (matrix) multiply, etc) */
+ /* save / push */
+ prevFunction = A->CurFunction;
+ A->CurFunction = fun;
+
+ /*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));
+ _slang_alloc(totalArgs * sizeof(ParamMode));
substOld = (slang_variable **)
- _mesa_calloc(totalArgs * sizeof(slang_variable *));
+ _slang_alloc(totalArgs * sizeof(slang_variable *));
substNew = (slang_operation **)
- _mesa_calloc(totalArgs * sizeof(slang_operation *));
+ _slang_alloc(totalArgs * sizeof(slang_operation *));
#if 0
printf("Inline call to %s (total vars=%d nparams=%d)\n",
slang_variable *resultVar;
commaSeq = slang_operation_new(1);
- commaSeq->type = slang_oper_sequence;
+ commaSeq->type = SLANG_OPER_SEQUENCE;
assert(commaSeq->locals);
commaSeq->locals->outer_scope = oper->locals->outer_scope;
commaSeq->num_children = 3;
/* child[0] = __resultTmp declaration */
declOper = &commaSeq->children[0];
- declOper->type = slang_oper_variable_decl;
+ declOper->type = SLANG_OPER_VARIABLE_DECL;
declOper->a_id = resultVar->a_name;
- declOper->locals->outer_scope = commaSeq->locals; /*** ??? **/
+ 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->type = SLANG_OPER_IDENTIFIER;
returnOper->a_id = resultVar->a_name;
returnOper->locals->outer_scope = commaSeq->locals;
- declOper->locals->outer_scope = commaSeq->locals;
top = commaSeq;
}
slang_type_qual_string(p->type.qualifier),
(char *) p->a_name);
*/
- if (p->type.qualifier == slang_qual_inout ||
- p->type.qualifier == slang_qual_out) {
+ if (p->type.qualifier == SLANG_QUAL_INOUT ||
+ p->type.qualifier == SLANG_QUAL_OUT) {
/* an output param */
slang_operation *arg;
if (i < numArgs)
arg = returnOper;
paramMode[i] = SUBST;
- if (arg->type == slang_oper_identifier)
+ if (arg->type == SLANG_OPER_IDENTIFIER)
slang_resolve_variable(arg);
/* replace parameter 'p' with argument 'arg' */
substNew[substCount] = arg; /* will get copied */
substCount++;
}
- else if (p->type.qualifier == slang_qual_const) {
+ 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) {
+ 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.
*/
slang_operation_copy(inlined, fun->body);
/*** XXX review this */
- assert(inlined->type = slang_oper_block_no_new_scope);
- inlined->type = slang_oper_block_new_scope;
+ assert(inlined->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE);
+ inlined->type = SLANG_OPER_BLOCK_NEW_SCOPE;
#if 0
printf("======================= orig body code ======================\n");
/*
printf("COPY_IN %s from expr\n", (char*)p->a_name);
*/
- decl->type = slang_oper_variable_decl;
+ decl->type = SLANG_OPER_VARIABLE_DECL;
assert(decl->locals);
- decl->locals = fun->parameters;
+ decl->locals->outer_scope = inlined->locals;
decl->a_id = p->a_name;
decl->num_children = 1;
decl->children = slang_operation_new(1);
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,
- (char *) A->CurFunction->end_label);
+ lab->type = SLANG_OPER_LABEL;
+ lab->label = A->curFuncEndLabel;
}
for (i = 0; i < totalArgs; i++) {
slang_operation *ass = slang_operation_insert(&inlined->num_children,
&inlined->children,
inlined->num_children);
- ass->type = slang_oper_assign;
+ ass->type = SLANG_OPER_ASSIGN;
ass->num_children = 2;
- ass->locals = _slang_variable_scope_new(inlined->locals);
- assert(ass->locals);
+ ass->locals->outer_scope = inlined->locals;
ass->children = slang_operation_new(2);
ass->children[0] = args[i]; /*XXX copy */
- ass->children[1].type = slang_oper_identifier;
+ 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);
+ ass->children[1].locals->outer_scope = ass->locals;
}
}
- _mesa_free(paramMode);
- _mesa_free(substOld);
- _mesa_free(substNew);
+ _slang_free(paramMode);
+ _slang_free(substOld);
+ _slang_free(substNew);
#if 0
printf("Done Inline call to %s (total vars=%d nparams=%d)\n",
fun->parameters->num_variables, numArgs);
slang_print_tree(top, 0);
#endif
+
+ /* pop */
+ A->CurFunction = prevFunction;
+
return top;
}
{
slang_ir_node *n;
slang_operation *inlined;
- slang_function *prevFunc;
+ slang_label *prevFuncEndLabel;
+ char name[200];
- prevFunc = A->CurFunction;
- A->CurFunction = fun;
-
- if (!A->CurFunction->end_label) {
- char name[200];
- sprintf(name, "__endOfFunc_%s_", (char *) A->CurFunction->header.a_name);
- A->CurFunction->end_label = slang_atom_pool_gen(A->atoms, name);
- }
+ prevFuncEndLabel = A->curFuncEndLabel;
+ sprintf(name, "__endOfFunc_%s_", (char *) fun->header.a_name);
+ A->curFuncEndLabel = _slang_label_new(name);
+ assert(A->curFuncEndLabel);
if (slang_is_asm_function(fun) && !dest) {
/* assemble assembly function - tree style */
else {
/* non-assembly function */
inlined = slang_inline_function_call(A, fun, oper, dest);
+ if (inlined && _slang_find_node_type(inlined, SLANG_OPER_RETURN)) {
+ /* This inlined function has one or more 'return' statements.
+ * So, we can't truly inline this function because we need to
+ * implement 'return' with RET (and CAL).
+ * XXX check if there's one 'return' and if it's the very last
+ * statement in the function - we can optimize that case.
+ */
+ assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
+ inlined->type == SLANG_OPER_SEQUENCE);
+ inlined->type = SLANG_OPER_INLINED_CALL;
+ inlined->fun = fun;
+ inlined->label = _slang_label_new_unique((char*) fun->header.a_name);
+ }
}
+ if (!inlined)
+ return NULL;
+
/* Replace the function call with the inlined block */
-#if 0
- slang_operation_construct(oper);
- slang_operation_copy(oper, inlined);
-#else
+ slang_operation_destruct(oper);
*oper = *inlined;
-#endif
-
+ _slang_free(inlined);
#if 0
assert(inlined->locals);
n = _slang_gen_operation(A, oper);
- A->CurFunction->end_label = NULL;
-
- A->CurFunction = prevFunc;
+ /*_slang_label_delete(A->curFuncEndLabel);*/
+ A->curFuncEndLabel = prevFuncEndLabel;
return n;
}
static GLuint
-make_writemask(char *field)
+make_writemask(const char *field)
{
GLuint mask = 0x0;
while (*field) {
switch (*field) {
case 'x':
+ case 's':
+ case 'r':
mask |= WRITEMASK_X;
break;
case 'y':
+ case 't':
+ case 'g':
mask |= WRITEMASK_Y;
break;
case 'z':
+ case 'p':
+ case 'b':
mask |= WRITEMASK_Z;
break;
case 'w':
+ case 'q':
+ case 'a':
mask |= WRITEMASK_W;
break;
default:
- abort();
+ _mesa_problem(NULL, "invalid writemask in make_writemask()");
+ return 0;
}
field++;
}
*/
static slang_ir_node *
_slang_gen_asm(slang_assemble_ctx *A, slang_operation *oper,
- slang_operation *dest)
+ slang_operation *dest)
{
const slang_asm_info *info;
slang_ir_node *kids[3], *n;
GLuint j, firstOperand;
- assert(oper->type == slang_oper_asm);
+ assert(oper->type == SLANG_OPER_ASM);
info = slang_find_asm_info((char *) oper->a_id);
if (!info) {
kids[0] = kids[1] = kids[2] = NULL;
for (j = 0; j < info->NumParams; j++) {
kids[j] = _slang_gen_operation(A, &oper->children[firstOperand + j]);
+ if (!kids[j])
+ return NULL;
}
n = new_node3(info->Opcode, kids[0], kids[1], kids[2]);
slang_ir_node *n0;
dest_oper = &oper->children[0];
- while /*if*/ (dest_oper->type == slang_oper_field) {
+ while (dest_oper->type == SLANG_OPER_FIELD) {
/* writemask */
- writemask &= /*=*/make_writemask((char*) dest_oper->a_id);
+ writemask &= make_writemask((char*) dest_oper->a_id);
dest_oper = &dest_oper->children[0];
}
n->Store = n0->Store;
n->Writemask = writemask;
- free(n0);
+ _slang_free(n0);
}
return n;
}
-
-static GLboolean
-_slang_is_noop(const slang_operation *oper)
-{
- if (!oper ||
- oper->type == slang_oper_void ||
- (oper->num_children == 1 && oper->children[0].type == slang_oper_void))
- return GL_TRUE;
- else
- return GL_FALSE;
-}
-
-
static void
print_funcs(struct slang_function_scope_ *scope, const char *name)
{
* Return first function in the scope that has the given name.
* This is the function we'll try to call when there is no exact match
* between function parameters and call arguments.
+ *
+ * XXX we should really create a list of candidate functions and try
+ * all of them...
*/
static slang_function *
_slang_first_function(struct slang_function_scope_ *scope, const char *name)
* Use 'name' to find the function to call
*/
fun = _slang_locate_function(A->space.funcs, atom, params, param_count,
- &A->space, A->atoms);
+ &A->space, A->atoms, A->log);
if (!fun) {
/* A function with exactly the right parameters/types was not found.
* Try adapting the parameters.
*/
fun = _slang_first_function(A->space.funcs, name);
- if (!_slang_adapt_call(oper, fun, &A->space, A->atoms)) {
- RETURN_ERROR2("Undefined function (or no matching parameters)",
- name, 0);
+ if (!fun || !_slang_adapt_call(oper, fun, &A->space, A->atoms, A->log)) {
+ slang_info_log_error(A->log, "Function '%s' not found (check argument types)", name);
+ return NULL;
}
assert(fun);
}
static GLboolean
_slang_is_constant_cond(const slang_operation *oper, GLboolean *value)
{
- if (oper->type == slang_oper_literal_float ||
- oper->type == slang_oper_literal_int ||
- oper->type == slang_oper_literal_bool) {
+ if (oper->type == SLANG_OPER_LITERAL_FLOAT ||
+ oper->type == SLANG_OPER_LITERAL_INT ||
+ oper->type == SLANG_OPER_LITERAL_BOOL) {
if (oper->literal[0])
*value = GL_TRUE;
else
*value = GL_FALSE;
return GL_TRUE;
}
- else if (oper->type == slang_oper_expression &&
+ else if (oper->type == SLANG_OPER_EXPRESSION &&
oper->num_children == 1) {
return _slang_is_constant_cond(&oper->children[0], value);
}
}
+/**
+ * Test if an operation is a scalar or boolean.
+ */
+static GLboolean
+_slang_is_scalar_or_boolean(slang_assemble_ctx *A, slang_operation *oper)
+{
+ slang_typeinfo type;
+ GLint size;
+
+ slang_typeinfo_construct(&type);
+ _slang_typeof_operation(A, oper, &type);
+ size = _slang_sizeof_type_specifier(&type.spec);
+ slang_typeinfo_destruct(&type);
+ return size == 1;
+}
+
/**
* Generate loop code using high-level IR_LOOP instruction
* BREAK if !expr (child[0])
* body code (child[1])
*/
- slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
+ slang_ir_node *prevLoop, *loop, *breakIf, *body;
GLboolean isConst, constTrue;
+ /* type-check expression */
+ if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) {
+ slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'");
+ return NULL;
+ }
+
/* Check if loop condition is a constant */
isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
prevLoop = A->CurLoop;
A->CurLoop = loop;
- cond = new_cond(_slang_gen_operation(A, &oper->children[0]));
if (isConst && constTrue) {
/* while(nonzero constant), no conditional break */
breakIf = NULL;
}
else {
- breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+ slang_ir_node *cond
+ = new_cond(new_not(_slang_gen_operation(A, &oper->children[0])));
+ breakIf = new_break_if_true(A->CurLoop, cond);
}
body = _slang_gen_operation(A, &oper->children[1]);
loop->Children[0] = new_seq(breakIf, body);
/* Do infinite loop detection */
- if (loop->BranchNode == 0 && isConst && constTrue) {
+ /* loop->List is head of linked list of break/continue nodes */
+ if (!loop->List && isConst && constTrue) {
/* infinite loop detected */
A->CurLoop = prevLoop; /* clean-up */
- RETURN_ERROR("Infinite loop detected!", 0);
+ slang_info_log_error(A->log, "Infinite loop detected!");
+ return NULL;
}
/* pop loop, restore prev */
/*
* LOOP:
* body code (child[0])
- * BREAK if !expr (child[1])
+ * tail code:
+ * BREAK if !expr (child[1])
*/
- slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
+ slang_ir_node *prevLoop, *loop;
GLboolean isConst, constTrue;
- /* Check if loop condition is a constant */
- isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
+ /* type-check expression */
+ if (!_slang_is_scalar_or_boolean(A, &oper->children[1])) {
+ slang_info_log_error(A->log, "scalar/boolean expression expected for 'do/while'");
+ return NULL;
+ }
loop = new_loop(NULL);
prevLoop = A->CurLoop;
A->CurLoop = loop;
- body = _slang_gen_operation(A, &oper->children[0]);
- cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
+ /* loop body: */
+ loop->Children[0] = _slang_gen_operation(A, &oper->children[0]);
+
+ /* Check if loop condition is a constant */
+ isConst = _slang_is_constant_cond(&oper->children[1], &constTrue);
if (isConst && constTrue) {
- /* while(nonzero constant), no conditional break */
- breakIf = NULL;
+ /* do { } while(1) ==> no conditional break */
+ loop->Children[1] = NULL; /* no tail code */
}
else {
- breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+ slang_ir_node *cond
+ = new_cond(new_not(_slang_gen_operation(A, &oper->children[1])));
+ loop->Children[1] = new_break_if_true(A->CurLoop, cond);
}
- loop->Children[0] = new_seq(body, breakIf);
+
+ /* XXX we should do infinite loop detection, as above */
/* pop loop, restore prev */
A->CurLoop = prevLoop;
_slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
{
/*
- * init (child[0])
+ * init code (child[0])
* LOOP:
* BREAK if !expr (child[1])
* body code (child[3])
- * incr code (child[2]) // XXX continue here
+ * tail code:
+ * incr code (child[2]) // XXX continue here
*/
slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
prevLoop = A->CurLoop;
A->CurLoop = loop;
- cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
- breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+ cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1])));
+ breakIf = new_break_if_true(A->CurLoop, cond);
body = _slang_gen_operation(A, &oper->children[3]);
incr = _slang_gen_operation(A, &oper->children[2]);
- loop->Children[0] = new_seq(breakIf,
- new_seq(body, incr));
+
+ loop->Children[0] = new_seq(breakIf, body);
+ loop->Children[1] = incr; /* tail code */
/* pop loop, restore prev */
A->CurLoop = prevLoop;
}
-/**
- * Generate IR tree for an if/then/else conditional using BRAnch instructions.
- */
static slang_ir_node *
-_slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
+_slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper)
{
- /*
- * eval expr (child[0]), updating condcodes
- * branch if false to _else or _endif
- * "true" code block
- * if haveElseClause clause:
- * jump "__endif"
- * label "__else"
- * "false" code block
- * label "__endif"
- */
- const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]);
- slang_ir_node *cond, *bra, *trueBody, *endifLab, *tree;
- slang_atom elseAtom = slang_atom_pool_gen(A->atoms, "__else");
- slang_atom endifAtom = slang_atom_pool_gen(A->atoms, "__endif");
-
- cond = _slang_gen_operation(A, &oper->children[0]);
- cond = new_cond(cond);
- /*assert(cond->Store);*/
- bra = new_cjump(haveElseClause ? elseAtom : endifAtom, 0);
- tree = new_seq(cond, bra);
-
- trueBody = _slang_gen_operation(A, &oper->children[1]);
- tree = new_seq(tree, trueBody);
-
- if (haveElseClause) {
- /* else clause */
- slang_ir_node *jump, *elseLab, *falseBody;
- jump = new_jump(endifAtom);
- tree = new_seq(tree, jump);
-
- elseLab = new_label(elseAtom);
- tree = new_seq(tree, elseLab);
-
- falseBody = _slang_gen_operation(A, &oper->children[2]);
- tree = new_seq(tree, falseBody);
+ slang_ir_node *n, *loopNode;
+ assert(oper->type == SLANG_OPER_CONTINUE);
+ loopNode = A->CurLoop;
+ assert(loopNode);
+ assert(loopNode->Opcode == IR_LOOP);
+ n = new_node0(IR_CONT);
+ if (n) {
+ n->Parent = loopNode;
+ /* insert this node at head of linked list */
+ n->List = loopNode->List;
+ loopNode->List = n;
}
-
- endifLab = new_label(endifAtom);
- tree = new_seq(tree, endifLab);
-
- return tree;
+ return n;
}
* Determine if the given operation is of a specific type.
*/
static GLboolean
-is_operation_type(const const slang_operation *oper, slang_operation_type type)
+is_operation_type(const slang_operation *oper, slang_operation_type type)
{
if (oper->type == type)
return GL_TRUE;
- else if ((oper->type == slang_oper_block_new_scope ||
- oper->type == slang_oper_block_no_new_scope) &&
+ else if ((oper->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
+ oper->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) &&
oper->num_children == 1)
return is_operation_type(&oper->children[0], type);
else
* IR_IF instruction.
*/
static slang_ir_node *
-_slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper)
+_slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
{
/*
- * eval expr (child[0]), updating condcodes
+ * eval expr (child[0])
* IF expr THEN
* if-body code
* ELSE
*/
const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]);
slang_ir_node *ifNode, *cond, *ifBody, *elseBody;
+ GLboolean isConst, constTrue;
+
+ /* type-check expression */
+ if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) {
+ slang_info_log_error(A->log, "scalar/boolean expression expected for 'if'");
+ return NULL;
+ }
+
+ isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
+ if (isConst) {
+ if (constTrue) {
+ /* if (true) ... */
+ return _slang_gen_operation(A, &oper->children[1]);
+ }
+ else {
+ /* if (false) ... */
+ return _slang_gen_operation(A, &oper->children[2]);
+ }
+ }
cond = _slang_gen_operation(A, &oper->children[0]);
cond = new_cond(cond);
- if (is_operation_type(&oper->children[1], slang_oper_break)) {
+ if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK)) {
/* Special case: generate a conditional break */
- ifBody = new_break_if(A->CurLoop, cond, GL_TRUE);
+ ifBody = new_break_if_true(A->CurLoop, cond);
if (haveElseClause) {
elseBody = _slang_gen_operation(A, &oper->children[2]);
return new_seq(ifBody, elseBody);
}
return ifBody;
}
- else if (is_operation_type(&oper->children[1], slang_oper_continue)) {
+ else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE)) {
/* Special case: generate a conditional break */
- ifBody = new_cont_if(A->CurLoop, cond, GL_TRUE);
+ ifBody = new_cont_if_true(A->CurLoop, cond);
if (haveElseClause) {
elseBody = _slang_gen_operation(A, &oper->children[2]);
return new_seq(ifBody, elseBody);
+static slang_ir_node *
+_slang_gen_not(slang_assemble_ctx * A, const slang_operation *oper)
+{
+ slang_ir_node *n;
+
+ assert(oper->type == SLANG_OPER_NOT);
+
+ /* type-check expression */
+ if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) {
+ slang_info_log_error(A->log,
+ "scalar/boolean expression expected for '!'");
+ return NULL;
+ }
+
+ n = _slang_gen_operation(A, &oper->children[0]);
+ if (n)
+ return new_not(n);
+ else
+ return NULL;
+}
+
+
+static slang_ir_node *
+_slang_gen_xor(slang_assemble_ctx * A, const slang_operation *oper)
+{
+ slang_ir_node *n1, *n2;
+
+ assert(oper->type == SLANG_OPER_LOGICALXOR);
+
+ if (!_slang_is_scalar_or_boolean(A, &oper->children[0]) ||
+ !_slang_is_scalar_or_boolean(A, &oper->children[0])) {
+ slang_info_log_error(A->log,
+ "scalar/boolean expressions expected for '^^'");
+ return NULL;
+ }
+
+ n1 = _slang_gen_operation(A, &oper->children[0]);
+ if (!n1)
+ return NULL;
+ n2 = _slang_gen_operation(A, &oper->children[1]);
+ if (!n2)
+ return NULL;
+ return new_node2(IR_NOTEQUAL, n1, n2);
+}
+
+
/**
* Generate IR node for storage of a temporary of given size.
*/
_slang_gen_temporary(GLint size)
{
slang_ir_storage *store;
- slang_ir_node *n;
+ slang_ir_node *n = NULL;
store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size);
if (store) {
n->Store = store;
}
else {
- free(store);
+ _slang_free(store);
}
}
return n;
_slang_gen_var_decl(slang_assemble_ctx *A, slang_variable *var)
{
slang_ir_node *n;
+ assert(!is_sampler_type(&var->type));
n = new_node0(IR_VAR_DECL);
if (n) {
- n->Var = var;
- slang_allocate_storage(A, n);
+ _slang_attach_storage(n, var);
+
+ assert(var->aux);
+ assert(n->Store == var->aux);
assert(n->Store);
assert(n->Store->Index < 0);
+
+ n->Store->File = PROGRAM_TEMPORARY;
+ n->Store->Size = _slang_sizeof_type_specifier(&n->Var->type.specifier);
+ A->program->NumTemporaries++;
assert(n->Store->Size > 0);
- assert(var->aux);
- assert(n->Store == var->aux);
}
return n;
}
-
-
/**
* Generate code for a selection expression: b ? x : y
- * XXX in some cases we could implement a selection expression
+ * XXX In some cases we could implement a selection expression
* with an LRP instruction (use the boolean as the interpolant).
+ * Otherwise, we use an IF/ELSE/ENDIF construct.
*/
static slang_ir_node *
_slang_gen_select(slang_assemble_ctx *A, slang_operation *oper)
{
- slang_atom altAtom = slang_atom_pool_gen(A->atoms, "__selectAlt");
- slang_atom endAtom = slang_atom_pool_gen(A->atoms, "__selectEnd");
- slang_ir_node *altLab, *endLab;
- slang_ir_node *tree, *tmpDecl, *tmpVar, *cond, *cjump, *jump;
- slang_ir_node *bodx, *body, *assignx, *assigny;
+ slang_ir_node *cond, *ifNode, *trueExpr, *falseExpr, *trueNode, *falseNode;
+ slang_ir_node *tmpDecl, *tmpVar, *tree;
slang_typeinfo type;
int size;
- assert(oper->type == slang_oper_select);
+ assert(oper->type == SLANG_OPER_SELECT);
assert(oper->num_children == 3);
/* size of x or y's type */
/* temporary var */
tmpDecl = _slang_gen_temporary(size);
- /* eval condition */
+ /* the condition (child 0) */
cond = _slang_gen_operation(A, &oper->children[0]);
cond = new_cond(cond);
- tree = new_seq(tmpDecl, cond);
- /* jump if false to "alt" label */
- cjump = new_cjump(altAtom, 0);
- tree = new_seq(tree, cjump);
-
- /* evaluate child 1 (x) and assign to tmp */
+ /* if-true body (child 1) */
tmpVar = new_node0(IR_VAR);
tmpVar->Store = tmpDecl->Store;
- body = _slang_gen_operation(A, &oper->children[1]);
- assigny = new_node2(IR_MOVE, tmpVar, body);
- tree = new_seq(tree, assigny);
+ trueExpr = _slang_gen_operation(A, &oper->children[1]);
+ trueNode = new_node2(IR_MOVE, tmpVar, trueExpr);
- /* jump to "end" label */
- jump = new_jump(endAtom);
- tree = new_seq(tree, jump);
-
- /* "alt" label */
- altLab = new_label(altAtom);
- tree = new_seq(tree, altLab);
-
- /* evaluate child 2 (y) and assign to tmp */
+ /* if-false body (child 2) */
tmpVar = new_node0(IR_VAR);
tmpVar->Store = tmpDecl->Store;
- bodx = _slang_gen_operation(A, &oper->children[2]);
- assignx = new_node2(IR_MOVE, tmpVar, bodx);
- tree = new_seq(tree, assignx);
-
- /* "end" label */
- endLab = new_label(endAtom);
- tree = new_seq(tree, endLab);
-
+ falseExpr = _slang_gen_operation(A, &oper->children[2]);
+ falseNode = new_node2(IR_MOVE, tmpVar, falseExpr);
+
+ ifNode = new_if(cond, trueNode, falseNode);
+
/* tmp var value */
tmpVar = new_node0(IR_VAR);
tmpVar->Store = tmpDecl->Store;
- tree = new_seq(tree, tmpVar);
+ tree = new_seq(ifNode, tmpVar);
+ tree = new_seq(tmpDecl, tree);
+
+ /*_slang_print_ir_tree(tree, 10);*/
return tree;
}
slang_ir_node *n;
select = slang_operation_new(1);
- select->type = slang_oper_select;
+ select->type = SLANG_OPER_SELECT;
select->num_children = 3;
select->children = slang_operation_new(3);
slang_operation_copy(&select->children[0], &oper->children[0]);
slang_operation_copy(&select->children[1], &oper->children[1]);
- select->children[2].type = slang_oper_literal_bool;
- ASSIGN_4V(select->children[2].literal, 0, 0, 0, 0);
- select->children[2].literal_size = 2;
+ select->children[2].type = SLANG_OPER_LITERAL_BOOL;
+ ASSIGN_4V(select->children[2].literal, 0, 0, 0, 0); /* false */
+ select->children[2].literal_size = 1;
n = _slang_gen_select(A, select);
-
- /* xxx wrong */
- free(select->children);
- free(select);
-
return n;
}
slang_ir_node *n;
select = slang_operation_new(1);
- select->type = slang_oper_select;
+ select->type = SLANG_OPER_SELECT;
select->num_children = 3;
select->children = slang_operation_new(3);
slang_operation_copy(&select->children[0], &oper->children[0]);
- select->children[1].type = slang_oper_literal_bool;
- ASSIGN_4V(select->children[2].literal, 1, 1, 1, 1);
+ select->children[1].type = SLANG_OPER_LITERAL_BOOL;
+ ASSIGN_4V(select->children[1].literal, 1, 1, 1, 1); /* true */
+ select->children[1].literal_size = 1;
slang_operation_copy(&select->children[2], &oper->children[1]);
- select->children[2].literal_size = 2;
n = _slang_gen_select(A, select);
-
- /* xxx wrong */
- free(select->children);
- free(select);
-
return n;
}
-
/**
* Generate IR tree for a return statement.
*/
static slang_ir_node *
_slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
{
- if (oper->num_children == 0 ||
- (oper->num_children == 1 &&
- oper->children[0].type == slang_oper_void)) {
- /* Convert from:
- * return;
- * To:
- * goto __endOfFunction;
- */
- slang_ir_node *n;
- slang_operation gotoOp;
- slang_operation_construct(&gotoOp);
- gotoOp.type = slang_oper_goto;
- /* XXX don't call function? */
- gotoOp.a_id = slang_atom_pool_atom(A->atoms,
- (char *) A->CurFunction->end_label);
- /* assemble the new code */
- n = _slang_gen_operation(A, &gotoOp);
- /* destroy temp code */
- slang_operation_destruct(&gotoOp);
- return n;
+ const GLboolean haveReturnValue
+ = (oper->num_children == 1 &&
+ oper->children[0].type != SLANG_OPER_VOID);
+
+ /* error checking */
+ assert(A->CurFunction);
+ if (haveReturnValue &&
+ A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) {
+ slang_info_log_error(A->log, "illegal return expression");
+ return NULL;
+ }
+ else if (!haveReturnValue &&
+ A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
+ slang_info_log_error(A->log, "return statement requires an expression");
+ return NULL;
+ }
+
+ if (!haveReturnValue) {
+ return new_return(A->curFuncEndLabel);
}
else {
/*
* return expr;
* To:
* __retVal = expr;
- * goto __endOfFunction;
+ * return; // goto __endOfFunction
*/
- slang_operation *block, *assign, *jump;
+ slang_operation *assign;
slang_atom a_retVal;
slang_ir_node *n;
{
slang_variable *v
= _slang_locate_variable(oper->locals, a_retVal, GL_TRUE);
- assert(v);
+ if (!v) {
+ /* trying to return a value in a void-valued function */
+ return NULL;
+ }
}
#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 = slang_operation_new(1);
+ assign->type = SLANG_OPER_ASSIGN;
assign->num_children = 2;
assign->children = slang_operation_new(2);
/* lhs (__retVal) */
- assign->children[0].type = slang_oper_identifier;
+ assign->children[0].type = SLANG_OPER_IDENTIFIER;
assign->children[0].a_id = a_retVal;
assign->children[0].locals->outer_scope = assign->locals;
/* rhs (expr) */
/* XXX we might be able to avoid this copy someday */
slang_operation_copy(&assign->children[1], &oper->children[0]);
- /* child[1]: goto __endOfFunction */
- jump = &block->children[1];
- jump->type = slang_oper_goto;
- assert(A->CurFunction->end_label);
- /* XXX don't call function? */
- jump->a_id = slang_atom_pool_atom(A->atoms,
- (char *) A->CurFunction->end_label);
-
-#if 0 /* debug */
- printf("NEW RETURN:\n");
- slang_print_tree(block, 0);
-#endif
-
/* assemble the new code */
- n = _slang_gen_operation(A, block);
- slang_operation_delete(block);
+ n = new_seq(_slang_gen_operation(A, assign),
+ new_return(A->curFuncEndLabel));
+
+ slang_operation_delete(assign);
return n;
}
}
assert(oper->num_children == 1);
var = new_var(A, oper, oper->a_id);
if (!var) {
- RETURN_ERROR2("Undefined variable:", varName, 0);
+ slang_info_log_error(A->log, "undefined variable '%s'", varName);
+ return NULL;
}
/* XXX make copy of this initializer? */
rhs = _slang_gen_operation(A, &oper->children[0]);
slang_ir_node *var, *init, *rhs;
var = new_var(A, oper, oper->a_id);
if (!var) {
- RETURN_ERROR2("Undefined variable:", varName, 0);
+ slang_info_log_error(A->log, "undefined variable '%s'", varName);
+ return NULL;
}
#if 0
/* XXX make copy of this initializer? */
_slang_simplify(v->initializer, &A->space, A->atoms);
rhs = _slang_gen_operation(A, v->initializer);
#endif
+ if (!rhs)
+ return NULL;
+
assert(rhs);
init = new_node2(IR_MOVE, var, rhs);
/*
slang_atom aVar = oper->var ? oper->var->a_name : oper->a_id;
slang_ir_node *n = new_var(A, oper, aVar);
if (!n) {
- RETURN_ERROR2("Undefined variable:", (char *) aVar, 0);
+ slang_info_log_error(A->log, "undefined variable '%s'", (char *) aVar);
+ return NULL;
}
return n;
}
* v.xy = vec2(a, b);
* Hard example:
* vec3 v;
- * v.yz = vec2(a, b);
- * this would have to be transformed/swizzled into:
- * v.yz = vec2(a, b).*xy* (* = don't care)
- * Instead, we'll effectively do this:
- * v.y = vec2(a, b).xxxx;
- * v.z = vec2(a, b).yyyy;
- *
+ * v.zy = vec2(a, b);
+ * this gets transformed/swizzled into:
+ * v.zy = vec2(a, b).*yx* (* = don't care)
+ * This function helps to determine simple vs. non-simple.
*/
static GLboolean
-_slang_simple_writemask(GLuint writemask)
+_slang_simple_writemask(GLuint writemask, GLuint swizzle)
{
switch (writemask) {
case WRITEMASK_X:
+ return GET_SWZ(swizzle, 0) == SWIZZLE_X;
case WRITEMASK_Y:
+ return GET_SWZ(swizzle, 1) == SWIZZLE_Y;
case WRITEMASK_Z:
+ return GET_SWZ(swizzle, 2) == SWIZZLE_Z;
case WRITEMASK_W:
+ return GET_SWZ(swizzle, 3) == SWIZZLE_W;
case WRITEMASK_XY:
+ return (GET_SWZ(swizzle, 0) == SWIZZLE_X)
+ && (GET_SWZ(swizzle, 1) == SWIZZLE_Y);
case WRITEMASK_XYZ:
+ return (GET_SWZ(swizzle, 0) == SWIZZLE_X)
+ && (GET_SWZ(swizzle, 1) == SWIZZLE_Y)
+ && (GET_SWZ(swizzle, 2) == SWIZZLE_Z);
case WRITEMASK_XYZW:
- return GL_TRUE;
+ return swizzle == SWIZZLE_NOOP;
default:
return GL_FALSE;
}
newSwizzle[2],
newSwizzle[3]);
- if (_slang_simple_writemask(mask)) {
+ if (_slang_simple_writemask(mask, *swizzleOut)) {
if (size >= 1)
assert(GET_SWZ(*swizzleOut, 0) == SWIZZLE_X);
if (size >= 2)
_slang_gen_swizzle(slang_ir_node *child, GLuint swizzle)
{
slang_ir_node *n = new_node1(IR_SWIZZLE, child);
+ assert(child);
if (n) {
n->Store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -1, -1);
n->Store->Swizzle = swizzle;
static slang_ir_node *
_slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
{
- if (oper->children[0].type == slang_oper_identifier &&
- oper->children[1].type == slang_oper_call) {
+ if (oper->children[0].type == SLANG_OPER_IDENTIFIER) {
+ /* Check that var is writeable */
+ slang_variable *var
+ = _slang_locate_variable(oper->children[0].locals,
+ oper->children[0].a_id, GL_TRUE);
+ if (!var) {
+ slang_info_log_error(A->log, "undefined variable '%s'",
+ (char *) oper->children[0].a_id);
+ return NULL;
+ }
+ if (var->type.qualifier == SLANG_QUAL_CONST ||
+ var->type.qualifier == SLANG_QUAL_ATTRIBUTE ||
+ var->type.qualifier == SLANG_QUAL_UNIFORM) {
+ slang_info_log_error(A->log,
+ "illegal assignment to read-only variable '%s'",
+ (char *) oper->children[0].a_id);
+ return NULL;
+ }
+ }
+
+ if (oper->children[0].type == SLANG_OPER_IDENTIFIER &&
+ oper->children[1].type == SLANG_OPER_CALL) {
/* Special case of: x = f(a, b)
* Replace with f(a, b, x) (where x == hidden __retVal out param)
*
else {
slang_ir_node *n, *lhs, *rhs;
lhs = _slang_gen_operation(A, &oper->children[0]);
+
+ if (lhs) {
+ if (lhs->Store->File != PROGRAM_OUTPUT &&
+ lhs->Store->File != PROGRAM_TEMPORARY &&
+ lhs->Store->File != PROGRAM_VARYING &&
+ lhs->Store->File != PROGRAM_UNDEFINED) {
+ slang_info_log_error(A->log,
+ "illegal assignment to read-only l-value");
+ return NULL;
+ }
+ }
+
rhs = _slang_gen_operation(A, &oper->children[1]);
if (lhs && rhs) {
/* convert lhs swizzle into writemask */
{
slang_typeinfo ti;
+ /* type of struct */
slang_typeinfo_construct(&ti);
_slang_typeof_operation(A, &oper->children[0], &ti);
slang_ir_node *n;
GLuint swizzle;
if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) {
- RETURN_ERROR("Bad swizzle", 0);
+ slang_info_log_error(A->log, "Bad swizzle");
}
swizzle = MAKE_SWIZZLE4(swz.swizzle[0],
swz.swizzle[1],
n = _slang_gen_operation(A, &oper->children[0]);
/* create new parent node with swizzle */
- n = _slang_gen_swizzle(n, swizzle);
+ if (n)
+ n = _slang_gen_swizzle(n, swizzle);
return n;
}
- else if (ti.spec.type == slang_spec_float) {
+ else if ( ti.spec.type == SLANG_SPEC_FLOAT
+ || ti.spec.type == SLANG_SPEC_INT) {
const GLuint rows = 1;
slang_swizzle swz;
slang_ir_node *n;
GLuint swizzle;
if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) {
- RETURN_ERROR("Bad swizzle", 0);
+ slang_info_log_error(A->log, "Bad swizzle");
}
swizzle = MAKE_SWIZZLE4(swz.swizzle[0],
swz.swizzle[1],
/* the field is a structure member (base.field) */
/* oper->children[0] is the base */
/* oper->a_id is the field name */
+ slang_ir_node *base, *n;
+ slang_typeinfo field_ti;
+ GLint fieldSize, fieldOffset = -1;
+ /* type of field */
+ slang_typeinfo_construct(&field_ti);
+ _slang_typeof_operation(A, oper, &field_ti);
+
+ fieldSize = _slang_sizeof_type_specifier(&field_ti.spec);
+ if (fieldSize > 0)
+ fieldOffset = _slang_field_offset(&ti.spec, oper->a_id);
+
+ if (fieldSize == 0 || fieldOffset < 0) {
+ slang_info_log_error(A->log,
+ "\"%s\" is not a member of struct \"%s\"",
+ (char *) oper->a_id,
+ (char *) ti.spec._struct->a_name);
+ return NULL;
+ }
+ assert(fieldSize >= 0);
+
+ base = _slang_gen_operation(A, &oper->children[0]);
+ if (!base) {
+ /* error msg should have already been logged */
+ return NULL;
+ }
+
+ n = new_node1(IR_FIELD, base);
+ if (n) {
+ n->Field = (char *) oper->a_id;
+ n->FieldOffset = fieldOffset;
+ assert(n->FieldOffset >= 0);
+ n->Store = _slang_new_ir_storage(base->Store->File,
+ base->Store->Index,
+ fieldSize);
+ }
+ return n;
+
+#if 0
_mesa_problem(NULL, "glsl structs/fields not supported yet");
return NULL;
+#endif
}
}
slang_ir_node *n;
index = (GLint) oper->children[1].literal[0];
- if (oper->children[1].type != slang_oper_literal_int ||
+ if (oper->children[1].type != SLANG_OPER_LITERAL_INT ||
index >= max) {
- RETURN_ERROR("Invalid array index for vector type", 0);
+ slang_info_log_error(A->log, "Invalid array index for vector type");
+ return NULL;
}
n = _slang_gen_operation(A, &oper->children[0]);
/* conventional array */
slang_typeinfo elem_ti;
slang_ir_node *elem, *array, *index;
- GLint elemSize;
+ GLint elemSize, arrayLen;
/* size of array element */
slang_typeinfo_construct(&elem_ti);
_slang_typeof_operation(A, oper, &elem_ti);
elemSize = _slang_sizeof_type_specifier(&elem_ti.spec);
- assert(elemSize >= 1);
+
+ if (_slang_type_is_matrix(array_ti.spec.type))
+ arrayLen = _slang_type_dim(array_ti.spec.type);
+ else
+ arrayLen = array_ti.array_len;
+
+ slang_typeinfo_destruct(&array_ti);
+ slang_typeinfo_destruct(&elem_ti);
+
+ if (elemSize <= 0) {
+ /* unknown var or type */
+ slang_info_log_error(A->log, "Undefined variable or type");
+ return NULL;
+ }
array = _slang_gen_operation(A, &oper->children[0]);
index = _slang_gen_operation(A, &oper->children[1]);
if (array && index) {
+ /* bounds check */
+ if (index->Opcode == IR_FLOAT &&
+ ((int) index->Value[0] < 0 ||
+ (int) index->Value[0] >= arrayLen)) {
+ slang_info_log_error(A->log,
+ "Array index out of bounds (index=%d size=%d)",
+ (int) index->Value[0], arrayLen);
+ _slang_free_ir_tree(array);
+ _slang_free_ir_tree(index);
+ return NULL;
+ }
+
elem = new_node2(IR_ELEMENT, array, index);
elem->Store = _slang_new_ir_storage(array->Store->File,
array->Store->Index,
elemSize);
+ /* XXX try to do some array bounds checking here */
return elem;
}
else {
+ _slang_free_ir_tree(array);
+ _slang_free_ir_tree(index);
return NULL;
}
}
}
+/**
+ * Look for expressions such as: gl_ModelviewMatrix * gl_Vertex
+ * and replace with this: gl_Vertex * gl_ModelviewMatrixTranpose
+ * Since matrices are stored in column-major order, the second form of
+ * multiplication is much more efficient (just 4 dot products).
+ */
+static void
+_slang_check_matmul_optimization(slang_assemble_ctx *A, slang_operation *oper)
+{
+ static const struct {
+ const char *orig;
+ const char *tranpose;
+ } matrices[] = {
+ {"gl_ModelViewMatrix", "gl_ModelViewMatrixTranspose"},
+ {"gl_ProjectionMatrix", "gl_ProjectionMatrixTranspose"},
+ {"gl_ModelViewProjectionMatrix", "gl_ModelViewProjectionMatrixTranspose"},
+ {"gl_TextureMatrix", "gl_TextureMatrixTranspose"},
+ {"gl_NormalMatrix", "__NormalMatrixTranspose"},
+ { NULL, NULL }
+ };
+
+ assert(oper->type == SLANG_OPER_MULTIPLY);
+ if (oper->children[0].type == SLANG_OPER_IDENTIFIER) {
+ GLuint i;
+ for (i = 0; matrices[i].orig; i++) {
+ if (oper->children[0].a_id
+ == slang_atom_pool_atom(A->atoms, matrices[i].orig)) {
+ /*
+ _mesa_printf("Replace %s with %s\n",
+ matrices[i].orig, matrices[i].tranpose);
+ */
+ assert(oper->children[0].type == SLANG_OPER_IDENTIFIER);
+ oper->children[0].a_id
+ = slang_atom_pool_atom(A->atoms, matrices[i].tranpose);
+ /* finally, swap the operands */
+ _slang_operation_swap(&oper->children[0], &oper->children[1]);
+ return;
+ }
+ }
+ }
+}
+
/**
* Generate IR tree for a slang_operation (AST node)
_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
{
switch (oper->type) {
- case slang_oper_block_new_scope:
+ case SLANG_OPER_BLOCK_NEW_SCOPE:
{
slang_ir_node *n;
_slang_push_var_table(A->vartable);
- oper->type = slang_oper_block_no_new_scope; /* temp change */
+ oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; /* temp change */
n = _slang_gen_operation(A, oper);
- oper->type = slang_oper_block_new_scope; /* restore */
+ oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; /* restore */
_slang_pop_var_table(A->vartable);
}
break;
- case slang_oper_block_no_new_scope:
+ case SLANG_OPER_BLOCK_NO_NEW_SCOPE:
/* list of operations */
if (oper->num_children > 0)
{
#endif
return tree;
}
- break;
- case slang_oper_expression:
+ else {
+ return new_node0(IR_NOP);
+ }
+
+ case SLANG_OPER_EXPRESSION:
return _slang_gen_operation(A, &oper->children[0]);
- case slang_oper_for:
+ case SLANG_OPER_FOR:
return _slang_gen_for(A, oper);
- case slang_oper_do:
+ case SLANG_OPER_DO:
return _slang_gen_do(A, oper);
- case slang_oper_while:
+ case SLANG_OPER_WHILE:
return _slang_gen_while(A, oper);
- case slang_oper_break:
+ case SLANG_OPER_BREAK:
if (!A->CurLoop) {
- RETURN_ERROR("'break' not in loop", 0);
+ slang_info_log_error(A->log, "'break' not in loop");
+ return NULL;
}
return new_break(A->CurLoop);
- case slang_oper_continue:
+ case SLANG_OPER_CONTINUE:
if (!A->CurLoop) {
- RETURN_ERROR("'continue' not in loop", 0);
+ slang_info_log_error(A->log, "'continue' not in loop");
+ return NULL;
}
- return new_cont(A->CurLoop);
- case slang_oper_discard:
+ return _slang_gen_continue(A, oper);
+ case SLANG_OPER_DISCARD:
return new_node0(IR_KILL);
- case slang_oper_equal:
- return new_node2(IR_SEQUAL,
+ case SLANG_OPER_EQUAL:
+ return new_node2(IR_EQUAL,
_slang_gen_operation(A, &oper->children[0]),
_slang_gen_operation(A, &oper->children[1]));
- case slang_oper_notequal:
- return new_node2(IR_SNEQUAL,
+ case SLANG_OPER_NOTEQUAL:
+ return new_node2(IR_NOTEQUAL,
_slang_gen_operation(A, &oper->children[0]),
_slang_gen_operation(A, &oper->children[1]));
- case slang_oper_greater:
+ case SLANG_OPER_GREATER:
return new_node2(IR_SGT,
_slang_gen_operation(A, &oper->children[0]),
_slang_gen_operation(A, &oper->children[1]));
- case slang_oper_less:
- /* child[0] < child[1] ----> child[1] > child[0] */
- return new_node2(IR_SGT,
- _slang_gen_operation(A, &oper->children[1]),
- _slang_gen_operation(A, &oper->children[0]));
- case slang_oper_greaterequal:
- return new_node2(IR_SGE,
+ case SLANG_OPER_LESS:
+ return new_node2(IR_SLT,
_slang_gen_operation(A, &oper->children[0]),
_slang_gen_operation(A, &oper->children[1]));
- case slang_oper_lessequal:
- /* child[0] <= child[1] ----> child[1] >= child[0] */
+ case SLANG_OPER_GREATEREQUAL:
return new_node2(IR_SGE,
- _slang_gen_operation(A, &oper->children[1]),
- _slang_gen_operation(A, &oper->children[0]));
- case slang_oper_add:
+ _slang_gen_operation(A, &oper->children[0]),
+ _slang_gen_operation(A, &oper->children[1]));
+ case SLANG_OPER_LESSEQUAL:
+ return new_node2(IR_SLE,
+ _slang_gen_operation(A, &oper->children[0]),
+ _slang_gen_operation(A, &oper->children[1]));
+ case SLANG_OPER_ADD:
{
slang_ir_node *n;
assert(oper->num_children == 2);
n = _slang_gen_function_call_name(A, "+", oper, NULL);
return n;
}
- case slang_oper_subtract:
+ case SLANG_OPER_SUBTRACT:
{
slang_ir_node *n;
assert(oper->num_children == 2);
n = _slang_gen_function_call_name(A, "-", oper, NULL);
return n;
}
- case slang_oper_multiply:
+ case SLANG_OPER_MULTIPLY:
{
slang_ir_node *n;
assert(oper->num_children == 2);
+ _slang_check_matmul_optimization(A, oper);
n = _slang_gen_function_call_name(A, "*", oper, NULL);
return n;
}
- case slang_oper_divide:
+ case SLANG_OPER_DIVIDE:
{
slang_ir_node *n;
assert(oper->num_children == 2);
n = _slang_gen_function_call_name(A, "/", oper, NULL);
return n;
}
- case slang_oper_minus:
+ case SLANG_OPER_MINUS:
{
slang_ir_node *n;
assert(oper->num_children == 1);
n = _slang_gen_function_call_name(A, "-", oper, NULL);
return n;
}
- case slang_oper_plus:
+ case SLANG_OPER_PLUS:
/* +expr --> do nothing */
return _slang_gen_operation(A, &oper->children[0]);
- case slang_oper_variable_decl:
+ case SLANG_OPER_VARIABLE_DECL:
return _slang_gen_declaration(A, oper);
- case slang_oper_assign:
+ case SLANG_OPER_ASSIGN:
return _slang_gen_assignment(A, oper);
- case slang_oper_addassign:
+ case SLANG_OPER_ADDASSIGN:
{
slang_ir_node *n;
assert(oper->num_children == 2);
n = _slang_gen_function_call_name(A, "+=", oper, &oper->children[0]);
return n;
}
- case slang_oper_subassign:
+ case SLANG_OPER_SUBASSIGN:
{
slang_ir_node *n;
assert(oper->num_children == 2);
return n;
}
break;
- case slang_oper_mulassign:
+ case SLANG_OPER_MULASSIGN:
{
slang_ir_node *n;
assert(oper->num_children == 2);
n = _slang_gen_function_call_name(A, "*=", oper, &oper->children[0]);
return n;
}
- case slang_oper_divassign:
+ case SLANG_OPER_DIVASSIGN:
{
slang_ir_node *n;
assert(oper->num_children == 2);
n = _slang_gen_function_call_name(A, "/=", oper, &oper->children[0]);
return n;
}
- case slang_oper_logicaland:
+ case SLANG_OPER_LOGICALAND:
{
slang_ir_node *n;
assert(oper->num_children == 2);
n = _slang_gen_logical_and(A, oper);
return n;
}
- case slang_oper_logicalor:
+ case SLANG_OPER_LOGICALOR:
{
slang_ir_node *n;
assert(oper->num_children == 2);
n = _slang_gen_logical_or(A, oper);
return n;
}
- case slang_oper_logicalxor:
- {
- slang_ir_node *n;
- assert(oper->num_children == 2);
- n = _slang_gen_function_call_name(A, "__logicalXor", oper, NULL);
- return n;
- }
- case slang_oper_not:
- {
- slang_ir_node *n;
- assert(oper->num_children == 1);
- n = _slang_gen_function_call_name(A, "__logicalNot", oper, NULL);
- return n;
- }
-
- case slang_oper_select: /* b ? x : y */
+ case SLANG_OPER_LOGICALXOR:
+ return _slang_gen_xor(A, oper);
+ case SLANG_OPER_NOT:
+ return _slang_gen_not(A, oper);
+ case SLANG_OPER_SELECT: /* b ? x : y */
{
slang_ir_node *n;
assert(oper->num_children == 3);
return n;
}
- case slang_oper_asm:
+ case SLANG_OPER_ASM:
return _slang_gen_asm(A, oper, NULL);
- case slang_oper_call:
+ case SLANG_OPER_CALL:
return _slang_gen_function_call_name(A, (const char *) oper->a_id,
oper, NULL);
- case slang_oper_return:
+ case SLANG_OPER_RETURN:
return _slang_gen_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:
+ case SLANG_OPER_LABEL:
+ return new_label(oper->label);
+ case SLANG_OPER_IDENTIFIER:
return _slang_gen_variable(A, oper);
- case slang_oper_if:
- if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB) {
- return _slang_gen_hl_if(A, oper);
- }
- else {
- /* XXX update tnl executor */
- return _slang_gen_if(A, oper);
- }
- case slang_oper_field:
+ case SLANG_OPER_IF:
+ return _slang_gen_if(A, oper);
+ case SLANG_OPER_FIELD:
return _slang_gen_field(A, oper);
- case slang_oper_subscript:
+ case SLANG_OPER_SUBSCRIPT:
return _slang_gen_subscript(A, oper);
- case slang_oper_literal_float:
+ case SLANG_OPER_LITERAL_FLOAT:
/* fall-through */
- case slang_oper_literal_int:
+ case SLANG_OPER_LITERAL_INT:
/* fall-through */
- case slang_oper_literal_bool:
- return new_float_literal(oper->literal);
+ case SLANG_OPER_LITERAL_BOOL:
+ return new_float_literal(oper->literal, oper->literal_size);
- case slang_oper_postincrement: /* var++ */
+ case SLANG_OPER_POSTINCREMENT: /* var++ */
{
slang_ir_node *n;
assert(oper->num_children == 1);
n = _slang_gen_function_call_name(A, "__postIncr", oper, NULL);
return n;
}
- case slang_oper_postdecrement: /* var-- */
+ case SLANG_OPER_POSTDECREMENT: /* var-- */
{
slang_ir_node *n;
assert(oper->num_children == 1);
n = _slang_gen_function_call_name(A, "__postDecr", oper, NULL);
return n;
}
- case slang_oper_preincrement: /* ++var */
+ case SLANG_OPER_PREINCREMENT: /* ++var */
{
slang_ir_node *n;
assert(oper->num_children == 1);
n = _slang_gen_function_call_name(A, "++", oper, NULL);
return n;
}
- case slang_oper_predecrement: /* --var */
+ case SLANG_OPER_PREDECREMENT: /* --var */
{
slang_ir_node *n;
assert(oper->num_children == 1);
return n;
}
- case slang_oper_sequence:
+ case SLANG_OPER_INLINED_CALL:
+ case SLANG_OPER_SEQUENCE:
{
slang_ir_node *tree = NULL;
GLuint i;
slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]);
tree = tree ? new_seq(tree, n) : n;
}
+ if (oper->type == SLANG_OPER_INLINED_CALL) {
+ tree = new_inlined_function_call(tree, oper->label);
+ }
return tree;
}
- case slang_oper_none:
- return NULL;
- case slang_oper_void:
- return NULL;
+ case SLANG_OPER_NONE:
+ case SLANG_OPER_VOID:
+ /* returning NULL here would generate an error */
+ return new_node0(IR_NOP);
default:
- printf("Unhandled node type %d\n", oper->type);
- abort();
+ _mesa_problem(NULL, "bad node type %d in _slang_gen_operation",
+ oper->type);
return new_node0(IR_NOP);
}
- abort();
+
return NULL;
}
struct gl_program *prog = A->program;
const char *varName = (char *) var->a_name;
GLboolean success = GL_TRUE;
- GLint texIndex;
slang_ir_storage *store = NULL;
int dbg = 0;
-
- texIndex = sampler_to_texture_index(var->type.specifier.type);
+ const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier);
+ const GLint texIndex = sampler_to_texture_index(var->type.specifier.type);
if (texIndex != -1) {
/* Texture sampler:
* store->Index = sampler uniform location
* store->Size = texture type index (1D, 2D, 3D, cube, etc)
*/
- GLint samplerUniform = _mesa_add_sampler(prog->Parameters, varName);
+ GLint samplerUniform
+ = _mesa_add_sampler(prog->Parameters, varName, datatype);
store = _slang_new_ir_storage(PROGRAM_SAMPLER, samplerUniform, texIndex);
if (dbg) printf("SAMPLER ");
}
- else if (var->type.qualifier == slang_qual_uniform) {
+ else if (var->type.qualifier == SLANG_QUAL_UNIFORM) {
/* Uniform variable */
- const GLint size = _slang_sizeof_type_specifier(&var->type.specifier);
+ const GLint size = _slang_sizeof_type_specifier(&var->type.specifier)
+ * MAX2(var->array_len, 1);
if (prog) {
/* user-defined uniform */
- GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName, size);
- store = _slang_new_ir_storage(PROGRAM_UNIFORM, uniformLoc, size);
+ if (datatype == GL_NONE) {
+ if (var->type.specifier.type == SLANG_SPEC_STRUCT) {
+ _mesa_problem(NULL, "user-declared uniform structs not supported yet");
+ /* XXX what we need to do is unroll the struct into its
+ * basic types, creating a uniform variable for each.
+ * For example:
+ * struct foo {
+ * vec3 a;
+ * vec4 b;
+ * };
+ * uniform foo f;
+ *
+ * Should produce uniforms:
+ * "f.a" (GL_FLOAT_VEC3)
+ * "f.b" (GL_FLOAT_VEC4)
+ */
+ }
+ else {
+ slang_info_log_error(A->log,
+ "invalid datatype for uniform variable %s",
+ (char *) var->a_name);
+ }
+ return GL_FALSE;
+ }
+ else {
+ GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName,
+ size, datatype);
+ store = _slang_new_ir_storage(PROGRAM_UNIFORM, uniformLoc, size);
+ }
}
else {
/* pre-defined uniform, like gl_ModelviewMatrix */
*/
store = _slang_new_ir_storage(PROGRAM_STATE_VAR, -1, size);
}
- if (dbg) printf("UNIFORM ");
+ if (dbg) printf("UNIFORM (sz %d) ", size);
}
- else if (var->type.qualifier == slang_qual_varying) {
+ else if (var->type.qualifier == SLANG_QUAL_VARYING) {
const GLint size = 4; /* XXX fix */
if (prog) {
/* user-defined varying */
}
else {
/* pre-defined varying, like gl_Color or gl_TexCoord */
- if (type == slang_unit_fragment_builtin) {
- GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB);
+ if (type == SLANG_UNIT_FRAGMENT_BUILTIN) {
+ GLuint swizzle;
+ GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB,
+ &swizzle);
assert(index >= 0);
store = _slang_new_ir_storage(PROGRAM_INPUT, index, size);
+ store->Swizzle = swizzle;
assert(index < FRAG_ATTRIB_MAX);
}
else {
GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB);
assert(index >= 0);
- assert(type == slang_unit_vertex_builtin);
+ assert(type == SLANG_UNIT_VERTEX_BUILTIN);
store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size);
assert(index < VERT_RESULT_MAX);
}
}
if (dbg) printf("VARYING ");
}
- else if (var->type.qualifier == slang_qual_attribute) {
+ else if (var->type.qualifier == SLANG_QUAL_ATTRIBUTE) {
if (prog) {
/* user-defined vertex attribute */
const GLint size = _slang_sizeof_type_specifier(&var->type.specifier);
}
else {
/* pre-defined vertex attrib */
- GLint index = _slang_input_index(varName, GL_VERTEX_PROGRAM_ARB);
+ GLuint swizzle;
+ GLint index = _slang_input_index(varName, GL_VERTEX_PROGRAM_ARB,
+ &swizzle);
GLint size = 4; /* XXX? */
assert(index >= 0);
store = _slang_new_ir_storage(PROGRAM_INPUT, index, size);
+ store->Swizzle = swizzle;
}
if (dbg) printf("ATTRIB ");
}
- else if (var->type.qualifier == slang_qual_fixedinput) {
- GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB);
+ else if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT) {
+ GLuint swizzle = SWIZZLE_XYZW; /* silence compiler warning */
+ GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB,
+ &swizzle);
GLint size = 4; /* XXX? */
store = _slang_new_ir_storage(PROGRAM_INPUT, index, size);
+ store->Swizzle = swizzle;
if (dbg) printf("INPUT ");
}
- else if (var->type.qualifier == slang_qual_fixedoutput) {
- if (type == slang_unit_vertex_builtin) {
+ else if (var->type.qualifier == SLANG_QUAL_FIXEDOUTPUT) {
+ if (type == SLANG_UNIT_VERTEX_BUILTIN) {
GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB);
GLint size = 4; /* XXX? */
store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size);
}
else {
- assert(type == slang_unit_fragment_builtin);
GLint index = _slang_output_index(varName, GL_FRAGMENT_PROGRAM_ARB);
GLint size = 4; /* XXX? */
+ assert(type == SLANG_UNIT_FRAGMENT_BUILTIN);
store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size);
}
if (dbg) printf("OUTPUT ");
}
- else if (var->type.qualifier == slang_qual_const && !prog) {
+ else if (var->type.qualifier == SLANG_QUAL_CONST && !prog) {
/* pre-defined global constant, like gl_MaxLights */
const GLint size = _slang_sizeof_type_specifier(&var->type.specifier);
store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size);
n = new_seq(n, init);
}
- success = _slang_emit_code(n, A->vartable, A->program, GL_FALSE);
+ success = _slang_emit_code(n, A->vartable, A->program, GL_FALSE, A->log);
_slang_free_ir_tree(n);
}
GLboolean
_slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
{
- slang_ir_node *n, *endLabel;
+ slang_ir_node *n;
GLboolean success = GL_TRUE;
if (_mesa_strcmp((char *) fun->header.a_name, "main") != 0) {
/* we only really generate code for main, all other functions get
* inlined.
*/
+#if 0
+ /* do some basic error checking though */
+ if (fun->header.type.specifier.type != SLANG_SPEC_VOID) {
+ /* check that non-void functions actually return something */
+ slang_operation *op
+ = _slang_find_node_type(fun->body, SLANG_OPER_RETURN);
+ if (!op) {
+ slang_info_log_error(A->log,
+ "function \"%s\" has no return statement",
+ (char *) fun->header.a_name);
+ printf(
+ "function \"%s\" has no return statement\n",
+ (char *) fun->header.a_name);
+ return GL_FALSE;
+ }
+ }
+#endif
return GL_TRUE; /* not an error */
}
-#if 1
- printf("\n*********** codegen_function %s\n", (char *) fun->header.a_name);
-#endif
#if 0
+ printf("\n*********** codegen_function %s\n", (char *) fun->header.a_name);
slang_print_function(fun, 1);
#endif
assert(A->program->Parameters );
assert(A->program->Varying);
assert(A->vartable);
+ A->CurLoop = NULL;
+ A->CurFunction = fun;
/* fold constant expressions, etc. */
_slang_simplify(fun->body, &A->space, A->atoms);
- A->CurFunction = fun;
+#if 0
+ printf("\n*********** simplified %s\n", (char *) fun->header.a_name);
+ slang_print_function(fun, 1);
+#endif
/* Create an end-of-function label */
- if (!A->CurFunction->end_label)
- A->CurFunction->end_label = slang_atom_pool_gen(A->atoms, "__endOfFunc_main_");
+ A->curFuncEndLabel = _slang_label_new("__endOfFunc__main");
/* push new vartable scope */
_slang_push_var_table(A->vartable);
}
/* append an end-of-function-label to IR tree */
- endLabel = new_label(fun->end_label);
- n = new_seq(n, endLabel);
+ n = new_seq(n, new_label(A->curFuncEndLabel));
- A->CurFunction = NULL;
+ /*_slang_label_delete(A->curFuncEndLabel);*/
+ A->curFuncEndLabel = NULL;
#if 0
printf("************* New AST for %s *****\n", (char*)fun->header.a_name);
#endif
#if 0
printf("************* IR for %s *******\n", (char*)fun->header.a_name);
- slang_print_ir(n, 0);
+ _slang_print_ir_tree(n, 0);
#endif
-#if 1
+#if 0
printf("************* End codegen function ************\n\n");
#endif
/* Emit program instructions */
- success = _slang_emit_code(n, A->vartable, A->program, GL_TRUE);
+ success = _slang_emit_code(n, A->vartable, A->program, GL_TRUE, A->log);
_slang_free_ir_tree(n);
/* free codegen context */