diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/ast_to_hir.cpp | 545 | ||||
-rw-r--r-- | mesalib/src/glsl/glcpp/glcpp-lex.l | 656 | ||||
-rw-r--r-- | mesalib/src/glsl/glcpp/glcpp-parse.y | 3 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser.yy | 6 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser_extras.cpp | 2 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser_extras.h | 21 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 38 |
7 files changed, 669 insertions, 602 deletions
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index cde7052b0..c580359fd 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -54,6 +54,7 @@ #include "glsl_parser_extras.h" #include "ast.h" #include "glsl_types.h" +#include "program/hash_table.h" #include "ir.h" void @@ -3405,7 +3406,7 @@ ast_jump_statement::hir(exec_list *instructions, "continue may only appear in a loop"); } else if (mode == ast_break && state->loop_nesting_ast == NULL && - state->switch_nesting_ast == NULL) { + state->switch_state.switch_nesting_ast == NULL) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, @@ -3423,11 +3424,11 @@ ast_jump_statement::hir(exec_list *instructions, state); } - if (state->is_switch_innermost && + if (state->switch_state.is_switch_innermost && mode == ast_break) { /* Force break out of switch by setting is_break switch state. */ - ir_variable *const is_break_var = state->is_break_var; + ir_variable *const is_break_var = state->switch_state.is_break_var; ir_dereference_variable *const deref_is_break_var = new(ctx) ir_dereference_variable(is_break_var); ir_constant *const true_val = new(ctx) ir_constant(true); @@ -3530,25 +3531,25 @@ ast_switch_statement::hir(exec_list *instructions, /* Track the switch-statement nesting in a stack-like manner. */ - ir_variable *saved_test_var = state->test_var; - ir_variable *saved_is_fallthru_var = state->is_fallthru_var; - - bool save_is_switch_innermost = state->is_switch_innermost; - ast_switch_statement *saved_nesting_ast = state->switch_nesting_ast; + struct glsl_switch_state saved = state->switch_state; - state->is_switch_innermost = true; - state->switch_nesting_ast = this; + state->switch_state.is_switch_innermost = true; + state->switch_state.switch_nesting_ast = this; + state->switch_state.labels_ht = hash_table_ctor(0, hash_table_pointer_hash, + hash_table_pointer_compare); + state->switch_state.previous_default = NULL; /* Initalize is_fallthru state to false. */ ir_rvalue *const is_fallthru_val = new (ctx) ir_constant(false); - state->is_fallthru_var = new(ctx) ir_variable(glsl_type::bool_type, - "switch_is_fallthru_tmp", - ir_var_temporary); - instructions->push_tail(state->is_fallthru_var); + state->switch_state.is_fallthru_var = + new(ctx) ir_variable(glsl_type::bool_type, + "switch_is_fallthru_tmp", + ir_var_temporary); + instructions->push_tail(state->switch_state.is_fallthru_var); ir_dereference_variable *deref_is_fallthru_var = - new(ctx) ir_dereference_variable(state->is_fallthru_var); + new(ctx) ir_dereference_variable(state->switch_state.is_fallthru_var); instructions->push_tail(new(ctx) ir_assignment(deref_is_fallthru_var, is_fallthru_val, NULL)); @@ -3556,13 +3557,13 @@ ast_switch_statement::hir(exec_list *instructions, /* Initalize is_break state to false. */ ir_rvalue *const is_break_val = new (ctx) ir_constant(false); - state->is_break_var = new(ctx) ir_variable(glsl_type::bool_type, - "switch_is_break_tmp", - ir_var_temporary); - instructions->push_tail(state->is_break_var); + state->switch_state.is_break_var = new(ctx) ir_variable(glsl_type::bool_type, + "switch_is_break_tmp", + ir_var_temporary); + instructions->push_tail(state->switch_state.is_break_var); ir_dereference_variable *deref_is_break_var = - new(ctx) ir_dereference_variable(state->is_break_var); + new(ctx) ir_dereference_variable(state->switch_state.is_break_var); instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var, is_break_val, NULL)); @@ -3575,254 +3576,294 @@ ast_switch_statement::hir(exec_list *instructions, */ body->hir(instructions, state); - /* Restore previous nesting before returning. - */ - state->switch_nesting_ast = saved_nesting_ast; - state->is_switch_innermost = save_is_switch_innermost; + hash_table_dtor(state->switch_state.labels_ht); - state->test_var = saved_test_var; - state->is_fallthru_var = saved_is_fallthru_var; + state->switch_state = saved; - /* Switch statements do not have r-values. - */ - return NULL; -} + /* Switch statements do not have r-values. + */ + return NULL; + } -void -ast_switch_statement::test_to_hir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - void *ctx = state; - - /* Cache value of test expression. - */ - ir_rvalue *const test_val = - test_expression->hir(instructions, - state); + void + ast_switch_statement::test_to_hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) + { + void *ctx = state; - state->test_var = new(ctx) ir_variable(glsl_type::int_type, - "switch_test_tmp", - ir_var_temporary); - ir_dereference_variable *deref_test_var = - new(ctx) ir_dereference_variable(state->test_var); + /* Cache value of test expression. + */ + ir_rvalue *const test_val = + test_expression->hir(instructions, + state); - instructions->push_tail(state->test_var); - instructions->push_tail(new(ctx) ir_assignment(deref_test_var, - test_val, - NULL)); -} + state->switch_state.test_var = new(ctx) ir_variable(glsl_type::int_type, + "switch_test_tmp", + ir_var_temporary); + ir_dereference_variable *deref_test_var = + new(ctx) ir_dereference_variable(state->switch_state.test_var); + instructions->push_tail(state->switch_state.test_var); + instructions->push_tail(new(ctx) ir_assignment(deref_test_var, + test_val, + NULL)); + } -ir_rvalue * -ast_switch_body::hir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - if (stmts != NULL) - stmts->hir(instructions, state); - - /* Switch bodies do not have r-values. - */ - return NULL; -} + ir_rvalue * + ast_switch_body::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) + { + if (stmts != NULL) + stmts->hir(instructions, state); -ir_rvalue * -ast_case_statement_list::hir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - foreach_list_typed (ast_case_statement, case_stmt, link, & this->cases) - case_stmt->hir(instructions, state); - - /* Case statements do not have r-values. - */ - return NULL; -} + /* Switch bodies do not have r-values. + */ + return NULL; + } -ir_rvalue * -ast_case_statement::hir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - labels->hir(instructions, state); - - /* Conditionally set fallthru state based on break state. - */ - ir_constant *const false_val = new(state) ir_constant(false); - ir_dereference_variable *const deref_is_fallthru_var = - new(state) ir_dereference_variable(state->is_fallthru_var); - ir_dereference_variable *const deref_is_break_var = - new(state) ir_dereference_variable(state->is_break_var); - ir_assignment *const reset_fallthru_on_break = - new(state) ir_assignment(deref_is_fallthru_var, - false_val, - deref_is_break_var); - instructions->push_tail(reset_fallthru_on_break); - - /* Guard case statements depending on fallthru state. - */ - ir_dereference_variable *const deref_fallthru_guard = - new(state) ir_dereference_variable(state->is_fallthru_var); - ir_if *const test_fallthru = new(state) ir_if(deref_fallthru_guard); - - foreach_list_typed (ast_node, stmt, link, & this->stmts) - stmt->hir(& test_fallthru->then_instructions, state); - - instructions->push_tail(test_fallthru); - - /* Case statements do not have r-values. - */ - return NULL; -} - - -ir_rvalue * -ast_case_label_list::hir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - foreach_list_typed (ast_case_label, label, link, & this->labels) - label->hir(instructions, state); - - /* Case labels do not have r-values. - */ - return NULL; -} - - -ir_rvalue * -ast_case_label::hir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - void *ctx = state; - - ir_dereference_variable *deref_fallthru_var = - new(ctx) ir_dereference_variable(state->is_fallthru_var); - - ir_rvalue *const true_val = new(ctx) ir_constant(true); - - /* If not default case, ... - */ - if (this->test_value != NULL) { - /* Conditionally set fallthru state based on - * comparison of cached test expression value to case label. - */ - ir_rvalue *const test_val = this->test_value->hir(instructions, state); + ir_rvalue * + ast_case_statement_list::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) + { + foreach_list_typed (ast_case_statement, case_stmt, link, & this->cases) + case_stmt->hir(instructions, state); - ir_dereference_variable *deref_test_var = - new(ctx) ir_dereference_variable(state->test_var); + /* Case statements do not have r-values. + */ + return NULL; + } - ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal, - glsl_type::bool_type, - test_val, - deref_test_var); - ir_assignment *set_fallthru_on_test = - new(ctx) ir_assignment(deref_fallthru_var, - true_val, - test_cond); - - instructions->push_tail(set_fallthru_on_test); - } else { /* default case */ - /* Set falltrhu state. - */ - ir_assignment *set_fallthru = - new(ctx) ir_assignment(deref_fallthru_var, - true_val, - NULL); - - instructions->push_tail(set_fallthru); - } - - /* Case statements do not have r-values. - */ - return NULL; -} - - -void -ast_iteration_statement::condition_to_hir(ir_loop *stmt, - struct _mesa_glsl_parse_state *state) -{ - void *ctx = state; - - if (condition != NULL) { - ir_rvalue *const cond = - condition->hir(& stmt->body_instructions, state); - - if ((cond == NULL) - || !cond->type->is_boolean() || !cond->type->is_scalar()) { - YYLTYPE loc = condition->get_location(); - - _mesa_glsl_error(& loc, state, - "loop condition must be scalar boolean"); - } else { - /* As the first code in the loop body, generate a block that looks - * like 'if (!condition) break;' as the loop termination condition. - */ - ir_rvalue *const not_cond = - new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond, - NULL); - - ir_if *const if_stmt = new(ctx) ir_if(not_cond); - - ir_jump *const break_stmt = - new(ctx) ir_loop_jump(ir_loop_jump::jump_break); - - if_stmt->then_instructions.push_tail(break_stmt); - stmt->body_instructions.push_tail(if_stmt); - } - } -} - - -ir_rvalue * -ast_iteration_statement::hir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - void *ctx = state; - - /* For-loops and while-loops start a new scope, but do-while loops do not. - */ - if (mode != ast_do_while) - state->symbols->push_scope(); - - if (init_statement != NULL) - init_statement->hir(instructions, state); - - ir_loop *const stmt = new(ctx) ir_loop(); - instructions->push_tail(stmt); - - /* Track the current loop nesting. - */ - ast_iteration_statement *nesting_ast = state->loop_nesting_ast; - - state->loop_nesting_ast = this; - - /* Likewise, indicate that following code is closest to a loop, - * NOT closest to a switch. - */ - bool saved_is_switch_innermost = state->is_switch_innermost; - state->is_switch_innermost = false; - - if (mode != ast_do_while) - condition_to_hir(stmt, state); - - if (body != NULL) - body->hir(& stmt->body_instructions, state); - - if (rest_expression != NULL) - rest_expression->hir(& stmt->body_instructions, state); - - if (mode == ast_do_while) - condition_to_hir(stmt, state); - - if (mode != ast_do_while) - state->symbols->pop_scope(); + ir_rvalue * + ast_case_statement::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) + { + labels->hir(instructions, state); + + /* Conditionally set fallthru state based on break state. + */ + ir_constant *const false_val = new(state) ir_constant(false); + ir_dereference_variable *const deref_is_fallthru_var = + new(state) ir_dereference_variable(state->switch_state.is_fallthru_var); + ir_dereference_variable *const deref_is_break_var = + new(state) ir_dereference_variable(state->switch_state.is_break_var); + ir_assignment *const reset_fallthru_on_break = + new(state) ir_assignment(deref_is_fallthru_var, + false_val, + deref_is_break_var); + instructions->push_tail(reset_fallthru_on_break); + + /* Guard case statements depending on fallthru state. + */ + ir_dereference_variable *const deref_fallthru_guard = + new(state) ir_dereference_variable(state->switch_state.is_fallthru_var); + ir_if *const test_fallthru = new(state) ir_if(deref_fallthru_guard); + + foreach_list_typed (ast_node, stmt, link, & this->stmts) + stmt->hir(& test_fallthru->then_instructions, state); + + instructions->push_tail(test_fallthru); + + /* Case statements do not have r-values. + */ + return NULL; + } + + + ir_rvalue * + ast_case_label_list::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) + { + foreach_list_typed (ast_case_label, label, link, & this->labels) + label->hir(instructions, state); + + /* Case labels do not have r-values. + */ + return NULL; + } + + + ir_rvalue * + ast_case_label::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) + { + void *ctx = state; + + ir_dereference_variable *deref_fallthru_var = + new(ctx) ir_dereference_variable(state->switch_state.is_fallthru_var); + + ir_rvalue *const true_val = new(ctx) ir_constant(true); + + /* If not default case, ... + */ + if (this->test_value != NULL) { + /* Conditionally set fallthru state based on + * comparison of cached test expression value to case label. + */ + ir_rvalue *const label_rval = this->test_value->hir(instructions, state); + ir_constant *label_const = label_rval->constant_expression_value(); + + if (!label_const) { + YYLTYPE loc = this->test_value->get_location(); + + _mesa_glsl_error(& loc, state, + "switch statement case label must be a " + "constant expression"); + + /* Stuff a dummy value in to allow processing to continue. */ + label_const = new(ctx) ir_constant(0); + } else { + ast_expression *previous_label = (ast_expression *) + hash_table_find(state->switch_state.labels_ht, + (void *)(uintptr_t)label_const->value.u[0]); + + if (previous_label) { + YYLTYPE loc = this->test_value->get_location(); + _mesa_glsl_error(& loc, state, + "duplicate case value"); + + loc = previous_label->get_location(); + _mesa_glsl_error(& loc, state, + "this is the previous case label"); + } else { + hash_table_insert(state->switch_state.labels_ht, + this->test_value, + (void *)(uintptr_t)label_const->value.u[0]); + } + } + + ir_dereference_variable *deref_test_var = + new(ctx) ir_dereference_variable(state->switch_state.test_var); + + ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal, + glsl_type::bool_type, + label_const, + deref_test_var); + + ir_assignment *set_fallthru_on_test = + new(ctx) ir_assignment(deref_fallthru_var, + true_val, + test_cond); + + instructions->push_tail(set_fallthru_on_test); + } else { /* default case */ + if (state->switch_state.previous_default) { + printf("a\n"); + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(& loc, state, + "multiple default labels in one switch"); + + printf("b\n"); + + loc = state->switch_state.previous_default->get_location(); + _mesa_glsl_error(& loc, state, + "this is the first default label"); + } + state->switch_state.previous_default = this; + + /* Set falltrhu state. + */ + ir_assignment *set_fallthru = + new(ctx) ir_assignment(deref_fallthru_var, + true_val, + NULL); + + instructions->push_tail(set_fallthru); + } + + /* Case statements do not have r-values. + */ + return NULL; + } + + + void + ast_iteration_statement::condition_to_hir(ir_loop *stmt, + struct _mesa_glsl_parse_state *state) + { + void *ctx = state; + + if (condition != NULL) { + ir_rvalue *const cond = + condition->hir(& stmt->body_instructions, state); + + if ((cond == NULL) + || !cond->type->is_boolean() || !cond->type->is_scalar()) { + YYLTYPE loc = condition->get_location(); + + _mesa_glsl_error(& loc, state, + "loop condition must be scalar boolean"); + } else { + /* As the first code in the loop body, generate a block that looks + * like 'if (!condition) break;' as the loop termination condition. + */ + ir_rvalue *const not_cond = + new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond, + NULL); + + ir_if *const if_stmt = new(ctx) ir_if(not_cond); + + ir_jump *const break_stmt = + new(ctx) ir_loop_jump(ir_loop_jump::jump_break); + + if_stmt->then_instructions.push_tail(break_stmt); + stmt->body_instructions.push_tail(if_stmt); + } + } + } + + + ir_rvalue * + ast_iteration_statement::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) + { + void *ctx = state; + + /* For-loops and while-loops start a new scope, but do-while loops do not. + */ + if (mode != ast_do_while) + state->symbols->push_scope(); + + if (init_statement != NULL) + init_statement->hir(instructions, state); + + ir_loop *const stmt = new(ctx) ir_loop(); + instructions->push_tail(stmt); + + /* Track the current loop nesting. + */ + ast_iteration_statement *nesting_ast = state->loop_nesting_ast; + + state->loop_nesting_ast = this; + + /* Likewise, indicate that following code is closest to a loop, + * NOT closest to a switch. + */ + bool saved_is_switch_innermost = state->switch_state.is_switch_innermost; + state->switch_state.is_switch_innermost = false; + + if (mode != ast_do_while) + condition_to_hir(stmt, state); + + if (body != NULL) + body->hir(& stmt->body_instructions, state); + + if (rest_expression != NULL) + rest_expression->hir(& stmt->body_instructions, state); - /* Restore previous nesting before returning. - */ - state->loop_nesting_ast = nesting_ast; - state->is_switch_innermost = saved_is_switch_innermost; + if (mode == ast_do_while) + condition_to_hir(stmt, state); + + if (mode != ast_do_while) + state->symbols->pop_scope(); + + /* Restore previous nesting before returning. + */ + state->loop_nesting_ast = nesting_ast; + state->switch_state.is_switch_innermost = saved_is_switch_innermost; /* Loops do not have r-values. */ diff --git a/mesalib/src/glsl/glcpp/glcpp-lex.l b/mesalib/src/glsl/glcpp/glcpp-lex.l index 596c6db70..b34f2c0e9 100644 --- a/mesalib/src/glsl/glcpp/glcpp-lex.l +++ b/mesalib/src/glsl/glcpp/glcpp-lex.l @@ -1,324 +1,332 @@ -%{
-/*
- * 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 <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "glcpp.h"
-#include "glcpp-parse.h"
-
-/* Flex annoyingly generates some functions without making them
- * static. Let's declare them here. */
-int glcpp_get_column (yyscan_t yyscanner);
-void glcpp_set_column (int column_no , yyscan_t yyscanner);
-
-#ifdef _MSC_VER
-#define YY_NO_UNISTD_H
-#endif
-
-#define YY_NO_INPUT
-
-#define YY_USER_ACTION \
- do { \
- yylloc->first_column = yycolumn + 1; \
- yylloc->first_line = yylineno; \
- yycolumn += yyleng; \
- } while(0);
-
-#define YY_USER_INIT \
- do { \
- yylineno = 1; \
- yycolumn = 1; \
- yylloc->source = 0; \
- } while(0)
-%}
-
-%option bison-bridge bison-locations reentrant noyywrap
-%option extra-type="glcpp_parser_t *"
-%option prefix="glcpp_"
-%option stack
-%option never-interactive
-
-%x DONE COMMENT UNREACHABLE SKIP
-
-SPACE [[:space:]]
-NONSPACE [^[:space:]]
-NEWLINE [\n]
-HSPACE [ \t]
-HASH ^{HSPACE}*#{HSPACE}*
-IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
-PUNCTUATION [][(){}.&*~!/%<>^|;,=+-]
-OTHER [^][(){}.&*~!/%<>^|;,=#[:space:]+-]+
-
-DIGITS [0-9][0-9]*
-DECIMAL_INTEGER [1-9][0-9]*[uU]?
-OCTAL_INTEGER 0[0-7]*[uU]?
-HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
-
-%%
- /* Implicitly switch between SKIP and INITIAL (non-skipping);
- * don't switch if some other state was explicitly set.
- */
- glcpp_parser_t *parser = yyextra;
- if (YY_START == 0 || YY_START == SKIP) {
- if (parser->lexing_if || parser->skip_stack == NULL || parser->skip_stack->type == SKIP_NO_SKIP) {
- BEGIN 0;
- } else {
- BEGIN SKIP;
- }
- }
-
- /* Single-line comments */
-"//"[^\n]* {
-}
-
- /* Multi-line comments */
-"/*" { yy_push_state(COMMENT, yyscanner); }
-<COMMENT>[^*\n]*
-<COMMENT>[^*\n]*\n { yylineno++; yycolumn = 0; return NEWLINE; }
-<COMMENT>"*"+[^*/\n]*
-<COMMENT>"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; return NEWLINE; }
-<COMMENT>"*"+"/" {
- yy_pop_state(yyscanner);
- if (yyextra->space_tokens)
- return SPACE;
-}
-
-{HASH}version {
- yylval->str = ralloc_strdup (yyextra, yytext);
- yyextra->space_tokens = 0;
- return HASH_VERSION;
-}
-
- /* glcpp doesn't handle #extension, #version, or #pragma directives.
- * Simply pass them through to the main compiler's lexer/parser. */
-{HASH}(extension|pragma)[^\n]+ {
- yylval->str = ralloc_strdup (yyextra, yytext);
- yylineno++;
- yycolumn = 0;
- return OTHER;
-}
-
-{HASH}line{HSPACE}+{DIGITS}{HSPACE}+{DIGITS}{HSPACE}*$ {
- /* Eat characters until the first digit is
- * encountered
- */
- char *ptr = yytext;
- while (!isdigit(*ptr))
- ptr++;
-
- /* Subtract one from the line number because
- * yylineno is zero-based instead of
- * one-based.
- */
- yylineno = strtol(ptr, &ptr, 0) - 1;
- yylloc->source = strtol(ptr, NULL, 0);
-}
-
-{HASH}line{HSPACE}+{DIGITS}{HSPACE}*$ {
- /* Eat characters until the first digit is
- * encountered
- */
- char *ptr = yytext;
- while (!isdigit(*ptr))
- ptr++;
-
- /* Subtract one from the line number because
- * yylineno is zero-based instead of
- * one-based.
- */
- yylineno = strtol(ptr, &ptr, 0) - 1;
-}
-
-<SKIP,INITIAL>{
-{HASH}ifdef {
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IFDEF;
-}
-
-{HASH}ifndef {
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IFNDEF;
-}
-
-{HASH}if/[^_a-zA-Z0-9] {
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IF;
-}
-
-{HASH}elif {
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_ELIF;
-}
-
-{HASH}else {
- yyextra->space_tokens = 0;
- return HASH_ELSE;
-}
-
-{HASH}endif {
- yyextra->space_tokens = 0;
- return HASH_ENDIF;
-}
-}
-
-<SKIP>[^\n] ;
-
-{HASH}error.* {
- char *p;
- for (p = yytext; !isalpha(p[0]); p++); /* skip " # " */
- p += 5; /* skip "error" */
- glcpp_error(yylloc, yyextra, "#error%s", p);
-}
-
-{HASH}define{HSPACE}+/{IDENTIFIER}"(" {
- yyextra->space_tokens = 0;
- return HASH_DEFINE_FUNC;
-}
-
-{HASH}define {
- yyextra->space_tokens = 0;
- return HASH_DEFINE_OBJ;
-}
-
-{HASH}undef {
- yyextra->space_tokens = 0;
- return HASH_UNDEF;
-}
-
-{HASH} {
- yyextra->space_tokens = 0;
- return HASH;
-}
-
-{DECIMAL_INTEGER} {
- yylval->str = ralloc_strdup (yyextra, yytext);
- return INTEGER_STRING;
-}
-
-{OCTAL_INTEGER} {
- yylval->str = ralloc_strdup (yyextra, yytext);
- return INTEGER_STRING;
-}
-
-{HEXADECIMAL_INTEGER} {
- yylval->str = ralloc_strdup (yyextra, yytext);
- return INTEGER_STRING;
-}
-
-"<<" {
- return LEFT_SHIFT;
-}
-
-">>" {
- return RIGHT_SHIFT;
-}
-
-"<=" {
- return LESS_OR_EQUAL;
-}
-
-">=" {
- return GREATER_OR_EQUAL;
-}
-
-"==" {
- return EQUAL;
-}
-
-"!=" {
- return NOT_EQUAL;
-}
-
-"&&" {
- return AND;
-}
-
-"||" {
- return OR;
-}
-
-"##" {
- return PASTE;
-}
-
-"defined" {
- return DEFINED;
-}
-
-{IDENTIFIER} {
- yylval->str = ralloc_strdup (yyextra, yytext);
- return IDENTIFIER;
-}
-
-{PUNCTUATION} {
- return yytext[0];
-}
-
-{OTHER}+ {
- yylval->str = ralloc_strdup (yyextra, yytext);
- return OTHER;
-}
-
-{HSPACE}+ {
- if (yyextra->space_tokens) {
- return SPACE;
- }
-}
-
-<SKIP,INITIAL>\n {
- yyextra->lexing_if = 0;
- yylineno++;
- yycolumn = 0;
- return NEWLINE;
-}
-
- /* Handle missing newline at EOF. */
-<INITIAL><<EOF>> {
- BEGIN DONE; /* Don't keep matching this rule forever. */
- yyextra->lexing_if = 0;
- return NEWLINE;
-}
-
- /* We don't actually use the UNREACHABLE start condition. We
- only have this action here so that we can pretend to call some
- generated functions, (to avoid "defined but not used"
- warnings. */
-<UNREACHABLE>. {
- unput('.');
- yy_top_state(yyextra);
-}
-
-%%
-
-void
-glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader)
-{
- yy_scan_string(shader, parser->scanner);
-}
+%{ +/* + * 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 <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "glcpp.h" +#include "glcpp-parse.h" + +/* Flex annoyingly generates some functions without making them + * static. Let's declare them here. */ +int glcpp_get_column (yyscan_t yyscanner); +void glcpp_set_column (int column_no , yyscan_t yyscanner); + +#ifdef _MSC_VER +#define YY_NO_UNISTD_H +#endif + +#define YY_NO_INPUT + +#define YY_USER_ACTION \ + do { \ + yylloc->first_column = yycolumn + 1; \ + yylloc->first_line = yylineno; \ + yycolumn += yyleng; \ + } while(0); + +#define YY_USER_INIT \ + do { \ + yylineno = 1; \ + yycolumn = 1; \ + yylloc->source = 0; \ + } while(0) +%} + +%option bison-bridge bison-locations reentrant noyywrap +%option extra-type="glcpp_parser_t *" +%option prefix="glcpp_" +%option stack +%option never-interactive + +%x DONE COMMENT UNREACHABLE SKIP + +SPACE [[:space:]] +NONSPACE [^[:space:]] +NEWLINE [\n] +HSPACE [ \t] +HASH ^{HSPACE}*#{HSPACE}* +IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* +PUNCTUATION [][(){}.&*~!/%<>^|;,=+-] + +/* The OTHER class is simply a catch-all for things that the CPP +parser just doesn't care about. Since flex regular expressions that +match longer strings take priority over those matching shorter +strings, we have to be careful to avoid OTHER matching and hiding +something that CPP does care about. So we simply exclude all +characters that appear in any other expressions. */ + +OTHER [^][_#[:space:]#a-zA-Z0-9(){}.&*~!/%<>^|;,=+-] + +DIGITS [0-9][0-9]* +DECIMAL_INTEGER [1-9][0-9]*[uU]? +OCTAL_INTEGER 0[0-7]*[uU]? +HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]? + +%% + /* Implicitly switch between SKIP and INITIAL (non-skipping); + * don't switch if some other state was explicitly set. + */ + glcpp_parser_t *parser = yyextra; + if (YY_START == 0 || YY_START == SKIP) { + if (parser->lexing_if || parser->skip_stack == NULL || parser->skip_stack->type == SKIP_NO_SKIP) { + BEGIN 0; + } else { + BEGIN SKIP; + } + } + + /* Single-line comments */ +"//"[^\n]* { +} + + /* Multi-line comments */ +"/*" { yy_push_state(COMMENT, yyscanner); } +<COMMENT>[^*\n]* +<COMMENT>[^*\n]*\n { yylineno++; yycolumn = 0; return NEWLINE; } +<COMMENT>"*"+[^*/\n]* +<COMMENT>"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; return NEWLINE; } +<COMMENT>"*"+"/" { + yy_pop_state(yyscanner); + if (yyextra->space_tokens) + return SPACE; +} + +{HASH}version { + yylval->str = ralloc_strdup (yyextra, yytext); + yyextra->space_tokens = 0; + return HASH_VERSION; +} + + /* glcpp doesn't handle #extension, #version, or #pragma directives. + * Simply pass them through to the main compiler's lexer/parser. */ +{HASH}(extension|pragma)[^\n]+ { + yylval->str = ralloc_strdup (yyextra, yytext); + yylineno++; + yycolumn = 0; + return OTHER; +} + +{HASH}line{HSPACE}+{DIGITS}{HSPACE}+{DIGITS}{HSPACE}*$ { + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; + yylloc->source = strtol(ptr, NULL, 0); +} + +{HASH}line{HSPACE}+{DIGITS}{HSPACE}*$ { + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; +} + +<SKIP,INITIAL>{ +{HASH}ifdef { + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IFDEF; +} + +{HASH}ifndef { + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IFNDEF; +} + +{HASH}if/[^_a-zA-Z0-9] { + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IF; +} + +{HASH}elif { + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_ELIF; +} + +{HASH}else { + yyextra->space_tokens = 0; + return HASH_ELSE; +} + +{HASH}endif { + yyextra->space_tokens = 0; + return HASH_ENDIF; +} +} + +<SKIP>[^\n] ; + +{HASH}error.* { + char *p; + for (p = yytext; !isalpha(p[0]); p++); /* skip " # " */ + p += 5; /* skip "error" */ + glcpp_error(yylloc, yyextra, "#error%s", p); +} + +{HASH}define{HSPACE}+/{IDENTIFIER}"(" { + yyextra->space_tokens = 0; + return HASH_DEFINE_FUNC; +} + +{HASH}define { + yyextra->space_tokens = 0; + return HASH_DEFINE_OBJ; +} + +{HASH}undef { + yyextra->space_tokens = 0; + return HASH_UNDEF; +} + +{HASH} { + yyextra->space_tokens = 0; + return HASH; +} + +{DECIMAL_INTEGER} { + yylval->str = ralloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + +{OCTAL_INTEGER} { + yylval->str = ralloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + +{HEXADECIMAL_INTEGER} { + yylval->str = ralloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + +"<<" { + return LEFT_SHIFT; +} + +">>" { + return RIGHT_SHIFT; +} + +"<=" { + return LESS_OR_EQUAL; +} + +">=" { + return GREATER_OR_EQUAL; +} + +"==" { + return EQUAL; +} + +"!=" { + return NOT_EQUAL; +} + +"&&" { + return AND; +} + +"||" { + return OR; +} + +"##" { + return PASTE; +} + +"defined" { + return DEFINED; +} + +{IDENTIFIER} { + yylval->str = ralloc_strdup (yyextra, yytext); + return IDENTIFIER; +} + +{PUNCTUATION} { + return yytext[0]; +} + +{OTHER}+ { + yylval->str = ralloc_strdup (yyextra, yytext); + return OTHER; +} + +{HSPACE}+ { + if (yyextra->space_tokens) { + return SPACE; + } +} + +<SKIP,INITIAL>\n { + yyextra->lexing_if = 0; + yylineno++; + yycolumn = 0; + return NEWLINE; +} + + /* Handle missing newline at EOF. */ +<INITIAL><<EOF>> { + BEGIN DONE; /* Don't keep matching this rule forever. */ + yyextra->lexing_if = 0; + return NEWLINE; +} + + /* We don't actually use the UNREACHABLE start condition. We + only have this action here so that we can pretend to call some + generated functions, (to avoid "defined but not used" + warnings. */ +<UNREACHABLE>. { + unput('.'); + yy_top_state(yyextra); +} + +%% + +void +glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader) +{ + yy_scan_string(shader, parser->scanner); +} diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y index 2b7e65cd4..efcc205c2 100644 --- a/mesalib/src/glsl/glcpp/glcpp-parse.y +++ b/mesalib/src/glsl/glcpp/glcpp-parse.y @@ -85,7 +85,6 @@ _token_create_ival (void *ctx, int type, int ival); static token_list_t * _token_list_create (void *ctx); -/* Note: This function calls ralloc_steal on token. */ static void _token_list_append (token_list_t *list, token_t *token); @@ -763,8 +762,6 @@ _token_list_append (token_list_t *list, token_t *token) node->token = token; node->next = NULL; - ralloc_steal (list, token); - if (list->head == NULL) { list->head = node; } else { diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index e774b4697..d5e85abc0 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -1671,6 +1671,7 @@ switch_statement: SWITCH '(' expression ')' switch_body { $$ = new(state) ast_switch_statement($3, $5); + $$->set_location(yylloc); } ; @@ -1691,10 +1692,12 @@ case_label: CASE expression ':' { $$ = new(state) ast_case_label($2); + $$->set_location(yylloc); } | DEFAULT ':' { $$ = new(state) ast_case_label(NULL); + $$->set_location(yylloc); } ; @@ -1705,6 +1708,7 @@ case_label_list: labels->labels.push_tail(& $1->link); $$ = labels; + $$->set_location(yylloc); } | case_label_list case_label { @@ -1717,6 +1721,7 @@ case_statement: case_label_list statement { ast_case_statement *stmts = new(state) ast_case_statement($1); + stmts->set_location(yylloc); stmts->stmts.push_tail(& $2->link); $$ = stmts; @@ -1732,6 +1737,7 @@ case_statement_list: case_statement { ast_case_statement_list *cases= new(state) ast_case_statement_list(); + cases->set_location(yylloc); cases->cases.push_tail(& $1->link); $$ = cases; diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index 7f8d47ce9..2a72ba1f6 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -51,7 +51,7 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx, this->info_log = ralloc_strdup(mem_ctx, ""); this->error = false; this->loop_nesting_ast = NULL; - this->switch_nesting_ast = NULL; + this->switch_state.switch_nesting_ast = NULL; this->num_builtins_to_link = 0; diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index ee714637d..ce207ecda 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -42,6 +42,20 @@ enum _mesa_glsl_parser_targets { struct gl_context; +struct glsl_switch_state { + /** Temporary variables needed for switch statement. */ + ir_variable *test_var; + ir_variable *is_fallthru_var; + ir_variable *is_break_var; + class ast_switch_statement *switch_nesting_ast; + + /** Table of constant values already used in case labels */ + struct hash_table *labels_ht; + class ast_case_label *previous_default; + + bool is_switch_innermost; // if switch stmt is closest to break, ... +}; + struct _mesa_glsl_parse_state { _mesa_glsl_parse_state(struct gl_context *ctx, GLenum target, void *mem_ctx); @@ -154,13 +168,8 @@ struct _mesa_glsl_parse_state { /** Loop or switch statement containing the current instructions. */ class ast_iteration_statement *loop_nesting_ast; - class ast_switch_statement *switch_nesting_ast; - bool is_switch_innermost; // if switch stmt is closest to break, ... - /** Temporary variables needed for switch statement. */ - ir_variable *test_var; - ir_variable *is_fallthru_var; - ir_variable *is_break_var; + struct glsl_switch_state switch_state; /** List of structures defined in user code. */ const glsl_type **user_structures; diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index 509575192..82bddb003 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -856,6 +856,27 @@ get_main_function_signature(gl_shader *sh) /** + * This class is only used in link_intrastage_shaders() below but declaring + * it inside that function leads to compiler warnings with some versions of + * gcc. + */ +class array_sizing_visitor : public ir_hierarchical_visitor { +public: + virtual ir_visitor_status visit(ir_variable *var) + { + if (var->type->is_array() && (var->type->length == 0)) { + const glsl_type *type = + glsl_type::get_array_instance(var->type->fields.array, + var->max_array_access + 1); + assert(type != NULL); + var->type = type; + } + return visit_continue; + } +}; + + +/** * Combine a group of shaders for a single stage to generate a linked shader * * \note @@ -1005,22 +1026,7 @@ link_intrastage_shaders(void *mem_ctx, * max_array_access field. */ if (linked != NULL) { - class array_sizing_visitor : public ir_hierarchical_visitor { - public: - virtual ir_visitor_status visit(ir_variable *var) - { - if (var->type->is_array() && (var->type->length == 0)) { - const glsl_type *type = - glsl_type::get_array_instance(var->type->fields.array, - var->max_array_access + 1); - - assert(type != NULL); - var->type = type; - } - - return visit_continue; - } - } v; + array_sizing_visitor v; v.run(linked->ir); } |