aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/ast.h82
-rw-r--r--mesalib/src/glsl/ast_function.cpp323
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp6
-rw-r--r--mesalib/src/glsl/ast_type.cpp68
-rw-r--r--mesalib/src/glsl/glsl_parser.yy109
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp4
-rw-r--r--mesalib/src/glsl/glsl_types.cpp5
-rw-r--r--mesalib/src/glsl/hir_field_selection.cpp2
-rw-r--r--mesalib/src/glsl/ir.cpp17
-rw-r--r--mesalib/src/glsl/ir.h83
-rw-r--r--mesalib/src/glsl/ir_basic_block.cpp43
-rw-r--r--mesalib/src/glsl/ir_clone.cpp18
-rw-r--r--mesalib/src/glsl/ir_constant_expression.cpp33
-rw-r--r--mesalib/src/glsl/ir_expression_flattening.cpp5
-rw-r--r--mesalib/src/glsl/ir_function.cpp2
-rw-r--r--mesalib/src/glsl/ir_function_can_inline.cpp152
-rw-r--r--mesalib/src/glsl/ir_function_detect_recursion.cpp2
-rw-r--r--mesalib/src/glsl/ir_hierarchical_visitor.cpp9
-rw-r--r--mesalib/src/glsl/ir_hierarchical_visitor.h1
-rw-r--r--mesalib/src/glsl/ir_hv_accept.cpp15
-rw-r--r--mesalib/src/glsl/ir_print_visitor.cpp9
-rw-r--r--mesalib/src/glsl/ir_print_visitor.h1
-rw-r--r--mesalib/src/glsl/ir_reader.cpp60
-rw-r--r--mesalib/src/glsl/ir_validate.cpp17
-rw-r--r--mesalib/src/glsl/ir_visitor.h1
-rw-r--r--mesalib/src/glsl/link_functions.cpp6
-rw-r--r--mesalib/src/glsl/link_uniforms.cpp3
-rw-r--r--mesalib/src/glsl/linker.cpp12
-rw-r--r--mesalib/src/glsl/loop_analysis.cpp28
-rw-r--r--mesalib/src/glsl/loop_analysis.h6
-rw-r--r--mesalib/src/glsl/lower_clip_distance.cpp2
-rw-r--r--mesalib/src/glsl/lower_output_reads.cpp18
-rw-r--r--mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp2
-rw-r--r--mesalib/src/glsl/opt_constant_folding.cpp12
-rw-r--r--mesalib/src/glsl/opt_constant_propagation.cpp2
-rw-r--r--mesalib/src/glsl/opt_constant_variable.cpp14
-rw-r--r--mesalib/src/glsl/opt_copy_propagation.cpp2
-rw-r--r--mesalib/src/glsl/opt_copy_propagation_elements.cpp2
-rw-r--r--mesalib/src/glsl/opt_dead_code.cpp3
-rw-r--r--mesalib/src/glsl/opt_dead_code_local.cpp7
-rw-r--r--mesalib/src/glsl/opt_dead_functions.cpp2
-rw-r--r--mesalib/src/glsl/opt_function_inlining.cpp62
-rw-r--r--mesalib/src/glsl/opt_tree_grafting.cpp5
43 files changed, 609 insertions, 646 deletions
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h
index 1f78af87e..9b1e0b192 100644
--- a/mesalib/src/glsl/ast.h
+++ b/mesalib/src/glsl/ast.h
@@ -206,7 +206,7 @@ public:
subexpressions[0] = NULL;
subexpressions[1] = NULL;
subexpressions[2] = NULL;
- primary_expression.identifier = (char *) identifier;
+ primary_expression.identifier = identifier;
this->non_lvalue_description = NULL;
}
@@ -222,7 +222,7 @@ public:
ast_expression *subexpressions[3];
union {
- char *identifier;
+ const char *identifier;
int int_constant;
float float_constant;
unsigned uint_constant;
@@ -317,11 +317,11 @@ public:
class ast_declaration : public ast_node {
public:
- ast_declaration(char *identifier, int is_array, ast_expression *array_size,
+ ast_declaration(const char *identifier, int is_array, ast_expression *array_size,
ast_expression *initializer);
virtual void print(void) const;
- char *identifier;
+ const char *identifier;
int is_array;
ast_expression *array_size;
@@ -407,83 +407,23 @@ struct ast_type_qualifier {
class ast_struct_specifier : public ast_node {
public:
- ast_struct_specifier(char *identifier, ast_node *declarator_list);
+ ast_struct_specifier(const char *identifier, ast_node *declarator_list);
virtual void print(void) const;
virtual ir_rvalue *hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state);
- char *name;
+ const char *name;
exec_list declarations;
};
-enum ast_types {
- ast_void,
- ast_float,
- ast_int,
- ast_uint,
- ast_bool,
- ast_vec2,
- ast_vec3,
- ast_vec4,
- ast_bvec2,
- ast_bvec3,
- ast_bvec4,
- ast_ivec2,
- ast_ivec3,
- ast_ivec4,
- ast_uvec2,
- ast_uvec3,
- ast_uvec4,
- ast_mat2,
- ast_mat2x3,
- ast_mat2x4,
- ast_mat3x2,
- ast_mat3,
- ast_mat3x4,
- ast_mat4x2,
- ast_mat4x3,
- ast_mat4,
- ast_sampler1d,
- ast_sampler2d,
- ast_sampler2drect,
- ast_sampler3d,
- ast_samplercube,
- ast_samplerexternaloes,
- ast_sampler1dshadow,
- ast_sampler2dshadow,
- ast_sampler2drectshadow,
- ast_samplercubeshadow,
- ast_sampler1darray,
- ast_sampler2darray,
- ast_sampler1darrayshadow,
- ast_sampler2darrayshadow,
- ast_isampler1d,
- ast_isampler2d,
- ast_isampler3d,
- ast_isamplercube,
- ast_isampler1darray,
- ast_isampler2darray,
- ast_usampler1d,
- ast_usampler2d,
- ast_usampler3d,
- ast_usamplercube,
- ast_usampler1darray,
- ast_usampler2darray,
-
- ast_struct,
- ast_type_name
-};
-
class ast_type_specifier : public ast_node {
public:
- ast_type_specifier(int specifier);
-
/** Construct a type specifier from a type name */
ast_type_specifier(const char *name)
- : type_specifier(ast_type_name), type_name(name), structure(NULL),
+ : type_name(name), structure(NULL),
is_array(false), array_size(NULL), precision(ast_precision_none),
is_precision_statement(false)
{
@@ -492,7 +432,7 @@ public:
/** Construct a type specifier from a structure definition */
ast_type_specifier(ast_struct_specifier *s)
- : type_specifier(ast_struct), type_name(s->name), structure(s),
+ : type_name(s->name), structure(s),
is_array(false), array_size(NULL), precision(ast_precision_none),
is_precision_statement(false)
{
@@ -507,8 +447,6 @@ public:
ir_rvalue *hir(exec_list *, struct _mesa_glsl_parse_state *);
- enum ast_types type_specifier;
-
const char *type_name;
ast_struct_specifier *structure;
@@ -568,7 +506,7 @@ public:
struct _mesa_glsl_parse_state *state);
ast_fully_specified_type *type;
- char *identifier;
+ const char *identifier;
int is_array;
ast_expression *array_size;
@@ -599,7 +537,7 @@ public:
struct _mesa_glsl_parse_state *state);
ast_fully_specified_type *return_type;
- char *identifier;
+ const char *identifier;
exec_list parameters;
diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp
index 1c2e8613c..39401017b 100644
--- a/mesalib/src/glsl/ast_function.cpp
+++ b/mesalib/src/glsl/ast_function.cpp
@@ -83,7 +83,7 @@ prototype_string(const glsl_type *return_type, const char *name,
const char *comma = "";
foreach_list(node, parameters) {
- const ir_instruction *const param = (ir_instruction *) node;
+ const ir_variable *const param = (ir_variable *) node;
ralloc_asprintf_append(&str, "%s%s", comma, param->type->name);
comma = ", ";
@@ -94,76 +94,116 @@ prototype_string(const glsl_type *return_type, const char *name,
}
/**
- * If a function call is generated, \c call_ir will point to it on exit.
- * Otherwise \c call_ir will be set to \c NULL.
+ * Verify that 'out' and 'inout' actual parameters are lvalues. Also, verify
+ * that 'const_in' formal parameters (an extension in our IR) correspond to
+ * ir_constant actual parameters.
*/
-static ir_rvalue *
-generate_call(exec_list *instructions, ir_function_signature *sig,
- YYLTYPE *loc, exec_list *actual_parameters,
- ir_call **call_ir,
- struct _mesa_glsl_parse_state *state)
+static bool
+verify_parameter_modes(_mesa_glsl_parse_state *state,
+ ir_function_signature *sig,
+ exec_list &actual_ir_parameters,
+ exec_list &actual_ast_parameters)
{
- void *ctx = state;
- exec_list post_call_conversions;
+ exec_node *actual_ir_node = actual_ir_parameters.head;
+ exec_node *actual_ast_node = actual_ast_parameters.head;
- *call_ir = NULL;
+ foreach_list(formal_node, &sig->parameters) {
+ /* The lists must be the same length. */
+ assert(!actual_ir_node->is_tail_sentinel());
+ assert(!actual_ast_node->is_tail_sentinel());
- /* Verify that 'out' and 'inout' actual parameters are lvalues. This
- * isn't done in ir_function::matching_signature because that function
- * cannot generate the necessary diagnostics.
- *
- * Also, validate that 'const_in' formal parameters (an extension of our
- * IR) correspond to ir_constant actual parameters.
- *
- * Also, perform implicit conversion of arguments. Note: to implicitly
- * convert out parameters, we need to place them in a temporary
- * variable, and do the conversion after the call takes place. Since we
- * haven't emitted the call yet, we'll place the post-call conversions
- * in a temporary exec_list, and emit them later.
- */
- exec_list_iterator actual_iter = actual_parameters->iterator();
- exec_list_iterator formal_iter = sig->parameters.iterator();
-
- while (actual_iter.has_next()) {
- ir_rvalue *actual = (ir_rvalue *) actual_iter.get();
- ir_variable *formal = (ir_variable *) formal_iter.get();
+ const ir_variable *const formal = (ir_variable *) formal_node;
+ const ir_rvalue *const actual = (ir_rvalue *) actual_ir_node;
+ const ast_expression *const actual_ast =
+ exec_node_data(ast_expression, actual_ast_node, link);
- assert(actual != NULL);
- assert(formal != NULL);
+ /* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always
+ * FIXME: 0:0(0).
+ */
+ YYLTYPE loc = actual_ast->get_location();
- if (formal->mode == ir_var_const_in && !actual->as_constant()) {
- _mesa_glsl_error(loc, state,
- "parameter `%s' must be a constant expression",
+ /* Verify that 'const_in' parameters are ir_constants. */
+ if (formal->mode == ir_var_const_in &&
+ actual->ir_type != ir_type_constant) {
+ _mesa_glsl_error(&loc, state,
+ "parameter `in %s' must be a constant expression",
formal->name);
- return ir_call::get_error_instruction(ctx);
+ return false;
}
- if ((formal->mode == ir_var_out)
- || (formal->mode == ir_var_inout)) {
+ /* Verify that 'out' and 'inout' actual parameters are lvalues. */
+ if (formal->mode == ir_var_out || formal->mode == ir_var_inout) {
const char *mode = NULL;
switch (formal->mode) {
case ir_var_out: mode = "out"; break;
case ir_var_inout: mode = "inout"; break;
default: assert(false); break;
}
- /* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always
- * FIXME: 0:0(0).
+
+ /* This AST-based check catches errors like f(i++). The IR-based
+ * is_lvalue() is insufficient because the actual parameter at the
+ * IR-level is just a temporary value, which is an l-value.
*/
+ if (actual_ast->non_lvalue_description != NULL) {
+ _mesa_glsl_error(&loc, state,
+ "function parameter '%s %s' references a %s",
+ mode, formal->name,
+ actual_ast->non_lvalue_description);
+ return false;
+ }
+
if (actual->variable_referenced()
&& actual->variable_referenced()->read_only) {
- _mesa_glsl_error(loc, state,
+ _mesa_glsl_error(&loc, state,
"function parameter '%s %s' references the "
"read-only variable '%s'",
mode, formal->name,
actual->variable_referenced()->name);
-
+ return false;
} else if (!actual->is_lvalue()) {
- _mesa_glsl_error(loc, state,
+ _mesa_glsl_error(&loc, state,
"function parameter '%s %s' is not an lvalue",
mode, formal->name);
+ return false;
}
}
+ actual_ir_node = actual_ir_node->next;
+ actual_ast_node = actual_ast_node->next;
+ }
+ return true;
+}
+
+/**
+ * If a function call is generated, \c call_ir will point to it on exit.
+ * Otherwise \c call_ir will be set to \c NULL.
+ */
+static ir_rvalue *
+generate_call(exec_list *instructions, ir_function_signature *sig,
+ YYLTYPE *loc, exec_list *actual_parameters,
+ ir_call **call_ir,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ exec_list post_call_conversions;
+
+ *call_ir = NULL;
+
+ /* Perform implicit conversion of arguments. For out parameters, we need
+ * to place them in a temporary variable and do the conversion after the
+ * call takes place. Since we haven't emitted the call yet, we'll place
+ * the post-call conversions in a temporary exec_list, and emit them later.
+ */
+ exec_list_iterator actual_iter = actual_parameters->iterator();
+ exec_list_iterator formal_iter = sig->parameters.iterator();
+
+ while (actual_iter.has_next()) {
+ ir_rvalue *actual = (ir_rvalue *) actual_iter.get();
+ ir_variable *formal = (ir_variable *) formal_iter.get();
+
+ assert(actual != NULL);
+ assert(formal != NULL);
+
if (formal->type->is_numeric() || formal->type->is_boolean()) {
switch (formal->mode) {
case ir_var_const_in:
@@ -229,29 +269,21 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
formal_iter.next();
}
- /* Always insert the call in the instruction stream, and return a deref
- * of its return val if it returns a value, since we don't know if
- * the rvalue is going to be assigned to anything or not.
+ /* If the function call is a constant expression, don't generate any
+ * instructions; just generate an ir_constant.
*
- * Also insert any out parameter conversions after the call.
+ * Function calls were first allowed to be constant expressions in GLSL 1.20.
*/
- ir_call *call = new(ctx) ir_call(sig, actual_parameters);
- ir_dereference_variable *deref;
- if (!sig->return_type->is_void()) {
- /* If the function call is a constant expression, don't
- * generate the instructions to call it; just generate an
- * ir_constant representing the constant value.
- *
- * Function calls can only be constant expressions starting
- * in GLSL 1.20.
- */
- if (state->language_version >= 120) {
- ir_constant *const_val = call->constant_expression_value();
- if (const_val) {
- return const_val;
- }
+ if (state->language_version >= 120) {
+ ir_constant *value = sig->constant_expression_value(actual_parameters);
+ if (value != NULL) {
+ return value;
}
+ }
+ ir_dereference_variable *deref = NULL;
+ if (!sig->return_type->is_void()) {
+ /* Create a new temporary to hold the return value. */
ir_variable *var;
var = new(ctx) ir_variable(sig->return_type,
@@ -261,24 +293,22 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
instructions->push_tail(var);
deref = new(ctx) ir_dereference_variable(var);
- ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL);
- instructions->push_tail(assign);
- *call_ir = call;
-
- deref = new(ctx) ir_dereference_variable(var);
- } else {
- instructions->push_tail(call);
- *call_ir = call;
- deref = NULL;
}
+ ir_call *call = new(ctx) ir_call(sig, deref, actual_parameters);
+ instructions->push_tail(call);
+
+ /* Also emit any necessary out-parameter conversions. */
instructions->append_list(&post_call_conversions);
- return deref;
+
+ return deref ? deref->clone(ctx, NULL) : NULL;
}
-static ir_rvalue *
-match_function_by_name(exec_list *instructions, const char *name,
- YYLTYPE *loc, exec_list *actual_parameters,
- ir_call **call_ir,
+/**
+ * Given a function name and parameter list, find the matching signature.
+ */
+static ir_function_signature *
+match_function_by_name(const char *name,
+ exec_list *actual_parameters,
struct _mesa_glsl_parse_state *state)
{
void *ctx = state;
@@ -350,43 +380,45 @@ done:
}
f->add_signature(sig->clone_prototype(f, NULL));
}
+ }
+ return sig;
+}
- /* Finally, generate a call instruction. */
- return generate_call(instructions, sig, loc, actual_parameters,
- call_ir, state);
- } else {
- char *str = prototype_string(NULL, name, actual_parameters);
-
- _mesa_glsl_error(loc, state, "no matching function for call to `%s'",
- str);
- ralloc_free(str);
-
- const char *prefix = "candidates are: ";
+/**
+ * Raise a "no matching function" error, listing all possible overloads the
+ * compiler considered so developers can figure out what went wrong.
+ */
+static void
+no_matching_function_error(const char *name,
+ YYLTYPE *loc,
+ exec_list *actual_parameters,
+ _mesa_glsl_parse_state *state)
+{
+ char *str = prototype_string(NULL, name, actual_parameters);
+ _mesa_glsl_error(loc, state, "no matching function for call to `%s'", str);
+ ralloc_free(str);
- for (int i = -1; i < (int) state->num_builtins_to_link; i++) {
- glsl_symbol_table *syms = i >= 0 ? state->builtins_to_link[i]->symbols
- : state->symbols;
- f = syms->get_function(name);
- if (f == NULL)
- continue;
+ const char *prefix = "candidates are: ";
- foreach_list (node, &f->signatures) {
- ir_function_signature *sig = (ir_function_signature *) node;
+ for (int i = -1; i < (int) state->num_builtins_to_link; i++) {
+ glsl_symbol_table *syms = i >= 0 ? state->builtins_to_link[i]->symbols
+ : state->symbols;
+ ir_function *f = syms->get_function(name);
+ if (f == NULL)
+ continue;
- str = prototype_string(sig->return_type, f->name, &sig->parameters);
- _mesa_glsl_error(loc, state, "%s%s", prefix, str);
- ralloc_free(str);
+ foreach_list (node, &f->signatures) {
+ ir_function_signature *sig = (ir_function_signature *) node;
- prefix = " ";
- }
+ str = prototype_string(sig->return_type, f->name, &sig->parameters);
+ _mesa_glsl_error(loc, state, "%s%s", prefix, str);
+ ralloc_free(str);
+ prefix = " ";
}
-
- return ir_call::get_error_instruction(ctx);
}
}
-
/**
* Perform automatic type conversion of constructor parameters
*
@@ -558,7 +590,7 @@ process_array_constructor(exec_list *instructions,
"parameter%s",
(constructor_type->length != 0) ? "at least" : "exactly",
min_param, (min_param <= 1) ? "" : "s");
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
if (constructor_type->length == 0) {
@@ -1195,7 +1227,7 @@ ast_function_expression::hir(exec_list *instructions,
_mesa_glsl_error(& loc, state, "unknown type `%s' (structure name "
"may be shadowed by a variable with the same name)",
type->type_name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
@@ -1204,14 +1236,14 @@ ast_function_expression::hir(exec_list *instructions,
if (constructor_type->is_sampler()) {
_mesa_glsl_error(& loc, state, "cannot construct sampler type `%s'",
constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
if (constructor_type->is_array()) {
if (state->language_version <= 110) {
_mesa_glsl_error(& loc, state,
"array constructors forbidden in GLSL 1.10");
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
return process_array_constructor(instructions, constructor_type,
@@ -1242,7 +1274,7 @@ ast_function_expression::hir(exec_list *instructions,
"insufficient parameters to constructor "
"for `%s'",
constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
if (apply_implicit_conversion(constructor_type->fields.structure[i].type,
@@ -1256,7 +1288,7 @@ ast_function_expression::hir(exec_list *instructions,
constructor_type->fields.structure[i].name,
ir->type->name,
constructor_type->fields.structure[i].type->name);
- return ir_call::get_error_instruction(ctx);;
+ return ir_rvalue::error_value(ctx);;
}
node = node->next;
@@ -1265,7 +1297,7 @@ ast_function_expression::hir(exec_list *instructions,
if (!node->is_tail_sentinel()) {
_mesa_glsl_error(&loc, state, "too many parameters in constructor "
"for `%s'", constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
ir_rvalue *const constant =
@@ -1279,7 +1311,7 @@ ast_function_expression::hir(exec_list *instructions,
}
if (!constructor_type->is_numeric() && !constructor_type->is_boolean())
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
/* Total number of components of the type being constructed. */
const unsigned type_components = constructor_type->components();
@@ -1306,14 +1338,14 @@ ast_function_expression::hir(exec_list *instructions,
_mesa_glsl_error(& loc, state, "too many parameters to `%s' "
"constructor",
constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
if (!result->type->is_numeric() && !result->type->is_boolean()) {
_mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
"non-numeric data type",
constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
/* Count the number of matrix and nonmatrix parameters. This
@@ -1338,7 +1370,7 @@ ast_function_expression::hir(exec_list *instructions,
_mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
"matrix in GLSL 1.10",
constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
/* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
@@ -1352,7 +1384,7 @@ ast_function_expression::hir(exec_list *instructions,
_mesa_glsl_error(& loc, state, "for matrix `%s' constructor, "
"matrix must be only parameter",
constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
/* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
@@ -1366,7 +1398,7 @@ ast_function_expression::hir(exec_list *instructions,
_mesa_glsl_error(& loc, state, "too few components to construct "
"`%s'",
constructor_type->name);
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
/* Later, we cast each parameter to the same base type as the
@@ -1447,60 +1479,31 @@ ast_function_expression::hir(exec_list *instructions,
}
} else {
const ast_expression *id = subexpressions[0];
+ const char *func_name = id->primary_expression.identifier;
YYLTYPE loc = id->get_location();
exec_list actual_parameters;
process_parameters(instructions, &actual_parameters, &this->expressions,
state);
- ir_call *call = NULL;
- ir_rvalue *const value =
- match_function_by_name(instructions,
- id->primary_expression.identifier,
- &loc, &actual_parameters, &call, state);
-
- if (call != NULL) {
- /* If a function was found, make sure that none of the 'out' or 'inout'
- * parameters violate the extra l-value rules.
- */
- ir_function_signature *f = call->get_callee();
- assert(f != NULL);
-
- exec_node *formal_node = f->parameters.head;
+ ir_function_signature *sig =
+ match_function_by_name(func_name, &actual_parameters, state);
- foreach_list (actual_node, &this->expressions) {
- /* Both parameter lists had better be the same length!
- */
- assert(!actual_node->is_tail_sentinel());
-
- const ir_variable *const formal_parameter =
- (ir_variable *) formal_node;
- const ast_expression *const actual_parameter =
- exec_node_data(ast_expression, actual_node, link);
-
- if ((formal_parameter->mode == ir_var_out
- || formal_parameter->mode == ir_var_inout)
- && actual_parameter->non_lvalue_description != NULL) {
- YYLTYPE loc = actual_parameter->get_location();
-
- _mesa_glsl_error(&loc, state,
- "function parameter '%s %s' references a %s",
- (formal_parameter->mode == ir_var_out)
- ? "out" : "inout",
- formal_parameter->name,
- actual_parameter->non_lvalue_description);
- return ir_call::get_error_instruction(ctx);
- }
-
- /* Only advance the formal_node pointer here because the
- * foreach_list business already advances actual_node.
- */
- formal_node = formal_node->next;
- }
+ ir_call *call = NULL;
+ ir_rvalue *value = NULL;
+ if (sig == NULL) {
+ no_matching_function_error(func_name, &loc, &actual_parameters, state);
+ value = ir_rvalue::error_value(ctx);
+ } else if (!verify_parameter_modes(state, sig, actual_parameters, this->expressions)) {
+ /* an error has already been emitted */
+ value = ir_rvalue::error_value(ctx);
+ } else {
+ value = generate_call(instructions, sig, &loc, &actual_parameters,
+ &call, state);
}
return value;
}
- return ir_call::get_error_instruction(ctx);
+ return ir_rvalue::error_value(ctx);
}
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index ff56e33b7..f4dfc4ce3 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -1699,7 +1699,7 @@ ast_expression::hir(exec_list *instructions,
_mesa_glsl_error(& loc, state, "`%s' undeclared",
this->primary_expression.identifier);
- result = ir_call::get_error_instruction(ctx);
+ result = ir_rvalue::error_value(ctx);
error_emitted = true;
}
break;
@@ -3904,8 +3904,8 @@ ast_type_specifier::hir(exec_list *instructions,
"arrays");
return NULL;
}
- if (this->type_specifier != ast_float
- && this->type_specifier != ast_int) {
+ if (strcmp(this->type_name, "float") != 0 &&
+ strcmp(this->type_name, "int") != 0) {
_mesa_glsl_error(&loc, state,
"default precision statements apply only to types "
"float and int");
diff --git a/mesalib/src/glsl/ast_type.cpp b/mesalib/src/glsl/ast_type.cpp
index 79c43eefb..6c44f8c41 100644
--- a/mesalib/src/glsl/ast_type.cpp
+++ b/mesalib/src/glsl/ast_type.cpp
@@ -29,7 +29,7 @@ extern "C" {
void
ast_type_specifier::print(void) const
{
- if (type_specifier == ast_struct) {
+ if (structure) {
structure->print();
} else {
printf("%s ", type_name);
@@ -46,72 +46,6 @@ ast_type_specifier::print(void) const
}
}
-ast_type_specifier::ast_type_specifier(int specifier)
- : type_specifier(ast_types(specifier)), type_name(NULL), structure(NULL),
- is_array(false), array_size(NULL), precision(ast_precision_none),
- is_precision_statement(false)
-{
- static const char *const names[] = {
- "void",
- "float",
- "int",
- "uint",
- "bool",
- "vec2",
- "vec3",
- "vec4",
- "bvec2",
- "bvec3",
- "bvec4",
- "ivec2",
- "ivec3",
- "ivec4",
- "uvec2",
- "uvec3",
- "uvec4",
- "mat2",
- "mat2x3",
- "mat2x4",
- "mat3x2",
- "mat3",
- "mat3x4",
- "mat4x2",
- "mat4x3",
- "mat4",
- "sampler1D",
- "sampler2D",
- "sampler2DRect",
- "sampler3D",
- "samplerCube",
- "samplerExternalOES",
- "sampler1DShadow",
- "sampler2DShadow",
- "sampler2DRectShadow",
- "samplerCubeShadow",
- "sampler1DArray",
- "sampler2DArray",
- "sampler1DArrayShadow",
- "sampler2DArrayShadow",
- "isampler1D",
- "isampler2D",
- "isampler3D",
- "isamplerCube",
- "isampler1DArray",
- "isampler2DArray",
- "usampler1D",
- "usampler2D",
- "usampler3D",
- "usamplerCube",
- "usampler1DArray",
- "usampler2DArray",
-
- NULL, /* ast_struct */
- NULL /* ast_type_name */
- };
-
- type_name = names[specifier];
-}
-
bool
ast_fully_specified_type::has_qualifiers() const
{
diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy
index 64506b635..920213c30 100644
--- a/mesalib/src/glsl/glsl_parser.yy
+++ b/mesalib/src/glsl/glsl_parser.yy
@@ -58,7 +58,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
%union {
int n;
float real;
- char *identifier;
+ const char *identifier;
struct ast_type_qualifier type_qualifier;
@@ -156,7 +156,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
%type <type_specifier> type_specifier
%type <type_specifier> type_specifier_no_prec
%type <type_specifier> type_specifier_nonarray
-%type <n> basic_type_specifier_nonarray
+%type <identifier> basic_type_specifier_nonarray
%type <fully_specified_type> fully_specified_type
%type <function> function_prototype
%type <function> function_header
@@ -1365,58 +1365,59 @@ type_specifier_nonarray:
;
basic_type_specifier_nonarray:
- VOID_TOK { $$ = ast_void; }
- | FLOAT_TOK { $$ = ast_float; }
- | INT_TOK { $$ = ast_int; }
- | UINT_TOK { $$ = ast_uint; }
- | BOOL_TOK { $$ = ast_bool; }
- | VEC2 { $$ = ast_vec2; }
- | VEC3 { $$ = ast_vec3; }
- | VEC4 { $$ = ast_vec4; }
- | BVEC2 { $$ = ast_bvec2; }
- | BVEC3 { $$ = ast_bvec3; }
- | BVEC4 { $$ = ast_bvec4; }
- | IVEC2 { $$ = ast_ivec2; }
- | IVEC3 { $$ = ast_ivec3; }
- | IVEC4 { $$ = ast_ivec4; }
- | UVEC2 { $$ = ast_uvec2; }
- | UVEC3 { $$ = ast_uvec3; }
- | UVEC4 { $$ = ast_uvec4; }
- | MAT2X2 { $$ = ast_mat2; }
- | MAT2X3 { $$ = ast_mat2x3; }
- | MAT2X4 { $$ = ast_mat2x4; }
- | MAT3X2 { $$ = ast_mat3x2; }
- | MAT3X3 { $$ = ast_mat3; }
- | MAT3X4 { $$ = ast_mat3x4; }
- | MAT4X2 { $$ = ast_mat4x2; }
- | MAT4X3 { $$ = ast_mat4x3; }
- | MAT4X4 { $$ = ast_mat4; }
- | SAMPLER1D { $$ = ast_sampler1d; }
- | SAMPLER2D { $$ = ast_sampler2d; }
- | SAMPLER2DRECT { $$ = ast_sampler2drect; }
- | SAMPLER3D { $$ = ast_sampler3d; }
- | SAMPLERCUBE { $$ = ast_samplercube; }
- | SAMPLEREXTERNALOES { $$ = ast_samplerexternaloes; }
- | SAMPLER1DSHADOW { $$ = ast_sampler1dshadow; }
- | SAMPLER2DSHADOW { $$ = ast_sampler2dshadow; }
- | SAMPLER2DRECTSHADOW { $$ = ast_sampler2drectshadow; }
- | SAMPLERCUBESHADOW { $$ = ast_samplercubeshadow; }
- | SAMPLER1DARRAY { $$ = ast_sampler1darray; }
- | SAMPLER2DARRAY { $$ = ast_sampler2darray; }
- | SAMPLER1DARRAYSHADOW { $$ = ast_sampler1darrayshadow; }
- | SAMPLER2DARRAYSHADOW { $$ = ast_sampler2darrayshadow; }
- | ISAMPLER1D { $$ = ast_isampler1d; }
- | ISAMPLER2D { $$ = ast_isampler2d; }
- | ISAMPLER3D { $$ = ast_isampler3d; }
- | ISAMPLERCUBE { $$ = ast_isamplercube; }
- | ISAMPLER1DARRAY { $$ = ast_isampler1darray; }
- | ISAMPLER2DARRAY { $$ = ast_isampler2darray; }
- | USAMPLER1D { $$ = ast_usampler1d; }
- | USAMPLER2D { $$ = ast_usampler2d; }
- | USAMPLER3D { $$ = ast_usampler3d; }
- | USAMPLERCUBE { $$ = ast_usamplercube; }
- | USAMPLER1DARRAY { $$ = ast_usampler1darray; }
- | USAMPLER2DARRAY { $$ = ast_usampler2darray; }
+ VOID_TOK { $$ = "void"; }
+ | FLOAT_TOK { $$ = "float"; }
+ | INT_TOK { $$ = "int"; }
+ | UINT_TOK { $$ = "uint"; }
+ | BOOL_TOK { $$ = "bool"; }
+ | VEC2 { $$ = "vec2"; }
+ | VEC3 { $$ = "vec3"; }
+ | VEC4 { $$ = "vec4"; }
+ | BVEC2 { $$ = "bvec2"; }
+ | BVEC3 { $$ = "bvec3"; }
+ | BVEC4 { $$ = "bvec4"; }
+ | IVEC2 { $$ = "ivec2"; }
+ | IVEC3 { $$ = "ivec3"; }
+ | IVEC4 { $$ = "ivec4"; }
+ | UVEC2 { $$ = "uvec2"; }
+ | UVEC3 { $$ = "uvec3"; }
+ | UVEC4 { $$ = "uvec4"; }
+ | MAT2X2 { $$ = "mat2"; }
+ | MAT2X3 { $$ = "mat2x3"; }
+ | MAT2X4 { $$ = "mat2x4"; }
+ | MAT3X2 { $$ = "mat3x2"; }
+ | MAT3X3 { $$ = "mat3"; }
+ | MAT3X4 { $$ = "mat3x4"; }
+ | MAT4X2 { $$ = "mat4x2"; }
+ | MAT4X3 { $$ = "mat4x3"; }
+ | MAT4X4 { $$ = "mat4"; }
+ | SAMPLER1D { $$ = "sampler1D"; }
+ | SAMPLER2D { $$ = "sampler2D"; }
+ | SAMPLER2DRECT { $$ = "sampler2DRect"; }
+ | SAMPLER3D { $$ = "sampler3D"; }
+ | SAMPLERCUBE { $$ = "samplerCube"; }
+ | SAMPLEREXTERNALOES { $$ = "samplerExternalOES"; }
+ | SAMPLER1DSHADOW { $$ = "sampler1DShadow"; }
+ | SAMPLER2DSHADOW { $$ = "sampler2DShadow"; }
+ | SAMPLER2DRECTSHADOW { $$ = "sampler2DRectShadow"; }
+ | SAMPLERCUBESHADOW { $$ = "samplerCubeShadow"; }
+ | SAMPLER1DARRAY { $$ = "sampler1DArray"; }
+ | SAMPLER2DARRAY { $$ = "sampler2DArray"; }
+ | SAMPLER1DARRAYSHADOW { $$ = "sampler1DArrayShadow"; }
+ | SAMPLER2DARRAYSHADOW { $$ = "sampler2DArrayShadow"; }
+ | SAMPLERBUFFER { $$ = "samplerBuffer"; }
+ | ISAMPLER1D { $$ = "isampler1D"; }
+ | ISAMPLER2D { $$ = "isampler2D"; }
+ | ISAMPLER3D { $$ = "isampler3D"; }
+ | ISAMPLERCUBE { $$ = "isamplerCube"; }
+ | ISAMPLER1DARRAY { $$ = "isampler1DArray"; }
+ | ISAMPLER2DARRAY { $$ = "isampler2DArray"; }
+ | USAMPLER1D { $$ = "usampler1D"; }
+ | USAMPLER2D { $$ = "usampler2D"; }
+ | USAMPLER3D { $$ = "usampler3D"; }
+ | USAMPLERCUBE { $$ = "usamplerCube"; }
+ | USAMPLER1DARRAY { $$ = "usampler1DArray"; }
+ | USAMPLER2DARRAY { $$ = "usampler2DArray"; }
;
precision_qualifier:
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index 21c3c6ec2..6547ad2d3 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -713,7 +713,7 @@ ast_declaration::print(void) const
}
-ast_declaration::ast_declaration(char *identifier, int is_array,
+ast_declaration::ast_declaration(const char *identifier, int is_array,
ast_expression *array_size,
ast_expression *initializer)
{
@@ -979,7 +979,7 @@ ast_struct_specifier::print(void) const
}
-ast_struct_specifier::ast_struct_specifier(char *identifier,
+ast_struct_specifier::ast_struct_specifier(const char *identifier,
ast_node *declarator_list)
{
if (identifier == NULL) {
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp
index 069ebd10d..8a34b8eb0 100644
--- a/mesalib/src/glsl/glsl_types.cpp
+++ b/mesalib/src/glsl/glsl_types.cpp
@@ -146,7 +146,6 @@ glsl_type::sampler_index() const
case GLSL_SAMPLER_DIM_RECT:
return TEXTURE_RECT_INDEX;
case GLSL_SAMPLER_DIM_BUF:
- assert(!"FINISHME: Implement ARB_texture_buffer_object");
return TEXTURE_BUFFER_INDEX;
case GLSL_SAMPLER_DIM_EXTERNAL:
return TEXTURE_EXTERNAL_INDEX;
@@ -213,6 +212,10 @@ glsl_type::generate_140_types(glsl_symbol_table *symtab)
add_types_to_symbol_table(symtab, builtin_140_types,
Elements(builtin_140_types), false);
+
+ add_types_to_symbol_table(symtab, builtin_EXT_texture_buffer_object_types,
+ Elements(builtin_EXT_texture_buffer_object_types),
+ false);
}
diff --git a/mesalib/src/glsl/hir_field_selection.cpp b/mesalib/src/glsl/hir_field_selection.cpp
index 3c33127b5..260b415a8 100644
--- a/mesalib/src/glsl/hir_field_selection.cpp
+++ b/mesalib/src/glsl/hir_field_selection.cpp
@@ -98,5 +98,5 @@ _mesa_ast_field_selection_to_hir(const ast_expression *expr,
expr->primary_expression.identifier);
}
- return result ? result : ir_call::get_error_instruction(ctx);
+ return result ? result : ir_rvalue::error_value(ctx);
}
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index 3c9d6e174..1ba87515e 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -1458,22 +1458,15 @@ ir_function::has_user_signature()
}
-ir_call *
-ir_call::get_error_instruction(void *ctx)
+ir_rvalue *
+ir_rvalue::error_value(void *mem_ctx)
{
- ir_call *call = new(ctx) ir_call;
+ ir_rvalue *v = new(mem_ctx) ir_rvalue;
- call->type = glsl_type::error_type;
- return call;
+ v->type = glsl_type::error_type;
+ return v;
}
-void
-ir_call::set_callee(ir_function_signature *sig)
-{
- assert((this->type == NULL) || (this->type == sig->return_type));
-
- this->callee = sig;
-}
void
visit_exec_list(exec_list *list, ir_visitor *visitor)
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h
index 1faae3c72..b1ae6db74 100644
--- a/mesalib/src/glsl/ir.h
+++ b/mesalib/src/glsl/ir.h
@@ -88,7 +88,6 @@ enum ir_node_type {
class ir_instruction : public exec_node {
public:
enum ir_node_type ir_type;
- const struct glsl_type *type;
/** ir_print_visitor helper for debugging. */
void print(void) const;
@@ -127,16 +126,27 @@ protected:
ir_instruction()
{
ir_type = ir_type_unset;
- type = NULL;
}
};
+/**
+ * The base class for all "values"/expression trees.
+ */
class ir_rvalue : public ir_instruction {
public:
- virtual ir_rvalue *clone(void *mem_ctx, struct hash_table *) const = 0;
+ const struct glsl_type *type;
+
+ virtual ir_rvalue *clone(void *mem_ctx, struct hash_table *) const;
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
- virtual ir_constant *constant_expression_value() = 0;
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ virtual ir_constant *constant_expression_value();
virtual ir_rvalue * as_rvalue()
{
@@ -209,6 +219,14 @@ public:
*/
virtual bool is_negative_one() const;
+
+ /**
+ * Return a generic value of error_type.
+ *
+ * Allocation will be performed with 'mem_ctx' as ralloc owner.
+ */
+ static ir_rvalue *error_value(void *mem_ctx);
+
protected:
ir_rvalue();
};
@@ -303,6 +321,11 @@ public:
glsl_interp_qualifier determine_interpolation_mode(bool flat_shade);
/**
+ * Declared type of the variable
+ */
+ const struct glsl_type *type;
+
+ /**
* Delcared name of the variable
*/
const char *name;
@@ -460,6 +483,12 @@ public:
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
/**
+ * Attempt to evaluate this function as a constant expression, given
+ * a list of the actual parameters. Returns NULL for non-built-ins.
+ */
+ ir_constant *constant_expression_value(exec_list *actual_parameters);
+
+ /**
* Get the name of the function for which this is a signature
*/
const char *function_name() const;
@@ -999,16 +1028,18 @@ public:
/**
- * IR instruction representing a function call
+ * HIR instruction representing a high-level function call, containing a list
+ * of parameters and returning a value in the supplied temporary.
*/
-class ir_call : public ir_rvalue {
+class ir_call : public ir_instruction {
public:
- ir_call(ir_function_signature *callee, exec_list *actual_parameters)
- : callee(callee)
+ ir_call(ir_function_signature *callee,
+ ir_dereference_variable *return_deref,
+ exec_list *actual_parameters)
+ : return_deref(return_deref), callee(callee)
{
ir_type = ir_type_call;
assert(callee->return_type != NULL);
- type = callee->return_type;
actual_parameters->move_nodes_to(& this->actual_parameters);
this->use_builtin = callee->is_builtin;
}
@@ -1030,13 +1061,6 @@ public:
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
/**
- * Get a generic ir_call object when an error occurs
- *
- * Any allocation will be performed with 'ctx' as ralloc owner.
- */
- static ir_call *get_error_instruction(void *ctx);
-
- /**
* Get an iterator for the set of acutal parameters
*/
exec_list_iterator iterator()
@@ -1053,38 +1077,27 @@ public:
}
/**
- * Get the function signature bound to this function call
+ * Generates an inline version of the function before @ir,
+ * storing the return value in return_deref.
*/
- ir_function_signature *get_callee()
- {
- return callee;
- }
+ void generate_inline(ir_instruction *ir);
/**
- * Set the function call target
+ * Storage for the function's return value.
+ * This must be NULL if the return type is void.
*/
- void set_callee(ir_function_signature *sig);
+ ir_dereference_variable *return_deref;
/**
- * Generates an inline version of the function before @ir,
- * returning the return value of the function.
+ * The specific function signature being called.
*/
- ir_rvalue *generate_inline(ir_instruction *ir);
+ ir_function_signature *callee;
/* List of ir_rvalue of paramaters passed in this call. */
exec_list actual_parameters;
/** Should this call only bind to a built-in function? */
bool use_builtin;
-
-private:
- ir_call()
- : callee(NULL)
- {
- this->ir_type = ir_type_call;
- }
-
- ir_function_signature *callee;
};
diff --git a/mesalib/src/glsl/ir_basic_block.cpp b/mesalib/src/glsl/ir_basic_block.cpp
index a83382596..86e0cf795 100644
--- a/mesalib/src/glsl/ir_basic_block.cpp
+++ b/mesalib/src/glsl/ir_basic_block.cpp
@@ -32,31 +32,6 @@
#include "ir_basic_block.h"
#include "glsl_types.h"
-class ir_has_call_visitor : public ir_hierarchical_visitor {
-public:
- ir_has_call_visitor()
- {
- has_call = false;
- }
-
- virtual ir_visitor_status visit_enter(ir_call *ir)
- {
- (void) ir;
- has_call = true;
- return visit_stop;
- }
-
- bool has_call;
-};
-
-bool
-ir_has_call(ir_instruction *ir)
-{
- ir_has_call_visitor v;
- ir->accept(&v);
- return v.has_call;
-}
-
/**
* Calls a user function for every basic block in the instruction stream.
*
@@ -122,24 +97,6 @@ void call_for_basic_blocks(exec_list *instructions,
call_for_basic_blocks(&ir_sig->body, callback, data);
}
- } else if (ir->as_assignment()) {
- /* If there's a call in the expression tree being assigned,
- * then that ends the BB too.
- *
- * The assumption is that any consumer of the basic block
- * walker is fine with the fact that the call is somewhere in
- * the tree even if portions of the tree may be evaluated
- * after the call.
- *
- * A consumer that has an issue with this could not process
- * the last instruction of the basic block. If doing so,
- * expression flattener may be useful before using the basic
- * block finder to get more maximal basic blocks out.
- */
- if (ir_has_call(ir)) {
- callback(leader, ir, data);
- leader = NULL;
- }
}
last = ir;
}
diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp
index c63615c7e..26b0d8f5f 100644
--- a/mesalib/src/glsl/ir_clone.cpp
+++ b/mesalib/src/glsl/ir_clone.cpp
@@ -27,6 +27,13 @@
#include "glsl_types.h"
#include "program/hash_table.h"
+ir_rvalue *
+ir_rvalue::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ /* The only possible instantiation is the generic error value. */
+ return error_value(mem_ctx);
+}
+
/**
* Duplicate an IR variable
*
@@ -160,8 +167,9 @@ ir_loop::clone(void *mem_ctx, struct hash_table *ht) const
ir_call *
ir_call::clone(void *mem_ctx, struct hash_table *ht) const
{
- if (this->type == glsl_type::error_type)
- return ir_call::get_error_instruction(mem_ctx);
+ ir_dereference_variable *new_return_ref = NULL;
+ if (this->return_deref != NULL)
+ new_return_ref = this->return_deref->clone(mem_ctx, ht);
exec_list new_parameters;
@@ -170,7 +178,7 @@ ir_call::clone(void *mem_ctx, struct hash_table *ht) const
new_parameters.push_tail(ir->clone(mem_ctx, ht));
}
- return new(mem_ctx) ir_call(this->callee, &new_parameters);
+ return new(mem_ctx) ir_call(this->callee, new_return_ref, &new_parameters);
}
ir_expression *
@@ -390,9 +398,9 @@ public:
* table. If it is found, replace it with the value from the table.
*/
ir_function_signature *sig =
- (ir_function_signature *) hash_table_find(this->ht, ir->get_callee());
+ (ir_function_signature *) hash_table_find(this->ht, ir->callee);
if (sig != NULL)
- ir->set_callee(sig);
+ ir->callee = sig;
/* Since this may be used before function call parameters are flattened,
* the children also need to be processed.
diff --git a/mesalib/src/glsl/ir_constant_expression.cpp b/mesalib/src/glsl/ir_constant_expression.cpp
index adca62e8d..4e1714a84 100644
--- a/mesalib/src/glsl/ir_constant_expression.cpp
+++ b/mesalib/src/glsl/ir_constant_expression.cpp
@@ -71,6 +71,13 @@ dot(ir_constant *op0, ir_constant *op1)
}
ir_constant *
+ir_rvalue::constant_expression_value()
+{
+ assert(this->type->is_error());
+ return NULL;
+}
+
+ir_constant *
ir_expression::constant_expression_value()
{
if (this->type->is_error())
@@ -1017,21 +1024,29 @@ ir_constant::constant_expression_value()
ir_constant *
ir_call::constant_expression_value()
{
- if (this->type == glsl_type::error_type)
+ return this->callee->constant_expression_value(&this->actual_parameters);
+}
+
+
+ir_constant *
+ir_function_signature::constant_expression_value(exec_list *actual_parameters)
+{
+ const glsl_type *type = this->return_type;
+ if (type == glsl_type::void_type)
return NULL;
/* From the GLSL 1.20 spec, page 23:
* "Function calls to user-defined functions (non-built-in functions)
* cannot be used to form constant expressions."
*/
- if (!this->callee->is_builtin)
+ if (!this->is_builtin)
return NULL;
unsigned num_parameters = 0;
/* Check if all parameters are constant */
ir_constant *op[3];
- foreach_list(n, &this->actual_parameters) {
+ foreach_list(n, actual_parameters) {
ir_constant *constant = ((ir_rvalue *) n)->constant_expression_value();
if (constant == NULL)
return NULL;
@@ -1053,7 +1068,7 @@ ir_call::constant_expression_value()
ir_constant_data data;
memset(&data, 0, sizeof(data));
- const char *callee = this->callee_name();
+ const char *callee = this->function_name();
if (strcmp(callee, "abs") == 0) {
expr = new(mem_ctx) ir_expression(ir_unop_abs, type, op[0], NULL);
} else if (strcmp(callee, "all") == 0) {
@@ -1101,7 +1116,7 @@ ir_call::constant_expression_value()
for (unsigned c = 0; c < op[0]->type->components(); c++)
data.f[c] = atanhf(op[0]->value.f[c]);
} else if (strcmp(callee, "dFdx") == 0 || strcmp(callee, "dFdy") == 0) {
- return ir_constant::zero(mem_ctx, this->type);
+ return ir_constant::zero(mem_ctx, type);
} else if (strcmp(callee, "ceil") == 0) {
expr = new(mem_ctx) ir_expression(ir_unop_ceil, type, op[0], NULL);
} else if (strcmp(callee, "clamp") == 0) {
@@ -1192,7 +1207,7 @@ ir_call::constant_expression_value()
} else if (strcmp(callee, "fract") == 0) {
expr = new(mem_ctx) ir_expression(ir_unop_fract, type, op[0], NULL);
} else if (strcmp(callee, "fwidth") == 0) {
- return ir_constant::zero(mem_ctx, this->type);
+ return ir_constant::zero(mem_ctx, type);
} else if (strcmp(callee, "greaterThan") == 0) {
assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
for (unsigned c = 0; c < op[0]->type->components(); c++) {
@@ -1298,7 +1313,7 @@ ir_call::constant_expression_value()
float length = sqrtf(dot(op[0], op[0]));
if (length == 0)
- return ir_constant::zero(mem_ctx, this->type);
+ return ir_constant::zero(mem_ctx, type);
for (unsigned c = 0; c < op[0]->type->components(); c++)
data.f[c] = op[0]->value.f[c] / length;
@@ -1349,7 +1364,7 @@ ir_call::constant_expression_value()
const float dot_NI = dot(op[1], op[0]);
const float k = 1.0F - eta * eta * (1.0F - dot_NI * dot_NI);
if (k < 0.0) {
- return ir_constant::zero(mem_ctx, this->type);
+ return ir_constant::zero(mem_ctx, type);
} else {
for (unsigned c = 0; c < type->components(); c++) {
data.f[c] = eta * op[0]->value.f[c] - (eta * dot_NI + sqrtf(k))
@@ -1418,5 +1433,5 @@ ir_call::constant_expression_value()
if (expr != NULL)
return expr->constant_expression_value();
- return new(mem_ctx) ir_constant(this->type, &data);
+ return new(mem_ctx) ir_constant(type, &data);
}
diff --git a/mesalib/src/glsl/ir_expression_flattening.cpp b/mesalib/src/glsl/ir_expression_flattening.cpp
index bd4ac67bc..b44e68ca3 100644
--- a/mesalib/src/glsl/ir_expression_flattening.cpp
+++ b/mesalib/src/glsl/ir_expression_flattening.cpp
@@ -29,11 +29,6 @@
*
* This is used for breaking down matrix operations, where it's easier to
* create a temporary and work on each of its vector components individually.
- *
- * It is also used for automatic function inlining, where we want to take
- * an expression containing a call and move the call out to its own
- * assignment so that we can inline it at the appropriate place in the
- * instruction stream.
*/
#include "ir.h"
diff --git a/mesalib/src/glsl/ir_function.cpp b/mesalib/src/glsl/ir_function.cpp
index b34a50081..a525693ed 100644
--- a/mesalib/src/glsl/ir_function.cpp
+++ b/mesalib/src/glsl/ir_function.cpp
@@ -59,7 +59,7 @@ parameter_lists_match(const exec_list *list_a, const exec_list *list_b)
const ir_variable *const param = (ir_variable *) node_a;
- const ir_instruction *const actual = (ir_instruction *) node_b;
+ const ir_rvalue *const actual = (ir_rvalue *) node_b;
if (param->type == actual->type)
continue;
diff --git a/mesalib/src/glsl/ir_function_can_inline.cpp b/mesalib/src/glsl/ir_function_can_inline.cpp
index 2ed3aaa49..7b15d5df1 100644
--- a/mesalib/src/glsl/ir_function_can_inline.cpp
+++ b/mesalib/src/glsl/ir_function_can_inline.cpp
@@ -1,76 +1,76 @@
-/*
- * Copyright © 2010 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_can_inline.cpp
- *
- * Determines if we can inline a function call using ir_function_inlining.cpp.
- *
- * The primary restriction is that we can't return from the function
- * other than as the last instruction. We could potentially work
- * around this for some constructs by flattening control flow and
- * moving the return to the end, or by using breaks from a do {} while
- * (0) loop surrounding the function body.
- */
-
-#include "ir.h"
-
-class ir_function_can_inline_visitor : public ir_hierarchical_visitor {
-public:
- ir_function_can_inline_visitor()
- {
- this->num_returns = 0;
- }
-
- virtual ir_visitor_status visit_enter(ir_return *);
-
- int num_returns;
-};
-
-ir_visitor_status
-ir_function_can_inline_visitor::visit_enter(ir_return *ir)
-{
- (void) ir;
- this->num_returns++;
- return visit_continue;
-}
-
-bool
-can_inline(ir_call *call)
-{
- ir_function_can_inline_visitor v;
- const ir_function_signature *callee = call->get_callee();
- if (!callee->is_defined)
- return false;
-
- v.run((exec_list *) &callee->body);
-
- /* If the function is empty (no last instruction) or does not end with a
- * return statement, we need to count the implicit return.
- */
- ir_instruction *last = (ir_instruction *)callee->body.get_tail();
- if (last == NULL || !last->as_return())
- v.num_returns++;
-
- return v.num_returns == 1;
-}
+/*
+ * Copyright © 2010 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_can_inline.cpp
+ *
+ * Determines if we can inline a function call using ir_function_inlining.cpp.
+ *
+ * The primary restriction is that we can't return from the function
+ * other than as the last instruction. We could potentially work
+ * around this for some constructs by flattening control flow and
+ * moving the return to the end, or by using breaks from a do {} while
+ * (0) loop surrounding the function body.
+ */
+
+#include "ir.h"
+
+class ir_function_can_inline_visitor : public ir_hierarchical_visitor {
+public:
+ ir_function_can_inline_visitor()
+ {
+ this->num_returns = 0;
+ }
+
+ virtual ir_visitor_status visit_enter(ir_return *);
+
+ int num_returns;
+};
+
+ir_visitor_status
+ir_function_can_inline_visitor::visit_enter(ir_return *ir)
+{
+ (void) ir;
+ this->num_returns++;
+ return visit_continue;
+}
+
+bool
+can_inline(ir_call *call)
+{
+ ir_function_can_inline_visitor v;
+ const ir_function_signature *callee = call->callee;
+ if (!callee->is_defined)
+ return false;
+
+ v.run((exec_list *) &callee->body);
+
+ /* If the function is empty (no last instruction) or does not end with a
+ * return statement, we need to count the implicit return.
+ */
+ ir_instruction *last = (ir_instruction *)callee->body.get_tail();
+ if (last == NULL || !last->as_return())
+ v.num_returns++;
+
+ return v.num_returns == 1;
+}
diff --git a/mesalib/src/glsl/ir_function_detect_recursion.cpp b/mesalib/src/glsl/ir_function_detect_recursion.cpp
index 890bc455f..0a5e647cd 100644
--- a/mesalib/src/glsl/ir_function_detect_recursion.cpp
+++ b/mesalib/src/glsl/ir_function_detect_recursion.cpp
@@ -217,7 +217,7 @@ public:
if (this->current == NULL)
return visit_continue;
- function *const target = this->get_function(call->get_callee());
+ function *const target = this->get_function(call->callee);
/* Create a link from the caller to the callee.
*/
diff --git a/mesalib/src/glsl/ir_hierarchical_visitor.cpp b/mesalib/src/glsl/ir_hierarchical_visitor.cpp
index b5eacd6d2..f24414046 100644
--- a/mesalib/src/glsl/ir_hierarchical_visitor.cpp
+++ b/mesalib/src/glsl/ir_hierarchical_visitor.cpp
@@ -33,6 +33,15 @@ ir_hierarchical_visitor::ir_hierarchical_visitor()
}
ir_visitor_status
+ir_hierarchical_visitor::visit(ir_rvalue *ir)
+{
+ if (this->callback != NULL)
+ this->callback(ir, this->data);
+
+ return visit_continue;
+}
+
+ir_visitor_status
ir_hierarchical_visitor::visit(ir_variable *ir)
{
if (this->callback != NULL)
diff --git a/mesalib/src/glsl/ir_hierarchical_visitor.h b/mesalib/src/glsl/ir_hierarchical_visitor.h
index bba046db4..143eb7c88 100644
--- a/mesalib/src/glsl/ir_hierarchical_visitor.h
+++ b/mesalib/src/glsl/ir_hierarchical_visitor.h
@@ -82,6 +82,7 @@ public:
* \name Visit methods for leaf-node classes
*/
/*@{*/
+ virtual ir_visitor_status visit(class ir_rvalue *);
virtual ir_visitor_status visit(class ir_variable *);
virtual ir_visitor_status visit(class ir_constant *);
virtual ir_visitor_status visit(class ir_loop_jump *);
diff --git a/mesalib/src/glsl/ir_hv_accept.cpp b/mesalib/src/glsl/ir_hv_accept.cpp
index 0e78fda81..3ce895924 100644
--- a/mesalib/src/glsl/ir_hv_accept.cpp
+++ b/mesalib/src/glsl/ir_hv_accept.cpp
@@ -66,6 +66,13 @@ visit_list_elements(ir_hierarchical_visitor *v, exec_list *l,
ir_visitor_status
+ir_rvalue::accept(ir_hierarchical_visitor *v)
+{
+ return v->visit(this);
+}
+
+
+ir_visitor_status
ir_variable::accept(ir_hierarchical_visitor *v)
{
return v->visit(this);
@@ -326,6 +333,14 @@ ir_call::accept(ir_hierarchical_visitor *v)
if (s != visit_continue)
return (s == visit_continue_with_parent) ? visit_continue : s;
+ if (this->return_deref != NULL) {
+ v->in_assignee = true;
+ s = this->return_deref->accept(v);
+ v->in_assignee = false;
+ if (s != visit_continue)
+ return (s == visit_continue_with_parent) ? visit_continue : s;
+ }
+
s = visit_list_elements(v, &this->actual_parameters, false);
if (s == visit_stop)
return s;
diff --git a/mesalib/src/glsl/ir_print_visitor.cpp b/mesalib/src/glsl/ir_print_visitor.cpp
index 1471355f3..8aa26e5d0 100644
--- a/mesalib/src/glsl/ir_print_visitor.cpp
+++ b/mesalib/src/glsl/ir_print_visitor.cpp
@@ -135,6 +135,10 @@ print_type(const glsl_type *t)
}
}
+void ir_print_visitor::visit(ir_rvalue *ir)
+{
+ printf("error");
+}
void ir_print_visitor::visit(ir_variable *ir)
{
@@ -404,7 +408,10 @@ void ir_print_visitor::visit(ir_constant *ir)
void
ir_print_visitor::visit(ir_call *ir)
{
- printf("(call %s (", ir->callee_name());
+ printf("(call %s ", ir->callee_name());
+ if (ir->return_deref)
+ ir->return_deref->accept(this);
+ printf(" (");
foreach_iter(exec_list_iterator, iter, *ir) {
ir_instruction *const inst = (ir_instruction *) iter.get();
diff --git a/mesalib/src/glsl/ir_print_visitor.h b/mesalib/src/glsl/ir_print_visitor.h
index c7136f11a..6c308f31e 100644
--- a/mesalib/src/glsl/ir_print_visitor.h
+++ b/mesalib/src/glsl/ir_print_visitor.h
@@ -54,6 +54,7 @@ public:
* the hierarchy should not have \c visit methods.
*/
/*@{*/
+ virtual void visit(ir_rvalue *);
virtual void visit(ir_variable *);
virtual void visit(ir_function_signature *);
virtual void visit(ir_function *);
diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp
index 6f50cc439..7ce683ef7 100644
--- a/mesalib/src/glsl/ir_reader.cpp
+++ b/mesalib/src/glsl/ir_reader.cpp
@@ -51,16 +51,17 @@ private:
ir_variable *read_declaration(s_expression *);
ir_if *read_if(s_expression *, ir_loop *);
ir_loop *read_loop(s_expression *);
+ ir_call *read_call(s_expression *);
ir_return *read_return(s_expression *);
ir_rvalue *read_rvalue(s_expression *);
ir_assignment *read_assignment(s_expression *);
ir_expression *read_expression(s_expression *);
- ir_call *read_call(s_expression *);
ir_swizzle *read_swizzle(s_expression *);
ir_constant *read_constant(s_expression *);
ir_texture *read_texture(s_expression *);
ir_dereference *read_dereference(s_expression *);
+ ir_dereference_variable *read_var_ref(s_expression *);
};
ir_reader::ir_reader(_mesa_glsl_parse_state *state) : state(state)
@@ -348,6 +349,8 @@ ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx)
inst = read_if(list, loop_ctx);
} else if (strcmp(tag->value(), "loop") == 0) {
inst = read_loop(list);
+ } else if (strcmp(tag->value(), "call") == 0) {
+ inst = read_call(list);
} else if (strcmp(tag->value(), "return") == 0) {
inst = read_return(list);
} else if (strcmp(tag->value(), "function") == 0) {
@@ -521,8 +524,6 @@ ir_reader::read_rvalue(s_expression *expr)
rvalue = read_swizzle(list);
} else if (strcmp(tag->value(), "expression") == 0) {
rvalue = read_expression(list);
- } else if (strcmp(tag->value(), "call") == 0) {
- rvalue = read_call(list);
} else if (strcmp(tag->value(), "constant") == 0) {
rvalue = read_constant(list);
} else {
@@ -610,10 +611,20 @@ ir_reader::read_call(s_expression *expr)
{
s_symbol *name;
s_list *params;
+ s_list *s_return = NULL;
- s_pattern pat[] = { "call", name, params };
- if (!MATCH(expr, pat)) {
- ir_read_error(expr, "expected (call <name> (<param> ...))");
+ ir_dereference_variable *return_deref = NULL;
+
+ s_pattern void_pat[] = { "call", name, params };
+ s_pattern non_void_pat[] = { "call", name, s_return, params };
+ if (MATCH(expr, non_void_pat)) {
+ return_deref = read_var_ref(s_return);
+ if (return_deref == NULL) {
+ ir_read_error(s_return, "when reading a call's return storage");
+ return NULL;
+ }
+ } else if (!MATCH(expr, void_pat)) {
+ ir_read_error(expr, "expected (call <name> [<deref>] (<param> ...))");
return NULL;
}
@@ -643,7 +654,15 @@ ir_reader::read_call(s_expression *expr)
return NULL;
}
- return new(mem_ctx) ir_call(callee, &parameters);
+ if (callee->return_type == glsl_type::void_type && return_deref) {
+ ir_read_error(expr, "call has return value storage but void type");
+ return NULL;
+ } else if (callee->return_type != glsl_type::void_type && !return_deref) {
+ ir_read_error(expr, "call has non-void type but no return value storage");
+ return NULL;
+ }
+
+ return new(mem_ctx) ir_call(callee, return_deref, &parameters);
}
ir_expression *
@@ -828,17 +847,11 @@ ir_reader::read_constant(s_expression *expr)
return new(mem_ctx) ir_constant(type, &data);
}
-ir_dereference *
-ir_reader::read_dereference(s_expression *expr)
+ir_dereference_variable *
+ir_reader::read_var_ref(s_expression *expr)
{
s_symbol *s_var;
- s_expression *s_subject;
- s_expression *s_index;
- s_symbol *s_field;
-
s_pattern var_pat[] = { "var_ref", s_var };
- s_pattern array_pat[] = { "array_ref", s_subject, s_index };
- s_pattern record_pat[] = { "record_ref", s_subject, s_field };
if (MATCH(expr, var_pat)) {
ir_variable *var = state->symbols->get_variable(s_var->value());
@@ -847,6 +860,23 @@ ir_reader::read_dereference(s_expression *expr)
return NULL;
}
return new(mem_ctx) ir_dereference_variable(var);
+ }
+ return NULL;
+}
+
+ir_dereference *
+ir_reader::read_dereference(s_expression *expr)
+{
+ s_expression *s_subject;
+ s_expression *s_index;
+ s_symbol *s_field;
+
+ s_pattern array_pat[] = { "array_ref", s_subject, s_index };
+ s_pattern record_pat[] = { "record_ref", s_subject, s_field };
+
+ ir_dereference_variable *var_ref = read_var_ref(expr);
+ if (var_ref != NULL) {
+ return var_ref;
} else if (MATCH(expr, array_pat)) {
ir_rvalue *subject = read_rvalue(s_subject);
if (subject == NULL) {
diff --git a/mesalib/src/glsl/ir_validate.cpp b/mesalib/src/glsl/ir_validate.cpp
index 101d9992d..7efb43477 100644
--- a/mesalib/src/glsl/ir_validate.cpp
+++ b/mesalib/src/glsl/ir_validate.cpp
@@ -541,13 +541,24 @@ ir_validate::visit_enter(ir_assignment *ir)
ir_visitor_status
ir_validate::visit_enter(ir_call *ir)
{
- ir_function_signature *const callee = ir->get_callee();
+ ir_function_signature *const callee = ir->callee;
if (callee->ir_type != ir_type_function_signature) {
printf("IR called by ir_call is not ir_function_signature!\n");
abort();
}
+ if (ir->return_deref) {
+ if (ir->return_deref->type != callee->return_type) {
+ printf("callee type %s does not match return storage type %s\n",
+ callee->return_type->name, ir->return_deref->type->name);
+ abort();
+ }
+ } else if (callee->return_type != glsl_type::void_type) {
+ printf("ir_call has non-void callee but no return storage\n");
+ abort();
+ }
+
const exec_node *formal_param_node = callee->parameters.head;
const exec_node *actual_param_node = ir->actual_parameters.head;
while (true) {
@@ -611,7 +622,9 @@ check_node_type(ir_instruction *ir, void *data)
printf("Instruction node with unset type\n");
ir->print(); printf("\n");
}
- assert(ir->type != glsl_type::error_type);
+ ir_rvalue *value = ir->as_rvalue();
+ if (value != NULL)
+ assert(value->type != glsl_type::error_type);
}
void
diff --git a/mesalib/src/glsl/ir_visitor.h b/mesalib/src/glsl/ir_visitor.h
index 7dd35fe1d..4a00155be 100644
--- a/mesalib/src/glsl/ir_visitor.h
+++ b/mesalib/src/glsl/ir_visitor.h
@@ -44,6 +44,7 @@ public:
* the hierarchy should not have \c visit methods.
*/
/*@{*/
+ virtual void visit(class ir_rvalue *) { assert(!"unhandled error_type"); }
virtual void visit(class ir_variable *) = 0;
virtual void visit(class ir_function_signature *) = 0;
virtual void visit(class ir_function *) = 0;
diff --git a/mesalib/src/glsl/link_functions.cpp b/mesalib/src/glsl/link_functions.cpp
index acee32712..6b3e15448 100644
--- a/mesalib/src/glsl/link_functions.cpp
+++ b/mesalib/src/glsl/link_functions.cpp
@@ -68,7 +68,7 @@ public:
* Doing so will modify the original shader. This may prevent that
* shader from being linkable in other programs.
*/
- const ir_function_signature *const callee = ir->get_callee();
+ const ir_function_signature *const callee = ir->callee;
assert(callee != NULL);
const char *const name = callee->function_name();
@@ -79,7 +79,7 @@ public:
find_matching_signature(name, &callee->parameters, &linked, 1,
ir->use_builtin);
if (sig != NULL) {
- ir->set_callee(sig);
+ ir->callee = sig;
return visit_continue;
}
@@ -168,7 +168,7 @@ public:
*/
linked_sig->accept(this);
- ir->set_callee(linked_sig);
+ ir->callee = linked_sig;
return visit_continue;
}
diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp
index 613c9b7ae..2f1c9f5f7 100644
--- a/mesalib/src/glsl/link_uniforms.cpp
+++ b/mesalib/src/glsl/link_uniforms.cpp
@@ -173,8 +173,7 @@ private:
if (this->map->get(id, name))
return;
- char *key = strdup(name);
- this->map->put(this->num_active_uniforms, key);
+ this->map->put(this->num_active_uniforms, name);
/* Each leaf uniform occupies one entry in the list of active
* uniforms.
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 09ffdff63..49b6b8f4a 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -101,7 +101,7 @@ public:
virtual ir_visitor_status visit_enter(ir_call *ir)
{
- exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+ exec_list_iterator sig_iter = ir->callee->parameters.iterator();
foreach_iter(exec_list_iterator, iter, *ir) {
ir_rvalue *param_rval = (ir_rvalue *)iter.get();
ir_variable *sig_param = (ir_variable *)sig_iter.get();
@@ -117,6 +117,15 @@ public:
sig_iter.next();
}
+ if (ir->return_deref != NULL) {
+ ir_variable *const var = ir->return_deref->variable_referenced();
+
+ if (strcmp(name, var->name) == 0) {
+ found = true;
+ return visit_stop;
+ }
+ }
+
return visit_continue_with_parent;
}
@@ -830,6 +839,7 @@ move_non_declarations(exec_list *instructions, exec_node *last,
continue;
assert(inst->as_assignment()
+ || inst->as_call()
|| ((var != NULL) && (var->mode == ir_var_temporary)));
if (make_copies) {
diff --git a/mesalib/src/glsl/loop_analysis.cpp b/mesalib/src/glsl/loop_analysis.cpp
index 9bba6a97c..6a0e4da51 100644
--- a/mesalib/src/glsl/loop_analysis.cpp
+++ b/mesalib/src/glsl/loop_analysis.cpp
@@ -110,6 +110,8 @@ public:
virtual ir_visitor_status visit(ir_loop_jump *);
virtual ir_visitor_status visit(ir_dereference_variable *);
+ virtual ir_visitor_status visit_enter(ir_call *);
+
virtual ir_visitor_status visit_enter(ir_loop *);
virtual ir_visitor_status visit_leave(ir_loop *);
virtual ir_visitor_status visit_enter(ir_assignment *);
@@ -153,6 +155,21 @@ loop_analysis::visit(ir_loop_jump *ir)
ir_visitor_status
+loop_analysis::visit_enter(ir_call *ir)
+{
+ /* If we're not somewhere inside a loop, there's nothing to do. */
+ if (this->state.is_empty())
+ return visit_continue;
+
+ loop_variable_state *const ls =
+ (loop_variable_state *) this->state.get_head();
+
+ ls->contains_calls = true;
+ return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
loop_analysis::visit(ir_dereference_variable *ir)
{
/* If we're not somewhere inside a loop, there's nothing to do.
@@ -209,6 +226,17 @@ loop_analysis::visit_leave(ir_loop *ir)
loop_variable_state *const ls =
(loop_variable_state *) this->state.pop_head();
+ /* Function calls may contain side effects. These could alter any of our
+ * variables in ways that cannot be known, and may even terminate shader
+ * execution (say, calling discard in the fragment shader). So we can't
+ * rely on any of our analysis about assignments to variables.
+ *
+ * We could perform some conservative analysis (prove there's no statically
+ * possible assignment, etc.) but it isn't worth it for now; function
+ * inlining will allow us to unroll loops anyway.
+ */
+ if (ls->contains_calls)
+ return visit_continue;
foreach_list(node, &ir->body_instructions) {
/* Skip over declarations at the start of a loop.
diff --git a/mesalib/src/glsl/loop_analysis.h b/mesalib/src/glsl/loop_analysis.h
index 229730836..8bed1db02 100644
--- a/mesalib/src/glsl/loop_analysis.h
+++ b/mesalib/src/glsl/loop_analysis.h
@@ -122,10 +122,16 @@ public:
*/
unsigned num_loop_jumps;
+ /**
+ * Whether this loop contains any function calls.
+ */
+ bool contains_calls;
+
loop_variable_state()
{
this->max_iterations = -1;
this->num_loop_jumps = 0;
+ this->contains_calls = false;
this->var_hash = hash_table_ctor(0, hash_table_pointer_hash,
hash_table_pointer_compare);
}
diff --git a/mesalib/src/glsl/lower_clip_distance.cpp b/mesalib/src/glsl/lower_clip_distance.cpp
index 143e378f9..031691471 100644
--- a/mesalib/src/glsl/lower_clip_distance.cpp
+++ b/mesalib/src/glsl/lower_clip_distance.cpp
@@ -276,7 +276,7 @@ lower_clip_distance_visitor::visit_leave(ir_call *ir)
{
void *ctx = ralloc_parent(ir);
- const exec_node *formal_param_node = ir->get_callee()->parameters.head;
+ const exec_node *formal_param_node = ir->callee->parameters.head;
const exec_node *actual_param_node = ir->actual_parameters.head;
while (!actual_param_node->is_tail_sentinel()) {
ir_variable *formal_param = (ir_variable *) formal_param_node;
diff --git a/mesalib/src/glsl/lower_output_reads.cpp b/mesalib/src/glsl/lower_output_reads.cpp
index 415b541c3..90d71b04a 100644
--- a/mesalib/src/glsl/lower_output_reads.cpp
+++ b/mesalib/src/glsl/lower_output_reads.cpp
@@ -54,11 +54,27 @@ public:
virtual ir_visitor_status visit_leave(class ir_function_signature *);
};
+/**
+ * Hash function for the output variables - computes the hash of the name.
+ * NOTE: We're using the name string to ensure that the hash doesn't depend
+ * on any random factors, otherwise the output_read_remover could produce
+ * the random order of the assignments.
+ *
+ * NOTE: If you want to reuse this function please take into account that
+ * generally the names of the variables are non-unique.
+ */
+static unsigned
+hash_table_var_hash(const void *key)
+{
+ const ir_variable * var = static_cast<const ir_variable *>(key);
+ return hash_table_string_hash(var->name);
+}
+
output_read_remover::output_read_remover()
{
mem_ctx = ralloc_context(NULL);
replacements =
- hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
+ hash_table_ctor(0, hash_table_var_hash, hash_table_pointer_compare);
}
output_read_remover::~output_read_remover()
diff --git a/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp b/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp
index f8e4a1de4..57771074a 100644
--- a/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp
+++ b/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp
@@ -117,7 +117,7 @@ compare_index_block(exec_list *instructions, ir_variable *index,
}
static inline bool
-is_array_or_matrix(const ir_instruction *ir)
+is_array_or_matrix(const ir_rvalue *ir)
{
return (ir->type->is_array() || ir->type->is_matrix());
}
diff --git a/mesalib/src/glsl/opt_constant_folding.cpp b/mesalib/src/glsl/opt_constant_folding.cpp
index 599b21525..dcad59997 100644
--- a/mesalib/src/glsl/opt_constant_folding.cpp
+++ b/mesalib/src/glsl/opt_constant_folding.cpp
@@ -117,7 +117,8 @@ ir_constant_folding_visitor::visit_enter(ir_assignment *ir)
ir_visitor_status
ir_constant_folding_visitor::visit_enter(ir_call *ir)
{
- exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+ /* Attempt to constant fold parameters */
+ exec_list_iterator sig_iter = ir->callee->parameters.iterator();
foreach_iter(exec_list_iterator, iter, *ir) {
ir_rvalue *param_rval = (ir_rvalue *)iter.get();
ir_variable *sig_param = (ir_variable *)sig_iter.get();
@@ -133,6 +134,15 @@ ir_constant_folding_visitor::visit_enter(ir_call *ir)
sig_iter.next();
}
+ /* Next, see if the call can be replaced with an assignment of a constant */
+ ir_constant *const_val = ir->constant_expression_value();
+
+ if (const_val != NULL) {
+ ir_assignment *assignment =
+ new(ralloc_parent(ir)) ir_assignment(ir->return_deref, const_val);
+ ir->replace_with(assignment);
+ }
+
return visit_continue_with_parent;
}
diff --git a/mesalib/src/glsl/opt_constant_propagation.cpp b/mesalib/src/glsl/opt_constant_propagation.cpp
index af77e4906..d3812637d 100644
--- a/mesalib/src/glsl/opt_constant_propagation.cpp
+++ b/mesalib/src/glsl/opt_constant_propagation.cpp
@@ -259,7 +259,7 @@ ir_visitor_status
ir_constant_propagation_visitor::visit_enter(ir_call *ir)
{
/* Do constant propagation on call parameters, but skip any out params */
- exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
+ exec_list_iterator sig_param_iter = ir->callee->parameters.iterator();
foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
ir_rvalue *param = (ir_rvalue *)iter.get();
diff --git a/mesalib/src/glsl/opt_constant_variable.cpp b/mesalib/src/glsl/opt_constant_variable.cpp
index 3fa7c3bad..f3bc8675e 100644
--- a/mesalib/src/glsl/opt_constant_variable.cpp
+++ b/mesalib/src/glsl/opt_constant_variable.cpp
@@ -127,7 +127,8 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
ir_visitor_status
ir_constant_variable_visitor::visit_enter(ir_call *ir)
{
- exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+ /* Mark any out parameters as assigned to */
+ exec_list_iterator sig_iter = ir->callee->parameters.iterator();
foreach_iter(exec_list_iterator, iter, *ir) {
ir_rvalue *param_rval = (ir_rvalue *)iter.get();
ir_variable *param = (ir_variable *)sig_iter.get();
@@ -143,6 +144,17 @@ ir_constant_variable_visitor::visit_enter(ir_call *ir)
}
sig_iter.next();
}
+
+ /* Mark the return storage as having been assigned to */
+ if (ir->return_deref != NULL) {
+ ir_variable *var = ir->return_deref->variable_referenced();
+ struct assignment_entry *entry;
+
+ assert(var);
+ entry = get_assignment_entry(var, &this->list);
+ entry->assignment_count++;
+ }
+
return visit_continue;
}
diff --git a/mesalib/src/glsl/opt_copy_propagation.cpp b/mesalib/src/glsl/opt_copy_propagation.cpp
index efa3afda3..923619db4 100644
--- a/mesalib/src/glsl/opt_copy_propagation.cpp
+++ b/mesalib/src/glsl/opt_copy_propagation.cpp
@@ -181,7 +181,7 @@ ir_visitor_status
ir_copy_propagation_visitor::visit_enter(ir_call *ir)
{
/* Do copy propagation on call parameters, but skip any out params */
- exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
+ exec_list_iterator sig_param_iter = ir->callee->parameters.iterator();
foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
ir_instruction *ir = (ir_instruction *)iter.get();
diff --git a/mesalib/src/glsl/opt_copy_propagation_elements.cpp b/mesalib/src/glsl/opt_copy_propagation_elements.cpp
index ebfd4fd3f..314db4e18 100644
--- a/mesalib/src/glsl/opt_copy_propagation_elements.cpp
+++ b/mesalib/src/glsl/opt_copy_propagation_elements.cpp
@@ -288,7 +288,7 @@ ir_visitor_status
ir_copy_propagation_elements_visitor::visit_enter(ir_call *ir)
{
/* Do copy propagation on call parameters, but skip any out params */
- exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
+ exec_list_iterator sig_param_iter = ir->callee->parameters.iterator();
foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
ir_instruction *ir = (ir_instruction *)iter.get();
diff --git a/mesalib/src/glsl/opt_dead_code.cpp b/mesalib/src/glsl/opt_dead_code.cpp
index 22c7af1c2..0578f1737 100644
--- a/mesalib/src/glsl/opt_dead_code.cpp
+++ b/mesalib/src/glsl/opt_dead_code.cpp
@@ -78,8 +78,7 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned)
* Don't do so if it's a shader output, though.
*/
if (entry->var->mode != ir_var_out &&
- entry->var->mode != ir_var_inout &&
- !ir_has_call(entry->assign)) {
+ entry->var->mode != ir_var_inout) {
entry->assign->remove();
progress = true;
diff --git a/mesalib/src/glsl/opt_dead_code_local.cpp b/mesalib/src/glsl/opt_dead_code_local.cpp
index 39962bd60..a81a38fff 100644
--- a/mesalib/src/glsl/opt_dead_code_local.cpp
+++ b/mesalib/src/glsl/opt_dead_code_local.cpp
@@ -149,12 +149,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
}
}
- /* Add this instruction to the assignment list available to be removed.
- * But not if the assignment has other side effects.
- */
- if (ir_has_call(ir))
- return progress;
-
+ /* Add this instruction to the assignment list available to be removed. */
assignment_entry *entry = new(ctx) assignment_entry(var, ir);
assignments->push_tail(entry);
diff --git a/mesalib/src/glsl/opt_dead_functions.cpp b/mesalib/src/glsl/opt_dead_functions.cpp
index 51c77e3b9..017a28639 100644
--- a/mesalib/src/glsl/opt_dead_functions.cpp
+++ b/mesalib/src/glsl/opt_dead_functions.cpp
@@ -103,7 +103,7 @@ ir_dead_functions_visitor::visit_enter(ir_function_signature *ir)
ir_visitor_status
ir_dead_functions_visitor::visit_enter(ir_call *ir)
{
- signature_entry *entry = this->get_signature_entry(ir->get_callee());
+ signature_entry *entry = this->get_signature_entry(ir->callee);
entry->used = true;
diff --git a/mesalib/src/glsl/opt_function_inlining.cpp b/mesalib/src/glsl/opt_function_inlining.cpp
index ec8b72c63..4ff4d97d9 100644
--- a/mesalib/src/glsl/opt_function_inlining.cpp
+++ b/mesalib/src/glsl/opt_function_inlining.cpp
@@ -53,7 +53,6 @@ public:
virtual ir_visitor_status visit_enter(ir_expression *);
virtual ir_visitor_status visit_enter(ir_call *);
- virtual ir_visitor_status visit_enter(ir_assignment *);
virtual ir_visitor_status visit_enter(ir_return *);
virtual ir_visitor_status visit_enter(ir_texture *);
virtual ir_visitor_status visit_enter(ir_swizzle *);
@@ -63,23 +62,10 @@ public:
bool
-automatic_inlining_predicate(ir_instruction *ir)
-{
- ir_call *call = ir->as_call();
-
- if (call && can_inline(call))
- return true;
-
- return false;
-}
-
-bool
do_function_inlining(exec_list *instructions)
{
ir_function_inlining_visitor v;
- do_expression_flattening(instructions, automatic_inlining_predicate);
-
v.run(instructions);
return v.progress;
@@ -89,12 +75,12 @@ static void
replace_return_with_assignment(ir_instruction *ir, void *data)
{
void *ctx = ralloc_parent(ir);
- ir_variable *retval = (ir_variable *)data;
+ ir_dereference *orig_deref = (ir_dereference *) data;
ir_return *ret = ir->as_return();
if (ret) {
if (ret->value) {
- ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
+ ir_rvalue *lhs = orig_deref->clone(ctx, NULL);
ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
} else {
/* un-valued return has to be the last return, or we shouldn't
@@ -106,14 +92,13 @@ replace_return_with_assignment(ir_instruction *ir, void *data)
}
}
-ir_rvalue *
+void
ir_call::generate_inline(ir_instruction *next_ir)
{
void *ctx = ralloc_parent(this);
ir_variable **parameters;
int num_parameters;
int i;
- ir_variable *retval = NULL;
struct hash_table *ht;
ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
@@ -124,13 +109,6 @@ ir_call::generate_inline(ir_instruction *next_ir)
parameters = new ir_variable *[num_parameters];
- /* Generate storage for the return value. */
- if (!this->callee->return_type->is_void()) {
- retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val",
- ir_var_auto);
- next_ir->insert_before(retval);
- }
-
/* Generate the declarations for the parameters to our inlined code,
* and set up the mapping of real function body variables to ours.
*/
@@ -185,7 +163,7 @@ ir_call::generate_inline(ir_instruction *next_ir)
ir_instruction *new_ir = ir->clone(ctx, ht);
new_instructions.push_tail(new_ir);
- visit_tree(new_ir, replace_return_with_assignment, retval);
+ visit_tree(new_ir, replace_return_with_assignment, this->return_deref);
}
/* If any samplers were passed in, replace any deref of the sampler
@@ -238,11 +216,6 @@ ir_call::generate_inline(ir_instruction *next_ir)
delete [] parameters;
hash_table_dtor(ht);
-
- if (retval)
- return new(ctx) ir_dereference_variable(retval);
- else
- return NULL;
}
@@ -282,13 +255,7 @@ ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_call *ir)
{
if (can_inline(ir)) {
- /* If the call was part of some tree, then it should have been
- * flattened out or we shouldn't have seen it because of a
- * visit_continue_with_parent in this visitor.
- */
- assert(ir == base_ir);
-
- (void) ir->generate_inline(ir);
+ ir->generate_inline(ir);
ir->remove();
this->progress = true;
}
@@ -297,25 +264,6 @@ ir_function_inlining_visitor::visit_enter(ir_call *ir)
}
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
-{
- ir_call *call = ir->rhs->as_call();
- if (!call || !can_inline(call))
- return visit_continue;
-
- /* generates the parameter setup, function body, and returns the return
- * value of the function
- */
- ir_rvalue *rhs = call->generate_inline(ir);
- assert(rhs);
-
- ir->rhs = rhs;
- this->progress = true;
-
- return visit_continue;
-}
-
/**
* Replaces references to the "sampler" variable with a clone of "deref."
*
diff --git a/mesalib/src/glsl/opt_tree_grafting.cpp b/mesalib/src/glsl/opt_tree_grafting.cpp
index e2aff5f80..d86eab80e 100644
--- a/mesalib/src/glsl/opt_tree_grafting.cpp
+++ b/mesalib/src/glsl/opt_tree_grafting.cpp
@@ -202,7 +202,7 @@ ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir)
ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_call *ir)
{
- exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+ exec_list_iterator sig_iter = ir->callee->parameters.iterator();
/* Reminder: iterating ir_call iterates its parameters. */
foreach_iter(exec_list_iterator, iter, *ir) {
ir_variable *sig_param = (ir_variable *)sig_iter.get();
@@ -222,6 +222,9 @@ ir_tree_grafting_visitor::visit_enter(ir_call *ir)
sig_iter.next();
}
+ if (ir->return_deref && check_graft(ir, ir->return_deref->var) == visit_stop)
+ return visit_stop;
+
return visit_continue;
}