From a87ac255cf7ef0672b4de865d82e6a40c93b57d8 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 22 Feb 2010 13:19:34 -0800 Subject: [PATCH] Initial commit. lol --- .dir-locals.el | 1 + Makefile | 40 ++ ast.h | 511 ++++++++++++++++ ast_to_hir.cc | 1172 +++++++++++++++++++++++++++++++++++++ builtin_types.sh | 328 +++++++++++ glsl_lexer.l | 273 +++++++++ glsl_parser.y | 1228 +++++++++++++++++++++++++++++++++++++++ glsl_parser_extras.cc | 771 ++++++++++++++++++++++++ glsl_parser_extras.h | 68 +++ glsl_types.c | 159 +++++ glsl_types.h | 141 +++++ hash_table.c | 159 +++++ hash_table.h | 117 ++++ hir_field_selection.cc | 187 ++++++ hir_function.c | 41 ++ ir.cc | 116 ++++ ir.h | 302 ++++++++++ main/imports.h | 6 + main/simple_list.h | 235 ++++++++ symbol_table.c | 377 ++++++++++++ symbol_table.h | 63 ++ tests/parameters-01.txt | 9 + tests/parameters-02.txt | 9 + tests/parameters-03.txt | 9 + tests/swiz-01.glsl | 10 + tests/swiz-02.glsl | 10 + 26 files changed, 6342 insertions(+) create mode 100644 .dir-locals.el create mode 100644 Makefile create mode 100644 ast.h create mode 100644 ast_to_hir.cc create mode 100755 builtin_types.sh create mode 100644 glsl_lexer.l create mode 100644 glsl_parser.y create mode 100644 glsl_parser_extras.cc create mode 100644 glsl_parser_extras.h create mode 100644 glsl_types.c create mode 100644 glsl_types.h create mode 100644 hash_table.c create mode 100644 hash_table.h create mode 100644 hir_field_selection.cc create mode 100644 hir_function.c create mode 100644 ir.cc create mode 100644 ir.h create mode 100644 main/imports.h create mode 100644 main/simple_list.h create mode 100644 symbol_table.c create mode 100644 symbol_table.h create mode 100644 tests/parameters-01.txt create mode 100644 tests/parameters-02.txt create mode 100644 tests/parameters-03.txt create mode 100644 tests/swiz-01.glsl create mode 100644 tests/swiz-02.glsl diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 00000000000..148e4ca61f0 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1 @@ +((c-mode . ((c-basic-offset . 3)))) diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..2f2142ed131 --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +CSRCS = symbol_table.c hash_table.c glsl_types.c +CCSRCS = glsl_parser.tab.cc glsl_lexer.cc glsl_parser_extras.cc +# ast_to_hir.cc ir.cc hir_field_selection.cc +OBJS = $(CSRCS:.c=.o) $(CCSRCS:.cc=.o) + +CC = gcc +CXX = g++ +WARN = -Wall -Wextra -Wunsafe-loop-optimizations -Wstack-protector \ + -Wunreachable-code +CPPFLAGS = -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE +CFLAGS = -O0 -ggdb3 -fstack-protector $(CPPFLAGS) $(WARN) -std=c89 -ansi -pedantic +CXXFLAGS = -O0 -ggdb3 -fstack-protector $(CPPFLAGS) $(WARN) +LDLAGS = -ggdb3 + +glsl: $(OBJS) + $(CXX) $(LDLAGS) $(OBJS) -o glsl + +glsl_parser.tab.cc glsl_parser.tab.h: glsl_parser.y + bison --report-file=glsl_parser.output -v -d \ + --output=glsl_parser.tab.cc \ + --name-prefix=_mesa_glsl_ $< && \ + mv glsl_parser.tab.hh glsl_parser.tab.h + +glsl_lexer.cc: glsl_lexer.l + flex --outfile="glsl_lexer.cc" $< + +glsl_parser_tab.o: glsl_parser.tab.cc +glsl_types.o: glsl_types.c glsl_types.h builtin_types.h +glsl_lexer.o: glsl_lexer.cc glsl_parser.tab.h glsl_parser_extras.h ast.h +glsl_parser.o: glsl_parser_extras.h ast.h +ast_to_hir.o: ast_to_hir.cc symbol_table.h glsl_parser_extras.h ast.h glsl_types.h ir.h + +builtin_types.h: builtin_types.sh + ./builtin_types.sh > builtin_types.h + +clean: + rm -f $(OBJS) glsl + rm -f glsl_lexer.cc glsl_parser.tab.{cc,h,hh} glsl_parser.output + rm -f builtin_types.h + rm -f *~ \ No newline at end of file diff --git a/ast.h b/ast.h new file mode 100644 index 00000000000..591655d06cc --- /dev/null +++ b/ast.h @@ -0,0 +1,511 @@ +/* + * 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 AST_H +#define AST_H + +#include "main/simple_list.h" +#include "glsl_parser_extras.h" + +struct ir_instruction; +struct _mesa_glsl_parse_state; + +struct YYLTYPE; + +#define _mesa_ast_print(n) \ + ((ast_node *) n)->print() + +#define _mesa_ast_to_hir(n, instr, s) \ + ((struct ast_node *) n)->vtbl->to_hir((struct ast_node *) n, instr, s) + +#define _mesa_ast_function_call_to_hir(n, p, s) \ + ((struct ast_node *) n)->vtbl->function_call_to_hir( \ + (struct ast_node *) n, \ + (struct ast_node *) p, \ + s) + +class ast_node : public simple_node { +public: + virtual ~ast_node(); + virtual void print(void) const; + + /** + * Retrieve the source location of an AST node + * + * This function is primarily used to get the source position of an AST node + * into a form that can be passed to \c _mesa_glsl_error. + * + * \sa _mesa_glsl_error, ast_node::set_location + */ + struct YYLTYPE get_location(void) const + { + struct YYLTYPE locp; + + locp.source = this->location.source; + locp.first_line = this->location.line; + locp.first_column = this->location.column; + locp.last_line = locp.first_line; + locp.last_column = locp.first_column; + + return locp; + } + + /** + * Set the source location of an AST node from a parser location + * + * \sa ast_node::get_location + */ + void set_location(const struct YYLTYPE *locp) + { + this->location.source = locp->source; + this->location.line = locp->first_line; + this->location.column = locp->first_column; + } + + + int type; + + struct { + unsigned source; + unsigned line; + unsigned column; + } location; + +protected: + ast_node(void); +}; + + +enum ast_operators { + ast_assign, + ast_plus, /**< Unary + operator. */ + ast_neg, + ast_add, + ast_sub, + ast_mul, + ast_div, + ast_mod, + ast_lshift, + ast_rshift, + ast_less, + ast_greater, + ast_lequal, + ast_gequal, + ast_equal, + ast_nequal, + ast_bit_and, + ast_bit_xor, + ast_bit_or, + ast_bit_not, + ast_logic_and, + ast_logic_xor, + ast_logic_or, + ast_logic_not, + + ast_mul_assign, + ast_div_assign, + ast_mod_assign, + ast_add_assign, + ast_sub_assign, + ast_ls_assign, + ast_rs_assign, + ast_and_assign, + ast_xor_assign, + ast_or_assign, + + ast_conditional, + + ast_pre_inc, + ast_pre_dec, + ast_post_inc, + ast_post_dec, + ast_field_selection, + ast_array_index, + + ast_function_call, + + ast_identifier, + ast_int_constant, + ast_uint_constant, + ast_float_constant, + ast_bool_constant, + + ast_sequence +}; + +class ast_expression : public ast_node { +public: + ast_expression(int oper, ast_expression *, + ast_expression *, ast_expression *); + + virtual void print(void) const; + + enum ast_operators oper; + + ast_expression *subexpressions[3]; + + union { + char *identifier; + int int_constant; + float float_constant; + unsigned uint_constant; + int bool_constant; + } primary_expression; + + + /** + * List of expressions for an \c ast_sequence. + */ + struct simple_node expressions; +}; + +/** + * Number of possible operators for an ast_expression + * + * This is done as a define instead of as an additional value in the enum so + * that the compiler won't generate spurious messages like "warning: + * enumeration value ‘ast_num_operators’ not handled in switch" + */ +#define AST_NUM_OPERATORS (ast_sequence + 1) + + +class ast_compound_statement : public ast_node { +public: + ast_compound_statement(int new_scope, ast_node *statements); + virtual void print(void) const; + + int new_scope; + struct simple_node statements; +}; + +class ast_declaration : public ast_node { +public: + ast_declaration(char *identifier, int is_array, ast_expression *array_size, + ast_expression *initializer); + virtual void print(void) const; + + char *identifier; + + int is_array; + ast_expression *array_size; + + ast_expression *initializer; +}; + + +enum { + ast_precision_high = 0, /**< Default precision. */ + ast_precision_medium, + ast_precision_low +}; + +struct ast_type_qualifier { + unsigned invariant:1; + unsigned constant:1; + unsigned attribute:1; + unsigned varying:1; + unsigned in:1; + unsigned out:1; + unsigned centroid:1; + unsigned uniform:1; + unsigned smooth:1; + unsigned flat:1; + unsigned noperspective:1; +}; + +class ast_struct_specifier : public ast_node { +public: + ast_struct_specifier(char *identifier, ast_node *declarator_list); + virtual void print(void) const; + + char *name; + struct simple_node 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_sampler3d, + ast_samplercube, + ast_sampler1dshadow, + ast_sampler2dshadow, + 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); + + virtual void print(void) const; + + enum ast_types type_specifier; + + char *type_name; + ast_struct_specifier *structure; + + int is_array; + ast_expression *array_size; + + unsigned precision:2; +}; + + +class ast_fully_specified_type : public ast_node { +public: + virtual void print(void) const; + + ast_type_qualifier qualifier; + ast_type_specifier *specifier; +}; + + +class ast_declarator_list : public ast_node { +public: + ast_declarator_list(ast_fully_specified_type *); + virtual void print(void) const; + + ast_fully_specified_type *type; + struct simple_node declarations; + + /** + * Special flag for vertex shader "invariant" declarations. + * + * Vertex shaders can contain "invariant" variable redeclarations that do + * not include a type. For example, "invariant gl_Position;". This flag + * is used to note these cases when no type is specified. + */ + int invariant; +}; + + +class ast_parameter_declarator : public ast_node { +public: + virtual void print(void) const; + + ast_fully_specified_type *type; + char *identifier; + int is_array; + ast_expression *array_size; +}; + + +class ast_function : public ast_node { +public: + ast_function(void); + + virtual void print(void) const; + + ast_fully_specified_type *return_type; + char *identifier; + + struct simple_node parameters; +}; + + +class ast_declaration_statement : public ast_node { +public: + ast_declaration_statement(void); + + enum { + ast_function, + ast_declaration, + ast_precision + } mode; + + union { + class ast_function *function; + ast_declarator_list *declarator; + ast_type_specifier *type; + ast_node *node; + } declaration; +}; + + +class ast_expression_statement : public ast_node { +public: + ast_expression_statement(ast_expression *); + virtual void print(void) const; + + ast_expression *expression; +}; + + +class ast_case_label : public ast_node { +public: + + /** + * An expression of NULL means 'default'. + */ + ast_expression *expression; +}; + +class ast_selection_statement : public ast_node { +public: + ast_selection_statement(ast_expression *condition, + ast_node *then_statement, + ast_node *else_statement); + virtual void print(void) const; + + ast_expression *condition; + ast_node *then_statement; + ast_node *else_statement; +}; + + +class ast_switch_statement : public ast_node { +public: + ast_expression *expression; + struct simple_node statements; +}; + +class ast_iteration_statement : public ast_node { +public: + ast_iteration_statement(int mode, ast_node *init, ast_node *condition, + ast_expression *rest_expression, ast_node *body); + + virtual void print(void) const; + + enum ast_iteration_modes { + ast_for, + ast_while, + ast_do_while + } mode; + + + ast_node *init_statement; + ast_node *condition; + ast_expression *rest_expression; + + ast_node *body; +}; + + +class ast_jump_statement : public ast_node { +public: + ast_jump_statement(int mode, ast_expression *return_value); + virtual void print(void) const; + + enum ast_jump_modes { + ast_continue, + ast_break, + ast_return, + ast_discard + } mode; + + ast_expression *opt_return_value; +}; + + +class ast_function_definition : public ast_node { +public: + virtual void print(void) const; + + ast_function *prototype; + ast_compound_statement *body; +}; + + +extern struct ir_instruction * +ast_expression_to_hir(const ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state); + +extern struct ir_instruction * +ast_expression_statement_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state); + +extern struct ir_instruction * +ast_compound_statement_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state); + +extern struct ir_instruction * +ast_function_definition_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state); + +extern struct ir_instruction * +ast_declarator_list_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state); + +extern struct ir_instruction * +ast_parameter_declarator_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state); + +extern struct ir_instruction * +_mesa_ast_field_selection_to_hir(const struct ast_expression *expr, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state); + +#endif /* AST_H */ diff --git a/ast_to_hir.cc b/ast_to_hir.cc new file mode 100644 index 00000000000..8474a461ce2 --- /dev/null +++ b/ast_to_hir.cc @@ -0,0 +1,1172 @@ +/* + * 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 ast_to_hir.c + * Convert abstract syntax to to high-level intermediate reprensentation (HIR). + * + * During the conversion to HIR, the majority of the symantic checking is + * preformed on the program. This includes: + * + * * Symbol table management + * * Type checking + * * Function binding + * + * The majority of this work could be done during parsing, and the parser could + * probably generate HIR directly. However, this results in frequent changes + * to the parser code. Since we do not assume that every system this complier + * is built on will have Flex and Bison installed, we have to store the code + * generated by these tools in our version control system. In other parts of + * the system we've seen problems where a parser was changed but the generated + * code was not committed, merge conflicts where created because two developers + * had slightly different versions of Bison installed, etc. + * + * I have also noticed that running Bison generated parsers in GDB is very + * irritating. When you get a segfault on '$$ = $1->foo', you can't very + * well 'print $1' in GDB. + * + * As a result, my preference is to put as little C code as possible in the + * parser (and lexer) sources. + */ +#include +#include "main/imports.h" +#include "symbol_table.h" +#include "glsl_parser_extras.h" +#include "ast.h" +#include "glsl_types.h" +#include "ir.h" + +void +_mesa_generate_hir_from_ast(struct _mesa_glsl_parse_state *state) +{ + struct simple_node *ptr; + + foreach (ptr, & state->translation_unit) { + if (1) { + } + } +} + + +static const struct glsl_type * +arithmetic_result_type(const struct glsl_type *type_a, + const struct glsl_type *type_b, + bool multiply, + struct _mesa_glsl_parse_state *state) +{ + /* From GLSL 1.50 spec, page 56: + * + * "The arithmetic binary operators add (+), subtract (-), + * multiply (*), and divide (/) operate on integer and + * floating-point scalars, vectors, and matrices." + */ + if (! is_numeric_base_type(type_a->base_type) + || ! is_numeric_base_type(type_b->base_type)) { + return glsl_error_type; + } + + + /* "If one operand is floating-point based and the other is + * not, then the conversions from Section 4.1.10 "Implicit + * Conversions" are applied to the non-floating-point-based operand." + * + * This conversion was added in GLSL 1.20. If the compilation mode is + * GLSL 1.10, the conversion is skipped. + */ + if (state->language_version >= 120) { + if ((type_a->base_type == GLSL_TYPE_FLOAT) + && (type_b->base_type != GLSL_TYPE_FLOAT)) { + } else if ((type_a->base_type != GLSL_TYPE_FLOAT) + && (type_b->base_type == GLSL_TYPE_FLOAT)) { + } + } + + /* "If the operands are integer types, they must both be signed or + * both be unsigned." + * + * From this rule and the preceeding conversion it can be inferred that + * both types must be GLSL_TYPE_FLOAT, or GLSL_TYPE_UINT, or GLSL_TYPE_INT. + * The is_numeric_base_type check above already filtered out the case + * where either type is not one of these, so now the base types need only + * be tested for equality. + */ + if (type_a->base_type != type_b->base_type) { + return glsl_error_type; + } + + /* "All arithmetic binary operators result in the same fundamental type + * (signed integer, unsigned integer, or floating-point) as the + * operands they operate on, after operand type conversion. After + * conversion, the following cases are valid + * + * * The two operands are scalars. In this case the operation is + * applied, resulting in a scalar." + */ + if (is_glsl_type_scalar(type_a) && is_glsl_type_scalar(type_b)) + return type_a; + + /* "* One operand is a scalar, and the other is a vector or matrix. + * In this case, the scalar operation is applied independently to each + * component of the vector or matrix, resulting in the same size + * vector or matrix." + */ + if (is_glsl_type_scalar(type_a)) { + if (!is_glsl_type_scalar(type_b)) + return type_b; + } else if (is_glsl_type_scalar(type_b)) { + return type_a; + } + + /* All of the combinations of , , + * , , and have been + * handled. + */ + assert(type_a->vector_elements > 1); + assert(type_b->vector_elements > 1); + + /* "* The two operands are vectors of the same size. In this case, the + * operation is done component-wise resulting in the same size + * vector." + */ + if (is_glsl_type_vector(type_a) && is_glsl_type_vector(type_b)) { + if (type_a->vector_elements == type_b->vector_elements) + return type_a; + else + return glsl_error_type; + } + + /* All of the combinations of , , + * , , , and + * have been handled. At least one of the operands must + * be matrix. Further, since there are no integer matrix types, the base + * type of both operands must be float. + */ + assert((type_a->matrix_rows > 1) || (type_b->matrix_rows > 1)); + assert(type_a->base_type == GLSL_TYPE_FLOAT); + assert(type_b->base_type == GLSL_TYPE_FLOAT); + + /* "* The operator is add (+), subtract (-), or divide (/), and the + * operands are matrices with the same number of rows and the same + * number of columns. In this case, the operation is done component- + * wise resulting in the same size matrix." + * * The operator is multiply (*), where both operands are matrices or + * one operand is a vector and the other a matrix. A right vector + * operand is treated as a column vector and a left vector operand as a + * row vector. In all these cases, it is required that the number of + * columns of the left operand is equal to the number of rows of the + * right operand. Then, the multiply (*) operation does a linear + * algebraic multiply, yielding an object that has the same number of + * rows as the left operand and the same number of columns as the right + * operand. Section 5.10 "Vector and Matrix Operations" explains in + * more detail how vectors and matrices are operated on." + */ + if (! multiply) { + if (is_glsl_type_matrix(type_a) && is_glsl_type_matrix(type_b) + && (type_a->vector_elements == type_b->vector_elements) + && (type_a->matrix_rows == type_b->matrix_rows)) + return type_a; + else + return glsl_error_type; + } else { + if (is_glsl_type_matrix(type_a) && is_glsl_type_matrix(type_b)) { + if (type_a->vector_elements == type_b->matrix_rows) { + char type_name[7]; + const struct glsl_type *t; + + type_name[0] = 'm'; + type_name[1] = 'a'; + type_name[2] = 't'; + + if (type_a->matrix_rows == type_b->vector_elements) { + type_name[3] = '0' + type_a->matrix_rows; + type_name[4] = '\0'; + } else { + type_name[3] = '0' + type_a->matrix_rows; + type_name[4] = 'x'; + type_name[5] = '0' + type_b->vector_elements; + type_name[6] = '\0'; + } + + t = _mesa_symbol_table_find_symbol(state->symbols, 0, type_name); + return (t != NULL) ? t : glsl_error_type; + } + } else if (is_glsl_type_matrix(type_a)) { + /* A is a matrix and B is a column vector. Columns of A must match + * rows of B. + */ + if (type_a->vector_elements == type_b->vector_elements) + return type_b; + } else { + assert(is_glsl_type_matrix(type_b)); + + /* A is a row vector and B is a matrix. Columns of A must match + * rows of B. + */ + if (type_a->vector_elements == type_b->matrix_rows) + return type_a; + } + } + + + /* "All other cases are illegal." + */ + return glsl_error_type; +} + + +static const struct glsl_type * +unary_arithmetic_result_type(const struct glsl_type *type) +{ + /* From GLSL 1.50 spec, page 57: + * + * "The arithmetic unary operators negate (-), post- and pre-increment + * and decrement (-- and ++) operate on integer or floating-point + * values (including vectors and matrices). All unary operators work + * component-wise on their operands. These result with the same type + * they operated on." + */ + if (!is_numeric_base_type(type->base_type)) + return glsl_error_type; + + return type; +} + + +static const struct glsl_type * +modulus_result_type(const struct glsl_type *type_a, + const struct glsl_type *type_b) +{ + /* From GLSL 1.50 spec, page 56: + * "The operator modulus (%) operates on signed or unsigned integers or + * integer vectors. The operand types must both be signed or both be + * unsigned." + */ + if (! is_integer_base_type(type_a->base_type) + || ! is_integer_base_type(type_b->base_type) + || (type_a->base_type != type_b->base_type)) { + return glsl_error_type; + } + + /* "The operands cannot be vectors of differing size. If one operand is + * a scalar and the other vector, then the scalar is applied component- + * wise to the vector, resulting in the same type as the vector. If both + * are vectors of the same size, the result is computed component-wise." + */ + if (is_glsl_type_vector(type_a)) { + if (!is_glsl_type_vector(type_b) + || (type_a->vector_elements == type_b->vector_elements)) + return type_a; + } else + return type_b; + + /* "The operator modulus (%) is not defined for any other data types + * (non-integer types)." + */ + return glsl_error_type; +} + + +static const struct glsl_type * +relational_result_type(const struct glsl_type *type_a, + const struct glsl_type *type_b, + struct _mesa_glsl_parse_state *state) +{ + /* From GLSL 1.50 spec, page 56: + * "The relational operators greater than (>), less than (<), greater + * than or equal (>=), and less than or equal (<=) operate only on + * scalar integer and scalar floating-point expressions." + */ + if (! is_numeric_base_type(type_a->base_type) + || ! is_numeric_base_type(type_b->base_type) + || ! is_glsl_type_scalar(type_a) + || ! is_glsl_type_scalar(type_b)) + return glsl_error_type; + + /* "Either the operands' types must match, or the conversions from + * Section 4.1.10 "Implicit Conversions" will be applied to the integer + * operand, after which the types must match." + * + * This conversion was added in GLSL 1.20. If the compilation mode is + * GLSL 1.10, the conversion is skipped. + */ + if (state->language_version >= 120) { + if ((type_a->base_type == GLSL_TYPE_FLOAT) + && (type_b->base_type != GLSL_TYPE_FLOAT)) { + /* FINISHME: Generate the implicit type conversion. */ + } else if ((type_a->base_type != GLSL_TYPE_FLOAT) + && (type_b->base_type == GLSL_TYPE_FLOAT)) { + /* FINISHME: Generate the implicit type conversion. */ + } + } + + if (type_a->base_type != type_b->base_type) + return glsl_error_type; + + /* "The result is scalar Boolean." + */ + return glsl_bool_type; +} + + +struct ir_instruction * +ast_expression_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state) +{ + const struct ast_expression *expr = + (struct ast_expression *) ast; + static const int operations[AST_NUM_OPERATORS] = { + -1, /* ast_assign doesn't convert to ir_expression. */ + -1, /* ast_plus doesn't convert to ir_expression. */ + ir_unop_neg, + ir_binop_add, + ir_binop_sub, + ir_binop_mul, + ir_binop_div, + ir_binop_mod, + ir_binop_lshift, + ir_binop_rshift, + ir_binop_less, + ir_binop_greater, + ir_binop_lequal, + ir_binop_gequal, + ir_binop_equal, + ir_binop_nequal, + ir_binop_bit_and, + ir_binop_bit_xor, + ir_binop_bit_or, + ir_unop_bit_not, + ir_binop_logic_and, + ir_binop_logic_xor, + ir_binop_logic_or, + ir_unop_logic_not, + + /* Note: The following block of expression types actually convert + * to multiple IR instructions. + */ + ir_binop_mul, /* ast_mul_assign */ + ir_binop_div, /* ast_div_assign */ + ir_binop_mod, /* ast_mod_assign */ + ir_binop_add, /* ast_add_assign */ + ir_binop_sub, /* ast_sub_assign */ + ir_binop_lshift, /* ast_ls_assign */ + ir_binop_rshift, /* ast_rs_assign */ + ir_binop_bit_and, /* ast_and_assign */ + ir_binop_bit_xor, /* ast_xor_assign */ + ir_binop_bit_or, /* ast_or_assign */ + + -1, /* ast_conditional doesn't convert to ir_expression. */ + -1, /* ast_pre_inc doesn't convert to ir_expression. */ + -1, /* ast_pre_dec doesn't convert to ir_expression. */ + -1, /* ast_post_inc doesn't convert to ir_expression. */ + -1, /* ast_post_dec doesn't convert to ir_expression. */ + -1, /* ast_field_selection doesn't conv to ir_expression. */ + -1, /* ast_array_index doesn't convert to ir_expression. */ + -1, /* ast_function_call doesn't conv to ir_expression. */ + -1, /* ast_identifier doesn't convert to ir_expression. */ + -1, /* ast_int_constant doesn't convert to ir_expression. */ + -1, /* ast_uint_constant doesn't conv to ir_expression. */ + -1, /* ast_float_constant doesn't conv to ir_expression. */ + -1, /* ast_bool_constant doesn't conv to ir_expression. */ + -1, /* ast_sequence doesn't convert to ir_expression. */ + }; + struct ir_instruction *result = NULL; + struct ir_instruction *op[2]; + struct simple_node op_list; + const struct glsl_type *type = glsl_error_type; + bool error_emitted = false; + YYLTYPE loc; + + loc = ast->get_location(); + make_empty_list(& op_list); + + switch (expr->oper) { + case ast_assign: + op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state); + op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state); + + error_emitted = ((op[0]->type == glsl_error_type) + || (op[1]->type == glsl_error_type)); + + type = op[0]->type; + if (!error_emitted) { + YYLTYPE loc; + + /* FINISHME: This does not handle 'foo.bar.a.b.c[5].d = 5' */ + loc = expr->subexpressions[0]->get_location(); + if (op[0]->mode != ir_op_dereference) { + _mesa_glsl_error(& loc, state, "invalid lvalue in assignment"); + error_emitted = true; + + type = glsl_error_type; + } else { + const struct ir_dereference *const ref = + (struct ir_dereference *) op[0]; + const struct ir_variable *const var = + (struct ir_variable *) ref->var; + + if ((var != NULL) + && (var->mode == ir_op_var_decl) + && (var->read_only)) { + _mesa_glsl_error(& loc, state, "cannot assign to read-only " + "variable `%s'", var->name); + error_emitted = true; + + type = glsl_error_type; + } + } + } + + /* FINISHME: Check that the LHS and RHS have matching types. */ + /* FINISHME: For GLSL 1.10, check that the types are not arrays. */ + + result = new ir_assignment(op[0], op[1], NULL); + break; + + case ast_plus: + op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state); + + error_emitted = (op[0]->type == glsl_error_type); + if (type == glsl_error_type) + op[0]->type = type; + + result = op[0]; + break; + + case ast_neg: + op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state); + + type = unary_arithmetic_result_type(op[0]->type); + + error_emitted = (op[0]->type == glsl_error_type); + + result = new ir_expression(operations[expr->oper], type, + op[0], NULL); + break; + + case ast_add: + case ast_sub: + case ast_mul: + case ast_div: + op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state); + op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state); + + type = arithmetic_result_type(op[0]->type, op[1]->type, + (expr->operr == ast_mul), + state); + + result = new ir_expression(operations[expr->oper], type, + op[0], op[1]); + break; + + case ast_mod: + op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state); + op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state); + + error_emitted = ((op[0]->type == glsl_error_type) + || (op[1]->type == glsl_error_type)); + + type = modulus_result_type(op[0]->type, op[1]->type); + + assert(operations[expr->oper] == ir_binop_mod); + + result = new ir_expression(operations[expr->oper], type, + op[0], op[1]); + break; + + case ast_lshift: + case ast_rshift: + /* FINISHME: Implement bit-shift operators. */ + break; + + case ast_less: + case ast_greater: + case ast_lequal: + case ast_gequal: + op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state); + op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state); + + error_emitted = ((op[0]->type == glsl_error_type) + || (op[1]->type == glsl_error_type)); + + type = relational_result_type(op[0]->type, op[1]->type, state); + + /* The relational operators must either generate an error or result + * in a scalar boolean. See page 57 of the GLSL 1.50 spec. + */ + assert((type == glsl_error_type) + || ((type->base_type == GLSL_TYPE_BOOL) + && is_glsl_type_scalar(type))); + + result = new ir_expression(operations[expr->oper], type, + op[0], op[1]); + break; + + case ast_nequal: + case ast_equal: + /* FINISHME: Implement equality operators. */ + break; + + case ast_bit_and: + case ast_bit_xor: + case ast_bit_or: + case ast_bit_not: + /* FINISHME: Implement bit-wise operators. */ + break; + + case ast_logic_and: + case ast_logic_xor: + case ast_logic_or: + case ast_logic_not: + /* FINISHME: Implement logical operators. */ + break; + + case ast_mul_assign: + case ast_div_assign: + case ast_add_assign: + case ast_sub_assign: { + struct ir_instruction *temp_rhs; + + op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state); + op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state); + + error_emitted = ((op[0]->type == glsl_error_type) + || (op[1]->type == glsl_error_type)); + + type = arithmetic_result_type(op[0]->type, op[1]->type, + (expr->oper == ast_mul_assign), + state); + + temp_rhs = new ir_expression(operations[expr->oper], type, + op[0], op[1]); + + /* FINISHME: Check that the LHS is assignable. */ + + /* We still have to test that the LHS and RHS have matching type. For + * example, the following GLSL code should generate a type error: + * + * mat4 m; vec4 v; m *= v; + * + * The type of (m*v) is a vec4, but the type of m is a mat4. + * + * FINISHME: Is multiplication between a matrix and a vector the only + * FINISHME: case that resuls in mismatched types? + */ + /* FINISHME: Check that the LHS and RHS have matching types. */ + + /* GLSL 1.10 does not allow array assignment. However, we don't have to + * explicitly test for this because none of the binary expression + * operators allow array operands either. + */ + + /* FINISHME: This is wrong. The operation should assign to a new + * FINISHME: temporary. This assignment should then be added to the + * FINISHME: instruction list. Another assignment to the real + * FINISHME: destination should be generated. The temporary should then + * FINISHME: be returned as the r-value. + */ + result = new ir_assignment(op[0], temp_rhs, NULL); + break; + } + + case ast_mod_assign: + + case ast_ls_assign: + case ast_rs_assign: + + case ast_and_assign: + case ast_xor_assign: + case ast_or_assign: + + case ast_conditional: + + case ast_pre_inc: + case ast_pre_dec: + + case ast_post_inc: + case ast_post_dec: + break; + + case ast_field_selection: + result = _mesa_ast_field_selection_to_hir(expr, instructions, state); + type = result->type; + break; + + case ast_array_index: + break; + + case ast_function_call: + /* There are three sorts of function calls. + * + * 1. contstructors - The first subexpression is an ast_type_specifier. + * 2. methods - Only the .length() method of array types. + * 3. functions - Calls to regular old functions. + * + * Method calls are actually detected when the ast_field_selection + * expression is handled. + */ + result = _mesa_ast_function_call_to_hir(expr->subexpressions[0], + expr->subexpressions[1], + state); + type = result->type; + break; + + case ast_identifier: { + /* ast_identifier can appear several places in a full abstract syntax + * tree. This particular use must be at location specified in the grammar + * as 'variable_identifier'. + */ + struct ir_variable *var = + _mesa_symbol_table_find_symbol(state->symbols, 0, + expr->primary_expression.identifier); + + result = new ir_dereference(var); + + if (var != NULL) { + type = result->type; + } else { + _mesa_glsl_error(& loc, NULL, "`%s' undeclared", + expr->primary_expression.identifier); + + error_emitted = true; + } + break; + } + + case ast_int_constant: + type = glsl_int_type; + result = new ir_constant(type, & expr->primary_expression); + break; + + case ast_uint_constant: + type = glsl_uint_type; + result = new ir_constant(type, & expr->primary_expression); + break; + + case ast_float_constant: + type = glsl_float_type; + result = new ir_constant(type, & expr->primary_expression); + break; + + case ast_bool_constant: + type = glsl_bool_type; + result = new ir_constant(type, & expr->primary_expression); + break; + + case ast_sequence: { + struct simple_node *ptr; + + /* It should not be possible to generate a sequence in the AST without + * any expressions in it. + */ + assert(!is_empty_list(&expr->expressions)); + + /* The r-value of a sequence is the last expression in the sequence. If + * the other expressions in the sequence do not have side-effects (and + * therefore add instructions to the instruction list), they get dropped + * on the floor. + */ + foreach (ptr, &expr->expressions) + result = _mesa_ast_to_hir(ptr, instructions, state); + + type = result->type; + + /* Any errors should have already been emitted in the loop above. + */ + error_emitted = true; + break; + } + } + + if (is_error_type(type) && !error_emitted) + _mesa_glsl_error(& loc, NULL, "type mismatch"); + + return result; +} + + +struct ir_instruction * +ast_expression_statement_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state) +{ + const struct ast_expression_statement *stmt = + (struct ast_expression_statement *) ast; + + /* It is possible to have expression statements that don't have an + * expression. This is the solitary semicolon: + * + * for (i = 0; i < 5; i++) + * ; + * + * In this case the expression will be NULL. Test for NULL and don't do + * anything in that case. + */ + if (stmt->expression != NULL) + _mesa_ast_to_hir(stmt->expression, instructions, state); + + /* Statements do not have r-values. + */ + return NULL; +} + + +struct ir_instruction * +ast_compound_statement_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state) +{ + const struct ast_compound_statement *stmt = + (struct ast_compound_statement *) ast; + struct simple_node *ptr; + + + if (stmt->new_scope) + _mesa_symbol_table_push_scope(state->symbols); + + foreach (ptr, &stmt->statements) + _mesa_ast_to_hir(ptr, instructions, state); + + if (stmt->new_scope) + _mesa_symbol_table_pop_scope(state->symbols); + + /* Compound statements do not have r-values. + */ + return NULL; +} + + +static const struct glsl_type * +type_specifier_to_glsl_type(const struct ast_type_specifier *spec, + const char **name, + struct _mesa_glsl_parse_state *state) +{ + static const char *const type_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", + "sampler3D", + "samplerCube", + "sampler1DShadow", + "sampler2DShadow", + "samplerCubeShadow", + "sampler1DArray", + "sampler2DArray", + "sampler1DArrayShadow", + "sampler2DArrayShadow", + "isampler1D", + "isampler2D", + "isampler3D", + "isamplerCube", + "isampler1DArray", + "isampler2DArray", + "usampler1D", + "usampler2D", + "usampler3D", + "usamplerCube", + "usampler1DArray", + "usampler2DArray", + + NULL, /* ast_struct */ + NULL /* ast_type_name */ + }; + struct glsl_type *type; + const char *type_name = NULL; + + if (spec->type_specifier == ast_struct) { + /* FINISHME: Handle annonymous structures. */ + type = NULL; + } else { + type_name = (spec->type_specifier == ast_type_name) + ? spec->type_name : type_names[spec->type_specifier]; + + type = _mesa_symbol_table_find_symbol(state->symbols, 0, type_name); + *name = type_name; + + /* FINISHME: Handle array declarations. Note that this requires complete + * FINSIHME: handling of constant expressions. + */ + } + + return type; +} + + +static void +apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, + struct ir_variable *var, + struct _mesa_glsl_parse_state *state) +{ + if (qual->invariant) + var->invariant = 1; + + /* FINISHME: Mark 'in' variables at global scope as read-only. */ + if (qual->constant || qual->attribute || qual->uniform + || (qual->varying && (state->target == fragment_shader))) + var->read_only = 1; + + if (qual->centroid) + var->centroid = 1; + + if (qual->in && qual->out) + var->mode = ir_var_inout; + else if (qual->attribute || qual->in + || (qual->varying && (state->target == fragment_shader))) + var->mode = ir_var_in; + else if (qual->out) + var->mode = ir_var_out; + else if (qual->uniform) + var->mode = ir_var_uniform; + else + var->mode = ir_var_auto; + + if (qual->flat) + var->interpolation = ir_var_flat; + else if (qual->noperspective) + var->interpolation = ir_var_noperspective; + else + var->interpolation = ir_var_smooth; +} + + +struct ir_instruction * +ast_declarator_list_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state) +{ + const struct ast_declarator_list *dlist = (struct ast_declarator_list *) ast; + struct simple_node *ptr; + const struct glsl_type *decl_type; + const char *type_name = NULL; + + + /* FINISHME: Handle vertex shader "invariant" declarations that do not + * FINISHME: include a type. These re-declare built-in variables to be + * FINISHME: invariant. + */ + + decl_type = type_specifier_to_glsl_type(dlist->type->specifier, + & type_name, state); + + foreach (ptr, &dlist->declarations) { + struct ast_declaration *const decl = (struct ast_declaration * )ptr; + const struct glsl_type *var_type; + struct ir_variable *var; + + + /* FINISHME: Emit a warning if a variable declaration shadows a + * FINISHME: declaration at a higher scope. + */ + + if (decl_type == NULL) { + YYLTYPE loc; + + loc = ast->get_location(); + if (type_name != NULL) { + _mesa_glsl_error(& loc, state, + "invalid type `%s' in declaration of `%s'", + type_name, decl->identifier); + } else { + _mesa_glsl_error(& loc, state, + "invalid type in declaration of `%s'", + decl->identifier); + } + continue; + } + + if (decl->is_array) { + /* FINISHME: Handle array declarations. Note that this requires + * FINISHME: complete handling of constant expressions. + */ + + /* FINISHME: Reject delcarations of multidimensional arrays. */ + } else { + var_type = decl_type; + } + + var = new ir_variable(var_type, decl->identifier); + + /* FINSIHME: Variables that are attribute, uniform, varying, in, or + * FINISHME: out varibles must be declared either at global scope or + * FINISHME: in a parameter list (in and out only). + */ + + apply_type_qualifier_to_variable(& dlist->type->qualifier, var, state); + + /* Attempt to add the variable to the symbol table. If this fails, it + * means the variable has already been declared at this scope. + */ + if (_mesa_symbol_table_add_symbol(state->symbols, 0, decl->identifier, + var) != 0) { + YYLTYPE loc = ast->get_location(); + + _mesa_glsl_error(& loc, state, "`%s' redeclared", + decl->identifier); + continue; + } + + insert_at_tail(instructions, (struct simple_node *) var); + + /* FINISHME: Process the declaration initializer. */ + } + + /* Variable declarations do not have r-values. + */ + return NULL; +} + + +struct ir_instruction * +ast_parameter_declarator_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state) +{ + const struct ast_parameter_declarator *decl = + (struct ast_parameter_declarator *) ast; + struct ir_variable *var; + const struct glsl_type *type; + const char *name = NULL; + + + type = type_specifier_to_glsl_type(decl->type->specifier, & name, state); + + if (type == NULL) { + YYLTYPE loc = ast->get_location(); + if (name != NULL) { + _mesa_glsl_error(& loc, state, + "invalid type `%s' in declaration of `%s'", + name, decl->identifier); + } else { + _mesa_glsl_error(& loc, state, + "invalid type in declaration of `%s'", + decl->identifier); + } + + type = glsl_error_type; + } + + var = new ir_variable(type, decl->identifier); + + /* FINISHME: Handle array declarations. Note that this requires + * FINISHME: complete handling of constant expressions. + */ + + apply_type_qualifier_to_variable(& decl->type->qualifier, var, state); + + insert_at_tail(instructions, var); + + /* Parameter declarations do not have r-values. + */ + return NULL; +} + + +static void +ast_function_parameters_to_hir(struct simple_node *ast_parameters, + struct simple_node *ir_parameters, + struct _mesa_glsl_parse_state *state) +{ + struct simple_node *ptr; + + foreach (ptr, ast_parameters) { + _mesa_ast_to_hir(ptr, ir_parameters, state); + } +} + + +static bool +parameter_lists_match(struct simple_node *list_a, struct simple_node *list_b) +{ + struct simple_node *node_a; + struct simple_node *node_b; + + node_b = first_elem(list_b); + foreach (node_a, list_a) { + /* If all of the parameters from the other parameter list have been + * exhausted, the lists have different length and, by definition, + * do not match. + */ + if (at_end(list_b, node_b)) + return false; + + /* If the types of the parameters do not match, the parameters lists + * are different. + */ + /* FINISHME */ + + + node_b = next_elem(node_b); + } + + return true; +} + + +struct ir_instruction * +ast_function_definition_to_hir(const struct ast_node *ast, + struct simple_node *instructions, + struct _mesa_glsl_parse_state *state) +{ + const struct ast_function_definition *func = + (struct ast_function_definition *) ast; + struct ir_label *label; + struct simple_node *ptr; + struct simple_node *tmp; + struct ir_function_signature *signature = NULL; + struct ir_function *f = NULL; + struct simple_node parameters; + + + /* Convert the list of function parameters to HIR now so that they can be + * used below to compare this function's signature with previously seen + * signatures for functions with the same name. + */ + make_empty_list(& parameters); + ast_function_parameters_to_hir(& func->prototype->parameters, & parameters, + state); + + + /* 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. + */ + f = _mesa_symbol_table_find_symbol(state->symbols, 0, + func->prototype->identifier); + if (f != NULL) { + foreach (ptr, & f->signatures) { + signature = (struct ir_function_signature *) ptr; + + /* Compare the parameter list of the function being defined to the + * existing function. If the parameter lists match, then the return + * type must also match and the existing function must not have a + * definition. + */ + if (parameter_lists_match(& parameters, & signature->parameters)) { + /* FINISHME: Compare return types. */ + + if (signature->definition != NULL) { + YYLTYPE loc = ast->get_location(); + + _mesa_glsl_error(& loc, state, "function `%s' redefined", + func->prototype->identifier); + signature = NULL; + break; + } + } + + signature = NULL; + } + + } else { + f = new ir_function(); + f->name = func->prototype->identifier; + + _mesa_symbol_table_add_symbol(state->symbols, 0, f->name, f); + } + + + /* Finish storing the information about this new function in its signature. + */ + if (signature == NULL) { + signature = new ir_function_signature(); + insert_at_tail(& f->signatures, (struct simple_node *) signature); + } else { + /* Destroy all of the previous parameter information. The previous + * parameter information comes from the function prototype, and it can + * either include invalid parameter names or may not have names at all. + */ + foreach_s(ptr, tmp, & signature->parameters) { + assert(((struct ir_instruction *)ptr)->mode == ir_op_var_decl); + + remove_from_list(ptr); + free(ptr); + } + } + + + ast_function_parameters_to_hir(& func->prototype->parameters, + & signature->parameters, + state); + /* FINISHME: Set signature->return_type */ + + label = new ir_label(func->prototype->identifier); + if (signature->definition == NULL) { + signature->definition = label; + } + insert_at_tail(instructions, label); + + /* Add the function parameters to the symbol table. During this step the + * parameter declarations are also moved from the temporary "parameters" list + * to the instruction list. There are other more efficient ways to do this, + * but they involve ugly linked-list gymnastics. + */ + _mesa_symbol_table_push_scope(state->symbols); + foreach_s(ptr, tmp, & parameters) { + struct ir_variable *const var = (struct ir_variable *) ptr; + + assert(var->mode == ir_op_var_decl); + + remove_from_list(ptr); + insert_at_tail(instructions, ptr); + + _mesa_symbol_table_add_symbol(state->symbols, 0, var->name, var); + } + + /* Convert the body of the function to HIR, and append the resulting + * instructions to the list that currently consists of the function label + * and the function parameters. + */ + _mesa_ast_to_hir(func->body, instructions, state); + + _mesa_symbol_table_pop_scope(state->symbols); + + + /* Function definitions do not have r-values. + */ + return NULL; +} diff --git a/builtin_types.sh b/builtin_types.sh new file mode 100755 index 00000000000..19dcbaf124e --- /dev/null +++ b/builtin_types.sh @@ -0,0 +1,328 @@ +#!/bin/sh +# +# 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. + +# gen_integral_type +function gen_integral_type +{ + printf ' { %17s, 0, 0, 0, 0, %u, %u, "%s", 0, {NULL} },\n' $2 $3 $4 $1 + index=$((index + 1)) +} + +# gen_struct_type +function gen_struct_type +{ + elements=$(printf "%s_fields" $1) + printf ' {\n GLSL_TYPE_STRUCT, 0, 0, 0, 0, 0, 0, "%s",\n Elements(%s),\n {(void *) %s}\n },\n' \ + $1 $elements $elements +} + +# gen_sampler_type +function gen_sampler_type +{ + name=$(printf "sampler%s" $1) + + if [ $4 -eq 1 ]; then + name=$(printf "%sArray" $name) + fi + + if [ $3 -eq 1 ]; then + name=$(printf "%sShadow" $name) + fi + + if [ $5 == GLSL_TYPE_INT ]; then + name=$(printf "i%s" $name) + elif [ $5 == GLSL_TYPE_UINT ]; then + name=$(printf "u%s" $name) + fi + + printf ' { GLSL_TYPE_SAMPLER, %21s, %u, %u, %15s, 0, 0,\n "%s", 0, {NULL} },\n' \ + $2 $3 $4 $5 $name +} + +function gen_header +{ + if [ x$1 == x ]; then + name="builtin_types" + else + name="builtin_${1}_types" + fi + + printf "\nstatic const struct glsl_type %s[] = {\n" $name +} + +function gen_footer +{ + printf "};\n" +} + +function gen_struct_field_header +{ + printf "\nstatic const struct glsl_struct_field %s_fields[] = {\n" $1 +} + +function gen_struct_field_footer +{ + printf "};\n" +} + +function gen_struct_field +{ + printf ' { & %s[%2u], "%s" },\n' $1 $2 "$3" +} + +cat <source = 0; \ + yylloc->first_column = yycolumn + 1; \ + yylloc->first_line = yylineno + 1; \ + yycolumn += yyleng; \ + } while(0); + +%} + +%option bison-bridge bison-locations reentrant noyywrap +%option never-interactive +%option prefix="_mesa_glsl_" +%option extra-type="struct _mesa_glsl_parse_state *" +%option stack + +%x PP COMMENT + +%% + +"/*" { yy_push_state(COMMENT, yyscanner); } +[^*\n]* +[^*\n]*\n { yylineno++; yycolumn = 0; } +"*"+[^*/\n]* +"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; } +"*"+"/" { yy_pop_state(yyscanner); } + +\/\/.*\n { yylineno++; yycolumn = 0; } +[ \r\t]+ ; + + /* Preprocessor tokens. */ +^[ \t]*#[ \t]*$ ; +^[ \t]*#[ \t]*version { BEGIN PP; return VERSION; } +^[ \t]*#[ \t]*extension { BEGIN PP; return EXTENSION; } +^[ \t]*#[ \t]*line { BEGIN PP; return LINE; } +^[ \t]*#[ \t]*pragma { BEGIN PP; return PRAGMA; } +: return COLON; +[_a-zA-Z][_a-zA-Z0-9]* { + yylval->identifier = strdup(yytext); + return IDENTIFIER; + } +[1-9][0-9]* { + yylval->n = strtol(yytext, NULL, 10); + return INTCONSTANT; + } +\n { BEGIN 0; yylineno++; yycolumn = 0; return EOL; } + +\n { yylineno++; yycolumn = 0; } + +attribute return ATTRIBUTE; +const return CONST; +bool return BOOL; +float return FLOAT; +int return INT; + +break return BREAK; +continue return CONTINUE; +do return DO; +while return WHILE; +else return ELSE; +for return FOR; +if return IF; +discard return DISCARD; +return return RETURN; + +bvec2 return BVEC2; +bvec3 return BVEC3; +bvec4 return BVEC4; +ivec2 return IVEC2; +ivec3 return IVEC3; +ivec4 return IVEC4; +vec2 return VEC2; +vec3 return VEC3; +vec4 return VEC4; +mat2 return MAT2; +mat3 return MAT3; +mat4 return MAT4; +mat2x2 return MAT2X2; +mat2x3 return MAT2X3; +mat2x4 return MAT2X4; +mat3x2 return MAT3X2; +mat3x3 return MAT3X3; +mat3x4 return MAT3X4; +mat4x2 return MAT4X2; +mat4x3 return MAT4X3; +mat4x4 return MAT4X4; + +in return IN; +out return OUT; +inout return INOUT; +uniform return UNIFORM; +varying return VARYING; +centroid return CENTROID; +invariant return INVARIANT; + +sampler1D return SAMPLER1D; +sampler2D return SAMPLER2D; +sampler3D return SAMPLER3D; +samplerCube return SAMPLERCUBE; +sampler1DShadow return SAMPLER1DSHADOW; +sampler2DShadow return SAMPLER2DSHADOW; + +struct return STRUCT; +void return VOID; + +\+\+ return INC_OP; +-- return DEC_OP; +\<= return LE_OP; +>= return GE_OP; +== return EQ_OP; +!= return NE_OP; +&& return AND_OP; +\|\| return OR_OP; +"^^" return XOR_OP; + +\*= return MUL_ASSIGN; +\/= return DIV_ASSIGN; +\+= return ADD_ASSIGN; +\%= return MOD_ASSIGN; +\<\<= return LEFT_ASSIGN; +>>= return RIGHT_ASSIGN; +&= return AND_ASSIGN; +^= return XOR_ASSIGN; +\|= return OR_ASSIGN; +-= return SUB_ASSIGN; + +[1-9][0-9]* { + yylval->n = strtol(yytext, NULL, 10); + return INTCONSTANT; + } +0[xX][0-9a-fA-F]+ { + yylval->n = strtol(yytext + 2, NULL, 16); + return INTCONSTANT; + } +0[0-7]* { + yylval->n = strtol(yytext + 2, NULL, 8); + return INTCONSTANT; + } + +[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?[fF]? { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } +\.[0-9]+([eE][+-]?[0-9]+)?[fF]? { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } +[0-9]+\.([eE][+-]?[0-9]+)?[fF]? { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } +[0-9]+[eE][+-]?[0-9]+[fF]? { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } + +true { + yylval->n = 1; + return BOOLCONSTANT; + } +false { + yylval->n = 0; + return BOOLCONSTANT; + } + + + /* Reserved words in GLSL 1.10. */ +asm return ASM; +class return CLASS; +union return UNION; +enum return ENUM; +typedef return TYPEDEF; +template return TEMPLATE; +this return THIS; +packed return PACKED; +goto return GOTO; +switch return SWITCH; +default return DEFAULT; +inline return INLINE; +noinline return NOINLINE; +volatile return VOLATILE; +public return PUBLIC; +static return STATIC; +extern return EXTERN; +external return EXTERNAL; +interface return INTERFACE; +long return LONG; +short return SHORT; +double return DOUBLE; +half return HALF; +fixed return FIXED; +unsigned return UNSIGNED; +input return INPUT; +output return OUTPUT; +hvec2 return HVEC2; +hvec3 return HVEC3; +hvec4 return HVEC4; +dvec2 return DVEC2; +dvec3 return DVEC3; +dvec4 return DVEC4; +fvec2 return FVEC2; +fvec3 return FVEC3; +fvec4 return FVEC4; +sampler2DRect return SAMPLER2DRECT; +sampler3DRect return SAMPLER3DRECT; +sampler2DRectShadow return SAMPLER2DRECTSHADOW; +sizeof return SIZEOF; +cast return CAST; +namespace return NAMESPACE; +using return USING; + + /* Additional reserved words in GLSL 1.20. */ +lowp return LOWP; +mediump return MEDIUMP; +highp return HIGHP; +precision return PRECISION; + +[_a-zA-Z][_a-zA-Z0-9]* { + yylval->identifier = strdup(yytext); + + if (_mesa_symbol_table_find_symbol(yyextra->symbols, + 0, + yylval->identifier)) + return TYPE_NAME; + else + return IDENTIFIER; + } + +. { return yytext[0]; } + +%% + +void +_mesa_glsl_lexer_ctor(struct _mesa_glsl_parse_state *state, + const char *string, size_t len) +{ + yylex_init_extra(state, & state->scanner); + yy_scan_bytes(string, len, state->scanner); +} + +void +_mesa_glsl_lexer_dtor(struct _mesa_glsl_parse_state *state) +{ + yylex_destroy(state->scanner); +} diff --git a/glsl_parser.y b/glsl_parser.y new file mode 100644 index 00000000000..f9bfb0bc812 --- /dev/null +++ b/glsl_parser.y @@ -0,0 +1,1228 @@ +%{ +/* + * Copyright © 2008, 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. + */ +#include +#include +#include +#include + +#include "ast.h" +#include "glsl_parser_extras.h" +#include "symbol_table.h" +#include "glsl_types.h" + +#define YYLEX_PARAM state->scanner + +%} + +%pure-parser +%locations +%error-verbose + +%lex-param {void *scanner} +%parse-param {struct _mesa_glsl_parse_state *state} + +%union { + int n; + float real; + char *identifier; + + union { + struct ast_type_qualifier q; + unsigned i; + } type_qualifier; + + struct ast_node *node; + struct ast_type_specifier *type_specifier; + struct ast_fully_specified_type *fully_specified_type; + struct ast_function *function; + struct ast_parameter_declarator *parameter_declarator; + struct ast_function_definition *function_definition; + struct ast_compound_statement *compound_statement; + struct ast_expression *expression; + struct ast_declarator_list *declarator_list; + struct ast_struct_specifier *struct_specifier; + struct ast_declaration *declaration; + + struct { + struct ast_node *cond; + struct ast_expression *rest; + } for_rest_statement; +} + +%token ATTRIBUTE CONST BOOL FLOAT INT UINT +%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT +%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4 +%token MAT2 MAT3 MAT4 CENTROID IN OUT INOUT UNIFORM VARYING +%token NOPERSPECTIVE FLAT SMOOTH +%token MAT2X2 MAT2X3 MAT2X4 +%token MAT3X2 MAT3X3 MAT3X4 +%token MAT4X2 MAT4X3 MAT4X4 +%token SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW +%token SAMPLERCUBESHADOW SAMPLER1DARRAY SAMPLER2DARRAY SAMPLER1DARRAYSHADOW +%token SAMPLER2DARRAYSHADOW ISAMPLER1D ISAMPLER2D ISAMPLER3D ISAMPLERCUBE +%token ISAMPLER1DARRAY ISAMPLER2DARRAY USAMPLER1D USAMPLER2D USAMPLER3D +%token USAMPLERCUBE USAMPLER1DARRAY USAMPLER2DARRAY +%token STRUCT VOID WHILE +%token IDENTIFIER TYPE_NAME +%token FLOATCONSTANT +%token INTCONSTANT UINTCONSTANT BOOLCONSTANT +%token FIELD_SELECTION +%token LEFT_OP RIGHT_OP +%token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN +%token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN +%token SUB_ASSIGN +%token INVARIANT +%token HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION + +%token VERSION EXTENSION LINE PRAGMA COLON EOL INTERFACE OUTPUT + + /* Reserved words that are not actually used in the grammar. + */ +%token ASM CLASS UNION ENUM TYPEDEF TEMPLATE THIS PACKED GOTO +%token INLINE NOINLINE VOLATILE PUBLIC STATIC EXTERN EXTERNAL +%token LONG SHORT DOUBLE HALF FIXED UNSIGNED INPUT OUPTUT +%token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4 +%token SAMPLER2DRECT SAMPLER3DRECT SAMPLER2DRECTSHADOW +%token SIZEOF CAST NAMESPACE USING LOWP MEDIUMP HIGHP + +%type variable_identifier +%type statement +%type statement_list +%type simple_statement +%type statement_matched +%type statement_unmatched +%type precision_qualifier +%type type_qualifier +%type storage_qualifier +%type interpolation_qualifier +%type type_specifier +%type type_specifier_no_prec +%type type_specifier_nonarray +%type basic_type_specifier_nonarray +%type fully_specified_type +%type function_prototype +%type function_header +%type function_header_with_parameters +%type function_declarator +%type parameter_declarator +%type parameter_declaration +%type parameter_qualifier +%type parameter_type_qualifier +%type parameter_type_specifier +%type function_definition +%type compound_statement_no_new_scope +%type compound_statement +%type statement_no_new_scope +%type expression_statement +%type expression +%type primary_expression +%type assignment_expression +%type conditional_expression +%type logical_or_expression +%type logical_xor_expression +%type logical_and_expression +%type inclusive_or_expression +%type exclusive_or_expression +%type and_expression +%type equality_expression +%type relational_expression +%type shift_expression +%type additive_expression +%type multiplicative_expression +%type unary_expression +%type constant_expression +%type integer_expression +%type postfix_expression +%type function_call_header_with_parameters +%type function_call_header_no_parameters +%type function_call_header +%type function_call_generic +%type function_call_or_method +%type function_call +%type assignment_operator +%type unary_operator +%type function_identifier +%type external_declaration +%type init_declarator_list +%type single_declaration +%type initializer +%type declaration +%type declaration_statement +%type jump_statement +%type struct_specifier +%type struct_declaration_list +%type struct_declaration +%type struct_declarator +%type struct_declarator_list +%type selection_statement_matched +%type selection_statement_unmatched +%type iteration_statement +%type condition +%type conditionopt +%type for_init_statement +%type for_rest_statement +%% + +translation_unit: + version_statement + { + _mesa_glsl_initialize_types(state); + } + external_declaration_list + | + { + state->language_version = 110; + _mesa_glsl_initialize_types(state); + } + external_declaration_list + ; + +version_statement: + VERSION INTCONSTANT EOL + { + switch ($2) { + case 110: + case 120: + case 130: + /* FINISHME: Check against implementation support versions. */ + state->language_version = $2; + break; + default: + _mesa_glsl_error(& @2, state, "Shading language version" + "%u is not supported\n", $2); + break; + } + } + ; + +external_declaration_list: + external_declaration + { + insert_at_tail(& state->translation_unit, + (struct simple_node *) $1); + } + | external_declaration_list external_declaration + { + insert_at_tail(& state->translation_unit, + (struct simple_node *) $2); + } + ; + +variable_identifier: + IDENTIFIER + ; + +primary_expression: + variable_identifier + { + $$ = new ast_expression(ast_identifier, NULL, NULL, NULL); + $$->primary_expression.identifier = $1; + } + | INTCONSTANT + { + $$ = new ast_expression(ast_int_constant, NULL, NULL, NULL); + $$->primary_expression.int_constant = $1; + } + | UINTCONSTANT + { + $$ = new ast_expression(ast_uint_constant, NULL, NULL, NULL); + $$->primary_expression.uint_constant = $1; + } + | FLOATCONSTANT + { + $$ = new ast_expression(ast_float_constant, NULL, NULL, NULL); + $$->primary_expression.float_constant = $1; + } + | BOOLCONSTANT + { + $$ = new ast_expression(ast_bool_constant, NULL, NULL, NULL); + $$->primary_expression.bool_constant = $1; + } + | '(' expression ')' + { + $$ = $2; + } + ; + +postfix_expression: + primary_expression + | postfix_expression '[' integer_expression ']' + { + $$ = new ast_expression(ast_array_index, $1, $3, NULL); + } + | function_call + { + $$ = $1; + } + | postfix_expression '.' IDENTIFIER + { + $$ = new ast_expression(ast_field_selection, $1, NULL, NULL); + $$->primary_expression.identifier = $3; + } + | postfix_expression INC_OP + { + $$ = new ast_expression(ast_post_inc, $1, NULL, NULL); + } + | postfix_expression DEC_OP + { + $$ = new ast_expression(ast_post_dec, $1, NULL, NULL); + } + ; + +integer_expression: + expression + ; + +function_call: + function_call_or_method + ; + +function_call_or_method: + function_call_generic + | postfix_expression '.' function_call_generic + { + $$ = new ast_expression(ast_field_selection, $1, $3, NULL); + } + ; + +function_call_generic: + function_call_header_with_parameters ')' + | function_call_header_no_parameters ')' + ; + +function_call_header_no_parameters: + function_call_header VOID + | function_call_header + ; + +function_call_header_with_parameters: + function_call_header assignment_expression + { + $$ = $1; + $$->subexpressions[1] = $2; + } + | function_call_header_with_parameters ',' assignment_expression + { + $$ = $1; + insert_at_tail((struct simple_node *) $$->subexpressions[1], + (struct simple_node *) $3); + } + ; + + // Grammar Note: Constructors look like functions, but lexical + // analysis recognized most of them as keywords. They are now + // recognized through "type_specifier". +function_call_header: + function_identifier '(' + { + $$ = new ast_expression(ast_function_call, + (struct ast_expression *) $1, + NULL, NULL); + } + ; + +function_identifier: + type_specifier + { + $$ = (struct ast_node *) $1; + } + | IDENTIFIER + { + ast_expression *expr = + new ast_expression(ast_identifier, NULL, NULL, NULL); + expr->primary_expression.identifier = $1; + + $$ = (struct ast_node *) expr; + } + | FIELD_SELECTION + { + ast_expression *expr = + new ast_expression(ast_identifier, NULL, NULL, NULL); + expr->primary_expression.identifier = $1; + + $$ = (struct ast_node *) expr; + } + ; + + // Grammar Note: No traditional style type casts. +unary_expression: + postfix_expression + | INC_OP unary_expression + { + $$ = new ast_expression(ast_pre_inc, $2, NULL, NULL); + } + | DEC_OP unary_expression + { + $$ = new ast_expression(ast_pre_dec, $2, NULL, NULL); + } + | unary_operator unary_expression + { + $$ = new ast_expression($1, $2, NULL, NULL); + } + ; + + // Grammar Note: No '*' or '&' unary ops. Pointers are not supported. +unary_operator: + '+' { $$ = ast_plus; } + | '-' { $$ = ast_neg; } + | '!' { $$ = ast_logic_not; } + | '~' { $$ = ast_bit_not; } + ; + +multiplicative_expression: + unary_expression + | multiplicative_expression '*' unary_expression + { + $$ = new ast_expression(ast_mul, $1, $3, NULL); + } + | multiplicative_expression '/' unary_expression + { + $$ = new ast_expression(ast_div, $1, $3, NULL); + } + | multiplicative_expression '%' unary_expression + { + $$ = new ast_expression(ast_mod, $1, $3, NULL); + } + ; + +additive_expression: + multiplicative_expression + | additive_expression '+' multiplicative_expression + { + $$ = new ast_expression(ast_add, $1, $3, NULL); + } + | additive_expression '-' multiplicative_expression + { + $$ = new ast_expression(ast_sub, $1, $3, NULL); + } + ; + +shift_expression: + additive_expression + | shift_expression LEFT_OP additive_expression + { + $$ = new ast_expression(ast_lshift, $1, $3, NULL); + } + | shift_expression RIGHT_OP additive_expression + { + $$ = new ast_expression(ast_rshift, $1, $3, NULL); + } + ; + +relational_expression: + shift_expression + | relational_expression '<' shift_expression + { + $$ = new ast_expression(ast_less, $1, $3, NULL); + } + | relational_expression '>' shift_expression + { + $$ = new ast_expression(ast_greater, $1, $3, NULL); + } + | relational_expression LE_OP shift_expression + { + $$ = new ast_expression(ast_lequal, $1, $3, NULL); + } + | relational_expression GE_OP shift_expression + { + $$ = new ast_expression(ast_gequal, $1, $3, NULL); + } + ; + +equality_expression: + relational_expression + | equality_expression EQ_OP relational_expression + { + $$ = new ast_expression(ast_equal, $1, $3, NULL); + } + | equality_expression NE_OP relational_expression + { + $$ = new ast_expression(ast_nequal, $1, $3, NULL); + } + ; + +and_expression: + equality_expression + | and_expression '&' equality_expression + { + $$ = new ast_expression(ast_bit_or, $1, $3, NULL); + } + ; + +exclusive_or_expression: + and_expression + | exclusive_or_expression '^' and_expression + { + $$ = new ast_expression(ast_bit_xor, $1, $3, NULL); + } + ; + +inclusive_or_expression: + exclusive_or_expression + | inclusive_or_expression '|' exclusive_or_expression + { + $$ = new ast_expression(ast_bit_or, $1, $3, NULL); + } + ; + +logical_and_expression: + inclusive_or_expression + | logical_and_expression AND_OP inclusive_or_expression + { + $$ = new ast_expression(ast_logic_and, $1, $3, NULL); + } + ; + +logical_xor_expression: + logical_and_expression + | logical_xor_expression XOR_OP logical_and_expression + { + $$ = new ast_expression(ast_logic_xor, $1, $3, NULL); + } + ; + +logical_or_expression: + logical_xor_expression + | logical_or_expression OR_OP logical_xor_expression + { + $$ = new ast_expression(ast_logic_or, $1, $3, NULL); + } + ; + +conditional_expression: + logical_or_expression + | logical_or_expression '?' expression ':' assignment_expression + { + $$ = new ast_expression(ast_conditional, $1, $3, $5); + } + ; + +assignment_expression: + conditional_expression + | unary_expression assignment_operator assignment_expression + { + $$ = new ast_expression($2, $1, $3, NULL); + } + ; + +assignment_operator: + '=' { $$ = ast_assign; } + | MUL_ASSIGN { $$ = ast_mul_assign; } + | DIV_ASSIGN { $$ = ast_div_assign; } + | MOD_ASSIGN { $$ = ast_mod_assign; } + | ADD_ASSIGN { $$ = ast_add_assign; } + | SUB_ASSIGN { $$ = ast_sub_assign; } + | LEFT_ASSIGN { $$ = ast_ls_assign; } + | RIGHT_ASSIGN { $$ = ast_rs_assign; } + | AND_ASSIGN { $$ = ast_and_assign; } + | XOR_ASSIGN { $$ = ast_xor_assign; } + | OR_ASSIGN { $$ = ast_or_assign; } + ; + +expression: + assignment_expression + { + $$ = $1; + } + | expression ',' assignment_expression + { + if ($1->oper != ast_sequence) { + $$ = new ast_expression(ast_sequence, NULL, NULL, NULL); + insert_at_tail(& $$->expressions, $1); + } else { + $$ = $1; + } + + insert_at_tail(& $$->expressions, $3); + } + ; + +constant_expression: + conditional_expression + ; + +declaration: + function_prototype ';' + { + $$ = $1; + } + | init_declarator_list ';' + { + $$ = $1; + } + | PRECISION precision_qualifier type_specifier_no_prec ';' + { + $$ = NULL; /* FINISHME */ + } + ; + +function_prototype: + function_declarator ')' + ; + +function_declarator: + function_header + | function_header_with_parameters + ; + +function_header_with_parameters: + function_header parameter_declaration + { + $$ = $1; + insert_at_head(& $$->parameters, + (struct simple_node *) $2); + } + | function_header_with_parameters ',' parameter_declaration + { + $$ = $1; + insert_at_head(& $$->parameters, + (struct simple_node *) $3); + } + ; + +function_header: + fully_specified_type IDENTIFIER '(' + { + $$ = new ast_function(); + $$->return_type = $1; + $$->identifier = $2; + } + ; + +parameter_declarator: + type_specifier IDENTIFIER + { + $$ = new ast_parameter_declarator(); + $$->type = new ast_fully_specified_type(); + $$->type->specifier = $1; + $$->identifier = $2; + } + | type_specifier IDENTIFIER '[' constant_expression ']' + { + $$ = new ast_parameter_declarator(); + $$->type = new ast_fully_specified_type(); + $$->type->specifier = $1; + $$->identifier = $2; + $$->is_array = true; + $$->array_size = $4; + } + ; + +parameter_declaration: + parameter_type_qualifier parameter_qualifier parameter_declarator + { + $1.i |= $2.i; + + $$ = $3; + $$->type->qualifier = $1.q; + } + | parameter_qualifier parameter_declarator + { + $$ = $2; + $$->type->qualifier = $1.q; + } + | parameter_type_qualifier parameter_qualifier parameter_type_specifier + { + $1.i |= $2.i; + + $$ = new ast_parameter_declarator(); + $$->type = new ast_fully_specified_type(); + $$->type->qualifier = $1.q; + $$->type->specifier = $3; + } + | parameter_qualifier parameter_type_specifier + { + $$ = new ast_parameter_declarator(); + $$->type = new ast_fully_specified_type(); + $$->type->qualifier = $1.q; + $$->type->specifier = $2; + } + ; + +parameter_qualifier: + /* empty */ { $$.i = 0; } + | IN { $$.i = 0; $$.q.in = 1; } + | OUT { $$.i = 0; $$.q.out = 1; } + | INOUT { $$.i = 0; $$.q.in = 1; $$.q.out = 1; } + ; + +parameter_type_specifier: + type_specifier + ; + +init_declarator_list: + single_declaration + | init_declarator_list ',' IDENTIFIER + { + ast_declaration *decl = new ast_declaration($3, false, NULL, NULL); + + $$ = $1; + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | init_declarator_list ',' IDENTIFIER '[' ']' + { + ast_declaration *decl = new ast_declaration($3, true, NULL, NULL); + + $$ = $1; + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | init_declarator_list ',' IDENTIFIER '[' constant_expression ']' + { + ast_declaration *decl = new ast_declaration($3, true, $5, NULL); + + $$ = $1; + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | init_declarator_list ',' IDENTIFIER '[' ']' '=' initializer + { + ast_declaration *decl = new ast_declaration($3, true, NULL, $7); + + $$ = $1; + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | init_declarator_list ',' IDENTIFIER '[' constant_expression ']' '=' initializer + { + ast_declaration *decl = new ast_declaration($3, true, $5, $8); + + $$ = $1; + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | init_declarator_list ',' IDENTIFIER '=' initializer + { + ast_declaration *decl = new ast_declaration($3, false, NULL, $5); + + $$ = $1; + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + ; + + // Grammar Note: No 'enum', or 'typedef'. +single_declaration: + fully_specified_type + { + $$ = new ast_declarator_list($1); + } + | fully_specified_type IDENTIFIER + { + ast_declaration *decl = new ast_declaration($2, false, NULL, NULL); + + $$ = new ast_declarator_list($1); + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | fully_specified_type IDENTIFIER '[' ']' + { + ast_declaration *decl = new ast_declaration($2, true, NULL, NULL); + + $$ = new ast_declarator_list($1); + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | fully_specified_type IDENTIFIER '[' constant_expression ']' + { + ast_declaration *decl = new ast_declaration($2, true, $4, NULL); + + $$ = new ast_declarator_list($1); + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | fully_specified_type IDENTIFIER '[' ']' '=' initializer + { + ast_declaration *decl = new ast_declaration($2, true, NULL, $6); + + $$ = new ast_declarator_list($1); + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | fully_specified_type IDENTIFIER '[' constant_expression ']' '=' initializer + { + ast_declaration *decl = new ast_declaration($2, true, $4, $7); + + $$ = new ast_declarator_list($1); + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | fully_specified_type IDENTIFIER '=' initializer + { + ast_declaration *decl = new ast_declaration($2, false, NULL, $4); + + $$ = new ast_declarator_list($1); + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + | INVARIANT IDENTIFIER // Vertex only. + { + ast_declaration *decl = new ast_declaration($2, false, NULL, NULL); + + $$ = new ast_declarator_list(NULL); + $$->invariant = true; + + insert_at_tail(& $$->declarations, + (struct simple_node *) decl); + } + ; + +fully_specified_type: + type_specifier + { + $$ = new ast_fully_specified_type(); + $$->specifier = $1; + } + | type_qualifier type_specifier + { + $$ = new ast_fully_specified_type(); + $$->qualifier = $1.q; + $$->specifier = $2; + } + ; + +interpolation_qualifier: + SMOOTH { $$.i = 0; $$.q.smooth = 1; } + | FLAT { $$.i = 0; $$.q.flat = 1; } + | NOPERSPECTIVE { $$.i = 0; $$.q.noperspective = 1; } + ; + +parameter_type_qualifier: + CONST { $$.i = 0; $$.q.constant = 1; } + ; + +type_qualifier: + storage_qualifier + | interpolation_qualifier type_qualifier + { + $$.i = $1.i | $2.i; + } + | INVARIANT type_qualifier + { + $$ = $2; + $$.q.invariant = 1; + } + ; + +storage_qualifier: + CONST { $$.i = 0; $$.q.constant = 1; } + | ATTRIBUTE { $$.i = 0; $$.q.attribute = 1; } + | VARYING { $$.i = 0; $$.q.varying = 1; } + | CENTROID VARYING { $$.i = 0; $$.q.centroid = 1; $$.q.varying = 1; } + | IN { $$.i = 0; $$.q.in = 1; } + | OUT { $$.i = 0; $$.q.out = 1; } + | CENTROID IN { $$.i = 0; $$.q.centroid = 1; $$.q.in = 1; } + | CENTROID OUT { $$.i = 0; $$.q.centroid = 1; $$.q.out = 1; } + | UNIFORM { $$.i = 0; $$.q.uniform = 1; } + ; + +type_specifier: + type_specifier_no_prec + | precision_qualifier type_specifier_no_prec + { + $$ = $2; + $$->precision = $1; + } + ; + +type_specifier_no_prec: + type_specifier_nonarray + | type_specifier_nonarray '[' ']' + { + $$ = $1; + $$->is_array = true; + $$->array_size = NULL; + } + | type_specifier_nonarray '[' constant_expression ']' + { + $$ = $1; + $$->is_array = true; + $$->array_size = $3; + } + ; + +type_specifier_nonarray: + basic_type_specifier_nonarray + { + $$ = new ast_type_specifier($1); + } + | struct_specifier + { + $$ = new ast_type_specifier(ast_struct); + $$->structure = $1; + } + | TYPE_NAME + { + $$ = new ast_type_specifier(ast_type_name); + $$->type_name = $1; + } + ; + +basic_type_specifier_nonarray: + VOID { $$ = ast_void; } + | FLOAT { $$ = ast_float; } + | INT { $$ = ast_int; } + | UINT { $$ = ast_uint; } + | BOOL { $$ = 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; } + | MAT2 { $$ = ast_mat2; } + | MAT3 { $$ = ast_mat3; } + | MAT4 { $$ = ast_mat4; } + | 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; } + | SAMPLER3D { $$ = ast_sampler3d; } + | SAMPLERCUBE { $$ = ast_samplercube; } + | SAMPLER1DSHADOW { $$ = ast_sampler1dshadow; } + | SAMPLER2DSHADOW { $$ = ast_sampler2dshadow; } + | 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; } + ; + +precision_qualifier: + HIGH_PRECISION { $$ = ast_precision_high; } + | MEDIUM_PRECISION { $$ = ast_precision_medium; } + | LOW_PRECISION { $$ = ast_precision_low; } + ; + +struct_specifier: + STRUCT IDENTIFIER '{' struct_declaration_list '}' + { + $$ = new ast_struct_specifier($2, $4); + + _mesa_symbol_table_add_symbol(state->symbols, 0, $2, $$); + } + | STRUCT '{' struct_declaration_list '}' + { + $$ = new ast_struct_specifier(NULL, $3); + } + ; + +struct_declaration_list: + struct_declaration + { + $$ = (struct ast_node *) $1; + } + | struct_declaration_list struct_declaration + { + $$ = (struct ast_node *) $1; + insert_at_tail((struct simple_node *) $$, + (struct simple_node *) $2); + } + ; + +struct_declaration: + type_specifier struct_declarator_list ';' + { + ast_fully_specified_type *type = new ast_fully_specified_type(); + + type->specifier = $1; + $$ = new ast_declarator_list(type); + + insert_at_tail((struct simple_node *) $2, + & $$->declarations); + } + ; + +struct_declarator_list: + struct_declarator + | struct_declarator_list ',' struct_declarator + { + $$ = $1; + insert_at_tail((struct simple_node *) $$, + (struct simple_node *) $3); + } + ; + +struct_declarator: + IDENTIFIER + { + $$ = new ast_declaration($1, false, NULL, NULL); + } + | IDENTIFIER '[' constant_expression ']' + { + $$ = new ast_declaration($1, true, $3, NULL); + } + ; + +initializer: + assignment_expression + ; + +declaration_statement: + declaration + ; + + // Grammar Note: labeled statements for SWITCH only; 'goto' is not + // supported. +statement: + statement_matched + | statement_unmatched + ; + +statement_matched: + compound_statement { $$ = (struct ast_node *) $1; } + | simple_statement + ; + +statement_unmatched: + selection_statement_unmatched + ; + +simple_statement: + declaration_statement + | expression_statement + | selection_statement_matched + | switch_statement { $$ = NULL; } + | case_label { $$ = NULL; } + | iteration_statement + | jump_statement + ; + +compound_statement: + '{' '}' + { + $$ = new ast_compound_statement(true, NULL); + } + | '{' statement_list '}' + { + $$ = new ast_compound_statement(true, $2); + } + ; + +statement_no_new_scope: + compound_statement_no_new_scope { $$ = (struct ast_node *) $1; } + | simple_statement + ; + +compound_statement_no_new_scope: + '{' '}' + { + $$ = new ast_compound_statement(false, NULL); + } + | '{' statement_list '}' + { + $$ = new ast_compound_statement(false, $2); + } + ; + +statement_list: + statement + { + if ($1 == NULL) { + _mesa_glsl_error(& @1, state, " statement\n"); + assert($1 != NULL); + } + + $$ = $1; + make_empty_list((struct simple_node *) $$); + } + | statement_list statement + { + if ($2 == NULL) { + _mesa_glsl_error(& @2, state, " statement\n"); + assert($2 != NULL); + } + $$ = $1; + insert_at_tail((struct simple_node *) $$, + (struct simple_node *) $2); + } + ; + +expression_statement: + ';' + { + $$ = new ast_expression_statement(NULL); + } + | expression ';' + { + $$ = new ast_expression_statement($1); + } + ; + +selection_statement_matched: + IF '(' expression ')' statement_matched ELSE statement_matched + { + $$ = new ast_selection_statement($3, $5, $7); + } + ; + +selection_statement_unmatched: + IF '(' expression ')' statement_matched + { + $$ = new ast_selection_statement($3, $5, NULL); + } + | IF '(' expression ')' statement_unmatched + { + $$ = new ast_selection_statement($3, $5, NULL); + } + | IF '(' expression ')' statement_matched ELSE statement_unmatched + { + $$ = new ast_selection_statement($3, $5, $7); + } + ; + +condition: + expression + { + $$ = (struct ast_node *) $1; + } + | fully_specified_type IDENTIFIER '=' initializer + { + ast_declaration *decl = new ast_declaration($2, false, NULL, $4); + ast_declarator_list *declarator = new ast_declarator_list($1); + + insert_at_tail(& declarator->declarations, + (struct simple_node *) decl); + + $$ = declarator; + } + ; + +switch_statement: + SWITCH '(' expression ')' compound_statement + ; + +case_label: + CASE expression ':' + | DEFAULT ':' + ; + +iteration_statement: + WHILE '(' condition ')' statement_no_new_scope + { + $$ = new ast_iteration_statement(ast_iteration_statement::ast_while, + NULL, $3, NULL, $5); + } + | DO statement WHILE '(' expression ')' ';' + { + $$ = new ast_iteration_statement(ast_iteration_statement::ast_do_while, + NULL, $5, NULL, $2); + } + | FOR '(' for_init_statement for_rest_statement ')' statement_no_new_scope + { + $$ = new ast_iteration_statement(ast_iteration_statement::ast_for, + $3, $4.cond, $4.rest, $6); + } + ; + +for_init_statement: + expression_statement + | declaration_statement + ; + +conditionopt: + condition + | /* empty */ + { + $$ = NULL; + } + ; + +for_rest_statement: + conditionopt ';' + { + $$.cond = $1; + $$.rest = NULL; + } + | conditionopt ';' expression + { + $$.cond = $1; + $$.rest = $3; + } + ; + + // Grammar Note: No 'goto'. Gotos are not supported. +jump_statement: + CONTINUE ';' + { + $$ = new ast_jump_statement(ast_jump_statement::ast_continue, NULL); + } + | BREAK ';' + { + $$ = new ast_jump_statement(ast_jump_statement::ast_break, NULL); + } + | RETURN ';' + { + $$ = new ast_jump_statement(ast_jump_statement::ast_return, NULL); + } + | RETURN expression ';' + { + $$ = new ast_jump_statement(ast_jump_statement::ast_return, $2); + } + | DISCARD ';' // Fragment shader only. + { + $$ = new ast_jump_statement(ast_jump_statement::ast_discard, NULL); + } + ; + +external_declaration: + function_definition { $$ = $1; } + | declaration { $$ = $1; } + ; + +function_definition: + function_prototype compound_statement_no_new_scope + { + $$ = new ast_function_definition(); + $$->prototype = $1; + $$->body = $2; + } + ; diff --git a/glsl_parser_extras.cc b/glsl_parser_extras.cc new file mode 100644 index 00000000000..679b600fb3c --- /dev/null +++ b/glsl_parser_extras.cc @@ -0,0 +1,771 @@ +/* + * Copyright © 2008, 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. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ast.h" +#include "glsl_parser_extras.h" +#include "glsl_parser.tab.h" +#include "symbol_table.h" + +void +_mesa_glsl_error(YYLTYPE *locp, void *state, const char *fmt, ...) +{ + char buf[1024]; + int len; + va_list ap; + + (void) state; + len = snprintf(buf, sizeof(buf), "%u:%u(%u): error: ", + locp->source, locp->first_line, locp->first_column); + + va_start(ap, fmt); + vsnprintf(buf + len, sizeof(buf) - len, fmt, ap); + va_end(ap); + + printf("%s\n", buf); +} + + +ast_node::~ast_node() +{ + /* empty */ +} + + +void +_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q) +{ + if (q->constant) + printf("const "); + + if (q->invariant) + printf("invariant "); + + if (q->attribute) + printf("attribute "); + + if (q->varying) + printf("varying "); + + if (q->in && q->out) + printf("inout "); + else { + if (q->in) + printf("in "); + + if (q->out) + printf("out "); + } + + if (q->centroid) + printf("centroid "); + if (q->uniform) + printf("uniform "); + if (q->smooth) + printf("smooth "); + if (q->flat) + printf("flat "); + if (q->noperspective) + printf("noperspective "); +} + + +void +ast_node::print(void) const +{ + printf("node_%d ", type); +} + + +ast_node::ast_node(void) +{ +// make_empty_list(& ast->node); +} + +void +ast_type_specifier::print(void) const +{ + switch (type_specifier) { + case ast_void: printf("void "); break; + case ast_float: printf("float "); break; + case ast_int: printf("int "); break; + case ast_uint: printf("uint "); break; + case ast_bool: printf("bool "); break; + case ast_vec2: printf("vec2 "); break; + case ast_vec3: printf("vec3 "); break; + case ast_vec4: printf("vec4 "); break; + case ast_bvec2: printf("bvec2 "); break; + case ast_bvec3: printf("bvec3 "); break; + case ast_bvec4: printf("bvec4 "); break; + case ast_ivec2: printf("ivec2 "); break; + case ast_ivec3: printf("ivec3 "); break; + case ast_ivec4: printf("ivec4 "); break; + case ast_uvec2: printf("uvec2 "); break; + case ast_uvec3: printf("uvec3 "); break; + case ast_uvec4: printf("uvec4 "); break; + case ast_mat2: printf("mat2 "); break; + case ast_mat2x3: printf("mat2x3 "); break; + case ast_mat2x4: printf("mat2x4 "); break; + case ast_mat3x2: printf("mat3x2 "); break; + case ast_mat3: printf("mat3 "); break; + case ast_mat3x4: printf("mat3x4 "); break; + case ast_mat4x2: printf("mat4x2 "); break; + case ast_mat4x3: printf("mat4x3 "); break; + case ast_mat4: printf("mat4 "); break; + case ast_sampler1d: printf("sampler1d "); break; + case ast_sampler2d: printf("sampler2d "); break; + case ast_sampler3d: printf("sampler3d "); break; + case ast_samplercube: printf("samplercube "); break; + case ast_sampler1dshadow: printf("sampler1dshadow "); break; + case ast_sampler2dshadow: printf("sampler2dshadow "); break; + case ast_samplercubeshadow: printf("samplercubeshadow "); break; + case ast_sampler1darray: printf("sampler1darray "); break; + case ast_sampler2darray: printf("sampler2darray "); break; + case ast_sampler1darrayshadow: printf("sampler1darrayshadow "); break; + case ast_sampler2darrayshadow: printf("sampler2darrayshadow "); break; + case ast_isampler1d: printf("isampler1d "); break; + case ast_isampler2d: printf("isampler2d "); break; + case ast_isampler3d: printf("isampler3d "); break; + case ast_isamplercube: printf("isamplercube "); break; + case ast_isampler1darray: printf("isampler1darray "); break; + case ast_isampler2darray: printf("isampler2darray "); break; + case ast_usampler1d: printf("usampler1d "); break; + case ast_usampler2d: printf("usampler2d "); break; + case ast_usampler3d: printf("usampler3d "); break; + case ast_usamplercube: printf("usamplercube "); break; + case ast_usampler1darray: printf("usampler1darray "); break; + case ast_usampler2darray: printf("usampler2darray "); break; + + case ast_struct: + structure->print(); + break; + + case ast_type_name: printf("%s ", type_name); break; + } + + if (is_array) { + printf("[ "); + + if (array_size) { + array_size->print(); + } + + printf("] "); + } +} + +static void +ast_opt_array_size_print(bool is_array, const ast_expression *array_size) +{ + if (is_array) { + printf("[ "); + + if (array_size) + array_size->print(); + + printf("] "); + } +} + + +ast_type_specifier::ast_type_specifier(int specifier) +{ + type_specifier = ast_types(specifier); +} + + +void +ast_compound_statement::print(void) const +{ + const struct simple_node *ptr; + + printf("{\n"); + + foreach(ptr, & statements) { + _mesa_ast_print(ptr); + } + + printf("}\n"); +} + + +ast_compound_statement::ast_compound_statement(int new_scope, + ast_node *statements) +{ + this->new_scope = new_scope; + make_empty_list(& this->statements); + + if (statements != NULL) { + /* This seems odd, but it works. The simple_list is, + * basically, a circular list. insert_at_tail adds + * the specified node to the list before the current + * head. + */ + insert_at_tail((struct simple_node *) statements, + & this->statements); + } +} + + +void +ast_expression::print(void) const +{ + static const char *const operators[] = { + "=", + "+", + "-", + "+", + "-", + "*", + "/", + "%", + "<<", + ">>", + "<", + ">", + "<=", + ">=", + "==", + "!=", + "&", + "^", + "|", + "~", + "&&", + "^^", + "!", + + "*=", + "/=", + "%=", + "+=", + "-=", + "<<=", + ">>=", + "&=", + "^=", + "|=", + + "?:", + "++", + "--", + "++", + "--", + ".", + }; + + + switch (oper) { + case ast_assign: + case ast_add: + case ast_sub: + case ast_mul: + case ast_div: + case ast_mod: + case ast_lshift: + case ast_rshift: + case ast_less: + case ast_greater: + case ast_lequal: + case ast_gequal: + case ast_equal: + case ast_nequal: + case ast_bit_and: + case ast_bit_xor: + case ast_bit_or: + case ast_logic_and: + case ast_logic_xor: + case ast_logic_or: + case ast_mul_assign: + case ast_div_assign: + case ast_mod_assign: + case ast_add_assign: + case ast_sub_assign: + case ast_ls_assign: + case ast_rs_assign: + case ast_and_assign: + case ast_xor_assign: + case ast_or_assign: + subexpressions[0]->print(); + printf("%s ", operators[oper]); + subexpressions[1]->print(); + break; + + case ast_field_selection: + subexpressions[0]->print(); + printf(". %s ", primary_expression.identifier); + break; + + case ast_plus: + case ast_neg: + case ast_bit_not: + case ast_logic_not: + case ast_pre_inc: + case ast_pre_dec: + printf("%s ", operators[oper]); + subexpressions[0]->print(); + break; + + case ast_post_inc: + case ast_post_dec: + subexpressions[0]->print(); + printf("%s ", operators[oper]); + break; + + case ast_conditional: + subexpressions[0]->print(); + printf("? "); + subexpressions[1]->print(); + printf(": "); + subexpressions[1]->print(); + break; + + case ast_array_index: + subexpressions[0]->print(); + printf("[ "); + subexpressions[1]->print(); + printf("] "); + break; + + case ast_function_call: { + ast_expression *parameters = subexpressions[1]; + + subexpressions[0]->print(); + printf("( "); + + if (parameters != NULL) { + struct simple_node *ptr; + + parameters->print(); + foreach (ptr, (struct simple_node *) parameters) { + printf(", "); + _mesa_ast_print(ptr); + } + } + + printf(") "); + break; + } + + case ast_identifier: + printf("%s ", primary_expression.identifier); + break; + + case ast_int_constant: + printf("%d ", primary_expression.int_constant); + break; + + case ast_uint_constant: + printf("%u ", primary_expression.uint_constant); + break; + + case ast_float_constant: + printf("%f ", primary_expression.float_constant); + break; + + case ast_bool_constant: + printf("%s ", + primary_expression.bool_constant + ? "true" : "false"); + break; + + case ast_sequence: { + struct simple_node *ptr; + struct simple_node *const head = first_elem(& expressions); + + printf("( "); + foreach (ptr, & expressions) { + if (ptr != head) + printf(", "); + + _mesa_ast_print(ptr); + } + printf(") "); + break; + } + } +} + +ast_expression::ast_expression(int oper, + ast_expression *ex0, + ast_expression *ex1, + ast_expression *ex2) +{ + this->oper = ast_operators(oper); + this->subexpressions[0] = ex0; + this->subexpressions[1] = ex1; + this->subexpressions[2] = ex2; + make_empty_list(& expressions); +} + + +void +ast_expression_statement::print(void) const +{ + if (expression) + expression->print(); + + printf("; "); +} + + +ast_expression_statement::ast_expression_statement(ast_expression *ex) : + expression(ex) +{ + /* empty */ +} + + +void +ast_function::print(void) const +{ + struct simple_node *ptr; + + return_type->print(); + printf(" %s (", identifier); + + foreach(ptr, & parameters) { + _mesa_ast_print(ptr); + } + + printf(")"); +} + + +ast_function::ast_function(void) +{ + make_empty_list(& parameters); +} + + +void +ast_fully_specified_type::print(void) const +{ + _mesa_ast_type_qualifier_print(& qualifier); + specifier->print(); +} + + +void +ast_parameter_declarator::print(void) const +{ + type->print(); + if (identifier) + printf("%s ", identifier); + ast_opt_array_size_print(is_array, array_size); +} + + +void +ast_function_definition::print(void) const +{ + prototype->print(); + body->print(); +} + + +void +ast_declaration::print(void) const +{ + printf("%s ", identifier); + ast_opt_array_size_print(is_array, array_size); + + if (initializer) { + printf("= "); + initializer->print(); + } +} + + +ast_declaration::ast_declaration(char *identifier, int is_array, + ast_expression *array_size, + ast_expression *initializer) +{ + this->identifier = identifier; + this->is_array = is_array; + this->array_size = array_size; + this->initializer = initializer; +} + + +void +ast_declarator_list::print(void) const +{ + struct simple_node *head; + struct simple_node *ptr; + + assert(type || invariant); + + if (type) + type->print(); + else + printf("invariant "); + + head = first_elem(& declarations); + foreach (ptr, & declarations) { + if (ptr != head) + printf(", "); + + _mesa_ast_print(ptr); + } + + printf("; "); +} + + +ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type) +{ + this->type = type; + make_empty_list(& this->declarations); +} + +void +ast_jump_statement::print(void) const +{ + switch (mode) { + case ast_continue: + printf("continue; "); + break; + case ast_break: + printf("break; "); + break; + case ast_return: + printf("return "); + if (opt_return_value) + opt_return_value->print(); + + printf("; "); + break; + case ast_discard: + printf("discard; "); + break; + } +} + + +ast_jump_statement::ast_jump_statement(int mode, ast_expression *return_value) +{ + this->mode = ast_jump_modes(mode); + + if (mode == ast_return) + opt_return_value = return_value; +} + + +void +ast_selection_statement::print(void) const +{ + printf("if ( "); + condition->print(); + printf(") "); + + then_statement->print(); + + if (else_statement) { + printf("else "); + else_statement->print(); + } + +} + + +ast_selection_statement::ast_selection_statement(ast_expression *condition, + ast_node *then_statement, + ast_node *else_statement) +{ + this->condition = condition; + this->then_statement = then_statement; + this->else_statement = else_statement; +} + + +void +ast_iteration_statement::print(void) const +{ + switch (mode) { + case ast_for: + printf("for( "); + if (init_statement) + init_statement->print(); + printf("; "); + + if (condition) + condition->print(); + printf("; "); + + if (rest_expression) + rest_expression->print(); + printf(") "); + + body->print(); + break; + + case ast_while: + printf("while ( "); + if (condition) + condition->print(); + printf(") "); + body->print(); + break; + + case ast_do_while: + printf("do "); + body->print(); + printf("while ( "); + if (condition) + condition->print(); + printf("); "); + break; + } +} + + +ast_iteration_statement::ast_iteration_statement(int mode, + ast_node *init, + ast_node *condition, + ast_expression *rest_expression, + ast_node *body) +{ + this->mode = ast_iteration_modes(mode); + this->init_statement = init; + this->condition = condition; + this->rest_expression = rest_expression; + this->body = body; +} + + +void +ast_struct_specifier::print(void) const +{ + struct simple_node *ptr; + + printf("struct %s { ", name); + foreach (ptr, & declarations) { + _mesa_ast_print(ptr); + } + printf("} "); +} + + +ast_struct_specifier::ast_struct_specifier(char *identifier, + ast_node *declarator_list) +{ + name = identifier; + + /* This seems odd, but it works. The simple_list is, + * basically, a circular list. insert_at_tail adds + * the specified node to the list before the current + * head. + */ + insert_at_tail((struct simple_node *) declarator_list, + & declarations); +} + + +static char * +load_text_file(const char *file_name, size_t *size) +{ + char *text = NULL; + struct stat st; + ssize_t total_read = 0; + int fd = open(file_name, O_RDONLY); + + *size = 0; + if (fd < 0) { + return NULL; + } + + if (fstat(fd, & st) == 0) { + text = (char *) malloc(st.st_size + 1); + if (text != NULL) { + do { + ssize_t bytes = read(fd, text + total_read, + st.st_size - total_read); + if (bytes < 0) { + free(text); + text = NULL; + break; + } + + if (bytes == 0) { + break; + } + + total_read += bytes; + } while (total_read < st.st_size); + + text[total_read] = '\0'; + *size = total_read; + } + } + + close(fd); + + return text; +} + + +int +main(int argc, char **argv) +{ + struct _mesa_glsl_parse_state state; + char *shader; + size_t shader_len; + struct simple_node *ptr; + struct simple_node instructions; + + (void) argc; + shader = load_text_file(argv[1], & shader_len); + + state.scanner = NULL; + make_empty_list(& state.translation_unit); + state.symbols = _mesa_symbol_table_ctor(); + + _mesa_glsl_lexer_ctor(& state, shader, shader_len); + _mesa_glsl_parse(& state); + _mesa_glsl_lexer_dtor(& state); + + foreach (ptr, & state.translation_unit) { + _mesa_ast_print(ptr); + } + +#if 0 + make_empty_list(& instructions); + foreach (ptr, & state.translation_unit) { + _mesa_ast_to_hir(ptr, &instructions, &state); + } +#endif + + _mesa_symbol_table_dtor(state.symbols); + + return 0; +} diff --git a/glsl_parser_extras.h b/glsl_parser_extras.h new file mode 100644 index 00000000000..932c12d8410 --- /dev/null +++ b/glsl_parser_extras.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#pragma once +#ifndef GLSL_PARSER_EXTRAS_H +#define GLSL_PARSER_EXTRAS_H + +#include "main/simple_list.h" + +enum _mesa_glsl_parser_targets { + vertex_shader, + geometry_shader, + fragment_shader +}; + +struct _mesa_glsl_parse_state { + void *scanner; + struct simple_node translation_unit; + struct _mesa_symbol_table *symbols; + + unsigned language_version; + enum _mesa_glsl_parser_targets target; +}; + +typedef struct YYLTYPE { + int first_line; + int first_column; + int last_line; + int last_column; + unsigned source; +} YYLTYPE; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 + +extern void _mesa_glsl_error(YYLTYPE *locp, void *state, const char *fmt, ...); + +extern void _mesa_glsl_lexer_ctor(struct _mesa_glsl_parse_state *state, + const char *string, size_t len); + +extern void _mesa_glsl_lexer_dtor(struct _mesa_glsl_parse_state *state); + +union YYSTYPE; +extern int _mesa_glsl_lex(union YYSTYPE *yylval, YYLTYPE *yylloc, + void *scanner); + +extern int _mesa_glsl_parse(struct _mesa_glsl_parse_state *); + +#endif /* GLSL_PARSER_EXTRAS_H */ diff --git a/glsl_types.c b/glsl_types.c new file mode 100644 index 00000000000..89732180175 --- /dev/null +++ b/glsl_types.c @@ -0,0 +1,159 @@ +/* + * 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. + */ + +#include +#include "symbol_table.h" +#include "glsl_parser_extras.h" +#include "glsl_types.h" +#include "builtin_types.h" + + +struct glsl_type * +_mesa_glsl_array_type_ctor(struct glsl_type *base, unsigned length, + const char *name) +{ + struct glsl_type *type = calloc(1, sizeof(*type)); + + type->base_type = GLSL_TYPE_ARRAY; + type->name = name; + type->length = length; + type->fields.array = base; + + return type; +} + + +static void +add_types_to_symbol_table(struct _mesa_symbol_table *symtab, + const struct glsl_type *types, + unsigned num_types) +{ + unsigned i; + + for (i = 0; i < num_types; i++) { + _mesa_symbol_table_add_symbol(symtab, 0, types[i].name, + (void *) & types[i]); + } +} + + +static void +generate_110_types(struct _mesa_symbol_table *symtab) +{ + add_types_to_symbol_table(symtab, builtin_core_types, + Elements(builtin_core_types)); + add_types_to_symbol_table(symtab, builtin_structure_types, + Elements(builtin_structure_types)); + add_types_to_symbol_table(symtab, builtin_110_deprecated_structure_types, + Elements(builtin_110_deprecated_structure_types)); +} + + +static void +generate_120_types(struct _mesa_symbol_table *symtab) +{ + generate_110_types(symtab); + + add_types_to_symbol_table(symtab, builtin_120_types, + Elements(builtin_120_types)); +} + + +static void +generate_130_types(struct _mesa_symbol_table *symtab) +{ + generate_120_types(symtab); + + add_types_to_symbol_table(symtab, builtin_130_types, + Elements(builtin_130_types)); +} + + +void +_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state) +{ + switch (state->language_version) { + case 110: + generate_110_types(state->symbols); + break; + case 120: + generate_120_types(state->symbols); + break; + case 130: + generate_130_types(state->symbols); + break; + default: + /* error */ + break; + } +} + + +const struct glsl_type * +_mesa_glsl_get_vector_type(unsigned base_type, unsigned vector_length) +{ + switch (base_type) { + case GLSL_TYPE_UINT: + switch (vector_length) { + case 1: + case 2: + case 3: + case 4: + return glsl_uint_type + (vector_length - 1); + default: + return glsl_error_type; + } + case GLSL_TYPE_INT: + switch (vector_length) { + case 1: + case 2: + case 3: + case 4: + return glsl_int_type + (vector_length - 1); + default: + return glsl_error_type; + } + case GLSL_TYPE_FLOAT: + switch (vector_length) { + case 1: + case 2: + case 3: + case 4: + return glsl_float_type + (vector_length - 1); + default: + return glsl_error_type; + } + case GLSL_TYPE_BOOL: + switch (vector_length) { + case 1: + case 2: + case 3: + case 4: + return glsl_bool_type + (vector_length - 1); + default: + return glsl_error_type; + } + default: + return glsl_error_type; + } +} diff --git a/glsl_types.h b/glsl_types.h new file mode 100644 index 00000000000..c69da956224 --- /dev/null +++ b/glsl_types.h @@ -0,0 +1,141 @@ +/* + * 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 + +#define GLSL_TYPE_UINT 0 +#define GLSL_TYPE_INT 1 +#define GLSL_TYPE_FLOAT 2 +#define GLSL_TYPE_BOOL 3 +#define GLSL_TYPE_SAMPLER 4 +#define GLSL_TYPE_STRUCT 5 +#define GLSL_TYPE_ARRAY 6 +#define GLSL_TYPE_FUNCTION 7 +#define GLSL_TYPE_VOID 8 +#define GLSL_TYPE_ERROR 9 + +#define is_numeric_base_type(b) \ + (((b) >= GLSL_TYPE_UINT) && ((b) <= GLSL_TYPE_FLOAT)) + +#define is_integer_base_type(b) \ + (((b) == GLSL_TYPE_UINT) || ((b) == GLSL_TYPE_INT)) + +#define is_error_type(t) ((t)->base_type == GLSL_TYPE_ERROR) + +#define GLSL_SAMPLER_DIM_1D 0 +#define GLSL_SAMPLER_DIM_2D 1 +#define GLSL_SAMPLER_DIM_3D 2 +#define GLSL_SAMPLER_DIM_CUBE 3 +#define GLSL_SAMPLER_DIM_RECT 4 +#define GLSL_SAMPLER_DIM_BUF 5 + + +struct glsl_type { + unsigned base_type:4; + + unsigned sampler_dimensionality:3; + 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. + */ + + unsigned vector_elements:3; /**< 0, 2, 3, or 4 vector elements. */ + unsigned matrix_rows:3; /**< 0, 2, 3, or 4 matrix rows. */ + + /** + * 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). + * + * For \c GLSL_TYPE_FUNCTION, it is the number of parameters to the + * function. The return value from a function is implicitly the first + * parameter. The types of the parameters are stored in + * \c fields.parameters (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. */ + const struct glsl_struct_field *structure;/**< List of struct fields. */ + } fields; +}; + +#define is_glsl_type_scalar(t) \ + (((t)->vector_elements == 0) \ + && ((t)->base_type >= GLSL_TYPE_UINT) \ + && ((t)->base_type <= GLSL_TYPE_BOOL)) + +#define is_glsl_type_vector(t) \ + (((t)->vector_elements > 0) \ + && ((t)->matrix_rows == 0) \ + && ((t)->base_type >= GLSL_TYPE_UINT) \ + && ((t)->base_type <= GLSL_TYPE_BOOL)) + +#define is_glsl_type_matrix(t) \ + (((t)->matrix_rows > 0) \ + && ((t)->base_type == GLSL_TYPE_FLOAT)) /* GLSL only has float matrices. */ + +struct glsl_struct_field { + const struct glsl_type *type; + const char *name; +}; + +struct _mesa_glsl_parse_state; + +#ifdef __cplusplus +extern "C" { +#endif + +extern void +_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state); + +extern const struct glsl_type * +_mesa_glsl_get_vector_type(unsigned base_type, unsigned vector_length); + +extern const struct glsl_type *const glsl_error_type; +extern const struct glsl_type *const glsl_int_type; +extern const struct glsl_type *const glsl_uint_type; +extern const struct glsl_type *const glsl_float_type; +extern const struct glsl_type *const glsl_bool_type; + +#ifdef __cplusplus +} +#endif + +#endif /* GLSL_TYPES_H */ diff --git a/hash_table.c b/hash_table.c new file mode 100644 index 00000000000..e89a2564d76 --- /dev/null +++ b/hash_table.c @@ -0,0 +1,159 @@ +/* + * Copyright © 2008 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 hash_table.c + * \brief Implementation of a generic, opaque hash table data type. + * + * \author Ian Romanick + */ + +#include "main/imports.h" +#include "main/simple_list.h" +#include "hash_table.h" + +struct node { + struct node *next; + struct node *prev; +}; + +struct hash_table { + hash_func_t hash; + hash_compare_func_t compare; + + unsigned num_buckets; + struct node buckets[1]; +}; + + +struct hash_node { + struct node link; + const void *key; + void *data; +}; + + +struct hash_table * +hash_table_ctor(unsigned num_buckets, hash_func_t hash, + hash_compare_func_t compare) +{ + struct hash_table *ht; + unsigned i; + + + if (num_buckets < 16) { + num_buckets = 16; + } + + ht = _mesa_malloc(sizeof(*ht) + ((num_buckets - 1) + * sizeof(ht->buckets[0]))); + if (ht != NULL) { + ht->hash = hash; + ht->compare = compare; + ht->num_buckets = num_buckets; + + for (i = 0; i < num_buckets; i++) { + make_empty_list(& ht->buckets[i]); + } + } + + return ht; +} + + +void +hash_table_dtor(struct hash_table *ht) +{ + hash_table_clear(ht); + _mesa_free(ht); +} + + +void +hash_table_clear(struct hash_table *ht) +{ + struct node *node; + struct node *temp; + unsigned i; + + + for (i = 0; i < ht->num_buckets; i++) { + foreach_s(node, temp, & ht->buckets[i]) { + remove_from_list(node); + _mesa_free(node); + } + + assert(is_empty_list(& ht->buckets[i])); + } +} + + +void * +hash_table_find(struct hash_table *ht, const void *key) +{ + const unsigned hash_value = (*ht->hash)(key); + const unsigned bucket = hash_value % ht->num_buckets; + struct node *node; + + foreach(node, & ht->buckets[bucket]) { + struct hash_node *hn = (struct hash_node *) node; + + if ((*ht->compare)(hn->key, key) == 0) { + return hn->data; + } + } + + return NULL; +} + + +void +hash_table_insert(struct hash_table *ht, void *data, const void *key) +{ + const unsigned hash_value = (*ht->hash)(key); + const unsigned bucket = hash_value % ht->num_buckets; + struct hash_node *node; + + node = _mesa_calloc(sizeof(*node)); + + node->data = data; + node->key = key; + + insert_at_head(& ht->buckets[bucket], & node->link); +} + + +unsigned +hash_table_string_hash(const void *key) +{ + const char *str = (const char *) key; + unsigned hash = 5381; + + + while (*str != '\0') { + hash = (hash * 33) + *str; + str++; + } + + return hash; +} diff --git a/hash_table.h b/hash_table.h new file mode 100644 index 00000000000..7b302f5dbee --- /dev/null +++ b/hash_table.h @@ -0,0 +1,117 @@ +/* + * Copyright © 2008 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 hash_table.h + * \brief Implementation of a generic, opaque hash table data type. + * + * \author Ian Romanick + */ + +#ifndef HASH_TABLE_H +#define HASH_TABLE_H + +#include + +struct hash_table; + +typedef unsigned (*hash_func_t)(const void *key); +typedef int (*hash_compare_func_t)(const void *key1, const void *key2); + +/** + * Hash table constructor + * + * Creates a hash table with the specified number of buckets. The supplied + * \c hash and \c compare routines are used when adding elements to the table + * and when searching for elements in the table. + * + * \param num_buckets Number of buckets (bins) in the hash table. + * \param hash Function used to compute hash value of input keys. + * \param compare Function used to compare keys. + */ +extern struct hash_table *hash_table_ctor(unsigned num_buckets, + hash_func_t hash, hash_compare_func_t compare); + + +/** + * Release all memory associated with a hash table + * + * \warning + * This function cannot release memory occupied either by keys or data. + */ +extern void hash_table_dtor(struct hash_table *ht); + + +/** + * Flush all entries from a hash table + * + * \param ht Table to be cleared of its entries. + */ +extern void hash_table_clear(struct hash_table *ht); + + +/** + * Search a hash table for a specific element + * + * \param ht Table to be searched + * \param key Key of the desired element + * + * \return + * The \c data value supplied to \c hash_table_insert when the element with + * the matching key was added. If no matching key exists in the table, + * \c NULL is returned. + */ +extern void *hash_table_find(struct hash_table *ht, const void *key); + + +/** + * Add an element to a hash table + */ +extern void hash_table_insert(struct hash_table *ht, void *data, + const void *key); + + +/** + * Compute hash value of a string + * + * Computes the hash value of a string using the DJB2 algorithm developed by + * Professor Daniel J. Bernstein. It was published on comp.lang.c once upon + * a time. I was unable to find the original posting in the archives. + * + * \param key Pointer to a NUL terminated string to be hashed. + * + * \sa hash_table_string_compare + */ +extern unsigned hash_table_string_hash(const void *key); + + +/** + * Compare two strings used as keys + * + * This is just a macro wrapper around \c strcmp. + * + * \sa hash_table_string_hash + */ +#define hash_table_string_compare ((hash_compare_func_t) strcmp) + +#endif /* HASH_TABLE_H */ diff --git a/hir_field_selection.cc b/hir_field_selection.cc new file mode 100644 index 00000000000..295cbaf8949 --- /dev/null +++ b/hir_field_selection.cc @@ -0,0 +1,187 @@ +/* + * 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. + */ +#include +#include "main/imports.h" +#include "symbol_table.h" +#include "glsl_parser_extras.h" +#include "ast.h" +#include "glsl_types.h" +#include "ir.h" + +#define X 1 +#define R 5 +#define S 9 +#define I 13 + +static bool +generate_swizzle(const char *str, struct ir_swizzle_mask *swiz, + unsigned vector_length) +{ + /* For each possible swizzle character, this table encodes the value in + * \c idx_map that represents the 0th element of the vector. For invalid + * swizzle characters (e.g., 'k'), a special value is used that will allow + * detection of errors. + */ + unsigned char base_idx[26] = { + /* a b c d e f g h i j k l m */ + R, R, I, I, I, I, R, I, I, I, I, I, I, + /* n o p q r s t u v w x y z */ + I, I, S, S, R, S, S, I, I, X, X, X, X + }; + + /* Each valid swizzle character has an entry in the previous table. This + * table encodes the base index encoded in the previous table plus the actual + * index of the swizzle character. When processing swizzles, the first + * character in the string is indexed in the previous table. Each character + * in the string is indexed in this table, and the value found there has the + * value form the first table subtracted. The result must be on the range + * [0,3]. + * + * For example, the string "wzyx" will get X from the first table. Each of + * the charcaters will get X+3, X+2, X+1, and X+0 from this table. After + * subtraction, the swizzle values are { 3, 2, 1, 0 }. + * + * The string "wzrg" will get X from the first table. Each of the characters + * will get X+3, X+2, R+0, and R+1 from this table. After subtraction, the + * swizzle values are { 3, 2, 4, 5 }. Since 4 and 5 are outside the range + * [0,3], the error is detected. + */ + unsigned char idx_map[26] = { + /* a b c d e f g h i j k l m */ + R+3, R+2, 0, 0, 0, 0, R+1, 0, 0, 0, 0, 0, 0, + /* n o p q r s t u v w x y z */ + 0, 0, S+2, S+3, R+0, S+0, S+1, 0, 0, X+3, X+0, X+1, X+2 + }; + + int swiz_idx[4] = { 0, 0, 0, 0 }; + unsigned base; + unsigned dup_mask = 0; + unsigned seen_mask = 0; + unsigned i; + + + /* Validate the first character in the swizzle string and look up the base + * index value as described above. + */ + if ((str[0] < 'a') || (str[0] > 'z')) + return FALSE; + + base = base_idx[str[0] - 'a']; + + + for (i = 0; (i < 4) && (str[i] != '\0'); i++) { + unsigned bit; + + /* Validate the next character, and, as described above, convert it to a + * swizzle index. + */ + if ((str[i] < 'a') || (str[i] > 'z')) + return FALSE; + + swiz_idx[i] = idx_map[str[0] - 'a'] - base; + if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length)) + return FALSE; + + + /* Track a bit-mask of the swizzle index values that have been seen. If + * a value is seen more than once, set the "duplicate" flag. + */ + bit = (1U << swiz_idx[i]); + dup_mask |= seen_mask & bit; + seen_mask |= bit; + } + + if (str[i] != '\0') + return FALSE; + + swiz->x = swiz_idx[0]; + swiz->y = swiz_idx[1]; + swiz->z = swiz_idx[2]; + swiz->w = swiz_idx[3]; + swiz->num_components = i; + swiz->has_duplicates = (dup_mask != 0); + + return TRUE; +} + + +struct ir_instruction * +_mesa_ast_field_selection_to_hir(const ast_expression *expr, + simple_node *instructions, + struct _mesa_glsl_parse_state *state) +{ + ir_instruction *op; + ir_dereference *deref; + YYLTYPE loc; + + + op = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state); + deref = new ir_dereference(op); + + /* Initially assume that the resulting type of the field selection is an + * error. This make the error paths below a bit easier to follow. + */ + deref->type = glsl_error_type; + + /* If processing the thing being dereferenced generated an error, bail out + * now. Doing so prevents spurious error messages from being logged below. + */ + if (is_error_type(op->type)) + return (struct ir_instruction *) deref; + + /* There are two kinds of field selection. There is the selection of a + * specific field from a structure, and there is the selection of a + * swizzle / mask from a vector. Which is which is determined entirely + * by the base type of the thing to which the field selection operator is + * being applied. + */ + _mesa_ast_get_location(expr, & loc); + if (is_glsl_type_vector(op->type)) { + if (generate_swizzle(expr->primary_expression.identifier, + & deref->selector.swizzle, + op->type->vector_elements)) { + /* Based on the number of elements in the swizzle and the base type + * (i.e., float, int, unsigned, or bool) of the vector being swizzled, + * generate the type of the resulting value. + */ + deref->type = + _mesa_glsl_get_vector_type(op->type->base_type, + deref->selector.swizzle.num_components); + } else { + /* FINISHME: Logging of error messages should be moved into + * FINISHME: generate_swizzle. This allows the generation of more + * FINISHME: specific error messages. + */ + _mesa_glsl_error(& loc, state, "Invalid swizzle / mask `%s'", + expr->primary_expression.identifier); + } + } else if (op->type->base_type == GLSL_TYPE_STRUCT) { + /* FINISHME: Handle field selection from structures. */ + } else { + _mesa_glsl_error(& loc, state, "Cannot access field `%s' of " + "non-structure / non-vector.", + expr->primary_expression.identifier); + } + + return (struct ir_instruction *) deref; +} diff --git a/hir_function.c b/hir_function.c new file mode 100644 index 00000000000..eac2b59a611 --- /dev/null +++ b/hir_function.c @@ -0,0 +1,41 @@ +struct ir_instruction * +_mesa_ast_constructor_to_hir(const struct ast_node *n, + const struct ast_node *parameters, + struct _mesa_glsl_parse_state *state) +{ + const struct ast_type_specifier *type = (struct ast_type_specifier *) n; + + + /* There are effectively three kinds of constructors. Each has its own set + * of rules. + * + * * Built-in scalar, vector, and matrix types: For each of these the only + * matching requirement is that the number of values supplied is + * sufficient to initialize all of the fields of the type. + * * Array types: The number of initializers must match the size of the + * array, if a size is specified. Each of the initializers must + * exactly match the base type of the array. + * * Structure types: These initializers must exactly match the fields of + * the structure in order. This is the most restrictive type. + * + * In all cases the built-in promotions from integer to floating-point types + * are applied. + */ + + if (type->is_array) { + /* FINISHME */ + } else if ((type->type_specifier == ast_struct) + || (type->type_specifier == ast_type_name)) { + /* FINISHME */ + } else { + const struct glsl_type *ctor_type; + + /* Look-up the type, by name, in the symbol table. + */ + + + /* Generate a series of assignments of constructor parameters to fields + * of the object being initialized. + */ + } +} diff --git a/ir.cc b/ir.cc new file mode 100644 index 00000000000..7bd7854ccb8 --- /dev/null +++ b/ir.cc @@ -0,0 +1,116 @@ +/* + * 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. + */ +#include +#include "main/imports.h" +#include "main/simple_list.h" +#include "ir.h" +#include "glsl_types.h" + +ir_instruction::ir_instruction(int mode) +{ + this->mode = mode; + make_empty_list(this); +} + + +ir_assignment::ir_assignment(ir_instruction *lhs, ir_instruction *rhs, + ir_expression *condition) + : ir_instruction(ir_op_assign) +{ + this->lhs = (ir_dereference *) lhs; + this->rhs = rhs; + this->condition = condition; +} + + +ir_expression::ir_expression(int op, const struct glsl_type *type, + ir_instruction *op0, ir_instruction *op1) + : ir_instruction(ir_op_expression) +{ + this->type = type; + this->operation = ir_expression_operation(op); + this->operands[0] = op0; + this->operands[1] = op1; +} + + +ir_label::ir_label(const char *label) + : ir_instruction(ir_op_label), label(label) +{ + /* empty */ +} + + +ir_constant::ir_constant(const struct glsl_type *type, const void *data) + : ir_instruction(ir_op_constant) +{ + const unsigned elements = + ((type->vector_elements == 0) ? 1 : type->vector_elements) + * ((type->matrix_rows == 0) ? 1 : type->matrix_rows); + unsigned size = 0; + + this->type = type; + switch (type->base_type) { + case GLSL_TYPE_UINT: size = sizeof(this->value.u[0]); break; + case GLSL_TYPE_INT: size = sizeof(this->value.i[0]); break; + case GLSL_TYPE_FLOAT: size = sizeof(this->value.f[0]); break; + case GLSL_TYPE_BOOL: size = sizeof(this->value.b[0]); break; + default: + /* FINISHME: What to do? Exceptions are not the answer. + */ + break; + } + + memcpy(& this->value, data, size * elements); +} + + +ir_dereference::ir_dereference(ir_instruction *var) + : ir_instruction(ir_op_dereference) +{ + this->mode = ir_reference_variable; + this->var = var; + this->type = (var != NULL) ? var->type : glsl_error_type; +} + + +ir_variable::ir_variable(const struct glsl_type *type, const char *name) + : ir_instruction(ir_op_var_decl) +{ + this->type = type; + this->name = name; +} + + +ir_function_signature::ir_function_signature(void) + : ir_instruction(ir_op_func_sig) +{ + make_empty_list(& parameters); +} + + +ir_function::ir_function(void) + : ir_instruction(ir_op_func) +{ + make_empty_list(& signatures); +} diff --git a/ir.h b/ir.h new file mode 100644 index 00000000000..304f1dccfe0 --- /dev/null +++ b/ir.h @@ -0,0 +1,302 @@ +/* + * 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. + */ + +struct ir_program { + void *bong_hits; +}; + + +enum ir_opcodes { + ir_op_var_decl, + ir_op_assign, + ir_op_expression, + ir_op_dereference, + ir_op_jump, + ir_op_label, + ir_op_constant, + ir_op_func_sig, + ir_op_func +}; + +/** + * Base class of all IR instructions + */ +class ir_instruction : public simple_node { +public: + unsigned mode; + const struct glsl_type *type; + +protected: + ir_instruction(int mode); + +private: + /** + * Dummy constructor to catch bad constructors in derived classes. + * + * Every derived must use the constructor that sets the instructions + * mode. Having the \c void constructor private prevents derived classes + * from accidentally doing the wrong thing. + */ + ir_instruction(void); +}; + + +enum ir_variable_mode { + ir_var_auto = 0, + ir_var_uniform, + ir_var_in, + ir_var_out, + ir_var_inout +}; + +enum ir_varaible_interpolation { + ir_var_smooth = 0, + ir_var_flat, + ir_var_noperspective +}; + +class ir_variable : public ir_instruction { +public: + ir_variable(const struct glsl_type *, const char *); + + const char *name; + + unsigned read_only:1; + unsigned centroid:1; + unsigned invariant:1; + + unsigned mode:3; + unsigned interpolation:2; +}; + + +class ir_label : public ir_instruction { +public: + ir_label(const char *label); + + const char *label; +}; + + +/*@{*/ +class ir_function_signature : public ir_instruction { +public: + ir_function_signature(void); + + /** + * Function return type. + * + * \note This discards the optional precision qualifier. + */ + const struct glsl_type *return_type; + + /** + * List of function parameters stored as ir_variable objects. + */ + struct simple_node parameters; + + /** + * Pointer to the label that begins the function definition. + */ + ir_label *definition; +}; + + +/** + * Header for tracking functions in the symbol table + */ +class ir_function : public ir_instruction { +public: + ir_function(void); + + /** + * Name of the function. + */ + const char *name; + + struct simple_node signatures; +}; +/*@}*/ + +class ir_expression; +class ir_dereference; + +class ir_assignment : public ir_instruction { +public: + ir_assignment(ir_instruction *lhs, ir_instruction *rhs, + ir_expression *condition); + + /** + * Left-hand side of the assignment. + */ + ir_dereference *lhs; + + /** + * Value being assigned + * + * This should be either \c ir_op_expression or \c ir_op_deference. + */ + ir_instruction *rhs; + + /** + * Optional condition for the assignment. + */ + ir_expression *condition; +}; + + +enum ir_expression_operation { + ir_unop_bit_not, + ir_unop_logic_not, + ir_unop_neg, + ir_unop_abs, + ir_unop_rcp, + ir_unop_rsq, + ir_unop_exp, + ir_unop_log, + ir_unop_f2i, /**< Float-to-integer conversion. */ + ir_unop_i2f, /**< Integer-to-float conversion. */ + + /** + * \name Unary floating-point rounding operations. + */ + /*@{*/ + ir_unop_trunc, + ir_unop_ceil, + ir_unop_floor, + /*@}*/ + + ir_binop_add, + ir_binop_sub, + ir_binop_mul, + ir_binop_div, + ir_binop_mod, + + /** + * \name Binary comparison operators + */ + /*@{*/ + ir_binop_less, + ir_binop_greater, + ir_binop_lequal, + ir_binop_gequal, + ir_binop_equal, + ir_binop_nequal, + /*@}*/ + + /** + * \name Bit-wise binary operations. + */ + /*@{*/ + ir_binop_lshift, + ir_binop_rshift, + ir_binop_bit_and, + ir_binop_bit_xor, + ir_binop_bit_or, + /*@}*/ + + ir_binop_logic_and, + ir_binop_logic_xor, + ir_binop_logic_or, + ir_binop_logic_not, + + ir_binop_dot, + ir_binop_min, + ir_binop_max, + + ir_binop_pow +}; + +class ir_expression : public ir_instruction { +public: + ir_expression(int op, const struct glsl_type *type, + ir_instruction *, ir_instruction *); + + ir_expression_operation operation; + ir_instruction *operands[2]; +}; + + +struct ir_swizzle_mask { + unsigned x:2; + unsigned y:2; + unsigned z:2; + unsigned w:2; + + /** + * Number of components in the swizzle. + */ + unsigned num_components:2; + + /** + * Does the swizzle contain duplicate components? + * + * L-value swizzles cannot contain duplicate components. + */ + unsigned has_duplicates:1; +}; + +class ir_dereference : public ir_instruction { +public: + ir_dereference(struct ir_instruction *); + + enum { + ir_reference_variable, + ir_reference_array, + ir_reference_record + } mode; + + /** + * Object being dereferenced. + * + * Must be either an \c ir_variable or an \c ir_deference. + */ + ir_instruction *var; + + union { + ir_expression *array_index; + const char *field; + struct ir_swizzle_mask swizzle; + } selector; +}; + + +class ir_constant : public ir_instruction { +public: + ir_constant(const struct glsl_type *type, const void *data); + + /** + * Value of the constant. + * + * The field used to back the values supplied by the constant is determined + * by the type associated with the \c ir_instruction. Constants may be + * scalars, vectors, or matrices. + */ + union { + unsigned u[16]; + int i[16]; + float f[16]; + bool b[16]; + } value; +}; + diff --git a/main/imports.h b/main/imports.h new file mode 100644 index 00000000000..d2197342c04 --- /dev/null +++ b/main/imports.h @@ -0,0 +1,6 @@ +#include +#include + +#define _mesa_malloc(x) malloc(x) +#define _mesa_free(x) free(x) +#define _mesa_calloc(x) calloc(1,x) diff --git a/main/simple_list.h b/main/simple_list.h new file mode 100644 index 00000000000..5ef39e14cc6 --- /dev/null +++ b/main/simple_list.h @@ -0,0 +1,235 @@ +/** + * \file simple_list.h + * Simple macros for type-safe, intrusive lists. + * + * Intended to work with a list sentinal which is created as an empty + * list. Insert & delete are O(1). + * + * \author + * (C) 1997, Keith Whitwell + */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef _SIMPLE_LIST_H +#define _SIMPLE_LIST_H + +struct simple_node { + struct simple_node *next; + struct simple_node *prev; +}; + +/** + * Remove an element from list. + * + * \param elem element to remove. + */ +#define remove_from_list(elem) \ +do { \ + (elem)->next->prev = (elem)->prev; \ + (elem)->prev->next = (elem)->next; \ +} while (0) + +/** + * Insert an element to the list head. + * + * \param list list. + * \param elem element to insert. + */ +#define insert_at_head(list, elem) \ +do { \ + (elem)->prev = list; \ + (elem)->next = (list)->next; \ + (list)->next->prev = elem; \ + (list)->next = elem; \ +} while(0) + +/** + * Insert an element to the list tail. + * + * \param list list. + * \param elem element to insert. + */ +#define insert_at_tail(list, elem) \ +do { \ + (elem)->next = list; \ + (elem)->prev = (list)->prev; \ + (list)->prev->next = elem; \ + (list)->prev = elem; \ +} while(0) + +/** + * Move an element to the list head. + * + * \param list list. + * \param elem element to move. + */ +#define move_to_head(list, elem) \ +do { \ + remove_from_list(elem); \ + insert_at_head(list, elem); \ +} while (0) + +/** + * Move an element to the list tail. + * + * \param list list. + * \param elem element to move. + */ +#define move_to_tail(list, elem) \ +do { \ + remove_from_list(elem); \ + insert_at_tail(list, elem); \ +} while (0) + +/** + * Consatinate a cyclic list to a list + * + * Appends the sequence of nodes starting with \c tail to the list \c head. + * A "cyclic list" is a list that does not have a sentinal node. This means + * that the data pointed to by \c tail is an actual node, not a dataless + * sentinal. Note that if \c tail constist of a single node, this macro + * behaves identically to \c insert_at_tail + * + * \param head Head of the list to be appended to. This may or may not + * be a cyclic list. + * \param tail Head of the cyclic list to be appended to \c head. + * \param temp Temporary \c simple_list used by the macro + * + * \sa insert_at_tail + */ +#define concat_list_and_cycle(head, tail, temp) \ +do { \ + (head)->prev->next = (tail); \ + (tail)->prev->next = (head); \ + (temp) = (head)->prev; \ + (head)->prev = (tail)->prev; \ + (tail)->prev = (temp); \ +} while (0) + +#define concat_list(head, next_list) \ +do { \ + (next_list)->next->prev = (head)->prev; \ + (next_list)->prev->next = (head); \ + (head)->prev->next = (next_list)->next; \ + (head)->prev = (next_list)->prev; \ +} while (0) + +/** + * Make a empty list empty. + * + * \param sentinal list (sentinal element). + */ +#define make_empty_list(sentinal) \ +do { \ + (sentinal)->next = sentinal; \ + (sentinal)->prev = sentinal; \ +} while (0) + +/** + * Get list first element. + * + * \param list list. + * + * \return pointer to first element. + */ +#define first_elem(list) ((list)->next) + +/** + * Get list last element. + * + * \param list list. + * + * \return pointer to last element. + */ +#define last_elem(list) ((list)->prev) + +/** + * Get next element. + * + * \param elem element. + * + * \return pointer to next element. + */ +#define next_elem(elem) ((elem)->next) + +/** + * Get previous element. + * + * \param elem element. + * + * \return pointer to previous element. + */ +#define prev_elem(elem) ((elem)->prev) + +/** + * Test whether element is at end of the list. + * + * \param list list. + * \param elem element. + * + * \return non-zero if element is at end of list, or zero otherwise. + */ +#define at_end(list, elem) ((elem) == (list)) + +/** + * Test if a list is empty. + * + * \param list list. + * + * \return non-zero if list empty, or zero otherwise. + */ +#define is_empty_list(list) ((list)->next == (list)) + +/** + * Walk through the elements of a list. + * + * \param ptr pointer to the current element. + * \param list list. + * + * \note It should be followed by a { } block or a single statement, as in a \c + * for loop. + */ +#define foreach(ptr, list) \ + for( ptr=(list)->next ; ptr!=list ; ptr=(ptr)->next ) + +/** + * Walk through the elements of a list. + * + * Same as #foreach but lets you unlink the current value during a list + * traversal. Useful for freeing a list, element by element. + * + * \param ptr pointer to the current element. + * \param t temporary pointer. + * \param list list. + * + * \note It should be followed by a { } block or a single statement, as in a \c + * for loop. + */ +#define foreach_s(ptr, t, list) \ + for(ptr=(list)->next,t=(ptr)->next; list != ptr; ptr=t, t=(t)->next) + +#endif diff --git a/symbol_table.c b/symbol_table.c new file mode 100644 index 00000000000..4e043d17336 --- /dev/null +++ b/symbol_table.c @@ -0,0 +1,377 @@ +/* + * Copyright © 2008 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. + */ + +#include "main/imports.h" +#include "symbol_table.h" +#include "hash_table.h" + +struct symbol { + /** + * Link to the next symbol in the table with the same name + * + * The linked list of symbols with the same name is ordered by scope + * from inner-most to outer-most. + */ + struct symbol *next_with_same_name; + + + /** + * Link to the next symbol in the table with the same scope + * + * The linked list of symbols with the same scope is unordered. Symbols + * in this list my have unique names. + */ + struct symbol *next_with_same_scope; + + + /** + * Header information for the list of symbols with the same name. + */ + struct symbol_header *hdr; + + + /** + * Name space of the symbol + * + * Name space are arbitrary user assigned integers. No two symbols can + * exist in the same name space at the same scope level. + */ + int name_space; + + + /** + * Arbitrary user supplied data. + */ + void *data; + + /** Scope depth where this symbol was defined. */ + unsigned depth; +}; + + +/** + */ +struct symbol_header { + /** Linkage in list of all headers in a given symbol table. */ + struct symbol_header *next; + + /** Symbol name. */ + const char *name; + + /** Linked list of symbols with the same name. */ + struct symbol *symbols; +}; + + +/** + * Element of the scope stack. + */ +struct scope_level { + /** Link to next (inner) scope level. */ + struct scope_level *next; + + /** Linked list of symbols with the same scope. */ + struct symbol *symbols; +}; + + +/** + * + */ +struct _mesa_symbol_table { + /** Hash table containing all symbols in the symbol table. */ + struct hash_table *ht; + + /** Top of scope stack. */ + struct scope_level *current_scope; + + /** List of all symbol headers in the table. */ + struct symbol_header *hdr; + + /** Current scope depth. */ + unsigned depth; +}; + + +struct _mesa_symbol_table_iterator { + /** + * Name space of symbols returned by this iterator. + */ + int name_space; + + + /** + * Currently iterated symbol + * + * The next call to \c _mesa_symbol_table_iterator_get will return this + * value. It will also update this value to the value that should be + * returned by the next call. + */ + struct symbol *curr; +}; + + +static void +check_symbol_table(struct _mesa_symbol_table *table) +{ +#if 1 + struct scope_level *scope; + + for (scope = table->current_scope; scope != NULL; scope = scope->next) { + struct symbol *sym; + + for (sym = scope->symbols + ; sym != NULL + ; sym = sym->next_with_same_name) { + const struct symbol_header *const hdr = sym->hdr; + struct symbol *sym2; + + for (sym2 = hdr->symbols + ; sym2 != NULL + ; sym2 = sym2->next_with_same_name) { + assert(sym2->hdr == hdr); + } + } + } +#endif +} + +void +_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table) +{ + struct scope_level *const scope = table->current_scope; + struct symbol *sym = scope->symbols; + + table->current_scope = scope->next; + table->depth--; + + free(scope); + + while (sym != NULL) { + struct symbol *const next = sym->next_with_same_scope; + struct symbol_header *const hdr = sym->hdr; + + assert(hdr->symbols == sym); + + hdr->symbols = sym->next_with_same_name; + + free(sym); + + sym = next; + } + + check_symbol_table(table); +} + + +void +_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table) +{ + struct scope_level *const scope = calloc(1, sizeof(*scope)); + + scope->next = table->current_scope; + table->current_scope = scope; + table->depth++; +} + + +static struct symbol_header * +find_symbol(struct _mesa_symbol_table *table, const char *name) +{ + return (struct symbol_header *) hash_table_find(table->ht, name); +} + + +struct _mesa_symbol_table_iterator * +_mesa_symbol_table_iterator_ctor(struct _mesa_symbol_table *table, + int name_space, const char *name) +{ + struct _mesa_symbol_table_iterator *iter = calloc(1, sizeof(*iter)); + struct symbol_header *const hdr = find_symbol(table, name); + + iter->name_space = name_space; + + if (hdr != NULL) { + struct symbol *sym; + + for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { + assert(sym->hdr == hdr); + + if ((name_space == -1) || (sym->name_space == name_space)) { + iter->curr = sym; + break; + } + } + } + + return iter; +} + + +void +_mesa_symbol_table_iterator_dtor(struct _mesa_symbol_table_iterator *iter) +{ + free(iter); +} + + +void * +_mesa_symbol_table_iterator_get(struct _mesa_symbol_table_iterator *iter) +{ + return (iter->curr == NULL) ? NULL : iter->curr->data; +} + + +int +_mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator *iter) +{ + struct symbol_header *hdr; + + if (iter->curr == NULL) { + return 0; + } + + hdr = iter->curr->hdr; + iter->curr = iter->curr->next_with_same_name; + + while (iter->curr != NULL) { + assert(iter->curr->hdr == hdr); + + if ((iter->name_space == -1) + || (iter->curr->name_space == iter->name_space)) { + return 1; + } + + iter->curr = iter->curr->next_with_same_name; + } + + return 0; +} + + +void * +_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table, + int name_space, const char *name) +{ + struct symbol_header *const hdr = find_symbol(table, name); + + if (hdr != NULL) { + struct symbol *sym; + + + for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { + assert(sym->hdr == hdr); + + if ((name_space == -1) || (sym->name_space == name_space)) { + return sym->data; + } + } + } + + return NULL; +} + + +int +_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table, + int name_space, const char *name, + void *declaration) +{ + struct symbol_header *hdr; + struct symbol *sym; + + check_symbol_table(table); + + hdr = find_symbol(table, name); + + check_symbol_table(table); + + if (hdr == NULL) { + hdr = calloc(1, sizeof(*hdr)); + hdr->name = name; + + hash_table_insert(table->ht, hdr, name); + hdr->next = table->hdr; + table->hdr = hdr; + } + + check_symbol_table(table); + + /* If the symbol already exists at this scope, it cannot be added to the + * table. + */ + if (hdr->symbols && (hdr->symbols->depth == table->depth)) + return -1; + + sym = calloc(1, sizeof(*sym)); + sym->next_with_same_name = hdr->symbols; + sym->next_with_same_scope = table->current_scope->symbols; + sym->hdr = hdr; + sym->name_space = name_space; + sym->data = declaration; + sym->depth = table->depth; + + assert(sym->hdr == hdr); + + hdr->symbols = sym; + table->current_scope->symbols = sym; + + check_symbol_table(table); + return 0; +} + + +struct _mesa_symbol_table * +_mesa_symbol_table_ctor(void) +{ + struct _mesa_symbol_table *table = calloc(1, sizeof(*table)); + + if (table != NULL) { + table->ht = hash_table_ctor(32, hash_table_string_hash, + hash_table_string_compare); + + _mesa_symbol_table_push_scope(table); + } + + return table; +} + + +void +_mesa_symbol_table_dtor(struct _mesa_symbol_table *table) +{ + struct symbol_header *hdr; + struct symbol_header *next; + + while (table->current_scope != NULL) { + _mesa_symbol_table_pop_scope(table); + } + + for (hdr = table->hdr; hdr != NULL; hdr = next) { + next = hdr->next; + _mesa_free(hdr); + } + + hash_table_dtor(table->ht); + free(table); +} diff --git a/symbol_table.h b/symbol_table.h new file mode 100644 index 00000000000..d3f65e30a92 --- /dev/null +++ b/symbol_table.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2008 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. + */ +#ifndef MESA_SYMBOL_TABLE_H +#define MESA_SYMBOL_TABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct _mesa_symbol_table; +struct _mesa_symbol_table_iterator; + +extern void _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table); + +extern void _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table); + +extern int _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *symtab, + int name_space, const char *name, void *declaration); + +extern void *_mesa_symbol_table_find_symbol( + struct _mesa_symbol_table *symtab, int name_space, const char *name); + +extern struct _mesa_symbol_table *_mesa_symbol_table_ctor(void); + +extern void _mesa_symbol_table_dtor(struct _mesa_symbol_table *); + +extern struct _mesa_symbol_table_iterator *_mesa_symbol_table_iterator_ctor( + struct _mesa_symbol_table *table, int name_space, const char *name); + +extern void _mesa_symbol_table_iterator_dtor( + struct _mesa_symbol_table_iterator *); + +extern void *_mesa_symbol_table_iterator_get( + struct _mesa_symbol_table_iterator *iter); + +extern int _mesa_symbol_table_iterator_next( + struct _mesa_symbol_table_iterator *iter); + +#ifdef __cplusplus +} +#endif + +#endif /* MESA_SYMBOL_TABLE_H */ diff --git a/tests/parameters-01.txt b/tests/parameters-01.txt new file mode 100644 index 00000000000..f0beb6c35d1 --- /dev/null +++ b/tests/parameters-01.txt @@ -0,0 +1,9 @@ +void a() +{ + ; +} + +void a() +{ + ; +} diff --git a/tests/parameters-02.txt b/tests/parameters-02.txt new file mode 100644 index 00000000000..58f44e532e1 --- /dev/null +++ b/tests/parameters-02.txt @@ -0,0 +1,9 @@ +void a() +{ + ; +} + +void a(float x) +{ + ; +} diff --git a/tests/parameters-03.txt b/tests/parameters-03.txt new file mode 100644 index 00000000000..7ec30f80cc6 --- /dev/null +++ b/tests/parameters-03.txt @@ -0,0 +1,9 @@ +/* FAIL - x is redeclared in the function body at the same scope as the + * parameter + */ +void a(float x, float y) +{ + float x; + + x = y; +} diff --git a/tests/swiz-01.glsl b/tests/swiz-01.glsl new file mode 100644 index 00000000000..a72af37c677 --- /dev/null +++ b/tests/swiz-01.glsl @@ -0,0 +1,10 @@ +#version 120 + +void main() +{ + float a; + vec4 b; + + b.x = 6.0; + a = b.x; +} diff --git a/tests/swiz-02.glsl b/tests/swiz-02.glsl new file mode 100644 index 00000000000..5e2acd1a25a --- /dev/null +++ b/tests/swiz-02.glsl @@ -0,0 +1,10 @@ +#version 120 + +void main() +{ + float a; + vec4 b; + + b.x = 6.0; + a = b.xy; +} -- 2.30.2