aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2011-07-22 08:22:17 +0200
committermarha <marha@users.sourceforge.net>2011-07-22 08:22:17 +0200
commit91e91b72f07f4e61db17ee86c6933a7217f0e25c (patch)
tree67cfe3dfc7562d2f53e9827b979e1dbbc1acec7b /mesalib/src/glsl
parent88101146f2ec7d53ffb793e365f05097ffd35fd3 (diff)
downloadvcxsrv-91e91b72f07f4e61db17ee86c6933a7217f0e25c.tar.gz
vcxsrv-91e91b72f07f4e61db17ee86c6933a7217f0e25c.tar.bz2
vcxsrv-91e91b72f07f4e61db17ee86c6933a7217f0e25c.zip
mesa git update 22 July 2011
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/Makefile1
-rw-r--r--mesalib/src/glsl/SConscript1
-rw-r--r--mesalib/src/glsl/ast_function.cpp6
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp37
-rw-r--r--mesalib/src/glsl/glsl_types.cpp16
-rw-r--r--mesalib/src/glsl/glsl_types.h962
-rw-r--r--mesalib/src/glsl/ir.cpp17
-rw-r--r--mesalib/src/glsl/ir.h30
-rw-r--r--mesalib/src/glsl/ir_function_detect_recursion.cpp371
-rw-r--r--mesalib/src/glsl/linker.cpp6
-rw-r--r--mesalib/src/glsl/s_expression.cpp64
-rw-r--r--mesalib/src/glsl/s_expression.h2
12 files changed, 997 insertions, 516 deletions
diff --git a/mesalib/src/glsl/Makefile b/mesalib/src/glsl/Makefile
index e0776c1b5..d1422c2a4 100644
--- a/mesalib/src/glsl/Makefile
+++ b/mesalib/src/glsl/Makefile
@@ -39,6 +39,7 @@ CXX_SOURCES = \
ir.cpp \
ir_expression_flattening.cpp \
ir_function_can_inline.cpp \
+ ir_function_detect_recursion.cpp \
ir_function.cpp \
ir_hierarchical_visitor.cpp \
ir_hv_accept.cpp \
diff --git a/mesalib/src/glsl/SConscript b/mesalib/src/glsl/SConscript
index 1441cc74b..ea104abb8 100644
--- a/mesalib/src/glsl/SConscript
+++ b/mesalib/src/glsl/SConscript
@@ -50,6 +50,7 @@ glsl_sources = [
'ir.cpp',
'ir_expression_flattening.cpp',
'ir_function_can_inline.cpp',
+ 'ir_function_detect_recursion.cpp',
'ir_function.cpp',
'ir_hierarchical_visitor.cpp',
'ir_hv_accept.cpp',
diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp
index 60a2c617f..bdb73f487 100644
--- a/mesalib/src/glsl/ast_function.cpp
+++ b/mesalib/src/glsl/ast_function.cpp
@@ -62,8 +62,10 @@ process_parameters(exec_list *instructions, exec_list *actual_parameters,
*
* \param return_type Return type of the function. May be \c NULL.
* \param name Name of the function.
- * \param parameters Parameter list for the function. This may be either a
- * formal or actual parameter list. Only the type is used.
+ * \param parameters List of \c ir_instruction nodes representing the
+ * parameter list for the function. This may be either a
+ * formal (\c ir_variable) or actual (\c ir_rvalue)
+ * parameter list. Only the type is used.
*
* \return
* A ralloced string representing the prototype of the function.
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index 2e54e8c22..c0524bf0b 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -83,6 +83,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
foreach_list_typed (ast_node, ast, link, & state->translation_unit)
ast->hir(instructions, state);
+
+ detect_recursion_unlinked(state, instructions);
}
@@ -2704,6 +2706,17 @@ ast_declarator_list::hir(exec_list *instructions,
: "and integer");
}
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "[Sampler types] can only be declared as function
+ * parameters or uniform variables (see Section 4.3.5
+ * "Uniform")".
+ */
+ if (var_type->contains_sampler() &&
+ !this->type->qualifier.flags.q.uniform) {
+ _mesa_glsl_error(&loc, state, "samplers must be declared uniform");
+ }
+
/* Process the initializer and add its instructions to a temporary
* list. This list will be added to the instruction stream (below) after
* the declaration is added. This is done because in some cases (such as
@@ -2864,6 +2877,18 @@ ast_parameter_declarator::hir(exec_list *instructions,
*/
apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc);
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Samplers cannot be treated as l-values; hence cannot be used
+ * as out or inout function parameters, nor can they be assigned
+ * into."
+ */
+ if ((var->mode == ir_var_inout || var->mode == ir_var_out)
+ && type->contains_sampler()) {
+ _mesa_glsl_error(&loc, state, "out and inout parameters cannot contain samplers");
+ type = glsl_type::error_type;
+ }
+
instructions->push_tail(var);
/* Parameter declarations do not have r-values.
@@ -2992,6 +3017,18 @@ ast_function::hir(exec_list *instructions,
"function `%s' return type has qualifiers", name);
}
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "[Sampler types] can only be declared as function parameters
+ * or uniform variables (see Section 4.3.5 "Uniform")".
+ */
+ if (return_type->contains_sampler()) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state,
+ "function `%s' return type can't contain a sampler",
+ name);
+ }
+
/* Verify that this function's signature either doesn't match a previously
* seen signature for a function with the same name, or, if a match is found,
* that the previously seen signature does not have an associated definition.
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp
index 78d10bd93..a5e21bbb9 100644
--- a/mesalib/src/glsl/glsl_types.cpp
+++ b/mesalib/src/glsl/glsl_types.cpp
@@ -111,6 +111,22 @@ add_types_to_symbol_table(glsl_symbol_table *symtab,
}
}
+bool
+glsl_type::contains_sampler() const
+{
+ if (this->is_array()) {
+ return this->fields.array->contains_sampler();
+ } else if (this->is_record()) {
+ for (unsigned int i = 0; i < this->length; i++) {
+ if (this->fields.structure[i].type->contains_sampler())
+ return true;
+ }
+ return false;
+ } else {
+ return this->is_sampler();
+ }
+}
+
void
glsl_type::generate_100ES_types(glsl_symbol_table *symtab)
{
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h
index e4c84c953..87f57e7c7 100644
--- a/mesalib/src/glsl/glsl_types.h
+++ b/mesalib/src/glsl/glsl_types.h
@@ -1,478 +1,484 @@
-/* -*- c++ -*- */
-/*
- * Copyright © 2009 Intel Corporation
- *
- * 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 (including the next
- * paragraph) 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
- * THE AUTHORS OR COPYRIGHT HOLDERS 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.
- */
-
-#pragma once
-#ifndef GLSL_TYPES_H
-#define GLSL_TYPES_H
-
-#include <string.h>
-#include <assert.h>
-
-extern "C" {
-#include "GL/gl.h"
-}
-
-#include "ralloc.h"
-
-struct _mesa_glsl_parse_state;
-struct glsl_symbol_table;
-
-extern "C" void
-_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state);
-
-extern "C" void
-_mesa_glsl_release_types(void);
-
-enum glsl_base_type {
- GLSL_TYPE_UINT = 0,
- GLSL_TYPE_INT,
- GLSL_TYPE_FLOAT,
- GLSL_TYPE_BOOL,
- GLSL_TYPE_SAMPLER,
- GLSL_TYPE_STRUCT,
- GLSL_TYPE_ARRAY,
- GLSL_TYPE_VOID,
- GLSL_TYPE_ERROR
-};
-
-enum glsl_sampler_dim {
- GLSL_SAMPLER_DIM_1D = 0,
- GLSL_SAMPLER_DIM_2D,
- GLSL_SAMPLER_DIM_3D,
- GLSL_SAMPLER_DIM_CUBE,
- GLSL_SAMPLER_DIM_RECT,
- GLSL_SAMPLER_DIM_BUF
-};
-
-
-struct glsl_type {
- GLenum gl_type;
- glsl_base_type base_type;
-
- unsigned sampler_dimensionality:3; /**< \see glsl_sampler_dim */
- unsigned sampler_shadow:1;
- unsigned sampler_array:1;
- unsigned sampler_type:2; /**< Type of data returned using this sampler.
- * only \c GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT,
- * and \c GLSL_TYPE_UINT are valid.
- */
-
- /* Callers of this ralloc-based new need not call delete. It's
- * easier to just ralloc_free 'mem_ctx' (or any of its ancestors). */
- static void* operator new(size_t size)
- {
- if (glsl_type::mem_ctx == NULL) {
- glsl_type::mem_ctx = ralloc_context(NULL);
- assert(glsl_type::mem_ctx != NULL);
- }
-
- void *type;
-
- type = ralloc_size(glsl_type::mem_ctx, size);
- assert(type != NULL);
-
- return type;
- }
-
- /* If the user *does* call delete, that's OK, we will just
- * ralloc_free in that case. */
- static void operator delete(void *type)
- {
- ralloc_free(type);
- }
-
- /**
- * \name Vector and matrix element counts
- *
- * For scalars, each of these values will be 1. For non-numeric types
- * these will be 0.
- */
- /*@{*/
- unsigned vector_elements:3; /**< 1, 2, 3, or 4 vector elements. */
- unsigned matrix_columns:3; /**< 1, 2, 3, or 4 matrix columns. */
- /*@}*/
-
- /**
- * Name of the data type
- *
- * This may be \c NULL for anonymous structures, for arrays, or for
- * function types.
- */
- const char *name;
-
- /**
- * For \c GLSL_TYPE_ARRAY, this is the length of the array. For
- * \c GLSL_TYPE_STRUCT, it is the number of elements in the structure and
- * the number of values pointed to by \c fields.structure (below).
- */
- unsigned length;
-
- /**
- * Subtype of composite data types.
- */
- union {
- const struct glsl_type *array; /**< Type of array elements. */
- const struct glsl_type *parameters; /**< Parameters to function. */
- struct glsl_struct_field *structure; /**< List of struct fields. */
- } fields;
-
-
- /**
- * \name Pointers to various public type singletons
- */
- /*@{*/
- static const glsl_type *const error_type;
- static const glsl_type *const void_type;
- static const glsl_type *const int_type;
- static const glsl_type *const ivec4_type;
- static const glsl_type *const uint_type;
- static const glsl_type *const uvec2_type;
- static const glsl_type *const uvec3_type;
- static const glsl_type *const uvec4_type;
- static const glsl_type *const float_type;
- static const glsl_type *const vec2_type;
- static const glsl_type *const vec3_type;
- static const glsl_type *const vec4_type;
- static const glsl_type *const bool_type;
- static const glsl_type *const mat2_type;
- static const glsl_type *const mat2x3_type;
- static const glsl_type *const mat2x4_type;
- static const glsl_type *const mat3x2_type;
- static const glsl_type *const mat3_type;
- static const glsl_type *const mat3x4_type;
- static const glsl_type *const mat4x2_type;
- static const glsl_type *const mat4x3_type;
- static const glsl_type *const mat4_type;
- /*@}*/
-
-
- /**
- * For numeric and boolean derrived types returns the basic scalar type
- *
- * If the type is a numeric or boolean scalar, vector, or matrix type,
- * this function gets the scalar type of the individual components. For
- * all other types, including arrays of numeric or boolean types, the
- * error type is returned.
- */
- const glsl_type *get_base_type() const;
-
- /**
- * Query the type of elements in an array
- *
- * \return
- * Pointer to the type of elements in the array for array types, or \c NULL
- * for non-array types.
- */
- const glsl_type *element_type() const
- {
- return is_array() ? fields.array : NULL;
- }
-
- /**
- * Get the instance of a built-in scalar, vector, or matrix type
- */
- static const glsl_type *get_instance(unsigned base_type, unsigned rows,
- unsigned columns);
-
- /**
- * Get the instance of an array type
- */
- static const glsl_type *get_array_instance(const glsl_type *base,
- unsigned elements);
-
- /**
- * Get the instance of a record type
- */
- static const glsl_type *get_record_instance(const glsl_struct_field *fields,
- unsigned num_fields,
- const char *name);
-
- /**
- * Query the total number of scalars that make up a scalar, vector or matrix
- */
- unsigned components() const
- {
- return vector_elements * matrix_columns;
- }
-
- /**
- * Calculate the number of components slots required to hold this type
- *
- * This is used to determine how many uniform or varying locations a type
- * might occupy.
- */
- unsigned component_slots() const;
-
-
- /**
- * Query whether or not a type is a scalar (non-vector and non-matrix).
- */
- bool is_scalar() const
- {
- return (vector_elements == 1)
- && (base_type >= GLSL_TYPE_UINT)
- && (base_type <= GLSL_TYPE_BOOL);
- }
-
- /**
- * Query whether or not a type is a vector
- */
- bool is_vector() const
- {
- return (vector_elements > 1)
- && (matrix_columns == 1)
- && (base_type >= GLSL_TYPE_UINT)
- && (base_type <= GLSL_TYPE_BOOL);
- }
-
- /**
- * Query whether or not a type is a matrix
- */
- bool is_matrix() const
- {
- /* GLSL only has float matrices. */
- return (matrix_columns > 1) && (base_type == GLSL_TYPE_FLOAT);
- }
-
- /**
- * Query whether or not a type is a non-array numeric type
- */
- bool is_numeric() const
- {
- return (base_type >= GLSL_TYPE_UINT) && (base_type <= GLSL_TYPE_FLOAT);
- }
-
- /**
- * Query whether or not a type is an integral type
- */
- bool is_integer() const
- {
- return (base_type == GLSL_TYPE_UINT) || (base_type == GLSL_TYPE_INT);
- }
-
- /**
- * Query whether or not a type is a float type
- */
- bool is_float() const
- {
- return base_type == GLSL_TYPE_FLOAT;
- }
-
- /**
- * Query whether or not a type is a non-array boolean type
- */
- bool is_boolean() const
- {
- return base_type == GLSL_TYPE_BOOL;
- }
-
- /**
- * Query whether or not a type is a sampler
- */
- bool is_sampler() const
- {
- return base_type == GLSL_TYPE_SAMPLER;
- }
-
- /**
- * Query whether or not a type is an array
- */
- bool is_array() const
- {
- return base_type == GLSL_TYPE_ARRAY;
- }
-
- /**
- * Query whether or not a type is a record
- */
- bool is_record() const
- {
- return base_type == GLSL_TYPE_STRUCT;
- }
-
- /**
- * Query whether or not a type is the void type singleton.
- */
- bool is_void() const
- {
- return base_type == GLSL_TYPE_VOID;
- }
-
- /**
- * Query whether or not a type is the error type singleton.
- */
- bool is_error() const
- {
- return base_type == GLSL_TYPE_ERROR;
- }
-
- /**
- * Query the full type of a matrix row
- *
- * \return
- * If the type is not a matrix, \c glsl_type::error_type is returned.
- * Otherwise a type matching the rows of the matrix is returned.
- */
- const glsl_type *row_type() const
- {
- return is_matrix()
- ? get_instance(base_type, matrix_columns, 1)
- : error_type;
- }
-
- /**
- * Query the full type of a matrix column
- *
- * \return
- * If the type is not a matrix, \c glsl_type::error_type is returned.
- * Otherwise a type matching the columns of the matrix is returned.
- */
- const glsl_type *column_type() const
- {
- return is_matrix()
- ? get_instance(base_type, vector_elements, 1)
- : error_type;
- }
-
-
- /**
- * Get the type of a structure field
- *
- * \return
- * Pointer to the type of the named field. If the type is not a structure
- * or the named field does not exist, \c glsl_type::error_type is returned.
- */
- const glsl_type *field_type(const char *name) const;
-
-
- /**
- * Get the location of a filed within a record type
- */
- int field_index(const char *name) const;
-
-
- /**
- * Query the number of elements in an array type
- *
- * \return
- * The number of elements in the array for array types or -1 for non-array
- * types. If the number of elements in the array has not yet been declared,
- * zero is returned.
- */
- int array_size() const
- {
- return is_array() ? length : -1;
- }
-
-private:
- /**
- * ralloc context for all glsl_type allocations
- *
- * Set on the first call to \c glsl_type::new.
- */
- static void *mem_ctx;
-
- void init_ralloc_type_ctx(void);
-
- /** Constructor for vector and matrix types */
- glsl_type(GLenum gl_type,
- glsl_base_type base_type, unsigned vector_elements,
- unsigned matrix_columns, const char *name);
-
- /** Constructor for sampler types */
- glsl_type(GLenum gl_type,
- enum glsl_sampler_dim dim, bool shadow, bool array,
- unsigned type, const char *name);
-
- /** Constructor for record types */
- glsl_type(const glsl_struct_field *fields, unsigned num_fields,
- const char *name);
-
- /** Constructor for array types */
- glsl_type(const glsl_type *array, unsigned length);
-
- /** Hash table containing the known array types. */
- static struct hash_table *array_types;
-
- /** Hash table containing the known record types. */
- static struct hash_table *record_types;
-
- static int record_key_compare(const void *a, const void *b);
- static unsigned record_key_hash(const void *key);
-
- /**
- * \name Pointers to various type singletons
- */
- /*@{*/
- static const glsl_type _error_type;
- static const glsl_type _void_type;
- static const glsl_type _sampler3D_type;
- static const glsl_type builtin_core_types[];
- static const glsl_type builtin_structure_types[];
- static const glsl_type builtin_110_deprecated_structure_types[];
- static const glsl_type builtin_110_types[];
- static const glsl_type builtin_120_types[];
- static const glsl_type builtin_130_types[];
- static const glsl_type builtin_ARB_texture_rectangle_types[];
- static const glsl_type builtin_EXT_texture_array_types[];
- static const glsl_type builtin_EXT_texture_buffer_object_types[];
- /*@}*/
-
- /**
- * \name Methods to populate a symbol table with built-in types.
- *
- * \internal
- * This is one of the truely annoying things about C++. Methods that are
- * completely internal and private to a type still have to be advertised to
- * the world in a public header file.
- */
- /*@{*/
- static void generate_100ES_types(glsl_symbol_table *);
- static void generate_110_types(glsl_symbol_table *);
- static void generate_120_types(glsl_symbol_table *);
- static void generate_130_types(glsl_symbol_table *);
- static void generate_ARB_texture_rectangle_types(glsl_symbol_table *, bool);
- static void generate_EXT_texture_array_types(glsl_symbol_table *, bool);
- static void generate_OES_texture_3D_types(glsl_symbol_table *, bool);
- /*@}*/
-
- /**
- * \name Friend functions.
- *
- * These functions are friends because they must have C linkage and the
- * need to call various private methods or access various private static
- * data.
- */
- /*@{*/
- friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *);
- friend void _mesa_glsl_release_types(void);
- /*@}*/
-};
-
-struct glsl_struct_field {
- const struct glsl_type *type;
- const char *name;
-};
-
-#endif /* GLSL_TYPES_H */
+/* -*- c++ -*- */
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#pragma once
+#ifndef GLSL_TYPES_H
+#define GLSL_TYPES_H
+
+#include <string.h>
+#include <assert.h>
+
+extern "C" {
+#include "GL/gl.h"
+}
+
+#include "ralloc.h"
+
+struct _mesa_glsl_parse_state;
+struct glsl_symbol_table;
+
+extern "C" void
+_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state);
+
+extern "C" void
+_mesa_glsl_release_types(void);
+
+enum glsl_base_type {
+ GLSL_TYPE_UINT = 0,
+ GLSL_TYPE_INT,
+ GLSL_TYPE_FLOAT,
+ GLSL_TYPE_BOOL,
+ GLSL_TYPE_SAMPLER,
+ GLSL_TYPE_STRUCT,
+ GLSL_TYPE_ARRAY,
+ GLSL_TYPE_VOID,
+ GLSL_TYPE_ERROR
+};
+
+enum glsl_sampler_dim {
+ GLSL_SAMPLER_DIM_1D = 0,
+ GLSL_SAMPLER_DIM_2D,
+ GLSL_SAMPLER_DIM_3D,
+ GLSL_SAMPLER_DIM_CUBE,
+ GLSL_SAMPLER_DIM_RECT,
+ GLSL_SAMPLER_DIM_BUF
+};
+
+
+struct glsl_type {
+ GLenum gl_type;
+ glsl_base_type base_type;
+
+ unsigned sampler_dimensionality:3; /**< \see glsl_sampler_dim */
+ unsigned sampler_shadow:1;
+ unsigned sampler_array:1;
+ unsigned sampler_type:2; /**< Type of data returned using this sampler.
+ * only \c GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT,
+ * and \c GLSL_TYPE_UINT are valid.
+ */
+
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'mem_ctx' (or any of its ancestors). */
+ static void* operator new(size_t size)
+ {
+ if (glsl_type::mem_ctx == NULL) {
+ glsl_type::mem_ctx = ralloc_context(NULL);
+ assert(glsl_type::mem_ctx != NULL);
+ }
+
+ void *type;
+
+ type = ralloc_size(glsl_type::mem_ctx, size);
+ assert(type != NULL);
+
+ return type;
+ }
+
+ /* If the user *does* call delete, that's OK, we will just
+ * ralloc_free in that case. */
+ static void operator delete(void *type)
+ {
+ ralloc_free(type);
+ }
+
+ /**
+ * \name Vector and matrix element counts
+ *
+ * For scalars, each of these values will be 1. For non-numeric types
+ * these will be 0.
+ */
+ /*@{*/
+ unsigned vector_elements:3; /**< 1, 2, 3, or 4 vector elements. */
+ unsigned matrix_columns:3; /**< 1, 2, 3, or 4 matrix columns. */
+ /*@}*/
+
+ /**
+ * Name of the data type
+ *
+ * This may be \c NULL for anonymous structures, for arrays, or for
+ * function types.
+ */
+ const char *name;
+
+ /**
+ * For \c GLSL_TYPE_ARRAY, this is the length of the array. For
+ * \c GLSL_TYPE_STRUCT, it is the number of elements in the structure and
+ * the number of values pointed to by \c fields.structure (below).
+ */
+ unsigned length;
+
+ /**
+ * Subtype of composite data types.
+ */
+ union {
+ const struct glsl_type *array; /**< Type of array elements. */
+ const struct glsl_type *parameters; /**< Parameters to function. */
+ struct glsl_struct_field *structure; /**< List of struct fields. */
+ } fields;
+
+
+ /**
+ * \name Pointers to various public type singletons
+ */
+ /*@{*/
+ static const glsl_type *const error_type;
+ static const glsl_type *const void_type;
+ static const glsl_type *const int_type;
+ static const glsl_type *const ivec4_type;
+ static const glsl_type *const uint_type;
+ static const glsl_type *const uvec2_type;
+ static const glsl_type *const uvec3_type;
+ static const glsl_type *const uvec4_type;
+ static const glsl_type *const float_type;
+ static const glsl_type *const vec2_type;
+ static const glsl_type *const vec3_type;
+ static const glsl_type *const vec4_type;
+ static const glsl_type *const bool_type;
+ static const glsl_type *const mat2_type;
+ static const glsl_type *const mat2x3_type;
+ static const glsl_type *const mat2x4_type;
+ static const glsl_type *const mat3x2_type;
+ static const glsl_type *const mat3_type;
+ static const glsl_type *const mat3x4_type;
+ static const glsl_type *const mat4x2_type;
+ static const glsl_type *const mat4x3_type;
+ static const glsl_type *const mat4_type;
+ /*@}*/
+
+
+ /**
+ * For numeric and boolean derrived types returns the basic scalar type
+ *
+ * If the type is a numeric or boolean scalar, vector, or matrix type,
+ * this function gets the scalar type of the individual components. For
+ * all other types, including arrays of numeric or boolean types, the
+ * error type is returned.
+ */
+ const glsl_type *get_base_type() const;
+
+ /**
+ * Query the type of elements in an array
+ *
+ * \return
+ * Pointer to the type of elements in the array for array types, or \c NULL
+ * for non-array types.
+ */
+ const glsl_type *element_type() const
+ {
+ return is_array() ? fields.array : NULL;
+ }
+
+ /**
+ * Get the instance of a built-in scalar, vector, or matrix type
+ */
+ static const glsl_type *get_instance(unsigned base_type, unsigned rows,
+ unsigned columns);
+
+ /**
+ * Get the instance of an array type
+ */
+ static const glsl_type *get_array_instance(const glsl_type *base,
+ unsigned elements);
+
+ /**
+ * Get the instance of a record type
+ */
+ static const glsl_type *get_record_instance(const glsl_struct_field *fields,
+ unsigned num_fields,
+ const char *name);
+
+ /**
+ * Query the total number of scalars that make up a scalar, vector or matrix
+ */
+ unsigned components() const
+ {
+ return vector_elements * matrix_columns;
+ }
+
+ /**
+ * Calculate the number of components slots required to hold this type
+ *
+ * This is used to determine how many uniform or varying locations a type
+ * might occupy.
+ */
+ unsigned component_slots() const;
+
+
+ /**
+ * Query whether or not a type is a scalar (non-vector and non-matrix).
+ */
+ bool is_scalar() const
+ {
+ return (vector_elements == 1)
+ && (base_type >= GLSL_TYPE_UINT)
+ && (base_type <= GLSL_TYPE_BOOL);
+ }
+
+ /**
+ * Query whether or not a type is a vector
+ */
+ bool is_vector() const
+ {
+ return (vector_elements > 1)
+ && (matrix_columns == 1)
+ && (base_type >= GLSL_TYPE_UINT)
+ && (base_type <= GLSL_TYPE_BOOL);
+ }
+
+ /**
+ * Query whether or not a type is a matrix
+ */
+ bool is_matrix() const
+ {
+ /* GLSL only has float matrices. */
+ return (matrix_columns > 1) && (base_type == GLSL_TYPE_FLOAT);
+ }
+
+ /**
+ * Query whether or not a type is a non-array numeric type
+ */
+ bool is_numeric() const
+ {
+ return (base_type >= GLSL_TYPE_UINT) && (base_type <= GLSL_TYPE_FLOAT);
+ }
+
+ /**
+ * Query whether or not a type is an integral type
+ */
+ bool is_integer() const
+ {
+ return (base_type == GLSL_TYPE_UINT) || (base_type == GLSL_TYPE_INT);
+ }
+
+ /**
+ * Query whether or not a type is a float type
+ */
+ bool is_float() const
+ {
+ return base_type == GLSL_TYPE_FLOAT;
+ }
+
+ /**
+ * Query whether or not a type is a non-array boolean type
+ */
+ bool is_boolean() const
+ {
+ return base_type == GLSL_TYPE_BOOL;
+ }
+
+ /**
+ * Query whether or not a type is a sampler
+ */
+ bool is_sampler() const
+ {
+ return base_type == GLSL_TYPE_SAMPLER;
+ }
+
+ /**
+ * Query whether or not type is a sampler, or for struct and array
+ * types, contains a sampler.
+ */
+ bool contains_sampler() const;
+
+ /**
+ * Query whether or not a type is an array
+ */
+ bool is_array() const
+ {
+ return base_type == GLSL_TYPE_ARRAY;
+ }
+
+ /**
+ * Query whether or not a type is a record
+ */
+ bool is_record() const
+ {
+ return base_type == GLSL_TYPE_STRUCT;
+ }
+
+ /**
+ * Query whether or not a type is the void type singleton.
+ */
+ bool is_void() const
+ {
+ return base_type == GLSL_TYPE_VOID;
+ }
+
+ /**
+ * Query whether or not a type is the error type singleton.
+ */
+ bool is_error() const
+ {
+ return base_type == GLSL_TYPE_ERROR;
+ }
+
+ /**
+ * Query the full type of a matrix row
+ *
+ * \return
+ * If the type is not a matrix, \c glsl_type::error_type is returned.
+ * Otherwise a type matching the rows of the matrix is returned.
+ */
+ const glsl_type *row_type() const
+ {
+ return is_matrix()
+ ? get_instance(base_type, matrix_columns, 1)
+ : error_type;
+ }
+
+ /**
+ * Query the full type of a matrix column
+ *
+ * \return
+ * If the type is not a matrix, \c glsl_type::error_type is returned.
+ * Otherwise a type matching the columns of the matrix is returned.
+ */
+ const glsl_type *column_type() const
+ {
+ return is_matrix()
+ ? get_instance(base_type, vector_elements, 1)
+ : error_type;
+ }
+
+
+ /**
+ * Get the type of a structure field
+ *
+ * \return
+ * Pointer to the type of the named field. If the type is not a structure
+ * or the named field does not exist, \c glsl_type::error_type is returned.
+ */
+ const glsl_type *field_type(const char *name) const;
+
+
+ /**
+ * Get the location of a filed within a record type
+ */
+ int field_index(const char *name) const;
+
+
+ /**
+ * Query the number of elements in an array type
+ *
+ * \return
+ * The number of elements in the array for array types or -1 for non-array
+ * types. If the number of elements in the array has not yet been declared,
+ * zero is returned.
+ */
+ int array_size() const
+ {
+ return is_array() ? length : -1;
+ }
+
+private:
+ /**
+ * ralloc context for all glsl_type allocations
+ *
+ * Set on the first call to \c glsl_type::new.
+ */
+ static void *mem_ctx;
+
+ void init_ralloc_type_ctx(void);
+
+ /** Constructor for vector and matrix types */
+ glsl_type(GLenum gl_type,
+ glsl_base_type base_type, unsigned vector_elements,
+ unsigned matrix_columns, const char *name);
+
+ /** Constructor for sampler types */
+ glsl_type(GLenum gl_type,
+ enum glsl_sampler_dim dim, bool shadow, bool array,
+ unsigned type, const char *name);
+
+ /** Constructor for record types */
+ glsl_type(const glsl_struct_field *fields, unsigned num_fields,
+ const char *name);
+
+ /** Constructor for array types */
+ glsl_type(const glsl_type *array, unsigned length);
+
+ /** Hash table containing the known array types. */
+ static struct hash_table *array_types;
+
+ /** Hash table containing the known record types. */
+ static struct hash_table *record_types;
+
+ static int record_key_compare(const void *a, const void *b);
+ static unsigned record_key_hash(const void *key);
+
+ /**
+ * \name Pointers to various type singletons
+ */
+ /*@{*/
+ static const glsl_type _error_type;
+ static const glsl_type _void_type;
+ static const glsl_type _sampler3D_type;
+ static const glsl_type builtin_core_types[];
+ static const glsl_type builtin_structure_types[];
+ static const glsl_type builtin_110_deprecated_structure_types[];
+ static const glsl_type builtin_110_types[];
+ static const glsl_type builtin_120_types[];
+ static const glsl_type builtin_130_types[];
+ static const glsl_type builtin_ARB_texture_rectangle_types[];
+ static const glsl_type builtin_EXT_texture_array_types[];
+ static const glsl_type builtin_EXT_texture_buffer_object_types[];
+ /*@}*/
+
+ /**
+ * \name Methods to populate a symbol table with built-in types.
+ *
+ * \internal
+ * This is one of the truely annoying things about C++. Methods that are
+ * completely internal and private to a type still have to be advertised to
+ * the world in a public header file.
+ */
+ /*@{*/
+ static void generate_100ES_types(glsl_symbol_table *);
+ static void generate_110_types(glsl_symbol_table *);
+ static void generate_120_types(glsl_symbol_table *);
+ static void generate_130_types(glsl_symbol_table *);
+ static void generate_ARB_texture_rectangle_types(glsl_symbol_table *, bool);
+ static void generate_EXT_texture_array_types(glsl_symbol_table *, bool);
+ static void generate_OES_texture_3D_types(glsl_symbol_table *, bool);
+ /*@}*/
+
+ /**
+ * \name Friend functions.
+ *
+ * These functions are friends because they must have C linkage and the
+ * need to call various private methods or access various private static
+ * data.
+ */
+ /*@{*/
+ friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *);
+ friend void _mesa_glsl_release_types(void);
+ /*@}*/
+};
+
+struct glsl_struct_field {
+ const struct glsl_type *type;
+ const char *name;
+};
+
+#endif /* GLSL_TYPES_H */
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index 95689dc10..827fe8e17 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -1095,21 +1095,6 @@ ir_dereference_record::ir_dereference_record(ir_variable *var,
? this->record->type->field_type(field) : glsl_type::error_type;
}
-bool type_contains_sampler(const glsl_type *type)
-{
- if (type->is_array()) {
- return type_contains_sampler(type->fields.array);
- } else if (type->is_record()) {
- for (unsigned int i = 0; i < type->length; i++) {
- if (type_contains_sampler(type->fields.structure[i].type))
- return true;
- }
- return false;
- } else {
- return type->is_sampler();
- }
-}
-
bool
ir_dereference::is_lvalue()
{
@@ -1129,7 +1114,7 @@ ir_dereference::is_lvalue()
* as out or inout function parameters, nor can they be
* assigned into."
*/
- if (type_contains_sampler(this->type))
+ if (this->type->contains_sampler())
return false;
return true;
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h
index 80ad3dd29..50a9d6e19 100644
--- a/mesalib/src/glsl/ir.h
+++ b/mesalib/src/glsl/ir.h
@@ -1635,6 +1635,32 @@ visit_exec_list(exec_list *list, ir_visitor *visitor);
*/
void validate_ir_tree(exec_list *instructions);
+struct _mesa_glsl_parse_state;
+struct gl_shader_program;
+
+/**
+ * Detect whether an unlinked shader contains static recursion
+ *
+ * If the list of instructions is determined to contain static recursion,
+ * \c _mesa_glsl_error will be called to emit error messages for each function
+ * that is in the recursion cycle.
+ */
+void
+detect_recursion_unlinked(struct _mesa_glsl_parse_state *state,
+ exec_list *instructions);
+
+/**
+ * Detect whether a linked shader contains static recursion
+ *
+ * If the list of instructions is determined to contain static recursion,
+ * \c link_error_printf will be called to emit error messages for each function
+ * that is in the recursion cycle. In addition,
+ * \c gl_shader_program::LinkStatus will be set to false.
+ */
+void
+detect_recursion_linked(struct gl_shader_program *prog,
+ exec_list *instructions);
+
/**
* Make a clone of each IR instruction in a list
*
@@ -1669,4 +1695,8 @@ ir_has_call(ir_instruction *ir);
extern void
do_set_program_inouts(exec_list *instructions, struct gl_program *prog);
+extern char *
+prototype_string(const glsl_type *return_type, const char *name,
+ exec_list *parameters);
+
#endif /* IR_H */
diff --git a/mesalib/src/glsl/ir_function_detect_recursion.cpp b/mesalib/src/glsl/ir_function_detect_recursion.cpp
new file mode 100644
index 000000000..44a1cd0b9
--- /dev/null
+++ b/mesalib/src/glsl/ir_function_detect_recursion.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 ir_function_detect_recursion.cpp
+ * Determine whether a shader contains static recursion.
+ *
+ * Consider the (possibly disjoint) graph of function calls in a shader. If a
+ * program contains recursion, this graph will contain a cycle. If a function
+ * is part of a cycle, it will have a caller and it will have a callee (it
+ * calls another function).
+ *
+ * To detect recursion, the function call graph is constructed. The graph is
+ * repeatedly reduced by removing any function that either has no callees
+ * (leaf functions) or has no caller. Eventually the only functions that
+ * remain will be the functions in the cycles.
+ *
+ * The GLSL spec is a bit wishy-washy about recursion.
+ *
+ * From page 39 (page 45 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "Behavior is undefined if recursion is used. Recursion means having any
+ * function appearing more than once at any one time in the run-time stack
+ * of function calls. That is, a function may not call itself either
+ * directly or indirectly. Compilers may give diagnostic messages when
+ * this is detectable at compile time, but not all such cases can be
+ * detected at compile time."
+ *
+ * From page 79 (page 85 of the PDF):
+ *
+ * "22) Should recursion be supported?
+ *
+ * DISCUSSION: Probably not necessary, but another example of limiting
+ * the language based on how it would directly map to hardware. One
+ * thought is that recursion would benefit ray tracing shaders. On the
+ * other hand, many recursion operations can also be implemented with the
+ * user managing the recursion through arrays. RenderMan doesn't support
+ * recursion. This could be added at a later date, if it proved to be
+ * necessary.
+ *
+ * RESOLVED on September 10, 2002: Implementations are not required to
+ * support recursion.
+ *
+ * CLOSED on September 10, 2002."
+ *
+ * From page 79 (page 85 of the PDF):
+ *
+ * "56) Is it an error for an implementation to support recursion if the
+ * specification says recursion is not supported?
+ *
+ * ADDED on September 10, 2002.
+ *
+ * DISCUSSION: This issues is related to Issue (22). If we say that
+ * recursion (or some other piece of functionality) is not supported, is
+ * it an error for an implementation to support it? Perhaps the
+ * specification should remain silent on these kind of things so that they
+ * could be gracefully added later as an extension or as part of the
+ * standard.
+ *
+ * RESOLUTION: Languages, in general, have programs that are not
+ * well-formed in ways a compiler cannot detect. Portability is only
+ * ensured for well-formed programs. Detecting recursion is an example of
+ * this. The language will say a well-formed program may not recurse, but
+ * compilers are not forced to detect that recursion may happen.
+ *
+ * CLOSED: November 29, 2002."
+ *
+ * In GLSL 1.10 the behavior of recursion is undefined. Compilers don't have
+ * to reject shaders (at compile-time or link-time) that contain recursion.
+ * Instead they could work, or crash, or kill a kitten.
+ *
+ * From page 44 (page 50 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Recursion is not allowed, not even statically. Static recursion is
+ * present if the static function call graph of the program contains
+ * cycles."
+ *
+ * This langauge clears things up a bit, but it still leaves a lot of
+ * questions unanswered.
+ *
+ * - Is the error generated at compile-time or link-time?
+ *
+ * - Is it an error to have a recursive function that is never statically
+ * called by main or any function called directly or indirectly by main?
+ * Technically speaking, such a function is not in the "static function
+ * call graph of the program" at all.
+ *
+ * \bug
+ * If a shader has multiple cycles, this algorithm may erroneously complain
+ * about functions that aren't in any cycle, but are in the part of the call
+ * tree that connects them. For example, if the call graph consists of a
+ * cycle between A and B, and a cycle between D and E, and B also calls C
+ * which calls D, then this algorithm will report C as a function which "has
+ * static recursion" even though it is not part of any cycle.
+ *
+ * A better algorithm for cycle detection that doesn't have this drawback can
+ * be found here:
+ *
+ * http://en.wikipedia.org/wiki/Tarjan%E2%80%99s_strongly_connected_components_algorithm
+ *
+ * \author Ian Romanick <ian.d.romanick@intel.com>
+ */
+#include "main/core.h"
+#include "ir.h"
+#include "glsl_parser_extras.h"
+#include "linker.h"
+#include "program/hash_table.h"
+
+struct call_node : public exec_node {
+ class function *func;
+};
+
+class function {
+public:
+ function(ir_function_signature *sig)
+ : sig(sig)
+ {
+ /* empty */
+ }
+
+
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
+ static void* operator new(size_t size, void *ctx)
+ {
+ void *node;
+
+ node = ralloc_size(ctx, size);
+ assert(node != NULL);
+
+ return node;
+ }
+
+ /* If the user *does* call delete, that's OK, we will just
+ * ralloc_free in that case. */
+ static void operator delete(void *node)
+ {
+ ralloc_free(node);
+ }
+
+ ir_function_signature *sig;
+
+ /** List of functions called by this function. */
+ exec_list callees;
+
+ /** List of functions that call this function. */
+ exec_list callers;
+};
+
+class has_recursion_visitor : public ir_hierarchical_visitor {
+public:
+ has_recursion_visitor()
+ : current(NULL)
+ {
+ this->mem_ctx = ralloc_context(NULL);
+ this->function_hash = hash_table_ctor(0, hash_table_pointer_hash,
+ hash_table_pointer_compare);
+ }
+
+ ~has_recursion_visitor()
+ {
+ hash_table_dtor(this->function_hash);
+ ralloc_free(this->mem_ctx);
+ }
+
+ function *get_function(ir_function_signature *sig)
+ {
+ function *f = (function *) hash_table_find(this->function_hash, sig);
+ if (f == NULL) {
+ f = new(mem_ctx) function(sig);
+ hash_table_insert(this->function_hash, f, sig);
+ }
+
+ return f;
+ }
+
+ virtual ir_visitor_status visit_enter(ir_function_signature *sig)
+ {
+ this->current = this->get_function(sig);
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_function_signature *sig)
+ {
+ (void) sig;
+ this->current = NULL;
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_enter(ir_call *call)
+ {
+ /* At global scope this->current will be NULL. Since there is no way to
+ * call global scope, it can never be part of a cycle. Don't bother
+ * adding calls from global scope to the graph.
+ */
+ if (this->current == NULL)
+ return visit_continue;
+
+ function *const target = this->get_function(call->get_callee());
+
+ /* Create a link from the caller to the callee.
+ */
+ call_node *node = new(mem_ctx) call_node;
+ node->func = target;
+ this->current->callees.push_tail(node);
+
+ /* Create a link from the callee to the caller.
+ */
+ node = new(mem_ctx) call_node;
+ node->func = this->current;
+ target->callers.push_tail(node);
+ return visit_continue;
+ }
+
+ function *current;
+ struct hash_table *function_hash;
+ void *mem_ctx;
+ bool progress;
+};
+
+static void
+destroy_links(exec_list *list, function *f)
+{
+ foreach_list_safe(node, list) {
+ struct call_node *n = (struct call_node *) node;
+
+ /* If this is the right function, remove it. Note that the loop cannot
+ * terminate now. There can be multiple links to a function if it is
+ * either called multiple times or calls multiple times.
+ */
+ if (n->func == f)
+ n->remove();
+ }
+}
+
+
+/**
+ * Remove a function if it has either no in or no out links
+ */
+static void
+remove_unlinked_functions(const void *key, void *data, void *closure)
+{
+ has_recursion_visitor *visitor = (has_recursion_visitor *) closure;
+ function *f = (function *) data;
+
+ if (f->callers.is_empty() || f->callees.is_empty()) {
+ while (!f->callers.is_empty()) {
+ struct call_node *n = (struct call_node *) f->callers.pop_head();
+ destroy_links(& n->func->callees, f);
+ }
+
+ while (!f->callees.is_empty()) {
+ struct call_node *n = (struct call_node *) f->callees.pop_head();
+ destroy_links(& n->func->callers, f);
+ }
+
+ hash_table_remove(visitor->function_hash, key);
+ visitor->progress = true;
+ }
+}
+
+
+static void
+emit_errors_unlinked(const void *key, void *data, void *closure)
+{
+ struct _mesa_glsl_parse_state *state =
+ (struct _mesa_glsl_parse_state *) closure;
+ function *f = (function *) data;
+ YYLTYPE loc;
+
+ char *proto = prototype_string(f->sig->return_type,
+ f->sig->function_name(),
+ &f->sig->parameters);
+
+ memset(&loc, 0, sizeof(loc));
+ _mesa_glsl_error(&loc, state,
+ "function `%s' has static recursion.",
+ proto);
+ ralloc_free(proto);
+}
+
+
+static void
+emit_errors_linked(const void *key, void *data, void *closure)
+{
+ struct gl_shader_program *prog =
+ (struct gl_shader_program *) closure;
+ function *f = (function *) data;
+
+ char *proto = prototype_string(f->sig->return_type,
+ f->sig->function_name(),
+ &f->sig->parameters);
+
+ linker_error_printf(prog,
+ "function `%s' has static recursion.\n",
+ proto);
+ ralloc_free(proto);
+ prog->LinkStatus = false;
+}
+
+
+void
+detect_recursion_unlinked(struct _mesa_glsl_parse_state *state,
+ exec_list *instructions)
+{
+ has_recursion_visitor v;
+
+ /* Collect all of the information about which functions call which other
+ * functions.
+ */
+ v.run(instructions);
+
+ /* Remove from the set all of the functions that either have no caller or
+ * call no other functions. Repeat until no functions are removed.
+ */
+ do {
+ v.progress = false;
+ hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
+ } while (v.progress);
+
+
+ /* At this point any functions still in the hash must be part of a cycle.
+ */
+ hash_table_call_foreach(v.function_hash, emit_errors_unlinked, state);
+}
+
+
+void
+detect_recursion_linked(struct gl_shader_program *prog,
+ exec_list *instructions)
+{
+ has_recursion_visitor v;
+
+ /* Collect all of the information about which functions call which other
+ * functions.
+ */
+ v.run(instructions);
+
+ /* Remove from the set all of the functions that either have no caller or
+ * call no other functions. Repeat until no functions are removed.
+ */
+ do {
+ v.progress = false;
+ hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
+ } while (v.progress);
+
+
+ /* At this point any functions still in the hash must be part of a cycle.
+ */
+ hash_table_call_foreach(v.function_hash, emit_errors_linked, prog);
+}
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 34b64837a..fe570b6cc 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -1343,7 +1343,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
foreach_list(node, sh->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
- if ((var == NULL) || (var->mode != direction))
+ if ((var == NULL) || (var->mode != (unsigned) direction))
continue;
if (var->explicit_location) {
@@ -1702,6 +1702,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
if (prog->_LinkedShaders[i] == NULL)
continue;
+ detect_recursion_linked(prog, prog->_LinkedShaders[i]->ir);
+ if (!prog->LinkStatus)
+ goto done;
+
while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, 32))
;
}
diff --git a/mesalib/src/glsl/s_expression.cpp b/mesalib/src/glsl/s_expression.cpp
index a922a50d3..e704a3be2 100644
--- a/mesalib/src/glsl/s_expression.cpp
+++ b/mesalib/src/glsl/s_expression.cpp
@@ -25,10 +25,13 @@
#include <assert.h>
#include "s_expression.h"
-s_symbol::s_symbol(const char *tmp, size_t n)
+s_symbol::s_symbol(const char *str, size_t n)
{
- this->str = ralloc_strndup (this, tmp, n);
- assert(this->str != NULL);
+ /* Assume the given string is already nul-terminated and in memory that
+ * will live as long as this node.
+ */
+ assert(str[n] == '\0');
+ this->str = str;
}
s_list::s_list()
@@ -36,22 +39,26 @@ s_list::s_list()
}
static void
-skip_whitespace(const char *& src)
+skip_whitespace(const char *&src, char *&symbol_buffer)
{
- src += strspn(src, " \v\t\r\n");
+ size_t n = strspn(src, " \v\t\r\n");
+ src += n;
+ symbol_buffer += n;
/* Also skip Scheme-style comments: semi-colon 'til end of line */
if (src[0] == ';') {
- src += strcspn(src, "\n");
- skip_whitespace(src);
+ n = strcspn(src, "\n");
+ src += n;
+ symbol_buffer += n;
+ skip_whitespace(src, symbol_buffer);
}
}
static s_expression *
-read_atom(void *ctx, const char *& src)
+read_atom(void *ctx, const char *&src, char *&symbol_buffer)
{
s_expression *expr = NULL;
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
size_t n = strcspn(src, "( \v\t\r\n);");
if (n == 0)
@@ -70,44 +77,65 @@ read_atom(void *ctx, const char *& src)
expr = new(ctx) s_int(i);
} else {
// Not a number; return a symbol.
- expr = new(ctx) s_symbol(src, n);
+ symbol_buffer[n] = '\0';
+ expr = new(ctx) s_symbol(symbol_buffer, n);
}
src += n;
+ symbol_buffer += n;
return expr;
}
-s_expression *
-s_expression::read_expression(void *ctx, const char *&src)
+static s_expression *
+__read_expression(void *ctx, const char *&src, char *&symbol_buffer)
{
- assert(src != NULL);
-
- s_expression *atom = read_atom(ctx, src);
+ s_expression *atom = read_atom(ctx, src, symbol_buffer);
if (atom != NULL)
return atom;
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
if (src[0] == '(') {
++src;
+ ++symbol_buffer;
s_list *list = new(ctx) s_list;
s_expression *expr;
- while ((expr = read_expression(ctx, src)) != NULL) {
+ while ((expr = __read_expression(ctx, src, symbol_buffer)) != NULL) {
list->subexpressions.push_tail(expr);
}
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
if (src[0] != ')') {
printf("Unclosed expression (check your parenthesis).\n");
return NULL;
}
++src;
+ ++symbol_buffer;
return list;
}
return NULL;
}
+s_expression *
+s_expression::read_expression(void *ctx, const char *&src)
+{
+ assert(src != NULL);
+
+ /* When we encounter a Symbol, we need to save a nul-terminated copy of
+ * the string. However, ralloc_strndup'ing every individual Symbol is
+ * extremely expensive. We could avoid this by simply overwriting the
+ * next character (guaranteed to be whitespace, parens, or semicolon) with
+ * a nul-byte. But overwriting non-whitespace would mess up parsing.
+ *
+ * So, just copy the whole buffer ahead of time. Walk both, leaving the
+ * original source string unmodified, and altering the copy to contain the
+ * necessary nul-bytes whenever we encounter a symbol.
+ */
+ char *symbol_buffer = ralloc_strdup(ctx, src);
+ return __read_expression(ctx, src, symbol_buffer);
+}
+
void s_int::print()
{
printf("%d", this->val);
diff --git a/mesalib/src/glsl/s_expression.h b/mesalib/src/glsl/s_expression.h
index c9dc676b3..642af19b4 100644
--- a/mesalib/src/glsl/s_expression.h
+++ b/mesalib/src/glsl/s_expression.h
@@ -129,7 +129,7 @@ public:
void print();
private:
- char *str;
+ const char *str;
};
/* Lists of expressions: (expr1 ... exprN) */