aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2011-02-01 10:46:14 +0000
committermarha <marha@users.sourceforge.net>2011-02-01 10:46:14 +0000
commitd4a8565009962e162d86a9c4ae24062a3fa12025 (patch)
treebcd249c3c523b23a6350b1d6b5a2cff7518cdb0e /mesalib/src/glsl
parent6751d9898be671d253d6f7b0806cd4b10daaaf85 (diff)
parent0bf07d32cbd460220c67d726900772cf3692746d (diff)
downloadvcxsrv-d4a8565009962e162d86a9c4ae24062a3fa12025.tar.gz
vcxsrv-d4a8565009962e162d86a9c4ae24062a3fa12025.tar.bz2
vcxsrv-d4a8565009962e162d86a9c4ae24062a3fa12025.zip
svn merge ^/branches/released .
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/Makefile365
-rw-r--r--mesalib/src/glsl/SConscript22
-rw-r--r--mesalib/src/glsl/ast.h12
-rw-r--r--mesalib/src/glsl/ast_function.cpp2547
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp4
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-lex.c5358
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-lex.l650
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-parse.c8425
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-parse.h7
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-parse.y3781
-rw-r--r--mesalib/src/glsl/glcpp/glcpp.c278
-rw-r--r--mesalib/src/glsl/glcpp/glcpp.h4
-rw-r--r--mesalib/src/glsl/glcpp/pp.c30
-rw-r--r--mesalib/src/glsl/glsl_lexer.cpp2
-rw-r--r--mesalib/src/glsl/glsl_lexer.lpp2
-rw-r--r--mesalib/src/glsl/glsl_parser.cpp527
-rw-r--r--mesalib/src/glsl/glsl_parser.ypp33
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp52
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.h38
-rw-r--r--mesalib/src/glsl/glsl_symbol_table.cpp16
-rw-r--r--mesalib/src/glsl/glsl_symbol_table.h260
-rw-r--r--mesalib/src/glsl/glsl_types.cpp994
-rw-r--r--mesalib/src/glsl/glsl_types.h951
-rw-r--r--mesalib/src/glsl/ir.cpp35
-rw-r--r--mesalib/src/glsl/ir.h34
-rw-r--r--mesalib/src/glsl/ir_clone.cpp840
-rw-r--r--mesalib/src/glsl/ir_constant_expression.cpp2708
-rw-r--r--mesalib/src/glsl/ir_expression_flattening.cpp2
-rw-r--r--mesalib/src/glsl/ir_function.cpp453
-rw-r--r--mesalib/src/glsl/ir_hv_accept.cpp6
-rw-r--r--mesalib/src/glsl/ir_import_prototypes.cpp246
-rw-r--r--mesalib/src/glsl/ir_print_visitor.cpp934
-rw-r--r--mesalib/src/glsl/ir_reader.cpp41
-rw-r--r--mesalib/src/glsl/ir_rvalue_visitor.cpp1
-rw-r--r--mesalib/src/glsl/ir_validate.cpp1058
-rw-r--r--mesalib/src/glsl/ir_variable.cpp1081
-rw-r--r--mesalib/src/glsl/ir_variable_refcount.h4
-rw-r--r--mesalib/src/glsl/linker.cpp23
-rw-r--r--mesalib/src/glsl/list.h32
-rw-r--r--mesalib/src/glsl/loop_analysis.cpp14
-rw-r--r--mesalib/src/glsl/loop_controls.cpp608
-rw-r--r--mesalib/src/glsl/loop_unroll.cpp428
-rw-r--r--mesalib/src/glsl/lower_discard.cpp396
-rw-r--r--mesalib/src/glsl/lower_if_to_cond_assign.cpp400
-rw-r--r--mesalib/src/glsl/lower_mat_op_to_vec.cpp980
-rw-r--r--mesalib/src/glsl/lower_noise.cpp2
-rw-r--r--mesalib/src/glsl/lower_texture_projection.cpp198
-rw-r--r--mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp765
-rw-r--r--mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp516
-rw-r--r--mesalib/src/glsl/lower_vec_index_to_swizzle.cpp314
-rw-r--r--mesalib/src/glsl/lower_vector.cpp448
-rw-r--r--mesalib/src/glsl/main.cpp688
-rw-r--r--mesalib/src/glsl/opt_algebraic.cpp822
-rw-r--r--mesalib/src/glsl/opt_constant_folding.cpp294
-rw-r--r--mesalib/src/glsl/opt_constant_propagation.cpp874
-rw-r--r--mesalib/src/glsl/opt_copy_propagation.cpp696
-rw-r--r--mesalib/src/glsl/opt_dead_code_local.cpp458
-rw-r--r--mesalib/src/glsl/opt_dead_functions.cpp306
-rw-r--r--mesalib/src/glsl/opt_function_inlining.cpp849
-rw-r--r--mesalib/src/glsl/opt_structure_splitting.cpp722
-rw-r--r--mesalib/src/glsl/opt_tree_grafting.cpp735
-rw-r--r--mesalib/src/glsl/ralloc.c448
-rw-r--r--mesalib/src/glsl/ralloc.h345
-rw-r--r--mesalib/src/glsl/s_expression.cpp372
-rw-r--r--mesalib/src/glsl/s_expression.h360
65 files changed, 22897 insertions, 21997 deletions
diff --git a/mesalib/src/glsl/Makefile b/mesalib/src/glsl/Makefile
index 22e01415f..4f307422c 100644
--- a/mesalib/src/glsl/Makefile
+++ b/mesalib/src/glsl/Makefile
@@ -1,183 +1,182 @@
-#src/glsl/pp/Makefile
-
-TOP = ../..
-
-include $(TOP)/configs/current
-
-LIBNAME = glsl
-
-LIBGLCPP_SOURCES = \
- glcpp/glcpp-lex.c \
- glcpp/glcpp-parse.c \
- glcpp/pp.c
-
-GLCPP_SOURCES = \
- $(LIBGLCPP_SOURCES) \
- glcpp/glcpp.c
-
-C_SOURCES = \
- strtod.c \
- $(LIBGLCPP_SOURCES)
-
-CXX_SOURCES = \
- ast_expr.cpp \
- ast_function.cpp \
- ast_to_hir.cpp \
- ast_type.cpp \
- glsl_lexer.cpp \
- glsl_parser.cpp \
- glsl_parser_extras.cpp \
- glsl_types.cpp \
- glsl_symbol_table.cpp \
- hir_field_selection.cpp \
- ir_basic_block.cpp \
- ir_clone.cpp \
- ir_constant_expression.cpp \
- ir.cpp \
- ir_expression_flattening.cpp \
- ir_function_can_inline.cpp \
- ir_function.cpp \
- ir_hierarchical_visitor.cpp \
- ir_hv_accept.cpp \
- ir_import_prototypes.cpp \
- ir_print_visitor.cpp \
- ir_reader.cpp \
- ir_rvalue_visitor.cpp \
- ir_set_program_inouts.cpp \
- ir_validate.cpp \
- ir_variable.cpp \
- ir_variable_refcount.cpp \
- linker.cpp \
- link_functions.cpp \
- loop_analysis.cpp \
- loop_controls.cpp \
- loop_unroll.cpp \
- lower_discard.cpp \
- lower_if_to_cond_assign.cpp \
- lower_instructions.cpp \
- lower_jumps.cpp \
- lower_mat_op_to_vec.cpp \
- lower_noise.cpp \
- lower_texture_projection.cpp \
- lower_variable_index_to_cond_assign.cpp \
- lower_vec_index_to_cond_assign.cpp \
- lower_vec_index_to_swizzle.cpp \
- lower_vector.cpp \
- opt_algebraic.cpp \
- opt_constant_folding.cpp \
- opt_constant_propagation.cpp \
- opt_constant_variable.cpp \
- opt_copy_propagation.cpp \
- opt_dead_code.cpp \
- opt_dead_code_local.cpp \
- opt_dead_functions.cpp \
- opt_discard_simplification.cpp \
- opt_function_inlining.cpp \
- opt_if_simplification.cpp \
- opt_noop_swizzle.cpp \
- opt_redundant_jumps.cpp \
- opt_structure_splitting.cpp \
- opt_swizzle_swizzle.cpp \
- opt_tree_grafting.cpp \
- s_expression.cpp
-
-LIBS = \
- $(TOP)/src/glsl/libglsl.a \
- $(TALLOC_LIBS)
-
-APPS = glsl_compiler glcpp/glcpp
-
-GLSL2_C_SOURCES = \
- ../mesa/program/hash_table.c \
- ../mesa/program/symbol_table.c
-GLSL2_CXX_SOURCES = \
- main.cpp
-
-GLSL2_OBJECTS = \
- $(GLSL2_C_SOURCES:.c=.o) \
- $(GLSL2_CXX_SOURCES:.cpp=.o)
-
-### Basic defines ###
-
-DEFINES += \
- $(LIBRARY_DEFINES) \
- $(API_DEFINES)
-
-GLCPP_OBJECTS = \
- $(GLCPP_SOURCES:.c=.o) \
- ../mesa/program/hash_table.o
-
-OBJECTS = \
- $(C_SOURCES:.c=.o) \
- $(CXX_SOURCES:.cpp=.o)
-
-INCLUDES = \
- $(TALLOC_CFLAGS) \
- -I. \
- -I../mesa \
- -I../mapi \
- -I../../include \
- $(LIBRARY_INCLUDES)
-
-ALL_SOURCES = \
- $(C_SOURCES) \
- $(CXX_SOURCES) \
- $(GLSL2_CXX_SOURCES) \
- $(GLSL2_C_SOURCES)
-
-##### TARGETS #####
-
-default: depend lib$(LIBNAME).a $(APPS)
-
-lib$(LIBNAME).a: $(OBJECTS) builtin_function.o Makefile $(TOP)/src/glsl/Makefile.template
- $(MKLIB) -cplusplus -o $(LIBNAME) -static $(OBJECTS) builtin_function.o
-
-depend: $(ALL_SOURCES) Makefile
- rm -f depend
- touch depend
- $(MKDEP) $(MKDEP_OPTIONS) $(INCLUDES) $(ALL_SOURCES) 2> /dev/null
-
-# Remove .o and backup files
-clean:
- rm -f $(GLCPP_OBJECTS) $(GLSL2_OBJECTS) $(OBJECTS) lib$(LIBNAME).a depend depend.bak builtin_function.cpp builtin_function.o builtin_stubs.o builtin_compiler
- -rm -f $(APPS)
-
-# Dummy target
-install:
- @echo -n ""
-
-
-##### RULES #####
-
-glsl_compiler: $(GLSL2_OBJECTS) libglsl.a
- $(APP_CXX) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(GLSL2_OBJECTS) $(LIBS) -o $@
-
-glcpp/glcpp: $(GLCPP_OBJECTS) libglsl.a
- $(APP_CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(GLCPP_OBJECTS) $(LIBS) -o $@
-
-.cpp.o:
- $(CXX) -c $(INCLUDES) $(CXXFLAGS) $(DEFINES) $< -o $@
-
-.c.o:
- $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
-
-glsl_lexer.cpp: glsl_lexer.lpp
- flex --nounistd -o$@ $<
-
-glsl_parser.cpp: glsl_parser.ypp
- bison -v -o "$@" -p "_mesa_glsl_" --defines=glsl_parser.h $<
-
-glcpp/glcpp-lex.c: glcpp/glcpp-lex.l
- flex --nounistd -o$@ $<
-
-glcpp/glcpp-parse.c: glcpp/glcpp-parse.y
- bison -v -o "$@" --defines=glcpp/glcpp-parse.h $<
-
-builtin_compiler: $(GLSL2_OBJECTS) $(OBJECTS) builtin_stubs.o
- $(APP_CXX) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $(GLSL2_OBJECTS) builtin_stubs.o $(TALLOC_LIBS) -o $@
-
-builtin_function.cpp: builtins/profiles/* builtins/ir/* builtins/tools/generate_builtins.py builtins/tools/texture_builtins.py builtin_compiler
- @echo Regenerating builtin_function.cpp...
- $(PYTHON2) $(PYTHON_FLAGS) builtins/tools/generate_builtins.py $(PWD)/builtin_compiler > builtin_function.cpp
-
--include depend
+#src/glsl/pp/Makefile
+
+TOP = ../..
+
+include $(TOP)/configs/current
+
+LIBNAME = glsl
+
+LIBGLCPP_SOURCES = \
+ glcpp/glcpp-lex.c \
+ glcpp/glcpp-parse.c \
+ glcpp/pp.c
+
+GLCPP_SOURCES = \
+ $(LIBGLCPP_SOURCES) \
+ glcpp/glcpp.c
+
+C_SOURCES = \
+ strtod.c \
+ ralloc.c \
+ $(LIBGLCPP_SOURCES)
+
+CXX_SOURCES = \
+ ast_expr.cpp \
+ ast_function.cpp \
+ ast_to_hir.cpp \
+ ast_type.cpp \
+ glsl_lexer.cpp \
+ glsl_parser.cpp \
+ glsl_parser_extras.cpp \
+ glsl_types.cpp \
+ glsl_symbol_table.cpp \
+ hir_field_selection.cpp \
+ ir_basic_block.cpp \
+ ir_clone.cpp \
+ ir_constant_expression.cpp \
+ ir.cpp \
+ ir_expression_flattening.cpp \
+ ir_function_can_inline.cpp \
+ ir_function.cpp \
+ ir_hierarchical_visitor.cpp \
+ ir_hv_accept.cpp \
+ ir_import_prototypes.cpp \
+ ir_print_visitor.cpp \
+ ir_reader.cpp \
+ ir_rvalue_visitor.cpp \
+ ir_set_program_inouts.cpp \
+ ir_validate.cpp \
+ ir_variable.cpp \
+ ir_variable_refcount.cpp \
+ linker.cpp \
+ link_functions.cpp \
+ loop_analysis.cpp \
+ loop_controls.cpp \
+ loop_unroll.cpp \
+ lower_discard.cpp \
+ lower_if_to_cond_assign.cpp \
+ lower_instructions.cpp \
+ lower_jumps.cpp \
+ lower_mat_op_to_vec.cpp \
+ lower_noise.cpp \
+ lower_texture_projection.cpp \
+ lower_variable_index_to_cond_assign.cpp \
+ lower_vec_index_to_cond_assign.cpp \
+ lower_vec_index_to_swizzle.cpp \
+ lower_vector.cpp \
+ opt_algebraic.cpp \
+ opt_constant_folding.cpp \
+ opt_constant_propagation.cpp \
+ opt_constant_variable.cpp \
+ opt_copy_propagation.cpp \
+ opt_dead_code.cpp \
+ opt_dead_code_local.cpp \
+ opt_dead_functions.cpp \
+ opt_discard_simplification.cpp \
+ opt_function_inlining.cpp \
+ opt_if_simplification.cpp \
+ opt_noop_swizzle.cpp \
+ opt_redundant_jumps.cpp \
+ opt_structure_splitting.cpp \
+ opt_swizzle_swizzle.cpp \
+ opt_tree_grafting.cpp \
+ s_expression.cpp
+
+LIBS = \
+ $(TOP)/src/glsl/libglsl.a
+
+APPS = glsl_compiler glcpp/glcpp
+
+GLSL2_C_SOURCES = \
+ ../mesa/program/hash_table.c \
+ ../mesa/program/symbol_table.c
+GLSL2_CXX_SOURCES = \
+ main.cpp
+
+GLSL2_OBJECTS = \
+ $(GLSL2_C_SOURCES:.c=.o) \
+ $(GLSL2_CXX_SOURCES:.cpp=.o)
+
+### Basic defines ###
+
+DEFINES += \
+ $(LIBRARY_DEFINES) \
+ $(API_DEFINES)
+
+GLCPP_OBJECTS = \
+ $(GLCPP_SOURCES:.c=.o) \
+ ../mesa/program/hash_table.o
+
+OBJECTS = \
+ $(C_SOURCES:.c=.o) \
+ $(CXX_SOURCES:.cpp=.o)
+
+INCLUDES = \
+ -I. \
+ -I../mesa \
+ -I../mapi \
+ -I../../include \
+ $(LIBRARY_INCLUDES)
+
+ALL_SOURCES = \
+ $(C_SOURCES) \
+ $(CXX_SOURCES) \
+ $(GLSL2_CXX_SOURCES) \
+ $(GLSL2_C_SOURCES)
+
+##### TARGETS #####
+
+default: depend lib$(LIBNAME).a $(APPS)
+
+lib$(LIBNAME).a: $(OBJECTS) builtin_function.o Makefile $(TOP)/src/glsl/Makefile.template
+ $(MKLIB) -cplusplus -o $(LIBNAME) -static $(OBJECTS) builtin_function.o
+
+depend: $(ALL_SOURCES) Makefile
+ rm -f depend
+ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(INCLUDES) $(ALL_SOURCES) 2> /dev/null
+
+# Remove .o and backup files
+clean:
+ rm -f $(GLCPP_OBJECTS) $(GLSL2_OBJECTS) $(OBJECTS) lib$(LIBNAME).a depend depend.bak builtin_function.cpp builtin_function.o builtin_stubs.o builtin_compiler
+ -rm -f $(APPS)
+
+# Dummy target
+install:
+ @echo -n ""
+
+
+##### RULES #####
+
+glsl_compiler: $(GLSL2_OBJECTS) libglsl.a builtin_stubs.o
+ $(APP_CXX) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(GLSL2_OBJECTS) builtin_stubs.o $(LIBS) -o $@
+
+glcpp/glcpp: $(GLCPP_OBJECTS) libglsl.a
+ $(APP_CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(GLCPP_OBJECTS) $(LIBS) -o $@
+
+.cpp.o:
+ $(CXX) -c $(INCLUDES) $(CXXFLAGS) $(DEFINES) $< -o $@
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+glsl_lexer.cpp: glsl_lexer.lpp
+ flex --nounistd -o$@ $<
+
+glsl_parser.cpp: glsl_parser.ypp
+ bison -v -o "$@" -p "_mesa_glsl_" --defines=glsl_parser.h $<
+
+glcpp/glcpp-lex.c: glcpp/glcpp-lex.l
+ flex --nounistd -o$@ $<
+
+glcpp/glcpp-parse.c: glcpp/glcpp-parse.y
+ bison -v -o "$@" --defines=glcpp/glcpp-parse.h $<
+
+builtin_compiler: $(GLSL2_OBJECTS) $(OBJECTS) builtin_stubs.o
+ $(APP_CXX) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $(GLSL2_OBJECTS) builtin_stubs.o -o $@
+
+builtin_function.cpp: builtins/profiles/* builtins/ir/* builtins/tools/generate_builtins.py builtins/tools/texture_builtins.py builtin_compiler
+ @echo Regenerating builtin_function.cpp...
+ $(PYTHON2) $(PYTHON_FLAGS) builtins/tools/generate_builtins.py $(PWD)/builtin_compiler > builtin_function.cpp
+
+-include depend
diff --git a/mesalib/src/glsl/SConscript b/mesalib/src/glsl/SConscript
index 5885e4b4f..2cc7b0eda 100644
--- a/mesalib/src/glsl/SConscript
+++ b/mesalib/src/glsl/SConscript
@@ -7,14 +7,12 @@ from sys import executable as python_cmd
env = env.Clone()
env.Prepend(CPPPATH = [
+ '#include',
'#src/mapi',
'#src/mesa',
'#src/glsl',
])
-if env['platform'] == 'windows':
- env.Prepend(CPPPATH = ['#src/talloc'])
-
sources = [
'glcpp/glcpp-lex.c',
'glcpp/glcpp-parse.c',
@@ -77,6 +75,7 @@ sources = [
'opt_structure_splitting.cpp',
'opt_swizzle_swizzle.cpp',
'opt_tree_grafting.cpp',
+ 'ralloc.c',
's_expression.cpp',
'strtod.c',
]
@@ -87,13 +86,6 @@ if env['platform'] == common.host_platform:
env.Prepend(CPPPATH = ['#/src/getopt'])
env.PrependUnique(LIBS = [getopt])
- if env['platform'] == 'windows':
- env.Prepend(CPPPATH = ['#src/talloc'])
- env.Prepend(LIBS = [talloc])
- else:
- env.Prepend(CPPPATH = ['#include'])
- env.Prepend(LIBS = ['talloc'])
-
builtin_compiler = env.Program(
target = 'builtin_compiler',
source = sources + ['main.cpp', 'builtin_stubs.cpp',
@@ -110,14 +102,6 @@ if env['platform'] == common.host_platform:
env.Depends(builtin_glsl_function, ['builtins/tools/generate_builtins.py', 'builtins/tools/texture_builtins.py'] + Glob('builtins/ir/*'))
- if env['msvc']:
- # There is no LD_LIBRARY_PATH equivalent on Windows. We need to ensure
- # talloc.dll is on the same dir as builtin_function.
- talloc_dll_src = talloc.dir.File('talloc.dll')
- talloc_dll_dst = builtin_compiler[0].dir.File('talloc.dll')
- talloc_dll = env.Command(talloc_dll_dst, talloc_dll_src, Copy(talloc_dll_dst, talloc_dll_src))
- env.Depends('builtin_function.cpp', talloc_dll)
-
Export('builtin_glsl_function')
if common.cross_compiling:
@@ -142,7 +126,7 @@ if env['platform'] == 'windows':
'user32',
])
-env.Prepend(LIBS = [glsl, talloc])
+env.Prepend(LIBS = [glsl])
env.Program(
target = 'glsl2',
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h
index 23b3b78b2..6963b83af 100644
--- a/mesalib/src/glsl/ast.h
+++ b/mesalib/src/glsl/ast.h
@@ -49,27 +49,27 @@ struct YYLTYPE;
*/
class ast_node {
public:
- /* Callers of this talloc-based new need not call delete. It's
- * easier to just talloc_free 'ctx' (or any of its ancestors). */
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
static void* operator new(size_t size, void *ctx)
{
void *node;
- node = talloc_zero_size(ctx, size);
+ node = rzalloc_size(ctx, size);
assert(node != NULL);
return node;
}
/* If the user *does* call delete, that's OK, we will just
- * talloc_free in that case. */
+ * ralloc_free in that case. */
static void operator delete(void *table, void *ctx)
{
- talloc_free(table);
+ ralloc_free(table);
}
static void operator delete(void *table)
{
- talloc_free(table);
+ ralloc_free(table);
}
/**
diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp
index 02261d68f..28d49ee0d 100644
--- a/mesalib/src/glsl/ast_function.cpp
+++ b/mesalib/src/glsl/ast_function.cpp
@@ -1,1269 +1,1278 @@
-/*
- * 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 "glsl_symbol_table.h"
-#include "ast.h"
-#include "glsl_types.h"
-#include "ir.h"
-#include "main/core.h" /* for MIN2 */
-
-static ir_rvalue *
-convert_component(ir_rvalue *src, const glsl_type *desired_type);
-
-bool
-apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from,
- struct _mesa_glsl_parse_state *state);
-
-static unsigned
-process_parameters(exec_list *instructions, exec_list *actual_parameters,
- exec_list *parameters,
- struct _mesa_glsl_parse_state *state)
-{
- unsigned count = 0;
-
- foreach_list (n, parameters) {
- ast_node *const ast = exec_node_data(ast_node, n, link);
- ir_rvalue *result = ast->hir(instructions, state);
-
- ir_constant *const constant = result->constant_expression_value();
- if (constant != NULL)
- result = constant;
-
- actual_parameters->push_tail(result);
- count++;
- }
-
- return count;
-}
-
-
-/**
- * Generate a source prototype for a function signature
- *
- * \param return_type Return type of the function. May be \c NULL.
- * \param name Name of the function.
- * \param parameters Parameter list for the function. This may be either a
- * formal or actual parameter list. Only the type is used.
- *
- * \return
- * A talloced string representing the prototype of the function.
- */
-char *
-prototype_string(const glsl_type *return_type, const char *name,
- exec_list *parameters)
-{
- char *str = NULL;
-
- if (return_type != NULL)
- str = talloc_asprintf(str, "%s ", return_type->name);
-
- str = talloc_asprintf_append(str, "%s(", name);
-
- const char *comma = "";
- foreach_list(node, parameters) {
- const ir_instruction *const param = (ir_instruction *) node;
-
- str = talloc_asprintf_append(str, "%s%s", comma, param->type->name);
- comma = ", ";
- }
-
- str = talloc_strdup_append(str, ")");
- return str;
-}
-
-
-static ir_rvalue *
-match_function_by_name(exec_list *instructions, const char *name,
- YYLTYPE *loc, exec_list *actual_parameters,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
- ir_function *f = state->symbols->get_function(name);
- ir_function_signature *sig;
-
- sig = f ? f->matching_signature(actual_parameters) : NULL;
-
- /* FINISHME: This doesn't handle the case where shader X contains a
- * FINISHME: matching signature but shader X + N contains an _exact_
- * FINISHME: matching signature.
- */
- if (sig == NULL && (f == NULL || state->es_shader || !f->has_user_signature()) && state->symbols->get_type(name) == NULL && (state->language_version == 110 || state->symbols->get_variable(name) == NULL)) {
- /* The current shader doesn't contain a matching function or signature.
- * Before giving up, look for the prototype in the built-in functions.
- */
- for (unsigned i = 0; i < state->num_builtins_to_link; i++) {
- ir_function *builtin;
- builtin = state->builtins_to_link[i]->symbols->get_function(name);
- sig = builtin ? builtin->matching_signature(actual_parameters) : NULL;
- if (sig != NULL) {
- if (f == NULL) {
- f = new(ctx) ir_function(name);
- state->symbols->add_global_function(f);
- emit_function(state, instructions, f);
- }
-
- f->add_signature(sig->clone_prototype(f, NULL));
- break;
- }
- }
- }
-
- if (sig != NULL) {
- /* Verify that 'out' and 'inout' actual parameters are lvalues. This
- * isn't done in ir_function::matching_signature because that function
- * cannot generate the necessary diagnostics.
- */
- exec_list_iterator actual_iter = actual_parameters->iterator();
- exec_list_iterator formal_iter = sig->parameters.iterator();
-
- while (actual_iter.has_next()) {
- ir_rvalue *actual = (ir_rvalue *) actual_iter.get();
- ir_variable *formal = (ir_variable *) formal_iter.get();
-
- assert(actual != NULL);
- assert(formal != NULL);
-
- if ((formal->mode == ir_var_out)
- || (formal->mode == ir_var_inout)) {
- const char *mode = NULL;
- switch (formal->mode) {
- case ir_var_out: mode = "out"; break;
- case ir_var_inout: mode = "inout"; break;
- default: assert(false); break;
- }
- /* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always
- * FIXME: 0:0(0).
- */
- if (actual->variable_referenced()
- && actual->variable_referenced()->read_only) {
- _mesa_glsl_error(loc, state,
- "function parameter '%s %s' references the "
- "read-only variable '%s'",
- mode, formal->name,
- actual->variable_referenced()->name);
-
- } else if (!actual->is_lvalue()) {
- _mesa_glsl_error(loc, state,
- "function parameter '%s %s' is not an lvalue",
- mode, formal->name);
- }
- }
-
- if (formal->type->is_numeric() || formal->type->is_boolean()) {
- ir_rvalue *converted = convert_component(actual, formal->type);
- actual->replace_with(converted);
- }
-
- actual_iter.next();
- formal_iter.next();
- }
-
- /* Always insert the call in the instruction stream, and return a deref
- * of its return val if it returns a value, since we don't know if
- * the rvalue is going to be assigned to anything or not.
- */
- ir_call *call = new(ctx) ir_call(sig, actual_parameters);
- if (!sig->return_type->is_void()) {
- ir_variable *var;
- ir_dereference_variable *deref;
-
- var = new(ctx) ir_variable(sig->return_type,
- talloc_asprintf(ctx, "%s_retval",
- sig->function_name()),
- ir_var_temporary);
- instructions->push_tail(var);
-
- deref = new(ctx) ir_dereference_variable(var);
- ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL);
- instructions->push_tail(assign);
- if (state->language_version >= 120)
- var->constant_value = call->constant_expression_value();
-
- deref = new(ctx) ir_dereference_variable(var);
- return deref;
- } else {
- instructions->push_tail(call);
- return NULL;
- }
- } else {
- char *str = prototype_string(NULL, name, actual_parameters);
-
- _mesa_glsl_error(loc, state, "no matching function for call to `%s'",
- str);
- talloc_free(str);
-
- const char *prefix = "candidates are: ";
-
- for (int i = -1; i < state->num_builtins_to_link; i++) {
- glsl_symbol_table *syms = i >= 0 ? state->builtins_to_link[i]->symbols
- : state->symbols;
- f = syms->get_function(name);
- if (f == NULL)
- continue;
-
- foreach_list (node, &f->signatures) {
- ir_function_signature *sig = (ir_function_signature *) node;
-
- str = prototype_string(sig->return_type, f->name, &sig->parameters);
- _mesa_glsl_error(loc, state, "%s%s\n", prefix, str);
- talloc_free(str);
-
- prefix = " ";
- }
-
- }
-
- return ir_call::get_error_instruction(ctx);
- }
-}
-
-
-/**
- * Perform automatic type conversion of constructor parameters
- *
- * This implements the rules in the "Conversion and Scalar Constructors"
- * section (GLSL 1.10 section 5.4.1), not the "Implicit Conversions" rules.
- */
-static ir_rvalue *
-convert_component(ir_rvalue *src, const glsl_type *desired_type)
-{
- void *ctx = talloc_parent(src);
- const unsigned a = desired_type->base_type;
- const unsigned b = src->type->base_type;
- ir_expression *result = NULL;
-
- if (src->type->is_error())
- return src;
-
- assert(a <= GLSL_TYPE_BOOL);
- assert(b <= GLSL_TYPE_BOOL);
-
- if ((a == b) || (src->type->is_integer() && desired_type->is_integer()))
- return src;
-
- switch (a) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- if (b == GLSL_TYPE_FLOAT)
- result = new(ctx) ir_expression(ir_unop_f2i, desired_type, src, NULL);
- else {
- assert(b == GLSL_TYPE_BOOL);
- result = new(ctx) ir_expression(ir_unop_b2i, desired_type, src, NULL);
- }
- break;
- case GLSL_TYPE_FLOAT:
- switch (b) {
- case GLSL_TYPE_UINT:
- result = new(ctx) ir_expression(ir_unop_u2f, desired_type, src, NULL);
- break;
- case GLSL_TYPE_INT:
- result = new(ctx) ir_expression(ir_unop_i2f, desired_type, src, NULL);
- break;
- case GLSL_TYPE_BOOL:
- result = new(ctx) ir_expression(ir_unop_b2f, desired_type, src, NULL);
- break;
- }
- break;
- case GLSL_TYPE_BOOL:
- switch (b) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- result = new(ctx) ir_expression(ir_unop_i2b, desired_type, src, NULL);
- break;
- case GLSL_TYPE_FLOAT:
- result = new(ctx) ir_expression(ir_unop_f2b, desired_type, src, NULL);
- break;
- }
- break;
- }
-
- assert(result != NULL);
-
- /* Try constant folding; it may fold in the conversion we just added. */
- ir_constant *const constant = result->constant_expression_value();
- return (constant != NULL) ? (ir_rvalue *) constant : (ir_rvalue *) result;
-}
-
-/**
- * Dereference a specific component from a scalar, vector, or matrix
- */
-static ir_rvalue *
-dereference_component(ir_rvalue *src, unsigned component)
-{
- void *ctx = talloc_parent(src);
- assert(component < src->type->components());
-
- /* If the source is a constant, just create a new constant instead of a
- * dereference of the existing constant.
- */
- ir_constant *constant = src->as_constant();
- if (constant)
- return new(ctx) ir_constant(constant, component);
-
- if (src->type->is_scalar()) {
- return src;
- } else if (src->type->is_vector()) {
- return new(ctx) ir_swizzle(src, component, 0, 0, 0, 1);
- } else {
- assert(src->type->is_matrix());
-
- /* Dereference a row of the matrix, then call this function again to get
- * a specific element from that row.
- */
- const int c = component / src->type->column_type()->vector_elements;
- const int r = component % src->type->column_type()->vector_elements;
- ir_constant *const col_index = new(ctx) ir_constant(c);
- ir_dereference *const col = new(ctx) ir_dereference_array(src, col_index);
-
- col->type = src->type->column_type();
-
- return dereference_component(col, r);
- }
-
- assert(!"Should not get here.");
- return NULL;
-}
-
-
-static ir_rvalue *
-process_array_constructor(exec_list *instructions,
- const glsl_type *constructor_type,
- YYLTYPE *loc, exec_list *parameters,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
- /* Array constructors come in two forms: sized and unsized. Sized array
- * constructors look like 'vec4[2](a, b)', where 'a' and 'b' are vec4
- * variables. In this case the number of parameters must exactly match the
- * specified size of the array.
- *
- * Unsized array constructors look like 'vec4[](a, b)', where 'a' and 'b'
- * are vec4 variables. In this case the size of the array being constructed
- * is determined by the number of parameters.
- *
- * From page 52 (page 58 of the PDF) of the GLSL 1.50 spec:
- *
- * "There must be exactly the same number of arguments as the size of
- * the array being constructed. If no size is present in the
- * constructor, then the array is explicitly sized to the number of
- * arguments provided. The arguments are assigned in order, starting at
- * element 0, to the elements of the constructed array. Each argument
- * must be the same type as the element type of the array, or be a type
- * that can be converted to the element type of the array according to
- * Section 4.1.10 "Implicit Conversions.""
- */
- exec_list actual_parameters;
- const unsigned parameter_count =
- process_parameters(instructions, &actual_parameters, parameters, state);
-
- if ((parameter_count == 0)
- || ((constructor_type->length != 0)
- && (constructor_type->length != parameter_count))) {
- const unsigned min_param = (constructor_type->length == 0)
- ? 1 : constructor_type->length;
-
- _mesa_glsl_error(loc, state, "array constructor must have %s %u "
- "parameter%s",
- (constructor_type->length != 0) ? "at least" : "exactly",
- min_param, (min_param <= 1) ? "" : "s");
- return ir_call::get_error_instruction(ctx);
- }
-
- if (constructor_type->length == 0) {
- constructor_type =
- glsl_type::get_array_instance(constructor_type->element_type(),
- parameter_count);
- assert(constructor_type != NULL);
- assert(constructor_type->length == parameter_count);
- }
-
- bool all_parameters_are_constant = true;
-
- /* Type cast each parameter and, if possible, fold constants. */
- foreach_list_safe(n, &actual_parameters) {
- ir_rvalue *ir = (ir_rvalue *) n;
- ir_rvalue *result = ir;
-
- /* Apply implicit conversions (not the scalar constructor rules!) */
- if (constructor_type->element_type()->is_float()) {
- const glsl_type *desired_type =
- glsl_type::get_instance(GLSL_TYPE_FLOAT,
- ir->type->vector_elements,
- ir->type->matrix_columns);
- result = convert_component(ir, desired_type);
- }
-
- if (result->type != constructor_type->element_type()) {
- _mesa_glsl_error(loc, state, "type error in array constructor: "
- "expected: %s, found %s",
- constructor_type->element_type()->name,
- result->type->name);
- }
-
- /* Attempt to convert the parameter to a constant valued expression.
- * After doing so, track whether or not all the parameters to the
- * constructor are trivially constant valued expressions.
- */
- ir_rvalue *const constant = result->constant_expression_value();
-
- if (constant != NULL)
- result = constant;
- else
- all_parameters_are_constant = false;
-
- ir->replace_with(result);
- }
-
- if (all_parameters_are_constant)
- return new(ctx) ir_constant(constructor_type, &actual_parameters);
-
- ir_variable *var = new(ctx) ir_variable(constructor_type, "array_ctor",
- ir_var_temporary);
- instructions->push_tail(var);
-
- int i = 0;
- foreach_list(node, &actual_parameters) {
- ir_rvalue *rhs = (ir_rvalue *) node;
- ir_rvalue *lhs = new(ctx) ir_dereference_array(var,
- new(ctx) ir_constant(i));
-
- ir_instruction *assignment = new(ctx) ir_assignment(lhs, rhs, NULL);
- instructions->push_tail(assignment);
-
- i++;
- }
-
- return new(ctx) ir_dereference_variable(var);
-}
-
-
-/**
- * Try to convert a record constructor to a constant expression
- */
-static ir_constant *
-constant_record_constructor(const glsl_type *constructor_type,
- exec_list *parameters, void *mem_ctx)
-{
- foreach_list(node, parameters) {
- ir_constant *constant = ((ir_instruction *) node)->as_constant();
- if (constant == NULL)
- return NULL;
- node->replace_with(constant);
- }
-
- return new(mem_ctx) ir_constant(constructor_type, parameters);
-}
-
-
-/**
- * Determine if a list consists of a single scalar r-value
- */
-bool
-single_scalar_parameter(exec_list *parameters)
-{
- const ir_rvalue *const p = (ir_rvalue *) parameters->head;
- assert(((ir_rvalue *)p)->as_rvalue() != NULL);
-
- return (p->type->is_scalar() && p->next->is_tail_sentinel());
-}
-
-
-/**
- * Generate inline code for a vector constructor
- *
- * The generated constructor code will consist of a temporary variable
- * declaration of the same type as the constructor. A sequence of assignments
- * from constructor parameters to the temporary will follow.
- *
- * \return
- * An \c ir_dereference_variable of the temprorary generated in the constructor
- * body.
- */
-ir_rvalue *
-emit_inline_vector_constructor(const glsl_type *type,
- exec_list *instructions,
- exec_list *parameters,
- void *ctx)
-{
- assert(!parameters->is_empty());
-
- ir_variable *var = new(ctx) ir_variable(type, "vec_ctor", ir_var_temporary);
- instructions->push_tail(var);
-
- /* There are two kinds of vector constructors.
- *
- * - Construct a vector from a single scalar by replicating that scalar to
- * all components of the vector.
- *
- * - Construct a vector from an arbirary combination of vectors and
- * scalars. The components of the constructor parameters are assigned
- * to the vector in order until the vector is full.
- */
- const unsigned lhs_components = type->components();
- if (single_scalar_parameter(parameters)) {
- ir_rvalue *first_param = (ir_rvalue *)parameters->head;
- ir_rvalue *rhs = new(ctx) ir_swizzle(first_param, 0, 0, 0, 0,
- lhs_components);
- ir_dereference_variable *lhs = new(ctx) ir_dereference_variable(var);
- const unsigned mask = (1U << lhs_components) - 1;
-
- assert(rhs->type == lhs->type);
-
- ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL, mask);
- instructions->push_tail(inst);
- } else {
- unsigned base_component = 0;
- unsigned base_lhs_component = 0;
- ir_constant_data data;
- unsigned constant_mask = 0, constant_components = 0;
-
- memset(&data, 0, sizeof(data));
-
- foreach_list(node, parameters) {
- ir_rvalue *param = (ir_rvalue *) node;
- unsigned rhs_components = param->type->components();
-
- /* Do not try to assign more components to the vector than it has!
- */
- if ((rhs_components + base_lhs_component) > lhs_components) {
- rhs_components = lhs_components - base_lhs_component;
- }
-
- const ir_constant *const c = param->as_constant();
- if (c != NULL) {
- for (unsigned i = 0; i < rhs_components; i++) {
- switch (c->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[i + base_component] = c->get_uint_component(i);
- break;
- case GLSL_TYPE_INT:
- data.i[i + base_component] = c->get_int_component(i);
- break;
- case GLSL_TYPE_FLOAT:
- data.f[i + base_component] = c->get_float_component(i);
- break;
- case GLSL_TYPE_BOOL:
- data.b[i + base_component] = c->get_bool_component(i);
- break;
- default:
- assert(!"Should not get here.");
- break;
- }
- }
-
- /* Mask of fields to be written in the assignment.
- */
- constant_mask |= ((1U << rhs_components) - 1) << base_lhs_component;
- constant_components += rhs_components;
-
- base_component += rhs_components;
- }
- /* Advance the component index by the number of components
- * that were just assigned.
- */
- base_lhs_component += rhs_components;
- }
-
- if (constant_mask != 0) {
- ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
- const glsl_type *rhs_type = glsl_type::get_instance(var->type->base_type,
- constant_components,
- 1);
- ir_rvalue *rhs = new(ctx) ir_constant(rhs_type, &data);
-
- ir_instruction *inst =
- new(ctx) ir_assignment(lhs, rhs, NULL, constant_mask);
- instructions->push_tail(inst);
- }
-
- base_component = 0;
- foreach_list(node, parameters) {
- ir_rvalue *param = (ir_rvalue *) node;
- unsigned rhs_components = param->type->components();
-
- /* Do not try to assign more components to the vector than it has!
- */
- if ((rhs_components + base_component) > lhs_components) {
- rhs_components = lhs_components - base_component;
- }
-
- const ir_constant *const c = param->as_constant();
- if (c == NULL) {
- /* Mask of fields to be written in the assignment.
- */
- const unsigned write_mask = ((1U << rhs_components) - 1)
- << base_component;
-
- ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
-
- /* Generate a swizzle so that LHS and RHS sizes match.
- */
- ir_rvalue *rhs =
- new(ctx) ir_swizzle(param, 0, 1, 2, 3, rhs_components);
-
- ir_instruction *inst =
- new(ctx) ir_assignment(lhs, rhs, NULL, write_mask);
- instructions->push_tail(inst);
- }
-
- /* Advance the component index by the number of components that were
- * just assigned.
- */
- base_component += rhs_components;
- }
- }
- return new(ctx) ir_dereference_variable(var);
-}
-
-
-/**
- * Generate assignment of a portion of a vector to a portion of a matrix column
- *
- * \param src_base First component of the source to be used in assignment
- * \param column Column of destination to be assiged
- * \param row_base First component of the destination column to be assigned
- * \param count Number of components to be assigned
- *
- * \note
- * \c src_base + \c count must be less than or equal to the number of components
- * in the source vector.
- */
-ir_instruction *
-assign_to_matrix_column(ir_variable *var, unsigned column, unsigned row_base,
- ir_rvalue *src, unsigned src_base, unsigned count,
- void *mem_ctx)
-{
- ir_constant *col_idx = new(mem_ctx) ir_constant(column);
- ir_dereference *column_ref = new(mem_ctx) ir_dereference_array(var, col_idx);
-
- assert(column_ref->type->components() >= (row_base + count));
- assert(src->type->components() >= (src_base + count));
-
- /* Generate a swizzle that extracts the number of components from the source
- * that are to be assigned to the column of the matrix.
- */
- if (count < src->type->vector_elements) {
- src = new(mem_ctx) ir_swizzle(src,
- src_base + 0, src_base + 1,
- src_base + 2, src_base + 3,
- count);
- }
-
- /* Mask of fields to be written in the assignment.
- */
- const unsigned write_mask = ((1U << count) - 1) << row_base;
-
- return new(mem_ctx) ir_assignment(column_ref, src, NULL, write_mask);
-}
-
-
-/**
- * Generate inline code for a matrix constructor
- *
- * The generated constructor code will consist of a temporary variable
- * declaration of the same type as the constructor. A sequence of assignments
- * from constructor parameters to the temporary will follow.
- *
- * \return
- * An \c ir_dereference_variable of the temprorary generated in the constructor
- * body.
- */
-ir_rvalue *
-emit_inline_matrix_constructor(const glsl_type *type,
- exec_list *instructions,
- exec_list *parameters,
- void *ctx)
-{
- assert(!parameters->is_empty());
-
- ir_variable *var = new(ctx) ir_variable(type, "mat_ctor", ir_var_temporary);
- instructions->push_tail(var);
-
- /* There are three kinds of matrix constructors.
- *
- * - Construct a matrix from a single scalar by replicating that scalar to
- * along the diagonal of the matrix and setting all other components to
- * zero.
- *
- * - Construct a matrix from an arbirary combination of vectors and
- * scalars. The components of the constructor parameters are assigned
- * to the matrix in colum-major order until the matrix is full.
- *
- * - Construct a matrix from a single matrix. The source matrix is copied
- * to the upper left portion of the constructed matrix, and the remaining
- * elements take values from the identity matrix.
- */
- ir_rvalue *const first_param = (ir_rvalue *) parameters->head;
- if (single_scalar_parameter(parameters)) {
- /* Assign the scalar to the X component of a vec4, and fill the remaining
- * components with zero.
- */
- ir_variable *rhs_var =
- new(ctx) ir_variable(glsl_type::vec4_type, "mat_ctor_vec",
- ir_var_temporary);
- instructions->push_tail(rhs_var);
-
- ir_constant_data zero;
- zero.f[0] = 0.0;
- zero.f[1] = 0.0;
- zero.f[2] = 0.0;
- zero.f[3] = 0.0;
-
- ir_instruction *inst =
- new(ctx) ir_assignment(new(ctx) ir_dereference_variable(rhs_var),
- new(ctx) ir_constant(rhs_var->type, &zero),
- NULL);
- instructions->push_tail(inst);
-
- ir_dereference *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
-
- inst = new(ctx) ir_assignment(rhs_ref, first_param, NULL, 0x01);
- instructions->push_tail(inst);
-
- /* Assign the temporary vector to each column of the destination matrix
- * with a swizzle that puts the X component on the diagonal of the
- * matrix. In some cases this may mean that the X component does not
- * get assigned into the column at all (i.e., when the matrix has more
- * columns than rows).
- */
- static const unsigned rhs_swiz[4][4] = {
- { 0, 1, 1, 1 },
- { 1, 0, 1, 1 },
- { 1, 1, 0, 1 },
- { 1, 1, 1, 0 }
- };
-
- const unsigned cols_to_init = MIN2(type->matrix_columns,
- type->vector_elements);
- for (unsigned i = 0; i < cols_to_init; i++) {
- ir_constant *const col_idx = new(ctx) ir_constant(i);
- ir_rvalue *const col_ref = new(ctx) ir_dereference_array(var, col_idx);
-
- ir_rvalue *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
- ir_rvalue *const rhs = new(ctx) ir_swizzle(rhs_ref, rhs_swiz[i],
- type->vector_elements);
-
- inst = new(ctx) ir_assignment(col_ref, rhs, NULL);
- instructions->push_tail(inst);
- }
-
- for (unsigned i = cols_to_init; i < type->matrix_columns; i++) {
- ir_constant *const col_idx = new(ctx) ir_constant(i);
- ir_rvalue *const col_ref = new(ctx) ir_dereference_array(var, col_idx);
-
- ir_rvalue *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
- ir_rvalue *const rhs = new(ctx) ir_swizzle(rhs_ref, 1, 1, 1, 1,
- type->vector_elements);
-
- inst = new(ctx) ir_assignment(col_ref, rhs, NULL);
- instructions->push_tail(inst);
- }
- } else if (first_param->type->is_matrix()) {
- /* From page 50 (56 of the PDF) of the GLSL 1.50 spec:
- *
- * "If a matrix is constructed from a matrix, then each component
- * (column i, row j) in the result that has a corresponding
- * component (column i, row j) in the argument will be initialized
- * from there. All other components will be initialized to the
- * identity matrix. If a matrix argument is given to a matrix
- * constructor, it is an error to have any other arguments."
- */
- assert(first_param->next->is_tail_sentinel());
- ir_rvalue *const src_matrix = first_param;
-
- /* If the source matrix is smaller, pre-initialize the relavent parts of
- * the destination matrix to the identity matrix.
- */
- if ((src_matrix->type->matrix_columns < var->type->matrix_columns)
- || (src_matrix->type->vector_elements < var->type->vector_elements)) {
-
- /* If the source matrix has fewer rows, every column of the destination
- * must be initialized. Otherwise only the columns in the destination
- * that do not exist in the source must be initialized.
- */
- unsigned col =
- (src_matrix->type->vector_elements < var->type->vector_elements)
- ? 0 : src_matrix->type->matrix_columns;
-
- const glsl_type *const col_type = var->type->column_type();
- for (/* empty */; col < var->type->matrix_columns; col++) {
- ir_constant_data ident;
-
- ident.f[0] = 0.0;
- ident.f[1] = 0.0;
- ident.f[2] = 0.0;
- ident.f[3] = 0.0;
-
- ident.f[col] = 1.0;
-
- ir_rvalue *const rhs = new(ctx) ir_constant(col_type, &ident);
-
- ir_rvalue *const lhs =
- new(ctx) ir_dereference_array(var, new(ctx) ir_constant(col));
-
- ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL);
- instructions->push_tail(inst);
- }
- }
-
- /* Assign columns from the source matrix to the destination matrix.
- *
- * Since the parameter will be used in the RHS of multiple assignments,
- * generate a temporary and copy the paramter there.
- */
- ir_variable *const rhs_var =
- new(ctx) ir_variable(first_param->type, "mat_ctor_mat",
- ir_var_temporary);
- instructions->push_tail(rhs_var);
-
- ir_dereference *const rhs_var_ref =
- new(ctx) ir_dereference_variable(rhs_var);
- ir_instruction *const inst =
- new(ctx) ir_assignment(rhs_var_ref, first_param, NULL);
- instructions->push_tail(inst);
-
- const unsigned last_row = MIN2(src_matrix->type->vector_elements,
- var->type->vector_elements);
- const unsigned last_col = MIN2(src_matrix->type->matrix_columns,
- var->type->matrix_columns);
-
- unsigned swiz[4] = { 0, 0, 0, 0 };
- for (unsigned i = 1; i < last_row; i++)
- swiz[i] = i;
-
- const unsigned write_mask = (1U << last_row) - 1;
-
- for (unsigned i = 0; i < last_col; i++) {
- ir_dereference *const lhs =
- new(ctx) ir_dereference_array(var, new(ctx) ir_constant(i));
- ir_rvalue *const rhs_col =
- new(ctx) ir_dereference_array(rhs_var, new(ctx) ir_constant(i));
-
- /* If one matrix has columns that are smaller than the columns of the
- * other matrix, wrap the column access of the larger with a swizzle
- * so that the LHS and RHS of the assignment have the same size (and
- * therefore have the same type).
- *
- * It would be perfectly valid to unconditionally generate the
- * swizzles, this this will typically result in a more compact IR tree.
- */
- ir_rvalue *rhs;
- if (lhs->type->vector_elements != rhs_col->type->vector_elements) {
- rhs = new(ctx) ir_swizzle(rhs_col, swiz, last_row);
- } else {
- rhs = rhs_col;
- }
-
- ir_instruction *inst =
- new(ctx) ir_assignment(lhs, rhs, NULL, write_mask);
- instructions->push_tail(inst);
- }
- } else {
- const unsigned cols = type->matrix_columns;
- const unsigned rows = type->vector_elements;
- unsigned col_idx = 0;
- unsigned row_idx = 0;
-
- foreach_list (node, parameters) {
- ir_rvalue *const rhs = (ir_rvalue *) node;
- const unsigned components_remaining_this_column = rows - row_idx;
- unsigned rhs_components = rhs->type->components();
- unsigned rhs_base = 0;
-
- /* Since the parameter might be used in the RHS of two assignments,
- * generate a temporary and copy the paramter there.
- */
- ir_variable *rhs_var =
- new(ctx) ir_variable(rhs->type, "mat_ctor_vec", ir_var_temporary);
- instructions->push_tail(rhs_var);
-
- ir_dereference *rhs_var_ref =
- new(ctx) ir_dereference_variable(rhs_var);
- ir_instruction *inst = new(ctx) ir_assignment(rhs_var_ref, rhs, NULL);
- instructions->push_tail(inst);
-
- /* Assign the current parameter to as many components of the matrix
- * as it will fill.
- *
- * NOTE: A single vector parameter can span two matrix columns. A
- * single vec4, for example, can completely fill a mat2.
- */
- if (rhs_components >= components_remaining_this_column) {
- const unsigned count = MIN2(rhs_components,
- components_remaining_this_column);
-
- rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var);
-
- ir_instruction *inst = assign_to_matrix_column(var, col_idx,
- row_idx,
- rhs_var_ref, 0,
- count, ctx);
- instructions->push_tail(inst);
-
- rhs_base = count;
-
- col_idx++;
- row_idx = 0;
- }
-
- /* If there is data left in the parameter and components left to be
- * set in the destination, emit another assignment. It is possible
- * that the assignment could be of a vec4 to the last element of the
- * matrix. In this case col_idx==cols, but there is still data
- * left in the source parameter. Obviously, don't emit an assignment
- * to data outside the destination matrix.
- */
- if ((col_idx < cols) && (rhs_base < rhs_components)) {
- const unsigned count = rhs_components - rhs_base;
-
- rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var);
-
- ir_instruction *inst = assign_to_matrix_column(var, col_idx,
- row_idx,
- rhs_var_ref,
- rhs_base,
- count, ctx);
- instructions->push_tail(inst);
-
- row_idx += count;
- }
- }
- }
-
- return new(ctx) ir_dereference_variable(var);
-}
-
-
-ir_rvalue *
-emit_inline_record_constructor(const glsl_type *type,
- exec_list *instructions,
- exec_list *parameters,
- void *mem_ctx)
-{
- ir_variable *const var =
- new(mem_ctx) ir_variable(type, "record_ctor", ir_var_temporary);
- ir_dereference_variable *const d = new(mem_ctx) ir_dereference_variable(var);
-
- instructions->push_tail(var);
-
- exec_node *node = parameters->head;
- for (unsigned i = 0; i < type->length; i++) {
- assert(!node->is_tail_sentinel());
-
- ir_dereference *const lhs =
- new(mem_ctx) ir_dereference_record(d->clone(mem_ctx, NULL),
- type->fields.structure[i].name);
-
- ir_rvalue *const rhs = ((ir_instruction *) node)->as_rvalue();
- assert(rhs != NULL);
-
- ir_instruction *const assign = new(mem_ctx) ir_assignment(lhs, rhs, NULL);
-
- instructions->push_tail(assign);
- node = node->next;
- }
-
- return d;
-}
-
-
-ir_rvalue *
-ast_function_expression::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
- /* There are three sorts of function calls.
- *
- * 1. constructors - 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.
- */
- if (is_constructor()) {
- const ast_type_specifier *type = (ast_type_specifier *) subexpressions[0];
- YYLTYPE loc = type->get_location();
- const char *name;
-
- const glsl_type *const constructor_type = type->glsl_type(& name, state);
-
-
- /* Constructors for samplers are illegal.
- */
- if (constructor_type->is_sampler()) {
- _mesa_glsl_error(& loc, state, "cannot construct sampler type `%s'",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- if (constructor_type->is_array()) {
- if (state->language_version <= 110) {
- _mesa_glsl_error(& loc, state,
- "array constructors forbidden in GLSL 1.10");
- return ir_call::get_error_instruction(ctx);
- }
-
- return process_array_constructor(instructions, constructor_type,
- & loc, &this->expressions, state);
- }
-
-
- /* There are two kinds of constructor call. Constructors for built-in
- * language types, such as mat4 and vec2, are free form. The only
- * requirement is that the parameters must provide enough values of the
- * correct scalar type. Constructors for arrays and structures must
- * have the exact number of parameters with matching types in the
- * correct order. These constructors follow essentially the same type
- * matching rules as functions.
- */
- if (!constructor_type->is_numeric() && !constructor_type->is_boolean())
- return ir_call::get_error_instruction(ctx);
-
- /* Total number of components of the type being constructed. */
- const unsigned type_components = constructor_type->components();
-
- /* Number of components from parameters that have actually been
- * consumed. This is used to perform several kinds of error checking.
- */
- unsigned components_used = 0;
-
- unsigned matrix_parameters = 0;
- unsigned nonmatrix_parameters = 0;
- exec_list actual_parameters;
-
- foreach_list (n, &this->expressions) {
- ast_node *ast = exec_node_data(ast_node, n, link);
- ir_rvalue *result = ast->hir(instructions, state)->as_rvalue();
-
- /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
- *
- * "It is an error to provide extra arguments beyond this
- * last used argument."
- */
- if (components_used >= type_components) {
- _mesa_glsl_error(& loc, state, "too many parameters to `%s' "
- "constructor",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- if (!result->type->is_numeric() && !result->type->is_boolean()) {
- _mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
- "non-numeric data type",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- /* Count the number of matrix and nonmatrix parameters. This
- * is used below to enforce some of the constructor rules.
- */
- if (result->type->is_matrix())
- matrix_parameters++;
- else
- nonmatrix_parameters++;
-
- actual_parameters.push_tail(result);
- components_used += result->type->components();
- }
-
- /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
- *
- * "It is an error to construct matrices from other matrices. This
- * is reserved for future use."
- */
- if (state->language_version == 110 && matrix_parameters > 0
- && constructor_type->is_matrix()) {
- _mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
- "matrix in GLSL 1.10",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
- *
- * "If a matrix argument is given to a matrix constructor, it is
- * an error to have any other arguments."
- */
- if ((matrix_parameters > 0)
- && ((matrix_parameters + nonmatrix_parameters) > 1)
- && constructor_type->is_matrix()) {
- _mesa_glsl_error(& loc, state, "for matrix `%s' constructor, "
- "matrix must be only parameter",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
- *
- * "In these cases, there must be enough components provided in the
- * arguments to provide an initializer for every component in the
- * constructed value."
- */
- if (components_used < type_components && components_used != 1
- && matrix_parameters == 0) {
- _mesa_glsl_error(& loc, state, "too few components to construct "
- "`%s'",
- constructor_type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- /* Later, we cast each parameter to the same base type as the
- * constructor. Since there are no non-floating point matrices, we
- * need to break them up into a series of column vectors.
- */
- if (constructor_type->base_type != GLSL_TYPE_FLOAT) {
- foreach_list_safe(n, &actual_parameters) {
- ir_rvalue *matrix = (ir_rvalue *) n;
-
- if (!matrix->type->is_matrix())
- continue;
-
- /* Create a temporary containing the matrix. */
- ir_variable *var = new(ctx) ir_variable(matrix->type, "matrix_tmp",
- ir_var_temporary);
- instructions->push_tail(var);
- instructions->push_tail(new(ctx) ir_assignment(new(ctx)
- ir_dereference_variable(var), matrix, NULL));
- var->constant_value = matrix->constant_expression_value();
-
- /* Replace the matrix with dereferences of its columns. */
- for (int i = 0; i < matrix->type->matrix_columns; i++) {
- matrix->insert_before(new (ctx) ir_dereference_array(var,
- new(ctx) ir_constant(i)));
- }
- matrix->remove();
- }
- }
-
- bool all_parameters_are_constant = true;
-
- /* Type cast each parameter and, if possible, fold constants.*/
- foreach_list_safe(n, &actual_parameters) {
- ir_rvalue *ir = (ir_rvalue *) n;
-
- const glsl_type *desired_type =
- glsl_type::get_instance(constructor_type->base_type,
- ir->type->vector_elements,
- ir->type->matrix_columns);
- ir_rvalue *result = convert_component(ir, desired_type);
-
- /* Attempt to convert the parameter to a constant valued expression.
- * After doing so, track whether or not all the parameters to the
- * constructor are trivially constant valued expressions.
- */
- ir_rvalue *const constant = result->constant_expression_value();
-
- if (constant != NULL)
- result = constant;
- else
- all_parameters_are_constant = false;
-
- if (result != ir) {
- ir->replace_with(result);
- }
- }
-
- /* If all of the parameters are trivially constant, create a
- * constant representing the complete collection of parameters.
- */
- if (all_parameters_are_constant) {
- return new(ctx) ir_constant(constructor_type, &actual_parameters);
- } else if (constructor_type->is_scalar()) {
- return dereference_component((ir_rvalue *) actual_parameters.head,
- 0);
- } else if (constructor_type->is_vector()) {
- return emit_inline_vector_constructor(constructor_type,
- instructions,
- &actual_parameters,
- ctx);
- } else {
- assert(constructor_type->is_matrix());
- return emit_inline_matrix_constructor(constructor_type,
- instructions,
- &actual_parameters,
- ctx);
- }
- } else {
- const ast_expression *id = subexpressions[0];
- YYLTYPE loc = id->get_location();
- exec_list actual_parameters;
-
- process_parameters(instructions, &actual_parameters, &this->expressions,
- state);
-
- const glsl_type *const type =
- state->symbols->get_type(id->primary_expression.identifier);
-
- if ((type != NULL) && type->is_record()) {
- exec_node *node = actual_parameters.head;
- for (unsigned i = 0; i < type->length; i++) {
- ir_rvalue *ir = (ir_rvalue *) node;
-
- if (node->is_tail_sentinel()) {
- _mesa_glsl_error(&loc, state,
- "insufficient parameters to constructor "
- "for `%s'",
- type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- if (apply_implicit_conversion(type->fields.structure[i].type, ir,
- state)) {
- node->replace_with(ir);
- } else {
- _mesa_glsl_error(&loc, state,
- "parameter type mismatch in constructor "
- "for `%s.%s' (%s vs %s)",
- type->name,
- type->fields.structure[i].name,
- ir->type->name,
- type->fields.structure[i].type->name);
- return ir_call::get_error_instruction(ctx);;
- }
-
- node = node->next;
- }
-
- if (!node->is_tail_sentinel()) {
- _mesa_glsl_error(&loc, state, "too many parameters in constructor "
- "for `%s'", type->name);
- return ir_call::get_error_instruction(ctx);
- }
-
- ir_rvalue *const constant =
- constant_record_constructor(type, &actual_parameters, state);
-
- return (constant != NULL)
- ? constant
- : emit_inline_record_constructor(type, instructions,
- &actual_parameters, state);
- }
-
- return match_function_by_name(instructions,
- id->primary_expression.identifier, & loc,
- &actual_parameters, state);
- }
-
- return ir_call::get_error_instruction(ctx);
-}
+/*
+ * 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 "glsl_symbol_table.h"
+#include "ast.h"
+#include "glsl_types.h"
+#include "ir.h"
+#include "main/core.h" /* for MIN2 */
+
+static ir_rvalue *
+convert_component(ir_rvalue *src, const glsl_type *desired_type);
+
+bool
+apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from,
+ struct _mesa_glsl_parse_state *state);
+
+static unsigned
+process_parameters(exec_list *instructions, exec_list *actual_parameters,
+ exec_list *parameters,
+ struct _mesa_glsl_parse_state *state)
+{
+ unsigned count = 0;
+
+ foreach_list (n, parameters) {
+ ast_node *const ast = exec_node_data(ast_node, n, link);
+ ir_rvalue *result = ast->hir(instructions, state);
+
+ ir_constant *const constant = result->constant_expression_value();
+ if (constant != NULL)
+ result = constant;
+
+ actual_parameters->push_tail(result);
+ count++;
+ }
+
+ return count;
+}
+
+
+/**
+ * Generate a source prototype for a function signature
+ *
+ * \param return_type Return type of the function. May be \c NULL.
+ * \param name Name of the function.
+ * \param parameters Parameter list for the function. This may be either a
+ * formal or actual parameter list. Only the type is used.
+ *
+ * \return
+ * A ralloced string representing the prototype of the function.
+ */
+char *
+prototype_string(const glsl_type *return_type, const char *name,
+ exec_list *parameters)
+{
+ char *str = NULL;
+
+ if (return_type != NULL)
+ ralloc_asprintf(&str, "%s ", return_type->name);
+
+ ralloc_asprintf_append(&str, "%s(", name);
+
+ const char *comma = "";
+ foreach_list(node, parameters) {
+ const ir_instruction *const param = (ir_instruction *) node;
+
+ ralloc_asprintf_append(&str, "%s%s", comma, param->type->name);
+ comma = ", ";
+ }
+
+ ralloc_strcat(&str, ")");
+ return str;
+}
+
+
+static ir_rvalue *
+match_function_by_name(exec_list *instructions, const char *name,
+ YYLTYPE *loc, exec_list *actual_parameters,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ ir_function *f = state->symbols->get_function(name);
+ ir_function_signature *sig;
+
+ sig = f ? f->matching_signature(actual_parameters) : NULL;
+
+ /* FINISHME: This doesn't handle the case where shader X contains a
+ * FINISHME: matching signature but shader X + N contains an _exact_
+ * FINISHME: matching signature.
+ */
+ if (sig == NULL && (f == NULL || state->es_shader || !f->has_user_signature()) && state->symbols->get_type(name) == NULL && (state->language_version == 110 || state->symbols->get_variable(name) == NULL)) {
+ /* The current shader doesn't contain a matching function or signature.
+ * Before giving up, look for the prototype in the built-in functions.
+ */
+ for (unsigned i = 0; i < state->num_builtins_to_link; i++) {
+ ir_function *builtin;
+ builtin = state->builtins_to_link[i]->symbols->get_function(name);
+ sig = builtin ? builtin->matching_signature(actual_parameters) : NULL;
+ if (sig != NULL) {
+ if (f == NULL) {
+ f = new(ctx) ir_function(name);
+ state->symbols->add_global_function(f);
+ emit_function(state, instructions, f);
+ }
+
+ f->add_signature(sig->clone_prototype(f, NULL));
+ break;
+ }
+ }
+ }
+
+ if (sig != NULL) {
+ /* Verify that 'out' and 'inout' actual parameters are lvalues. This
+ * isn't done in ir_function::matching_signature because that function
+ * cannot generate the necessary diagnostics.
+ *
+ * Also, validate that 'const_in' formal parameters (an extension of our
+ * IR) correspond to ir_constant actual parameters.
+ */
+ exec_list_iterator actual_iter = actual_parameters->iterator();
+ exec_list_iterator formal_iter = sig->parameters.iterator();
+
+ while (actual_iter.has_next()) {
+ ir_rvalue *actual = (ir_rvalue *) actual_iter.get();
+ ir_variable *formal = (ir_variable *) formal_iter.get();
+
+ assert(actual != NULL);
+ assert(formal != NULL);
+
+ if (formal->mode == ir_var_const_in && !actual->as_constant()) {
+ _mesa_glsl_error(loc, state,
+ "parameter `%s' must be a constant expression",
+ formal->name);
+ }
+
+ if ((formal->mode == ir_var_out)
+ || (formal->mode == ir_var_inout)) {
+ const char *mode = NULL;
+ switch (formal->mode) {
+ case ir_var_out: mode = "out"; break;
+ case ir_var_inout: mode = "inout"; break;
+ default: assert(false); break;
+ }
+ /* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always
+ * FIXME: 0:0(0).
+ */
+ if (actual->variable_referenced()
+ && actual->variable_referenced()->read_only) {
+ _mesa_glsl_error(loc, state,
+ "function parameter '%s %s' references the "
+ "read-only variable '%s'",
+ mode, formal->name,
+ actual->variable_referenced()->name);
+
+ } else if (!actual->is_lvalue()) {
+ _mesa_glsl_error(loc, state,
+ "function parameter '%s %s' is not an lvalue",
+ mode, formal->name);
+ }
+ }
+
+ if (formal->type->is_numeric() || formal->type->is_boolean()) {
+ ir_rvalue *converted = convert_component(actual, formal->type);
+ actual->replace_with(converted);
+ }
+
+ actual_iter.next();
+ formal_iter.next();
+ }
+
+ /* Always insert the call in the instruction stream, and return a deref
+ * of its return val if it returns a value, since we don't know if
+ * the rvalue is going to be assigned to anything or not.
+ */
+ ir_call *call = new(ctx) ir_call(sig, actual_parameters);
+ if (!sig->return_type->is_void()) {
+ ir_variable *var;
+ ir_dereference_variable *deref;
+
+ var = new(ctx) ir_variable(sig->return_type,
+ ralloc_asprintf(ctx, "%s_retval",
+ sig->function_name()),
+ ir_var_temporary);
+ instructions->push_tail(var);
+
+ deref = new(ctx) ir_dereference_variable(var);
+ ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL);
+ instructions->push_tail(assign);
+ if (state->language_version >= 120)
+ var->constant_value = call->constant_expression_value();
+
+ deref = new(ctx) ir_dereference_variable(var);
+ return deref;
+ } else {
+ instructions->push_tail(call);
+ return NULL;
+ }
+ } else {
+ char *str = prototype_string(NULL, name, actual_parameters);
+
+ _mesa_glsl_error(loc, state, "no matching function for call to `%s'",
+ str);
+ ralloc_free(str);
+
+ const char *prefix = "candidates are: ";
+
+ for (int i = -1; i < (int) state->num_builtins_to_link; i++) {
+ glsl_symbol_table *syms = i >= 0 ? state->builtins_to_link[i]->symbols
+ : state->symbols;
+ f = syms->get_function(name);
+ if (f == NULL)
+ continue;
+
+ foreach_list (node, &f->signatures) {
+ ir_function_signature *sig = (ir_function_signature *) node;
+
+ str = prototype_string(sig->return_type, f->name, &sig->parameters);
+ _mesa_glsl_error(loc, state, "%s%s\n", prefix, str);
+ ralloc_free(str);
+
+ prefix = " ";
+ }
+
+ }
+
+ return ir_call::get_error_instruction(ctx);
+ }
+}
+
+
+/**
+ * Perform automatic type conversion of constructor parameters
+ *
+ * This implements the rules in the "Conversion and Scalar Constructors"
+ * section (GLSL 1.10 section 5.4.1), not the "Implicit Conversions" rules.
+ */
+static ir_rvalue *
+convert_component(ir_rvalue *src, const glsl_type *desired_type)
+{
+ void *ctx = ralloc_parent(src);
+ const unsigned a = desired_type->base_type;
+ const unsigned b = src->type->base_type;
+ ir_expression *result = NULL;
+
+ if (src->type->is_error())
+ return src;
+
+ assert(a <= GLSL_TYPE_BOOL);
+ assert(b <= GLSL_TYPE_BOOL);
+
+ if ((a == b) || (src->type->is_integer() && desired_type->is_integer()))
+ return src;
+
+ switch (a) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ if (b == GLSL_TYPE_FLOAT)
+ result = new(ctx) ir_expression(ir_unop_f2i, desired_type, src, NULL);
+ else {
+ assert(b == GLSL_TYPE_BOOL);
+ result = new(ctx) ir_expression(ir_unop_b2i, desired_type, src, NULL);
+ }
+ break;
+ case GLSL_TYPE_FLOAT:
+ switch (b) {
+ case GLSL_TYPE_UINT:
+ result = new(ctx) ir_expression(ir_unop_u2f, desired_type, src, NULL);
+ break;
+ case GLSL_TYPE_INT:
+ result = new(ctx) ir_expression(ir_unop_i2f, desired_type, src, NULL);
+ break;
+ case GLSL_TYPE_BOOL:
+ result = new(ctx) ir_expression(ir_unop_b2f, desired_type, src, NULL);
+ break;
+ }
+ break;
+ case GLSL_TYPE_BOOL:
+ switch (b) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ result = new(ctx) ir_expression(ir_unop_i2b, desired_type, src, NULL);
+ break;
+ case GLSL_TYPE_FLOAT:
+ result = new(ctx) ir_expression(ir_unop_f2b, desired_type, src, NULL);
+ break;
+ }
+ break;
+ }
+
+ assert(result != NULL);
+
+ /* Try constant folding; it may fold in the conversion we just added. */
+ ir_constant *const constant = result->constant_expression_value();
+ return (constant != NULL) ? (ir_rvalue *) constant : (ir_rvalue *) result;
+}
+
+/**
+ * Dereference a specific component from a scalar, vector, or matrix
+ */
+static ir_rvalue *
+dereference_component(ir_rvalue *src, unsigned component)
+{
+ void *ctx = ralloc_parent(src);
+ assert(component < src->type->components());
+
+ /* If the source is a constant, just create a new constant instead of a
+ * dereference of the existing constant.
+ */
+ ir_constant *constant = src->as_constant();
+ if (constant)
+ return new(ctx) ir_constant(constant, component);
+
+ if (src->type->is_scalar()) {
+ return src;
+ } else if (src->type->is_vector()) {
+ return new(ctx) ir_swizzle(src, component, 0, 0, 0, 1);
+ } else {
+ assert(src->type->is_matrix());
+
+ /* Dereference a row of the matrix, then call this function again to get
+ * a specific element from that row.
+ */
+ const int c = component / src->type->column_type()->vector_elements;
+ const int r = component % src->type->column_type()->vector_elements;
+ ir_constant *const col_index = new(ctx) ir_constant(c);
+ ir_dereference *const col = new(ctx) ir_dereference_array(src, col_index);
+
+ col->type = src->type->column_type();
+
+ return dereference_component(col, r);
+ }
+
+ assert(!"Should not get here.");
+ return NULL;
+}
+
+
+static ir_rvalue *
+process_array_constructor(exec_list *instructions,
+ const glsl_type *constructor_type,
+ YYLTYPE *loc, exec_list *parameters,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ /* Array constructors come in two forms: sized and unsized. Sized array
+ * constructors look like 'vec4[2](a, b)', where 'a' and 'b' are vec4
+ * variables. In this case the number of parameters must exactly match the
+ * specified size of the array.
+ *
+ * Unsized array constructors look like 'vec4[](a, b)', where 'a' and 'b'
+ * are vec4 variables. In this case the size of the array being constructed
+ * is determined by the number of parameters.
+ *
+ * From page 52 (page 58 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "There must be exactly the same number of arguments as the size of
+ * the array being constructed. If no size is present in the
+ * constructor, then the array is explicitly sized to the number of
+ * arguments provided. The arguments are assigned in order, starting at
+ * element 0, to the elements of the constructed array. Each argument
+ * must be the same type as the element type of the array, or be a type
+ * that can be converted to the element type of the array according to
+ * Section 4.1.10 "Implicit Conversions.""
+ */
+ exec_list actual_parameters;
+ const unsigned parameter_count =
+ process_parameters(instructions, &actual_parameters, parameters, state);
+
+ if ((parameter_count == 0)
+ || ((constructor_type->length != 0)
+ && (constructor_type->length != parameter_count))) {
+ const unsigned min_param = (constructor_type->length == 0)
+ ? 1 : constructor_type->length;
+
+ _mesa_glsl_error(loc, state, "array constructor must have %s %u "
+ "parameter%s",
+ (constructor_type->length != 0) ? "at least" : "exactly",
+ min_param, (min_param <= 1) ? "" : "s");
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ if (constructor_type->length == 0) {
+ constructor_type =
+ glsl_type::get_array_instance(constructor_type->element_type(),
+ parameter_count);
+ assert(constructor_type != NULL);
+ assert(constructor_type->length == parameter_count);
+ }
+
+ bool all_parameters_are_constant = true;
+
+ /* Type cast each parameter and, if possible, fold constants. */
+ foreach_list_safe(n, &actual_parameters) {
+ ir_rvalue *ir = (ir_rvalue *) n;
+ ir_rvalue *result = ir;
+
+ /* Apply implicit conversions (not the scalar constructor rules!) */
+ if (constructor_type->element_type()->is_float()) {
+ const glsl_type *desired_type =
+ glsl_type::get_instance(GLSL_TYPE_FLOAT,
+ ir->type->vector_elements,
+ ir->type->matrix_columns);
+ result = convert_component(ir, desired_type);
+ }
+
+ if (result->type != constructor_type->element_type()) {
+ _mesa_glsl_error(loc, state, "type error in array constructor: "
+ "expected: %s, found %s",
+ constructor_type->element_type()->name,
+ result->type->name);
+ }
+
+ /* Attempt to convert the parameter to a constant valued expression.
+ * After doing so, track whether or not all the parameters to the
+ * constructor are trivially constant valued expressions.
+ */
+ ir_rvalue *const constant = result->constant_expression_value();
+
+ if (constant != NULL)
+ result = constant;
+ else
+ all_parameters_are_constant = false;
+
+ ir->replace_with(result);
+ }
+
+ if (all_parameters_are_constant)
+ return new(ctx) ir_constant(constructor_type, &actual_parameters);
+
+ ir_variable *var = new(ctx) ir_variable(constructor_type, "array_ctor",
+ ir_var_temporary);
+ instructions->push_tail(var);
+
+ int i = 0;
+ foreach_list(node, &actual_parameters) {
+ ir_rvalue *rhs = (ir_rvalue *) node;
+ ir_rvalue *lhs = new(ctx) ir_dereference_array(var,
+ new(ctx) ir_constant(i));
+
+ ir_instruction *assignment = new(ctx) ir_assignment(lhs, rhs, NULL);
+ instructions->push_tail(assignment);
+
+ i++;
+ }
+
+ return new(ctx) ir_dereference_variable(var);
+}
+
+
+/**
+ * Try to convert a record constructor to a constant expression
+ */
+static ir_constant *
+constant_record_constructor(const glsl_type *constructor_type,
+ exec_list *parameters, void *mem_ctx)
+{
+ foreach_list(node, parameters) {
+ ir_constant *constant = ((ir_instruction *) node)->as_constant();
+ if (constant == NULL)
+ return NULL;
+ node->replace_with(constant);
+ }
+
+ return new(mem_ctx) ir_constant(constructor_type, parameters);
+}
+
+
+/**
+ * Determine if a list consists of a single scalar r-value
+ */
+bool
+single_scalar_parameter(exec_list *parameters)
+{
+ const ir_rvalue *const p = (ir_rvalue *) parameters->head;
+ assert(((ir_rvalue *)p)->as_rvalue() != NULL);
+
+ return (p->type->is_scalar() && p->next->is_tail_sentinel());
+}
+
+
+/**
+ * Generate inline code for a vector constructor
+ *
+ * The generated constructor code will consist of a temporary variable
+ * declaration of the same type as the constructor. A sequence of assignments
+ * from constructor parameters to the temporary will follow.
+ *
+ * \return
+ * An \c ir_dereference_variable of the temprorary generated in the constructor
+ * body.
+ */
+ir_rvalue *
+emit_inline_vector_constructor(const glsl_type *type,
+ exec_list *instructions,
+ exec_list *parameters,
+ void *ctx)
+{
+ assert(!parameters->is_empty());
+
+ ir_variable *var = new(ctx) ir_variable(type, "vec_ctor", ir_var_temporary);
+ instructions->push_tail(var);
+
+ /* There are two kinds of vector constructors.
+ *
+ * - Construct a vector from a single scalar by replicating that scalar to
+ * all components of the vector.
+ *
+ * - Construct a vector from an arbirary combination of vectors and
+ * scalars. The components of the constructor parameters are assigned
+ * to the vector in order until the vector is full.
+ */
+ const unsigned lhs_components = type->components();
+ if (single_scalar_parameter(parameters)) {
+ ir_rvalue *first_param = (ir_rvalue *)parameters->head;
+ ir_rvalue *rhs = new(ctx) ir_swizzle(first_param, 0, 0, 0, 0,
+ lhs_components);
+ ir_dereference_variable *lhs = new(ctx) ir_dereference_variable(var);
+ const unsigned mask = (1U << lhs_components) - 1;
+
+ assert(rhs->type == lhs->type);
+
+ ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL, mask);
+ instructions->push_tail(inst);
+ } else {
+ unsigned base_component = 0;
+ unsigned base_lhs_component = 0;
+ ir_constant_data data;
+ unsigned constant_mask = 0, constant_components = 0;
+
+ memset(&data, 0, sizeof(data));
+
+ foreach_list(node, parameters) {
+ ir_rvalue *param = (ir_rvalue *) node;
+ unsigned rhs_components = param->type->components();
+
+ /* Do not try to assign more components to the vector than it has!
+ */
+ if ((rhs_components + base_lhs_component) > lhs_components) {
+ rhs_components = lhs_components - base_lhs_component;
+ }
+
+ const ir_constant *const c = param->as_constant();
+ if (c != NULL) {
+ for (unsigned i = 0; i < rhs_components; i++) {
+ switch (c->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[i + base_component] = c->get_uint_component(i);
+ break;
+ case GLSL_TYPE_INT:
+ data.i[i + base_component] = c->get_int_component(i);
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[i + base_component] = c->get_float_component(i);
+ break;
+ case GLSL_TYPE_BOOL:
+ data.b[i + base_component] = c->get_bool_component(i);
+ break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ }
+
+ /* Mask of fields to be written in the assignment.
+ */
+ constant_mask |= ((1U << rhs_components) - 1) << base_lhs_component;
+ constant_components += rhs_components;
+
+ base_component += rhs_components;
+ }
+ /* Advance the component index by the number of components
+ * that were just assigned.
+ */
+ base_lhs_component += rhs_components;
+ }
+
+ if (constant_mask != 0) {
+ ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
+ const glsl_type *rhs_type = glsl_type::get_instance(var->type->base_type,
+ constant_components,
+ 1);
+ ir_rvalue *rhs = new(ctx) ir_constant(rhs_type, &data);
+
+ ir_instruction *inst =
+ new(ctx) ir_assignment(lhs, rhs, NULL, constant_mask);
+ instructions->push_tail(inst);
+ }
+
+ base_component = 0;
+ foreach_list(node, parameters) {
+ ir_rvalue *param = (ir_rvalue *) node;
+ unsigned rhs_components = param->type->components();
+
+ /* Do not try to assign more components to the vector than it has!
+ */
+ if ((rhs_components + base_component) > lhs_components) {
+ rhs_components = lhs_components - base_component;
+ }
+
+ const ir_constant *const c = param->as_constant();
+ if (c == NULL) {
+ /* Mask of fields to be written in the assignment.
+ */
+ const unsigned write_mask = ((1U << rhs_components) - 1)
+ << base_component;
+
+ ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
+
+ /* Generate a swizzle so that LHS and RHS sizes match.
+ */
+ ir_rvalue *rhs =
+ new(ctx) ir_swizzle(param, 0, 1, 2, 3, rhs_components);
+
+ ir_instruction *inst =
+ new(ctx) ir_assignment(lhs, rhs, NULL, write_mask);
+ instructions->push_tail(inst);
+ }
+
+ /* Advance the component index by the number of components that were
+ * just assigned.
+ */
+ base_component += rhs_components;
+ }
+ }
+ return new(ctx) ir_dereference_variable(var);
+}
+
+
+/**
+ * Generate assignment of a portion of a vector to a portion of a matrix column
+ *
+ * \param src_base First component of the source to be used in assignment
+ * \param column Column of destination to be assiged
+ * \param row_base First component of the destination column to be assigned
+ * \param count Number of components to be assigned
+ *
+ * \note
+ * \c src_base + \c count must be less than or equal to the number of components
+ * in the source vector.
+ */
+ir_instruction *
+assign_to_matrix_column(ir_variable *var, unsigned column, unsigned row_base,
+ ir_rvalue *src, unsigned src_base, unsigned count,
+ void *mem_ctx)
+{
+ ir_constant *col_idx = new(mem_ctx) ir_constant(column);
+ ir_dereference *column_ref = new(mem_ctx) ir_dereference_array(var, col_idx);
+
+ assert(column_ref->type->components() >= (row_base + count));
+ assert(src->type->components() >= (src_base + count));
+
+ /* Generate a swizzle that extracts the number of components from the source
+ * that are to be assigned to the column of the matrix.
+ */
+ if (count < src->type->vector_elements) {
+ src = new(mem_ctx) ir_swizzle(src,
+ src_base + 0, src_base + 1,
+ src_base + 2, src_base + 3,
+ count);
+ }
+
+ /* Mask of fields to be written in the assignment.
+ */
+ const unsigned write_mask = ((1U << count) - 1) << row_base;
+
+ return new(mem_ctx) ir_assignment(column_ref, src, NULL, write_mask);
+}
+
+
+/**
+ * Generate inline code for a matrix constructor
+ *
+ * The generated constructor code will consist of a temporary variable
+ * declaration of the same type as the constructor. A sequence of assignments
+ * from constructor parameters to the temporary will follow.
+ *
+ * \return
+ * An \c ir_dereference_variable of the temprorary generated in the constructor
+ * body.
+ */
+ir_rvalue *
+emit_inline_matrix_constructor(const glsl_type *type,
+ exec_list *instructions,
+ exec_list *parameters,
+ void *ctx)
+{
+ assert(!parameters->is_empty());
+
+ ir_variable *var = new(ctx) ir_variable(type, "mat_ctor", ir_var_temporary);
+ instructions->push_tail(var);
+
+ /* There are three kinds of matrix constructors.
+ *
+ * - Construct a matrix from a single scalar by replicating that scalar to
+ * along the diagonal of the matrix and setting all other components to
+ * zero.
+ *
+ * - Construct a matrix from an arbirary combination of vectors and
+ * scalars. The components of the constructor parameters are assigned
+ * to the matrix in colum-major order until the matrix is full.
+ *
+ * - Construct a matrix from a single matrix. The source matrix is copied
+ * to the upper left portion of the constructed matrix, and the remaining
+ * elements take values from the identity matrix.
+ */
+ ir_rvalue *const first_param = (ir_rvalue *) parameters->head;
+ if (single_scalar_parameter(parameters)) {
+ /* Assign the scalar to the X component of a vec4, and fill the remaining
+ * components with zero.
+ */
+ ir_variable *rhs_var =
+ new(ctx) ir_variable(glsl_type::vec4_type, "mat_ctor_vec",
+ ir_var_temporary);
+ instructions->push_tail(rhs_var);
+
+ ir_constant_data zero;
+ zero.f[0] = 0.0;
+ zero.f[1] = 0.0;
+ zero.f[2] = 0.0;
+ zero.f[3] = 0.0;
+
+ ir_instruction *inst =
+ new(ctx) ir_assignment(new(ctx) ir_dereference_variable(rhs_var),
+ new(ctx) ir_constant(rhs_var->type, &zero),
+ NULL);
+ instructions->push_tail(inst);
+
+ ir_dereference *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
+
+ inst = new(ctx) ir_assignment(rhs_ref, first_param, NULL, 0x01);
+ instructions->push_tail(inst);
+
+ /* Assign the temporary vector to each column of the destination matrix
+ * with a swizzle that puts the X component on the diagonal of the
+ * matrix. In some cases this may mean that the X component does not
+ * get assigned into the column at all (i.e., when the matrix has more
+ * columns than rows).
+ */
+ static const unsigned rhs_swiz[4][4] = {
+ { 0, 1, 1, 1 },
+ { 1, 0, 1, 1 },
+ { 1, 1, 0, 1 },
+ { 1, 1, 1, 0 }
+ };
+
+ const unsigned cols_to_init = MIN2(type->matrix_columns,
+ type->vector_elements);
+ for (unsigned i = 0; i < cols_to_init; i++) {
+ ir_constant *const col_idx = new(ctx) ir_constant(i);
+ ir_rvalue *const col_ref = new(ctx) ir_dereference_array(var, col_idx);
+
+ ir_rvalue *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
+ ir_rvalue *const rhs = new(ctx) ir_swizzle(rhs_ref, rhs_swiz[i],
+ type->vector_elements);
+
+ inst = new(ctx) ir_assignment(col_ref, rhs, NULL);
+ instructions->push_tail(inst);
+ }
+
+ for (unsigned i = cols_to_init; i < type->matrix_columns; i++) {
+ ir_constant *const col_idx = new(ctx) ir_constant(i);
+ ir_rvalue *const col_ref = new(ctx) ir_dereference_array(var, col_idx);
+
+ ir_rvalue *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
+ ir_rvalue *const rhs = new(ctx) ir_swizzle(rhs_ref, 1, 1, 1, 1,
+ type->vector_elements);
+
+ inst = new(ctx) ir_assignment(col_ref, rhs, NULL);
+ instructions->push_tail(inst);
+ }
+ } else if (first_param->type->is_matrix()) {
+ /* From page 50 (56 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "If a matrix is constructed from a matrix, then each component
+ * (column i, row j) in the result that has a corresponding
+ * component (column i, row j) in the argument will be initialized
+ * from there. All other components will be initialized to the
+ * identity matrix. If a matrix argument is given to a matrix
+ * constructor, it is an error to have any other arguments."
+ */
+ assert(first_param->next->is_tail_sentinel());
+ ir_rvalue *const src_matrix = first_param;
+
+ /* If the source matrix is smaller, pre-initialize the relavent parts of
+ * the destination matrix to the identity matrix.
+ */
+ if ((src_matrix->type->matrix_columns < var->type->matrix_columns)
+ || (src_matrix->type->vector_elements < var->type->vector_elements)) {
+
+ /* If the source matrix has fewer rows, every column of the destination
+ * must be initialized. Otherwise only the columns in the destination
+ * that do not exist in the source must be initialized.
+ */
+ unsigned col =
+ (src_matrix->type->vector_elements < var->type->vector_elements)
+ ? 0 : src_matrix->type->matrix_columns;
+
+ const glsl_type *const col_type = var->type->column_type();
+ for (/* empty */; col < var->type->matrix_columns; col++) {
+ ir_constant_data ident;
+
+ ident.f[0] = 0.0;
+ ident.f[1] = 0.0;
+ ident.f[2] = 0.0;
+ ident.f[3] = 0.0;
+
+ ident.f[col] = 1.0;
+
+ ir_rvalue *const rhs = new(ctx) ir_constant(col_type, &ident);
+
+ ir_rvalue *const lhs =
+ new(ctx) ir_dereference_array(var, new(ctx) ir_constant(col));
+
+ ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL);
+ instructions->push_tail(inst);
+ }
+ }
+
+ /* Assign columns from the source matrix to the destination matrix.
+ *
+ * Since the parameter will be used in the RHS of multiple assignments,
+ * generate a temporary and copy the paramter there.
+ */
+ ir_variable *const rhs_var =
+ new(ctx) ir_variable(first_param->type, "mat_ctor_mat",
+ ir_var_temporary);
+ instructions->push_tail(rhs_var);
+
+ ir_dereference *const rhs_var_ref =
+ new(ctx) ir_dereference_variable(rhs_var);
+ ir_instruction *const inst =
+ new(ctx) ir_assignment(rhs_var_ref, first_param, NULL);
+ instructions->push_tail(inst);
+
+ const unsigned last_row = MIN2(src_matrix->type->vector_elements,
+ var->type->vector_elements);
+ const unsigned last_col = MIN2(src_matrix->type->matrix_columns,
+ var->type->matrix_columns);
+
+ unsigned swiz[4] = { 0, 0, 0, 0 };
+ for (unsigned i = 1; i < last_row; i++)
+ swiz[i] = i;
+
+ const unsigned write_mask = (1U << last_row) - 1;
+
+ for (unsigned i = 0; i < last_col; i++) {
+ ir_dereference *const lhs =
+ new(ctx) ir_dereference_array(var, new(ctx) ir_constant(i));
+ ir_rvalue *const rhs_col =
+ new(ctx) ir_dereference_array(rhs_var, new(ctx) ir_constant(i));
+
+ /* If one matrix has columns that are smaller than the columns of the
+ * other matrix, wrap the column access of the larger with a swizzle
+ * so that the LHS and RHS of the assignment have the same size (and
+ * therefore have the same type).
+ *
+ * It would be perfectly valid to unconditionally generate the
+ * swizzles, this this will typically result in a more compact IR tree.
+ */
+ ir_rvalue *rhs;
+ if (lhs->type->vector_elements != rhs_col->type->vector_elements) {
+ rhs = new(ctx) ir_swizzle(rhs_col, swiz, last_row);
+ } else {
+ rhs = rhs_col;
+ }
+
+ ir_instruction *inst =
+ new(ctx) ir_assignment(lhs, rhs, NULL, write_mask);
+ instructions->push_tail(inst);
+ }
+ } else {
+ const unsigned cols = type->matrix_columns;
+ const unsigned rows = type->vector_elements;
+ unsigned col_idx = 0;
+ unsigned row_idx = 0;
+
+ foreach_list (node, parameters) {
+ ir_rvalue *const rhs = (ir_rvalue *) node;
+ const unsigned components_remaining_this_column = rows - row_idx;
+ unsigned rhs_components = rhs->type->components();
+ unsigned rhs_base = 0;
+
+ /* Since the parameter might be used in the RHS of two assignments,
+ * generate a temporary and copy the paramter there.
+ */
+ ir_variable *rhs_var =
+ new(ctx) ir_variable(rhs->type, "mat_ctor_vec", ir_var_temporary);
+ instructions->push_tail(rhs_var);
+
+ ir_dereference *rhs_var_ref =
+ new(ctx) ir_dereference_variable(rhs_var);
+ ir_instruction *inst = new(ctx) ir_assignment(rhs_var_ref, rhs, NULL);
+ instructions->push_tail(inst);
+
+ /* Assign the current parameter to as many components of the matrix
+ * as it will fill.
+ *
+ * NOTE: A single vector parameter can span two matrix columns. A
+ * single vec4, for example, can completely fill a mat2.
+ */
+ if (rhs_components >= components_remaining_this_column) {
+ const unsigned count = MIN2(rhs_components,
+ components_remaining_this_column);
+
+ rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var);
+
+ ir_instruction *inst = assign_to_matrix_column(var, col_idx,
+ row_idx,
+ rhs_var_ref, 0,
+ count, ctx);
+ instructions->push_tail(inst);
+
+ rhs_base = count;
+
+ col_idx++;
+ row_idx = 0;
+ }
+
+ /* If there is data left in the parameter and components left to be
+ * set in the destination, emit another assignment. It is possible
+ * that the assignment could be of a vec4 to the last element of the
+ * matrix. In this case col_idx==cols, but there is still data
+ * left in the source parameter. Obviously, don't emit an assignment
+ * to data outside the destination matrix.
+ */
+ if ((col_idx < cols) && (rhs_base < rhs_components)) {
+ const unsigned count = rhs_components - rhs_base;
+
+ rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var);
+
+ ir_instruction *inst = assign_to_matrix_column(var, col_idx,
+ row_idx,
+ rhs_var_ref,
+ rhs_base,
+ count, ctx);
+ instructions->push_tail(inst);
+
+ row_idx += count;
+ }
+ }
+ }
+
+ return new(ctx) ir_dereference_variable(var);
+}
+
+
+ir_rvalue *
+emit_inline_record_constructor(const glsl_type *type,
+ exec_list *instructions,
+ exec_list *parameters,
+ void *mem_ctx)
+{
+ ir_variable *const var =
+ new(mem_ctx) ir_variable(type, "record_ctor", ir_var_temporary);
+ ir_dereference_variable *const d = new(mem_ctx) ir_dereference_variable(var);
+
+ instructions->push_tail(var);
+
+ exec_node *node = parameters->head;
+ for (unsigned i = 0; i < type->length; i++) {
+ assert(!node->is_tail_sentinel());
+
+ ir_dereference *const lhs =
+ new(mem_ctx) ir_dereference_record(d->clone(mem_ctx, NULL),
+ type->fields.structure[i].name);
+
+ ir_rvalue *const rhs = ((ir_instruction *) node)->as_rvalue();
+ assert(rhs != NULL);
+
+ ir_instruction *const assign = new(mem_ctx) ir_assignment(lhs, rhs, NULL);
+
+ instructions->push_tail(assign);
+ node = node->next;
+ }
+
+ return d;
+}
+
+
+ir_rvalue *
+ast_function_expression::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ /* There are three sorts of function calls.
+ *
+ * 1. constructors - 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.
+ */
+ if (is_constructor()) {
+ const ast_type_specifier *type = (ast_type_specifier *) subexpressions[0];
+ YYLTYPE loc = type->get_location();
+ const char *name;
+
+ const glsl_type *const constructor_type = type->glsl_type(& name, state);
+
+
+ /* Constructors for samplers are illegal.
+ */
+ if (constructor_type->is_sampler()) {
+ _mesa_glsl_error(& loc, state, "cannot construct sampler type `%s'",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ if (constructor_type->is_array()) {
+ if (state->language_version <= 110) {
+ _mesa_glsl_error(& loc, state,
+ "array constructors forbidden in GLSL 1.10");
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ return process_array_constructor(instructions, constructor_type,
+ & loc, &this->expressions, state);
+ }
+
+
+ /* There are two kinds of constructor call. Constructors for built-in
+ * language types, such as mat4 and vec2, are free form. The only
+ * requirement is that the parameters must provide enough values of the
+ * correct scalar type. Constructors for arrays and structures must
+ * have the exact number of parameters with matching types in the
+ * correct order. These constructors follow essentially the same type
+ * matching rules as functions.
+ */
+ if (!constructor_type->is_numeric() && !constructor_type->is_boolean())
+ return ir_call::get_error_instruction(ctx);
+
+ /* Total number of components of the type being constructed. */
+ const unsigned type_components = constructor_type->components();
+
+ /* Number of components from parameters that have actually been
+ * consumed. This is used to perform several kinds of error checking.
+ */
+ unsigned components_used = 0;
+
+ unsigned matrix_parameters = 0;
+ unsigned nonmatrix_parameters = 0;
+ exec_list actual_parameters;
+
+ foreach_list (n, &this->expressions) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ir_rvalue *result = ast->hir(instructions, state)->as_rvalue();
+
+ /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "It is an error to provide extra arguments beyond this
+ * last used argument."
+ */
+ if (components_used >= type_components) {
+ _mesa_glsl_error(& loc, state, "too many parameters to `%s' "
+ "constructor",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ if (!result->type->is_numeric() && !result->type->is_boolean()) {
+ _mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
+ "non-numeric data type",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ /* Count the number of matrix and nonmatrix parameters. This
+ * is used below to enforce some of the constructor rules.
+ */
+ if (result->type->is_matrix())
+ matrix_parameters++;
+ else
+ nonmatrix_parameters++;
+
+ actual_parameters.push_tail(result);
+ components_used += result->type->components();
+ }
+
+ /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "It is an error to construct matrices from other matrices. This
+ * is reserved for future use."
+ */
+ if (state->language_version == 110 && matrix_parameters > 0
+ && constructor_type->is_matrix()) {
+ _mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
+ "matrix in GLSL 1.10",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "If a matrix argument is given to a matrix constructor, it is
+ * an error to have any other arguments."
+ */
+ if ((matrix_parameters > 0)
+ && ((matrix_parameters + nonmatrix_parameters) > 1)
+ && constructor_type->is_matrix()) {
+ _mesa_glsl_error(& loc, state, "for matrix `%s' constructor, "
+ "matrix must be only parameter",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "In these cases, there must be enough components provided in the
+ * arguments to provide an initializer for every component in the
+ * constructed value."
+ */
+ if (components_used < type_components && components_used != 1
+ && matrix_parameters == 0) {
+ _mesa_glsl_error(& loc, state, "too few components to construct "
+ "`%s'",
+ constructor_type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ /* Later, we cast each parameter to the same base type as the
+ * constructor. Since there are no non-floating point matrices, we
+ * need to break them up into a series of column vectors.
+ */
+ if (constructor_type->base_type != GLSL_TYPE_FLOAT) {
+ foreach_list_safe(n, &actual_parameters) {
+ ir_rvalue *matrix = (ir_rvalue *) n;
+
+ if (!matrix->type->is_matrix())
+ continue;
+
+ /* Create a temporary containing the matrix. */
+ ir_variable *var = new(ctx) ir_variable(matrix->type, "matrix_tmp",
+ ir_var_temporary);
+ instructions->push_tail(var);
+ instructions->push_tail(new(ctx) ir_assignment(new(ctx)
+ ir_dereference_variable(var), matrix, NULL));
+ var->constant_value = matrix->constant_expression_value();
+
+ /* Replace the matrix with dereferences of its columns. */
+ for (int i = 0; i < matrix->type->matrix_columns; i++) {
+ matrix->insert_before(new (ctx) ir_dereference_array(var,
+ new(ctx) ir_constant(i)));
+ }
+ matrix->remove();
+ }
+ }
+
+ bool all_parameters_are_constant = true;
+
+ /* Type cast each parameter and, if possible, fold constants.*/
+ foreach_list_safe(n, &actual_parameters) {
+ ir_rvalue *ir = (ir_rvalue *) n;
+
+ const glsl_type *desired_type =
+ glsl_type::get_instance(constructor_type->base_type,
+ ir->type->vector_elements,
+ ir->type->matrix_columns);
+ ir_rvalue *result = convert_component(ir, desired_type);
+
+ /* Attempt to convert the parameter to a constant valued expression.
+ * After doing so, track whether or not all the parameters to the
+ * constructor are trivially constant valued expressions.
+ */
+ ir_rvalue *const constant = result->constant_expression_value();
+
+ if (constant != NULL)
+ result = constant;
+ else
+ all_parameters_are_constant = false;
+
+ if (result != ir) {
+ ir->replace_with(result);
+ }
+ }
+
+ /* If all of the parameters are trivially constant, create a
+ * constant representing the complete collection of parameters.
+ */
+ if (all_parameters_are_constant) {
+ return new(ctx) ir_constant(constructor_type, &actual_parameters);
+ } else if (constructor_type->is_scalar()) {
+ return dereference_component((ir_rvalue *) actual_parameters.head,
+ 0);
+ } else if (constructor_type->is_vector()) {
+ return emit_inline_vector_constructor(constructor_type,
+ instructions,
+ &actual_parameters,
+ ctx);
+ } else {
+ assert(constructor_type->is_matrix());
+ return emit_inline_matrix_constructor(constructor_type,
+ instructions,
+ &actual_parameters,
+ ctx);
+ }
+ } else {
+ const ast_expression *id = subexpressions[0];
+ YYLTYPE loc = id->get_location();
+ exec_list actual_parameters;
+
+ process_parameters(instructions, &actual_parameters, &this->expressions,
+ state);
+
+ const glsl_type *const type =
+ state->symbols->get_type(id->primary_expression.identifier);
+
+ if ((type != NULL) && type->is_record()) {
+ exec_node *node = actual_parameters.head;
+ for (unsigned i = 0; i < type->length; i++) {
+ ir_rvalue *ir = (ir_rvalue *) node;
+
+ if (node->is_tail_sentinel()) {
+ _mesa_glsl_error(&loc, state,
+ "insufficient parameters to constructor "
+ "for `%s'",
+ type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ if (apply_implicit_conversion(type->fields.structure[i].type, ir,
+ state)) {
+ node->replace_with(ir);
+ } else {
+ _mesa_glsl_error(&loc, state,
+ "parameter type mismatch in constructor "
+ "for `%s.%s' (%s vs %s)",
+ type->name,
+ type->fields.structure[i].name,
+ ir->type->name,
+ type->fields.structure[i].type->name);
+ return ir_call::get_error_instruction(ctx);;
+ }
+
+ node = node->next;
+ }
+
+ if (!node->is_tail_sentinel()) {
+ _mesa_glsl_error(&loc, state, "too many parameters in constructor "
+ "for `%s'", type->name);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ ir_rvalue *const constant =
+ constant_record_constructor(type, &actual_parameters, state);
+
+ return (constant != NULL)
+ ? constant
+ : emit_inline_record_constructor(type, instructions,
+ &actual_parameters, state);
+ }
+
+ return match_function_by_name(instructions,
+ id->primary_expression.identifier, & loc,
+ &actual_parameters, state);
+ }
+
+ return ir_call::get_error_instruction(ctx);
+}
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index df11a30c1..75f28cd2c 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -719,7 +719,7 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
static ir_rvalue *
get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue)
{
- void *ctx = talloc_parent(lvalue);
+ void *ctx = ralloc_parent(lvalue);
ir_variable *var;
var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp",
@@ -3392,7 +3392,7 @@ ast_struct_specifier::hir(exec_list *instructions,
* the types to HIR. This ensures that structure definitions embedded in
* other structure definitions are processed.
*/
- glsl_struct_field *const fields = talloc_array(state, glsl_struct_field,
+ glsl_struct_field *const fields = ralloc_array(state, glsl_struct_field,
decl_count);
unsigned i = 0;
diff --git a/mesalib/src/glsl/glcpp/glcpp-lex.c b/mesalib/src/glsl/glcpp/glcpp-lex.c
index 546225bbc..b53bea627 100644
--- a/mesalib/src/glsl/glcpp/glcpp-lex.c
+++ b/mesalib/src/glsl/glcpp/glcpp-lex.c
@@ -1,2677 +1,2681 @@
-#line 2 "glcpp/glcpp-lex.c"
-
-#line 4 "glcpp/glcpp-lex.c"
-
-#define YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX (4294967295U)
-#endif
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index. If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* An opaque pointer. */
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-typedef void* yyscan_t;
-#endif
-
-/* For convenience, these vars (plus the bison vars far below)
- are macros in the reentrant scanner. */
-#define yyin yyg->yyin_r
-#define yyout yyg->yyout_r
-#define yyextra yyg->yyextra_r
-#define yyleng yyg->yyleng_r
-#define yytext yyg->yytext_r
-#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
-#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
-#define yy_flex_debug yyg->yy_flex_debug_r
-
-/* Enter a start condition. This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN yyg->yy_start = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state. The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START ((yyg->yy_start - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE glcpp_restart(yyin ,yyscanner )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#define YY_BUF_SIZE 16384
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
- #define YY_LESS_LINENO(n)
-
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- *yy_cp = yyg->yy_hold_char; \
- YY_RESTORE_YY_MORE_OFFSET \
- yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up yytext again */ \
- } \
- while ( 0 )
-
-#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
- {
- FILE *yy_input_file;
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- yy_size_t yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
- * delete it.
- */
- int yy_is_our_buffer;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether we're considered to be at the beginning of a line.
- * If so, '^' rules will be active on the next match, otherwise
- * not.
- */
- int yy_at_bol;
-
- int yy_bs_lineno; /**< The line count. */
- int yy_bs_column; /**< The column count. */
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
- /* When an EOF's been seen but there's still some text to process
- * then we mark the buffer as YY_EOF_PENDING, to indicate that we
- * shouldn't try reading from the input source any more. We might
- * still have a bunch of tokens to match, though, because of
- * possible backing-up.
- *
- * When we actually see the EOF, we change the status to "new"
- * (via glcpp_restart()), so that the user can continue scanning by
- * just pointing yyin at a new input file.
- */
-#define YY_BUFFER_EOF_PENDING 2
-
- };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
- ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
- : NULL)
-
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
-
-void glcpp_restart (FILE *input_file ,yyscan_t yyscanner );
-void glcpp__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-YY_BUFFER_STATE glcpp__create_buffer (FILE *file,int size ,yyscan_t yyscanner );
-void glcpp__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void glcpp__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void glcpp_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-void glcpp_pop_buffer_state (yyscan_t yyscanner );
-
-static void glcpp_ensure_buffer_stack (yyscan_t yyscanner );
-static void glcpp__load_buffer_state (yyscan_t yyscanner );
-static void glcpp__init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
-
-#define YY_FLUSH_BUFFER glcpp__flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
-
-YY_BUFFER_STATE glcpp__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
-YY_BUFFER_STATE glcpp__scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE glcpp__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
-
-void *glcpp_alloc (yy_size_t ,yyscan_t yyscanner );
-void *glcpp_realloc (void *,yy_size_t ,yyscan_t yyscanner );
-void glcpp_free (void * ,yyscan_t yyscanner );
-
-#define yy_new_buffer glcpp__create_buffer
-
-#define yy_set_interactive(is_interactive) \
- { \
- if ( ! YY_CURRENT_BUFFER ){ \
- glcpp_ensure_buffer_stack (yyscanner); \
- YY_CURRENT_BUFFER_LVALUE = \
- glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
- }
-
-#define yy_set_bol(at_bol) \
- { \
- if ( ! YY_CURRENT_BUFFER ){\
- glcpp_ensure_buffer_stack (yyscanner); \
- YY_CURRENT_BUFFER_LVALUE = \
- glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
- }
-
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-/* Begin user sect3 */
-
-#define glcpp_wrap(n) 1
-#define YY_SKIP_YYWRAP
-
-typedef unsigned char YY_CHAR;
-
-typedef int yy_state_type;
-
-#define yytext_ptr yytext_r
-
-static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
-static int yy_get_next_buffer (yyscan_t yyscanner );
-static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
- yyg->yytext_ptr = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
- yyg->yy_hold_char = *yy_cp; \
- *yy_cp = '\0'; \
- yyg->yy_c_buf_p = yy_cp;
-
-#define YY_NUM_RULES 43
-#define YY_END_OF_BUFFER 44
-/* This struct is not used in this scanner,
- but its presence is necessary. */
-struct yy_trans_info
- {
- flex_int32_t yy_verify;
- flex_int32_t yy_nxt;
- };
-static yyconst flex_int16_t yy_acclist[137] =
- { 0,
- 3, 3, 44, 39, 43, 40, 43, 41, 43, 43,
- 38, 43, 43, 38, 43, 38, 43, 38, 43, 25,
- 39, 43, 24, 39, 43, 38, 43, 38, 43, 38,
- 43, 37, 39, 43, 37, 39, 43, 38, 43, 40,
- 43, 23, 43, 43, 3, 43, 4, 43, 5, 43,
- 42, 43, 39, 18, 40, 32, 35, 33, 2, 1,
- 25, 39, 25, 39, 39, 24, 39, 24, 39, 27,
- 29, 31, 30, 28, 37, 39, 37, 39, 34, 40,
- 23, 23, 3, 4, 5, 6, 5, 7, 1, 26,
- 39, 37, 39,16398, 26, 39, 37, 39, 18, 37,
-
- 39,16399,16400, 8206, 18, 8206, 37, 39, 8207, 18,
- 8208, 18,16401, 19,16396, 22, 36, 37, 39, 21,
- 8209, 18, 19, 8204, 18,16397,16404, 8205, 18, 11,
- 18, 9, 8, 8212, 10, 18
- } ;
-
-static yyconst flex_int16_t yy_accept[164] =
- { 0,
- 1, 1, 1, 1, 1, 2, 3, 3, 3, 4,
- 6, 8, 10, 11, 13, 14, 16, 18, 20, 23,
- 26, 28, 30, 32, 35, 38, 40, 42, 44, 45,
- 47, 49, 51, 53, 54, 54, 55, 56, 57, 58,
- 59, 60, 61, 63, 65, 66, 68, 70, 71, 72,
- 73, 74, 75, 77, 79, 80, 81, 82, 83, 83,
- 83, 83, 83, 83, 83, 83, 84, 85, 86, 87,
- 88, 89, 90, 92, 94, 94, 94, 94, 94, 94,
- 95, 95, 95, 95, 95, 97, 99, 99, 99, 99,
- 99, 99, 99, 99, 100, 100, 100, 100, 100, 100,
-
- 100, 102, 102, 103, 104, 104, 104, 104, 104, 106,
- 106, 107, 107, 107, 107, 107, 107, 107, 109, 109,
- 109, 111, 111, 113, 114, 115, 115, 116, 116, 116,
- 116, 117, 117, 120, 121, 121, 123, 124, 124, 124,
- 126, 127, 127, 127, 127, 128, 128, 128, 130, 130,
- 132, 132, 133, 134, 134, 134, 134, 135, 135, 135,
- 137, 137, 137
- } ;
-
-static yyconst flex_int32_t yy_ec[256] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 4, 4, 4, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 2, 5, 1, 6, 1, 7, 8, 1, 9,
- 7, 10, 7, 7, 7, 7, 11, 12, 13, 13,
- 13, 13, 13, 13, 13, 14, 14, 1, 7, 15,
- 16, 17, 1, 1, 18, 18, 18, 18, 18, 18,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 20, 19, 19, 21, 19, 19,
- 7, 1, 7, 7, 19, 1, 22, 18, 18, 23,
-
- 24, 25, 26, 19, 27, 19, 19, 28, 29, 30,
- 31, 32, 19, 33, 34, 35, 36, 37, 19, 38,
- 19, 19, 7, 39, 7, 7, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1
- } ;
-
-static yyconst flex_int32_t yy_meta[40] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1
- } ;
-
-static yyconst flex_int16_t yy_base[182] =
- { 0,
- 0, 38, 0, 0, 38, 39, 499, 498, 500, 48,
- 43, 552, 496, 44, 63, 495, 59, 65, 87, 125,
- 58, 67, 68, 164, 203, 40, 75, 241, 552, 494,
- 552, 140, 552, 140, 493, 552, 144, 492, 491, 487,
- 486, 485, 156, 179, 267, 0, 209, 472, 471, 470,
- 469, 468, 446, 124, 466, 153, 462, 458, 154, 198,
- 159, 155, 183, 160, 193, 460, 552, 222, 552, 227,
- 552, 459, 204, 161, 231, 232, 238, 243, 236, 303,
- 245, 180, 247, 249, 281, 56, 257, 271, 248, 259,
- 252, 264, 455, 454, 297, 299, 312, 313, 320, 294,
-
- 407, 295, 427, 426, 321, 296, 324, 425, 552, 424,
- 552, 327, 329, 195, 328, 331, 332, 230, 334, 378,
- 552, 377, 552, 371, 370, 335, 365, 337, 358, 342,
- 360, 344, 326, 255, 340, 552, 260, 338, 246, 552,
- 197, 364, 192, 352, 382, 348, 186, 552, 420, 552,
- 423, 184, 141, 437, 421, 447, 79, 476, 346, 552,
- 453, 552, 515, 517, 519, 521, 523, 525, 71, 527,
- 529, 531, 533, 535, 537, 539, 541, 543, 545, 547,
- 549
- } ;
-
-static yyconst flex_int16_t yy_def[182] =
- { 0,
- 162, 1, 163, 163, 164, 164, 165, 165, 162, 166,
- 167, 162, 167, 167, 167, 167, 167, 167, 162, 166,
- 167, 167, 167, 168, 168, 167, 167, 167, 162, 169,
- 162, 170, 162, 20, 167, 162, 167, 167, 167, 167,
- 167, 171, 19, 20, 20, 20, 20, 167, 167, 167,
- 167, 167, 25, 25, 167, 167, 28, 28, 167, 167,
- 167, 167, 167, 167, 167, 169, 162, 170, 162, 170,
- 162, 171, 45, 25, 167, 167, 167, 167, 167, 167,
- 167, 167, 167, 167, 20, 25, 167, 167, 167, 167,
- 167, 167, 172, 173, 167, 167, 167, 167, 167, 167,
-
- 25, 167, 174, 175, 167, 167, 167, 172, 162, 173,
- 162, 167, 167, 167, 167, 167, 167, 25, 167, 174,
- 162, 175, 162, 176, 177, 167, 178, 167, 167, 167,
- 167, 167, 25, 167, 176, 162, 177, 167, 178, 162,
- 179, 167, 180, 167, 162, 167, 179, 162, 167, 162,
- 167, 180, 167, 181, 167, 167, 167, 181, 167, 162,
- 167, 0, 162, 162, 162, 162, 162, 162, 162, 162,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 162
- } ;
-
-static yyconst flex_int16_t yy_nxt[592] =
- { 0,
- 10, 11, 12, 13, 14, 15, 16, 17, 16, 16,
- 18, 19, 20, 20, 21, 22, 23, 24, 24, 24,
- 24, 24, 25, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 26, 27,
- 31, 31, 36, 28, 37, 36, 36, 32, 32, 35,
- 36, 35, 35, 35, 35, 35, 35, 35, 35, 38,
- 36, 36, 35, 35, 35, 36, 40, 36, 39, 36,
- 36, 66, 48, 49, 41, 42, 56, 36, 55, 53,
- 57, 36, 50, 51, 52, 101, 35, 34, 35, 36,
- 35, 35, 35, 35, 35, 35, 35, 35, 43, 43,
-
- 34, 35, 35, 35, 34, 34, 44, 45, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 44, 34, 45, 35, 35, 36, 35, 35,
- 35, 35, 35, 35, 35, 35, 46, 46, 46, 35,
- 35, 35, 69, 36, 47, 37, 36, 53, 74, 70,
- 71, 34, 34, 34, 56, 36, 36, 36, 57, 34,
- 47, 36, 36, 35, 34, 35, 36, 35, 35, 35,
- 35, 35, 35, 35, 35, 34, 34, 75, 35, 35,
- 35, 81, 36, 80, 53, 36, 36, 86, 148, 83,
- 34, 34, 34, 34, 36, 36, 129, 36, 34, 148,
-
- 36, 98, 35, 34, 35, 36, 35, 35, 35, 35,
- 35, 35, 35, 35, 34, 82, 84, 35, 35, 35,
- 34, 34, 34, 85, 69, 76, 54, 77, 34, 69,
- 78, 162, 162, 36, 36, 79, 70, 71, 36, 85,
- 36, 35, 58, 36, 34, 36, 39, 36, 140, 36,
- 36, 36, 133, 53, 36, 87, 145, 36, 88, 36,
- 90, 36, 36, 59, 60, 89, 36, 61, 62, 99,
- 92, 104, 63, 36, 97, 91, 64, 65, 73, 73,
- 73, 100, 106, 102, 73, 105, 34, 107, 73, 73,
- 73, 73, 34, 34, 34, 103, 36, 36, 36, 36,
-
- 34, 36, 34, 93, 93, 94, 93, 93, 93, 93,
- 93, 93, 93, 93, 36, 36, 34, 93, 93, 93,
- 112, 113, 36, 36, 119, 95, 36, 117, 125, 36,
- 36, 36, 96, 36, 36, 114, 36, 36, 115, 36,
- 36, 93, 136, 116, 36, 124, 36, 159, 160, 53,
- 36, 127, 128, 126, 36, 131, 130, 134, 132, 129,
- 36, 141, 36, 143, 146, 149, 150, 140, 138, 142,
- 142, 142, 36, 136, 144, 151, 151, 151, 155, 123,
- 121, 153, 35, 145, 36, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 154,
-
- 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
- 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
- 35, 149, 150, 36, 149, 150, 111, 109, 123, 121,
- 118, 156, 156, 156, 151, 151, 151, 35, 35, 36,
- 35, 35, 35, 35, 35, 157, 35, 35, 159, 160,
- 143, 35, 35, 35, 159, 160, 111, 109, 161, 161,
- 161, 36, 67, 35, 161, 161, 161, 35, 36, 53,
- 36, 36, 36, 36, 36, 35, 35, 35, 36, 35,
- 35, 35, 35, 35, 157, 35, 35, 36, 36, 36,
- 35, 35, 35, 36, 36, 36, 67, 36, 36, 162,
-
- 29, 29, 162, 162, 162, 162, 162, 162, 162, 162,
- 162, 162, 162, 162, 35, 29, 29, 30, 30, 33,
- 33, 34, 34, 35, 35, 53, 53, 68, 68, 72,
- 72, 108, 108, 110, 110, 120, 120, 122, 122, 135,
- 135, 137, 137, 139, 139, 147, 147, 152, 152, 158,
- 158, 9, 162, 162, 162, 162, 162, 162, 162, 162,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 162
-
- } ;
-
-static yyconst flex_int16_t yy_chk[592] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
- 5, 6, 26, 2, 11, 11, 14, 5, 6, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 14,
- 21, 17, 10, 10, 10, 15, 17, 18, 15, 22,
- 23, 169, 21, 21, 18, 18, 27, 27, 26, 86,
- 27, 157, 22, 23, 23, 86, 10, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 32, 153, 20, 37, 37, 54, 54, 32,
- 32, 34, 34, 34, 56, 56, 59, 62, 56, 34,
- 20, 61, 64, 20, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 34, 43, 59, 24, 24,
- 24, 62, 82, 61, 74, 63, 152, 74, 147, 64,
- 44, 44, 44, 43, 143, 65, 114, 114, 44, 141,
-
- 60, 82, 24, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 44, 63, 65, 25, 25, 25,
- 47, 47, 47, 73, 68, 60, 25, 60, 47, 70,
- 60, 68, 68, 75, 76, 60, 70, 70, 79, 73,
- 77, 25, 28, 28, 47, 78, 28, 81, 139, 83,
- 89, 84, 118, 118, 91, 75, 134, 134, 76, 87,
- 77, 90, 137, 28, 28, 76, 92, 28, 28, 83,
- 79, 89, 28, 88, 81, 78, 28, 28, 45, 45,
- 45, 84, 91, 87, 45, 90, 45, 92, 45, 45,
- 45, 45, 85, 85, 85, 88, 100, 102, 106, 95,
-
- 85, 96, 45, 80, 80, 80, 80, 80, 80, 80,
- 80, 80, 80, 80, 97, 98, 85, 80, 80, 80,
- 95, 96, 99, 105, 102, 80, 107, 100, 106, 112,
- 115, 113, 80, 116, 117, 97, 119, 126, 98, 128,
- 138, 80, 135, 99, 130, 105, 132, 159, 159, 133,
- 146, 112, 113, 107, 144, 116, 115, 119, 117, 129,
- 129, 128, 131, 130, 138, 142, 142, 127, 126, 129,
- 129, 129, 125, 124, 132, 142, 142, 142, 146, 122,
- 120, 144, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 149, 149, 155, 151, 151, 110, 108, 104, 103,
- 101, 149, 149, 149, 151, 151, 151, 154, 154, 154,
- 154, 154, 154, 154, 154, 154, 154, 154, 156, 156,
- 155, 154, 154, 154, 161, 161, 94, 93, 156, 156,
- 156, 72, 66, 58, 161, 161, 161, 57, 55, 53,
- 52, 51, 50, 49, 48, 154, 158, 158, 158, 158,
- 158, 158, 158, 158, 158, 158, 158, 42, 41, 40,
- 158, 158, 158, 39, 38, 35, 30, 16, 13, 9,
-
- 8, 7, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 158, 163, 163, 164, 164, 165,
- 165, 166, 166, 167, 167, 168, 168, 170, 170, 171,
- 171, 172, 172, 173, 173, 174, 174, 175, 175, 176,
- 176, 177, 177, 178, 178, 179, 179, 180, 180, 181,
- 181, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 162
-
- } ;
-
-#define YY_TRAILING_MASK 0x2000
-#define YY_TRAILING_HEAD_MASK 0x4000
-#define REJECT \
-{ \
-*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ \
-yy_cp = yyg->yy_full_match; /* restore poss. backed-over text */ \
-yyg->yy_lp = yyg->yy_full_lp; /* restore orig. accepting pos. */ \
-yyg->yy_state_ptr = yyg->yy_full_state; /* restore orig. state */ \
-yy_current_state = *yyg->yy_state_ptr; /* restore curr. state */ \
-++yyg->yy_lp; \
-goto find_rule; \
-}
-
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-#line 1 "glcpp/glcpp-lex.l"
-#line 2 "glcpp/glcpp-lex.l"
-/*
- * 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);
-
-#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)
-
-#line 700 "glcpp/glcpp-lex.c"
-
-#define INITIAL 0
-#define DONE 1
-#define COMMENT 2
-#define UNREACHABLE 3
-
-#define YY_EXTRA_TYPE glcpp_parser_t *
-
-/* Holds the entire state of the reentrant scanner. */
-struct yyguts_t
- {
-
- /* User-defined. Not touched by flex. */
- YY_EXTRA_TYPE yyextra_r;
-
- /* The rest are the same as the globals declared in the non-reentrant scanner. */
- FILE *yyin_r, *yyout_r;
- size_t yy_buffer_stack_top; /**< index of top of stack. */
- size_t yy_buffer_stack_max; /**< capacity of stack. */
- YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
- char yy_hold_char;
- int yy_n_chars;
- int yyleng_r;
- char *yy_c_buf_p;
- int yy_init;
- int yy_start;
- int yy_did_buffer_switch_on_eof;
- int yy_start_stack_ptr;
- int yy_start_stack_depth;
- int *yy_start_stack;
- yy_state_type yy_last_accepting_state;
- char* yy_last_accepting_cpos;
-
- int yylineno_r;
- int yy_flex_debug_r;
-
- yy_state_type *yy_state_buf;
- yy_state_type *yy_state_ptr;
- char *yy_full_match;
- int yy_lp;
-
- /* These are only needed for trailing context rules,
- * but there's no conditional variable for that yet. */
- int yy_looking_for_trail_begin;
- int yy_full_lp;
- int *yy_full_state;
-
- char *yytext_r;
- int yy_more_flag;
- int yy_more_len;
-
- YYSTYPE * yylval_r;
-
- YYLTYPE * yylloc_r;
-
- }; /* end struct yyguts_t */
-
-static int yy_init_globals (yyscan_t yyscanner );
-
- /* This must go here because YYSTYPE and YYLTYPE are included
- * from bison output in section 1.*/
- # define yylval yyg->yylval_r
-
- # define yylloc yyg->yylloc_r
-
-int glcpp_lex_init (yyscan_t* scanner);
-
-int glcpp_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
-
-/* Accessor methods to globals.
- These are made visible to non-reentrant scanners for convenience. */
-
-int glcpp_lex_destroy (yyscan_t yyscanner );
-
-int glcpp_get_debug (yyscan_t yyscanner );
-
-void glcpp_set_debug (int debug_flag ,yyscan_t yyscanner );
-
-YY_EXTRA_TYPE glcpp_get_extra (yyscan_t yyscanner );
-
-void glcpp_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
-
-FILE *glcpp_get_in (yyscan_t yyscanner );
-
-void glcpp_set_in (FILE * in_str ,yyscan_t yyscanner );
-
-FILE *glcpp_get_out (yyscan_t yyscanner );
-
-void glcpp_set_out (FILE * out_str ,yyscan_t yyscanner );
-
-int glcpp_get_leng (yyscan_t yyscanner );
-
-char *glcpp_get_text (yyscan_t yyscanner );
-
-int glcpp_get_lineno (yyscan_t yyscanner );
-
-void glcpp_set_lineno (int line_number ,yyscan_t yyscanner );
-
-YYSTYPE * glcpp_get_lval (yyscan_t yyscanner );
-
-void glcpp_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
-
- YYLTYPE *glcpp_get_lloc (yyscan_t yyscanner );
-
- void glcpp_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int glcpp_wrap (yyscan_t yyscanner );
-#else
-extern int glcpp_wrap (yyscan_t yyscanner );
-#endif
-#endif
-
- static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner);
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
-#endif
-
-#ifndef YY_NO_INPUT
-
-#ifdef __cplusplus
-static int yyinput (yyscan_t yyscanner );
-#else
-static int input (yyscan_t yyscanner );
-#endif
-
-#endif
-
- static void yy_push_state (int new_state ,yyscan_t yyscanner);
-
- static void yy_pop_state (yyscan_t yyscanner );
-
- static int yy_top_state (yyscan_t yyscanner );
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
-#endif
-
-/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
- { \
- int c = '*'; \
- unsigned n; \
- for ( n = 0; n < max_size && \
- (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
- buf[n] = (char) c; \
- if ( c == '\n' ) \
- buf[n++] = (char) c; \
- if ( c == EOF && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- result = n; \
- } \
- else \
- { \
- errno=0; \
- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
- { \
- if( errno != EINTR) \
- { \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- break; \
- } \
- errno=0; \
- clearerr(yyin); \
- } \
- }\
-\
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
-#endif
-
-/* end tables serialization structures and prototypes */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int glcpp_lex \
- (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
-
-#define YY_DECL int glcpp_lex \
- (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
- if ( yyleng > 0 ) \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
- (yytext[yyleng - 1] == '\n'); \
- YY_USER_ACTION
-
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
- register yy_state_type yy_current_state;
- register char *yy_cp, *yy_bp;
- register int yy_act;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-#line 76 "glcpp/glcpp-lex.l"
-
-
- /* Single-line comments */
-#line 958 "glcpp/glcpp-lex.c"
-
- yylval = yylval_param;
-
- yylloc = yylloc_param;
-
- if ( !yyg->yy_init )
- {
- yyg->yy_init = 1;
-
-#ifdef YY_USER_INIT
- YY_USER_INIT;
-#endif
-
- /* Create the reject buffer large enough to save one state per allowed character. */
- if ( ! yyg->yy_state_buf )
- yyg->yy_state_buf = (yy_state_type *)glcpp_alloc(YY_STATE_BUF_SIZE ,yyscanner);
- if ( ! yyg->yy_state_buf )
- YY_FATAL_ERROR( "out of dynamic memory in glcpp_lex()" );
-
- if ( ! yyg->yy_start )
- yyg->yy_start = 1; /* first start state */
-
- if ( ! yyin )
- yyin = stdin;
-
- if ( ! yyout )
- yyout = stdout;
-
- if ( ! YY_CURRENT_BUFFER ) {
- glcpp_ensure_buffer_stack (yyscanner);
- YY_CURRENT_BUFFER_LVALUE =
- glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
- }
-
- glcpp__load_buffer_state(yyscanner );
- }
-
- while ( 1 ) /* loops until end-of-file is reached */
- {
- yy_cp = yyg->yy_c_buf_p;
-
- /* Support of yytext. */
- *yy_cp = yyg->yy_hold_char;
-
- /* yy_bp points to the position in yy_ch_buf of the start of
- * the current run.
- */
- yy_bp = yy_cp;
-
- yy_current_state = yyg->yy_start;
- yy_current_state += YY_AT_BOL();
-
- yyg->yy_state_ptr = yyg->yy_state_buf;
- *yyg->yy_state_ptr++ = yy_current_state;
-
-yy_match:
- do
- {
- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 163 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- *yyg->yy_state_ptr++ = yy_current_state;
- ++yy_cp;
- }
- while ( yy_current_state != 162 );
-
-yy_find_action:
- yy_current_state = *--yyg->yy_state_ptr;
- yyg->yy_lp = yy_accept[yy_current_state];
-find_rule: /* we branch to this label when backing up */
- for ( ; ; ) /* until we find what rule we matched */
- {
- if ( yyg->yy_lp && yyg->yy_lp < yy_accept[yy_current_state + 1] )
- {
- yy_act = yy_acclist[yyg->yy_lp];
- if ( yy_act & YY_TRAILING_HEAD_MASK ||
- yyg->yy_looking_for_trail_begin )
- {
- if ( yy_act == yyg->yy_looking_for_trail_begin )
- {
- yyg->yy_looking_for_trail_begin = 0;
- yy_act &= ~YY_TRAILING_HEAD_MASK;
- break;
- }
- }
- else if ( yy_act & YY_TRAILING_MASK )
- {
- yyg->yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK;
- yyg->yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK;
- yyg->yy_full_match = yy_cp;
- yyg->yy_full_state = yyg->yy_state_ptr;
- yyg->yy_full_lp = yyg->yy_lp;
- }
- else
- {
- yyg->yy_full_match = yy_cp;
- yyg->yy_full_state = yyg->yy_state_ptr;
- yyg->yy_full_lp = yyg->yy_lp;
- break;
- }
- ++yyg->yy_lp;
- goto find_rule;
- }
- --yy_cp;
- yy_current_state = *--yyg->yy_state_ptr;
- yyg->yy_lp = yy_accept[yy_current_state];
- }
-
- YY_DO_BEFORE_ACTION;
-
-do_action: /* This label is used only to access EOF actions. */
-
- switch ( yy_act )
- { /* beginning of action switch */
-case 1:
-YY_RULE_SETUP
-#line 79 "glcpp/glcpp-lex.l"
-{
-}
- YY_BREAK
-/* Multi-line comments */
-case 2:
-YY_RULE_SETUP
-#line 83 "glcpp/glcpp-lex.l"
-{ yy_push_state(COMMENT, yyscanner); }
- YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 84 "glcpp/glcpp-lex.l"
-
- YY_BREAK
-case 4:
-/* rule 4 can match eol */
-YY_RULE_SETUP
-#line 85 "glcpp/glcpp-lex.l"
-{ yylineno++; yycolumn = 0; return NEWLINE; }
- YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 86 "glcpp/glcpp-lex.l"
-
- YY_BREAK
-case 6:
-/* rule 6 can match eol */
-YY_RULE_SETUP
-#line 87 "glcpp/glcpp-lex.l"
-{ yylineno++; yycolumn = 0; return NEWLINE; }
- YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 88 "glcpp/glcpp-lex.l"
-{
- yy_pop_state(yyscanner);
- if (yyextra->space_tokens)
- return SPACE;
-}
- YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 94 "glcpp/glcpp-lex.l"
-{
- yylval->str = talloc_strdup (yyextra, yytext);
- yyextra->space_tokens = 0;
- return HASH_VERSION;
-}
- YY_BREAK
-/* glcpp doesn't handle #extension, #version, or #pragma directives.
- * Simply pass them through to the main compiler's lexer/parser. */
-case 9:
-YY_RULE_SETUP
-#line 102 "glcpp/glcpp-lex.l"
-{
- yylval->str = talloc_strdup (yyextra, yytext);
- yylineno++;
- yycolumn = 0;
- return OTHER;
-}
- YY_BREAK
-case 10:
-*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
-yyg->yy_c_buf_p = yy_cp -= 1;
-YY_DO_BEFORE_ACTION; /* set up yytext again */
-YY_RULE_SETUP
-#line 109 "glcpp/glcpp-lex.l"
-{
- /* 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);
-}
- YY_BREAK
-case 11:
-*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
-yyg->yy_c_buf_p = yy_cp -= 1;
-YY_DO_BEFORE_ACTION; /* set up yytext again */
-YY_RULE_SETUP
-#line 125 "glcpp/glcpp-lex.l"
-{
- /* 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;
-}
- YY_BREAK
-case 12:
-/* rule 12 can match eol */
-YY_RULE_SETUP
-#line 140 "glcpp/glcpp-lex.l"
-{
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IFDEF;
-}
- YY_BREAK
-case 13:
-/* rule 13 can match eol */
-YY_RULE_SETUP
-#line 146 "glcpp/glcpp-lex.l"
-{
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IFNDEF;
-}
- YY_BREAK
-case 14:
-/* rule 14 can match eol */
-YY_RULE_SETUP
-#line 152 "glcpp/glcpp-lex.l"
-{
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IF;
-}
- YY_BREAK
-case 15:
-/* rule 15 can match eol */
-YY_RULE_SETUP
-#line 158 "glcpp/glcpp-lex.l"
-{
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_ELIF;
-}
- YY_BREAK
-case 16:
-/* rule 16 can match eol */
-YY_RULE_SETUP
-#line 164 "glcpp/glcpp-lex.l"
-{
- yyextra->space_tokens = 0;
- return HASH_ELSE;
-}
- YY_BREAK
-case 17:
-/* rule 17 can match eol */
-YY_RULE_SETUP
-#line 169 "glcpp/glcpp-lex.l"
-{
- yyextra->space_tokens = 0;
- return HASH_ENDIF;
-}
- YY_BREAK
-/* When skipping (due to an #if 0 or similar) consume anything
- * up to a newline. We do this with less priority than any
- * #if-related directive (#if, #elif, #else, #endif), but with
- * more priority than any other directive or token to avoid
- * any side-effects from skipped content.
- *
- * We use the lexing_if flag to avoid skipping any part of an
- * if conditional expression. */
-case 18:
-/* rule 18 can match eol */
-*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
-yyg->yy_c_buf_p = yy_cp -= 1;
-YY_DO_BEFORE_ACTION; /* set up yytext again */
-YY_RULE_SETUP
-#line 182 "glcpp/glcpp-lex.l"
-{
- /* Since this rule always matches, YY_USER_ACTION gets called for it,
- * wrongly incrementing yycolumn. We undo that effect here. */
- yycolumn -= yyleng;
- if (yyextra->lexing_if ||
- yyextra->skip_stack == NULL ||
- yyextra->skip_stack->type == SKIP_NO_SKIP)
- {
- REJECT;
- }
-}
- YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 194 "glcpp/glcpp-lex.l"
-{
- char *p;
- for (p = yytext; !isalpha(p[0]); p++); /* skip " # " */
- p += 5; /* skip "error" */
- glcpp_error(yylloc, yyextra, "#error%s", p);
-}
- YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 201 "glcpp/glcpp-lex.l"
-{
- yyextra->space_tokens = 0;
- return HASH_DEFINE_FUNC;
-}
- YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 206 "glcpp/glcpp-lex.l"
-{
- yyextra->space_tokens = 0;
- return HASH_DEFINE_OBJ;
-}
- YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 211 "glcpp/glcpp-lex.l"
-{
- yyextra->space_tokens = 0;
- return HASH_UNDEF;
-}
- YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 216 "glcpp/glcpp-lex.l"
-{
- yyextra->space_tokens = 0;
- return HASH;
-}
- YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 221 "glcpp/glcpp-lex.l"
-{
- yylval->str = talloc_strdup (yyextra, yytext);
- return INTEGER_STRING;
-}
- YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 226 "glcpp/glcpp-lex.l"
-{
- yylval->str = talloc_strdup (yyextra, yytext);
- return INTEGER_STRING;
-}
- YY_BREAK
-case 26:
-YY_RULE_SETUP
-#line 231 "glcpp/glcpp-lex.l"
-{
- yylval->str = talloc_strdup (yyextra, yytext);
- return INTEGER_STRING;
-}
- YY_BREAK
-case 27:
-YY_RULE_SETUP
-#line 236 "glcpp/glcpp-lex.l"
-{
- return LEFT_SHIFT;
-}
- YY_BREAK
-case 28:
-YY_RULE_SETUP
-#line 240 "glcpp/glcpp-lex.l"
-{
- return RIGHT_SHIFT;
-}
- YY_BREAK
-case 29:
-YY_RULE_SETUP
-#line 244 "glcpp/glcpp-lex.l"
-{
- return LESS_OR_EQUAL;
-}
- YY_BREAK
-case 30:
-YY_RULE_SETUP
-#line 248 "glcpp/glcpp-lex.l"
-{
- return GREATER_OR_EQUAL;
-}
- YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 252 "glcpp/glcpp-lex.l"
-{
- return EQUAL;
-}
- YY_BREAK
-case 32:
-YY_RULE_SETUP
-#line 256 "glcpp/glcpp-lex.l"
-{
- return NOT_EQUAL;
-}
- YY_BREAK
-case 33:
-YY_RULE_SETUP
-#line 260 "glcpp/glcpp-lex.l"
-{
- return AND;
-}
- YY_BREAK
-case 34:
-YY_RULE_SETUP
-#line 264 "glcpp/glcpp-lex.l"
-{
- return OR;
-}
- YY_BREAK
-case 35:
-YY_RULE_SETUP
-#line 268 "glcpp/glcpp-lex.l"
-{
- return PASTE;
-}
- YY_BREAK
-case 36:
-YY_RULE_SETUP
-#line 272 "glcpp/glcpp-lex.l"
-{
- return DEFINED;
-}
- YY_BREAK
-case 37:
-YY_RULE_SETUP
-#line 276 "glcpp/glcpp-lex.l"
-{
- yylval->str = talloc_strdup (yyextra, yytext);
- return IDENTIFIER;
-}
- YY_BREAK
-case 38:
-YY_RULE_SETUP
-#line 281 "glcpp/glcpp-lex.l"
-{
- return yytext[0];
-}
- YY_BREAK
-case 39:
-YY_RULE_SETUP
-#line 285 "glcpp/glcpp-lex.l"
-{
- yylval->str = talloc_strdup (yyextra, yytext);
- return OTHER;
-}
- YY_BREAK
-case 40:
-YY_RULE_SETUP
-#line 290 "glcpp/glcpp-lex.l"
-{
- if (yyextra->space_tokens) {
- return SPACE;
- }
-}
- YY_BREAK
-case 41:
-/* rule 41 can match eol */
-YY_RULE_SETUP
-#line 296 "glcpp/glcpp-lex.l"
-{
- yyextra->lexing_if = 0;
- yylineno++;
- yycolumn = 0;
- return NEWLINE;
-}
- YY_BREAK
-/* Handle missing newline at EOF. */
-case YY_STATE_EOF(INITIAL):
-#line 304 "glcpp/glcpp-lex.l"
-{
- BEGIN DONE; /* Don't keep matching this rule forever. */
- yyextra->lexing_if = 0;
- return NEWLINE;
-}
- YY_BREAK
-/* 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. */
-case 42:
-YY_RULE_SETUP
-#line 314 "glcpp/glcpp-lex.l"
-{
- unput('.');
- yy_top_state(yyextra);
-}
- YY_BREAK
-case 43:
-YY_RULE_SETUP
-#line 319 "glcpp/glcpp-lex.l"
-ECHO;
- YY_BREAK
-#line 1475 "glcpp/glcpp-lex.c"
- case YY_STATE_EOF(DONE):
- case YY_STATE_EOF(COMMENT):
- case YY_STATE_EOF(UNREACHABLE):
- yyterminate();
-
- case YY_END_OF_BUFFER:
- {
- /* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
-
- /* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = yyg->yy_hold_char;
- YY_RESTORE_YY_MORE_OFFSET
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
- {
- /* We're scanning a new file or input source. It's
- * possible that this happened because the user
- * just pointed yyin at a new source and called
- * glcpp_lex(). If so, then we have to assure
- * consistency between YY_CURRENT_BUFFER and our
- * globals. Here is the right place to do so, because
- * this is the first action (other than possibly a
- * back-up) that will match for the new input source.
- */
- yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
- }
-
- /* Note that here we test for yy_c_buf_p "<=" to the position
- * of the first EOB in the buffer, since yy_c_buf_p will
- * already have been incremented past the NUL character
- * (since all states make transitions on EOB to the
- * end-of-buffer state). Contrast this with the test
- * in input().
- */
- if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
- { /* This was really a NUL. */
- yy_state_type yy_next_state;
-
- yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( yyscanner );
-
- /* Okay, we're now positioned to make the NUL
- * transition. We couldn't have
- * yy_get_previous_state() go ahead and do it
- * for us because it doesn't know how to deal
- * with the possibility of jamming (and we don't
- * want to build jamming into it because then it
- * will run more slowly).
- */
-
- yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
-
- yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
-
- if ( yy_next_state )
- {
- /* Consume the NUL. */
- yy_cp = ++yyg->yy_c_buf_p;
- yy_current_state = yy_next_state;
- goto yy_match;
- }
-
- else
- {
- yy_cp = yyg->yy_c_buf_p;
- goto yy_find_action;
- }
- }
-
- else switch ( yy_get_next_buffer( yyscanner ) )
- {
- case EOB_ACT_END_OF_FILE:
- {
- yyg->yy_did_buffer_switch_on_eof = 0;
-
- if ( glcpp_wrap(yyscanner ) )
- {
- /* Note: because we've taken care in
- * yy_get_next_buffer() to have set up
- * yytext, we can now set up
- * yy_c_buf_p so that if some total
- * hoser (like flex itself) wants to
- * call the scanner after we return the
- * YY_NULL, it'll still work - another
- * YY_NULL will get returned.
- */
- yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
-
- yy_act = YY_STATE_EOF(YY_START);
- goto do_action;
- }
-
- else
- {
- if ( ! yyg->yy_did_buffer_switch_on_eof )
- YY_NEW_FILE;
- }
- break;
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- yyg->yy_c_buf_p =
- yyg->yytext_ptr + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( yyscanner );
-
- yy_cp = yyg->yy_c_buf_p;
- yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
- goto yy_match;
-
- case EOB_ACT_LAST_MATCH:
- yyg->yy_c_buf_p =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
-
- yy_current_state = yy_get_previous_state( yyscanner );
-
- yy_cp = yyg->yy_c_buf_p;
- yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
- goto yy_find_action;
- }
- break;
- }
-
- default:
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
-} /* end of glcpp_lex */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- * EOB_ACT_LAST_MATCH -
- * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- * EOB_ACT_END_OF_FILE - end of file
- */
-static int yy_get_next_buffer (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
- register char *source = yyg->yytext_ptr;
- register int number_to_move, i;
- int ret_val;
-
- if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--end of buffer missed" );
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
- { /* Don't try to fill the buffer, so this is an EOF. */
- if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
- {
- /* We matched a single character, the EOB, so
- * treat this as a final EOF.
- */
- return EOB_ACT_END_OF_FILE;
- }
-
- else
- {
- /* We matched some text prior to the EOB, first
- * process it.
- */
- return EOB_ACT_LAST_MATCH;
- }
- }
-
- /* Try to read more data. */
-
- /* First move last chars to start of buffer. */
- number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
-
- for ( i = 0; i < number_to_move; ++i )
- *(dest++) = *(source++);
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
- /* don't do the read, it's not guaranteed to return an EOF,
- * just force an EOF
- */
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
-
- else
- {
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-
- YY_FATAL_ERROR(
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
-
- }
-
- if ( num_to_read > YY_READ_BUF_SIZE )
- num_to_read = YY_READ_BUF_SIZE;
-
- /* Read in more data. */
- YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- yyg->yy_n_chars, (size_t) num_to_read );
-
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
- }
-
- if ( yyg->yy_n_chars == 0 )
- {
- if ( number_to_move == YY_MORE_ADJ )
- {
- ret_val = EOB_ACT_END_OF_FILE;
- glcpp_restart(yyin ,yyscanner);
- }
-
- else
- {
- ret_val = EOB_ACT_LAST_MATCH;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
- YY_BUFFER_EOF_PENDING;
- }
- }
-
- else
- ret_val = EOB_ACT_CONTINUE_SCAN;
-
- if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
- /* Extend the array by 50%, plus the number we really need. */
- yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) glcpp_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
- if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
- }
-
- yyg->yy_n_chars += number_to_move;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
-
- yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
- return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
- static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
-{
- register yy_state_type yy_current_state;
- register char *yy_cp;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- yy_current_state = yyg->yy_start;
- yy_current_state += YY_AT_BOL();
-
- yyg->yy_state_ptr = yyg->yy_state_buf;
- *yyg->yy_state_ptr++ = yy_current_state;
-
- for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
- {
- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 163 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- *yyg->yy_state_ptr++ = yy_current_state;
- }
-
- return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- * next_state = yy_try_NUL_trans( current_state );
- */
- static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
-{
- register int yy_is_jam;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
-
- register YY_CHAR yy_c = 1;
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 163 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 162);
- if ( ! yy_is_jam )
- *yyg->yy_state_ptr++ = yy_current_state;
-
- return yy_is_jam ? 0 : yy_current_state;
-}
-
- static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
-{
- register char *yy_cp;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- yy_cp = yyg->yy_c_buf_p;
-
- /* undo effects of setting up yytext */
- *yy_cp = yyg->yy_hold_char;
-
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
- { /* need to shift things up to make room */
- /* +2 for EOB chars. */
- register int number_to_move = yyg->yy_n_chars + 2;
- register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
- register char *source =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
-
- while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
- *--dest = *--source;
-
- yy_cp += (int) (dest - source);
- yy_bp += (int) (dest - source);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
- yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
-
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
- YY_FATAL_ERROR( "flex scanner push-back overflow" );
- }
-
- *--yy_cp = (char) c;
-
- yyg->yytext_ptr = yy_bp;
- yyg->yy_hold_char = *yy_cp;
- yyg->yy_c_buf_p = yy_cp;
-}
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
- static int yyinput (yyscan_t yyscanner)
-#else
- static int input (yyscan_t yyscanner)
-#endif
-
-{
- int c;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- *yyg->yy_c_buf_p = yyg->yy_hold_char;
-
- if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
- {
- /* yy_c_buf_p now points to the character we want to return.
- * If this occurs *before* the EOB characters, then it's a
- * valid NUL; if not, then we've hit the end of the buffer.
- */
- if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
- /* This was really a NUL. */
- *yyg->yy_c_buf_p = '\0';
-
- else
- { /* need more input */
- int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
- ++yyg->yy_c_buf_p;
-
- switch ( yy_get_next_buffer( yyscanner ) )
- {
- case EOB_ACT_LAST_MATCH:
- /* This happens because yy_g_n_b()
- * sees that we've accumulated a
- * token and flags that we need to
- * try matching the token before
- * proceeding. But for input(),
- * there's no matching to consider.
- * So convert the EOB_ACT_LAST_MATCH
- * to EOB_ACT_END_OF_FILE.
- */
-
- /* Reset buffer status. */
- glcpp_restart(yyin ,yyscanner);
-
- /*FALLTHROUGH*/
-
- case EOB_ACT_END_OF_FILE:
- {
- if ( glcpp_wrap(yyscanner ) )
- return EOF;
-
- if ( ! yyg->yy_did_buffer_switch_on_eof )
- YY_NEW_FILE;
-#ifdef __cplusplus
- return yyinput(yyscanner);
-#else
- return input(yyscanner);
-#endif
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
- break;
- }
- }
- }
-
- c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
- *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
- yyg->yy_hold_char = *++yyg->yy_c_buf_p;
-
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
-
- return c;
-}
-#endif /* ifndef YY_NO_INPUT */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- * @param yyscanner The scanner object.
- * @note This function does not reset the start condition to @c INITIAL .
- */
- void glcpp_restart (FILE * input_file , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- if ( ! YY_CURRENT_BUFFER ){
- glcpp_ensure_buffer_stack (yyscanner);
- YY_CURRENT_BUFFER_LVALUE =
- glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
- }
-
- glcpp__init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
- glcpp__load_buffer_state(yyscanner );
-}
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- * @param yyscanner The scanner object.
- */
- void glcpp__switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- /* TODO. We should be able to replace this entire function body
- * with
- * glcpp_pop_buffer_state();
- * glcpp_push_buffer_state(new_buffer);
- */
- glcpp_ensure_buffer_stack (yyscanner);
- if ( YY_CURRENT_BUFFER == new_buffer )
- return;
-
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *yyg->yy_c_buf_p = yyg->yy_hold_char;
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
- }
-
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
- glcpp__load_buffer_state(yyscanner );
-
- /* We don't actually know whether we did this switch during
- * EOF (glcpp_wrap()) processing, but the only time this flag
- * is looked at is after glcpp_wrap() is called, so it's safe
- * to go ahead and always set it.
- */
- yyg->yy_did_buffer_switch_on_eof = 1;
-}
-
-static void glcpp__load_buffer_state (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
- yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
- yyg->yy_hold_char = *yyg->yy_c_buf_p;
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- * @param yyscanner The scanner object.
- * @return the allocated buffer state.
- */
- YY_BUFFER_STATE glcpp__create_buffer (FILE * file, int size , yyscan_t yyscanner)
-{
- YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) glcpp_alloc(sizeof( struct yy_buffer_state ) ,yyscanner );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in glcpp__create_buffer()" );
-
- b->yy_buf_size = size;
-
- /* yy_ch_buf has to be 2 characters longer than the size given because
- * we need to put in 2 end-of-buffer characters.
- */
- b->yy_ch_buf = (char *) glcpp_alloc(b->yy_buf_size + 2 ,yyscanner );
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in glcpp__create_buffer()" );
-
- b->yy_is_our_buffer = 1;
-
- glcpp__init_buffer(b,file ,yyscanner);
-
- return b;
-}
-
-/** Destroy the buffer.
- * @param b a buffer created with glcpp__create_buffer()
- * @param yyscanner The scanner object.
- */
- void glcpp__delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- if ( ! b )
- return;
-
- if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
- YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
- if ( b->yy_is_our_buffer )
- glcpp_free((void *) b->yy_ch_buf ,yyscanner );
-
- glcpp_free((void *) b ,yyscanner );
-}
-
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a glcpp_restart() or at EOF.
- */
- static void glcpp__init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
-
-{
- int oerrno = errno;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- glcpp__flush_buffer(b ,yyscanner);
-
- b->yy_input_file = file;
- b->yy_fill_buffer = 1;
-
- /* If b is the current buffer, then glcpp__init_buffer was _probably_
- * called from glcpp_restart() or through yy_get_next_buffer.
- * In that case, we don't want to reset the lineno or column.
- */
- if (b != YY_CURRENT_BUFFER){
- b->yy_bs_lineno = 1;
- b->yy_bs_column = 0;
- }
-
- b->yy_is_interactive = 0;
-
- errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- * @param yyscanner The scanner object.
- */
- void glcpp__flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- if ( ! b )
- return;
-
- b->yy_n_chars = 0;
-
- /* We always need two end-of-buffer characters. The first causes
- * a transition to the end-of-buffer state. The second causes
- * a jam in that state.
- */
- b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
- b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
- b->yy_buf_pos = &b->yy_ch_buf[0];
-
- b->yy_at_bol = 1;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- if ( b == YY_CURRENT_BUFFER )
- glcpp__load_buffer_state(yyscanner );
-}
-
-/** Pushes the new state onto the stack. The new state becomes
- * the current state. This function will allocate the stack
- * if necessary.
- * @param new_buffer The new state.
- * @param yyscanner The scanner object.
- */
-void glcpp_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- if (new_buffer == NULL)
- return;
-
- glcpp_ensure_buffer_stack(yyscanner);
-
- /* This block is copied from glcpp__switch_to_buffer. */
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *yyg->yy_c_buf_p = yyg->yy_hold_char;
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
- }
-
- /* Only push if top exists. Otherwise, replace top. */
- if (YY_CURRENT_BUFFER)
- yyg->yy_buffer_stack_top++;
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
- /* copied from glcpp__switch_to_buffer. */
- glcpp__load_buffer_state(yyscanner );
- yyg->yy_did_buffer_switch_on_eof = 1;
-}
-
-/** Removes and deletes the top of the stack, if present.
- * The next element becomes the new top.
- * @param yyscanner The scanner object.
- */
-void glcpp_pop_buffer_state (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- if (!YY_CURRENT_BUFFER)
- return;
-
- glcpp__delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
- YY_CURRENT_BUFFER_LVALUE = NULL;
- if (yyg->yy_buffer_stack_top > 0)
- --yyg->yy_buffer_stack_top;
-
- if (YY_CURRENT_BUFFER) {
- glcpp__load_buffer_state(yyscanner );
- yyg->yy_did_buffer_switch_on_eof = 1;
- }
-}
-
-/* Allocates the stack if it does not exist.
- * Guarantees space for at least one push.
- */
-static void glcpp_ensure_buffer_stack (yyscan_t yyscanner)
-{
- int num_to_alloc;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- if (!yyg->yy_buffer_stack) {
-
- /* First allocation is just for 2 elements, since we don't know if this
- * scanner will even need a stack. We use 2 instead of 1 to avoid an
- * immediate realloc on the next call.
- */
- num_to_alloc = 1;
- yyg->yy_buffer_stack = (struct yy_buffer_state**)glcpp_alloc
- (num_to_alloc * sizeof(struct yy_buffer_state*)
- , yyscanner);
- if ( ! yyg->yy_buffer_stack )
- YY_FATAL_ERROR( "out of dynamic memory in glcpp_ensure_buffer_stack()" );
-
- memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
- yyg->yy_buffer_stack_max = num_to_alloc;
- yyg->yy_buffer_stack_top = 0;
- return;
- }
-
- if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
-
- /* Increase the buffer to prepare for a possible push. */
- int grow_size = 8 /* arbitrary grow size */;
-
- num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
- yyg->yy_buffer_stack = (struct yy_buffer_state**)glcpp_realloc
- (yyg->yy_buffer_stack,
- num_to_alloc * sizeof(struct yy_buffer_state*)
- , yyscanner);
- if ( ! yyg->yy_buffer_stack )
- YY_FATAL_ERROR( "out of dynamic memory in glcpp_ensure_buffer_stack()" );
-
- /* zero only the new slots.*/
- memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
- yyg->yy_buffer_stack_max = num_to_alloc;
- }
-}
-
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE glcpp__scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
-{
- YY_BUFFER_STATE b;
-
- if ( size < 2 ||
- base[size-2] != YY_END_OF_BUFFER_CHAR ||
- base[size-1] != YY_END_OF_BUFFER_CHAR )
- /* They forgot to leave room for the EOB's. */
- return 0;
-
- b = (YY_BUFFER_STATE) glcpp_alloc(sizeof( struct yy_buffer_state ) ,yyscanner );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in glcpp__scan_buffer()" );
-
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
- b->yy_buf_pos = b->yy_ch_buf = base;
- b->yy_is_our_buffer = 0;
- b->yy_input_file = 0;
- b->yy_n_chars = b->yy_buf_size;
- b->yy_is_interactive = 0;
- b->yy_at_bol = 1;
- b->yy_fill_buffer = 0;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- glcpp__switch_to_buffer(b ,yyscanner );
-
- return b;
-}
-
-/** Setup the input buffer state to scan a string. The next call to glcpp_lex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- * glcpp__scan_bytes() instead.
- */
-YY_BUFFER_STATE glcpp__scan_string (yyconst char * yystr , yyscan_t yyscanner)
-{
-
- return glcpp__scan_bytes(yystr,strlen(yystr) ,yyscanner);
-}
-
-/** Setup the input buffer state to scan the given bytes. The next call to glcpp_lex() will
- * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
- * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE glcpp__scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
-{
- YY_BUFFER_STATE b;
- char *buf;
- yy_size_t n;
- int i;
-
- /* Get memory for full buffer, including space for trailing EOB's. */
- n = _yybytes_len + 2;
- buf = (char *) glcpp_alloc(n ,yyscanner );
- if ( ! buf )
- YY_FATAL_ERROR( "out of dynamic memory in glcpp__scan_bytes()" );
-
- for ( i = 0; i < _yybytes_len; ++i )
- buf[i] = yybytes[i];
-
- buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
- b = glcpp__scan_buffer(buf,n ,yyscanner);
- if ( ! b )
- YY_FATAL_ERROR( "bad buffer in glcpp__scan_bytes()" );
-
- /* It's okay to grow etc. this buffer, and we should throw it
- * away when we're done.
- */
- b->yy_is_our_buffer = 1;
-
- return b;
-}
-
- static void yy_push_state (int new_state , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth )
- {
- yy_size_t new_size;
-
- yyg->yy_start_stack_depth += YY_START_STACK_INCR;
- new_size = yyg->yy_start_stack_depth * sizeof( int );
-
- if ( ! yyg->yy_start_stack )
- yyg->yy_start_stack = (int *) glcpp_alloc(new_size ,yyscanner );
-
- else
- yyg->yy_start_stack = (int *) glcpp_realloc((void *) yyg->yy_start_stack,new_size ,yyscanner );
-
- if ( ! yyg->yy_start_stack )
- YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
- }
-
- yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START;
-
- BEGIN(new_state);
-}
-
- static void yy_pop_state (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- if ( --yyg->yy_start_stack_ptr < 0 )
- YY_FATAL_ERROR( "start-condition stack underflow" );
-
- BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]);
-}
-
- static int yy_top_state (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1];
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
-{
- (void) fprintf( stderr, "%s\n", msg );
- exit( YY_EXIT_FAILURE );
-}
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- yytext[yyleng] = yyg->yy_hold_char; \
- yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
- yyg->yy_hold_char = *yyg->yy_c_buf_p; \
- *yyg->yy_c_buf_p = '\0'; \
- yyleng = yyless_macro_arg; \
- } \
- while ( 0 )
-
-/* Accessor methods (get/set functions) to struct members. */
-
-/** Get the user-defined data for this scanner.
- * @param yyscanner The scanner object.
- */
-YY_EXTRA_TYPE glcpp_get_extra (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyextra;
-}
-
-/** Get the current line number.
- * @param yyscanner The scanner object.
- */
-int glcpp_get_lineno (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- if (! YY_CURRENT_BUFFER)
- return 0;
-
- return yylineno;
-}
-
-/** Get the current column number.
- * @param yyscanner The scanner object.
- */
-int glcpp_get_column (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- if (! YY_CURRENT_BUFFER)
- return 0;
-
- return yycolumn;
-}
-
-/** Get the input stream.
- * @param yyscanner The scanner object.
- */
-FILE *glcpp_get_in (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyin;
-}
-
-/** Get the output stream.
- * @param yyscanner The scanner object.
- */
-FILE *glcpp_get_out (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyout;
-}
-
-/** Get the length of the current token.
- * @param yyscanner The scanner object.
- */
-int glcpp_get_leng (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyleng;
-}
-
-/** Get the current token.
- * @param yyscanner The scanner object.
- */
-
-char *glcpp_get_text (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yytext;
-}
-
-/** Set the user-defined data. This data is never touched by the scanner.
- * @param user_defined The data to be associated with this scanner.
- * @param yyscanner The scanner object.
- */
-void glcpp_set_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyextra = user_defined ;
-}
-
-/** Set the current line number.
- * @param line_number
- * @param yyscanner The scanner object.
- */
-void glcpp_set_lineno (int line_number , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- /* lineno is only valid if an input buffer exists. */
- if (! YY_CURRENT_BUFFER )
- yy_fatal_error( "glcpp_set_lineno called with no buffer" , yyscanner);
-
- yylineno = line_number;
-}
-
-/** Set the current column.
- * @param line_number
- * @param yyscanner The scanner object.
- */
-void glcpp_set_column (int column_no , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- /* column is only valid if an input buffer exists. */
- if (! YY_CURRENT_BUFFER )
- yy_fatal_error( "glcpp_set_column called with no buffer" , yyscanner);
-
- yycolumn = column_no;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param in_str A readable stream.
- * @param yyscanner The scanner object.
- * @see glcpp__switch_to_buffer
- */
-void glcpp_set_in (FILE * in_str , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyin = in_str ;
-}
-
-void glcpp_set_out (FILE * out_str , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyout = out_str ;
-}
-
-int glcpp_get_debug (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yy_flex_debug;
-}
-
-void glcpp_set_debug (int bdebug , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yy_flex_debug = bdebug ;
-}
-
-/* Accessor methods for yylval and yylloc */
-
-YYSTYPE * glcpp_get_lval (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yylval;
-}
-
-void glcpp_set_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yylval = yylval_param;
-}
-
-YYLTYPE *glcpp_get_lloc (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yylloc;
-}
-
-void glcpp_set_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yylloc = yylloc_param;
-}
-
-/* User-visible API */
-
-/* glcpp_lex_init is special because it creates the scanner itself, so it is
- * the ONLY reentrant function that doesn't take the scanner as the last argument.
- * That's why we explicitly handle the declaration, instead of using our macros.
- */
-
-int glcpp_lex_init(yyscan_t* ptr_yy_globals)
-
-{
- if (ptr_yy_globals == NULL){
- errno = EINVAL;
- return 1;
- }
-
- *ptr_yy_globals = (yyscan_t) glcpp_alloc ( sizeof( struct yyguts_t ), NULL );
-
- if (*ptr_yy_globals == NULL){
- errno = ENOMEM;
- return 1;
- }
-
- /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
- memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-
- return yy_init_globals ( *ptr_yy_globals );
-}
-
-/* glcpp_lex_init_extra has the same functionality as glcpp_lex_init, but follows the
- * convention of taking the scanner as the last argument. Note however, that
- * this is a *pointer* to a scanner, as it will be allocated by this call (and
- * is the reason, too, why this function also must handle its own declaration).
- * The user defined value in the first argument will be available to glcpp_alloc in
- * the yyextra field.
- */
-
-int glcpp_lex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
-
-{
- struct yyguts_t dummy_yyguts;
-
- glcpp_set_extra (yy_user_defined, &dummy_yyguts);
-
- if (ptr_yy_globals == NULL){
- errno = EINVAL;
- return 1;
- }
-
- *ptr_yy_globals = (yyscan_t) glcpp_alloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-
- if (*ptr_yy_globals == NULL){
- errno = ENOMEM;
- return 1;
- }
-
- /* By setting to 0xAA, we expose bugs in
- yy_init_globals. Leave at 0x00 for releases. */
- memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-
- glcpp_set_extra (yy_user_defined, *ptr_yy_globals);
-
- return yy_init_globals ( *ptr_yy_globals );
-}
-
-static int yy_init_globals (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- /* Initialization is the same as for the non-reentrant scanner.
- * This function is called from glcpp_lex_destroy(), so don't allocate here.
- */
-
- yyg->yy_buffer_stack = 0;
- yyg->yy_buffer_stack_top = 0;
- yyg->yy_buffer_stack_max = 0;
- yyg->yy_c_buf_p = (char *) 0;
- yyg->yy_init = 0;
- yyg->yy_start = 0;
-
- yyg->yy_start_stack_ptr = 0;
- yyg->yy_start_stack_depth = 0;
- yyg->yy_start_stack = NULL;
-
- yyg->yy_state_buf = 0;
- yyg->yy_state_ptr = 0;
- yyg->yy_full_match = 0;
- yyg->yy_lp = 0;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
- yyin = stdin;
- yyout = stdout;
-#else
- yyin = (FILE *) 0;
- yyout = (FILE *) 0;
-#endif
-
- /* For future reference: Set errno on error, since we are called by
- * glcpp_lex_init()
- */
- return 0;
-}
-
-/* glcpp_lex_destroy is for both reentrant and non-reentrant scanners. */
-int glcpp_lex_destroy (yyscan_t yyscanner)
-{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- /* Pop the buffer stack, destroying each element. */
- while(YY_CURRENT_BUFFER){
- glcpp__delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- glcpp_pop_buffer_state(yyscanner);
- }
-
- /* Destroy the stack itself. */
- glcpp_free(yyg->yy_buffer_stack ,yyscanner);
- yyg->yy_buffer_stack = NULL;
-
- /* Destroy the start condition stack. */
- glcpp_free(yyg->yy_start_stack ,yyscanner );
- yyg->yy_start_stack = NULL;
-
- glcpp_free ( yyg->yy_state_buf , yyscanner);
- yyg->yy_state_buf = NULL;
-
- /* Reset the globals. This is important in a non-reentrant scanner so the next time
- * glcpp_lex() is called, initialization will occur. */
- yy_init_globals( yyscanner);
-
- /* Destroy the main struct (reentrant only). */
- glcpp_free ( yyscanner , yyscanner );
- yyscanner = NULL;
- return 0;
-}
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
-{
- register int i;
- for ( i = 0; i < n; ++i )
- s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
-{
- register int n;
- for ( n = 0; s[n]; ++n )
- ;
-
- return n;
-}
-#endif
-
-void *glcpp_alloc (yy_size_t size , yyscan_t yyscanner)
-{
- return (void *) malloc( size );
-}
-
-void *glcpp_realloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
-{
- /* The cast to (char *) in the following accommodates both
- * implementations that use char* generic pointers, and those
- * that use void* generic pointers. It works with the latter
- * because both ANSI C and C++ allow castless assignment from
- * any pointer type to void*, and deal with argument conversions
- * as though doing an assignment.
- */
- return (void *) realloc( (char *) ptr, size );
-}
-
-void glcpp_free (void * ptr , yyscan_t yyscanner)
-{
- free( (char *) ptr ); /* see glcpp_realloc() for (char *) cast */
-}
-
-#define YYTABLES_NAME "yytables"
-
-#line 319 "glcpp/glcpp-lex.l"
-
-
-
-void
-glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader)
-{
- glcpp__scan_string(shader,parser->scanner);
-}
-
+#line 2 "glcpp/glcpp-lex.c"
+
+#line 4 "glcpp/glcpp-lex.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE glcpp_restart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via glcpp_restart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void glcpp_restart (FILE *input_file ,yyscan_t yyscanner );
+void glcpp__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE glcpp__create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void glcpp__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void glcpp__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void glcpp_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void glcpp_pop_buffer_state (yyscan_t yyscanner );
+
+static void glcpp_ensure_buffer_stack (yyscan_t yyscanner );
+static void glcpp__load_buffer_state (yyscan_t yyscanner );
+static void glcpp__init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER glcpp__flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE glcpp__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE glcpp__scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE glcpp__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *glcpp_alloc (yy_size_t ,yyscan_t yyscanner );
+void *glcpp_realloc (void *,yy_size_t ,yyscan_t yyscanner );
+void glcpp_free (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer glcpp__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ glcpp_ensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ glcpp_ensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define glcpp_wrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 43
+#define YY_END_OF_BUFFER 44
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_acclist[137] =
+ { 0,
+ 3, 3, 44, 39, 43, 40, 43, 41, 43, 43,
+ 38, 43, 43, 38, 43, 38, 43, 38, 43, 25,
+ 39, 43, 24, 39, 43, 38, 43, 38, 43, 38,
+ 43, 37, 39, 43, 37, 39, 43, 38, 43, 40,
+ 43, 23, 43, 43, 3, 43, 4, 43, 5, 43,
+ 42, 43, 39, 18, 40, 32, 35, 33, 2, 1,
+ 25, 39, 25, 39, 39, 24, 39, 24, 39, 27,
+ 29, 31, 30, 28, 37, 39, 37, 39, 34, 40,
+ 23, 23, 3, 4, 5, 6, 5, 7, 1, 26,
+ 39, 37, 39,16398, 26, 39, 37, 39, 18, 37,
+
+ 39,16399,16400, 8206, 18, 8206, 37, 39, 8207, 18,
+ 8208, 18,16401, 19,16396, 22, 36, 37, 39, 21,
+ 8209, 18, 19, 8204, 18,16397,16404, 8205, 18, 11,
+ 18, 9, 8, 8212, 10, 18
+ } ;
+
+static yyconst flex_int16_t yy_accept[164] =
+ { 0,
+ 1, 1, 1, 1, 1, 2, 3, 3, 3, 4,
+ 6, 8, 10, 11, 13, 14, 16, 18, 20, 23,
+ 26, 28, 30, 32, 35, 38, 40, 42, 44, 45,
+ 47, 49, 51, 53, 54, 54, 55, 56, 57, 58,
+ 59, 60, 61, 63, 65, 66, 68, 70, 71, 72,
+ 73, 74, 75, 77, 79, 80, 81, 82, 83, 83,
+ 83, 83, 83, 83, 83, 83, 84, 85, 86, 87,
+ 88, 89, 90, 92, 94, 94, 94, 94, 94, 94,
+ 95, 95, 95, 95, 95, 97, 99, 99, 99, 99,
+ 99, 99, 99, 99, 100, 100, 100, 100, 100, 100,
+
+ 100, 102, 102, 103, 104, 104, 104, 104, 104, 106,
+ 106, 107, 107, 107, 107, 107, 107, 107, 109, 109,
+ 109, 111, 111, 113, 114, 115, 115, 116, 116, 116,
+ 116, 117, 117, 120, 121, 121, 123, 124, 124, 124,
+ 126, 127, 127, 127, 127, 128, 128, 128, 130, 130,
+ 132, 132, 133, 134, 134, 134, 134, 135, 135, 135,
+ 137, 137, 137
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 4, 4, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 5, 1, 6, 1, 7, 8, 1, 9,
+ 7, 10, 7, 7, 7, 7, 11, 12, 13, 13,
+ 13, 13, 13, 13, 13, 14, 14, 1, 7, 15,
+ 16, 17, 1, 1, 18, 18, 18, 18, 18, 18,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 20, 19, 19, 21, 19, 19,
+ 7, 1, 7, 7, 19, 1, 22, 18, 18, 23,
+
+ 24, 25, 26, 19, 27, 19, 19, 28, 29, 30,
+ 31, 32, 19, 33, 34, 35, 36, 37, 19, 38,
+ 19, 19, 7, 39, 7, 7, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[40] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[182] =
+ { 0,
+ 0, 38, 0, 0, 38, 39, 499, 498, 500, 48,
+ 43, 552, 496, 44, 63, 495, 59, 65, 87, 125,
+ 58, 67, 68, 164, 203, 40, 75, 241, 552, 494,
+ 552, 140, 552, 140, 493, 552, 144, 492, 491, 487,
+ 486, 485, 156, 179, 267, 0, 209, 472, 471, 470,
+ 469, 468, 446, 124, 466, 153, 462, 458, 154, 198,
+ 159, 155, 183, 160, 193, 460, 552, 222, 552, 227,
+ 552, 459, 204, 161, 231, 232, 238, 243, 236, 303,
+ 245, 180, 247, 249, 281, 56, 257, 271, 248, 259,
+ 252, 264, 455, 454, 297, 299, 312, 313, 320, 294,
+
+ 407, 295, 427, 426, 321, 296, 324, 425, 552, 424,
+ 552, 327, 329, 195, 328, 331, 332, 230, 334, 378,
+ 552, 377, 552, 371, 370, 335, 365, 337, 358, 342,
+ 360, 344, 326, 255, 340, 552, 260, 338, 246, 552,
+ 197, 364, 192, 352, 382, 348, 186, 552, 420, 552,
+ 423, 184, 141, 437, 421, 447, 79, 476, 346, 552,
+ 453, 552, 515, 517, 519, 521, 523, 525, 71, 527,
+ 529, 531, 533, 535, 537, 539, 541, 543, 545, 547,
+ 549
+ } ;
+
+static yyconst flex_int16_t yy_def[182] =
+ { 0,
+ 162, 1, 163, 163, 164, 164, 165, 165, 162, 166,
+ 167, 162, 167, 167, 167, 167, 167, 167, 162, 166,
+ 167, 167, 167, 168, 168, 167, 167, 167, 162, 169,
+ 162, 170, 162, 20, 167, 162, 167, 167, 167, 167,
+ 167, 171, 19, 20, 20, 20, 20, 167, 167, 167,
+ 167, 167, 25, 25, 167, 167, 28, 28, 167, 167,
+ 167, 167, 167, 167, 167, 169, 162, 170, 162, 170,
+ 162, 171, 45, 25, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 20, 25, 167, 167, 167, 167,
+ 167, 167, 172, 173, 167, 167, 167, 167, 167, 167,
+
+ 25, 167, 174, 175, 167, 167, 167, 172, 162, 173,
+ 162, 167, 167, 167, 167, 167, 167, 25, 167, 174,
+ 162, 175, 162, 176, 177, 167, 178, 167, 167, 167,
+ 167, 167, 25, 167, 176, 162, 177, 167, 178, 162,
+ 179, 167, 180, 167, 162, 167, 179, 162, 167, 162,
+ 167, 180, 167, 181, 167, 167, 167, 181, 167, 162,
+ 167, 0, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162
+ } ;
+
+static yyconst flex_int16_t yy_nxt[592] =
+ { 0,
+ 10, 11, 12, 13, 14, 15, 16, 17, 16, 16,
+ 18, 19, 20, 20, 21, 22, 23, 24, 24, 24,
+ 24, 24, 25, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 26, 27,
+ 31, 31, 36, 28, 37, 36, 36, 32, 32, 35,
+ 36, 35, 35, 35, 35, 35, 35, 35, 35, 38,
+ 36, 36, 35, 35, 35, 36, 40, 36, 39, 36,
+ 36, 66, 48, 49, 41, 42, 56, 36, 55, 53,
+ 57, 36, 50, 51, 52, 101, 35, 34, 35, 36,
+ 35, 35, 35, 35, 35, 35, 35, 35, 43, 43,
+
+ 34, 35, 35, 35, 34, 34, 44, 45, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 44, 34, 45, 35, 35, 36, 35, 35,
+ 35, 35, 35, 35, 35, 35, 46, 46, 46, 35,
+ 35, 35, 69, 36, 47, 37, 36, 53, 74, 70,
+ 71, 34, 34, 34, 56, 36, 36, 36, 57, 34,
+ 47, 36, 36, 35, 34, 35, 36, 35, 35, 35,
+ 35, 35, 35, 35, 35, 34, 34, 75, 35, 35,
+ 35, 81, 36, 80, 53, 36, 36, 86, 148, 83,
+ 34, 34, 34, 34, 36, 36, 129, 36, 34, 148,
+
+ 36, 98, 35, 34, 35, 36, 35, 35, 35, 35,
+ 35, 35, 35, 35, 34, 82, 84, 35, 35, 35,
+ 34, 34, 34, 85, 69, 76, 54, 77, 34, 69,
+ 78, 162, 162, 36, 36, 79, 70, 71, 36, 85,
+ 36, 35, 58, 36, 34, 36, 39, 36, 140, 36,
+ 36, 36, 133, 53, 36, 87, 145, 36, 88, 36,
+ 90, 36, 36, 59, 60, 89, 36, 61, 62, 99,
+ 92, 104, 63, 36, 97, 91, 64, 65, 73, 73,
+ 73, 100, 106, 102, 73, 105, 34, 107, 73, 73,
+ 73, 73, 34, 34, 34, 103, 36, 36, 36, 36,
+
+ 34, 36, 34, 93, 93, 94, 93, 93, 93, 93,
+ 93, 93, 93, 93, 36, 36, 34, 93, 93, 93,
+ 112, 113, 36, 36, 119, 95, 36, 117, 125, 36,
+ 36, 36, 96, 36, 36, 114, 36, 36, 115, 36,
+ 36, 93, 136, 116, 36, 124, 36, 159, 160, 53,
+ 36, 127, 128, 126, 36, 131, 130, 134, 132, 129,
+ 36, 141, 36, 143, 146, 149, 150, 140, 138, 142,
+ 142, 142, 36, 136, 144, 151, 151, 151, 155, 123,
+ 121, 153, 35, 145, 36, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 154,
+
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 35, 149, 150, 36, 149, 150, 111, 109, 123, 121,
+ 118, 156, 156, 156, 151, 151, 151, 35, 35, 36,
+ 35, 35, 35, 35, 35, 157, 35, 35, 159, 160,
+ 143, 35, 35, 35, 159, 160, 111, 109, 161, 161,
+ 161, 36, 67, 35, 161, 161, 161, 35, 36, 53,
+ 36, 36, 36, 36, 36, 35, 35, 35, 36, 35,
+ 35, 35, 35, 35, 157, 35, 35, 36, 36, 36,
+ 35, 35, 35, 36, 36, 36, 67, 36, 36, 162,
+
+ 29, 29, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 35, 29, 29, 30, 30, 33,
+ 33, 34, 34, 35, 35, 53, 53, 68, 68, 72,
+ 72, 108, 108, 110, 110, 120, 120, 122, 122, 135,
+ 135, 137, 137, 139, 139, 147, 147, 152, 152, 158,
+ 158, 9, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162
+
+ } ;
+
+static yyconst flex_int16_t yy_chk[592] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 5, 6, 26, 2, 11, 11, 14, 5, 6, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 14,
+ 21, 17, 10, 10, 10, 15, 17, 18, 15, 22,
+ 23, 169, 21, 21, 18, 18, 27, 27, 26, 86,
+ 27, 157, 22, 23, 23, 86, 10, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 32, 153, 20, 37, 37, 54, 54, 32,
+ 32, 34, 34, 34, 56, 56, 59, 62, 56, 34,
+ 20, 61, 64, 20, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 34, 43, 59, 24, 24,
+ 24, 62, 82, 61, 74, 63, 152, 74, 147, 64,
+ 44, 44, 44, 43, 143, 65, 114, 114, 44, 141,
+
+ 60, 82, 24, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 44, 63, 65, 25, 25, 25,
+ 47, 47, 47, 73, 68, 60, 25, 60, 47, 70,
+ 60, 68, 68, 75, 76, 60, 70, 70, 79, 73,
+ 77, 25, 28, 28, 47, 78, 28, 81, 139, 83,
+ 89, 84, 118, 118, 91, 75, 134, 134, 76, 87,
+ 77, 90, 137, 28, 28, 76, 92, 28, 28, 83,
+ 79, 89, 28, 88, 81, 78, 28, 28, 45, 45,
+ 45, 84, 91, 87, 45, 90, 45, 92, 45, 45,
+ 45, 45, 85, 85, 85, 88, 100, 102, 106, 95,
+
+ 85, 96, 45, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 97, 98, 85, 80, 80, 80,
+ 95, 96, 99, 105, 102, 80, 107, 100, 106, 112,
+ 115, 113, 80, 116, 117, 97, 119, 126, 98, 128,
+ 138, 80, 135, 99, 130, 105, 132, 159, 159, 133,
+ 146, 112, 113, 107, 144, 116, 115, 119, 117, 129,
+ 129, 128, 131, 130, 138, 142, 142, 127, 126, 129,
+ 129, 129, 125, 124, 132, 142, 142, 142, 146, 122,
+ 120, 144, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 149, 149, 155, 151, 151, 110, 108, 104, 103,
+ 101, 149, 149, 149, 151, 151, 151, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 156, 156,
+ 155, 154, 154, 154, 161, 161, 94, 93, 156, 156,
+ 156, 72, 66, 58, 161, 161, 161, 57, 55, 53,
+ 52, 51, 50, 49, 48, 154, 158, 158, 158, 158,
+ 158, 158, 158, 158, 158, 158, 158, 42, 41, 40,
+ 158, 158, 158, 39, 38, 35, 30, 16, 13, 9,
+
+ 8, 7, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 158, 163, 163, 164, 164, 165,
+ 165, 166, 166, 167, 167, 168, 168, 170, 170, 171,
+ 171, 172, 172, 173, 173, 174, 174, 175, 175, 176,
+ 176, 177, 177, 178, 178, 179, 179, 180, 180, 181,
+ 181, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
+ 162
+
+ } ;
+
+#define YY_TRAILING_MASK 0x2000
+#define YY_TRAILING_HEAD_MASK 0x4000
+#define REJECT \
+{ \
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ \
+yy_cp = yyg->yy_full_match; /* restore poss. backed-over text */ \
+yyg->yy_lp = yyg->yy_full_lp; /* restore orig. accepting pos. */ \
+yyg->yy_state_ptr = yyg->yy_full_state; /* restore orig. state */ \
+yy_current_state = *yyg->yy_state_ptr; /* restore curr. state */ \
+++yyg->yy_lp; \
+goto find_rule; \
+}
+
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "glcpp/glcpp-lex.l"
+#line 2 "glcpp/glcpp-lex.l"
+/*
+ * 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);
+
+#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)
+
+#line 700 "glcpp/glcpp-lex.c"
+
+#define INITIAL 0
+#define DONE 1
+#define COMMENT 2
+#define UNREACHABLE 3
+
+#define YY_EXTRA_TYPE glcpp_parser_t *
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ yy_state_type *yy_state_buf;
+ yy_state_type *yy_state_ptr;
+ char *yy_full_match;
+ int yy_lp;
+
+ /* These are only needed for trailing context rules,
+ * but there's no conditional variable for that yet. */
+ int yy_looking_for_trail_begin;
+ int yy_full_lp;
+ int *yy_full_state;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ YYSTYPE * yylval_r;
+
+ YYLTYPE * yylloc_r;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+ /* This must go here because YYSTYPE and YYLTYPE are included
+ * from bison output in section 1.*/
+ # define yylval yyg->yylval_r
+
+ # define yylloc yyg->yylloc_r
+
+int glcpp_lex_init (yyscan_t* scanner);
+
+int glcpp_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int glcpp_lex_destroy (yyscan_t yyscanner );
+
+int glcpp_get_debug (yyscan_t yyscanner );
+
+void glcpp_set_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE glcpp_get_extra (yyscan_t yyscanner );
+
+void glcpp_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *glcpp_get_in (yyscan_t yyscanner );
+
+void glcpp_set_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *glcpp_get_out (yyscan_t yyscanner );
+
+void glcpp_set_out (FILE * out_str ,yyscan_t yyscanner );
+
+int glcpp_get_leng (yyscan_t yyscanner );
+
+char *glcpp_get_text (yyscan_t yyscanner );
+
+int glcpp_get_lineno (yyscan_t yyscanner );
+
+void glcpp_set_lineno (int line_number ,yyscan_t yyscanner );
+
+int glcpp_get_column (yyscan_t yyscanner );
+
+void glcpp_set_column (int column_no ,yyscan_t yyscanner );
+
+YYSTYPE * glcpp_get_lval (yyscan_t yyscanner );
+
+void glcpp_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+ YYLTYPE *glcpp_get_lloc (yyscan_t yyscanner );
+
+ void glcpp_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int glcpp_wrap (yyscan_t yyscanner );
+#else
+extern int glcpp_wrap (yyscan_t yyscanner );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner);
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+ static void yy_push_state (int new_state ,yyscan_t yyscanner);
+
+ static void yy_pop_state (yyscan_t yyscanner );
+
+ static int yy_top_state (yyscan_t yyscanner );
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ unsigned n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int glcpp_lex \
+ (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int glcpp_lex \
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 76 "glcpp/glcpp-lex.l"
+
+
+ /* Single-line comments */
+#line 962 "glcpp/glcpp-lex.c"
+
+ yylval = yylval_param;
+
+ yylloc = yylloc_param;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ /* Create the reject buffer large enough to save one state per allowed character. */
+ if ( ! yyg->yy_state_buf )
+ yyg->yy_state_buf = (yy_state_type *)glcpp_alloc(YY_STATE_BUF_SIZE ,yyscanner);
+ if ( ! yyg->yy_state_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in glcpp_lex()" );
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ glcpp_ensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ glcpp__load_buffer_state(yyscanner );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ yyg->yy_state_ptr = yyg->yy_state_buf;
+ *yyg->yy_state_ptr++ = yy_current_state;
+
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 163 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *yyg->yy_state_ptr++ = yy_current_state;
+ ++yy_cp;
+ }
+ while ( yy_current_state != 162 );
+
+yy_find_action:
+ yy_current_state = *--yyg->yy_state_ptr;
+ yyg->yy_lp = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+ for ( ; ; ) /* until we find what rule we matched */
+ {
+ if ( yyg->yy_lp && yyg->yy_lp < yy_accept[yy_current_state + 1] )
+ {
+ yy_act = yy_acclist[yyg->yy_lp];
+ if ( yy_act & YY_TRAILING_HEAD_MASK ||
+ yyg->yy_looking_for_trail_begin )
+ {
+ if ( yy_act == yyg->yy_looking_for_trail_begin )
+ {
+ yyg->yy_looking_for_trail_begin = 0;
+ yy_act &= ~YY_TRAILING_HEAD_MASK;
+ break;
+ }
+ }
+ else if ( yy_act & YY_TRAILING_MASK )
+ {
+ yyg->yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK;
+ yyg->yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK;
+ yyg->yy_full_match = yy_cp;
+ yyg->yy_full_state = yyg->yy_state_ptr;
+ yyg->yy_full_lp = yyg->yy_lp;
+ }
+ else
+ {
+ yyg->yy_full_match = yy_cp;
+ yyg->yy_full_state = yyg->yy_state_ptr;
+ yyg->yy_full_lp = yyg->yy_lp;
+ break;
+ }
+ ++yyg->yy_lp;
+ goto find_rule;
+ }
+ --yy_cp;
+ yy_current_state = *--yyg->yy_state_ptr;
+ yyg->yy_lp = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 79 "glcpp/glcpp-lex.l"
+{
+}
+ YY_BREAK
+/* Multi-line comments */
+case 2:
+YY_RULE_SETUP
+#line 83 "glcpp/glcpp-lex.l"
+{ yy_push_state(COMMENT, yyscanner); }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 84 "glcpp/glcpp-lex.l"
+
+ YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 85 "glcpp/glcpp-lex.l"
+{ yylineno++; yycolumn = 0; return NEWLINE; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 86 "glcpp/glcpp-lex.l"
+
+ YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 87 "glcpp/glcpp-lex.l"
+{ yylineno++; yycolumn = 0; return NEWLINE; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 88 "glcpp/glcpp-lex.l"
+{
+ yy_pop_state(yyscanner);
+ if (yyextra->space_tokens)
+ return SPACE;
+}
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 94 "glcpp/glcpp-lex.l"
+{
+ yylval->str = ralloc_strdup (yyextra, yytext);
+ yyextra->space_tokens = 0;
+ return HASH_VERSION;
+}
+ YY_BREAK
+/* glcpp doesn't handle #extension, #version, or #pragma directives.
+ * Simply pass them through to the main compiler's lexer/parser. */
+case 9:
+YY_RULE_SETUP
+#line 102 "glcpp/glcpp-lex.l"
+{
+ yylval->str = ralloc_strdup (yyextra, yytext);
+ yylineno++;
+ yycolumn = 0;
+ return OTHER;
+}
+ YY_BREAK
+case 10:
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 109 "glcpp/glcpp-lex.l"
+{
+ /* 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);
+}
+ YY_BREAK
+case 11:
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 125 "glcpp/glcpp-lex.l"
+{
+ /* 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;
+}
+ YY_BREAK
+case 12:
+/* rule 12 can match eol */
+YY_RULE_SETUP
+#line 140 "glcpp/glcpp-lex.l"
+{
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_IFDEF;
+}
+ YY_BREAK
+case 13:
+/* rule 13 can match eol */
+YY_RULE_SETUP
+#line 146 "glcpp/glcpp-lex.l"
+{
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_IFNDEF;
+}
+ YY_BREAK
+case 14:
+/* rule 14 can match eol */
+YY_RULE_SETUP
+#line 152 "glcpp/glcpp-lex.l"
+{
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_IF;
+}
+ YY_BREAK
+case 15:
+/* rule 15 can match eol */
+YY_RULE_SETUP
+#line 158 "glcpp/glcpp-lex.l"
+{
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_ELIF;
+}
+ YY_BREAK
+case 16:
+/* rule 16 can match eol */
+YY_RULE_SETUP
+#line 164 "glcpp/glcpp-lex.l"
+{
+ yyextra->space_tokens = 0;
+ return HASH_ELSE;
+}
+ YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+#line 169 "glcpp/glcpp-lex.l"
+{
+ yyextra->space_tokens = 0;
+ return HASH_ENDIF;
+}
+ YY_BREAK
+/* When skipping (due to an #if 0 or similar) consume anything
+ * up to a newline. We do this with less priority than any
+ * #if-related directive (#if, #elif, #else, #endif), but with
+ * more priority than any other directive or token to avoid
+ * any side-effects from skipped content.
+ *
+ * We use the lexing_if flag to avoid skipping any part of an
+ * if conditional expression. */
+case 18:
+/* rule 18 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 182 "glcpp/glcpp-lex.l"
+{
+ /* Since this rule always matches, YY_USER_ACTION gets called for it,
+ * wrongly incrementing yycolumn. We undo that effect here. */
+ yycolumn -= yyleng;
+ if (yyextra->lexing_if ||
+ yyextra->skip_stack == NULL ||
+ yyextra->skip_stack->type == SKIP_NO_SKIP)
+ {
+ REJECT;
+ }
+}
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 194 "glcpp/glcpp-lex.l"
+{
+ char *p;
+ for (p = yytext; !isalpha(p[0]); p++); /* skip " # " */
+ p += 5; /* skip "error" */
+ glcpp_error(yylloc, yyextra, "#error%s", p);
+}
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 201 "glcpp/glcpp-lex.l"
+{
+ yyextra->space_tokens = 0;
+ return HASH_DEFINE_FUNC;
+}
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 206 "glcpp/glcpp-lex.l"
+{
+ yyextra->space_tokens = 0;
+ return HASH_DEFINE_OBJ;
+}
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 211 "glcpp/glcpp-lex.l"
+{
+ yyextra->space_tokens = 0;
+ return HASH_UNDEF;
+}
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 216 "glcpp/glcpp-lex.l"
+{
+ yyextra->space_tokens = 0;
+ return HASH;
+}
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 221 "glcpp/glcpp-lex.l"
+{
+ yylval->str = ralloc_strdup (yyextra, yytext);
+ return INTEGER_STRING;
+}
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 226 "glcpp/glcpp-lex.l"
+{
+ yylval->str = ralloc_strdup (yyextra, yytext);
+ return INTEGER_STRING;
+}
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 231 "glcpp/glcpp-lex.l"
+{
+ yylval->str = ralloc_strdup (yyextra, yytext);
+ return INTEGER_STRING;
+}
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 236 "glcpp/glcpp-lex.l"
+{
+ return LEFT_SHIFT;
+}
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 240 "glcpp/glcpp-lex.l"
+{
+ return RIGHT_SHIFT;
+}
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 244 "glcpp/glcpp-lex.l"
+{
+ return LESS_OR_EQUAL;
+}
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 248 "glcpp/glcpp-lex.l"
+{
+ return GREATER_OR_EQUAL;
+}
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 252 "glcpp/glcpp-lex.l"
+{
+ return EQUAL;
+}
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 256 "glcpp/glcpp-lex.l"
+{
+ return NOT_EQUAL;
+}
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 260 "glcpp/glcpp-lex.l"
+{
+ return AND;
+}
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 264 "glcpp/glcpp-lex.l"
+{
+ return OR;
+}
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 268 "glcpp/glcpp-lex.l"
+{
+ return PASTE;
+}
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 272 "glcpp/glcpp-lex.l"
+{
+ return DEFINED;
+}
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 276 "glcpp/glcpp-lex.l"
+{
+ yylval->str = ralloc_strdup (yyextra, yytext);
+ return IDENTIFIER;
+}
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 281 "glcpp/glcpp-lex.l"
+{
+ return yytext[0];
+}
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 285 "glcpp/glcpp-lex.l"
+{
+ yylval->str = ralloc_strdup (yyextra, yytext);
+ return OTHER;
+}
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 290 "glcpp/glcpp-lex.l"
+{
+ if (yyextra->space_tokens) {
+ return SPACE;
+ }
+}
+ YY_BREAK
+case 41:
+/* rule 41 can match eol */
+YY_RULE_SETUP
+#line 296 "glcpp/glcpp-lex.l"
+{
+ yyextra->lexing_if = 0;
+ yylineno++;
+ yycolumn = 0;
+ return NEWLINE;
+}
+ YY_BREAK
+/* Handle missing newline at EOF. */
+case YY_STATE_EOF(INITIAL):
+#line 304 "glcpp/glcpp-lex.l"
+{
+ BEGIN DONE; /* Don't keep matching this rule forever. */
+ yyextra->lexing_if = 0;
+ return NEWLINE;
+}
+ YY_BREAK
+/* 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. */
+case 42:
+YY_RULE_SETUP
+#line 314 "glcpp/glcpp-lex.l"
+{
+ unput('.');
+ yy_top_state(yyextra);
+}
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 319 "glcpp/glcpp-lex.l"
+ECHO;
+ YY_BREAK
+#line 1479 "glcpp/glcpp-lex.c"
+ case YY_STATE_EOF(DONE):
+ case YY_STATE_EOF(COMMENT):
+ case YY_STATE_EOF(UNREACHABLE):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * glcpp_lex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( glcpp_wrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of glcpp_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = yyg->yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ glcpp_restart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) glcpp_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ yyg->yy_state_ptr = yyg->yy_state_buf;
+ *yyg->yy_state_ptr++ = yy_current_state;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 163 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *yyg->yy_state_ptr++ = yy_current_state;
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ register int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+
+ register YY_CHAR yy_c = 1;
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 163 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 162);
+ if ( ! yy_is_jam )
+ *yyg->yy_state_ptr++ = yy_current_state;
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
+{
+ register char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yyg->yy_n_chars + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ glcpp_restart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( glcpp_wrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void glcpp_restart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ glcpp_ensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ glcpp__init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ glcpp__load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void glcpp__switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * glcpp_pop_buffer_state();
+ * glcpp_push_buffer_state(new_buffer);
+ */
+ glcpp_ensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ glcpp__load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (glcpp_wrap()) processing, but the only time this flag
+ * is looked at is after glcpp_wrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void glcpp__load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE glcpp__create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) glcpp_alloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in glcpp__create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) glcpp_alloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in glcpp__create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ glcpp__init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with glcpp__create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void glcpp__delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ glcpp_free((void *) b->yy_ch_buf ,yyscanner );
+
+ glcpp_free((void *) b ,yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a glcpp_restart() or at EOF.
+ */
+ static void glcpp__init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ glcpp__flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then glcpp__init_buffer was _probably_
+ * called from glcpp_restart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void glcpp__flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ glcpp__load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void glcpp_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ glcpp_ensure_buffer_stack(yyscanner);
+
+ /* This block is copied from glcpp__switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from glcpp__switch_to_buffer. */
+ glcpp__load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void glcpp_pop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ glcpp__delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ glcpp__load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void glcpp_ensure_buffer_stack (yyscan_t yyscanner)
+{
+ int num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)glcpp_alloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in glcpp_ensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)glcpp_realloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in glcpp_ensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE glcpp__scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) glcpp_alloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in glcpp__scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ glcpp__switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to glcpp_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * glcpp__scan_bytes() instead.
+ */
+YY_BUFFER_STATE glcpp__scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return glcpp__scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to glcpp_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE glcpp__scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) glcpp_alloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in glcpp__scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = glcpp__scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in glcpp__scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+ static void yy_push_state (int new_state , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yyg->yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yyg->yy_start_stack_depth * sizeof( int );
+
+ if ( ! yyg->yy_start_stack )
+ yyg->yy_start_stack = (int *) glcpp_alloc(new_size ,yyscanner );
+
+ else
+ yyg->yy_start_stack = (int *) glcpp_realloc((void *) yyg->yy_start_stack,new_size ,yyscanner );
+
+ if ( ! yyg->yy_start_stack )
+ YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
+ }
+
+ yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+}
+
+ static void yy_pop_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( --yyg->yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]);
+}
+
+ static int yy_top_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1];
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE glcpp_get_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int glcpp_get_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int glcpp_get_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *glcpp_get_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *glcpp_get_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int glcpp_get_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *glcpp_get_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void glcpp_set_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void glcpp_set_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "glcpp_set_lineno called with no buffer" , yyscanner);
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void glcpp_set_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "glcpp_set_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see glcpp__switch_to_buffer
+ */
+void glcpp_set_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void glcpp_set_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int glcpp_get_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void glcpp_set_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * glcpp_get_lval (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylval;
+}
+
+void glcpp_set_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylval = yylval_param;
+}
+
+YYLTYPE *glcpp_get_lloc (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylloc;
+}
+
+void glcpp_set_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylloc = yylloc_param;
+}
+
+/* User-visible API */
+
+/* glcpp_lex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int glcpp_lex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) glcpp_alloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* glcpp_lex_init_extra has the same functionality as glcpp_lex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to glcpp_alloc in
+ * the yyextra field.
+ */
+
+int glcpp_lex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ glcpp_set_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) glcpp_alloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ glcpp_set_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from glcpp_lex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+ yyg->yy_state_buf = 0;
+ yyg->yy_state_ptr = 0;
+ yyg->yy_full_match = 0;
+ yyg->yy_lp = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * glcpp_lex_init()
+ */
+ return 0;
+}
+
+/* glcpp_lex_destroy is for both reentrant and non-reentrant scanners. */
+int glcpp_lex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ glcpp__delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ glcpp_pop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ glcpp_free(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ glcpp_free(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ glcpp_free ( yyg->yy_state_buf , yyscanner);
+ yyg->yy_state_buf = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * glcpp_lex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ glcpp_free ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *glcpp_alloc (yy_size_t size , yyscan_t yyscanner)
+{
+ return (void *) malloc( size );
+}
+
+void *glcpp_realloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void glcpp_free (void * ptr , yyscan_t yyscanner)
+{
+ free( (char *) ptr ); /* see glcpp_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 319 "glcpp/glcpp-lex.l"
+
+
+
+void
+glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader)
+{
+ glcpp__scan_string(shader,parser->scanner);
+}
+
diff --git a/mesalib/src/glsl/glcpp/glcpp-lex.l b/mesalib/src/glsl/glcpp/glcpp-lex.l
index 0df10c553..11b73aea8 100644
--- a/mesalib/src/glsl/glcpp/glcpp-lex.l
+++ b/mesalib/src/glsl/glcpp/glcpp-lex.l
@@ -1,325 +1,325 @@
-%{
-/*
- * 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);
-
-#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
-
-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]?
-
-%%
-
- /* 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 = talloc_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 = talloc_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;
-}
-
-{HASH}ifdef/.*\n {
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IFDEF;
-}
-
-{HASH}ifndef/.*\n {
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IFNDEF;
-}
-
-{HASH}if/[^_a-zA-Z0-9].*\n {
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_IF;
-}
-
-{HASH}elif/.*\n {
- yyextra->lexing_if = 1;
- yyextra->space_tokens = 0;
- return HASH_ELIF;
-}
-
-{HASH}else/.*\n {
- yyextra->space_tokens = 0;
- return HASH_ELSE;
-}
-
-{HASH}endif/.*\n {
- yyextra->space_tokens = 0;
- return HASH_ENDIF;
-}
-
- /* When skipping (due to an #if 0 or similar) consume anything
- * up to a newline. We do this with less priority than any
- * #if-related directive (#if, #elif, #else, #endif), but with
- * more priority than any other directive or token to avoid
- * any side-effects from skipped content.
- *
- * We use the lexing_if flag to avoid skipping any part of an
- * if conditional expression. */
-[^\n]+/\n {
- /* Since this rule always matches, YY_USER_ACTION gets called for it,
- * wrongly incrementing yycolumn. We undo that effect here. */
- yycolumn -= yyleng;
- if (yyextra->lexing_if ||
- yyextra->skip_stack == NULL ||
- yyextra->skip_stack->type == SKIP_NO_SKIP)
- {
- REJECT;
- }
-}
-
-{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 = talloc_strdup (yyextra, yytext);
- return INTEGER_STRING;
-}
-
-{OCTAL_INTEGER} {
- yylval->str = talloc_strdup (yyextra, yytext);
- return INTEGER_STRING;
-}
-
-{HEXADECIMAL_INTEGER} {
- yylval->str = talloc_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 = talloc_strdup (yyextra, yytext);
- return IDENTIFIER;
-}
-
-{PUNCTUATION} {
- return yytext[0];
-}
-
-{OTHER}+ {
- yylval->str = talloc_strdup (yyextra, yytext);
- return OTHER;
-}
-
-{HSPACE}+ {
- if (yyextra->space_tokens) {
- return SPACE;
- }
-}
-
-\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);
+
+#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
+
+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]?
+
+%%
+
+ /* 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;
+}
+
+{HASH}ifdef/.*\n {
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_IFDEF;
+}
+
+{HASH}ifndef/.*\n {
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_IFNDEF;
+}
+
+{HASH}if/[^_a-zA-Z0-9].*\n {
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_IF;
+}
+
+{HASH}elif/.*\n {
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_ELIF;
+}
+
+{HASH}else/.*\n {
+ yyextra->space_tokens = 0;
+ return HASH_ELSE;
+}
+
+{HASH}endif/.*\n {
+ yyextra->space_tokens = 0;
+ return HASH_ENDIF;
+}
+
+ /* When skipping (due to an #if 0 or similar) consume anything
+ * up to a newline. We do this with less priority than any
+ * #if-related directive (#if, #elif, #else, #endif), but with
+ * more priority than any other directive or token to avoid
+ * any side-effects from skipped content.
+ *
+ * We use the lexing_if flag to avoid skipping any part of an
+ * if conditional expression. */
+[^\n]+/\n {
+ /* Since this rule always matches, YY_USER_ACTION gets called for it,
+ * wrongly incrementing yycolumn. We undo that effect here. */
+ yycolumn -= yyleng;
+ if (yyextra->lexing_if ||
+ yyextra->skip_stack == NULL ||
+ yyextra->skip_stack->type == SKIP_NO_SKIP)
+ {
+ REJECT;
+ }
+}
+
+{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;
+ }
+}
+
+\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.c b/mesalib/src/glsl/glcpp/glcpp-parse.c
index e46fc91e1..3e51792e9 100644
--- a/mesalib/src/glsl/glcpp/glcpp-parse.c
+++ b/mesalib/src/glsl/glcpp/glcpp-parse.c
@@ -1,4216 +1,4209 @@
-/* A Bison parser, made by GNU Bison 2.4.3. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2009, 2010 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.4.3"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 1
-
-/* Push parsers. */
-#define YYPUSH 0
-
-/* Pull parsers. */
-#define YYPULL 1
-
-/* Using locations. */
-#define YYLSP_NEEDED 1
-
-
-
-/* Copy the first part of user declarations. */
-
-/* Line 189 of yacc.c */
-#line 1 "glcpp/glcpp-parse.y"
-
-/*
- * 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 <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <inttypes.h>
-
-#include "glcpp.h"
-#include "main/core.h" /* for struct gl_extensions */
-#include "main/mtypes.h" /* for gl_api enum */
-
-#define glcpp_print(stream, str) stream = talloc_strdup_append(stream, str)
-#define glcpp_printf(stream, fmt, args, ...) \
- stream = talloc_asprintf_append(stream, fmt, args)
-
-static void
-yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error);
-
-static void
-_define_object_macro (glcpp_parser_t *parser,
- YYLTYPE *loc,
- const char *macro,
- token_list_t *replacements);
-
-static void
-_define_function_macro (glcpp_parser_t *parser,
- YYLTYPE *loc,
- const char *macro,
- string_list_t *parameters,
- token_list_t *replacements);
-
-static string_list_t *
-_string_list_create (void *ctx);
-
-static void
-_string_list_append_item (string_list_t *list, const char *str);
-
-static int
-_string_list_contains (string_list_t *list, const char *member, int *index);
-
-static int
-_string_list_length (string_list_t *list);
-
-static int
-_string_list_equal (string_list_t *a, string_list_t *b);
-
-static argument_list_t *
-_argument_list_create (void *ctx);
-
-static void
-_argument_list_append (argument_list_t *list, token_list_t *argument);
-
-static int
-_argument_list_length (argument_list_t *list);
-
-static token_list_t *
-_argument_list_member_at (argument_list_t *list, int index);
-
-/* Note: This function talloc_steal()s the str pointer. */
-static token_t *
-_token_create_str (void *ctx, int type, char *str);
-
-static token_t *
-_token_create_ival (void *ctx, int type, int ival);
-
-static token_list_t *
-_token_list_create (void *ctx);
-
-/* Note: This function calls talloc_steal on token. */
-static void
-_token_list_append (token_list_t *list, token_t *token);
-
-static void
-_token_list_append_list (token_list_t *list, token_list_t *tail);
-
-static int
-_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b);
-
-static active_list_t *
-_active_list_push (active_list_t *list,
- const char *identifier,
- token_node_t *marker);
-
-static active_list_t *
-_active_list_pop (active_list_t *list);
-
-int
-_active_list_contains (active_list_t *list, const char *identifier);
-
-static void
-_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list);
-
-static void
-_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
- token_list_t *list);
-
-static void
-_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
- token_list_t *list);
-
-static void
-_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
- int condition);
-
-static void
-_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
- const char *type, int condition);
-
-static void
-_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc);
-
-#define yylex glcpp_parser_lex
-
-static int
-glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser);
-
-static void
-glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list);
-
-static void
-add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
-
-
-
-/* Line 189 of yacc.c */
-#line 220 "glcpp/glcpp-parse.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- COMMA_FINAL = 258,
- DEFINED = 259,
- ELIF_EXPANDED = 260,
- HASH = 261,
- HASH_DEFINE_FUNC = 262,
- HASH_DEFINE_OBJ = 263,
- HASH_ELIF = 264,
- HASH_ELSE = 265,
- HASH_ENDIF = 266,
- HASH_IF = 267,
- HASH_IFDEF = 268,
- HASH_IFNDEF = 269,
- HASH_UNDEF = 270,
- HASH_VERSION = 271,
- IDENTIFIER = 272,
- IF_EXPANDED = 273,
- INTEGER = 274,
- INTEGER_STRING = 275,
- NEWLINE = 276,
- OTHER = 277,
- PLACEHOLDER = 278,
- SPACE = 279,
- PASTE = 280,
- OR = 281,
- AND = 282,
- NOT_EQUAL = 283,
- EQUAL = 284,
- GREATER_OR_EQUAL = 285,
- LESS_OR_EQUAL = 286,
- RIGHT_SHIFT = 287,
- LEFT_SHIFT = 288,
- UNARY = 289
- };
-#endif
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-typedef struct YYLTYPE
-{
- int first_line;
- int first_column;
- int last_line;
- int last_column;
-} YYLTYPE;
-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
-# define YYLTYPE_IS_DECLARED 1
-# define YYLTYPE_IS_TRIVIAL 1
-#endif
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 264 of yacc.c */
-#line 308 "glcpp/glcpp-parse.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
-#else
-static int
-YYID (yyi)
- int yyi;
-#endif
-{
- return yyi;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
- && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
- YYLTYPE yyls_alloc;
-};
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
- + 2 * YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 2
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 606
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 57
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 17
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 101
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 162
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 289
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 47, 2, 2, 2, 43, 30, 2,
- 45, 46, 41, 39, 49, 40, 54, 42, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 55,
- 33, 56, 34, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 50, 2, 51, 29, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 52, 28, 53, 48, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 31, 32, 35, 36, 37, 38, 44
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 4, 7, 9, 11, 13, 16, 20,
- 24, 29, 36, 44, 48, 52, 55, 60, 65, 69,
- 72, 75, 78, 82, 85, 87, 89, 91, 95, 99,
- 103, 107, 111, 115, 119, 123, 127, 131, 135, 139,
- 143, 147, 151, 155, 159, 163, 166, 169, 172, 175,
- 179, 181, 185, 187, 190, 193, 194, 196, 197, 199,
- 202, 207, 209, 211, 214, 216, 219, 221, 223, 225,
- 227, 229, 231, 233, 235, 237, 239, 241, 243, 245,
- 247, 249, 251, 253, 255, 257, 259, 261, 263, 265,
- 267, 269, 271, 273, 275, 277, 279, 281, 283, 285,
- 287, 289
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int8 yyrhs[] =
-{
- 58, 0, -1, -1, 58, 59, -1, 61, -1, 65,
- -1, 60, -1, 6, 66, -1, 18, 63, 21, -1,
- 5, 63, 21, -1, 8, 17, 67, 21, -1, 7,
- 17, 45, 46, 67, 21, -1, 7, 17, 45, 64,
- 46, 67, 21, -1, 15, 17, 21, -1, 12, 70,
- 21, -1, 12, 21, -1, 13, 17, 68, 21, -1,
- 14, 17, 68, 21, -1, 9, 70, 21, -1, 9,
- 21, -1, 10, 21, -1, 11, 21, -1, 16, 62,
- 21, -1, 6, 21, -1, 20, -1, 19, -1, 62,
- -1, 63, 26, 63, -1, 63, 27, 63, -1, 63,
- 28, 63, -1, 63, 29, 63, -1, 63, 30, 63,
- -1, 63, 31, 63, -1, 63, 32, 63, -1, 63,
- 35, 63, -1, 63, 36, 63, -1, 63, 34, 63,
- -1, 63, 33, 63, -1, 63, 37, 63, -1, 63,
- 38, 63, -1, 63, 40, 63, -1, 63, 39, 63,
- -1, 63, 43, 63, -1, 63, 42, 63, -1, 63,
- 41, 63, -1, 47, 63, -1, 48, 63, -1, 40,
- 63, -1, 39, 63, -1, 45, 63, 46, -1, 17,
- -1, 64, 49, 17, -1, 21, -1, 71, 21, -1,
- 71, 21, -1, -1, 71, -1, -1, 71, -1, 4,
- 17, -1, 4, 45, 17, 46, -1, 72, -1, 69,
- -1, 70, 69, -1, 72, -1, 71, 72, -1, 17,
- -1, 20, -1, 73, -1, 22, -1, 24, -1, 50,
- -1, 51, -1, 45, -1, 46, -1, 52, -1, 53,
- -1, 54, -1, 30, -1, 41, -1, 39, -1, 40,
- -1, 48, -1, 47, -1, 42, -1, 43, -1, 38,
- -1, 37, -1, 33, -1, 34, -1, 36, -1, 35,
- -1, 32, -1, 31, -1, 29, -1, 28, -1, 27,
- -1, 26, -1, 55, -1, 49, -1, 56, -1, 25,
- -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 185, 185, 187, 191, 194, 199, 200, 204, 207,
- 213, 216, 219, 222, 230, 249, 259, 264, 269, 288,
- 303, 306, 309, 330, 334, 343, 348, 349, 352, 355,
- 358, 361, 364, 367, 370, 373, 376, 379, 382, 385,
- 388, 391, 394, 397, 405, 408, 411, 414, 417, 420,
- 426, 431, 439, 440, 444, 450, 451, 454, 456, 463,
- 467, 471, 476, 480, 487, 492, 499, 503, 507, 511,
- 515, 522, 523, 524, 525, 526, 527, 528, 529, 530,
- 531, 532, 533, 534, 535, 536, 537, 538, 539, 540,
- 541, 542, 543, 544, 545, 546, 547, 548, 549, 550,
- 551, 552
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "COMMA_FINAL", "DEFINED",
- "ELIF_EXPANDED", "HASH", "HASH_DEFINE_FUNC", "HASH_DEFINE_OBJ",
- "HASH_ELIF", "HASH_ELSE", "HASH_ENDIF", "HASH_IF", "HASH_IFDEF",
- "HASH_IFNDEF", "HASH_UNDEF", "HASH_VERSION", "IDENTIFIER", "IF_EXPANDED",
- "INTEGER", "INTEGER_STRING", "NEWLINE", "OTHER", "PLACEHOLDER", "SPACE",
- "PASTE", "OR", "AND", "'|'", "'^'", "'&'", "NOT_EQUAL", "EQUAL", "'<'",
- "'>'", "GREATER_OR_EQUAL", "LESS_OR_EQUAL", "RIGHT_SHIFT", "LEFT_SHIFT",
- "'+'", "'-'", "'*'", "'/'", "'%'", "UNARY", "'('", "')'", "'!'", "'~'",
- "','", "'['", "']'", "'{'", "'}'", "'.'", "';'", "'='", "$accept",
- "input", "line", "expanded_line", "control_line", "integer_constant",
- "expression", "identifier_list", "text_line", "non_directive",
- "replacement_list", "junk", "conditional_token", "conditional_tokens",
- "pp_tokens", "preprocessing_token", "operator", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 124, 94,
- 38, 283, 284, 60, 62, 285, 286, 287, 288, 43,
- 45, 42, 47, 37, 289, 40, 41, 33, 126, 44,
- 91, 93, 123, 125, 46, 59, 61
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 57, 58, 58, 59, 59, 59, 59, 60, 60,
- 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
- 61, 61, 61, 61, 62, 62, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 64, 64, 65, 65, 66, 67, 67, 68, 68, 69,
- 69, 69, 70, 70, 71, 71, 72, 72, 72, 72,
- 72, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 0, 2, 1, 1, 1, 2, 3, 3,
- 4, 6, 7, 3, 3, 2, 4, 4, 3, 2,
- 2, 2, 3, 2, 1, 1, 1, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 2, 2, 2, 2, 3,
- 1, 3, 1, 2, 2, 0, 1, 0, 1, 2,
- 4, 1, 1, 2, 1, 2, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
-{
- 2, 0, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 66, 0, 67, 52, 69,
- 70, 101, 97, 96, 95, 94, 78, 93, 92, 88,
- 89, 91, 90, 87, 86, 80, 81, 79, 84, 85,
- 73, 74, 83, 82, 99, 71, 72, 75, 76, 77,
- 98, 100, 3, 6, 4, 5, 0, 64, 68, 25,
- 24, 0, 0, 0, 0, 0, 26, 0, 23, 7,
- 0, 0, 55, 0, 19, 62, 0, 61, 20, 21,
- 15, 0, 57, 57, 0, 0, 0, 53, 65, 48,
- 47, 0, 45, 46, 9, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 54, 0, 0, 56, 59, 0, 18,
- 63, 14, 0, 58, 0, 13, 22, 8, 49, 27,
- 28, 29, 30, 31, 32, 33, 37, 36, 34, 35,
- 38, 39, 41, 40, 44, 43, 42, 50, 55, 0,
- 10, 0, 16, 17, 0, 55, 0, 60, 11, 0,
- 51, 12
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 1, 52, 53, 54, 66, 67, 149, 55, 69,
- 115, 122, 75, 76, 116, 57, 58
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -147
-static const yytype_int16 yypact[] =
-{
- -147, 112, -147, 28, -10, 55, 62, 152, -15, 59,
- 192, 85, 86, 87, 51, -147, 28, -147, -147, -147,
- -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,
- -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,
- -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,
- -147, -147, -147, -147, -147, -147, 312, -147, -147, -147,
- -147, 28, 28, 28, 28, 28, -147, 428, -147, -147,
- 352, 63, 392, 17, -147, -147, 232, -147, -147, -147,
- -147, 272, 392, 392, 84, 89, 451, -147, -147, -147,
- -147, 469, -147, -147, -147, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, -147, 60, 90, 392, -147, 96, -147,
- -147, -147, 93, 392, 94, -147, -147, -147, -147, 489,
- 505, 520, 534, 547, 558, 558, 18, 18, 18, 18,
- 563, 563, 23, 23, -147, -147, -147, -147, 392, 32,
- -147, 61, -147, -147, 110, 392, 118, -147, -147, 149,
- -147, -147
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -147, -147, -147, -147, -147, 157, -11, -147, -147, -147,
- -146, 92, -68, 200, 0, -7, -147
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -1
-static const yytype_uint8 yytable[] =
-{
- 77, 56, 154, 77, 70, 86, 78, 15, 120, 159,
- 17, 68, 19, 120, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 117, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 59, 60, 88,
- 89, 90, 91, 92, 93, 106, 107, 108, 109, 110,
- 111, 112, 118, 88, 110, 111, 112, 61, 62, 77,
- 59, 60, 71, 63, 77, 64, 65, 147, 155, 72,
- 79, 156, 123, 123, 129, 130, 131, 132, 133, 134,
- 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
- 145, 146, 82, 83, 84, 125, 148, 157, 114, 88,
- 126, 150, 2, 151, 152, 153, 88, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 158, 17, 18, 19, 160, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 73, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
- 161, 85, 17, 74, 19, 124, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 73, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
- 81, 0, 17, 80, 19, 0, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 73, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
- 0, 0, 17, 119, 19, 0, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 73, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
- 0, 0, 17, 121, 19, 0, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 0, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
- 0, 0, 17, 87, 19, 0, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 0, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
- 0, 0, 17, 113, 19, 0, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 0, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
- 0, 0, 17, 0, 19, 0, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 0, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 94,
- 0, 0, 0, 0, 95, 96, 97, 98, 99, 100,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- 111, 112, 127, 0, 0, 0, 0, 95, 96, 97,
- 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
- 108, 109, 110, 111, 112, 95, 96, 97, 98, 99,
- 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
- 110, 111, 112, 0, 0, 128, 96, 97, 98, 99,
- 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
- 110, 111, 112, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111, 112, 98,
- 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
- 109, 110, 111, 112, 99, 100, 101, 102, 103, 104,
- 105, 106, 107, 108, 109, 110, 111, 112, 100, 101,
- 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- 111, 112, 108, 109, 110, 111, 112
-};
-
-static const yytype_int16 yycheck[] =
-{
- 7, 1, 148, 10, 4, 16, 21, 17, 76, 155,
- 20, 21, 22, 81, 24, 25, 26, 27, 28, 29,
- 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 17, 45, 46, 47, 48, 49,
- 50, 51, 52, 53, 54, 55, 56, 19, 20, 56,
- 61, 62, 63, 64, 65, 37, 38, 39, 40, 41,
- 42, 43, 45, 70, 41, 42, 43, 39, 40, 76,
- 19, 20, 17, 45, 81, 47, 48, 17, 46, 17,
- 21, 49, 82, 83, 95, 96, 97, 98, 99, 100,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- 111, 112, 17, 17, 17, 21, 46, 46, 45, 116,
- 21, 21, 0, 17, 21, 21, 123, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
- 18, 21, 20, 21, 22, 17, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 42, 43, 4, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
- 21, 14, 20, 21, 22, 83, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 42, 43, 4, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
- 10, -1, 20, 21, 22, -1, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 42, 43, 4, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
- -1, -1, 20, 21, 22, -1, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 42, 43, 4, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
- -1, -1, 20, 21, 22, -1, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 42, 43, -1, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
- -1, -1, 20, 21, 22, -1, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 42, 43, -1, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
- -1, -1, 20, 21, 22, -1, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 42, 43, -1, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
- -1, -1, 20, -1, 22, -1, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 42, 43, -1, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 21,
- -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
- 42, 43, 21, -1, -1, -1, -1, 26, 27, 28,
- 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- 39, 40, 41, 42, 43, 26, 27, 28, 29, 30,
- 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, -1, -1, 46, 27, 28, 29, 30,
- 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 29,
- 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 30, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 40, 41, 42, 43, 31, 32,
- 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
- 43, 33, 34, 35, 36, 37, 38, 39, 40, 41,
- 42, 43, 39, 40, 41, 42, 43
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 58, 0, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 20, 21, 22,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 59, 60, 61, 65, 71, 72, 73, 19,
- 20, 39, 40, 45, 47, 48, 62, 63, 21, 66,
- 71, 17, 17, 4, 21, 69, 70, 72, 21, 21,
- 21, 70, 17, 17, 17, 62, 63, 21, 72, 63,
- 63, 63, 63, 63, 21, 26, 27, 28, 29, 30,
- 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 21, 45, 67, 71, 17, 45, 21,
- 69, 21, 68, 71, 68, 21, 21, 21, 46, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 17, 46, 64,
- 21, 17, 21, 21, 67, 46, 49, 46, 21, 67,
- 17, 21
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. However,
- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
- discussed. */
-
-#define YYFAIL goto yyerrlab
-#if defined YYFAIL
- /* This is here to suppress warnings from the GCC cpp's
- -Wunused-macros. Normally we don't worry about that warning, but
- some users do, and we want to make it easy for users to remove
- YYFAIL uses, which will produce warnings from Bison 2.5. */
-#endif
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (&yylloc, parser, YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
-#else
-# define YYLEX yylex (&yylval, &yylloc, parser)
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value, Location, parser); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, glcpp_parser_t *parser)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parser)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
- YYLTYPE const * const yylocationp;
- glcpp_parser_t *parser;
-#endif
-{
- if (!yyvaluep)
- return;
- YYUSE (yylocationp);
- YYUSE (parser);
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, glcpp_parser_t *parser)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, parser)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
- YYLTYPE const * const yylocationp;
- glcpp_parser_t *parser;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- YY_LOCATION_PRINT (yyoutput, *yylocationp);
- YYFPRINTF (yyoutput, ": ");
- yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parser);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, glcpp_parser_t *parser)
-#else
-static void
-yy_reduce_print (yyvsp, yylsp, yyrule, parser)
- YYSTYPE *yyvsp;
- YYLTYPE *yylsp;
- int yyrule;
- glcpp_parser_t *parser;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- , &(yylsp[(yyi + 1) - (yynrhs)]) , parser);
- YYFPRINTF (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, yylsp, Rule, parser); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, glcpp_parser_t *parser)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep, yylocationp, parser)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
- YYLTYPE *yylocationp;
- glcpp_parser_t *parser;
-#endif
-{
- YYUSE (yyvaluep);
- YYUSE (yylocationp);
- YYUSE (parser);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-/* Prevent warnings from -Wmissing-prototypes. */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (glcpp_parser_t *parser);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-
-
-/*-------------------------.
-| yyparse or yypush_parse. |
-`-------------------------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (glcpp_parser_t *parser)
-#else
-int
-yyparse (parser)
- glcpp_parser_t *parser;
-#endif
-#endif
-{
-/* The lookahead symbol. */
-int yychar;
-
-/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
-
-/* Location data for the lookahead symbol. */
-YYLTYPE yylloc;
-
- /* Number of syntax errors so far. */
- int yynerrs;
-
- int yystate;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs;
- YYSTYPE *yyvsp;
-
- /* The location stack. */
- YYLTYPE yylsa[YYINITDEPTH];
- YYLTYPE *yyls;
- YYLTYPE *yylsp;
-
- /* The locations where the error started and ended. */
- YYLTYPE yyerror_range[3];
-
- YYSIZE_T yystacksize;
-
- int yyn;
- int yyresult;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
- YYLTYPE yyloc;
-
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
- yyls = yylsa;
- yystacksize = YYINITDEPTH;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
- yylsp = yyls;
-
-#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
- /* Initialize the default location before parsing starts. */
- yylloc.first_line = yylloc.last_line = 1;
- yylloc.first_column = yylloc.last_column = 1;
-#endif
-
-/* User initialization code. */
-
-/* Line 1251 of yacc.c */
-#line 152 "glcpp/glcpp-parse.y"
-{
- yylloc.first_line = 1;
- yylloc.first_column = 1;
- yylloc.last_line = 1;
- yylloc.last_column = 1;
- yylloc.source = 0;
-}
-
-/* Line 1251 of yacc.c */
-#line 1622 "glcpp/glcpp-parse.c"
- yylsp[0] = yylloc;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
- YYLTYPE *yyls1 = yyls;
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yyls1, yysize * sizeof (*yylsp),
- &yystacksize);
-
- yyls = yyls1;
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
- YYSTACK_RELOCATE (yyls_alloc, yyls);
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
- yylsp = yyls + yysize - 1;
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- if (yystate == YYFINAL)
- YYACCEPT;
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to lookahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a lookahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the lookahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token. */
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
- *++yylsp = yylloc;
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
- /* Default location. */
- YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 4:
-
-/* Line 1464 of yacc.c */
-#line 191 "glcpp/glcpp-parse.y"
- {
- glcpp_print(parser->output, "\n");
- ;}
- break;
-
- case 5:
-
-/* Line 1464 of yacc.c */
-#line 194 "glcpp/glcpp-parse.y"
- {
- _glcpp_parser_print_expanded_token_list (parser, (yyvsp[(1) - (1)].token_list));
- glcpp_print(parser->output, "\n");
- talloc_free ((yyvsp[(1) - (1)].token_list));
- ;}
- break;
-
- case 8:
-
-/* Line 1464 of yacc.c */
-#line 204 "glcpp/glcpp-parse.y"
- {
- _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (3)]), (yyvsp[(2) - (3)].ival));
- ;}
- break;
-
- case 9:
-
-/* Line 1464 of yacc.c */
-#line 207 "glcpp/glcpp-parse.y"
- {
- _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (3)]), "elif", (yyvsp[(2) - (3)].ival));
- ;}
- break;
-
- case 10:
-
-/* Line 1464 of yacc.c */
-#line 213 "glcpp/glcpp-parse.y"
- {
- _define_object_macro (parser, & (yylsp[(2) - (4)]), (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].token_list));
- ;}
- break;
-
- case 11:
-
-/* Line 1464 of yacc.c */
-#line 216 "glcpp/glcpp-parse.y"
- {
- _define_function_macro (parser, & (yylsp[(2) - (6)]), (yyvsp[(2) - (6)].str), NULL, (yyvsp[(5) - (6)].token_list));
- ;}
- break;
-
- case 12:
-
-/* Line 1464 of yacc.c */
-#line 219 "glcpp/glcpp-parse.y"
- {
- _define_function_macro (parser, & (yylsp[(2) - (7)]), (yyvsp[(2) - (7)].str), (yyvsp[(4) - (7)].string_list), (yyvsp[(6) - (7)].token_list));
- ;}
- break;
-
- case 13:
-
-/* Line 1464 of yacc.c */
-#line 222 "glcpp/glcpp-parse.y"
- {
- macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (3)].str));
- if (macro) {
- hash_table_remove (parser->defines, (yyvsp[(2) - (3)].str));
- talloc_free (macro);
- }
- talloc_free ((yyvsp[(2) - (3)].str));
- ;}
- break;
-
- case 14:
-
-/* Line 1464 of yacc.c */
-#line 230 "glcpp/glcpp-parse.y"
- {
- /* Be careful to only evaluate the 'if' expression if
- * we are not skipping. When we are skipping, we
- * simply push a new 0-valued 'if' onto the skip
- * stack.
- *
- * This avoids generating diagnostics for invalid
- * expressions that are being skipped. */
- if (parser->skip_stack == NULL ||
- parser->skip_stack->type == SKIP_NO_SKIP)
- {
- _glcpp_parser_expand_if (parser, IF_EXPANDED, (yyvsp[(2) - (3)].token_list));
- }
- else
- {
- _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (3)]), 0);
- parser->skip_stack->type = SKIP_TO_ENDIF;
- }
- ;}
- break;
-
- case 15:
-
-/* Line 1464 of yacc.c */
-#line 249 "glcpp/glcpp-parse.y"
- {
- /* #if without an expression is only an error if we
- * are not skipping */
- if (parser->skip_stack == NULL ||
- parser->skip_stack->type == SKIP_NO_SKIP)
- {
- glcpp_error(& (yylsp[(1) - (2)]), parser, "#if with no expression");
- }
- _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (2)]), 0);
- ;}
- break;
-
- case 16:
-
-/* Line 1464 of yacc.c */
-#line 259 "glcpp/glcpp-parse.y"
- {
- macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (4)].str));
- talloc_free ((yyvsp[(2) - (4)].str));
- _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (4)]), macro != NULL);
- ;}
- break;
-
- case 17:
-
-/* Line 1464 of yacc.c */
-#line 264 "glcpp/glcpp-parse.y"
- {
- macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (4)].str));
- talloc_free ((yyvsp[(2) - (4)].str));
- _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (4)]), macro == NULL);
- ;}
- break;
-
- case 18:
-
-/* Line 1464 of yacc.c */
-#line 269 "glcpp/glcpp-parse.y"
- {
- /* Be careful to only evaluate the 'elif' expression
- * if we are not skipping. When we are skipping, we
- * simply change to a 0-valued 'elif' on the skip
- * stack.
- *
- * This avoids generating diagnostics for invalid
- * expressions that are being skipped. */
- if (parser->skip_stack &&
- parser->skip_stack->type == SKIP_TO_ELSE)
- {
- _glcpp_parser_expand_if (parser, ELIF_EXPANDED, (yyvsp[(2) - (3)].token_list));
- }
- else
- {
- _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (3)]),
- "elif", 0);
- }
- ;}
- break;
-
- case 19:
-
-/* Line 1464 of yacc.c */
-#line 288 "glcpp/glcpp-parse.y"
- {
- /* #elif without an expression is an error unless we
- * are skipping. */
- if (parser->skip_stack &&
- parser->skip_stack->type == SKIP_TO_ELSE)
- {
- glcpp_error(& (yylsp[(1) - (2)]), parser, "#elif with no expression");
- }
- else
- {
- _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (2)]),
- "elif", 0);
- glcpp_warning(& (yylsp[(1) - (2)]), parser, "ignoring illegal #elif without expression");
- }
- ;}
- break;
-
- case 20:
-
-/* Line 1464 of yacc.c */
-#line 303 "glcpp/glcpp-parse.y"
- {
- _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (2)]), "else", 1);
- ;}
- break;
-
- case 21:
-
-/* Line 1464 of yacc.c */
-#line 306 "glcpp/glcpp-parse.y"
- {
- _glcpp_parser_skip_stack_pop (parser, & (yylsp[(1) - (2)]));
- ;}
- break;
-
- case 22:
-
-/* Line 1464 of yacc.c */
-#line 309 "glcpp/glcpp-parse.y"
- {
- macro_t *macro = hash_table_find (parser->defines, "__VERSION__");
- if (macro) {
- hash_table_remove (parser->defines, "__VERSION__");
- talloc_free (macro);
- }
- add_builtin_define (parser, "__VERSION__", (yyvsp[(2) - (3)].ival));
-
- if ((yyvsp[(2) - (3)].ival) == 100)
- add_builtin_define (parser, "GL_ES", 1);
-
- /* Currently, all ES2 implementations support highp in the
- * fragment shader, so we always define this macro in ES2.
- * If we ever get a driver that doesn't support highp, we'll
- * need to add a flag to the gl_context and check that here.
- */
- if ((yyvsp[(2) - (3)].ival) >= 130 || (yyvsp[(2) - (3)].ival) == 100)
- add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1);
-
- glcpp_printf(parser->output, "#version %" PRIiMAX, (yyvsp[(2) - (3)].ival));
- ;}
- break;
-
- case 24:
-
-/* Line 1464 of yacc.c */
-#line 334 "glcpp/glcpp-parse.y"
- {
- if (strlen ((yyvsp[(1) - (1)].str)) >= 3 && strncmp ((yyvsp[(1) - (1)].str), "0x", 2) == 0) {
- (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str) + 2, NULL, 16);
- } else if ((yyvsp[(1) - (1)].str)[0] == '0') {
- (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str), NULL, 8);
- } else {
- (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str), NULL, 10);
- }
- ;}
- break;
-
- case 25:
-
-/* Line 1464 of yacc.c */
-#line 343 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (1)].ival);
- ;}
- break;
-
- case 27:
-
-/* Line 1464 of yacc.c */
-#line 349 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) || (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 28:
-
-/* Line 1464 of yacc.c */
-#line 352 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) && (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 29:
-
-/* Line 1464 of yacc.c */
-#line 355 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) | (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 30:
-
-/* Line 1464 of yacc.c */
-#line 358 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) ^ (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 31:
-
-/* Line 1464 of yacc.c */
-#line 361 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) & (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 32:
-
-/* Line 1464 of yacc.c */
-#line 364 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) != (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 33:
-
-/* Line 1464 of yacc.c */
-#line 367 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) == (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 34:
-
-/* Line 1464 of yacc.c */
-#line 370 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) >= (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 35:
-
-/* Line 1464 of yacc.c */
-#line 373 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) <= (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 36:
-
-/* Line 1464 of yacc.c */
-#line 376 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) > (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 37:
-
-/* Line 1464 of yacc.c */
-#line 379 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) < (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 38:
-
-/* Line 1464 of yacc.c */
-#line 382 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) >> (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 39:
-
-/* Line 1464 of yacc.c */
-#line 385 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) << (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 40:
-
-/* Line 1464 of yacc.c */
-#line 388 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) - (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 41:
-
-/* Line 1464 of yacc.c */
-#line 391 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) + (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 42:
-
-/* Line 1464 of yacc.c */
-#line 394 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) % (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 43:
-
-/* Line 1464 of yacc.c */
-#line 397 "glcpp/glcpp-parse.y"
- {
- if ((yyvsp[(3) - (3)].ival) == 0) {
- yyerror (& (yylsp[(1) - (3)]), parser,
- "division by 0 in preprocessor directive");
- } else {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) / (yyvsp[(3) - (3)].ival);
- }
- ;}
- break;
-
- case 44:
-
-/* Line 1464 of yacc.c */
-#line 405 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(1) - (3)].ival) * (yyvsp[(3) - (3)].ival);
- ;}
- break;
-
- case 45:
-
-/* Line 1464 of yacc.c */
-#line 408 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = ! (yyvsp[(2) - (2)].ival);
- ;}
- break;
-
- case 46:
-
-/* Line 1464 of yacc.c */
-#line 411 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = ~ (yyvsp[(2) - (2)].ival);
- ;}
- break;
-
- case 47:
-
-/* Line 1464 of yacc.c */
-#line 414 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = - (yyvsp[(2) - (2)].ival);
- ;}
- break;
-
- case 48:
-
-/* Line 1464 of yacc.c */
-#line 417 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = + (yyvsp[(2) - (2)].ival);
- ;}
- break;
-
- case 49:
-
-/* Line 1464 of yacc.c */
-#line 420 "glcpp/glcpp-parse.y"
- {
- (yyval.ival) = (yyvsp[(2) - (3)].ival);
- ;}
- break;
-
- case 50:
-
-/* Line 1464 of yacc.c */
-#line 426 "glcpp/glcpp-parse.y"
- {
- (yyval.string_list) = _string_list_create (parser);
- _string_list_append_item ((yyval.string_list), (yyvsp[(1) - (1)].str));
- talloc_steal ((yyval.string_list), (yyvsp[(1) - (1)].str));
- ;}
- break;
-
- case 51:
-
-/* Line 1464 of yacc.c */
-#line 431 "glcpp/glcpp-parse.y"
- {
- (yyval.string_list) = (yyvsp[(1) - (3)].string_list);
- _string_list_append_item ((yyval.string_list), (yyvsp[(3) - (3)].str));
- talloc_steal ((yyval.string_list), (yyvsp[(3) - (3)].str));
- ;}
- break;
-
- case 52:
-
-/* Line 1464 of yacc.c */
-#line 439 "glcpp/glcpp-parse.y"
- { (yyval.token_list) = NULL; ;}
- break;
-
- case 54:
-
-/* Line 1464 of yacc.c */
-#line 444 "glcpp/glcpp-parse.y"
- {
- yyerror (& (yylsp[(1) - (2)]), parser, "Invalid tokens after #");
- ;}
- break;
-
- case 55:
-
-/* Line 1464 of yacc.c */
-#line 450 "glcpp/glcpp-parse.y"
- { (yyval.token_list) = NULL; ;}
- break;
-
- case 58:
-
-/* Line 1464 of yacc.c */
-#line 456 "glcpp/glcpp-parse.y"
- {
- glcpp_warning(&(yylsp[(1) - (1)]), parser, "extra tokens at end of directive");
- ;}
- break;
-
- case 59:
-
-/* Line 1464 of yacc.c */
-#line 463 "glcpp/glcpp-parse.y"
- {
- int v = hash_table_find (parser->defines, (yyvsp[(2) - (2)].str)) ? 1 : 0;
- (yyval.token) = _token_create_ival (parser, INTEGER, v);
- ;}
- break;
-
- case 60:
-
-/* Line 1464 of yacc.c */
-#line 467 "glcpp/glcpp-parse.y"
- {
- int v = hash_table_find (parser->defines, (yyvsp[(3) - (4)].str)) ? 1 : 0;
- (yyval.token) = _token_create_ival (parser, INTEGER, v);
- ;}
- break;
-
- case 62:
-
-/* Line 1464 of yacc.c */
-#line 476 "glcpp/glcpp-parse.y"
- {
- (yyval.token_list) = _token_list_create (parser);
- _token_list_append ((yyval.token_list), (yyvsp[(1) - (1)].token));
- ;}
- break;
-
- case 63:
-
-/* Line 1464 of yacc.c */
-#line 480 "glcpp/glcpp-parse.y"
- {
- (yyval.token_list) = (yyvsp[(1) - (2)].token_list);
- _token_list_append ((yyval.token_list), (yyvsp[(2) - (2)].token));
- ;}
- break;
-
- case 64:
-
-/* Line 1464 of yacc.c */
-#line 487 "glcpp/glcpp-parse.y"
- {
- parser->space_tokens = 1;
- (yyval.token_list) = _token_list_create (parser);
- _token_list_append ((yyval.token_list), (yyvsp[(1) - (1)].token));
- ;}
- break;
-
- case 65:
-
-/* Line 1464 of yacc.c */
-#line 492 "glcpp/glcpp-parse.y"
- {
- (yyval.token_list) = (yyvsp[(1) - (2)].token_list);
- _token_list_append ((yyval.token_list), (yyvsp[(2) - (2)].token));
- ;}
- break;
-
- case 66:
-
-/* Line 1464 of yacc.c */
-#line 499 "glcpp/glcpp-parse.y"
- {
- (yyval.token) = _token_create_str (parser, IDENTIFIER, (yyvsp[(1) - (1)].str));
- (yyval.token)->location = yylloc;
- ;}
- break;
-
- case 67:
-
-/* Line 1464 of yacc.c */
-#line 503 "glcpp/glcpp-parse.y"
- {
- (yyval.token) = _token_create_str (parser, INTEGER_STRING, (yyvsp[(1) - (1)].str));
- (yyval.token)->location = yylloc;
- ;}
- break;
-
- case 68:
-
-/* Line 1464 of yacc.c */
-#line 507 "glcpp/glcpp-parse.y"
- {
- (yyval.token) = _token_create_ival (parser, (yyvsp[(1) - (1)].ival), (yyvsp[(1) - (1)].ival));
- (yyval.token)->location = yylloc;
- ;}
- break;
-
- case 69:
-
-/* Line 1464 of yacc.c */
-#line 511 "glcpp/glcpp-parse.y"
- {
- (yyval.token) = _token_create_str (parser, OTHER, (yyvsp[(1) - (1)].str));
- (yyval.token)->location = yylloc;
- ;}
- break;
-
- case 70:
-
-/* Line 1464 of yacc.c */
-#line 515 "glcpp/glcpp-parse.y"
- {
- (yyval.token) = _token_create_ival (parser, SPACE, SPACE);
- (yyval.token)->location = yylloc;
- ;}
- break;
-
- case 71:
-
-/* Line 1464 of yacc.c */
-#line 522 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '['; ;}
- break;
-
- case 72:
-
-/* Line 1464 of yacc.c */
-#line 523 "glcpp/glcpp-parse.y"
- { (yyval.ival) = ']'; ;}
- break;
-
- case 73:
-
-/* Line 1464 of yacc.c */
-#line 524 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '('; ;}
- break;
-
- case 74:
-
-/* Line 1464 of yacc.c */
-#line 525 "glcpp/glcpp-parse.y"
- { (yyval.ival) = ')'; ;}
- break;
-
- case 75:
-
-/* Line 1464 of yacc.c */
-#line 526 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '{'; ;}
- break;
-
- case 76:
-
-/* Line 1464 of yacc.c */
-#line 527 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '}'; ;}
- break;
-
- case 77:
-
-/* Line 1464 of yacc.c */
-#line 528 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '.'; ;}
- break;
-
- case 78:
-
-/* Line 1464 of yacc.c */
-#line 529 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '&'; ;}
- break;
-
- case 79:
-
-/* Line 1464 of yacc.c */
-#line 530 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '*'; ;}
- break;
-
- case 80:
-
-/* Line 1464 of yacc.c */
-#line 531 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '+'; ;}
- break;
-
- case 81:
-
-/* Line 1464 of yacc.c */
-#line 532 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '-'; ;}
- break;
-
- case 82:
-
-/* Line 1464 of yacc.c */
-#line 533 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '~'; ;}
- break;
-
- case 83:
-
-/* Line 1464 of yacc.c */
-#line 534 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '!'; ;}
- break;
-
- case 84:
-
-/* Line 1464 of yacc.c */
-#line 535 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '/'; ;}
- break;
-
- case 85:
-
-/* Line 1464 of yacc.c */
-#line 536 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '%'; ;}
- break;
-
- case 86:
-
-/* Line 1464 of yacc.c */
-#line 537 "glcpp/glcpp-parse.y"
- { (yyval.ival) = LEFT_SHIFT; ;}
- break;
-
- case 87:
-
-/* Line 1464 of yacc.c */
-#line 538 "glcpp/glcpp-parse.y"
- { (yyval.ival) = RIGHT_SHIFT; ;}
- break;
-
- case 88:
-
-/* Line 1464 of yacc.c */
-#line 539 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '<'; ;}
- break;
-
- case 89:
-
-/* Line 1464 of yacc.c */
-#line 540 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '>'; ;}
- break;
-
- case 90:
-
-/* Line 1464 of yacc.c */
-#line 541 "glcpp/glcpp-parse.y"
- { (yyval.ival) = LESS_OR_EQUAL; ;}
- break;
-
- case 91:
-
-/* Line 1464 of yacc.c */
-#line 542 "glcpp/glcpp-parse.y"
- { (yyval.ival) = GREATER_OR_EQUAL; ;}
- break;
-
- case 92:
-
-/* Line 1464 of yacc.c */
-#line 543 "glcpp/glcpp-parse.y"
- { (yyval.ival) = EQUAL; ;}
- break;
-
- case 93:
-
-/* Line 1464 of yacc.c */
-#line 544 "glcpp/glcpp-parse.y"
- { (yyval.ival) = NOT_EQUAL; ;}
- break;
-
- case 94:
-
-/* Line 1464 of yacc.c */
-#line 545 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '^'; ;}
- break;
-
- case 95:
-
-/* Line 1464 of yacc.c */
-#line 546 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '|'; ;}
- break;
-
- case 96:
-
-/* Line 1464 of yacc.c */
-#line 547 "glcpp/glcpp-parse.y"
- { (yyval.ival) = AND; ;}
- break;
-
- case 97:
-
-/* Line 1464 of yacc.c */
-#line 548 "glcpp/glcpp-parse.y"
- { (yyval.ival) = OR; ;}
- break;
-
- case 98:
-
-/* Line 1464 of yacc.c */
-#line 549 "glcpp/glcpp-parse.y"
- { (yyval.ival) = ';'; ;}
- break;
-
- case 99:
-
-/* Line 1464 of yacc.c */
-#line 550 "glcpp/glcpp-parse.y"
- { (yyval.ival) = ','; ;}
- break;
-
- case 100:
-
-/* Line 1464 of yacc.c */
-#line 551 "glcpp/glcpp-parse.y"
- { (yyval.ival) = '='; ;}
- break;
-
- case 101:
-
-/* Line 1464 of yacc.c */
-#line 552 "glcpp/glcpp-parse.y"
- { (yyval.ival) = PASTE; ;}
- break;
-
-
-
-/* Line 1464 of yacc.c */
-#line 2661 "glcpp/glcpp-parse.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
- *++yylsp = yyloc;
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (&yylloc, parser, YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (&yylloc, parser, yymsg);
- }
- else
- {
- yyerror (&yylloc, parser, YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
- yyerror_range[1] = yylloc;
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse lookahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval, &yylloc, parser);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse lookahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- yyerror_range[1] = yylsp[1-yylen];
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
- yyerror_range[1] = *yylsp;
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp, yylsp, parser);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- *++yyvsp = yylval;
-
- yyerror_range[2] = yylloc;
- /* Using YYLLOC is tempting, but would change the location of
- the lookahead. YYLOC is available though. */
- YYLLOC_DEFAULT (yyloc, yyerror_range, 2);
- *++yylsp = yyloc;
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#if !defined(yyoverflow) || YYERROR_VERBOSE
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (&yylloc, parser, YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval, &yylloc, parser);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp, yylsp, parser);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-
-/* Line 1684 of yacc.c */
-#line 555 "glcpp/glcpp-parse.y"
-
-
-string_list_t *
-_string_list_create (void *ctx)
-{
- string_list_t *list;
-
- list = talloc (ctx, string_list_t);
- list->head = NULL;
- list->tail = NULL;
-
- return list;
-}
-
-void
-_string_list_append_item (string_list_t *list, const char *str)
-{
- string_node_t *node;
-
- node = talloc (list, string_node_t);
- node->str = talloc_strdup (node, str);
-
- node->next = NULL;
-
- if (list->head == NULL) {
- list->head = node;
- } else {
- list->tail->next = node;
- }
-
- list->tail = node;
-}
-
-int
-_string_list_contains (string_list_t *list, const char *member, int *index)
-{
- string_node_t *node;
- int i;
-
- if (list == NULL)
- return 0;
-
- for (i = 0, node = list->head; node; i++, node = node->next) {
- if (strcmp (node->str, member) == 0) {
- if (index)
- *index = i;
- return 1;
- }
- }
-
- return 0;
-}
-
-int
-_string_list_length (string_list_t *list)
-{
- int length = 0;
- string_node_t *node;
-
- if (list == NULL)
- return 0;
-
- for (node = list->head; node; node = node->next)
- length++;
-
- return length;
-}
-
-int
-_string_list_equal (string_list_t *a, string_list_t *b)
-{
- string_node_t *node_a, *node_b;
-
- if (a == NULL && b == NULL)
- return 1;
-
- if (a == NULL || b == NULL)
- return 0;
-
- for (node_a = a->head, node_b = b->head;
- node_a && node_b;
- node_a = node_a->next, node_b = node_b->next)
- {
- if (strcmp (node_a->str, node_b->str))
- return 0;
- }
-
- /* Catch the case of lists being different lengths, (which
- * would cause the loop above to terminate after the shorter
- * list). */
- return node_a == node_b;
-}
-
-argument_list_t *
-_argument_list_create (void *ctx)
-{
- argument_list_t *list;
-
- list = talloc (ctx, argument_list_t);
- list->head = NULL;
- list->tail = NULL;
-
- return list;
-}
-
-void
-_argument_list_append (argument_list_t *list, token_list_t *argument)
-{
- argument_node_t *node;
-
- node = talloc (list, argument_node_t);
- node->argument = argument;
-
- node->next = NULL;
-
- if (list->head == NULL) {
- list->head = node;
- } else {
- list->tail->next = node;
- }
-
- list->tail = node;
-}
-
-int
-_argument_list_length (argument_list_t *list)
-{
- int length = 0;
- argument_node_t *node;
-
- if (list == NULL)
- return 0;
-
- for (node = list->head; node; node = node->next)
- length++;
-
- return length;
-}
-
-token_list_t *
-_argument_list_member_at (argument_list_t *list, int index)
-{
- argument_node_t *node;
- int i;
-
- if (list == NULL)
- return NULL;
-
- node = list->head;
- for (i = 0; i < index; i++) {
- node = node->next;
- if (node == NULL)
- break;
- }
-
- if (node)
- return node->argument;
-
- return NULL;
-}
-
-/* Note: This function talloc_steal()s the str pointer. */
-token_t *
-_token_create_str (void *ctx, int type, char *str)
-{
- token_t *token;
-
- token = talloc (ctx, token_t);
- token->type = type;
- token->value.str = talloc_steal (token, str);
-
- return token;
-}
-
-token_t *
-_token_create_ival (void *ctx, int type, int ival)
-{
- token_t *token;
-
- token = talloc (ctx, token_t);
- token->type = type;
- token->value.ival = ival;
-
- return token;
-}
-
-token_list_t *
-_token_list_create (void *ctx)
-{
- token_list_t *list;
-
- list = talloc (ctx, token_list_t);
- list->head = NULL;
- list->tail = NULL;
- list->non_space_tail = NULL;
-
- return list;
-}
-
-void
-_token_list_append (token_list_t *list, token_t *token)
-{
- token_node_t *node;
-
- node = talloc (list, token_node_t);
- node->token = talloc_steal (list, token);
-
- node->next = NULL;
-
- if (list->head == NULL) {
- list->head = node;
- } else {
- list->tail->next = node;
- }
-
- list->tail = node;
- if (token->type != SPACE)
- list->non_space_tail = node;
-}
-
-void
-_token_list_append_list (token_list_t *list, token_list_t *tail)
-{
- if (tail == NULL || tail->head == NULL)
- return;
-
- if (list->head == NULL) {
- list->head = tail->head;
- } else {
- list->tail->next = tail->head;
- }
-
- list->tail = tail->tail;
- list->non_space_tail = tail->non_space_tail;
-}
-
-static token_list_t *
-_token_list_copy (void *ctx, token_list_t *other)
-{
- token_list_t *copy;
- token_node_t *node;
-
- if (other == NULL)
- return NULL;
-
- copy = _token_list_create (ctx);
- for (node = other->head; node; node = node->next) {
- token_t *new_token = talloc (copy, token_t);
- *new_token = *node->token;
- _token_list_append (copy, new_token);
- }
-
- return copy;
-}
-
-static void
-_token_list_trim_trailing_space (token_list_t *list)
-{
- token_node_t *tail, *next;
-
- if (list->non_space_tail) {
- tail = list->non_space_tail->next;
- list->non_space_tail->next = NULL;
- list->tail = list->non_space_tail;
-
- while (tail) {
- next = tail->next;
- talloc_free (tail);
- tail = next;
- }
- }
-}
-
-int
-_token_list_is_empty_ignoring_space (token_list_t *l)
-{
- token_node_t *n;
-
- if (l == NULL)
- return 1;
-
- n = l->head;
- while (n != NULL && n->token->type == SPACE)
- n = n->next;
-
- return n == NULL;
-}
-
-int
-_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
-{
- token_node_t *node_a, *node_b;
-
- if (a == NULL || b == NULL) {
- int a_empty = _token_list_is_empty_ignoring_space(a);
- int b_empty = _token_list_is_empty_ignoring_space(b);
- return a_empty == b_empty;
- }
-
- node_a = a->head;
- node_b = b->head;
-
- while (1)
- {
- if (node_a == NULL && node_b == NULL)
- break;
-
- if (node_a == NULL || node_b == NULL)
- return 0;
-
- if (node_a->token->type == SPACE) {
- node_a = node_a->next;
- continue;
- }
-
- if (node_b->token->type == SPACE) {
- node_b = node_b->next;
- continue;
- }
-
- if (node_a->token->type != node_b->token->type)
- return 0;
-
- switch (node_a->token->type) {
- case INTEGER:
- if (node_a->token->value.ival !=
- node_b->token->value.ival)
- {
- return 0;
- }
- break;
- case IDENTIFIER:
- case INTEGER_STRING:
- case OTHER:
- if (strcmp (node_a->token->value.str,
- node_b->token->value.str))
- {
- return 0;
- }
- break;
- }
-
- node_a = node_a->next;
- node_b = node_b->next;
- }
-
- return 1;
-}
-
-static void
-_token_print (char **out, token_t *token)
-{
- if (token->type < 256) {
- glcpp_printf (*out, "%c", token->type);
- return;
- }
-
- switch (token->type) {
- case INTEGER:
- glcpp_printf (*out, "%" PRIiMAX, token->value.ival);
- break;
- case IDENTIFIER:
- case INTEGER_STRING:
- case OTHER:
- glcpp_print (*out, token->value.str);
- break;
- case SPACE:
- glcpp_print (*out, " ");
- break;
- case LEFT_SHIFT:
- glcpp_print (*out, "<<");
- break;
- case RIGHT_SHIFT:
- glcpp_print (*out, ">>");
- break;
- case LESS_OR_EQUAL:
- glcpp_print (*out, "<=");
- break;
- case GREATER_OR_EQUAL:
- glcpp_print (*out, ">=");
- break;
- case EQUAL:
- glcpp_print (*out, "==");
- break;
- case NOT_EQUAL:
- glcpp_print (*out, "!=");
- break;
- case AND:
- glcpp_print (*out, "&&");
- break;
- case OR:
- glcpp_print (*out, "||");
- break;
- case PASTE:
- glcpp_print (*out, "##");
- break;
- case COMMA_FINAL:
- glcpp_print (*out, ",");
- break;
- case PLACEHOLDER:
- /* Nothing to print. */
- break;
- default:
- assert(!"Error: Don't know how to print token.");
- break;
- }
-}
-
-/* Return a new token (talloc()ed off of 'token') formed by pasting
- * 'token' and 'other'. Note that this function may return 'token' or
- * 'other' directly rather than allocating anything new.
- *
- * Caution: Only very cursory error-checking is performed to see if
- * the final result is a valid single token. */
-static token_t *
-_token_paste (glcpp_parser_t *parser, token_t *token, token_t *other)
-{
- token_t *combined = NULL;
-
- /* Pasting a placeholder onto anything makes no change. */
- if (other->type == PLACEHOLDER)
- return token;
-
- /* When 'token' is a placeholder, just return 'other'. */
- if (token->type == PLACEHOLDER)
- return other;
-
- /* A very few single-character punctuators can be combined
- * with another to form a multi-character punctuator. */
- switch (token->type) {
- case '<':
- if (other->type == '<')
- combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT);
- else if (other->type == '=')
- combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL);
- break;
- case '>':
- if (other->type == '>')
- combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT);
- else if (other->type == '=')
- combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL);
- break;
- case '=':
- if (other->type == '=')
- combined = _token_create_ival (token, EQUAL, EQUAL);
- break;
- case '!':
- if (other->type == '=')
- combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL);
- break;
- case '&':
- if (other->type == '&')
- combined = _token_create_ival (token, AND, AND);
- break;
- case '|':
- if (other->type == '|')
- combined = _token_create_ival (token, OR, OR);
- break;
- }
-
- if (combined != NULL) {
- /* Inherit the location from the first token */
- combined->location = token->location;
- return combined;
- }
-
- /* Two string-valued tokens can usually just be mashed
- * together.
- *
- * XXX: This isn't actually legitimate. Several things here
- * should result in a diagnostic since the result cannot be a
- * valid, single pre-processing token. For example, pasting
- * "123" and "abc" is not legal, but we don't catch that
- * here. */
- if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) &&
- (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING))
- {
- char *str;
-
- str = talloc_asprintf (token, "%s%s", token->value.str,
- other->value.str);
- combined = _token_create_str (token, token->type, str);
- combined->location = token->location;
- return combined;
- }
-
- glcpp_error (&token->location, parser, "");
- glcpp_print (parser->info_log, "Pasting \"");
- _token_print (&parser->info_log, token);
- glcpp_print (parser->info_log, "\" and \"");
- _token_print (&parser->info_log, other);
- glcpp_print (parser->info_log, "\" does not give a valid preprocessing token.\n");
-
- return token;
-}
-
-static void
-_token_list_print (glcpp_parser_t *parser, token_list_t *list)
-{
- token_node_t *node;
-
- if (list == NULL)
- return;
-
- for (node = list->head; node; node = node->next)
- _token_print (&parser->output, node->token);
-}
-
-void
-yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error)
-{
- glcpp_error(locp, parser, "%s", error);
-}
-
-static void add_builtin_define(glcpp_parser_t *parser,
- const char *name, int value)
-{
- token_t *tok;
- token_list_t *list;
-
- tok = _token_create_ival (parser, INTEGER, value);
-
- list = _token_list_create(parser);
- _token_list_append(list, tok);
- _define_object_macro(parser, NULL, name, list);
-}
-
-glcpp_parser_t *
-glcpp_parser_create (const struct gl_extensions *extensions, int api)
-{
- glcpp_parser_t *parser;
- int language_version;
-
- parser = talloc (NULL, glcpp_parser_t);
-
- glcpp_lex_init_extra (parser, &parser->scanner);
- parser->defines = hash_table_ctor (32, hash_table_string_hash,
- hash_table_string_compare);
- parser->active = NULL;
- parser->lexing_if = 0;
- parser->space_tokens = 1;
- parser->newline_as_space = 0;
- parser->in_control_line = 0;
- parser->paren_count = 0;
-
- parser->skip_stack = NULL;
-
- parser->lex_from_list = NULL;
- parser->lex_from_node = NULL;
-
- parser->output = talloc_strdup(parser, "");
- parser->info_log = talloc_strdup(parser, "");
- parser->error = 0;
-
- /* Add pre-defined macros. */
- add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
- add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
-
- if (api == API_OPENGLES2)
- add_builtin_define(parser, "GL_ES", 1);
-
- if (extensions != NULL) {
- if (extensions->EXT_texture_array) {
- add_builtin_define(parser, "GL_EXT_texture_array", 1);
- }
-
- if (extensions->ARB_fragment_coord_conventions)
- add_builtin_define(parser, "GL_ARB_fragment_coord_conventions",
- 1);
-
- if (extensions->ARB_explicit_attrib_location)
- add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1);
- if (extensions->AMD_conservative_depth)
- add_builtin_define(parser, "GL_AMD_conservative_depth", 1);
- }
-
- language_version = 110;
- add_builtin_define(parser, "__VERSION__", language_version);
-
- return parser;
-}
-
-int
-glcpp_parser_parse (glcpp_parser_t *parser)
-{
- return yyparse (parser);
-}
-
-void
-glcpp_parser_destroy (glcpp_parser_t *parser)
-{
- glcpp_lex_destroy (parser->scanner);
- hash_table_dtor (parser->defines);
- talloc_free (parser);
-}
-
-typedef enum function_status
-{
- FUNCTION_STATUS_SUCCESS,
- FUNCTION_NOT_A_FUNCTION,
- FUNCTION_UNBALANCED_PARENTHESES
-} function_status_t;
-
-/* Find a set of function-like macro arguments by looking for a
- * balanced set of parentheses.
- *
- * When called, 'node' should be the opening-parenthesis token, (or
- * perhaps preceeding SPACE tokens). Upon successful return *last will
- * be the last consumed node, (corresponding to the closing right
- * parenthesis).
- *
- * Return values:
- *
- * FUNCTION_STATUS_SUCCESS:
- *
- * Successfully parsed a set of function arguments.
- *
- * FUNCTION_NOT_A_FUNCTION:
- *
- * Macro name not followed by a '('. This is not an error, but
- * simply that the macro name should be treated as a non-macro.
- *
- * FUNCTION_UNBALANCED_PARENTHESES
- *
- * Macro name is not followed by a balanced set of parentheses.
- */
-static function_status_t
-_arguments_parse (argument_list_t *arguments,
- token_node_t *node,
- token_node_t **last)
-{
- token_list_t *argument;
- int paren_count;
-
- node = node->next;
-
- /* Ignore whitespace before first parenthesis. */
- while (node && node->token->type == SPACE)
- node = node->next;
-
- if (node == NULL || node->token->type != '(')
- return FUNCTION_NOT_A_FUNCTION;
-
- node = node->next;
-
- argument = _token_list_create (arguments);
- _argument_list_append (arguments, argument);
-
- for (paren_count = 1; node; node = node->next) {
- if (node->token->type == '(')
- {
- paren_count++;
- }
- else if (node->token->type == ')')
- {
- paren_count--;
- if (paren_count == 0)
- break;
- }
-
- if (node->token->type == ',' &&
- paren_count == 1)
- {
- _token_list_trim_trailing_space (argument);
- argument = _token_list_create (arguments);
- _argument_list_append (arguments, argument);
- }
- else {
- if (argument->head == NULL) {
- /* Don't treat initial whitespace as
- * part of the arguement. */
- if (node->token->type == SPACE)
- continue;
- }
- _token_list_append (argument, node->token);
- }
- }
-
- if (paren_count)
- return FUNCTION_UNBALANCED_PARENTHESES;
-
- *last = node;
-
- return FUNCTION_STATUS_SUCCESS;
-}
-
-static token_list_t *
-_token_list_create_with_one_space (void *ctx)
-{
- token_list_t *list;
- token_t *space;
-
- list = _token_list_create (ctx);
- space = _token_create_ival (list, SPACE, SPACE);
- _token_list_append (list, space);
-
- return list;
-}
-
-static void
-_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list)
-{
- token_list_t *expanded;
- token_t *token;
-
- expanded = _token_list_create (parser);
- token = _token_create_ival (parser, type, type);
- _token_list_append (expanded, token);
- _glcpp_parser_expand_token_list (parser, list);
- _token_list_append_list (expanded, list);
- glcpp_parser_lex_from (parser, expanded);
-}
-
-/* This is a helper function that's essentially part of the
- * implementation of _glcpp_parser_expand_node. It shouldn't be called
- * except for by that function.
- *
- * Returns NULL if node is a simple token with no expansion, (that is,
- * although 'node' corresponds to an identifier defined as a
- * function-like macro, it is not followed with a parenthesized
- * argument list).
- *
- * Compute the complete expansion of node (which is a function-like
- * macro) and subsequent nodes which are arguments.
- *
- * Returns the token list that results from the expansion and sets
- * *last to the last node in the list that was consumed by the
- * expansion. Specifically, *last will be set as follows: as the
- * token of the closing right parenthesis.
- */
-static token_list_t *
-_glcpp_parser_expand_function (glcpp_parser_t *parser,
- token_node_t *node,
- token_node_t **last)
-
-{
- macro_t *macro;
- const char *identifier;
- argument_list_t *arguments;
- function_status_t status;
- token_list_t *substituted;
- int parameter_index;
-
- identifier = node->token->value.str;
-
- macro = hash_table_find (parser->defines, identifier);
-
- assert (macro->is_function);
-
- arguments = _argument_list_create (parser);
- status = _arguments_parse (arguments, node, last);
-
- switch (status) {
- case FUNCTION_STATUS_SUCCESS:
- break;
- case FUNCTION_NOT_A_FUNCTION:
- return NULL;
- case FUNCTION_UNBALANCED_PARENTHESES:
- glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier);
- return NULL;
- }
-
- /* Replace a macro defined as empty with a SPACE token. */
- if (macro->replacements == NULL) {
- talloc_free (arguments);
- return _token_list_create_with_one_space (parser);
- }
-
- if (! ((_argument_list_length (arguments) ==
- _string_list_length (macro->parameters)) ||
- (_string_list_length (macro->parameters) == 0 &&
- _argument_list_length (arguments) == 1 &&
- arguments->head->argument->head == NULL)))
- {
- glcpp_error (&node->token->location, parser,
- "Error: macro %s invoked with %d arguments (expected %d)\n",
- identifier,
- _argument_list_length (arguments),
- _string_list_length (macro->parameters));
- return NULL;
- }
-
- /* Perform argument substitution on the replacement list. */
- substituted = _token_list_create (arguments);
-
- for (node = macro->replacements->head; node; node = node->next)
- {
- if (node->token->type == IDENTIFIER &&
- _string_list_contains (macro->parameters,
- node->token->value.str,
- &parameter_index))
- {
- token_list_t *argument;
- argument = _argument_list_member_at (arguments,
- parameter_index);
- /* Before substituting, we expand the argument
- * tokens, or append a placeholder token for
- * an empty argument. */
- if (argument->head) {
- token_list_t *expanded_argument;
- expanded_argument = _token_list_copy (parser,
- argument);
- _glcpp_parser_expand_token_list (parser,
- expanded_argument);
- _token_list_append_list (substituted,
- expanded_argument);
- } else {
- token_t *new_token;
-
- new_token = _token_create_ival (substituted,
- PLACEHOLDER,
- PLACEHOLDER);
- _token_list_append (substituted, new_token);
- }
- } else {
- _token_list_append (substituted, node->token);
- }
- }
-
- /* After argument substitution, and before further expansion
- * below, implement token pasting. */
-
- _token_list_trim_trailing_space (substituted);
-
- node = substituted->head;
- while (node)
- {
- token_node_t *next_non_space;
-
- /* Look ahead for a PASTE token, skipping space. */
- next_non_space = node->next;
- while (next_non_space && next_non_space->token->type == SPACE)
- next_non_space = next_non_space->next;
-
- if (next_non_space == NULL)
- break;
-
- if (next_non_space->token->type != PASTE) {
- node = next_non_space;
- continue;
- }
-
- /* Now find the next non-space token after the PASTE. */
- next_non_space = next_non_space->next;
- while (next_non_space && next_non_space->token->type == SPACE)
- next_non_space = next_non_space->next;
-
- if (next_non_space == NULL) {
- yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n");
- return NULL;
- }
-
- node->token = _token_paste (parser, node->token, next_non_space->token);
- node->next = next_non_space->next;
- if (next_non_space == substituted->tail)
- substituted->tail = node;
-
- node = node->next;
- }
-
- substituted->non_space_tail = substituted->tail;
-
- return substituted;
-}
-
-/* Compute the complete expansion of node, (and subsequent nodes after
- * 'node' in the case that 'node' is a function-like macro and
- * subsequent nodes are arguments).
- *
- * Returns NULL if node is a simple token with no expansion.
- *
- * Otherwise, returns the token list that results from the expansion
- * and sets *last to the last node in the list that was consumed by
- * the expansion. Specifically, *last will be set as follows:
- *
- * As 'node' in the case of object-like macro expansion.
- *
- * As the token of the closing right parenthesis in the case of
- * function-like macro expansion.
- */
-static token_list_t *
-_glcpp_parser_expand_node (glcpp_parser_t *parser,
- token_node_t *node,
- token_node_t **last)
-{
- token_t *token = node->token;
- const char *identifier;
- macro_t *macro;
-
- /* We only expand identifiers */
- if (token->type != IDENTIFIER) {
- /* We change any COMMA into a COMMA_FINAL to prevent
- * it being mistaken for an argument separator
- * later. */
- if (token->type == ',') {
- token->type = COMMA_FINAL;
- token->value.ival = COMMA_FINAL;
- }
-
- return NULL;
- }
-
- /* Look up this identifier in the hash table. */
- identifier = token->value.str;
- macro = hash_table_find (parser->defines, identifier);
-
- /* Not a macro, so no expansion needed. */
- if (macro == NULL)
- return NULL;
-
- /* Finally, don't expand this macro if we're already actively
- * expanding it, (to avoid infinite recursion). */
- if (_active_list_contains (parser->active, identifier)) {
- /* We change the token type here from IDENTIFIER to
- * OTHER to prevent any future expansion of this
- * unexpanded token. */
- char *str;
- token_list_t *expansion;
- token_t *final;
-
- str = talloc_strdup (parser, token->value.str);
- final = _token_create_str (parser, OTHER, str);
- expansion = _token_list_create (parser);
- _token_list_append (expansion, final);
- *last = node;
- return expansion;
- }
-
- if (! macro->is_function)
- {
- *last = node;
-
- /* Replace a macro defined as empty with a SPACE token. */
- if (macro->replacements == NULL)
- return _token_list_create_with_one_space (parser);
-
- return _token_list_copy (parser, macro->replacements);
- }
-
- return _glcpp_parser_expand_function (parser, node, last);
-}
-
-/* Push a new identifier onto the active list, returning the new list.
- *
- * Here, 'marker' is the token node that appears in the list after the
- * expansion of 'identifier'. That is, when the list iterator begins
- * examinging 'marker', then it is time to pop this node from the
- * active stack.
- */
-active_list_t *
-_active_list_push (active_list_t *list,
- const char *identifier,
- token_node_t *marker)
-{
- active_list_t *node;
-
- node = talloc (list, active_list_t);
- node->identifier = talloc_strdup (node, identifier);
- node->marker = marker;
- node->next = list;
-
- return node;
-}
-
-active_list_t *
-_active_list_pop (active_list_t *list)
-{
- active_list_t *node = list;
-
- if (node == NULL)
- return NULL;
-
- node = list->next;
- talloc_free (list);
-
- return node;
-}
-
-int
-_active_list_contains (active_list_t *list, const char *identifier)
-{
- active_list_t *node;
-
- if (list == NULL)
- return 0;
-
- for (node = list; node; node = node->next)
- if (strcmp (node->identifier, identifier) == 0)
- return 1;
-
- return 0;
-}
-
-/* Walk over the token list replacing nodes with their expansion.
- * Whenever nodes are expanded the walking will walk over the new
- * nodes, continuing to expand as necessary. The results are placed in
- * 'list' itself;
- */
-static void
-_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
- token_list_t *list)
-{
- token_node_t *node_prev;
- token_node_t *node, *last = NULL;
- token_list_t *expansion;
-
- if (list == NULL)
- return;
-
- _token_list_trim_trailing_space (list);
-
- node_prev = NULL;
- node = list->head;
-
- while (node) {
-
- while (parser->active && parser->active->marker == node)
- parser->active = _active_list_pop (parser->active);
-
- /* Find the expansion for node, which will replace all
- * nodes from node to last, inclusive. */
- expansion = _glcpp_parser_expand_node (parser, node, &last);
- if (expansion) {
- token_node_t *n;
-
- for (n = node; n != last->next; n = n->next)
- while (parser->active &&
- parser->active->marker == n)
- {
- parser->active = _active_list_pop (parser->active);
- }
-
- parser->active = _active_list_push (parser->active,
- node->token->value.str,
- last->next);
-
- /* Splice expansion into list, supporting a
- * simple deletion if the expansion is
- * empty. */
- if (expansion->head) {
- if (node_prev)
- node_prev->next = expansion->head;
- else
- list->head = expansion->head;
- expansion->tail->next = last->next;
- if (last == list->tail)
- list->tail = expansion->tail;
- } else {
- if (node_prev)
- node_prev->next = last->next;
- else
- list->head = last->next;
- if (last == list->tail)
- list->tail = NULL;
- }
- } else {
- node_prev = node;
- }
- node = node_prev ? node_prev->next : list->head;
- }
-
- while (parser->active)
- parser->active = _active_list_pop (parser->active);
-
- list->non_space_tail = list->tail;
-}
-
-void
-_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
- token_list_t *list)
-{
- if (list == NULL)
- return;
-
- _glcpp_parser_expand_token_list (parser, list);
-
- _token_list_trim_trailing_space (list);
-
- _token_list_print (parser, list);
-}
-
-static void
-_check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc,
- const char *identifier)
-{
- /* According to the GLSL specification, macro names starting with "__"
- * or "GL_" are reserved for future use. So, don't allow them.
- */
- if (strncmp(identifier, "__", 2) == 0) {
- glcpp_error (loc, parser, "Macro names starting with \"__\" are reserved.\n");
- }
- if (strncmp(identifier, "GL_", 3) == 0) {
- glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n");
- }
-}
-
-static int
-_macro_equal (macro_t *a, macro_t *b)
-{
- if (a->is_function != b->is_function)
- return 0;
-
- if (a->is_function) {
- if (! _string_list_equal (a->parameters, b->parameters))
- return 0;
- }
-
- return _token_list_equal_ignoring_space (a->replacements,
- b->replacements);
-}
-
-void
-_define_object_macro (glcpp_parser_t *parser,
- YYLTYPE *loc,
- const char *identifier,
- token_list_t *replacements)
-{
- macro_t *macro, *previous;
-
- if (loc != NULL)
- _check_for_reserved_macro_name(parser, loc, identifier);
-
- macro = talloc (parser, macro_t);
-
- macro->is_function = 0;
- macro->parameters = NULL;
- macro->identifier = talloc_strdup (macro, identifier);
- macro->replacements = talloc_steal (macro, replacements);
-
- previous = hash_table_find (parser->defines, identifier);
- if (previous) {
- if (_macro_equal (macro, previous)) {
- talloc_free (macro);
- return;
- }
- glcpp_error (loc, parser, "Redefinition of macro %s\n",
- identifier);
- }
-
- hash_table_insert (parser->defines, macro, identifier);
-}
-
-void
-_define_function_macro (glcpp_parser_t *parser,
- YYLTYPE *loc,
- const char *identifier,
- string_list_t *parameters,
- token_list_t *replacements)
-{
- macro_t *macro, *previous;
-
- _check_for_reserved_macro_name(parser, loc, identifier);
-
- macro = talloc (parser, macro_t);
-
- macro->is_function = 1;
- macro->parameters = talloc_steal (macro, parameters);
- macro->identifier = talloc_strdup (macro, identifier);
- macro->replacements = talloc_steal (macro, replacements);
-
- previous = hash_table_find (parser->defines, identifier);
- if (previous) {
- if (_macro_equal (macro, previous)) {
- talloc_free (macro);
- return;
- }
- glcpp_error (loc, parser, "Redefinition of macro %s\n",
- identifier);
- }
-
- hash_table_insert (parser->defines, macro, identifier);
-}
-
-static int
-glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser)
-{
- token_node_t *node;
- int ret;
-
- if (parser->lex_from_list == NULL) {
- ret = glcpp_lex (yylval, yylloc, parser->scanner);
-
- /* XXX: This ugly block of code exists for the sole
- * purpose of converting a NEWLINE token into a SPACE
- * token, but only in the case where we have seen a
- * function-like macro name, but have not yet seen its
- * closing parenthesis.
- *
- * There's perhaps a more compact way to do this with
- * mid-rule actions in the grammar.
- *
- * I'm definitely not pleased with the complexity of
- * this code here.
- */
- if (parser->newline_as_space)
- {
- if (ret == '(') {
- parser->paren_count++;
- } else if (ret == ')') {
- parser->paren_count--;
- if (parser->paren_count == 0)
- parser->newline_as_space = 0;
- } else if (ret == NEWLINE) {
- ret = SPACE;
- } else if (ret != SPACE) {
- if (parser->paren_count == 0)
- parser->newline_as_space = 0;
- }
- }
- else if (parser->in_control_line)
- {
- if (ret == NEWLINE)
- parser->in_control_line = 0;
- }
- else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC ||
- ret == HASH_UNDEF || ret == HASH_IF ||
- ret == HASH_IFDEF || ret == HASH_IFNDEF ||
- ret == HASH_ELIF || ret == HASH_ELSE ||
- ret == HASH_ENDIF || ret == HASH)
- {
- parser->in_control_line = 1;
- }
- else if (ret == IDENTIFIER)
- {
- macro_t *macro;
- macro = hash_table_find (parser->defines,
- yylval->str);
- if (macro && macro->is_function) {
- parser->newline_as_space = 1;
- parser->paren_count = 0;
- }
- }
-
- return ret;
- }
-
- node = parser->lex_from_node;
-
- if (node == NULL) {
- talloc_free (parser->lex_from_list);
- parser->lex_from_list = NULL;
- return NEWLINE;
- }
-
- *yylval = node->token->value;
- ret = node->token->type;
-
- parser->lex_from_node = node->next;
-
- return ret;
-}
-
-static void
-glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list)
-{
- token_node_t *node;
-
- assert (parser->lex_from_list == NULL);
-
- /* Copy list, eliminating any space tokens. */
- parser->lex_from_list = _token_list_create (parser);
-
- for (node = list->head; node; node = node->next) {
- if (node->token->type == SPACE)
- continue;
- _token_list_append (parser->lex_from_list, node->token);
- }
-
- talloc_free (list);
-
- parser->lex_from_node = parser->lex_from_list->head;
-
- /* It's possible the list consisted of nothing but whitespace. */
- if (parser->lex_from_node == NULL) {
- talloc_free (parser->lex_from_list);
- parser->lex_from_list = NULL;
- }
-}
-
-static void
-_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
- int condition)
-{
- skip_type_t current = SKIP_NO_SKIP;
- skip_node_t *node;
-
- if (parser->skip_stack)
- current = parser->skip_stack->type;
-
- node = talloc (parser, skip_node_t);
- node->loc = *loc;
-
- if (current == SKIP_NO_SKIP) {
- if (condition)
- node->type = SKIP_NO_SKIP;
- else
- node->type = SKIP_TO_ELSE;
- } else {
- node->type = SKIP_TO_ENDIF;
- }
-
- node->next = parser->skip_stack;
- parser->skip_stack = node;
-}
-
-static void
-_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
- const char *type, int condition)
-{
- if (parser->skip_stack == NULL) {
- glcpp_error (loc, parser, "%s without #if\n", type);
- return;
- }
-
- if (parser->skip_stack->type == SKIP_TO_ELSE) {
- if (condition)
- parser->skip_stack->type = SKIP_NO_SKIP;
- } else {
- parser->skip_stack->type = SKIP_TO_ENDIF;
- }
-}
-
-static void
-_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc)
-{
- skip_node_t *node;
-
- if (parser->skip_stack == NULL) {
- glcpp_error (loc, parser, "#endif without #if\n");
- return;
- }
-
- node = parser->skip_stack;
- parser->skip_stack = node->next;
- talloc_free (node);
-}
-
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.4.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 1
+
+
+
+/* Copy the first part of user declarations. */
+
+/* Line 189 of yacc.c */
+#line 1 "glcpp/glcpp-parse.y"
+
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include "glcpp.h"
+#include "main/core.h" /* for struct gl_extensions */
+#include "main/mtypes.h" /* for gl_api enum */
+
+static void
+yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error);
+
+static void
+_define_object_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *macro,
+ token_list_t *replacements);
+
+static void
+_define_function_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *macro,
+ string_list_t *parameters,
+ token_list_t *replacements);
+
+static string_list_t *
+_string_list_create (void *ctx);
+
+static void
+_string_list_append_item (string_list_t *list, const char *str);
+
+static int
+_string_list_contains (string_list_t *list, const char *member, int *index);
+
+static int
+_string_list_length (string_list_t *list);
+
+static int
+_string_list_equal (string_list_t *a, string_list_t *b);
+
+static argument_list_t *
+_argument_list_create (void *ctx);
+
+static void
+_argument_list_append (argument_list_t *list, token_list_t *argument);
+
+static int
+_argument_list_length (argument_list_t *list);
+
+static token_list_t *
+_argument_list_member_at (argument_list_t *list, int index);
+
+/* Note: This function ralloc_steal()s the str pointer. */
+static token_t *
+_token_create_str (void *ctx, int type, char *str);
+
+static token_t *
+_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);
+
+static void
+_token_list_append_list (token_list_t *list, token_list_t *tail);
+
+static int
+_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b);
+
+static active_list_t *
+_active_list_push (active_list_t *list,
+ const char *identifier,
+ token_node_t *marker);
+
+static active_list_t *
+_active_list_pop (active_list_t *list);
+
+int
+_active_list_contains (active_list_t *list, const char *identifier);
+
+static void
+_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list);
+
+static void
+_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
+ token_list_t *list);
+
+static void
+_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
+ token_list_t *list);
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ int condition);
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *type, int condition);
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc);
+
+#define yylex glcpp_parser_lex
+
+static int
+glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser);
+
+static void
+glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list);
+
+static void
+add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
+
+
+
+/* Line 189 of yacc.c */
+#line 217 "glcpp/glcpp-parse.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ COMMA_FINAL = 258,
+ DEFINED = 259,
+ ELIF_EXPANDED = 260,
+ HASH = 261,
+ HASH_DEFINE_FUNC = 262,
+ HASH_DEFINE_OBJ = 263,
+ HASH_ELIF = 264,
+ HASH_ELSE = 265,
+ HASH_ENDIF = 266,
+ HASH_IF = 267,
+ HASH_IFDEF = 268,
+ HASH_IFNDEF = 269,
+ HASH_UNDEF = 270,
+ HASH_VERSION = 271,
+ IDENTIFIER = 272,
+ IF_EXPANDED = 273,
+ INTEGER = 274,
+ INTEGER_STRING = 275,
+ NEWLINE = 276,
+ OTHER = 277,
+ PLACEHOLDER = 278,
+ SPACE = 279,
+ PASTE = 280,
+ OR = 281,
+ AND = 282,
+ NOT_EQUAL = 283,
+ EQUAL = 284,
+ GREATER_OR_EQUAL = 285,
+ LESS_OR_EQUAL = 286,
+ RIGHT_SHIFT = 287,
+ LEFT_SHIFT = 288,
+ UNARY = 289
+ };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 264 of yacc.c */
+#line 305 "glcpp/glcpp-parse.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+ YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 606
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 57
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 17
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 101
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 162
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 289
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 47, 2, 2, 2, 43, 30, 2,
+ 45, 46, 41, 39, 49, 40, 54, 42, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 55,
+ 33, 56, 34, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 50, 2, 51, 29, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 52, 28, 53, 48, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 31, 32, 35, 36, 37, 38, 44
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 9, 11, 13, 16, 20,
+ 24, 29, 36, 44, 48, 52, 55, 60, 65, 69,
+ 72, 75, 78, 82, 85, 87, 89, 91, 95, 99,
+ 103, 107, 111, 115, 119, 123, 127, 131, 135, 139,
+ 143, 147, 151, 155, 159, 163, 166, 169, 172, 175,
+ 179, 181, 185, 187, 190, 193, 194, 196, 197, 199,
+ 202, 207, 209, 211, 214, 216, 219, 221, 223, 225,
+ 227, 229, 231, 233, 235, 237, 239, 241, 243, 245,
+ 247, 249, 251, 253, 255, 257, 259, 261, 263, 265,
+ 267, 269, 271, 273, 275, 277, 279, 281, 283, 285,
+ 287, 289
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 58, 0, -1, -1, 58, 59, -1, 61, -1, 65,
+ -1, 60, -1, 6, 66, -1, 18, 63, 21, -1,
+ 5, 63, 21, -1, 8, 17, 67, 21, -1, 7,
+ 17, 45, 46, 67, 21, -1, 7, 17, 45, 64,
+ 46, 67, 21, -1, 15, 17, 21, -1, 12, 70,
+ 21, -1, 12, 21, -1, 13, 17, 68, 21, -1,
+ 14, 17, 68, 21, -1, 9, 70, 21, -1, 9,
+ 21, -1, 10, 21, -1, 11, 21, -1, 16, 62,
+ 21, -1, 6, 21, -1, 20, -1, 19, -1, 62,
+ -1, 63, 26, 63, -1, 63, 27, 63, -1, 63,
+ 28, 63, -1, 63, 29, 63, -1, 63, 30, 63,
+ -1, 63, 31, 63, -1, 63, 32, 63, -1, 63,
+ 35, 63, -1, 63, 36, 63, -1, 63, 34, 63,
+ -1, 63, 33, 63, -1, 63, 37, 63, -1, 63,
+ 38, 63, -1, 63, 40, 63, -1, 63, 39, 63,
+ -1, 63, 43, 63, -1, 63, 42, 63, -1, 63,
+ 41, 63, -1, 47, 63, -1, 48, 63, -1, 40,
+ 63, -1, 39, 63, -1, 45, 63, 46, -1, 17,
+ -1, 64, 49, 17, -1, 21, -1, 71, 21, -1,
+ 71, 21, -1, -1, 71, -1, -1, 71, -1, 4,
+ 17, -1, 4, 45, 17, 46, -1, 72, -1, 69,
+ -1, 70, 69, -1, 72, -1, 71, 72, -1, 17,
+ -1, 20, -1, 73, -1, 22, -1, 24, -1, 50,
+ -1, 51, -1, 45, -1, 46, -1, 52, -1, 53,
+ -1, 54, -1, 30, -1, 41, -1, 39, -1, 40,
+ -1, 48, -1, 47, -1, 42, -1, 43, -1, 38,
+ -1, 37, -1, 33, -1, 34, -1, 36, -1, 35,
+ -1, 32, -1, 31, -1, 29, -1, 28, -1, 27,
+ -1, 26, -1, 55, -1, 49, -1, 56, -1, 25,
+ -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 181, 181, 183, 187, 190, 195, 196, 200, 203,
+ 209, 212, 215, 218, 226, 245, 255, 260, 265, 284,
+ 299, 302, 305, 326, 330, 339, 344, 345, 348, 351,
+ 354, 357, 360, 363, 366, 369, 372, 375, 378, 381,
+ 384, 387, 390, 393, 401, 404, 407, 410, 413, 416,
+ 422, 427, 435, 436, 440, 446, 447, 450, 452, 459,
+ 463, 467, 472, 476, 483, 488, 495, 499, 503, 507,
+ 511, 518, 519, 520, 521, 522, 523, 524, 525, 526,
+ 527, 528, 529, 530, 531, 532, 533, 534, 535, 536,
+ 537, 538, 539, 540, 541, 542, 543, 544, 545, 546,
+ 547, 548
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "COMMA_FINAL", "DEFINED",
+ "ELIF_EXPANDED", "HASH", "HASH_DEFINE_FUNC", "HASH_DEFINE_OBJ",
+ "HASH_ELIF", "HASH_ELSE", "HASH_ENDIF", "HASH_IF", "HASH_IFDEF",
+ "HASH_IFNDEF", "HASH_UNDEF", "HASH_VERSION", "IDENTIFIER", "IF_EXPANDED",
+ "INTEGER", "INTEGER_STRING", "NEWLINE", "OTHER", "PLACEHOLDER", "SPACE",
+ "PASTE", "OR", "AND", "'|'", "'^'", "'&'", "NOT_EQUAL", "EQUAL", "'<'",
+ "'>'", "GREATER_OR_EQUAL", "LESS_OR_EQUAL", "RIGHT_SHIFT", "LEFT_SHIFT",
+ "'+'", "'-'", "'*'", "'/'", "'%'", "UNARY", "'('", "')'", "'!'", "'~'",
+ "','", "'['", "']'", "'{'", "'}'", "'.'", "';'", "'='", "$accept",
+ "input", "line", "expanded_line", "control_line", "integer_constant",
+ "expression", "identifier_list", "text_line", "non_directive",
+ "replacement_list", "junk", "conditional_token", "conditional_tokens",
+ "pp_tokens", "preprocessing_token", "operator", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 124, 94,
+ 38, 283, 284, 60, 62, 285, 286, 287, 288, 43,
+ 45, 42, 47, 37, 289, 40, 41, 33, 126, 44,
+ 91, 93, 123, 125, 46, 59, 61
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 57, 58, 58, 59, 59, 59, 59, 60, 60,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 61, 61, 61, 61, 62, 62, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 64, 64, 65, 65, 66, 67, 67, 68, 68, 69,
+ 69, 69, 70, 70, 71, 71, 72, 72, 72, 72,
+ 72, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 1, 2, 3, 3,
+ 4, 6, 7, 3, 3, 2, 4, 4, 3, 2,
+ 2, 2, 3, 2, 1, 1, 1, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 2, 2, 2, 2, 3,
+ 1, 3, 1, 2, 2, 0, 1, 0, 1, 2,
+ 4, 1, 1, 2, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 66, 0, 67, 52, 69,
+ 70, 101, 97, 96, 95, 94, 78, 93, 92, 88,
+ 89, 91, 90, 87, 86, 80, 81, 79, 84, 85,
+ 73, 74, 83, 82, 99, 71, 72, 75, 76, 77,
+ 98, 100, 3, 6, 4, 5, 0, 64, 68, 25,
+ 24, 0, 0, 0, 0, 0, 26, 0, 23, 7,
+ 0, 0, 55, 0, 19, 62, 0, 61, 20, 21,
+ 15, 0, 57, 57, 0, 0, 0, 53, 65, 48,
+ 47, 0, 45, 46, 9, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 54, 0, 0, 56, 59, 0, 18,
+ 63, 14, 0, 58, 0, 13, 22, 8, 49, 27,
+ 28, 29, 30, 31, 32, 33, 37, 36, 34, 35,
+ 38, 39, 41, 40, 44, 43, 42, 50, 55, 0,
+ 10, 0, 16, 17, 0, 55, 0, 60, 11, 0,
+ 51, 12
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 52, 53, 54, 66, 67, 149, 55, 69,
+ 115, 122, 75, 76, 116, 57, 58
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -147
+static const yytype_int16 yypact[] =
+{
+ -147, 112, -147, 28, -10, 55, 62, 152, -15, 59,
+ 192, 85, 86, 87, 51, -147, 28, -147, -147, -147,
+ -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,
+ -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,
+ -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,
+ -147, -147, -147, -147, -147, -147, 312, -147, -147, -147,
+ -147, 28, 28, 28, 28, 28, -147, 428, -147, -147,
+ 352, 63, 392, 17, -147, -147, 232, -147, -147, -147,
+ -147, 272, 392, 392, 84, 89, 451, -147, -147, -147,
+ -147, 469, -147, -147, -147, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, -147, 60, 90, 392, -147, 96, -147,
+ -147, -147, 93, 392, 94, -147, -147, -147, -147, 489,
+ 505, 520, 534, 547, 558, 558, 18, 18, 18, 18,
+ 563, 563, 23, 23, -147, -147, -147, -147, 392, 32,
+ -147, 61, -147, -147, 110, 392, 118, -147, -147, 149,
+ -147, -147
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -147, -147, -147, -147, -147, 157, -11, -147, -147, -147,
+ -146, 92, -68, 200, 0, -7, -147
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 77, 56, 154, 77, 70, 86, 78, 15, 120, 159,
+ 17, 68, 19, 120, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 117, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 59, 60, 88,
+ 89, 90, 91, 92, 93, 106, 107, 108, 109, 110,
+ 111, 112, 118, 88, 110, 111, 112, 61, 62, 77,
+ 59, 60, 71, 63, 77, 64, 65, 147, 155, 72,
+ 79, 156, 123, 123, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 82, 83, 84, 125, 148, 157, 114, 88,
+ 126, 150, 2, 151, 152, 153, 88, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 158, 17, 18, 19, 160, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 73, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
+ 161, 85, 17, 74, 19, 124, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 73, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
+ 81, 0, 17, 80, 19, 0, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 73, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
+ 0, 0, 17, 119, 19, 0, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 73, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
+ 0, 0, 17, 121, 19, 0, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 0, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
+ 0, 0, 17, 87, 19, 0, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 0, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
+ 0, 0, 17, 113, 19, 0, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 0, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 15,
+ 0, 0, 17, 0, 19, 0, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 0, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 94,
+ 0, 0, 0, 0, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 127, 0, 0, 0, 0, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 0, 0, 128, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111, 112, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 100, 101,
+ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 108, 109, 110, 111, 112
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 7, 1, 148, 10, 4, 16, 21, 17, 76, 155,
+ 20, 21, 22, 81, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 17, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 19, 20, 56,
+ 61, 62, 63, 64, 65, 37, 38, 39, 40, 41,
+ 42, 43, 45, 70, 41, 42, 43, 39, 40, 76,
+ 19, 20, 17, 45, 81, 47, 48, 17, 46, 17,
+ 21, 49, 82, 83, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 17, 17, 17, 21, 46, 46, 45, 116,
+ 21, 21, 0, 17, 21, 21, 123, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 21, 20, 21, 22, 17, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 4, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
+ 21, 14, 20, 21, 22, 83, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 4, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
+ 10, -1, 20, 21, 22, -1, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 4, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
+ -1, -1, 20, 21, 22, -1, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 4, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
+ -1, -1, 20, 21, 22, -1, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, -1, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
+ -1, -1, 20, 21, 22, -1, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, -1, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
+ -1, -1, 20, 21, 22, -1, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, -1, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 17,
+ -1, -1, 20, -1, 22, -1, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, -1, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 21,
+ -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 21, -1, -1, -1, -1, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, -1, -1, 46, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 39, 40, 41, 42, 43
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 58, 0, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 20, 21, 22,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 59, 60, 61, 65, 71, 72, 73, 19,
+ 20, 39, 40, 45, 47, 48, 62, 63, 21, 66,
+ 71, 17, 17, 4, 21, 69, 70, 72, 21, 21,
+ 21, 70, 17, 17, 17, 62, 63, 21, 72, 63,
+ 63, 63, 63, 63, 21, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 21, 45, 67, 71, 17, 45, 21,
+ 69, 21, 68, 71, 68, 21, 21, 21, 46, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 17, 46, 64,
+ 21, 17, 21, 21, 67, 46, 49, 46, 21, 67,
+ 17, 21
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (&yylloc, parser, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, parser)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, Location, parser); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, glcpp_parser_t *parser)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parser)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ YYLTYPE const * const yylocationp;
+ glcpp_parser_t *parser;
+#endif
+{
+ if (!yyvaluep)
+ return;
+ YYUSE (yylocationp);
+ YYUSE (parser);
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, glcpp_parser_t *parser)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, parser)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ YYLTYPE const * const yylocationp;
+ glcpp_parser_t *parser;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ YY_LOCATION_PRINT (yyoutput, *yylocationp);
+ YYFPRINTF (yyoutput, ": ");
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parser);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, glcpp_parser_t *parser)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, parser)
+ YYSTYPE *yyvsp;
+ YYLTYPE *yylsp;
+ int yyrule;
+ glcpp_parser_t *parser;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , &(yylsp[(yyi + 1) - (yynrhs)]) , parser);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, yylsp, Rule, parser); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, glcpp_parser_t *parser)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, parser)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ YYLTYPE *yylocationp;
+ glcpp_parser_t *parser;
+#endif
+{
+ YYUSE (yyvaluep);
+ YYUSE (yylocationp);
+ YYUSE (parser);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (glcpp_parser_t *parser);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (glcpp_parser_t *parser)
+#else
+int
+yyparse (parser)
+ glcpp_parser_t *parser;
+#endif
+#endif
+{
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Location data for the lookahead symbol. */
+YYLTYPE yylloc;
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ /* The location stack. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls;
+ YYLTYPE *yylsp;
+
+ /* The locations where the error started and ended. */
+ YYLTYPE yyerror_range[2];
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yyls = yylsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+ yylsp = yyls;
+
+#if YYLTYPE_IS_TRIVIAL
+ /* Initialize the default location before parsing starts. */
+ yylloc.first_line = yylloc.last_line = 1;
+ yylloc.first_column = yylloc.last_column = 1;
+#endif
+
+/* User initialization code. */
+
+/* Line 1242 of yacc.c */
+#line 148 "glcpp/glcpp-parse.y"
+{
+ yylloc.first_line = 1;
+ yylloc.first_column = 1;
+ yylloc.last_line = 1;
+ yylloc.last_column = 1;
+ yylloc.source = 0;
+}
+
+/* Line 1242 of yacc.c */
+#line 1610 "glcpp/glcpp-parse.c"
+ yylsp[0] = yylloc;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+ YYLTYPE *yyls1 = yyls;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yyls1, yysize * sizeof (*yylsp),
+ &yystacksize);
+
+ yyls = yyls1;
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyls_alloc, yyls);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+ yylsp = yyls + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+ *++yylsp = yylloc;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+ /* Default location. */
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+
+/* Line 1455 of yacc.c */
+#line 187 "glcpp/glcpp-parse.y"
+ {
+ ralloc_strcat (&parser->output, "\n");
+ ;}
+ break;
+
+ case 5:
+
+/* Line 1455 of yacc.c */
+#line 190 "glcpp/glcpp-parse.y"
+ {
+ _glcpp_parser_print_expanded_token_list (parser, (yyvsp[(1) - (1)].token_list));
+ ralloc_strcat (&parser->output, "\n");
+ ralloc_free ((yyvsp[(1) - (1)].token_list));
+ ;}
+ break;
+
+ case 8:
+
+/* Line 1455 of yacc.c */
+#line 200 "glcpp/glcpp-parse.y"
+ {
+ _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (3)]), (yyvsp[(2) - (3)].ival));
+ ;}
+ break;
+
+ case 9:
+
+/* Line 1455 of yacc.c */
+#line 203 "glcpp/glcpp-parse.y"
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (3)]), "elif", (yyvsp[(2) - (3)].ival));
+ ;}
+ break;
+
+ case 10:
+
+/* Line 1455 of yacc.c */
+#line 209 "glcpp/glcpp-parse.y"
+ {
+ _define_object_macro (parser, & (yylsp[(2) - (4)]), (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].token_list));
+ ;}
+ break;
+
+ case 11:
+
+/* Line 1455 of yacc.c */
+#line 212 "glcpp/glcpp-parse.y"
+ {
+ _define_function_macro (parser, & (yylsp[(2) - (6)]), (yyvsp[(2) - (6)].str), NULL, (yyvsp[(5) - (6)].token_list));
+ ;}
+ break;
+
+ case 12:
+
+/* Line 1455 of yacc.c */
+#line 215 "glcpp/glcpp-parse.y"
+ {
+ _define_function_macro (parser, & (yylsp[(2) - (7)]), (yyvsp[(2) - (7)].str), (yyvsp[(4) - (7)].string_list), (yyvsp[(6) - (7)].token_list));
+ ;}
+ break;
+
+ case 13:
+
+/* Line 1455 of yacc.c */
+#line 218 "glcpp/glcpp-parse.y"
+ {
+ macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (3)].str));
+ if (macro) {
+ hash_table_remove (parser->defines, (yyvsp[(2) - (3)].str));
+ ralloc_free (macro);
+ }
+ ralloc_free ((yyvsp[(2) - (3)].str));
+ ;}
+ break;
+
+ case 14:
+
+/* Line 1455 of yacc.c */
+#line 226 "glcpp/glcpp-parse.y"
+ {
+ /* Be careful to only evaluate the 'if' expression if
+ * we are not skipping. When we are skipping, we
+ * simply push a new 0-valued 'if' onto the skip
+ * stack.
+ *
+ * This avoids generating diagnostics for invalid
+ * expressions that are being skipped. */
+ if (parser->skip_stack == NULL ||
+ parser->skip_stack->type == SKIP_NO_SKIP)
+ {
+ _glcpp_parser_expand_if (parser, IF_EXPANDED, (yyvsp[(2) - (3)].token_list));
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (3)]), 0);
+ parser->skip_stack->type = SKIP_TO_ENDIF;
+ }
+ ;}
+ break;
+
+ case 15:
+
+/* Line 1455 of yacc.c */
+#line 245 "glcpp/glcpp-parse.y"
+ {
+ /* #if without an expression is only an error if we
+ * are not skipping */
+ if (parser->skip_stack == NULL ||
+ parser->skip_stack->type == SKIP_NO_SKIP)
+ {
+ glcpp_error(& (yylsp[(1) - (2)]), parser, "#if with no expression");
+ }
+ _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (2)]), 0);
+ ;}
+ break;
+
+ case 16:
+
+/* Line 1455 of yacc.c */
+#line 255 "glcpp/glcpp-parse.y"
+ {
+ macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (4)].str));
+ ralloc_free ((yyvsp[(2) - (4)].str));
+ _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (4)]), macro != NULL);
+ ;}
+ break;
+
+ case 17:
+
+/* Line 1455 of yacc.c */
+#line 260 "glcpp/glcpp-parse.y"
+ {
+ macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (4)].str));
+ ralloc_free ((yyvsp[(2) - (4)].str));
+ _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (4)]), macro == NULL);
+ ;}
+ break;
+
+ case 18:
+
+/* Line 1455 of yacc.c */
+#line 265 "glcpp/glcpp-parse.y"
+ {
+ /* Be careful to only evaluate the 'elif' expression
+ * if we are not skipping. When we are skipping, we
+ * simply change to a 0-valued 'elif' on the skip
+ * stack.
+ *
+ * This avoids generating diagnostics for invalid
+ * expressions that are being skipped. */
+ if (parser->skip_stack &&
+ parser->skip_stack->type == SKIP_TO_ELSE)
+ {
+ _glcpp_parser_expand_if (parser, ELIF_EXPANDED, (yyvsp[(2) - (3)].token_list));
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (3)]),
+ "elif", 0);
+ }
+ ;}
+ break;
+
+ case 19:
+
+/* Line 1455 of yacc.c */
+#line 284 "glcpp/glcpp-parse.y"
+ {
+ /* #elif without an expression is an error unless we
+ * are skipping. */
+ if (parser->skip_stack &&
+ parser->skip_stack->type == SKIP_TO_ELSE)
+ {
+ glcpp_error(& (yylsp[(1) - (2)]), parser, "#elif with no expression");
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (2)]),
+ "elif", 0);
+ glcpp_warning(& (yylsp[(1) - (2)]), parser, "ignoring illegal #elif without expression");
+ }
+ ;}
+ break;
+
+ case 20:
+
+/* Line 1455 of yacc.c */
+#line 299 "glcpp/glcpp-parse.y"
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (2)]), "else", 1);
+ ;}
+ break;
+
+ case 21:
+
+/* Line 1455 of yacc.c */
+#line 302 "glcpp/glcpp-parse.y"
+ {
+ _glcpp_parser_skip_stack_pop (parser, & (yylsp[(1) - (2)]));
+ ;}
+ break;
+
+ case 22:
+
+/* Line 1455 of yacc.c */
+#line 305 "glcpp/glcpp-parse.y"
+ {
+ macro_t *macro = hash_table_find (parser->defines, "__VERSION__");
+ if (macro) {
+ hash_table_remove (parser->defines, "__VERSION__");
+ ralloc_free (macro);
+ }
+ add_builtin_define (parser, "__VERSION__", (yyvsp[(2) - (3)].ival));
+
+ if ((yyvsp[(2) - (3)].ival) == 100)
+ add_builtin_define (parser, "GL_ES", 1);
+
+ /* Currently, all ES2 implementations support highp in the
+ * fragment shader, so we always define this macro in ES2.
+ * If we ever get a driver that doesn't support highp, we'll
+ * need to add a flag to the gl_context and check that here.
+ */
+ if ((yyvsp[(2) - (3)].ival) >= 130 || (yyvsp[(2) - (3)].ival) == 100)
+ add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ ralloc_asprintf_append (&parser->output, "#version %" PRIiMAX, (yyvsp[(2) - (3)].ival));
+ ;}
+ break;
+
+ case 24:
+
+/* Line 1455 of yacc.c */
+#line 330 "glcpp/glcpp-parse.y"
+ {
+ if (strlen ((yyvsp[(1) - (1)].str)) >= 3 && strncmp ((yyvsp[(1) - (1)].str), "0x", 2) == 0) {
+ (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str) + 2, NULL, 16);
+ } else if ((yyvsp[(1) - (1)].str)[0] == '0') {
+ (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str), NULL, 8);
+ } else {
+ (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str), NULL, 10);
+ }
+ ;}
+ break;
+
+ case 25:
+
+/* Line 1455 of yacc.c */
+#line 339 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (1)].ival);
+ ;}
+ break;
+
+ case 27:
+
+/* Line 1455 of yacc.c */
+#line 345 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) || (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 28:
+
+/* Line 1455 of yacc.c */
+#line 348 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) && (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 29:
+
+/* Line 1455 of yacc.c */
+#line 351 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) | (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 30:
+
+/* Line 1455 of yacc.c */
+#line 354 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) ^ (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 31:
+
+/* Line 1455 of yacc.c */
+#line 357 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) & (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 32:
+
+/* Line 1455 of yacc.c */
+#line 360 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) != (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 33:
+
+/* Line 1455 of yacc.c */
+#line 363 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) == (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 34:
+
+/* Line 1455 of yacc.c */
+#line 366 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) >= (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 35:
+
+/* Line 1455 of yacc.c */
+#line 369 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) <= (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 36:
+
+/* Line 1455 of yacc.c */
+#line 372 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) > (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 37:
+
+/* Line 1455 of yacc.c */
+#line 375 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) < (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 38:
+
+/* Line 1455 of yacc.c */
+#line 378 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) >> (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 39:
+
+/* Line 1455 of yacc.c */
+#line 381 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) << (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 40:
+
+/* Line 1455 of yacc.c */
+#line 384 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) - (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 41:
+
+/* Line 1455 of yacc.c */
+#line 387 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) + (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 42:
+
+/* Line 1455 of yacc.c */
+#line 390 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) % (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 43:
+
+/* Line 1455 of yacc.c */
+#line 393 "glcpp/glcpp-parse.y"
+ {
+ if ((yyvsp[(3) - (3)].ival) == 0) {
+ yyerror (& (yylsp[(1) - (3)]), parser,
+ "division by 0 in preprocessor directive");
+ } else {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) / (yyvsp[(3) - (3)].ival);
+ }
+ ;}
+ break;
+
+ case 44:
+
+/* Line 1455 of yacc.c */
+#line 401 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(1) - (3)].ival) * (yyvsp[(3) - (3)].ival);
+ ;}
+ break;
+
+ case 45:
+
+/* Line 1455 of yacc.c */
+#line 404 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = ! (yyvsp[(2) - (2)].ival);
+ ;}
+ break;
+
+ case 46:
+
+/* Line 1455 of yacc.c */
+#line 407 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = ~ (yyvsp[(2) - (2)].ival);
+ ;}
+ break;
+
+ case 47:
+
+/* Line 1455 of yacc.c */
+#line 410 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = - (yyvsp[(2) - (2)].ival);
+ ;}
+ break;
+
+ case 48:
+
+/* Line 1455 of yacc.c */
+#line 413 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = + (yyvsp[(2) - (2)].ival);
+ ;}
+ break;
+
+ case 49:
+
+/* Line 1455 of yacc.c */
+#line 416 "glcpp/glcpp-parse.y"
+ {
+ (yyval.ival) = (yyvsp[(2) - (3)].ival);
+ ;}
+ break;
+
+ case 50:
+
+/* Line 1455 of yacc.c */
+#line 422 "glcpp/glcpp-parse.y"
+ {
+ (yyval.string_list) = _string_list_create (parser);
+ _string_list_append_item ((yyval.string_list), (yyvsp[(1) - (1)].str));
+ ralloc_steal ((yyval.string_list), (yyvsp[(1) - (1)].str));
+ ;}
+ break;
+
+ case 51:
+
+/* Line 1455 of yacc.c */
+#line 427 "glcpp/glcpp-parse.y"
+ {
+ (yyval.string_list) = (yyvsp[(1) - (3)].string_list);
+ _string_list_append_item ((yyval.string_list), (yyvsp[(3) - (3)].str));
+ ralloc_steal ((yyval.string_list), (yyvsp[(3) - (3)].str));
+ ;}
+ break;
+
+ case 52:
+
+/* Line 1455 of yacc.c */
+#line 435 "glcpp/glcpp-parse.y"
+ { (yyval.token_list) = NULL; ;}
+ break;
+
+ case 54:
+
+/* Line 1455 of yacc.c */
+#line 440 "glcpp/glcpp-parse.y"
+ {
+ yyerror (& (yylsp[(1) - (2)]), parser, "Invalid tokens after #");
+ ;}
+ break;
+
+ case 55:
+
+/* Line 1455 of yacc.c */
+#line 446 "glcpp/glcpp-parse.y"
+ { (yyval.token_list) = NULL; ;}
+ break;
+
+ case 58:
+
+/* Line 1455 of yacc.c */
+#line 452 "glcpp/glcpp-parse.y"
+ {
+ glcpp_warning(&(yylsp[(1) - (1)]), parser, "extra tokens at end of directive");
+ ;}
+ break;
+
+ case 59:
+
+/* Line 1455 of yacc.c */
+#line 459 "glcpp/glcpp-parse.y"
+ {
+ int v = hash_table_find (parser->defines, (yyvsp[(2) - (2)].str)) ? 1 : 0;
+ (yyval.token) = _token_create_ival (parser, INTEGER, v);
+ ;}
+ break;
+
+ case 60:
+
+/* Line 1455 of yacc.c */
+#line 463 "glcpp/glcpp-parse.y"
+ {
+ int v = hash_table_find (parser->defines, (yyvsp[(3) - (4)].str)) ? 1 : 0;
+ (yyval.token) = _token_create_ival (parser, INTEGER, v);
+ ;}
+ break;
+
+ case 62:
+
+/* Line 1455 of yacc.c */
+#line 472 "glcpp/glcpp-parse.y"
+ {
+ (yyval.token_list) = _token_list_create (parser);
+ _token_list_append ((yyval.token_list), (yyvsp[(1) - (1)].token));
+ ;}
+ break;
+
+ case 63:
+
+/* Line 1455 of yacc.c */
+#line 476 "glcpp/glcpp-parse.y"
+ {
+ (yyval.token_list) = (yyvsp[(1) - (2)].token_list);
+ _token_list_append ((yyval.token_list), (yyvsp[(2) - (2)].token));
+ ;}
+ break;
+
+ case 64:
+
+/* Line 1455 of yacc.c */
+#line 483 "glcpp/glcpp-parse.y"
+ {
+ parser->space_tokens = 1;
+ (yyval.token_list) = _token_list_create (parser);
+ _token_list_append ((yyval.token_list), (yyvsp[(1) - (1)].token));
+ ;}
+ break;
+
+ case 65:
+
+/* Line 1455 of yacc.c */
+#line 488 "glcpp/glcpp-parse.y"
+ {
+ (yyval.token_list) = (yyvsp[(1) - (2)].token_list);
+ _token_list_append ((yyval.token_list), (yyvsp[(2) - (2)].token));
+ ;}
+ break;
+
+ case 66:
+
+/* Line 1455 of yacc.c */
+#line 495 "glcpp/glcpp-parse.y"
+ {
+ (yyval.token) = _token_create_str (parser, IDENTIFIER, (yyvsp[(1) - (1)].str));
+ (yyval.token)->location = yylloc;
+ ;}
+ break;
+
+ case 67:
+
+/* Line 1455 of yacc.c */
+#line 499 "glcpp/glcpp-parse.y"
+ {
+ (yyval.token) = _token_create_str (parser, INTEGER_STRING, (yyvsp[(1) - (1)].str));
+ (yyval.token)->location = yylloc;
+ ;}
+ break;
+
+ case 68:
+
+/* Line 1455 of yacc.c */
+#line 503 "glcpp/glcpp-parse.y"
+ {
+ (yyval.token) = _token_create_ival (parser, (yyvsp[(1) - (1)].ival), (yyvsp[(1) - (1)].ival));
+ (yyval.token)->location = yylloc;
+ ;}
+ break;
+
+ case 69:
+
+/* Line 1455 of yacc.c */
+#line 507 "glcpp/glcpp-parse.y"
+ {
+ (yyval.token) = _token_create_str (parser, OTHER, (yyvsp[(1) - (1)].str));
+ (yyval.token)->location = yylloc;
+ ;}
+ break;
+
+ case 70:
+
+/* Line 1455 of yacc.c */
+#line 511 "glcpp/glcpp-parse.y"
+ {
+ (yyval.token) = _token_create_ival (parser, SPACE, SPACE);
+ (yyval.token)->location = yylloc;
+ ;}
+ break;
+
+ case 71:
+
+/* Line 1455 of yacc.c */
+#line 518 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '['; ;}
+ break;
+
+ case 72:
+
+/* Line 1455 of yacc.c */
+#line 519 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = ']'; ;}
+ break;
+
+ case 73:
+
+/* Line 1455 of yacc.c */
+#line 520 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '('; ;}
+ break;
+
+ case 74:
+
+/* Line 1455 of yacc.c */
+#line 521 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = ')'; ;}
+ break;
+
+ case 75:
+
+/* Line 1455 of yacc.c */
+#line 522 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '{'; ;}
+ break;
+
+ case 76:
+
+/* Line 1455 of yacc.c */
+#line 523 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '}'; ;}
+ break;
+
+ case 77:
+
+/* Line 1455 of yacc.c */
+#line 524 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '.'; ;}
+ break;
+
+ case 78:
+
+/* Line 1455 of yacc.c */
+#line 525 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '&'; ;}
+ break;
+
+ case 79:
+
+/* Line 1455 of yacc.c */
+#line 526 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '*'; ;}
+ break;
+
+ case 80:
+
+/* Line 1455 of yacc.c */
+#line 527 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '+'; ;}
+ break;
+
+ case 81:
+
+/* Line 1455 of yacc.c */
+#line 528 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '-'; ;}
+ break;
+
+ case 82:
+
+/* Line 1455 of yacc.c */
+#line 529 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '~'; ;}
+ break;
+
+ case 83:
+
+/* Line 1455 of yacc.c */
+#line 530 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '!'; ;}
+ break;
+
+ case 84:
+
+/* Line 1455 of yacc.c */
+#line 531 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '/'; ;}
+ break;
+
+ case 85:
+
+/* Line 1455 of yacc.c */
+#line 532 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '%'; ;}
+ break;
+
+ case 86:
+
+/* Line 1455 of yacc.c */
+#line 533 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = LEFT_SHIFT; ;}
+ break;
+
+ case 87:
+
+/* Line 1455 of yacc.c */
+#line 534 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = RIGHT_SHIFT; ;}
+ break;
+
+ case 88:
+
+/* Line 1455 of yacc.c */
+#line 535 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '<'; ;}
+ break;
+
+ case 89:
+
+/* Line 1455 of yacc.c */
+#line 536 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '>'; ;}
+ break;
+
+ case 90:
+
+/* Line 1455 of yacc.c */
+#line 537 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = LESS_OR_EQUAL; ;}
+ break;
+
+ case 91:
+
+/* Line 1455 of yacc.c */
+#line 538 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = GREATER_OR_EQUAL; ;}
+ break;
+
+ case 92:
+
+/* Line 1455 of yacc.c */
+#line 539 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = EQUAL; ;}
+ break;
+
+ case 93:
+
+/* Line 1455 of yacc.c */
+#line 540 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = NOT_EQUAL; ;}
+ break;
+
+ case 94:
+
+/* Line 1455 of yacc.c */
+#line 541 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '^'; ;}
+ break;
+
+ case 95:
+
+/* Line 1455 of yacc.c */
+#line 542 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '|'; ;}
+ break;
+
+ case 96:
+
+/* Line 1455 of yacc.c */
+#line 543 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = AND; ;}
+ break;
+
+ case 97:
+
+/* Line 1455 of yacc.c */
+#line 544 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = OR; ;}
+ break;
+
+ case 98:
+
+/* Line 1455 of yacc.c */
+#line 545 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = ';'; ;}
+ break;
+
+ case 99:
+
+/* Line 1455 of yacc.c */
+#line 546 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = ','; ;}
+ break;
+
+ case 100:
+
+/* Line 1455 of yacc.c */
+#line 547 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = '='; ;}
+ break;
+
+ case 101:
+
+/* Line 1455 of yacc.c */
+#line 548 "glcpp/glcpp-parse.y"
+ { (yyval.ival) = PASTE; ;}
+ break;
+
+
+
+/* Line 1455 of yacc.c */
+#line 2649 "glcpp/glcpp-parse.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (&yylloc, parser, YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (&yylloc, parser, yymsg);
+ }
+ else
+ {
+ yyerror (&yylloc, parser, YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+ yyerror_range[0] = yylloc;
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, &yylloc, parser);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ yyerror_range[0] = yylsp[1-yylen];
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ yyerror_range[0] = *yylsp;
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, yylsp, parser);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+ yyerror_range[1] = yylloc;
+ /* Using YYLLOC is tempting, but would change the location of
+ the lookahead. YYLOC is available though. */
+ YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
+ *++yylsp = yyloc;
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (&yylloc, parser, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc, parser);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, yylsp, parser);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+/* Line 1675 of yacc.c */
+#line 551 "glcpp/glcpp-parse.y"
+
+
+string_list_t *
+_string_list_create (void *ctx)
+{
+ string_list_t *list;
+
+ list = ralloc (ctx, string_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+
+ return list;
+}
+
+void
+_string_list_append_item (string_list_t *list, const char *str)
+{
+ string_node_t *node;
+
+ node = ralloc (list, string_node_t);
+ node->str = ralloc_strdup (node, str);
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+}
+
+int
+_string_list_contains (string_list_t *list, const char *member, int *index)
+{
+ string_node_t *node;
+ int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0, node = list->head; node; i++, node = node->next) {
+ if (strcmp (node->str, member) == 0) {
+ if (index)
+ *index = i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+_string_list_length (string_list_t *list)
+{
+ int length = 0;
+ string_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+int
+_string_list_equal (string_list_t *a, string_list_t *b)
+{
+ string_node_t *node_a, *node_b;
+
+ if (a == NULL && b == NULL)
+ return 1;
+
+ if (a == NULL || b == NULL)
+ return 0;
+
+ for (node_a = a->head, node_b = b->head;
+ node_a && node_b;
+ node_a = node_a->next, node_b = node_b->next)
+ {
+ if (strcmp (node_a->str, node_b->str))
+ return 0;
+ }
+
+ /* Catch the case of lists being different lengths, (which
+ * would cause the loop above to terminate after the shorter
+ * list). */
+ return node_a == node_b;
+}
+
+argument_list_t *
+_argument_list_create (void *ctx)
+{
+ argument_list_t *list;
+
+ list = ralloc (ctx, argument_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+
+ return list;
+}
+
+void
+_argument_list_append (argument_list_t *list, token_list_t *argument)
+{
+ argument_node_t *node;
+
+ node = ralloc (list, argument_node_t);
+ node->argument = argument;
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+}
+
+int
+_argument_list_length (argument_list_t *list)
+{
+ int length = 0;
+ argument_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+token_list_t *
+_argument_list_member_at (argument_list_t *list, int index)
+{
+ argument_node_t *node;
+ int i;
+
+ if (list == NULL)
+ return NULL;
+
+ node = list->head;
+ for (i = 0; i < index; i++) {
+ node = node->next;
+ if (node == NULL)
+ break;
+ }
+
+ if (node)
+ return node->argument;
+
+ return NULL;
+}
+
+/* Note: This function ralloc_steal()s the str pointer. */
+token_t *
+_token_create_str (void *ctx, int type, char *str)
+{
+ token_t *token;
+
+ token = ralloc (ctx, token_t);
+ token->type = type;
+ token->value.str = str;
+
+ ralloc_steal (token, str);
+
+ return token;
+}
+
+token_t *
+_token_create_ival (void *ctx, int type, int ival)
+{
+ token_t *token;
+
+ token = ralloc (ctx, token_t);
+ token->type = type;
+ token->value.ival = ival;
+
+ return token;
+}
+
+token_list_t *
+_token_list_create (void *ctx)
+{
+ token_list_t *list;
+
+ list = ralloc (ctx, token_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+ list->non_space_tail = NULL;
+
+ return list;
+}
+
+void
+_token_list_append (token_list_t *list, token_t *token)
+{
+ token_node_t *node;
+
+ node = ralloc (list, token_node_t);
+ node->token = token;
+ node->next = NULL;
+
+ ralloc_steal (list, token);
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+ if (token->type != SPACE)
+ list->non_space_tail = node;
+}
+
+void
+_token_list_append_list (token_list_t *list, token_list_t *tail)
+{
+ if (tail == NULL || tail->head == NULL)
+ return;
+
+ if (list->head == NULL) {
+ list->head = tail->head;
+ } else {
+ list->tail->next = tail->head;
+ }
+
+ list->tail = tail->tail;
+ list->non_space_tail = tail->non_space_tail;
+}
+
+static token_list_t *
+_token_list_copy (void *ctx, token_list_t *other)
+{
+ token_list_t *copy;
+ token_node_t *node;
+
+ if (other == NULL)
+ return NULL;
+
+ copy = _token_list_create (ctx);
+ for (node = other->head; node; node = node->next) {
+ token_t *new_token = ralloc (copy, token_t);
+ *new_token = *node->token;
+ _token_list_append (copy, new_token);
+ }
+
+ return copy;
+}
+
+static void
+_token_list_trim_trailing_space (token_list_t *list)
+{
+ token_node_t *tail, *next;
+
+ if (list->non_space_tail) {
+ tail = list->non_space_tail->next;
+ list->non_space_tail->next = NULL;
+ list->tail = list->non_space_tail;
+
+ while (tail) {
+ next = tail->next;
+ ralloc_free (tail);
+ tail = next;
+ }
+ }
+}
+
+static int
+_token_list_is_empty_ignoring_space (token_list_t *l)
+{
+ token_node_t *n;
+
+ if (l == NULL)
+ return 1;
+
+ n = l->head;
+ while (n != NULL && n->token->type == SPACE)
+ n = n->next;
+
+ return n == NULL;
+}
+
+int
+_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
+{
+ token_node_t *node_a, *node_b;
+
+ if (a == NULL || b == NULL) {
+ int a_empty = _token_list_is_empty_ignoring_space(a);
+ int b_empty = _token_list_is_empty_ignoring_space(b);
+ return a_empty == b_empty;
+ }
+
+ node_a = a->head;
+ node_b = b->head;
+
+ while (1)
+ {
+ if (node_a == NULL && node_b == NULL)
+ break;
+
+ if (node_a == NULL || node_b == NULL)
+ return 0;
+
+ if (node_a->token->type == SPACE) {
+ node_a = node_a->next;
+ continue;
+ }
+
+ if (node_b->token->type == SPACE) {
+ node_b = node_b->next;
+ continue;
+ }
+
+ if (node_a->token->type != node_b->token->type)
+ return 0;
+
+ switch (node_a->token->type) {
+ case INTEGER:
+ if (node_a->token->value.ival !=
+ node_b->token->value.ival)
+ {
+ return 0;
+ }
+ break;
+ case IDENTIFIER:
+ case INTEGER_STRING:
+ case OTHER:
+ if (strcmp (node_a->token->value.str,
+ node_b->token->value.str))
+ {
+ return 0;
+ }
+ break;
+ }
+
+ node_a = node_a->next;
+ node_b = node_b->next;
+ }
+
+ return 1;
+}
+
+static void
+_token_print (char **out, token_t *token)
+{
+ if (token->type < 256) {
+ ralloc_asprintf_append (out, "%c", token->type);
+ return;
+ }
+
+ switch (token->type) {
+ case INTEGER:
+ ralloc_asprintf_append (out, "%" PRIiMAX, token->value.ival);
+ break;
+ case IDENTIFIER:
+ case INTEGER_STRING:
+ case OTHER:
+ ralloc_strcat (out, token->value.str);
+ break;
+ case SPACE:
+ ralloc_strcat (out, " ");
+ break;
+ case LEFT_SHIFT:
+ ralloc_strcat (out, "<<");
+ break;
+ case RIGHT_SHIFT:
+ ralloc_strcat (out, ">>");
+ break;
+ case LESS_OR_EQUAL:
+ ralloc_strcat (out, "<=");
+ break;
+ case GREATER_OR_EQUAL:
+ ralloc_strcat (out, ">=");
+ break;
+ case EQUAL:
+ ralloc_strcat (out, "==");
+ break;
+ case NOT_EQUAL:
+ ralloc_strcat (out, "!=");
+ break;
+ case AND:
+ ralloc_strcat (out, "&&");
+ break;
+ case OR:
+ ralloc_strcat (out, "||");
+ break;
+ case PASTE:
+ ralloc_strcat (out, "##");
+ break;
+ case COMMA_FINAL:
+ ralloc_strcat (out, ",");
+ break;
+ case PLACEHOLDER:
+ /* Nothing to print. */
+ break;
+ default:
+ assert(!"Error: Don't know how to print token.");
+ break;
+ }
+}
+
+/* Return a new token (ralloc()ed off of 'token') formed by pasting
+ * 'token' and 'other'. Note that this function may return 'token' or
+ * 'other' directly rather than allocating anything new.
+ *
+ * Caution: Only very cursory error-checking is performed to see if
+ * the final result is a valid single token. */
+static token_t *
+_token_paste (glcpp_parser_t *parser, token_t *token, token_t *other)
+{
+ token_t *combined = NULL;
+
+ /* Pasting a placeholder onto anything makes no change. */
+ if (other->type == PLACEHOLDER)
+ return token;
+
+ /* When 'token' is a placeholder, just return 'other'. */
+ if (token->type == PLACEHOLDER)
+ return other;
+
+ /* A very few single-character punctuators can be combined
+ * with another to form a multi-character punctuator. */
+ switch (token->type) {
+ case '<':
+ if (other->type == '<')
+ combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT);
+ else if (other->type == '=')
+ combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL);
+ break;
+ case '>':
+ if (other->type == '>')
+ combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT);
+ else if (other->type == '=')
+ combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL);
+ break;
+ case '=':
+ if (other->type == '=')
+ combined = _token_create_ival (token, EQUAL, EQUAL);
+ break;
+ case '!':
+ if (other->type == '=')
+ combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL);
+ break;
+ case '&':
+ if (other->type == '&')
+ combined = _token_create_ival (token, AND, AND);
+ break;
+ case '|':
+ if (other->type == '|')
+ combined = _token_create_ival (token, OR, OR);
+ break;
+ }
+
+ if (combined != NULL) {
+ /* Inherit the location from the first token */
+ combined->location = token->location;
+ return combined;
+ }
+
+ /* Two string-valued tokens can usually just be mashed
+ * together.
+ *
+ * XXX: This isn't actually legitimate. Several things here
+ * should result in a diagnostic since the result cannot be a
+ * valid, single pre-processing token. For example, pasting
+ * "123" and "abc" is not legal, but we don't catch that
+ * here. */
+ if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) &&
+ (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING))
+ {
+ char *str;
+
+ str = ralloc_asprintf (token, "%s%s", token->value.str,
+ other->value.str);
+ combined = _token_create_str (token, token->type, str);
+ combined->location = token->location;
+ return combined;
+ }
+
+ glcpp_error (&token->location, parser, "");
+ ralloc_strcat (&parser->info_log, "Pasting \"");
+ _token_print (&parser->info_log, token);
+ ralloc_strcat (&parser->info_log, "\" and \"");
+ _token_print (&parser->info_log, other);
+ ralloc_strcat (&parser->info_log, "\" does not give a valid preprocessing token.\n");
+
+ return token;
+}
+
+static void
+_token_list_print (glcpp_parser_t *parser, token_list_t *list)
+{
+ token_node_t *node;
+
+ if (list == NULL)
+ return;
+
+ for (node = list->head; node; node = node->next)
+ _token_print (&parser->output, node->token);
+}
+
+void
+yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error)
+{
+ glcpp_error(locp, parser, "%s", error);
+}
+
+static void add_builtin_define(glcpp_parser_t *parser,
+ const char *name, int value)
+{
+ token_t *tok;
+ token_list_t *list;
+
+ tok = _token_create_ival (parser, INTEGER, value);
+
+ list = _token_list_create(parser);
+ _token_list_append(list, tok);
+ _define_object_macro(parser, NULL, name, list);
+}
+
+glcpp_parser_t *
+glcpp_parser_create (const struct gl_extensions *extensions, int api)
+{
+ glcpp_parser_t *parser;
+ int language_version;
+
+ parser = ralloc (NULL, glcpp_parser_t);
+
+ glcpp_lex_init_extra (parser, &parser->scanner);
+ parser->defines = hash_table_ctor (32, hash_table_string_hash,
+ hash_table_string_compare);
+ parser->active = NULL;
+ parser->lexing_if = 0;
+ parser->space_tokens = 1;
+ parser->newline_as_space = 0;
+ parser->in_control_line = 0;
+ parser->paren_count = 0;
+
+ parser->skip_stack = NULL;
+
+ parser->lex_from_list = NULL;
+ parser->lex_from_node = NULL;
+
+ parser->output = ralloc_strdup(parser, "");
+ parser->info_log = ralloc_strdup(parser, "");
+ parser->error = 0;
+
+ /* Add pre-defined macros. */
+ add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
+ add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
+
+ if (api == API_OPENGLES2)
+ add_builtin_define(parser, "GL_ES", 1);
+
+ if (extensions != NULL) {
+ if (extensions->EXT_texture_array) {
+ add_builtin_define(parser, "GL_EXT_texture_array", 1);
+ }
+
+ if (extensions->ARB_fragment_coord_conventions)
+ add_builtin_define(parser, "GL_ARB_fragment_coord_conventions",
+ 1);
+
+ if (extensions->ARB_explicit_attrib_location)
+ add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1);
+ if (extensions->AMD_conservative_depth)
+ add_builtin_define(parser, "GL_AMD_conservative_depth", 1);
+ }
+
+ language_version = 110;
+ add_builtin_define(parser, "__VERSION__", language_version);
+
+ return parser;
+}
+
+int
+glcpp_parser_parse (glcpp_parser_t *parser)
+{
+ return yyparse (parser);
+}
+
+void
+glcpp_parser_destroy (glcpp_parser_t *parser)
+{
+ glcpp_lex_destroy (parser->scanner);
+ hash_table_dtor (parser->defines);
+ ralloc_free (parser);
+}
+
+typedef enum function_status
+{
+ FUNCTION_STATUS_SUCCESS,
+ FUNCTION_NOT_A_FUNCTION,
+ FUNCTION_UNBALANCED_PARENTHESES
+} function_status_t;
+
+/* Find a set of function-like macro arguments by looking for a
+ * balanced set of parentheses.
+ *
+ * When called, 'node' should be the opening-parenthesis token, (or
+ * perhaps preceeding SPACE tokens). Upon successful return *last will
+ * be the last consumed node, (corresponding to the closing right
+ * parenthesis).
+ *
+ * Return values:
+ *
+ * FUNCTION_STATUS_SUCCESS:
+ *
+ * Successfully parsed a set of function arguments.
+ *
+ * FUNCTION_NOT_A_FUNCTION:
+ *
+ * Macro name not followed by a '('. This is not an error, but
+ * simply that the macro name should be treated as a non-macro.
+ *
+ * FUNCTION_UNBALANCED_PARENTHESES
+ *
+ * Macro name is not followed by a balanced set of parentheses.
+ */
+static function_status_t
+_arguments_parse (argument_list_t *arguments,
+ token_node_t *node,
+ token_node_t **last)
+{
+ token_list_t *argument;
+ int paren_count;
+
+ node = node->next;
+
+ /* Ignore whitespace before first parenthesis. */
+ while (node && node->token->type == SPACE)
+ node = node->next;
+
+ if (node == NULL || node->token->type != '(')
+ return FUNCTION_NOT_A_FUNCTION;
+
+ node = node->next;
+
+ argument = _token_list_create (arguments);
+ _argument_list_append (arguments, argument);
+
+ for (paren_count = 1; node; node = node->next) {
+ if (node->token->type == '(')
+ {
+ paren_count++;
+ }
+ else if (node->token->type == ')')
+ {
+ paren_count--;
+ if (paren_count == 0)
+ break;
+ }
+
+ if (node->token->type == ',' &&
+ paren_count == 1)
+ {
+ _token_list_trim_trailing_space (argument);
+ argument = _token_list_create (arguments);
+ _argument_list_append (arguments, argument);
+ }
+ else {
+ if (argument->head == NULL) {
+ /* Don't treat initial whitespace as
+ * part of the arguement. */
+ if (node->token->type == SPACE)
+ continue;
+ }
+ _token_list_append (argument, node->token);
+ }
+ }
+
+ if (paren_count)
+ return FUNCTION_UNBALANCED_PARENTHESES;
+
+ *last = node;
+
+ return FUNCTION_STATUS_SUCCESS;
+}
+
+static token_list_t *
+_token_list_create_with_one_space (void *ctx)
+{
+ token_list_t *list;
+ token_t *space;
+
+ list = _token_list_create (ctx);
+ space = _token_create_ival (list, SPACE, SPACE);
+ _token_list_append (list, space);
+
+ return list;
+}
+
+static void
+_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list)
+{
+ token_list_t *expanded;
+ token_t *token;
+
+ expanded = _token_list_create (parser);
+ token = _token_create_ival (parser, type, type);
+ _token_list_append (expanded, token);
+ _glcpp_parser_expand_token_list (parser, list);
+ _token_list_append_list (expanded, list);
+ glcpp_parser_lex_from (parser, expanded);
+}
+
+/* This is a helper function that's essentially part of the
+ * implementation of _glcpp_parser_expand_node. It shouldn't be called
+ * except for by that function.
+ *
+ * Returns NULL if node is a simple token with no expansion, (that is,
+ * although 'node' corresponds to an identifier defined as a
+ * function-like macro, it is not followed with a parenthesized
+ * argument list).
+ *
+ * Compute the complete expansion of node (which is a function-like
+ * macro) and subsequent nodes which are arguments.
+ *
+ * Returns the token list that results from the expansion and sets
+ * *last to the last node in the list that was consumed by the
+ * expansion. Specifically, *last will be set as follows: as the
+ * token of the closing right parenthesis.
+ */
+static token_list_t *
+_glcpp_parser_expand_function (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last)
+
+{
+ macro_t *macro;
+ const char *identifier;
+ argument_list_t *arguments;
+ function_status_t status;
+ token_list_t *substituted;
+ int parameter_index;
+
+ identifier = node->token->value.str;
+
+ macro = hash_table_find (parser->defines, identifier);
+
+ assert (macro->is_function);
+
+ arguments = _argument_list_create (parser);
+ status = _arguments_parse (arguments, node, last);
+
+ switch (status) {
+ case FUNCTION_STATUS_SUCCESS:
+ break;
+ case FUNCTION_NOT_A_FUNCTION:
+ return NULL;
+ case FUNCTION_UNBALANCED_PARENTHESES:
+ glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier);
+ return NULL;
+ }
+
+ /* Replace a macro defined as empty with a SPACE token. */
+ if (macro->replacements == NULL) {
+ ralloc_free (arguments);
+ return _token_list_create_with_one_space (parser);
+ }
+
+ if (! ((_argument_list_length (arguments) ==
+ _string_list_length (macro->parameters)) ||
+ (_string_list_length (macro->parameters) == 0 &&
+ _argument_list_length (arguments) == 1 &&
+ arguments->head->argument->head == NULL)))
+ {
+ glcpp_error (&node->token->location, parser,
+ "Error: macro %s invoked with %d arguments (expected %d)\n",
+ identifier,
+ _argument_list_length (arguments),
+ _string_list_length (macro->parameters));
+ return NULL;
+ }
+
+ /* Perform argument substitution on the replacement list. */
+ substituted = _token_list_create (arguments);
+
+ for (node = macro->replacements->head; node; node = node->next)
+ {
+ if (node->token->type == IDENTIFIER &&
+ _string_list_contains (macro->parameters,
+ node->token->value.str,
+ &parameter_index))
+ {
+ token_list_t *argument;
+ argument = _argument_list_member_at (arguments,
+ parameter_index);
+ /* Before substituting, we expand the argument
+ * tokens, or append a placeholder token for
+ * an empty argument. */
+ if (argument->head) {
+ token_list_t *expanded_argument;
+ expanded_argument = _token_list_copy (parser,
+ argument);
+ _glcpp_parser_expand_token_list (parser,
+ expanded_argument);
+ _token_list_append_list (substituted,
+ expanded_argument);
+ } else {
+ token_t *new_token;
+
+ new_token = _token_create_ival (substituted,
+ PLACEHOLDER,
+ PLACEHOLDER);
+ _token_list_append (substituted, new_token);
+ }
+ } else {
+ _token_list_append (substituted, node->token);
+ }
+ }
+
+ /* After argument substitution, and before further expansion
+ * below, implement token pasting. */
+
+ _token_list_trim_trailing_space (substituted);
+
+ node = substituted->head;
+ while (node)
+ {
+ token_node_t *next_non_space;
+
+ /* Look ahead for a PASTE token, skipping space. */
+ next_non_space = node->next;
+ while (next_non_space && next_non_space->token->type == SPACE)
+ next_non_space = next_non_space->next;
+
+ if (next_non_space == NULL)
+ break;
+
+ if (next_non_space->token->type != PASTE) {
+ node = next_non_space;
+ continue;
+ }
+
+ /* Now find the next non-space token after the PASTE. */
+ next_non_space = next_non_space->next;
+ while (next_non_space && next_non_space->token->type == SPACE)
+ next_non_space = next_non_space->next;
+
+ if (next_non_space == NULL) {
+ yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n");
+ return NULL;
+ }
+
+ node->token = _token_paste (parser, node->token, next_non_space->token);
+ node->next = next_non_space->next;
+ if (next_non_space == substituted->tail)
+ substituted->tail = node;
+
+ node = node->next;
+ }
+
+ substituted->non_space_tail = substituted->tail;
+
+ return substituted;
+}
+
+/* Compute the complete expansion of node, (and subsequent nodes after
+ * 'node' in the case that 'node' is a function-like macro and
+ * subsequent nodes are arguments).
+ *
+ * Returns NULL if node is a simple token with no expansion.
+ *
+ * Otherwise, returns the token list that results from the expansion
+ * and sets *last to the last node in the list that was consumed by
+ * the expansion. Specifically, *last will be set as follows:
+ *
+ * As 'node' in the case of object-like macro expansion.
+ *
+ * As the token of the closing right parenthesis in the case of
+ * function-like macro expansion.
+ */
+static token_list_t *
+_glcpp_parser_expand_node (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last)
+{
+ token_t *token = node->token;
+ const char *identifier;
+ macro_t *macro;
+
+ /* We only expand identifiers */
+ if (token->type != IDENTIFIER) {
+ /* We change any COMMA into a COMMA_FINAL to prevent
+ * it being mistaken for an argument separator
+ * later. */
+ if (token->type == ',') {
+ token->type = COMMA_FINAL;
+ token->value.ival = COMMA_FINAL;
+ }
+
+ return NULL;
+ }
+
+ /* Look up this identifier in the hash table. */
+ identifier = token->value.str;
+ macro = hash_table_find (parser->defines, identifier);
+
+ /* Not a macro, so no expansion needed. */
+ if (macro == NULL)
+ return NULL;
+
+ /* Finally, don't expand this macro if we're already actively
+ * expanding it, (to avoid infinite recursion). */
+ if (_active_list_contains (parser->active, identifier)) {
+ /* We change the token type here from IDENTIFIER to
+ * OTHER to prevent any future expansion of this
+ * unexpanded token. */
+ char *str;
+ token_list_t *expansion;
+ token_t *final;
+
+ str = ralloc_strdup (parser, token->value.str);
+ final = _token_create_str (parser, OTHER, str);
+ expansion = _token_list_create (parser);
+ _token_list_append (expansion, final);
+ *last = node;
+ return expansion;
+ }
+
+ if (! macro->is_function)
+ {
+ *last = node;
+
+ /* Replace a macro defined as empty with a SPACE token. */
+ if (macro->replacements == NULL)
+ return _token_list_create_with_one_space (parser);
+
+ return _token_list_copy (parser, macro->replacements);
+ }
+
+ return _glcpp_parser_expand_function (parser, node, last);
+}
+
+/* Push a new identifier onto the active list, returning the new list.
+ *
+ * Here, 'marker' is the token node that appears in the list after the
+ * expansion of 'identifier'. That is, when the list iterator begins
+ * examinging 'marker', then it is time to pop this node from the
+ * active stack.
+ */
+active_list_t *
+_active_list_push (active_list_t *list,
+ const char *identifier,
+ token_node_t *marker)
+{
+ active_list_t *node;
+
+ node = ralloc (list, active_list_t);
+ node->identifier = ralloc_strdup (node, identifier);
+ node->marker = marker;
+ node->next = list;
+
+ return node;
+}
+
+active_list_t *
+_active_list_pop (active_list_t *list)
+{
+ active_list_t *node = list;
+
+ if (node == NULL)
+ return NULL;
+
+ node = list->next;
+ ralloc_free (list);
+
+ return node;
+}
+
+int
+_active_list_contains (active_list_t *list, const char *identifier)
+{
+ active_list_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list; node; node = node->next)
+ if (strcmp (node->identifier, identifier) == 0)
+ return 1;
+
+ return 0;
+}
+
+/* Walk over the token list replacing nodes with their expansion.
+ * Whenever nodes are expanded the walking will walk over the new
+ * nodes, continuing to expand as necessary. The results are placed in
+ * 'list' itself;
+ */
+static void
+_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ token_node_t *node_prev;
+ token_node_t *node, *last = NULL;
+ token_list_t *expansion;
+
+ if (list == NULL)
+ return;
+
+ _token_list_trim_trailing_space (list);
+
+ node_prev = NULL;
+ node = list->head;
+
+ while (node) {
+
+ while (parser->active && parser->active->marker == node)
+ parser->active = _active_list_pop (parser->active);
+
+ /* Find the expansion for node, which will replace all
+ * nodes from node to last, inclusive. */
+ expansion = _glcpp_parser_expand_node (parser, node, &last);
+ if (expansion) {
+ token_node_t *n;
+
+ for (n = node; n != last->next; n = n->next)
+ while (parser->active &&
+ parser->active->marker == n)
+ {
+ parser->active = _active_list_pop (parser->active);
+ }
+
+ parser->active = _active_list_push (parser->active,
+ node->token->value.str,
+ last->next);
+
+ /* Splice expansion into list, supporting a
+ * simple deletion if the expansion is
+ * empty. */
+ if (expansion->head) {
+ if (node_prev)
+ node_prev->next = expansion->head;
+ else
+ list->head = expansion->head;
+ expansion->tail->next = last->next;
+ if (last == list->tail)
+ list->tail = expansion->tail;
+ } else {
+ if (node_prev)
+ node_prev->next = last->next;
+ else
+ list->head = last->next;
+ if (last == list->tail)
+ list->tail = NULL;
+ }
+ } else {
+ node_prev = node;
+ }
+ node = node_prev ? node_prev->next : list->head;
+ }
+
+ while (parser->active)
+ parser->active = _active_list_pop (parser->active);
+
+ list->non_space_tail = list->tail;
+}
+
+void
+_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ if (list == NULL)
+ return;
+
+ _glcpp_parser_expand_token_list (parser, list);
+
+ _token_list_trim_trailing_space (list);
+
+ _token_list_print (parser, list);
+}
+
+static void
+_check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *identifier)
+{
+ /* According to the GLSL specification, macro names starting with "__"
+ * or "GL_" are reserved for future use. So, don't allow them.
+ */
+ if (strncmp(identifier, "__", 2) == 0) {
+ glcpp_error (loc, parser, "Macro names starting with \"__\" are reserved.\n");
+ }
+ if (strncmp(identifier, "GL_", 3) == 0) {
+ glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n");
+ }
+}
+
+static int
+_macro_equal (macro_t *a, macro_t *b)
+{
+ if (a->is_function != b->is_function)
+ return 0;
+
+ if (a->is_function) {
+ if (! _string_list_equal (a->parameters, b->parameters))
+ return 0;
+ }
+
+ return _token_list_equal_ignoring_space (a->replacements,
+ b->replacements);
+}
+
+void
+_define_object_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *identifier,
+ token_list_t *replacements)
+{
+ macro_t *macro, *previous;
+
+ if (loc != NULL)
+ _check_for_reserved_macro_name(parser, loc, identifier);
+
+ macro = ralloc (parser, macro_t);
+
+ macro->is_function = 0;
+ macro->parameters = NULL;
+ macro->identifier = ralloc_strdup (macro, identifier);
+ macro->replacements = replacements;
+ ralloc_steal (macro, replacements);
+
+ previous = hash_table_find (parser->defines, identifier);
+ if (previous) {
+ if (_macro_equal (macro, previous)) {
+ ralloc_free (macro);
+ return;
+ }
+ glcpp_error (loc, parser, "Redefinition of macro %s\n",
+ identifier);
+ }
+
+ hash_table_insert (parser->defines, macro, identifier);
+}
+
+void
+_define_function_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *identifier,
+ string_list_t *parameters,
+ token_list_t *replacements)
+{
+ macro_t *macro, *previous;
+
+ _check_for_reserved_macro_name(parser, loc, identifier);
+
+ macro = ralloc (parser, macro_t);
+ ralloc_steal (macro, parameters);
+ ralloc_steal (macro, replacements);
+
+ macro->is_function = 1;
+ macro->parameters = parameters;
+ macro->identifier = ralloc_strdup (macro, identifier);
+ macro->replacements = replacements;
+ previous = hash_table_find (parser->defines, identifier);
+ if (previous) {
+ if (_macro_equal (macro, previous)) {
+ ralloc_free (macro);
+ return;
+ }
+ glcpp_error (loc, parser, "Redefinition of macro %s\n",
+ identifier);
+ }
+
+ hash_table_insert (parser->defines, macro, identifier);
+}
+
+static int
+glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser)
+{
+ token_node_t *node;
+ int ret;
+
+ if (parser->lex_from_list == NULL) {
+ ret = glcpp_lex (yylval, yylloc, parser->scanner);
+
+ /* XXX: This ugly block of code exists for the sole
+ * purpose of converting a NEWLINE token into a SPACE
+ * token, but only in the case where we have seen a
+ * function-like macro name, but have not yet seen its
+ * closing parenthesis.
+ *
+ * There's perhaps a more compact way to do this with
+ * mid-rule actions in the grammar.
+ *
+ * I'm definitely not pleased with the complexity of
+ * this code here.
+ */
+ if (parser->newline_as_space)
+ {
+ if (ret == '(') {
+ parser->paren_count++;
+ } else if (ret == ')') {
+ parser->paren_count--;
+ if (parser->paren_count == 0)
+ parser->newline_as_space = 0;
+ } else if (ret == NEWLINE) {
+ ret = SPACE;
+ } else if (ret != SPACE) {
+ if (parser->paren_count == 0)
+ parser->newline_as_space = 0;
+ }
+ }
+ else if (parser->in_control_line)
+ {
+ if (ret == NEWLINE)
+ parser->in_control_line = 0;
+ }
+ else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC ||
+ ret == HASH_UNDEF || ret == HASH_IF ||
+ ret == HASH_IFDEF || ret == HASH_IFNDEF ||
+ ret == HASH_ELIF || ret == HASH_ELSE ||
+ ret == HASH_ENDIF || ret == HASH)
+ {
+ parser->in_control_line = 1;
+ }
+ else if (ret == IDENTIFIER)
+ {
+ macro_t *macro;
+ macro = hash_table_find (parser->defines,
+ yylval->str);
+ if (macro && macro->is_function) {
+ parser->newline_as_space = 1;
+ parser->paren_count = 0;
+ }
+ }
+
+ return ret;
+ }
+
+ node = parser->lex_from_node;
+
+ if (node == NULL) {
+ ralloc_free (parser->lex_from_list);
+ parser->lex_from_list = NULL;
+ return NEWLINE;
+ }
+
+ *yylval = node->token->value;
+ ret = node->token->type;
+
+ parser->lex_from_node = node->next;
+
+ return ret;
+}
+
+static void
+glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list)
+{
+ token_node_t *node;
+
+ assert (parser->lex_from_list == NULL);
+
+ /* Copy list, eliminating any space tokens. */
+ parser->lex_from_list = _token_list_create (parser);
+
+ for (node = list->head; node; node = node->next) {
+ if (node->token->type == SPACE)
+ continue;
+ _token_list_append (parser->lex_from_list, node->token);
+ }
+
+ ralloc_free (list);
+
+ parser->lex_from_node = parser->lex_from_list->head;
+
+ /* It's possible the list consisted of nothing but whitespace. */
+ if (parser->lex_from_node == NULL) {
+ ralloc_free (parser->lex_from_list);
+ parser->lex_from_list = NULL;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ int condition)
+{
+ skip_type_t current = SKIP_NO_SKIP;
+ skip_node_t *node;
+
+ if (parser->skip_stack)
+ current = parser->skip_stack->type;
+
+ node = ralloc (parser, skip_node_t);
+ node->loc = *loc;
+
+ if (current == SKIP_NO_SKIP) {
+ if (condition)
+ node->type = SKIP_NO_SKIP;
+ else
+ node->type = SKIP_TO_ELSE;
+ } else {
+ node->type = SKIP_TO_ENDIF;
+ }
+
+ node->next = parser->skip_stack;
+ parser->skip_stack = node;
+}
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *type, int condition)
+{
+ if (parser->skip_stack == NULL) {
+ glcpp_error (loc, parser, "%s without #if\n", type);
+ return;
+ }
+
+ if (parser->skip_stack->type == SKIP_TO_ELSE) {
+ if (condition)
+ parser->skip_stack->type = SKIP_NO_SKIP;
+ } else {
+ parser->skip_stack->type = SKIP_TO_ENDIF;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc)
+{
+ skip_node_t *node;
+
+ if (parser->skip_stack == NULL) {
+ glcpp_error (loc, parser, "#endif without #if\n");
+ return;
+ }
+
+ node = parser->skip_stack;
+ parser->skip_stack = node->next;
+ ralloc_free (node);
+}
+
diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.h b/mesalib/src/glsl/glcpp/glcpp-parse.h
index 40556854f..50758930e 100644
--- a/mesalib/src/glsl/glcpp/glcpp-parse.h
+++ b/mesalib/src/glsl/glcpp/glcpp-parse.h
@@ -1,9 +1,10 @@
-/* A Bison parser, made by GNU Bison 2.4.3. */
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
/* Skeleton interface for Bison's Yacc-like parsers in C
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y
index 7976101bc..aa5a0c4f2 100644
--- a/mesalib/src/glsl/glcpp/glcpp-parse.y
+++ b/mesalib/src/glsl/glcpp/glcpp-parse.y
@@ -1,1890 +1,1891 @@
-%{
-/*
- * 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 <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <inttypes.h>
-
-#include "glcpp.h"
-#include "main/core.h" /* for struct gl_extensions */
-#include "main/mtypes.h" /* for gl_api enum */
-
-#define glcpp_print(stream, str) stream = talloc_strdup_append(stream, str)
-#define glcpp_printf(stream, fmt, args, ...) \
- stream = talloc_asprintf_append(stream, fmt, args)
-
-static void
-yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error);
-
-static void
-_define_object_macro (glcpp_parser_t *parser,
- YYLTYPE *loc,
- const char *macro,
- token_list_t *replacements);
-
-static void
-_define_function_macro (glcpp_parser_t *parser,
- YYLTYPE *loc,
- const char *macro,
- string_list_t *parameters,
- token_list_t *replacements);
-
-static string_list_t *
-_string_list_create (void *ctx);
-
-static void
-_string_list_append_item (string_list_t *list, const char *str);
-
-static int
-_string_list_contains (string_list_t *list, const char *member, int *index);
-
-static int
-_string_list_length (string_list_t *list);
-
-static int
-_string_list_equal (string_list_t *a, string_list_t *b);
-
-static argument_list_t *
-_argument_list_create (void *ctx);
-
-static void
-_argument_list_append (argument_list_t *list, token_list_t *argument);
-
-static int
-_argument_list_length (argument_list_t *list);
-
-static token_list_t *
-_argument_list_member_at (argument_list_t *list, int index);
-
-/* Note: This function talloc_steal()s the str pointer. */
-static token_t *
-_token_create_str (void *ctx, int type, char *str);
-
-static token_t *
-_token_create_ival (void *ctx, int type, int ival);
-
-static token_list_t *
-_token_list_create (void *ctx);
-
-/* Note: This function calls talloc_steal on token. */
-static void
-_token_list_append (token_list_t *list, token_t *token);
-
-static void
-_token_list_append_list (token_list_t *list, token_list_t *tail);
-
-static int
-_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b);
-
-static active_list_t *
-_active_list_push (active_list_t *list,
- const char *identifier,
- token_node_t *marker);
-
-static active_list_t *
-_active_list_pop (active_list_t *list);
-
-int
-_active_list_contains (active_list_t *list, const char *identifier);
-
-static void
-_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list);
-
-static void
-_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
- token_list_t *list);
-
-static void
-_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
- token_list_t *list);
-
-static void
-_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
- int condition);
-
-static void
-_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
- const char *type, int condition);
-
-static void
-_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc);
-
-#define yylex glcpp_parser_lex
-
-static int
-glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser);
-
-static void
-glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list);
-
-static void
-add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
-
-%}
-
-%pure-parser
-%error-verbose
-
-%locations
-%initial-action {
- @$.first_line = 1;
- @$.first_column = 1;
- @$.last_line = 1;
- @$.last_column = 1;
- @$.source = 0;
-}
-
-%parse-param {glcpp_parser_t *parser}
-%lex-param {glcpp_parser_t *parser}
-
-%expect 0
-%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING NEWLINE OTHER PLACEHOLDER SPACE
-%token PASTE
-%type <ival> expression INTEGER operator SPACE integer_constant
-%type <str> IDENTIFIER INTEGER_STRING OTHER
-%type <string_list> identifier_list
-%type <token> preprocessing_token conditional_token
-%type <token_list> pp_tokens replacement_list text_line conditional_tokens
-%left OR
-%left AND
-%left '|'
-%left '^'
-%left '&'
-%left EQUAL NOT_EQUAL
-%left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL
-%left LEFT_SHIFT RIGHT_SHIFT
-%left '+' '-'
-%left '*' '/' '%'
-%right UNARY
-
-%%
-
-input:
- /* empty */
-| input line
-;
-
-line:
- control_line {
- glcpp_print(parser->output, "\n");
- }
-| text_line {
- _glcpp_parser_print_expanded_token_list (parser, $1);
- glcpp_print(parser->output, "\n");
- talloc_free ($1);
- }
-| expanded_line
-| HASH non_directive
-;
-
-expanded_line:
- IF_EXPANDED expression NEWLINE {
- _glcpp_parser_skip_stack_push_if (parser, & @1, $2);
- }
-| ELIF_EXPANDED expression NEWLINE {
- _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2);
- }
-;
-
-control_line:
- HASH_DEFINE_OBJ IDENTIFIER replacement_list NEWLINE {
- _define_object_macro (parser, & @2, $2, $3);
- }
-| HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE {
- _define_function_macro (parser, & @2, $2, NULL, $5);
- }
-| HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE {
- _define_function_macro (parser, & @2, $2, $4, $6);
- }
-| HASH_UNDEF IDENTIFIER NEWLINE {
- macro_t *macro = hash_table_find (parser->defines, $2);
- if (macro) {
- hash_table_remove (parser->defines, $2);
- talloc_free (macro);
- }
- talloc_free ($2);
- }
-| HASH_IF conditional_tokens NEWLINE {
- /* Be careful to only evaluate the 'if' expression if
- * we are not skipping. When we are skipping, we
- * simply push a new 0-valued 'if' onto the skip
- * stack.
- *
- * This avoids generating diagnostics for invalid
- * expressions that are being skipped. */
- if (parser->skip_stack == NULL ||
- parser->skip_stack->type == SKIP_NO_SKIP)
- {
- _glcpp_parser_expand_if (parser, IF_EXPANDED, $2);
- }
- else
- {
- _glcpp_parser_skip_stack_push_if (parser, & @1, 0);
- parser->skip_stack->type = SKIP_TO_ENDIF;
- }
- }
-| HASH_IF NEWLINE {
- /* #if without an expression is only an error if we
- * are not skipping */
- if (parser->skip_stack == NULL ||
- parser->skip_stack->type == SKIP_NO_SKIP)
- {
- glcpp_error(& @1, parser, "#if with no expression");
- }
- _glcpp_parser_skip_stack_push_if (parser, & @1, 0);
- }
-| HASH_IFDEF IDENTIFIER junk NEWLINE {
- macro_t *macro = hash_table_find (parser->defines, $2);
- talloc_free ($2);
- _glcpp_parser_skip_stack_push_if (parser, & @1, macro != NULL);
- }
-| HASH_IFNDEF IDENTIFIER junk NEWLINE {
- macro_t *macro = hash_table_find (parser->defines, $2);
- talloc_free ($2);
- _glcpp_parser_skip_stack_push_if (parser, & @1, macro == NULL);
- }
-| HASH_ELIF conditional_tokens NEWLINE {
- /* Be careful to only evaluate the 'elif' expression
- * if we are not skipping. When we are skipping, we
- * simply change to a 0-valued 'elif' on the skip
- * stack.
- *
- * This avoids generating diagnostics for invalid
- * expressions that are being skipped. */
- if (parser->skip_stack &&
- parser->skip_stack->type == SKIP_TO_ELSE)
- {
- _glcpp_parser_expand_if (parser, ELIF_EXPANDED, $2);
- }
- else
- {
- _glcpp_parser_skip_stack_change_if (parser, & @1,
- "elif", 0);
- }
- }
-| HASH_ELIF NEWLINE {
- /* #elif without an expression is an error unless we
- * are skipping. */
- if (parser->skip_stack &&
- parser->skip_stack->type == SKIP_TO_ELSE)
- {
- glcpp_error(& @1, parser, "#elif with no expression");
- }
- else
- {
- _glcpp_parser_skip_stack_change_if (parser, & @1,
- "elif", 0);
- glcpp_warning(& @1, parser, "ignoring illegal #elif without expression");
- }
- }
-| HASH_ELSE NEWLINE {
- _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1);
- }
-| HASH_ENDIF NEWLINE {
- _glcpp_parser_skip_stack_pop (parser, & @1);
- }
-| HASH_VERSION integer_constant NEWLINE {
- macro_t *macro = hash_table_find (parser->defines, "__VERSION__");
- if (macro) {
- hash_table_remove (parser->defines, "__VERSION__");
- talloc_free (macro);
- }
- add_builtin_define (parser, "__VERSION__", $2);
-
- if ($2 == 100)
- add_builtin_define (parser, "GL_ES", 1);
-
- /* Currently, all ES2 implementations support highp in the
- * fragment shader, so we always define this macro in ES2.
- * If we ever get a driver that doesn't support highp, we'll
- * need to add a flag to the gl_context and check that here.
- */
- if ($2 >= 130 || $2 == 100)
- add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1);
-
- glcpp_printf(parser->output, "#version %" PRIiMAX, $2);
- }
-| HASH NEWLINE
-;
-
-integer_constant:
- INTEGER_STRING {
- if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) {
- $$ = strtoll ($1 + 2, NULL, 16);
- } else if ($1[0] == '0') {
- $$ = strtoll ($1, NULL, 8);
- } else {
- $$ = strtoll ($1, NULL, 10);
- }
- }
-| INTEGER {
- $$ = $1;
- }
-
-expression:
- integer_constant
-| expression OR expression {
- $$ = $1 || $3;
- }
-| expression AND expression {
- $$ = $1 && $3;
- }
-| expression '|' expression {
- $$ = $1 | $3;
- }
-| expression '^' expression {
- $$ = $1 ^ $3;
- }
-| expression '&' expression {
- $$ = $1 & $3;
- }
-| expression NOT_EQUAL expression {
- $$ = $1 != $3;
- }
-| expression EQUAL expression {
- $$ = $1 == $3;
- }
-| expression GREATER_OR_EQUAL expression {
- $$ = $1 >= $3;
- }
-| expression LESS_OR_EQUAL expression {
- $$ = $1 <= $3;
- }
-| expression '>' expression {
- $$ = $1 > $3;
- }
-| expression '<' expression {
- $$ = $1 < $3;
- }
-| expression RIGHT_SHIFT expression {
- $$ = $1 >> $3;
- }
-| expression LEFT_SHIFT expression {
- $$ = $1 << $3;
- }
-| expression '-' expression {
- $$ = $1 - $3;
- }
-| expression '+' expression {
- $$ = $1 + $3;
- }
-| expression '%' expression {
- $$ = $1 % $3;
- }
-| expression '/' expression {
- if ($3 == 0) {
- yyerror (& @1, parser,
- "division by 0 in preprocessor directive");
- } else {
- $$ = $1 / $3;
- }
- }
-| expression '*' expression {
- $$ = $1 * $3;
- }
-| '!' expression %prec UNARY {
- $$ = ! $2;
- }
-| '~' expression %prec UNARY {
- $$ = ~ $2;
- }
-| '-' expression %prec UNARY {
- $$ = - $2;
- }
-| '+' expression %prec UNARY {
- $$ = + $2;
- }
-| '(' expression ')' {
- $$ = $2;
- }
-;
-
-identifier_list:
- IDENTIFIER {
- $$ = _string_list_create (parser);
- _string_list_append_item ($$, $1);
- talloc_steal ($$, $1);
- }
-| identifier_list ',' IDENTIFIER {
- $$ = $1;
- _string_list_append_item ($$, $3);
- talloc_steal ($$, $3);
- }
-;
-
-text_line:
- NEWLINE { $$ = NULL; }
-| pp_tokens NEWLINE
-;
-
-non_directive:
- pp_tokens NEWLINE {
- yyerror (& @1, parser, "Invalid tokens after #");
- }
-;
-
-replacement_list:
- /* empty */ { $$ = NULL; }
-| pp_tokens
-;
-
-junk:
- /* empty */
-| pp_tokens {
- glcpp_warning(&@1, parser, "extra tokens at end of directive");
- }
-;
-
-conditional_token:
- /* Handle "defined" operator */
- DEFINED IDENTIFIER {
- int v = hash_table_find (parser->defines, $2) ? 1 : 0;
- $$ = _token_create_ival (parser, INTEGER, v);
- }
-| DEFINED '(' IDENTIFIER ')' {
- int v = hash_table_find (parser->defines, $3) ? 1 : 0;
- $$ = _token_create_ival (parser, INTEGER, v);
- }
-| preprocessing_token
-;
-
-conditional_tokens:
- /* Exactly the same as pp_tokens, but using conditional_token */
- conditional_token {
- $$ = _token_list_create (parser);
- _token_list_append ($$, $1);
- }
-| conditional_tokens conditional_token {
- $$ = $1;
- _token_list_append ($$, $2);
- }
-;
-
-pp_tokens:
- preprocessing_token {
- parser->space_tokens = 1;
- $$ = _token_list_create (parser);
- _token_list_append ($$, $1);
- }
-| pp_tokens preprocessing_token {
- $$ = $1;
- _token_list_append ($$, $2);
- }
-;
-
-preprocessing_token:
- IDENTIFIER {
- $$ = _token_create_str (parser, IDENTIFIER, $1);
- $$->location = yylloc;
- }
-| INTEGER_STRING {
- $$ = _token_create_str (parser, INTEGER_STRING, $1);
- $$->location = yylloc;
- }
-| operator {
- $$ = _token_create_ival (parser, $1, $1);
- $$->location = yylloc;
- }
-| OTHER {
- $$ = _token_create_str (parser, OTHER, $1);
- $$->location = yylloc;
- }
-| SPACE {
- $$ = _token_create_ival (parser, SPACE, SPACE);
- $$->location = yylloc;
- }
-;
-
-operator:
- '[' { $$ = '['; }
-| ']' { $$ = ']'; }
-| '(' { $$ = '('; }
-| ')' { $$ = ')'; }
-| '{' { $$ = '{'; }
-| '}' { $$ = '}'; }
-| '.' { $$ = '.'; }
-| '&' { $$ = '&'; }
-| '*' { $$ = '*'; }
-| '+' { $$ = '+'; }
-| '-' { $$ = '-'; }
-| '~' { $$ = '~'; }
-| '!' { $$ = '!'; }
-| '/' { $$ = '/'; }
-| '%' { $$ = '%'; }
-| LEFT_SHIFT { $$ = LEFT_SHIFT; }
-| RIGHT_SHIFT { $$ = RIGHT_SHIFT; }
-| '<' { $$ = '<'; }
-| '>' { $$ = '>'; }
-| LESS_OR_EQUAL { $$ = LESS_OR_EQUAL; }
-| GREATER_OR_EQUAL { $$ = GREATER_OR_EQUAL; }
-| EQUAL { $$ = EQUAL; }
-| NOT_EQUAL { $$ = NOT_EQUAL; }
-| '^' { $$ = '^'; }
-| '|' { $$ = '|'; }
-| AND { $$ = AND; }
-| OR { $$ = OR; }
-| ';' { $$ = ';'; }
-| ',' { $$ = ','; }
-| '=' { $$ = '='; }
-| PASTE { $$ = PASTE; }
-;
-
-%%
-
-string_list_t *
-_string_list_create (void *ctx)
-{
- string_list_t *list;
-
- list = talloc (ctx, string_list_t);
- list->head = NULL;
- list->tail = NULL;
-
- return list;
-}
-
-void
-_string_list_append_item (string_list_t *list, const char *str)
-{
- string_node_t *node;
-
- node = talloc (list, string_node_t);
- node->str = talloc_strdup (node, str);
-
- node->next = NULL;
-
- if (list->head == NULL) {
- list->head = node;
- } else {
- list->tail->next = node;
- }
-
- list->tail = node;
-}
-
-int
-_string_list_contains (string_list_t *list, const char *member, int *index)
-{
- string_node_t *node;
- int i;
-
- if (list == NULL)
- return 0;
-
- for (i = 0, node = list->head; node; i++, node = node->next) {
- if (strcmp (node->str, member) == 0) {
- if (index)
- *index = i;
- return 1;
- }
- }
-
- return 0;
-}
-
-int
-_string_list_length (string_list_t *list)
-{
- int length = 0;
- string_node_t *node;
-
- if (list == NULL)
- return 0;
-
- for (node = list->head; node; node = node->next)
- length++;
-
- return length;
-}
-
-int
-_string_list_equal (string_list_t *a, string_list_t *b)
-{
- string_node_t *node_a, *node_b;
-
- if (a == NULL && b == NULL)
- return 1;
-
- if (a == NULL || b == NULL)
- return 0;
-
- for (node_a = a->head, node_b = b->head;
- node_a && node_b;
- node_a = node_a->next, node_b = node_b->next)
- {
- if (strcmp (node_a->str, node_b->str))
- return 0;
- }
-
- /* Catch the case of lists being different lengths, (which
- * would cause the loop above to terminate after the shorter
- * list). */
- return node_a == node_b;
-}
-
-argument_list_t *
-_argument_list_create (void *ctx)
-{
- argument_list_t *list;
-
- list = talloc (ctx, argument_list_t);
- list->head = NULL;
- list->tail = NULL;
-
- return list;
-}
-
-void
-_argument_list_append (argument_list_t *list, token_list_t *argument)
-{
- argument_node_t *node;
-
- node = talloc (list, argument_node_t);
- node->argument = argument;
-
- node->next = NULL;
-
- if (list->head == NULL) {
- list->head = node;
- } else {
- list->tail->next = node;
- }
-
- list->tail = node;
-}
-
-int
-_argument_list_length (argument_list_t *list)
-{
- int length = 0;
- argument_node_t *node;
-
- if (list == NULL)
- return 0;
-
- for (node = list->head; node; node = node->next)
- length++;
-
- return length;
-}
-
-token_list_t *
-_argument_list_member_at (argument_list_t *list, int index)
-{
- argument_node_t *node;
- int i;
-
- if (list == NULL)
- return NULL;
-
- node = list->head;
- for (i = 0; i < index; i++) {
- node = node->next;
- if (node == NULL)
- break;
- }
-
- if (node)
- return node->argument;
-
- return NULL;
-}
-
-/* Note: This function talloc_steal()s the str pointer. */
-token_t *
-_token_create_str (void *ctx, int type, char *str)
-{
- token_t *token;
-
- token = talloc (ctx, token_t);
- token->type = type;
- token->value.str = talloc_steal (token, str);
-
- return token;
-}
-
-token_t *
-_token_create_ival (void *ctx, int type, int ival)
-{
- token_t *token;
-
- token = talloc (ctx, token_t);
- token->type = type;
- token->value.ival = ival;
-
- return token;
-}
-
-token_list_t *
-_token_list_create (void *ctx)
-{
- token_list_t *list;
-
- list = talloc (ctx, token_list_t);
- list->head = NULL;
- list->tail = NULL;
- list->non_space_tail = NULL;
-
- return list;
-}
-
-void
-_token_list_append (token_list_t *list, token_t *token)
-{
- token_node_t *node;
-
- node = talloc (list, token_node_t);
- node->token = talloc_steal (list, token);
-
- node->next = NULL;
-
- if (list->head == NULL) {
- list->head = node;
- } else {
- list->tail->next = node;
- }
-
- list->tail = node;
- if (token->type != SPACE)
- list->non_space_tail = node;
-}
-
-void
-_token_list_append_list (token_list_t *list, token_list_t *tail)
-{
- if (tail == NULL || tail->head == NULL)
- return;
-
- if (list->head == NULL) {
- list->head = tail->head;
- } else {
- list->tail->next = tail->head;
- }
-
- list->tail = tail->tail;
- list->non_space_tail = tail->non_space_tail;
-}
-
-static token_list_t *
-_token_list_copy (void *ctx, token_list_t *other)
-{
- token_list_t *copy;
- token_node_t *node;
-
- if (other == NULL)
- return NULL;
-
- copy = _token_list_create (ctx);
- for (node = other->head; node; node = node->next) {
- token_t *new_token = talloc (copy, token_t);
- *new_token = *node->token;
- _token_list_append (copy, new_token);
- }
-
- return copy;
-}
-
-static void
-_token_list_trim_trailing_space (token_list_t *list)
-{
- token_node_t *tail, *next;
-
- if (list->non_space_tail) {
- tail = list->non_space_tail->next;
- list->non_space_tail->next = NULL;
- list->tail = list->non_space_tail;
-
- while (tail) {
- next = tail->next;
- talloc_free (tail);
- tail = next;
- }
- }
-}
-
-int
-_token_list_is_empty_ignoring_space (token_list_t *l)
-{
- token_node_t *n;
-
- if (l == NULL)
- return 1;
-
- n = l->head;
- while (n != NULL && n->token->type == SPACE)
- n = n->next;
-
- return n == NULL;
-}
-
-int
-_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
-{
- token_node_t *node_a, *node_b;
-
- if (a == NULL || b == NULL) {
- int a_empty = _token_list_is_empty_ignoring_space(a);
- int b_empty = _token_list_is_empty_ignoring_space(b);
- return a_empty == b_empty;
- }
-
- node_a = a->head;
- node_b = b->head;
-
- while (1)
- {
- if (node_a == NULL && node_b == NULL)
- break;
-
- if (node_a == NULL || node_b == NULL)
- return 0;
-
- if (node_a->token->type == SPACE) {
- node_a = node_a->next;
- continue;
- }
-
- if (node_b->token->type == SPACE) {
- node_b = node_b->next;
- continue;
- }
-
- if (node_a->token->type != node_b->token->type)
- return 0;
-
- switch (node_a->token->type) {
- case INTEGER:
- if (node_a->token->value.ival !=
- node_b->token->value.ival)
- {
- return 0;
- }
- break;
- case IDENTIFIER:
- case INTEGER_STRING:
- case OTHER:
- if (strcmp (node_a->token->value.str,
- node_b->token->value.str))
- {
- return 0;
- }
- break;
- }
-
- node_a = node_a->next;
- node_b = node_b->next;
- }
-
- return 1;
-}
-
-static void
-_token_print (char **out, token_t *token)
-{
- if (token->type < 256) {
- glcpp_printf (*out, "%c", token->type);
- return;
- }
-
- switch (token->type) {
- case INTEGER:
- glcpp_printf (*out, "%" PRIiMAX, token->value.ival);
- break;
- case IDENTIFIER:
- case INTEGER_STRING:
- case OTHER:
- glcpp_print (*out, token->value.str);
- break;
- case SPACE:
- glcpp_print (*out, " ");
- break;
- case LEFT_SHIFT:
- glcpp_print (*out, "<<");
- break;
- case RIGHT_SHIFT:
- glcpp_print (*out, ">>");
- break;
- case LESS_OR_EQUAL:
- glcpp_print (*out, "<=");
- break;
- case GREATER_OR_EQUAL:
- glcpp_print (*out, ">=");
- break;
- case EQUAL:
- glcpp_print (*out, "==");
- break;
- case NOT_EQUAL:
- glcpp_print (*out, "!=");
- break;
- case AND:
- glcpp_print (*out, "&&");
- break;
- case OR:
- glcpp_print (*out, "||");
- break;
- case PASTE:
- glcpp_print (*out, "##");
- break;
- case COMMA_FINAL:
- glcpp_print (*out, ",");
- break;
- case PLACEHOLDER:
- /* Nothing to print. */
- break;
- default:
- assert(!"Error: Don't know how to print token.");
- break;
- }
-}
-
-/* Return a new token (talloc()ed off of 'token') formed by pasting
- * 'token' and 'other'. Note that this function may return 'token' or
- * 'other' directly rather than allocating anything new.
- *
- * Caution: Only very cursory error-checking is performed to see if
- * the final result is a valid single token. */
-static token_t *
-_token_paste (glcpp_parser_t *parser, token_t *token, token_t *other)
-{
- token_t *combined = NULL;
-
- /* Pasting a placeholder onto anything makes no change. */
- if (other->type == PLACEHOLDER)
- return token;
-
- /* When 'token' is a placeholder, just return 'other'. */
- if (token->type == PLACEHOLDER)
- return other;
-
- /* A very few single-character punctuators can be combined
- * with another to form a multi-character punctuator. */
- switch (token->type) {
- case '<':
- if (other->type == '<')
- combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT);
- else if (other->type == '=')
- combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL);
- break;
- case '>':
- if (other->type == '>')
- combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT);
- else if (other->type == '=')
- combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL);
- break;
- case '=':
- if (other->type == '=')
- combined = _token_create_ival (token, EQUAL, EQUAL);
- break;
- case '!':
- if (other->type == '=')
- combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL);
- break;
- case '&':
- if (other->type == '&')
- combined = _token_create_ival (token, AND, AND);
- break;
- case '|':
- if (other->type == '|')
- combined = _token_create_ival (token, OR, OR);
- break;
- }
-
- if (combined != NULL) {
- /* Inherit the location from the first token */
- combined->location = token->location;
- return combined;
- }
-
- /* Two string-valued tokens can usually just be mashed
- * together.
- *
- * XXX: This isn't actually legitimate. Several things here
- * should result in a diagnostic since the result cannot be a
- * valid, single pre-processing token. For example, pasting
- * "123" and "abc" is not legal, but we don't catch that
- * here. */
- if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) &&
- (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING))
- {
- char *str;
-
- str = talloc_asprintf (token, "%s%s", token->value.str,
- other->value.str);
- combined = _token_create_str (token, token->type, str);
- combined->location = token->location;
- return combined;
- }
-
- glcpp_error (&token->location, parser, "");
- glcpp_print (parser->info_log, "Pasting \"");
- _token_print (&parser->info_log, token);
- glcpp_print (parser->info_log, "\" and \"");
- _token_print (&parser->info_log, other);
- glcpp_print (parser->info_log, "\" does not give a valid preprocessing token.\n");
-
- return token;
-}
-
-static void
-_token_list_print (glcpp_parser_t *parser, token_list_t *list)
-{
- token_node_t *node;
-
- if (list == NULL)
- return;
-
- for (node = list->head; node; node = node->next)
- _token_print (&parser->output, node->token);
-}
-
-void
-yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error)
-{
- glcpp_error(locp, parser, "%s", error);
-}
-
-static void add_builtin_define(glcpp_parser_t *parser,
- const char *name, int value)
-{
- token_t *tok;
- token_list_t *list;
-
- tok = _token_create_ival (parser, INTEGER, value);
-
- list = _token_list_create(parser);
- _token_list_append(list, tok);
- _define_object_macro(parser, NULL, name, list);
-}
-
-glcpp_parser_t *
-glcpp_parser_create (const struct gl_extensions *extensions, int api)
-{
- glcpp_parser_t *parser;
- int language_version;
-
- parser = talloc (NULL, glcpp_parser_t);
-
- glcpp_lex_init_extra (parser, &parser->scanner);
- parser->defines = hash_table_ctor (32, hash_table_string_hash,
- hash_table_string_compare);
- parser->active = NULL;
- parser->lexing_if = 0;
- parser->space_tokens = 1;
- parser->newline_as_space = 0;
- parser->in_control_line = 0;
- parser->paren_count = 0;
-
- parser->skip_stack = NULL;
-
- parser->lex_from_list = NULL;
- parser->lex_from_node = NULL;
-
- parser->output = talloc_strdup(parser, "");
- parser->info_log = talloc_strdup(parser, "");
- parser->error = 0;
-
- /* Add pre-defined macros. */
- add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
- add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
-
- if (api == API_OPENGLES2)
- add_builtin_define(parser, "GL_ES", 1);
-
- if (extensions != NULL) {
- if (extensions->EXT_texture_array) {
- add_builtin_define(parser, "GL_EXT_texture_array", 1);
- }
-
- if (extensions->ARB_fragment_coord_conventions)
- add_builtin_define(parser, "GL_ARB_fragment_coord_conventions",
- 1);
-
- if (extensions->ARB_explicit_attrib_location)
- add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1);
- if (extensions->AMD_conservative_depth)
- add_builtin_define(parser, "GL_AMD_conservative_depth", 1);
- }
-
- language_version = 110;
- add_builtin_define(parser, "__VERSION__", language_version);
-
- return parser;
-}
-
-int
-glcpp_parser_parse (glcpp_parser_t *parser)
-{
- return yyparse (parser);
-}
-
-void
-glcpp_parser_destroy (glcpp_parser_t *parser)
-{
- glcpp_lex_destroy (parser->scanner);
- hash_table_dtor (parser->defines);
- talloc_free (parser);
-}
-
-typedef enum function_status
-{
- FUNCTION_STATUS_SUCCESS,
- FUNCTION_NOT_A_FUNCTION,
- FUNCTION_UNBALANCED_PARENTHESES
-} function_status_t;
-
-/* Find a set of function-like macro arguments by looking for a
- * balanced set of parentheses.
- *
- * When called, 'node' should be the opening-parenthesis token, (or
- * perhaps preceeding SPACE tokens). Upon successful return *last will
- * be the last consumed node, (corresponding to the closing right
- * parenthesis).
- *
- * Return values:
- *
- * FUNCTION_STATUS_SUCCESS:
- *
- * Successfully parsed a set of function arguments.
- *
- * FUNCTION_NOT_A_FUNCTION:
- *
- * Macro name not followed by a '('. This is not an error, but
- * simply that the macro name should be treated as a non-macro.
- *
- * FUNCTION_UNBALANCED_PARENTHESES
- *
- * Macro name is not followed by a balanced set of parentheses.
- */
-static function_status_t
-_arguments_parse (argument_list_t *arguments,
- token_node_t *node,
- token_node_t **last)
-{
- token_list_t *argument;
- int paren_count;
-
- node = node->next;
-
- /* Ignore whitespace before first parenthesis. */
- while (node && node->token->type == SPACE)
- node = node->next;
-
- if (node == NULL || node->token->type != '(')
- return FUNCTION_NOT_A_FUNCTION;
-
- node = node->next;
-
- argument = _token_list_create (arguments);
- _argument_list_append (arguments, argument);
-
- for (paren_count = 1; node; node = node->next) {
- if (node->token->type == '(')
- {
- paren_count++;
- }
- else if (node->token->type == ')')
- {
- paren_count--;
- if (paren_count == 0)
- break;
- }
-
- if (node->token->type == ',' &&
- paren_count == 1)
- {
- _token_list_trim_trailing_space (argument);
- argument = _token_list_create (arguments);
- _argument_list_append (arguments, argument);
- }
- else {
- if (argument->head == NULL) {
- /* Don't treat initial whitespace as
- * part of the arguement. */
- if (node->token->type == SPACE)
- continue;
- }
- _token_list_append (argument, node->token);
- }
- }
-
- if (paren_count)
- return FUNCTION_UNBALANCED_PARENTHESES;
-
- *last = node;
-
- return FUNCTION_STATUS_SUCCESS;
-}
-
-static token_list_t *
-_token_list_create_with_one_space (void *ctx)
-{
- token_list_t *list;
- token_t *space;
-
- list = _token_list_create (ctx);
- space = _token_create_ival (list, SPACE, SPACE);
- _token_list_append (list, space);
-
- return list;
-}
-
-static void
-_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list)
-{
- token_list_t *expanded;
- token_t *token;
-
- expanded = _token_list_create (parser);
- token = _token_create_ival (parser, type, type);
- _token_list_append (expanded, token);
- _glcpp_parser_expand_token_list (parser, list);
- _token_list_append_list (expanded, list);
- glcpp_parser_lex_from (parser, expanded);
-}
-
-/* This is a helper function that's essentially part of the
- * implementation of _glcpp_parser_expand_node. It shouldn't be called
- * except for by that function.
- *
- * Returns NULL if node is a simple token with no expansion, (that is,
- * although 'node' corresponds to an identifier defined as a
- * function-like macro, it is not followed with a parenthesized
- * argument list).
- *
- * Compute the complete expansion of node (which is a function-like
- * macro) and subsequent nodes which are arguments.
- *
- * Returns the token list that results from the expansion and sets
- * *last to the last node in the list that was consumed by the
- * expansion. Specifically, *last will be set as follows: as the
- * token of the closing right parenthesis.
- */
-static token_list_t *
-_glcpp_parser_expand_function (glcpp_parser_t *parser,
- token_node_t *node,
- token_node_t **last)
-
-{
- macro_t *macro;
- const char *identifier;
- argument_list_t *arguments;
- function_status_t status;
- token_list_t *substituted;
- int parameter_index;
-
- identifier = node->token->value.str;
-
- macro = hash_table_find (parser->defines, identifier);
-
- assert (macro->is_function);
-
- arguments = _argument_list_create (parser);
- status = _arguments_parse (arguments, node, last);
-
- switch (status) {
- case FUNCTION_STATUS_SUCCESS:
- break;
- case FUNCTION_NOT_A_FUNCTION:
- return NULL;
- case FUNCTION_UNBALANCED_PARENTHESES:
- glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier);
- return NULL;
- }
-
- /* Replace a macro defined as empty with a SPACE token. */
- if (macro->replacements == NULL) {
- talloc_free (arguments);
- return _token_list_create_with_one_space (parser);
- }
-
- if (! ((_argument_list_length (arguments) ==
- _string_list_length (macro->parameters)) ||
- (_string_list_length (macro->parameters) == 0 &&
- _argument_list_length (arguments) == 1 &&
- arguments->head->argument->head == NULL)))
- {
- glcpp_error (&node->token->location, parser,
- "Error: macro %s invoked with %d arguments (expected %d)\n",
- identifier,
- _argument_list_length (arguments),
- _string_list_length (macro->parameters));
- return NULL;
- }
-
- /* Perform argument substitution on the replacement list. */
- substituted = _token_list_create (arguments);
-
- for (node = macro->replacements->head; node; node = node->next)
- {
- if (node->token->type == IDENTIFIER &&
- _string_list_contains (macro->parameters,
- node->token->value.str,
- &parameter_index))
- {
- token_list_t *argument;
- argument = _argument_list_member_at (arguments,
- parameter_index);
- /* Before substituting, we expand the argument
- * tokens, or append a placeholder token for
- * an empty argument. */
- if (argument->head) {
- token_list_t *expanded_argument;
- expanded_argument = _token_list_copy (parser,
- argument);
- _glcpp_parser_expand_token_list (parser,
- expanded_argument);
- _token_list_append_list (substituted,
- expanded_argument);
- } else {
- token_t *new_token;
-
- new_token = _token_create_ival (substituted,
- PLACEHOLDER,
- PLACEHOLDER);
- _token_list_append (substituted, new_token);
- }
- } else {
- _token_list_append (substituted, node->token);
- }
- }
-
- /* After argument substitution, and before further expansion
- * below, implement token pasting. */
-
- _token_list_trim_trailing_space (substituted);
-
- node = substituted->head;
- while (node)
- {
- token_node_t *next_non_space;
-
- /* Look ahead for a PASTE token, skipping space. */
- next_non_space = node->next;
- while (next_non_space && next_non_space->token->type == SPACE)
- next_non_space = next_non_space->next;
-
- if (next_non_space == NULL)
- break;
-
- if (next_non_space->token->type != PASTE) {
- node = next_non_space;
- continue;
- }
-
- /* Now find the next non-space token after the PASTE. */
- next_non_space = next_non_space->next;
- while (next_non_space && next_non_space->token->type == SPACE)
- next_non_space = next_non_space->next;
-
- if (next_non_space == NULL) {
- yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n");
- return NULL;
- }
-
- node->token = _token_paste (parser, node->token, next_non_space->token);
- node->next = next_non_space->next;
- if (next_non_space == substituted->tail)
- substituted->tail = node;
-
- node = node->next;
- }
-
- substituted->non_space_tail = substituted->tail;
-
- return substituted;
-}
-
-/* Compute the complete expansion of node, (and subsequent nodes after
- * 'node' in the case that 'node' is a function-like macro and
- * subsequent nodes are arguments).
- *
- * Returns NULL if node is a simple token with no expansion.
- *
- * Otherwise, returns the token list that results from the expansion
- * and sets *last to the last node in the list that was consumed by
- * the expansion. Specifically, *last will be set as follows:
- *
- * As 'node' in the case of object-like macro expansion.
- *
- * As the token of the closing right parenthesis in the case of
- * function-like macro expansion.
- */
-static token_list_t *
-_glcpp_parser_expand_node (glcpp_parser_t *parser,
- token_node_t *node,
- token_node_t **last)
-{
- token_t *token = node->token;
- const char *identifier;
- macro_t *macro;
-
- /* We only expand identifiers */
- if (token->type != IDENTIFIER) {
- /* We change any COMMA into a COMMA_FINAL to prevent
- * it being mistaken for an argument separator
- * later. */
- if (token->type == ',') {
- token->type = COMMA_FINAL;
- token->value.ival = COMMA_FINAL;
- }
-
- return NULL;
- }
-
- /* Look up this identifier in the hash table. */
- identifier = token->value.str;
- macro = hash_table_find (parser->defines, identifier);
-
- /* Not a macro, so no expansion needed. */
- if (macro == NULL)
- return NULL;
-
- /* Finally, don't expand this macro if we're already actively
- * expanding it, (to avoid infinite recursion). */
- if (_active_list_contains (parser->active, identifier)) {
- /* We change the token type here from IDENTIFIER to
- * OTHER to prevent any future expansion of this
- * unexpanded token. */
- char *str;
- token_list_t *expansion;
- token_t *final;
-
- str = talloc_strdup (parser, token->value.str);
- final = _token_create_str (parser, OTHER, str);
- expansion = _token_list_create (parser);
- _token_list_append (expansion, final);
- *last = node;
- return expansion;
- }
-
- if (! macro->is_function)
- {
- *last = node;
-
- /* Replace a macro defined as empty with a SPACE token. */
- if (macro->replacements == NULL)
- return _token_list_create_with_one_space (parser);
-
- return _token_list_copy (parser, macro->replacements);
- }
-
- return _glcpp_parser_expand_function (parser, node, last);
-}
-
-/* Push a new identifier onto the active list, returning the new list.
- *
- * Here, 'marker' is the token node that appears in the list after the
- * expansion of 'identifier'. That is, when the list iterator begins
- * examinging 'marker', then it is time to pop this node from the
- * active stack.
- */
-active_list_t *
-_active_list_push (active_list_t *list,
- const char *identifier,
- token_node_t *marker)
-{
- active_list_t *node;
-
- node = talloc (list, active_list_t);
- node->identifier = talloc_strdup (node, identifier);
- node->marker = marker;
- node->next = list;
-
- return node;
-}
-
-active_list_t *
-_active_list_pop (active_list_t *list)
-{
- active_list_t *node = list;
-
- if (node == NULL)
- return NULL;
-
- node = list->next;
- talloc_free (list);
-
- return node;
-}
-
-int
-_active_list_contains (active_list_t *list, const char *identifier)
-{
- active_list_t *node;
-
- if (list == NULL)
- return 0;
-
- for (node = list; node; node = node->next)
- if (strcmp (node->identifier, identifier) == 0)
- return 1;
-
- return 0;
-}
-
-/* Walk over the token list replacing nodes with their expansion.
- * Whenever nodes are expanded the walking will walk over the new
- * nodes, continuing to expand as necessary. The results are placed in
- * 'list' itself;
- */
-static void
-_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
- token_list_t *list)
-{
- token_node_t *node_prev;
- token_node_t *node, *last = NULL;
- token_list_t *expansion;
-
- if (list == NULL)
- return;
-
- _token_list_trim_trailing_space (list);
-
- node_prev = NULL;
- node = list->head;
-
- while (node) {
-
- while (parser->active && parser->active->marker == node)
- parser->active = _active_list_pop (parser->active);
-
- /* Find the expansion for node, which will replace all
- * nodes from node to last, inclusive. */
- expansion = _glcpp_parser_expand_node (parser, node, &last);
- if (expansion) {
- token_node_t *n;
-
- for (n = node; n != last->next; n = n->next)
- while (parser->active &&
- parser->active->marker == n)
- {
- parser->active = _active_list_pop (parser->active);
- }
-
- parser->active = _active_list_push (parser->active,
- node->token->value.str,
- last->next);
-
- /* Splice expansion into list, supporting a
- * simple deletion if the expansion is
- * empty. */
- if (expansion->head) {
- if (node_prev)
- node_prev->next = expansion->head;
- else
- list->head = expansion->head;
- expansion->tail->next = last->next;
- if (last == list->tail)
- list->tail = expansion->tail;
- } else {
- if (node_prev)
- node_prev->next = last->next;
- else
- list->head = last->next;
- if (last == list->tail)
- list->tail = NULL;
- }
- } else {
- node_prev = node;
- }
- node = node_prev ? node_prev->next : list->head;
- }
-
- while (parser->active)
- parser->active = _active_list_pop (parser->active);
-
- list->non_space_tail = list->tail;
-}
-
-void
-_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
- token_list_t *list)
-{
- if (list == NULL)
- return;
-
- _glcpp_parser_expand_token_list (parser, list);
-
- _token_list_trim_trailing_space (list);
-
- _token_list_print (parser, list);
-}
-
-static void
-_check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc,
- const char *identifier)
-{
- /* According to the GLSL specification, macro names starting with "__"
- * or "GL_" are reserved for future use. So, don't allow them.
- */
- if (strncmp(identifier, "__", 2) == 0) {
- glcpp_error (loc, parser, "Macro names starting with \"__\" are reserved.\n");
- }
- if (strncmp(identifier, "GL_", 3) == 0) {
- glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n");
- }
-}
-
-static int
-_macro_equal (macro_t *a, macro_t *b)
-{
- if (a->is_function != b->is_function)
- return 0;
-
- if (a->is_function) {
- if (! _string_list_equal (a->parameters, b->parameters))
- return 0;
- }
-
- return _token_list_equal_ignoring_space (a->replacements,
- b->replacements);
-}
-
-void
-_define_object_macro (glcpp_parser_t *parser,
- YYLTYPE *loc,
- const char *identifier,
- token_list_t *replacements)
-{
- macro_t *macro, *previous;
-
- if (loc != NULL)
- _check_for_reserved_macro_name(parser, loc, identifier);
-
- macro = talloc (parser, macro_t);
-
- macro->is_function = 0;
- macro->parameters = NULL;
- macro->identifier = talloc_strdup (macro, identifier);
- macro->replacements = talloc_steal (macro, replacements);
-
- previous = hash_table_find (parser->defines, identifier);
- if (previous) {
- if (_macro_equal (macro, previous)) {
- talloc_free (macro);
- return;
- }
- glcpp_error (loc, parser, "Redefinition of macro %s\n",
- identifier);
- }
-
- hash_table_insert (parser->defines, macro, identifier);
-}
-
-void
-_define_function_macro (glcpp_parser_t *parser,
- YYLTYPE *loc,
- const char *identifier,
- string_list_t *parameters,
- token_list_t *replacements)
-{
- macro_t *macro, *previous;
-
- _check_for_reserved_macro_name(parser, loc, identifier);
-
- macro = talloc (parser, macro_t);
-
- macro->is_function = 1;
- macro->parameters = talloc_steal (macro, parameters);
- macro->identifier = talloc_strdup (macro, identifier);
- macro->replacements = talloc_steal (macro, replacements);
-
- previous = hash_table_find (parser->defines, identifier);
- if (previous) {
- if (_macro_equal (macro, previous)) {
- talloc_free (macro);
- return;
- }
- glcpp_error (loc, parser, "Redefinition of macro %s\n",
- identifier);
- }
-
- hash_table_insert (parser->defines, macro, identifier);
-}
-
-static int
-glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser)
-{
- token_node_t *node;
- int ret;
-
- if (parser->lex_from_list == NULL) {
- ret = glcpp_lex (yylval, yylloc, parser->scanner);
-
- /* XXX: This ugly block of code exists for the sole
- * purpose of converting a NEWLINE token into a SPACE
- * token, but only in the case where we have seen a
- * function-like macro name, but have not yet seen its
- * closing parenthesis.
- *
- * There's perhaps a more compact way to do this with
- * mid-rule actions in the grammar.
- *
- * I'm definitely not pleased with the complexity of
- * this code here.
- */
- if (parser->newline_as_space)
- {
- if (ret == '(') {
- parser->paren_count++;
- } else if (ret == ')') {
- parser->paren_count--;
- if (parser->paren_count == 0)
- parser->newline_as_space = 0;
- } else if (ret == NEWLINE) {
- ret = SPACE;
- } else if (ret != SPACE) {
- if (parser->paren_count == 0)
- parser->newline_as_space = 0;
- }
- }
- else if (parser->in_control_line)
- {
- if (ret == NEWLINE)
- parser->in_control_line = 0;
- }
- else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC ||
- ret == HASH_UNDEF || ret == HASH_IF ||
- ret == HASH_IFDEF || ret == HASH_IFNDEF ||
- ret == HASH_ELIF || ret == HASH_ELSE ||
- ret == HASH_ENDIF || ret == HASH)
- {
- parser->in_control_line = 1;
- }
- else if (ret == IDENTIFIER)
- {
- macro_t *macro;
- macro = hash_table_find (parser->defines,
- yylval->str);
- if (macro && macro->is_function) {
- parser->newline_as_space = 1;
- parser->paren_count = 0;
- }
- }
-
- return ret;
- }
-
- node = parser->lex_from_node;
-
- if (node == NULL) {
- talloc_free (parser->lex_from_list);
- parser->lex_from_list = NULL;
- return NEWLINE;
- }
-
- *yylval = node->token->value;
- ret = node->token->type;
-
- parser->lex_from_node = node->next;
-
- return ret;
-}
-
-static void
-glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list)
-{
- token_node_t *node;
-
- assert (parser->lex_from_list == NULL);
-
- /* Copy list, eliminating any space tokens. */
- parser->lex_from_list = _token_list_create (parser);
-
- for (node = list->head; node; node = node->next) {
- if (node->token->type == SPACE)
- continue;
- _token_list_append (parser->lex_from_list, node->token);
- }
-
- talloc_free (list);
-
- parser->lex_from_node = parser->lex_from_list->head;
-
- /* It's possible the list consisted of nothing but whitespace. */
- if (parser->lex_from_node == NULL) {
- talloc_free (parser->lex_from_list);
- parser->lex_from_list = NULL;
- }
-}
-
-static void
-_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
- int condition)
-{
- skip_type_t current = SKIP_NO_SKIP;
- skip_node_t *node;
-
- if (parser->skip_stack)
- current = parser->skip_stack->type;
-
- node = talloc (parser, skip_node_t);
- node->loc = *loc;
-
- if (current == SKIP_NO_SKIP) {
- if (condition)
- node->type = SKIP_NO_SKIP;
- else
- node->type = SKIP_TO_ELSE;
- } else {
- node->type = SKIP_TO_ENDIF;
- }
-
- node->next = parser->skip_stack;
- parser->skip_stack = node;
-}
-
-static void
-_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
- const char *type, int condition)
-{
- if (parser->skip_stack == NULL) {
- glcpp_error (loc, parser, "%s without #if\n", type);
- return;
- }
-
- if (parser->skip_stack->type == SKIP_TO_ELSE) {
- if (condition)
- parser->skip_stack->type = SKIP_NO_SKIP;
- } else {
- parser->skip_stack->type = SKIP_TO_ENDIF;
- }
-}
-
-static void
-_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc)
-{
- skip_node_t *node;
-
- if (parser->skip_stack == NULL) {
- glcpp_error (loc, parser, "#endif without #if\n");
- return;
- }
-
- node = parser->skip_stack;
- parser->skip_stack = node->next;
- talloc_free (node);
-}
+%{
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include "glcpp.h"
+#include "main/core.h" /* for struct gl_extensions */
+#include "main/mtypes.h" /* for gl_api enum */
+
+static void
+yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error);
+
+static void
+_define_object_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *macro,
+ token_list_t *replacements);
+
+static void
+_define_function_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *macro,
+ string_list_t *parameters,
+ token_list_t *replacements);
+
+static string_list_t *
+_string_list_create (void *ctx);
+
+static void
+_string_list_append_item (string_list_t *list, const char *str);
+
+static int
+_string_list_contains (string_list_t *list, const char *member, int *index);
+
+static int
+_string_list_length (string_list_t *list);
+
+static int
+_string_list_equal (string_list_t *a, string_list_t *b);
+
+static argument_list_t *
+_argument_list_create (void *ctx);
+
+static void
+_argument_list_append (argument_list_t *list, token_list_t *argument);
+
+static int
+_argument_list_length (argument_list_t *list);
+
+static token_list_t *
+_argument_list_member_at (argument_list_t *list, int index);
+
+/* Note: This function ralloc_steal()s the str pointer. */
+static token_t *
+_token_create_str (void *ctx, int type, char *str);
+
+static token_t *
+_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);
+
+static void
+_token_list_append_list (token_list_t *list, token_list_t *tail);
+
+static int
+_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b);
+
+static active_list_t *
+_active_list_push (active_list_t *list,
+ const char *identifier,
+ token_node_t *marker);
+
+static active_list_t *
+_active_list_pop (active_list_t *list);
+
+int
+_active_list_contains (active_list_t *list, const char *identifier);
+
+static void
+_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list);
+
+static void
+_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
+ token_list_t *list);
+
+static void
+_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
+ token_list_t *list);
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ int condition);
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *type, int condition);
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc);
+
+#define yylex glcpp_parser_lex
+
+static int
+glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser);
+
+static void
+glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list);
+
+static void
+add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
+
+%}
+
+%pure-parser
+%error-verbose
+
+%locations
+%initial-action {
+ @$.first_line = 1;
+ @$.first_column = 1;
+ @$.last_line = 1;
+ @$.last_column = 1;
+ @$.source = 0;
+}
+
+%parse-param {glcpp_parser_t *parser}
+%lex-param {glcpp_parser_t *parser}
+
+%expect 0
+%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING NEWLINE OTHER PLACEHOLDER SPACE
+%token PASTE
+%type <ival> expression INTEGER operator SPACE integer_constant
+%type <str> IDENTIFIER INTEGER_STRING OTHER
+%type <string_list> identifier_list
+%type <token> preprocessing_token conditional_token
+%type <token_list> pp_tokens replacement_list text_line conditional_tokens
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOT_EQUAL
+%left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL
+%left LEFT_SHIFT RIGHT_SHIFT
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY
+
+%%
+
+input:
+ /* empty */
+| input line
+;
+
+line:
+ control_line {
+ ralloc_strcat (&parser->output, "\n");
+ }
+| text_line {
+ _glcpp_parser_print_expanded_token_list (parser, $1);
+ ralloc_strcat (&parser->output, "\n");
+ ralloc_free ($1);
+ }
+| expanded_line
+| HASH non_directive
+;
+
+expanded_line:
+ IF_EXPANDED expression NEWLINE {
+ _glcpp_parser_skip_stack_push_if (parser, & @1, $2);
+ }
+| ELIF_EXPANDED expression NEWLINE {
+ _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2);
+ }
+;
+
+control_line:
+ HASH_DEFINE_OBJ IDENTIFIER replacement_list NEWLINE {
+ _define_object_macro (parser, & @2, $2, $3);
+ }
+| HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE {
+ _define_function_macro (parser, & @2, $2, NULL, $5);
+ }
+| HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE {
+ _define_function_macro (parser, & @2, $2, $4, $6);
+ }
+| HASH_UNDEF IDENTIFIER NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, $2);
+ if (macro) {
+ hash_table_remove (parser->defines, $2);
+ ralloc_free (macro);
+ }
+ ralloc_free ($2);
+ }
+| HASH_IF conditional_tokens NEWLINE {
+ /* Be careful to only evaluate the 'if' expression if
+ * we are not skipping. When we are skipping, we
+ * simply push a new 0-valued 'if' onto the skip
+ * stack.
+ *
+ * This avoids generating diagnostics for invalid
+ * expressions that are being skipped. */
+ if (parser->skip_stack == NULL ||
+ parser->skip_stack->type == SKIP_NO_SKIP)
+ {
+ _glcpp_parser_expand_if (parser, IF_EXPANDED, $2);
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_push_if (parser, & @1, 0);
+ parser->skip_stack->type = SKIP_TO_ENDIF;
+ }
+ }
+| HASH_IF NEWLINE {
+ /* #if without an expression is only an error if we
+ * are not skipping */
+ if (parser->skip_stack == NULL ||
+ parser->skip_stack->type == SKIP_NO_SKIP)
+ {
+ glcpp_error(& @1, parser, "#if with no expression");
+ }
+ _glcpp_parser_skip_stack_push_if (parser, & @1, 0);
+ }
+| HASH_IFDEF IDENTIFIER junk NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, $2);
+ ralloc_free ($2);
+ _glcpp_parser_skip_stack_push_if (parser, & @1, macro != NULL);
+ }
+| HASH_IFNDEF IDENTIFIER junk NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, $2);
+ ralloc_free ($2);
+ _glcpp_parser_skip_stack_push_if (parser, & @1, macro == NULL);
+ }
+| HASH_ELIF conditional_tokens NEWLINE {
+ /* Be careful to only evaluate the 'elif' expression
+ * if we are not skipping. When we are skipping, we
+ * simply change to a 0-valued 'elif' on the skip
+ * stack.
+ *
+ * This avoids generating diagnostics for invalid
+ * expressions that are being skipped. */
+ if (parser->skip_stack &&
+ parser->skip_stack->type == SKIP_TO_ELSE)
+ {
+ _glcpp_parser_expand_if (parser, ELIF_EXPANDED, $2);
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & @1,
+ "elif", 0);
+ }
+ }
+| HASH_ELIF NEWLINE {
+ /* #elif without an expression is an error unless we
+ * are skipping. */
+ if (parser->skip_stack &&
+ parser->skip_stack->type == SKIP_TO_ELSE)
+ {
+ glcpp_error(& @1, parser, "#elif with no expression");
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & @1,
+ "elif", 0);
+ glcpp_warning(& @1, parser, "ignoring illegal #elif without expression");
+ }
+ }
+| HASH_ELSE NEWLINE {
+ _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1);
+ }
+| HASH_ENDIF NEWLINE {
+ _glcpp_parser_skip_stack_pop (parser, & @1);
+ }
+| HASH_VERSION integer_constant NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, "__VERSION__");
+ if (macro) {
+ hash_table_remove (parser->defines, "__VERSION__");
+ ralloc_free (macro);
+ }
+ add_builtin_define (parser, "__VERSION__", $2);
+
+ if ($2 == 100)
+ add_builtin_define (parser, "GL_ES", 1);
+
+ /* Currently, all ES2 implementations support highp in the
+ * fragment shader, so we always define this macro in ES2.
+ * If we ever get a driver that doesn't support highp, we'll
+ * need to add a flag to the gl_context and check that here.
+ */
+ if ($2 >= 130 || $2 == 100)
+ add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ ralloc_asprintf_append (&parser->output, "#version %" PRIiMAX, $2);
+ }
+| HASH NEWLINE
+;
+
+integer_constant:
+ INTEGER_STRING {
+ if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) {
+ $$ = strtoll ($1 + 2, NULL, 16);
+ } else if ($1[0] == '0') {
+ $$ = strtoll ($1, NULL, 8);
+ } else {
+ $$ = strtoll ($1, NULL, 10);
+ }
+ }
+| INTEGER {
+ $$ = $1;
+ }
+
+expression:
+ integer_constant
+| expression OR expression {
+ $$ = $1 || $3;
+ }
+| expression AND expression {
+ $$ = $1 && $3;
+ }
+| expression '|' expression {
+ $$ = $1 | $3;
+ }
+| expression '^' expression {
+ $$ = $1 ^ $3;
+ }
+| expression '&' expression {
+ $$ = $1 & $3;
+ }
+| expression NOT_EQUAL expression {
+ $$ = $1 != $3;
+ }
+| expression EQUAL expression {
+ $$ = $1 == $3;
+ }
+| expression GREATER_OR_EQUAL expression {
+ $$ = $1 >= $3;
+ }
+| expression LESS_OR_EQUAL expression {
+ $$ = $1 <= $3;
+ }
+| expression '>' expression {
+ $$ = $1 > $3;
+ }
+| expression '<' expression {
+ $$ = $1 < $3;
+ }
+| expression RIGHT_SHIFT expression {
+ $$ = $1 >> $3;
+ }
+| expression LEFT_SHIFT expression {
+ $$ = $1 << $3;
+ }
+| expression '-' expression {
+ $$ = $1 - $3;
+ }
+| expression '+' expression {
+ $$ = $1 + $3;
+ }
+| expression '%' expression {
+ $$ = $1 % $3;
+ }
+| expression '/' expression {
+ if ($3 == 0) {
+ yyerror (& @1, parser,
+ "division by 0 in preprocessor directive");
+ } else {
+ $$ = $1 / $3;
+ }
+ }
+| expression '*' expression {
+ $$ = $1 * $3;
+ }
+| '!' expression %prec UNARY {
+ $$ = ! $2;
+ }
+| '~' expression %prec UNARY {
+ $$ = ~ $2;
+ }
+| '-' expression %prec UNARY {
+ $$ = - $2;
+ }
+| '+' expression %prec UNARY {
+ $$ = + $2;
+ }
+| '(' expression ')' {
+ $$ = $2;
+ }
+;
+
+identifier_list:
+ IDENTIFIER {
+ $$ = _string_list_create (parser);
+ _string_list_append_item ($$, $1);
+ ralloc_steal ($$, $1);
+ }
+| identifier_list ',' IDENTIFIER {
+ $$ = $1;
+ _string_list_append_item ($$, $3);
+ ralloc_steal ($$, $3);
+ }
+;
+
+text_line:
+ NEWLINE { $$ = NULL; }
+| pp_tokens NEWLINE
+;
+
+non_directive:
+ pp_tokens NEWLINE {
+ yyerror (& @1, parser, "Invalid tokens after #");
+ }
+;
+
+replacement_list:
+ /* empty */ { $$ = NULL; }
+| pp_tokens
+;
+
+junk:
+ /* empty */
+| pp_tokens {
+ glcpp_warning(&@1, parser, "extra tokens at end of directive");
+ }
+;
+
+conditional_token:
+ /* Handle "defined" operator */
+ DEFINED IDENTIFIER {
+ int v = hash_table_find (parser->defines, $2) ? 1 : 0;
+ $$ = _token_create_ival (parser, INTEGER, v);
+ }
+| DEFINED '(' IDENTIFIER ')' {
+ int v = hash_table_find (parser->defines, $3) ? 1 : 0;
+ $$ = _token_create_ival (parser, INTEGER, v);
+ }
+| preprocessing_token
+;
+
+conditional_tokens:
+ /* Exactly the same as pp_tokens, but using conditional_token */
+ conditional_token {
+ $$ = _token_list_create (parser);
+ _token_list_append ($$, $1);
+ }
+| conditional_tokens conditional_token {
+ $$ = $1;
+ _token_list_append ($$, $2);
+ }
+;
+
+pp_tokens:
+ preprocessing_token {
+ parser->space_tokens = 1;
+ $$ = _token_list_create (parser);
+ _token_list_append ($$, $1);
+ }
+| pp_tokens preprocessing_token {
+ $$ = $1;
+ _token_list_append ($$, $2);
+ }
+;
+
+preprocessing_token:
+ IDENTIFIER {
+ $$ = _token_create_str (parser, IDENTIFIER, $1);
+ $$->location = yylloc;
+ }
+| INTEGER_STRING {
+ $$ = _token_create_str (parser, INTEGER_STRING, $1);
+ $$->location = yylloc;
+ }
+| operator {
+ $$ = _token_create_ival (parser, $1, $1);
+ $$->location = yylloc;
+ }
+| OTHER {
+ $$ = _token_create_str (parser, OTHER, $1);
+ $$->location = yylloc;
+ }
+| SPACE {
+ $$ = _token_create_ival (parser, SPACE, SPACE);
+ $$->location = yylloc;
+ }
+;
+
+operator:
+ '[' { $$ = '['; }
+| ']' { $$ = ']'; }
+| '(' { $$ = '('; }
+| ')' { $$ = ')'; }
+| '{' { $$ = '{'; }
+| '}' { $$ = '}'; }
+| '.' { $$ = '.'; }
+| '&' { $$ = '&'; }
+| '*' { $$ = '*'; }
+| '+' { $$ = '+'; }
+| '-' { $$ = '-'; }
+| '~' { $$ = '~'; }
+| '!' { $$ = '!'; }
+| '/' { $$ = '/'; }
+| '%' { $$ = '%'; }
+| LEFT_SHIFT { $$ = LEFT_SHIFT; }
+| RIGHT_SHIFT { $$ = RIGHT_SHIFT; }
+| '<' { $$ = '<'; }
+| '>' { $$ = '>'; }
+| LESS_OR_EQUAL { $$ = LESS_OR_EQUAL; }
+| GREATER_OR_EQUAL { $$ = GREATER_OR_EQUAL; }
+| EQUAL { $$ = EQUAL; }
+| NOT_EQUAL { $$ = NOT_EQUAL; }
+| '^' { $$ = '^'; }
+| '|' { $$ = '|'; }
+| AND { $$ = AND; }
+| OR { $$ = OR; }
+| ';' { $$ = ';'; }
+| ',' { $$ = ','; }
+| '=' { $$ = '='; }
+| PASTE { $$ = PASTE; }
+;
+
+%%
+
+string_list_t *
+_string_list_create (void *ctx)
+{
+ string_list_t *list;
+
+ list = ralloc (ctx, string_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+
+ return list;
+}
+
+void
+_string_list_append_item (string_list_t *list, const char *str)
+{
+ string_node_t *node;
+
+ node = ralloc (list, string_node_t);
+ node->str = ralloc_strdup (node, str);
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+}
+
+int
+_string_list_contains (string_list_t *list, const char *member, int *index)
+{
+ string_node_t *node;
+ int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0, node = list->head; node; i++, node = node->next) {
+ if (strcmp (node->str, member) == 0) {
+ if (index)
+ *index = i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+_string_list_length (string_list_t *list)
+{
+ int length = 0;
+ string_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+int
+_string_list_equal (string_list_t *a, string_list_t *b)
+{
+ string_node_t *node_a, *node_b;
+
+ if (a == NULL && b == NULL)
+ return 1;
+
+ if (a == NULL || b == NULL)
+ return 0;
+
+ for (node_a = a->head, node_b = b->head;
+ node_a && node_b;
+ node_a = node_a->next, node_b = node_b->next)
+ {
+ if (strcmp (node_a->str, node_b->str))
+ return 0;
+ }
+
+ /* Catch the case of lists being different lengths, (which
+ * would cause the loop above to terminate after the shorter
+ * list). */
+ return node_a == node_b;
+}
+
+argument_list_t *
+_argument_list_create (void *ctx)
+{
+ argument_list_t *list;
+
+ list = ralloc (ctx, argument_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+
+ return list;
+}
+
+void
+_argument_list_append (argument_list_t *list, token_list_t *argument)
+{
+ argument_node_t *node;
+
+ node = ralloc (list, argument_node_t);
+ node->argument = argument;
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+}
+
+int
+_argument_list_length (argument_list_t *list)
+{
+ int length = 0;
+ argument_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+token_list_t *
+_argument_list_member_at (argument_list_t *list, int index)
+{
+ argument_node_t *node;
+ int i;
+
+ if (list == NULL)
+ return NULL;
+
+ node = list->head;
+ for (i = 0; i < index; i++) {
+ node = node->next;
+ if (node == NULL)
+ break;
+ }
+
+ if (node)
+ return node->argument;
+
+ return NULL;
+}
+
+/* Note: This function ralloc_steal()s the str pointer. */
+token_t *
+_token_create_str (void *ctx, int type, char *str)
+{
+ token_t *token;
+
+ token = ralloc (ctx, token_t);
+ token->type = type;
+ token->value.str = str;
+
+ ralloc_steal (token, str);
+
+ return token;
+}
+
+token_t *
+_token_create_ival (void *ctx, int type, int ival)
+{
+ token_t *token;
+
+ token = ralloc (ctx, token_t);
+ token->type = type;
+ token->value.ival = ival;
+
+ return token;
+}
+
+token_list_t *
+_token_list_create (void *ctx)
+{
+ token_list_t *list;
+
+ list = ralloc (ctx, token_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+ list->non_space_tail = NULL;
+
+ return list;
+}
+
+void
+_token_list_append (token_list_t *list, token_t *token)
+{
+ token_node_t *node;
+
+ node = ralloc (list, token_node_t);
+ node->token = token;
+ node->next = NULL;
+
+ ralloc_steal (list, token);
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+ if (token->type != SPACE)
+ list->non_space_tail = node;
+}
+
+void
+_token_list_append_list (token_list_t *list, token_list_t *tail)
+{
+ if (tail == NULL || tail->head == NULL)
+ return;
+
+ if (list->head == NULL) {
+ list->head = tail->head;
+ } else {
+ list->tail->next = tail->head;
+ }
+
+ list->tail = tail->tail;
+ list->non_space_tail = tail->non_space_tail;
+}
+
+static token_list_t *
+_token_list_copy (void *ctx, token_list_t *other)
+{
+ token_list_t *copy;
+ token_node_t *node;
+
+ if (other == NULL)
+ return NULL;
+
+ copy = _token_list_create (ctx);
+ for (node = other->head; node; node = node->next) {
+ token_t *new_token = ralloc (copy, token_t);
+ *new_token = *node->token;
+ _token_list_append (copy, new_token);
+ }
+
+ return copy;
+}
+
+static void
+_token_list_trim_trailing_space (token_list_t *list)
+{
+ token_node_t *tail, *next;
+
+ if (list->non_space_tail) {
+ tail = list->non_space_tail->next;
+ list->non_space_tail->next = NULL;
+ list->tail = list->non_space_tail;
+
+ while (tail) {
+ next = tail->next;
+ ralloc_free (tail);
+ tail = next;
+ }
+ }
+}
+
+static int
+_token_list_is_empty_ignoring_space (token_list_t *l)
+{
+ token_node_t *n;
+
+ if (l == NULL)
+ return 1;
+
+ n = l->head;
+ while (n != NULL && n->token->type == SPACE)
+ n = n->next;
+
+ return n == NULL;
+}
+
+int
+_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
+{
+ token_node_t *node_a, *node_b;
+
+ if (a == NULL || b == NULL) {
+ int a_empty = _token_list_is_empty_ignoring_space(a);
+ int b_empty = _token_list_is_empty_ignoring_space(b);
+ return a_empty == b_empty;
+ }
+
+ node_a = a->head;
+ node_b = b->head;
+
+ while (1)
+ {
+ if (node_a == NULL && node_b == NULL)
+ break;
+
+ if (node_a == NULL || node_b == NULL)
+ return 0;
+
+ if (node_a->token->type == SPACE) {
+ node_a = node_a->next;
+ continue;
+ }
+
+ if (node_b->token->type == SPACE) {
+ node_b = node_b->next;
+ continue;
+ }
+
+ if (node_a->token->type != node_b->token->type)
+ return 0;
+
+ switch (node_a->token->type) {
+ case INTEGER:
+ if (node_a->token->value.ival !=
+ node_b->token->value.ival)
+ {
+ return 0;
+ }
+ break;
+ case IDENTIFIER:
+ case INTEGER_STRING:
+ case OTHER:
+ if (strcmp (node_a->token->value.str,
+ node_b->token->value.str))
+ {
+ return 0;
+ }
+ break;
+ }
+
+ node_a = node_a->next;
+ node_b = node_b->next;
+ }
+
+ return 1;
+}
+
+static void
+_token_print (char **out, token_t *token)
+{
+ if (token->type < 256) {
+ ralloc_asprintf_append (out, "%c", token->type);
+ return;
+ }
+
+ switch (token->type) {
+ case INTEGER:
+ ralloc_asprintf_append (out, "%" PRIiMAX, token->value.ival);
+ break;
+ case IDENTIFIER:
+ case INTEGER_STRING:
+ case OTHER:
+ ralloc_strcat (out, token->value.str);
+ break;
+ case SPACE:
+ ralloc_strcat (out, " ");
+ break;
+ case LEFT_SHIFT:
+ ralloc_strcat (out, "<<");
+ break;
+ case RIGHT_SHIFT:
+ ralloc_strcat (out, ">>");
+ break;
+ case LESS_OR_EQUAL:
+ ralloc_strcat (out, "<=");
+ break;
+ case GREATER_OR_EQUAL:
+ ralloc_strcat (out, ">=");
+ break;
+ case EQUAL:
+ ralloc_strcat (out, "==");
+ break;
+ case NOT_EQUAL:
+ ralloc_strcat (out, "!=");
+ break;
+ case AND:
+ ralloc_strcat (out, "&&");
+ break;
+ case OR:
+ ralloc_strcat (out, "||");
+ break;
+ case PASTE:
+ ralloc_strcat (out, "##");
+ break;
+ case COMMA_FINAL:
+ ralloc_strcat (out, ",");
+ break;
+ case PLACEHOLDER:
+ /* Nothing to print. */
+ break;
+ default:
+ assert(!"Error: Don't know how to print token.");
+ break;
+ }
+}
+
+/* Return a new token (ralloc()ed off of 'token') formed by pasting
+ * 'token' and 'other'. Note that this function may return 'token' or
+ * 'other' directly rather than allocating anything new.
+ *
+ * Caution: Only very cursory error-checking is performed to see if
+ * the final result is a valid single token. */
+static token_t *
+_token_paste (glcpp_parser_t *parser, token_t *token, token_t *other)
+{
+ token_t *combined = NULL;
+
+ /* Pasting a placeholder onto anything makes no change. */
+ if (other->type == PLACEHOLDER)
+ return token;
+
+ /* When 'token' is a placeholder, just return 'other'. */
+ if (token->type == PLACEHOLDER)
+ return other;
+
+ /* A very few single-character punctuators can be combined
+ * with another to form a multi-character punctuator. */
+ switch (token->type) {
+ case '<':
+ if (other->type == '<')
+ combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT);
+ else if (other->type == '=')
+ combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL);
+ break;
+ case '>':
+ if (other->type == '>')
+ combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT);
+ else if (other->type == '=')
+ combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL);
+ break;
+ case '=':
+ if (other->type == '=')
+ combined = _token_create_ival (token, EQUAL, EQUAL);
+ break;
+ case '!':
+ if (other->type == '=')
+ combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL);
+ break;
+ case '&':
+ if (other->type == '&')
+ combined = _token_create_ival (token, AND, AND);
+ break;
+ case '|':
+ if (other->type == '|')
+ combined = _token_create_ival (token, OR, OR);
+ break;
+ }
+
+ if (combined != NULL) {
+ /* Inherit the location from the first token */
+ combined->location = token->location;
+ return combined;
+ }
+
+ /* Two string-valued tokens can usually just be mashed
+ * together.
+ *
+ * XXX: This isn't actually legitimate. Several things here
+ * should result in a diagnostic since the result cannot be a
+ * valid, single pre-processing token. For example, pasting
+ * "123" and "abc" is not legal, but we don't catch that
+ * here. */
+ if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) &&
+ (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING))
+ {
+ char *str;
+
+ str = ralloc_asprintf (token, "%s%s", token->value.str,
+ other->value.str);
+ combined = _token_create_str (token, token->type, str);
+ combined->location = token->location;
+ return combined;
+ }
+
+ glcpp_error (&token->location, parser, "");
+ ralloc_strcat (&parser->info_log, "Pasting \"");
+ _token_print (&parser->info_log, token);
+ ralloc_strcat (&parser->info_log, "\" and \"");
+ _token_print (&parser->info_log, other);
+ ralloc_strcat (&parser->info_log, "\" does not give a valid preprocessing token.\n");
+
+ return token;
+}
+
+static void
+_token_list_print (glcpp_parser_t *parser, token_list_t *list)
+{
+ token_node_t *node;
+
+ if (list == NULL)
+ return;
+
+ for (node = list->head; node; node = node->next)
+ _token_print (&parser->output, node->token);
+}
+
+void
+yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error)
+{
+ glcpp_error(locp, parser, "%s", error);
+}
+
+static void add_builtin_define(glcpp_parser_t *parser,
+ const char *name, int value)
+{
+ token_t *tok;
+ token_list_t *list;
+
+ tok = _token_create_ival (parser, INTEGER, value);
+
+ list = _token_list_create(parser);
+ _token_list_append(list, tok);
+ _define_object_macro(parser, NULL, name, list);
+}
+
+glcpp_parser_t *
+glcpp_parser_create (const struct gl_extensions *extensions, int api)
+{
+ glcpp_parser_t *parser;
+ int language_version;
+
+ parser = ralloc (NULL, glcpp_parser_t);
+
+ glcpp_lex_init_extra (parser, &parser->scanner);
+ parser->defines = hash_table_ctor (32, hash_table_string_hash,
+ hash_table_string_compare);
+ parser->active = NULL;
+ parser->lexing_if = 0;
+ parser->space_tokens = 1;
+ parser->newline_as_space = 0;
+ parser->in_control_line = 0;
+ parser->paren_count = 0;
+
+ parser->skip_stack = NULL;
+
+ parser->lex_from_list = NULL;
+ parser->lex_from_node = NULL;
+
+ parser->output = ralloc_strdup(parser, "");
+ parser->info_log = ralloc_strdup(parser, "");
+ parser->error = 0;
+
+ /* Add pre-defined macros. */
+ add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
+ add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
+
+ if (api == API_OPENGLES2)
+ add_builtin_define(parser, "GL_ES", 1);
+
+ if (extensions != NULL) {
+ if (extensions->EXT_texture_array) {
+ add_builtin_define(parser, "GL_EXT_texture_array", 1);
+ }
+
+ if (extensions->ARB_fragment_coord_conventions)
+ add_builtin_define(parser, "GL_ARB_fragment_coord_conventions",
+ 1);
+
+ if (extensions->ARB_explicit_attrib_location)
+ add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1);
+ if (extensions->AMD_conservative_depth)
+ add_builtin_define(parser, "GL_AMD_conservative_depth", 1);
+ }
+
+ language_version = 110;
+ add_builtin_define(parser, "__VERSION__", language_version);
+
+ return parser;
+}
+
+int
+glcpp_parser_parse (glcpp_parser_t *parser)
+{
+ return yyparse (parser);
+}
+
+void
+glcpp_parser_destroy (glcpp_parser_t *parser)
+{
+ glcpp_lex_destroy (parser->scanner);
+ hash_table_dtor (parser->defines);
+ ralloc_free (parser);
+}
+
+typedef enum function_status
+{
+ FUNCTION_STATUS_SUCCESS,
+ FUNCTION_NOT_A_FUNCTION,
+ FUNCTION_UNBALANCED_PARENTHESES
+} function_status_t;
+
+/* Find a set of function-like macro arguments by looking for a
+ * balanced set of parentheses.
+ *
+ * When called, 'node' should be the opening-parenthesis token, (or
+ * perhaps preceeding SPACE tokens). Upon successful return *last will
+ * be the last consumed node, (corresponding to the closing right
+ * parenthesis).
+ *
+ * Return values:
+ *
+ * FUNCTION_STATUS_SUCCESS:
+ *
+ * Successfully parsed a set of function arguments.
+ *
+ * FUNCTION_NOT_A_FUNCTION:
+ *
+ * Macro name not followed by a '('. This is not an error, but
+ * simply that the macro name should be treated as a non-macro.
+ *
+ * FUNCTION_UNBALANCED_PARENTHESES
+ *
+ * Macro name is not followed by a balanced set of parentheses.
+ */
+static function_status_t
+_arguments_parse (argument_list_t *arguments,
+ token_node_t *node,
+ token_node_t **last)
+{
+ token_list_t *argument;
+ int paren_count;
+
+ node = node->next;
+
+ /* Ignore whitespace before first parenthesis. */
+ while (node && node->token->type == SPACE)
+ node = node->next;
+
+ if (node == NULL || node->token->type != '(')
+ return FUNCTION_NOT_A_FUNCTION;
+
+ node = node->next;
+
+ argument = _token_list_create (arguments);
+ _argument_list_append (arguments, argument);
+
+ for (paren_count = 1; node; node = node->next) {
+ if (node->token->type == '(')
+ {
+ paren_count++;
+ }
+ else if (node->token->type == ')')
+ {
+ paren_count--;
+ if (paren_count == 0)
+ break;
+ }
+
+ if (node->token->type == ',' &&
+ paren_count == 1)
+ {
+ _token_list_trim_trailing_space (argument);
+ argument = _token_list_create (arguments);
+ _argument_list_append (arguments, argument);
+ }
+ else {
+ if (argument->head == NULL) {
+ /* Don't treat initial whitespace as
+ * part of the arguement. */
+ if (node->token->type == SPACE)
+ continue;
+ }
+ _token_list_append (argument, node->token);
+ }
+ }
+
+ if (paren_count)
+ return FUNCTION_UNBALANCED_PARENTHESES;
+
+ *last = node;
+
+ return FUNCTION_STATUS_SUCCESS;
+}
+
+static token_list_t *
+_token_list_create_with_one_space (void *ctx)
+{
+ token_list_t *list;
+ token_t *space;
+
+ list = _token_list_create (ctx);
+ space = _token_create_ival (list, SPACE, SPACE);
+ _token_list_append (list, space);
+
+ return list;
+}
+
+static void
+_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list)
+{
+ token_list_t *expanded;
+ token_t *token;
+
+ expanded = _token_list_create (parser);
+ token = _token_create_ival (parser, type, type);
+ _token_list_append (expanded, token);
+ _glcpp_parser_expand_token_list (parser, list);
+ _token_list_append_list (expanded, list);
+ glcpp_parser_lex_from (parser, expanded);
+}
+
+/* This is a helper function that's essentially part of the
+ * implementation of _glcpp_parser_expand_node. It shouldn't be called
+ * except for by that function.
+ *
+ * Returns NULL if node is a simple token with no expansion, (that is,
+ * although 'node' corresponds to an identifier defined as a
+ * function-like macro, it is not followed with a parenthesized
+ * argument list).
+ *
+ * Compute the complete expansion of node (which is a function-like
+ * macro) and subsequent nodes which are arguments.
+ *
+ * Returns the token list that results from the expansion and sets
+ * *last to the last node in the list that was consumed by the
+ * expansion. Specifically, *last will be set as follows: as the
+ * token of the closing right parenthesis.
+ */
+static token_list_t *
+_glcpp_parser_expand_function (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last)
+
+{
+ macro_t *macro;
+ const char *identifier;
+ argument_list_t *arguments;
+ function_status_t status;
+ token_list_t *substituted;
+ int parameter_index;
+
+ identifier = node->token->value.str;
+
+ macro = hash_table_find (parser->defines, identifier);
+
+ assert (macro->is_function);
+
+ arguments = _argument_list_create (parser);
+ status = _arguments_parse (arguments, node, last);
+
+ switch (status) {
+ case FUNCTION_STATUS_SUCCESS:
+ break;
+ case FUNCTION_NOT_A_FUNCTION:
+ return NULL;
+ case FUNCTION_UNBALANCED_PARENTHESES:
+ glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier);
+ return NULL;
+ }
+
+ /* Replace a macro defined as empty with a SPACE token. */
+ if (macro->replacements == NULL) {
+ ralloc_free (arguments);
+ return _token_list_create_with_one_space (parser);
+ }
+
+ if (! ((_argument_list_length (arguments) ==
+ _string_list_length (macro->parameters)) ||
+ (_string_list_length (macro->parameters) == 0 &&
+ _argument_list_length (arguments) == 1 &&
+ arguments->head->argument->head == NULL)))
+ {
+ glcpp_error (&node->token->location, parser,
+ "Error: macro %s invoked with %d arguments (expected %d)\n",
+ identifier,
+ _argument_list_length (arguments),
+ _string_list_length (macro->parameters));
+ return NULL;
+ }
+
+ /* Perform argument substitution on the replacement list. */
+ substituted = _token_list_create (arguments);
+
+ for (node = macro->replacements->head; node; node = node->next)
+ {
+ if (node->token->type == IDENTIFIER &&
+ _string_list_contains (macro->parameters,
+ node->token->value.str,
+ &parameter_index))
+ {
+ token_list_t *argument;
+ argument = _argument_list_member_at (arguments,
+ parameter_index);
+ /* Before substituting, we expand the argument
+ * tokens, or append a placeholder token for
+ * an empty argument. */
+ if (argument->head) {
+ token_list_t *expanded_argument;
+ expanded_argument = _token_list_copy (parser,
+ argument);
+ _glcpp_parser_expand_token_list (parser,
+ expanded_argument);
+ _token_list_append_list (substituted,
+ expanded_argument);
+ } else {
+ token_t *new_token;
+
+ new_token = _token_create_ival (substituted,
+ PLACEHOLDER,
+ PLACEHOLDER);
+ _token_list_append (substituted, new_token);
+ }
+ } else {
+ _token_list_append (substituted, node->token);
+ }
+ }
+
+ /* After argument substitution, and before further expansion
+ * below, implement token pasting. */
+
+ _token_list_trim_trailing_space (substituted);
+
+ node = substituted->head;
+ while (node)
+ {
+ token_node_t *next_non_space;
+
+ /* Look ahead for a PASTE token, skipping space. */
+ next_non_space = node->next;
+ while (next_non_space && next_non_space->token->type == SPACE)
+ next_non_space = next_non_space->next;
+
+ if (next_non_space == NULL)
+ break;
+
+ if (next_non_space->token->type != PASTE) {
+ node = next_non_space;
+ continue;
+ }
+
+ /* Now find the next non-space token after the PASTE. */
+ next_non_space = next_non_space->next;
+ while (next_non_space && next_non_space->token->type == SPACE)
+ next_non_space = next_non_space->next;
+
+ if (next_non_space == NULL) {
+ yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n");
+ return NULL;
+ }
+
+ node->token = _token_paste (parser, node->token, next_non_space->token);
+ node->next = next_non_space->next;
+ if (next_non_space == substituted->tail)
+ substituted->tail = node;
+
+ node = node->next;
+ }
+
+ substituted->non_space_tail = substituted->tail;
+
+ return substituted;
+}
+
+/* Compute the complete expansion of node, (and subsequent nodes after
+ * 'node' in the case that 'node' is a function-like macro and
+ * subsequent nodes are arguments).
+ *
+ * Returns NULL if node is a simple token with no expansion.
+ *
+ * Otherwise, returns the token list that results from the expansion
+ * and sets *last to the last node in the list that was consumed by
+ * the expansion. Specifically, *last will be set as follows:
+ *
+ * As 'node' in the case of object-like macro expansion.
+ *
+ * As the token of the closing right parenthesis in the case of
+ * function-like macro expansion.
+ */
+static token_list_t *
+_glcpp_parser_expand_node (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last)
+{
+ token_t *token = node->token;
+ const char *identifier;
+ macro_t *macro;
+
+ /* We only expand identifiers */
+ if (token->type != IDENTIFIER) {
+ /* We change any COMMA into a COMMA_FINAL to prevent
+ * it being mistaken for an argument separator
+ * later. */
+ if (token->type == ',') {
+ token->type = COMMA_FINAL;
+ token->value.ival = COMMA_FINAL;
+ }
+
+ return NULL;
+ }
+
+ /* Look up this identifier in the hash table. */
+ identifier = token->value.str;
+ macro = hash_table_find (parser->defines, identifier);
+
+ /* Not a macro, so no expansion needed. */
+ if (macro == NULL)
+ return NULL;
+
+ /* Finally, don't expand this macro if we're already actively
+ * expanding it, (to avoid infinite recursion). */
+ if (_active_list_contains (parser->active, identifier)) {
+ /* We change the token type here from IDENTIFIER to
+ * OTHER to prevent any future expansion of this
+ * unexpanded token. */
+ char *str;
+ token_list_t *expansion;
+ token_t *final;
+
+ str = ralloc_strdup (parser, token->value.str);
+ final = _token_create_str (parser, OTHER, str);
+ expansion = _token_list_create (parser);
+ _token_list_append (expansion, final);
+ *last = node;
+ return expansion;
+ }
+
+ if (! macro->is_function)
+ {
+ *last = node;
+
+ /* Replace a macro defined as empty with a SPACE token. */
+ if (macro->replacements == NULL)
+ return _token_list_create_with_one_space (parser);
+
+ return _token_list_copy (parser, macro->replacements);
+ }
+
+ return _glcpp_parser_expand_function (parser, node, last);
+}
+
+/* Push a new identifier onto the active list, returning the new list.
+ *
+ * Here, 'marker' is the token node that appears in the list after the
+ * expansion of 'identifier'. That is, when the list iterator begins
+ * examinging 'marker', then it is time to pop this node from the
+ * active stack.
+ */
+active_list_t *
+_active_list_push (active_list_t *list,
+ const char *identifier,
+ token_node_t *marker)
+{
+ active_list_t *node;
+
+ node = ralloc (list, active_list_t);
+ node->identifier = ralloc_strdup (node, identifier);
+ node->marker = marker;
+ node->next = list;
+
+ return node;
+}
+
+active_list_t *
+_active_list_pop (active_list_t *list)
+{
+ active_list_t *node = list;
+
+ if (node == NULL)
+ return NULL;
+
+ node = list->next;
+ ralloc_free (list);
+
+ return node;
+}
+
+int
+_active_list_contains (active_list_t *list, const char *identifier)
+{
+ active_list_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list; node; node = node->next)
+ if (strcmp (node->identifier, identifier) == 0)
+ return 1;
+
+ return 0;
+}
+
+/* Walk over the token list replacing nodes with their expansion.
+ * Whenever nodes are expanded the walking will walk over the new
+ * nodes, continuing to expand as necessary. The results are placed in
+ * 'list' itself;
+ */
+static void
+_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ token_node_t *node_prev;
+ token_node_t *node, *last = NULL;
+ token_list_t *expansion;
+
+ if (list == NULL)
+ return;
+
+ _token_list_trim_trailing_space (list);
+
+ node_prev = NULL;
+ node = list->head;
+
+ while (node) {
+
+ while (parser->active && parser->active->marker == node)
+ parser->active = _active_list_pop (parser->active);
+
+ /* Find the expansion for node, which will replace all
+ * nodes from node to last, inclusive. */
+ expansion = _glcpp_parser_expand_node (parser, node, &last);
+ if (expansion) {
+ token_node_t *n;
+
+ for (n = node; n != last->next; n = n->next)
+ while (parser->active &&
+ parser->active->marker == n)
+ {
+ parser->active = _active_list_pop (parser->active);
+ }
+
+ parser->active = _active_list_push (parser->active,
+ node->token->value.str,
+ last->next);
+
+ /* Splice expansion into list, supporting a
+ * simple deletion if the expansion is
+ * empty. */
+ if (expansion->head) {
+ if (node_prev)
+ node_prev->next = expansion->head;
+ else
+ list->head = expansion->head;
+ expansion->tail->next = last->next;
+ if (last == list->tail)
+ list->tail = expansion->tail;
+ } else {
+ if (node_prev)
+ node_prev->next = last->next;
+ else
+ list->head = last->next;
+ if (last == list->tail)
+ list->tail = NULL;
+ }
+ } else {
+ node_prev = node;
+ }
+ node = node_prev ? node_prev->next : list->head;
+ }
+
+ while (parser->active)
+ parser->active = _active_list_pop (parser->active);
+
+ list->non_space_tail = list->tail;
+}
+
+void
+_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ if (list == NULL)
+ return;
+
+ _glcpp_parser_expand_token_list (parser, list);
+
+ _token_list_trim_trailing_space (list);
+
+ _token_list_print (parser, list);
+}
+
+static void
+_check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *identifier)
+{
+ /* According to the GLSL specification, macro names starting with "__"
+ * or "GL_" are reserved for future use. So, don't allow them.
+ */
+ if (strncmp(identifier, "__", 2) == 0) {
+ glcpp_error (loc, parser, "Macro names starting with \"__\" are reserved.\n");
+ }
+ if (strncmp(identifier, "GL_", 3) == 0) {
+ glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n");
+ }
+}
+
+static int
+_macro_equal (macro_t *a, macro_t *b)
+{
+ if (a->is_function != b->is_function)
+ return 0;
+
+ if (a->is_function) {
+ if (! _string_list_equal (a->parameters, b->parameters))
+ return 0;
+ }
+
+ return _token_list_equal_ignoring_space (a->replacements,
+ b->replacements);
+}
+
+void
+_define_object_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *identifier,
+ token_list_t *replacements)
+{
+ macro_t *macro, *previous;
+
+ if (loc != NULL)
+ _check_for_reserved_macro_name(parser, loc, identifier);
+
+ macro = ralloc (parser, macro_t);
+
+ macro->is_function = 0;
+ macro->parameters = NULL;
+ macro->identifier = ralloc_strdup (macro, identifier);
+ macro->replacements = replacements;
+ ralloc_steal (macro, replacements);
+
+ previous = hash_table_find (parser->defines, identifier);
+ if (previous) {
+ if (_macro_equal (macro, previous)) {
+ ralloc_free (macro);
+ return;
+ }
+ glcpp_error (loc, parser, "Redefinition of macro %s\n",
+ identifier);
+ }
+
+ hash_table_insert (parser->defines, macro, identifier);
+}
+
+void
+_define_function_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *identifier,
+ string_list_t *parameters,
+ token_list_t *replacements)
+{
+ macro_t *macro, *previous;
+
+ _check_for_reserved_macro_name(parser, loc, identifier);
+
+ macro = ralloc (parser, macro_t);
+ ralloc_steal (macro, parameters);
+ ralloc_steal (macro, replacements);
+
+ macro->is_function = 1;
+ macro->parameters = parameters;
+ macro->identifier = ralloc_strdup (macro, identifier);
+ macro->replacements = replacements;
+ previous = hash_table_find (parser->defines, identifier);
+ if (previous) {
+ if (_macro_equal (macro, previous)) {
+ ralloc_free (macro);
+ return;
+ }
+ glcpp_error (loc, parser, "Redefinition of macro %s\n",
+ identifier);
+ }
+
+ hash_table_insert (parser->defines, macro, identifier);
+}
+
+static int
+glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser)
+{
+ token_node_t *node;
+ int ret;
+
+ if (parser->lex_from_list == NULL) {
+ ret = glcpp_lex (yylval, yylloc, parser->scanner);
+
+ /* XXX: This ugly block of code exists for the sole
+ * purpose of converting a NEWLINE token into a SPACE
+ * token, but only in the case where we have seen a
+ * function-like macro name, but have not yet seen its
+ * closing parenthesis.
+ *
+ * There's perhaps a more compact way to do this with
+ * mid-rule actions in the grammar.
+ *
+ * I'm definitely not pleased with the complexity of
+ * this code here.
+ */
+ if (parser->newline_as_space)
+ {
+ if (ret == '(') {
+ parser->paren_count++;
+ } else if (ret == ')') {
+ parser->paren_count--;
+ if (parser->paren_count == 0)
+ parser->newline_as_space = 0;
+ } else if (ret == NEWLINE) {
+ ret = SPACE;
+ } else if (ret != SPACE) {
+ if (parser->paren_count == 0)
+ parser->newline_as_space = 0;
+ }
+ }
+ else if (parser->in_control_line)
+ {
+ if (ret == NEWLINE)
+ parser->in_control_line = 0;
+ }
+ else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC ||
+ ret == HASH_UNDEF || ret == HASH_IF ||
+ ret == HASH_IFDEF || ret == HASH_IFNDEF ||
+ ret == HASH_ELIF || ret == HASH_ELSE ||
+ ret == HASH_ENDIF || ret == HASH)
+ {
+ parser->in_control_line = 1;
+ }
+ else if (ret == IDENTIFIER)
+ {
+ macro_t *macro;
+ macro = hash_table_find (parser->defines,
+ yylval->str);
+ if (macro && macro->is_function) {
+ parser->newline_as_space = 1;
+ parser->paren_count = 0;
+ }
+ }
+
+ return ret;
+ }
+
+ node = parser->lex_from_node;
+
+ if (node == NULL) {
+ ralloc_free (parser->lex_from_list);
+ parser->lex_from_list = NULL;
+ return NEWLINE;
+ }
+
+ *yylval = node->token->value;
+ ret = node->token->type;
+
+ parser->lex_from_node = node->next;
+
+ return ret;
+}
+
+static void
+glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list)
+{
+ token_node_t *node;
+
+ assert (parser->lex_from_list == NULL);
+
+ /* Copy list, eliminating any space tokens. */
+ parser->lex_from_list = _token_list_create (parser);
+
+ for (node = list->head; node; node = node->next) {
+ if (node->token->type == SPACE)
+ continue;
+ _token_list_append (parser->lex_from_list, node->token);
+ }
+
+ ralloc_free (list);
+
+ parser->lex_from_node = parser->lex_from_list->head;
+
+ /* It's possible the list consisted of nothing but whitespace. */
+ if (parser->lex_from_node == NULL) {
+ ralloc_free (parser->lex_from_list);
+ parser->lex_from_list = NULL;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ int condition)
+{
+ skip_type_t current = SKIP_NO_SKIP;
+ skip_node_t *node;
+
+ if (parser->skip_stack)
+ current = parser->skip_stack->type;
+
+ node = ralloc (parser, skip_node_t);
+ node->loc = *loc;
+
+ if (current == SKIP_NO_SKIP) {
+ if (condition)
+ node->type = SKIP_NO_SKIP;
+ else
+ node->type = SKIP_TO_ELSE;
+ } else {
+ node->type = SKIP_TO_ENDIF;
+ }
+
+ node->next = parser->skip_stack;
+ parser->skip_stack = node;
+}
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *type, int condition)
+{
+ if (parser->skip_stack == NULL) {
+ glcpp_error (loc, parser, "%s without #if\n", type);
+ return;
+ }
+
+ if (parser->skip_stack->type == SKIP_TO_ELSE) {
+ if (condition)
+ parser->skip_stack->type = SKIP_NO_SKIP;
+ } else {
+ parser->skip_stack->type = SKIP_TO_ENDIF;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc)
+{
+ skip_node_t *node;
+
+ if (parser->skip_stack == NULL) {
+ glcpp_error (loc, parser, "#endif without #if\n");
+ return;
+ }
+
+ node = parser->skip_stack;
+ parser->skip_stack = node->next;
+ ralloc_free (node);
+}
diff --git a/mesalib/src/glsl/glcpp/glcpp.c b/mesalib/src/glsl/glcpp/glcpp.c
index 016d7f97e..62065481c 100644
--- a/mesalib/src/glsl/glcpp/glcpp.c
+++ b/mesalib/src/glsl/glcpp/glcpp.c
@@ -1,139 +1,139 @@
-/*
- * 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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include "glcpp.h"
-#include "main/mtypes.h"
-#include "main/shaderobj.h"
-
-#ifdef _MSC_VER
-#include <io.h>
-#define STDIN_FILENO 0
-#define read _read
-#define open _open
-#define close _close
-#endif
-
-extern int yydebug;
-
-void
-_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
- struct gl_shader *sh)
-{
- *ptr = sh;
-}
-
-/* Read from fd until EOF and return a string of everything read.
- */
-static char *
-load_text_fd (void *ctx, int fd)
-{
-#define CHUNK 4096
- char *text = NULL;
- ssize_t text_size = 0;
- ssize_t total_read = 0;
- ssize_t bytes;
-
- while (1) {
- if (total_read + CHUNK + 1 > text_size) {
- text_size = text_size ? text_size * 2 : CHUNK + 1;
- text = talloc_realloc_size (ctx, text, text_size);
- if (text == NULL) {
- fprintf (stderr, "Out of memory\n");
- return NULL;
- }
- }
- bytes = read (fd, text + total_read, CHUNK);
- if (bytes < 0) {
- fprintf (stderr, "Error while reading: %s\n",
- strerror (errno));
- talloc_free (text);
- return NULL;
- }
-
- if (bytes == 0) {
- break;
- }
-
- total_read += bytes;
- }
-
- text[total_read] = '\0';
-
- return text;
-}
-
-static char *
-load_text_file(void *ctx, const char *filename)
-{
- char *text;
- int fd;
-
- if (filename == NULL || strcmp (filename, "-") == 0)
- return load_text_fd (ctx, STDIN_FILENO);
-
- fd = open (filename, O_RDONLY);
- if (fd < 0) {
- fprintf (stderr, "Failed to open file %s: %s\n",
- filename, strerror (errno));
- return NULL;
- }
-
- text = load_text_fd (ctx, fd);
-
- close(fd);
-
- return text;
-}
-
-int
-main (int argc, char *argv[])
-{
- char *filename = NULL;
- void *ctx = talloc(NULL, void*);
- char *info_log = talloc_strdup(ctx, "");
- const char *shader;
- int ret;
-
- if (argc) {
- filename = argv[1];
- }
-
- shader = load_text_file (ctx, filename);
- if (shader == NULL)
- return 1;
-
- ret = preprocess(ctx, &shader, &info_log, NULL, API_OPENGL);
-
- printf("%s", shader);
- fprintf(stderr, "%s", info_log);
-
- talloc_free(ctx);
-
- return ret;
-}
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "glcpp.h"
+#include "main/mtypes.h"
+#include "main/shaderobj.h"
+
+#ifdef _MSC_VER
+#include <io.h>
+#define STDIN_FILENO 0
+#define read _read
+#define open _open
+#define close _close
+#endif
+
+extern int yydebug;
+
+void
+_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
+ struct gl_shader *sh)
+{
+ *ptr = sh;
+}
+
+/* Read from fd until EOF and return a string of everything read.
+ */
+static char *
+load_text_fd (void *ctx, int fd)
+{
+#define CHUNK 4096
+ char *text = NULL;
+ ssize_t text_size = 0;
+ ssize_t total_read = 0;
+ ssize_t bytes;
+
+ while (1) {
+ if (total_read + CHUNK + 1 > text_size) {
+ text_size = text_size ? text_size * 2 : CHUNK + 1;
+ text = reralloc_size (ctx, text, text_size);
+ if (text == NULL) {
+ fprintf (stderr, "Out of memory\n");
+ return NULL;
+ }
+ }
+ bytes = read (fd, text + total_read, CHUNK);
+ if (bytes < 0) {
+ fprintf (stderr, "Error while reading: %s\n",
+ strerror (errno));
+ ralloc_free (text);
+ return NULL;
+ }
+
+ if (bytes == 0) {
+ break;
+ }
+
+ total_read += bytes;
+ }
+
+ text[total_read] = '\0';
+
+ return text;
+}
+
+static char *
+load_text_file(void *ctx, const char *filename)
+{
+ char *text;
+ int fd;
+
+ if (filename == NULL || strcmp (filename, "-") == 0)
+ return load_text_fd (ctx, STDIN_FILENO);
+
+ fd = open (filename, O_RDONLY);
+ if (fd < 0) {
+ fprintf (stderr, "Failed to open file %s: %s\n",
+ filename, strerror (errno));
+ return NULL;
+ }
+
+ text = load_text_fd (ctx, fd);
+
+ close(fd);
+
+ return text;
+}
+
+int
+main (int argc, char *argv[])
+{
+ char *filename = NULL;
+ void *ctx = ralloc(NULL, void*);
+ char *info_log = ralloc_strdup(ctx, "");
+ const char *shader;
+ int ret;
+
+ if (argc) {
+ filename = argv[1];
+ }
+
+ shader = load_text_file (ctx, filename);
+ if (shader == NULL)
+ return 1;
+
+ ret = preprocess(ctx, &shader, &info_log, NULL, API_OPENGL);
+
+ printf("%s", shader);
+ fprintf(stderr, "%s", info_log);
+
+ ralloc_free(ctx);
+
+ return ret;
+}
diff --git a/mesalib/src/glsl/glcpp/glcpp.h b/mesalib/src/glsl/glcpp/glcpp.h
index 7125d325d..dc816e90e 100644
--- a/mesalib/src/glsl/glcpp/glcpp.h
+++ b/mesalib/src/glsl/glcpp/glcpp.h
@@ -26,7 +26,7 @@
#include <stdint.h>
-#include <talloc.h>
+#include "../ralloc.h"
#include "program/hash_table.h"
@@ -189,7 +189,7 @@ void
glcpp_parser_destroy (glcpp_parser_t *parser);
int
-preprocess(void *talloc_ctx, const char **shader, char **info_log,
+preprocess(void *ralloc_ctx, const char **shader, char **info_log,
const struct gl_extensions *extensions, int api);
/* Functions for writing to the info log */
diff --git a/mesalib/src/glsl/glcpp/pp.c b/mesalib/src/glsl/glcpp/pp.c
index e1a3a88a3..3640896a2 100644
--- a/mesalib/src/glsl/glcpp/pp.c
+++ b/mesalib/src/glsl/glcpp/pp.c
@@ -33,16 +33,15 @@ glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
va_list ap;
parser->error = 1;
- parser->info_log = talloc_asprintf_append(parser->info_log,
- "%u:%u(%u): "
+ ralloc_asprintf_append(&parser->info_log, "%u:%u(%u): "
"preprocessor error: ",
locp->source,
locp->first_line,
locp->first_column);
va_start(ap, fmt);
- parser->info_log = talloc_vasprintf_append(parser->info_log, fmt, ap);
+ ralloc_vasprintf_append(&parser->info_log, fmt, ap);
va_end(ap);
- parser->info_log = talloc_strdup_append(parser->info_log, "\n");
+ ralloc_strcat(&parser->info_log, "\n");
}
void
@@ -50,16 +49,15 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
{
va_list ap;
- parser->info_log = talloc_asprintf_append(parser->info_log,
- "%u:%u(%u): "
+ ralloc_asprintf_append(&parser->info_log, "%u:%u(%u): "
"preprocessor warning: ",
locp->source,
locp->first_line,
locp->first_column);
va_start(ap, fmt);
- parser->info_log = talloc_vasprintf_append(parser->info_log, fmt, ap);
+ ralloc_vasprintf_append(&parser->info_log, fmt, ap);
va_end(ap);
- parser->info_log = talloc_strdup_append(parser->info_log, "\n");
+ ralloc_strcat(&parser->info_log, "\n");
}
/* Searches backwards for '^ *#' from a given starting point. */
@@ -92,7 +90,7 @@ remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
{
int in_continued_line = 0;
int extra_newlines = 0;
- char *clean = talloc_strdup(ctx, "");
+ char *clean = ralloc_strdup(ctx, "");
const char *search_start = shader;
const char *newline;
while ((newline = strchr(search_start, '\n')) != NULL) {
@@ -122,27 +120,27 @@ remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
}
if (in_continued_line) {
/* Copy everything before the \ */
- clean = talloc_strndup_append(clean, shader, backslash - shader);
+ ralloc_strncat(&clean, shader, backslash - shader);
shader = newline + 1;
extra_newlines++;
}
} else if (in_continued_line) {
/* Copy everything up to and including the \n */
- clean = talloc_strndup_append(clean, shader, newline - shader + 1);
+ ralloc_strncat(&clean, shader, newline - shader + 1);
shader = newline + 1;
/* Output extra newlines to make line numbers match */
for (; extra_newlines > 0; extra_newlines--)
- clean = talloc_strdup_append(clean, "\n");
+ ralloc_strcat(&clean, "\n");
in_continued_line = 0;
}
search_start = newline + 1;
}
- clean = talloc_strdup_append(clean, shader);
+ ralloc_strcat(&clean, shader);
return clean;
}
int
-preprocess(void *talloc_ctx, const char **shader, char **info_log,
+preprocess(void *ralloc_ctx, const char **shader, char **info_log,
const struct gl_extensions *extensions, int api)
{
int errors;
@@ -156,9 +154,9 @@ preprocess(void *talloc_ctx, const char **shader, char **info_log,
if (parser->skip_stack)
glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n");
- *info_log = talloc_strdup_append(*info_log, parser->info_log);
+ ralloc_strcat(info_log, parser->info_log);
- talloc_steal(talloc_ctx, parser->output);
+ ralloc_steal(ralloc_ctx, parser->output);
*shader = parser->output;
errors = parser->error;
diff --git a/mesalib/src/glsl/glsl_lexer.cpp b/mesalib/src/glsl/glsl_lexer.cpp
index 04a434eb5..04927950f 100644
--- a/mesalib/src/glsl/glsl_lexer.cpp
+++ b/mesalib/src/glsl/glsl_lexer.cpp
@@ -2537,7 +2537,7 @@ YY_RULE_SETUP
{
struct _mesa_glsl_parse_state *state = yyextra;
void *ctx = state;
- yylval->identifier = talloc_strdup(ctx, yytext);
+ yylval->identifier = ralloc_strdup(ctx, yytext);
return IDENTIFIER;
}
YY_BREAK
diff --git a/mesalib/src/glsl/glsl_lexer.lpp b/mesalib/src/glsl/glsl_lexer.lpp
index 4d6866390..d3d53ffb6 100644
--- a/mesalib/src/glsl/glsl_lexer.lpp
+++ b/mesalib/src/glsl/glsl_lexer.lpp
@@ -418,7 +418,7 @@ row_major KEYWORD(130, 999, ROW_MAJOR);
[_a-zA-Z][_a-zA-Z0-9]* {
struct _mesa_glsl_parse_state *state = yyextra;
void *ctx = state;
- yylval->identifier = talloc_strdup(ctx, yytext);
+ yylval->identifier = ralloc_strdup(ctx, yytext);
return IDENTIFIER;
}
diff --git a/mesalib/src/glsl/glsl_parser.cpp b/mesalib/src/glsl/glsl_parser.cpp
index 360676cf8..69435997a 100644
--- a/mesalib/src/glsl/glsl_parser.cpp
+++ b/mesalib/src/glsl/glsl_parser.cpp
@@ -807,34 +807,34 @@ static const yytype_int16 yyrhs[] =
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 213, 213, 212, 219, 221, 246, 247, 248, 249,
- 250, 262, 264, 268, 277, 285, 296, 300, 307, 314,
- 321, 328, 335, 342, 343, 349, 353, 360, 366, 375,
- 379, 383, 384, 393, 394, 398, 399, 403, 409, 421,
- 425, 431, 438, 449, 450, 456, 462, 472, 473, 474,
- 475, 479, 480, 486, 492, 501, 502, 508, 517, 518,
- 524, 533, 534, 540, 546, 552, 561, 562, 568, 577,
- 578, 587, 588, 597, 598, 607, 608, 617, 618, 627,
- 628, 637, 638, 647, 648, 657, 658, 659, 660, 661,
- 662, 663, 664, 665, 666, 667, 671, 675, 691, 695,
- 699, 703, 712, 716, 717, 721, 726, 734, 745, 755,
- 770, 777, 782, 793, 806, 809, 814, 819, 828, 832,
- 833, 842, 851, 860, 869, 878, 891, 902, 911, 920,
- 929, 938, 947, 956, 970, 977, 988, 995, 996, 1015,
- 1067, 1108, 1113, 1118, 1126, 1134, 1135, 1136, 1141, 1142,
- 1147, 1152, 1158, 1166, 1171, 1176, 1181, 1187, 1192, 1197,
- 1202, 1207, 1215, 1219, 1227, 1228, 1234, 1243, 1249, 1255,
- 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273,
- 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283,
- 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293,
- 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303,
- 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313,
- 1314, 1318, 1328, 1338, 1351, 1357, 1366, 1371, 1379, 1394,
- 1399, 1407, 1413, 1422, 1426, 1432, 1433, 1437, 1438, 1439,
- 1440, 1441, 1442, 1443, 1447, 1453, 1462, 1463, 1467, 1473,
- 1482, 1492, 1504, 1510, 1519, 1528, 1533, 1541, 1545, 1559,
- 1563, 1564, 1568, 1575, 1582, 1592, 1593, 1597, 1599, 1605,
- 1610, 1619, 1625, 1631, 1637, 1643, 1652, 1653, 1654, 1658
+ 0, 213, 213, 212, 219, 221, 261, 262, 263, 264,
+ 265, 277, 279, 283, 292, 300, 311, 315, 322, 329,
+ 336, 343, 350, 357, 358, 364, 368, 375, 381, 390,
+ 394, 398, 399, 408, 409, 413, 414, 418, 424, 436,
+ 440, 446, 453, 464, 465, 471, 477, 487, 488, 489,
+ 490, 494, 495, 501, 507, 516, 517, 523, 532, 533,
+ 539, 548, 549, 555, 561, 567, 576, 577, 583, 592,
+ 593, 602, 603, 612, 613, 622, 623, 632, 633, 642,
+ 643, 652, 653, 662, 663, 672, 673, 674, 675, 676,
+ 677, 678, 679, 680, 681, 682, 686, 690, 706, 710,
+ 714, 718, 727, 731, 732, 736, 741, 749, 760, 770,
+ 785, 792, 797, 808, 821, 824, 829, 834, 843, 847,
+ 848, 857, 866, 875, 884, 893, 906, 917, 926, 935,
+ 944, 953, 962, 971, 985, 992, 1003, 1010, 1011, 1030,
+ 1082, 1123, 1128, 1133, 1141, 1149, 1150, 1151, 1156, 1157,
+ 1162, 1167, 1173, 1181, 1186, 1191, 1196, 1202, 1207, 1212,
+ 1217, 1222, 1230, 1234, 1242, 1243, 1249, 1258, 1264, 1270,
+ 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288,
+ 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298,
+ 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308,
+ 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318,
+ 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328,
+ 1329, 1333, 1343, 1353, 1366, 1372, 1381, 1386, 1394, 1409,
+ 1414, 1422, 1428, 1437, 1441, 1447, 1448, 1452, 1453, 1454,
+ 1455, 1456, 1457, 1458, 1462, 1468, 1477, 1478, 1482, 1488,
+ 1497, 1507, 1519, 1525, 1534, 1543, 1548, 1556, 1560, 1574,
+ 1578, 1579, 1583, 1590, 1597, 1607, 1608, 1612, 1614, 1620,
+ 1625, 1634, 1640, 1646, 1652, 1658, 1667, 1668, 1669, 1673
};
#endif
@@ -2835,32 +2835,47 @@ yyreduce:
/* Line 1464 of yacc.c */
#line 222 "glsl_parser.ypp"
{
+ bool supported = false;
+
switch ((yyvsp[(2) - (3)].n)) {
case 100:
state->es_shader = true;
+ supported = state->Const.GLSL_100ES;
+ break;
case 110:
+ supported = state->Const.GLSL_110;
+ break;
case 120:
+ supported = state->Const.GLSL_120;
+ break;
case 130:
- /* FINISHME: Check against implementation support versions. */
- state->language_version = (yyvsp[(2) - (3)].n);
- state->version_string =
- talloc_asprintf(state, "GLSL%s %d.%02d",
- state->es_shader ? " ES" : "",
- state->language_version / 100,
- state->language_version % 100);
+ supported = state->Const.GLSL_130;
break;
default:
- _mesa_glsl_error(& (yylsp[(2) - (3)]), state, "Shading language version"
- "%u is not supported\n", (yyvsp[(2) - (3)].n));
+ supported = false;
break;
}
+
+ state->language_version = (yyvsp[(2) - (3)].n);
+ state->version_string =
+ ralloc_asprintf(state, "GLSL%s %d.%02d",
+ state->es_shader ? " ES" : "",
+ state->language_version / 100,
+ state->language_version % 100);
+
+ if (!supported) {
+ _mesa_glsl_error(& (yylsp[(2) - (3)]), state, "%s is not supported. "
+ "Supported versions are: %s\n",
+ state->version_string,
+ state->supported_version_string);
+ }
;}
break;
case 10:
/* Line 1464 of yacc.c */
-#line 251 "glsl_parser.ypp"
+#line 266 "glsl_parser.ypp"
{
if (state->language_version < 120) {
_mesa_glsl_warning(& (yylsp[(1) - (2)]), state,
@@ -2875,7 +2890,7 @@ yyreduce:
case 13:
/* Line 1464 of yacc.c */
-#line 269 "glsl_parser.ypp"
+#line 284 "glsl_parser.ypp"
{
if (!_mesa_glsl_process_extension((yyvsp[(2) - (5)].identifier), & (yylsp[(2) - (5)]), (yyvsp[(4) - (5)].identifier), & (yylsp[(4) - (5)]), state)) {
YYERROR;
@@ -2886,7 +2901,7 @@ yyreduce:
case 14:
/* Line 1464 of yacc.c */
-#line 278 "glsl_parser.ypp"
+#line 293 "glsl_parser.ypp"
{
/* FINISHME: The NULL test is required because pragmas are set to
* FINISHME: NULL. (See production rule for external_declaration.)
@@ -2899,7 +2914,7 @@ yyreduce:
case 15:
/* Line 1464 of yacc.c */
-#line 286 "glsl_parser.ypp"
+#line 301 "glsl_parser.ypp"
{
/* FINISHME: The NULL test is required because pragmas are set to
* FINISHME: NULL. (See production rule for external_declaration.)
@@ -2912,7 +2927,7 @@ yyreduce:
case 17:
/* Line 1464 of yacc.c */
-#line 301 "glsl_parser.ypp"
+#line 316 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_identifier, NULL, NULL, NULL);
@@ -2924,7 +2939,7 @@ yyreduce:
case 18:
/* Line 1464 of yacc.c */
-#line 308 "glsl_parser.ypp"
+#line 323 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_int_constant, NULL, NULL, NULL);
@@ -2936,7 +2951,7 @@ yyreduce:
case 19:
/* Line 1464 of yacc.c */
-#line 315 "glsl_parser.ypp"
+#line 330 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_uint_constant, NULL, NULL, NULL);
@@ -2948,7 +2963,7 @@ yyreduce:
case 20:
/* Line 1464 of yacc.c */
-#line 322 "glsl_parser.ypp"
+#line 337 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_float_constant, NULL, NULL, NULL);
@@ -2960,7 +2975,7 @@ yyreduce:
case 21:
/* Line 1464 of yacc.c */
-#line 329 "glsl_parser.ypp"
+#line 344 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_bool_constant, NULL, NULL, NULL);
@@ -2972,7 +2987,7 @@ yyreduce:
case 22:
/* Line 1464 of yacc.c */
-#line 336 "glsl_parser.ypp"
+#line 351 "glsl_parser.ypp"
{
(yyval.expression) = (yyvsp[(2) - (3)].expression);
;}
@@ -2981,7 +2996,7 @@ yyreduce:
case 24:
/* Line 1464 of yacc.c */
-#line 344 "glsl_parser.ypp"
+#line 359 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_array_index, (yyvsp[(1) - (4)].expression), (yyvsp[(3) - (4)].expression), NULL);
@@ -2992,7 +3007,7 @@ yyreduce:
case 25:
/* Line 1464 of yacc.c */
-#line 350 "glsl_parser.ypp"
+#line 365 "glsl_parser.ypp"
{
(yyval.expression) = (yyvsp[(1) - (1)].expression);
;}
@@ -3001,7 +3016,7 @@ yyreduce:
case 26:
/* Line 1464 of yacc.c */
-#line 354 "glsl_parser.ypp"
+#line 369 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_field_selection, (yyvsp[(1) - (3)].expression), NULL, NULL);
@@ -3013,7 +3028,7 @@ yyreduce:
case 27:
/* Line 1464 of yacc.c */
-#line 361 "glsl_parser.ypp"
+#line 376 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_post_inc, (yyvsp[(1) - (2)].expression), NULL, NULL);
@@ -3024,7 +3039,7 @@ yyreduce:
case 28:
/* Line 1464 of yacc.c */
-#line 367 "glsl_parser.ypp"
+#line 382 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_post_dec, (yyvsp[(1) - (2)].expression), NULL, NULL);
@@ -3035,7 +3050,7 @@ yyreduce:
case 32:
/* Line 1464 of yacc.c */
-#line 385 "glsl_parser.ypp"
+#line 400 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_field_selection, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression), NULL);
@@ -3046,7 +3061,7 @@ yyreduce:
case 37:
/* Line 1464 of yacc.c */
-#line 404 "glsl_parser.ypp"
+#line 419 "glsl_parser.ypp"
{
(yyval.expression) = (yyvsp[(1) - (2)].expression);
(yyval.expression)->set_location(yylloc);
@@ -3057,7 +3072,7 @@ yyreduce:
case 38:
/* Line 1464 of yacc.c */
-#line 410 "glsl_parser.ypp"
+#line 425 "glsl_parser.ypp"
{
(yyval.expression) = (yyvsp[(1) - (3)].expression);
(yyval.expression)->set_location(yylloc);
@@ -3068,7 +3083,7 @@ yyreduce:
case 40:
/* Line 1464 of yacc.c */
-#line 426 "glsl_parser.ypp"
+#line 441 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_function_expression((yyvsp[(1) - (1)].type_specifier));
@@ -3079,7 +3094,7 @@ yyreduce:
case 41:
/* Line 1464 of yacc.c */
-#line 432 "glsl_parser.ypp"
+#line 447 "glsl_parser.ypp"
{
void *ctx = state;
ast_expression *callee = new(ctx) ast_expression((yyvsp[(1) - (1)].identifier));
@@ -3091,7 +3106,7 @@ yyreduce:
case 42:
/* Line 1464 of yacc.c */
-#line 439 "glsl_parser.ypp"
+#line 454 "glsl_parser.ypp"
{
void *ctx = state;
ast_expression *callee = new(ctx) ast_expression((yyvsp[(1) - (1)].identifier));
@@ -3103,7 +3118,7 @@ yyreduce:
case 44:
/* Line 1464 of yacc.c */
-#line 451 "glsl_parser.ypp"
+#line 466 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_pre_inc, (yyvsp[(2) - (2)].expression), NULL, NULL);
@@ -3114,7 +3129,7 @@ yyreduce:
case 45:
/* Line 1464 of yacc.c */
-#line 457 "glsl_parser.ypp"
+#line 472 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_pre_dec, (yyvsp[(2) - (2)].expression), NULL, NULL);
@@ -3125,7 +3140,7 @@ yyreduce:
case 46:
/* Line 1464 of yacc.c */
-#line 463 "glsl_parser.ypp"
+#line 478 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression((yyvsp[(1) - (2)].n), (yyvsp[(2) - (2)].expression), NULL, NULL);
@@ -3136,35 +3151,35 @@ yyreduce:
case 47:
/* Line 1464 of yacc.c */
-#line 472 "glsl_parser.ypp"
+#line 487 "glsl_parser.ypp"
{ (yyval.n) = ast_plus; ;}
break;
case 48:
/* Line 1464 of yacc.c */
-#line 473 "glsl_parser.ypp"
+#line 488 "glsl_parser.ypp"
{ (yyval.n) = ast_neg; ;}
break;
case 49:
/* Line 1464 of yacc.c */
-#line 474 "glsl_parser.ypp"
+#line 489 "glsl_parser.ypp"
{ (yyval.n) = ast_logic_not; ;}
break;
case 50:
/* Line 1464 of yacc.c */
-#line 475 "glsl_parser.ypp"
+#line 490 "glsl_parser.ypp"
{ (yyval.n) = ast_bit_not; ;}
break;
case 52:
/* Line 1464 of yacc.c */
-#line 481 "glsl_parser.ypp"
+#line 496 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_mul, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3175,7 +3190,7 @@ yyreduce:
case 53:
/* Line 1464 of yacc.c */
-#line 487 "glsl_parser.ypp"
+#line 502 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_div, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3186,7 +3201,7 @@ yyreduce:
case 54:
/* Line 1464 of yacc.c */
-#line 493 "glsl_parser.ypp"
+#line 508 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_mod, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3197,7 +3212,7 @@ yyreduce:
case 56:
/* Line 1464 of yacc.c */
-#line 503 "glsl_parser.ypp"
+#line 518 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_add, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3208,7 +3223,7 @@ yyreduce:
case 57:
/* Line 1464 of yacc.c */
-#line 509 "glsl_parser.ypp"
+#line 524 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_sub, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3219,7 +3234,7 @@ yyreduce:
case 59:
/* Line 1464 of yacc.c */
-#line 519 "glsl_parser.ypp"
+#line 534 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_lshift, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3230,7 +3245,7 @@ yyreduce:
case 60:
/* Line 1464 of yacc.c */
-#line 525 "glsl_parser.ypp"
+#line 540 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_rshift, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3241,7 +3256,7 @@ yyreduce:
case 62:
/* Line 1464 of yacc.c */
-#line 535 "glsl_parser.ypp"
+#line 550 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_less, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3252,7 +3267,7 @@ yyreduce:
case 63:
/* Line 1464 of yacc.c */
-#line 541 "glsl_parser.ypp"
+#line 556 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_greater, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3263,7 +3278,7 @@ yyreduce:
case 64:
/* Line 1464 of yacc.c */
-#line 547 "glsl_parser.ypp"
+#line 562 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_lequal, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3274,7 +3289,7 @@ yyreduce:
case 65:
/* Line 1464 of yacc.c */
-#line 553 "glsl_parser.ypp"
+#line 568 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_gequal, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3285,7 +3300,7 @@ yyreduce:
case 67:
/* Line 1464 of yacc.c */
-#line 563 "glsl_parser.ypp"
+#line 578 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_equal, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3296,7 +3311,7 @@ yyreduce:
case 68:
/* Line 1464 of yacc.c */
-#line 569 "glsl_parser.ypp"
+#line 584 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_nequal, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3307,7 +3322,7 @@ yyreduce:
case 70:
/* Line 1464 of yacc.c */
-#line 579 "glsl_parser.ypp"
+#line 594 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_bit_and, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3318,7 +3333,7 @@ yyreduce:
case 72:
/* Line 1464 of yacc.c */
-#line 589 "glsl_parser.ypp"
+#line 604 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_bit_xor, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3329,7 +3344,7 @@ yyreduce:
case 74:
/* Line 1464 of yacc.c */
-#line 599 "glsl_parser.ypp"
+#line 614 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_bit_or, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3340,7 +3355,7 @@ yyreduce:
case 76:
/* Line 1464 of yacc.c */
-#line 609 "glsl_parser.ypp"
+#line 624 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_logic_and, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3351,7 +3366,7 @@ yyreduce:
case 78:
/* Line 1464 of yacc.c */
-#line 619 "glsl_parser.ypp"
+#line 634 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_logic_xor, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3362,7 +3377,7 @@ yyreduce:
case 80:
/* Line 1464 of yacc.c */
-#line 629 "glsl_parser.ypp"
+#line 644 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression_bin(ast_logic_or, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression));
@@ -3373,7 +3388,7 @@ yyreduce:
case 82:
/* Line 1464 of yacc.c */
-#line 639 "glsl_parser.ypp"
+#line 654 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression(ast_conditional, (yyvsp[(1) - (5)].expression), (yyvsp[(3) - (5)].expression), (yyvsp[(5) - (5)].expression));
@@ -3384,7 +3399,7 @@ yyreduce:
case 84:
/* Line 1464 of yacc.c */
-#line 649 "glsl_parser.ypp"
+#line 664 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.expression) = new(ctx) ast_expression((yyvsp[(2) - (3)].n), (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression), NULL);
@@ -3395,84 +3410,84 @@ yyreduce:
case 85:
/* Line 1464 of yacc.c */
-#line 657 "glsl_parser.ypp"
+#line 672 "glsl_parser.ypp"
{ (yyval.n) = ast_assign; ;}
break;
case 86:
/* Line 1464 of yacc.c */
-#line 658 "glsl_parser.ypp"
+#line 673 "glsl_parser.ypp"
{ (yyval.n) = ast_mul_assign; ;}
break;
case 87:
/* Line 1464 of yacc.c */
-#line 659 "glsl_parser.ypp"
+#line 674 "glsl_parser.ypp"
{ (yyval.n) = ast_div_assign; ;}
break;
case 88:
/* Line 1464 of yacc.c */
-#line 660 "glsl_parser.ypp"
+#line 675 "glsl_parser.ypp"
{ (yyval.n) = ast_mod_assign; ;}
break;
case 89:
/* Line 1464 of yacc.c */
-#line 661 "glsl_parser.ypp"
+#line 676 "glsl_parser.ypp"
{ (yyval.n) = ast_add_assign; ;}
break;
case 90:
/* Line 1464 of yacc.c */
-#line 662 "glsl_parser.ypp"
+#line 677 "glsl_parser.ypp"
{ (yyval.n) = ast_sub_assign; ;}
break;
case 91:
/* Line 1464 of yacc.c */
-#line 663 "glsl_parser.ypp"
+#line 678 "glsl_parser.ypp"
{ (yyval.n) = ast_ls_assign; ;}
break;
case 92:
/* Line 1464 of yacc.c */
-#line 664 "glsl_parser.ypp"
+#line 679 "glsl_parser.ypp"
{ (yyval.n) = ast_rs_assign; ;}
break;
case 93:
/* Line 1464 of yacc.c */
-#line 665 "glsl_parser.ypp"
+#line 680 "glsl_parser.ypp"
{ (yyval.n) = ast_and_assign; ;}
break;
case 94:
/* Line 1464 of yacc.c */
-#line 666 "glsl_parser.ypp"
+#line 681 "glsl_parser.ypp"
{ (yyval.n) = ast_xor_assign; ;}
break;
case 95:
/* Line 1464 of yacc.c */
-#line 667 "glsl_parser.ypp"
+#line 682 "glsl_parser.ypp"
{ (yyval.n) = ast_or_assign; ;}
break;
case 96:
/* Line 1464 of yacc.c */
-#line 672 "glsl_parser.ypp"
+#line 687 "glsl_parser.ypp"
{
(yyval.expression) = (yyvsp[(1) - (1)].expression);
;}
@@ -3481,7 +3496,7 @@ yyreduce:
case 97:
/* Line 1464 of yacc.c */
-#line 676 "glsl_parser.ypp"
+#line 691 "glsl_parser.ypp"
{
void *ctx = state;
if ((yyvsp[(1) - (3)].expression)->oper != ast_sequence) {
@@ -3499,7 +3514,7 @@ yyreduce:
case 99:
/* Line 1464 of yacc.c */
-#line 696 "glsl_parser.ypp"
+#line 711 "glsl_parser.ypp"
{
(yyval.node) = (yyvsp[(1) - (2)].function);
;}
@@ -3508,7 +3523,7 @@ yyreduce:
case 100:
/* Line 1464 of yacc.c */
-#line 700 "glsl_parser.ypp"
+#line 715 "glsl_parser.ypp"
{
(yyval.node) = (yyvsp[(1) - (2)].declarator_list);
;}
@@ -3517,7 +3532,7 @@ yyreduce:
case 101:
/* Line 1464 of yacc.c */
-#line 704 "glsl_parser.ypp"
+#line 719 "glsl_parser.ypp"
{
(yyvsp[(3) - (4)].type_specifier)->precision = (yyvsp[(2) - (4)].n);
(yyvsp[(3) - (4)].type_specifier)->is_precision_statement = true;
@@ -3528,7 +3543,7 @@ yyreduce:
case 105:
/* Line 1464 of yacc.c */
-#line 722 "glsl_parser.ypp"
+#line 737 "glsl_parser.ypp"
{
(yyval.function) = (yyvsp[(1) - (2)].function);
(yyval.function)->parameters.push_tail(& (yyvsp[(2) - (2)].parameter_declarator)->link);
@@ -3538,7 +3553,7 @@ yyreduce:
case 106:
/* Line 1464 of yacc.c */
-#line 727 "glsl_parser.ypp"
+#line 742 "glsl_parser.ypp"
{
(yyval.function) = (yyvsp[(1) - (3)].function);
(yyval.function)->parameters.push_tail(& (yyvsp[(3) - (3)].parameter_declarator)->link);
@@ -3548,7 +3563,7 @@ yyreduce:
case 107:
/* Line 1464 of yacc.c */
-#line 735 "glsl_parser.ypp"
+#line 750 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.function) = new(ctx) ast_function();
@@ -3561,7 +3576,7 @@ yyreduce:
case 108:
/* Line 1464 of yacc.c */
-#line 746 "glsl_parser.ypp"
+#line 761 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.parameter_declarator) = new(ctx) ast_parameter_declarator();
@@ -3576,7 +3591,7 @@ yyreduce:
case 109:
/* Line 1464 of yacc.c */
-#line 756 "glsl_parser.ypp"
+#line 771 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.parameter_declarator) = new(ctx) ast_parameter_declarator();
@@ -3593,7 +3608,7 @@ yyreduce:
case 110:
/* Line 1464 of yacc.c */
-#line 771 "glsl_parser.ypp"
+#line 786 "glsl_parser.ypp"
{
(yyvsp[(1) - (3)].type_qualifier).flags.i |= (yyvsp[(2) - (3)].type_qualifier).flags.i;
@@ -3605,7 +3620,7 @@ yyreduce:
case 111:
/* Line 1464 of yacc.c */
-#line 778 "glsl_parser.ypp"
+#line 793 "glsl_parser.ypp"
{
(yyval.parameter_declarator) = (yyvsp[(2) - (2)].parameter_declarator);
(yyval.parameter_declarator)->type->qualifier = (yyvsp[(1) - (2)].type_qualifier);
@@ -3615,7 +3630,7 @@ yyreduce:
case 112:
/* Line 1464 of yacc.c */
-#line 783 "glsl_parser.ypp"
+#line 798 "glsl_parser.ypp"
{
void *ctx = state;
(yyvsp[(1) - (3)].type_qualifier).flags.i |= (yyvsp[(2) - (3)].type_qualifier).flags.i;
@@ -3631,7 +3646,7 @@ yyreduce:
case 113:
/* Line 1464 of yacc.c */
-#line 794 "glsl_parser.ypp"
+#line 809 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.parameter_declarator) = new(ctx) ast_parameter_declarator();
@@ -3645,7 +3660,7 @@ yyreduce:
case 114:
/* Line 1464 of yacc.c */
-#line 806 "glsl_parser.ypp"
+#line 821 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
;}
@@ -3654,7 +3669,7 @@ yyreduce:
case 115:
/* Line 1464 of yacc.c */
-#line 810 "glsl_parser.ypp"
+#line 825 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.in = 1;
@@ -3664,7 +3679,7 @@ yyreduce:
case 116:
/* Line 1464 of yacc.c */
-#line 815 "glsl_parser.ypp"
+#line 830 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.out = 1;
@@ -3674,7 +3689,7 @@ yyreduce:
case 117:
/* Line 1464 of yacc.c */
-#line 820 "glsl_parser.ypp"
+#line 835 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.in = 1;
@@ -3685,7 +3700,7 @@ yyreduce:
case 120:
/* Line 1464 of yacc.c */
-#line 834 "glsl_parser.ypp"
+#line 849 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (3)].identifier), false, NULL, NULL);
@@ -3699,7 +3714,7 @@ yyreduce:
case 121:
/* Line 1464 of yacc.c */
-#line 843 "glsl_parser.ypp"
+#line 858 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (5)].identifier), true, NULL, NULL);
@@ -3713,7 +3728,7 @@ yyreduce:
case 122:
/* Line 1464 of yacc.c */
-#line 852 "glsl_parser.ypp"
+#line 867 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (6)].identifier), true, (yyvsp[(5) - (6)].expression), NULL);
@@ -3727,7 +3742,7 @@ yyreduce:
case 123:
/* Line 1464 of yacc.c */
-#line 861 "glsl_parser.ypp"
+#line 876 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (7)].identifier), true, NULL, (yyvsp[(7) - (7)].expression));
@@ -3741,7 +3756,7 @@ yyreduce:
case 124:
/* Line 1464 of yacc.c */
-#line 870 "glsl_parser.ypp"
+#line 885 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (8)].identifier), true, (yyvsp[(5) - (8)].expression), (yyvsp[(8) - (8)].expression));
@@ -3755,7 +3770,7 @@ yyreduce:
case 125:
/* Line 1464 of yacc.c */
-#line 879 "glsl_parser.ypp"
+#line 894 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (5)].identifier), false, NULL, (yyvsp[(5) - (5)].expression));
@@ -3769,7 +3784,7 @@ yyreduce:
case 126:
/* Line 1464 of yacc.c */
-#line 892 "glsl_parser.ypp"
+#line 907 "glsl_parser.ypp"
{
void *ctx = state;
if ((yyvsp[(1) - (1)].fully_specified_type)->specifier->type_specifier != ast_struct) {
@@ -3785,7 +3800,7 @@ yyreduce:
case 127:
/* Line 1464 of yacc.c */
-#line 903 "glsl_parser.ypp"
+#line 918 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (2)].identifier), false, NULL, NULL);
@@ -3799,7 +3814,7 @@ yyreduce:
case 128:
/* Line 1464 of yacc.c */
-#line 912 "glsl_parser.ypp"
+#line 927 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (4)].identifier), true, NULL, NULL);
@@ -3813,7 +3828,7 @@ yyreduce:
case 129:
/* Line 1464 of yacc.c */
-#line 921 "glsl_parser.ypp"
+#line 936 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (5)].identifier), true, (yyvsp[(4) - (5)].expression), NULL);
@@ -3827,7 +3842,7 @@ yyreduce:
case 130:
/* Line 1464 of yacc.c */
-#line 930 "glsl_parser.ypp"
+#line 945 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (6)].identifier), true, NULL, (yyvsp[(6) - (6)].expression));
@@ -3841,7 +3856,7 @@ yyreduce:
case 131:
/* Line 1464 of yacc.c */
-#line 939 "glsl_parser.ypp"
+#line 954 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (7)].identifier), true, (yyvsp[(4) - (7)].expression), (yyvsp[(7) - (7)].expression));
@@ -3855,7 +3870,7 @@ yyreduce:
case 132:
/* Line 1464 of yacc.c */
-#line 948 "glsl_parser.ypp"
+#line 963 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (4)].identifier), false, NULL, (yyvsp[(4) - (4)].expression));
@@ -3869,7 +3884,7 @@ yyreduce:
case 133:
/* Line 1464 of yacc.c */
-#line 957 "glsl_parser.ypp"
+#line 972 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (2)].identifier), false, NULL, NULL);
@@ -3885,7 +3900,7 @@ yyreduce:
case 134:
/* Line 1464 of yacc.c */
-#line 971 "glsl_parser.ypp"
+#line 986 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.fully_specified_type) = new(ctx) ast_fully_specified_type();
@@ -3897,7 +3912,7 @@ yyreduce:
case 135:
/* Line 1464 of yacc.c */
-#line 978 "glsl_parser.ypp"
+#line 993 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.fully_specified_type) = new(ctx) ast_fully_specified_type();
@@ -3910,7 +3925,7 @@ yyreduce:
case 136:
/* Line 1464 of yacc.c */
-#line 989 "glsl_parser.ypp"
+#line 1004 "glsl_parser.ypp"
{
(yyval.type_qualifier) = (yyvsp[(3) - (4)].type_qualifier);
;}
@@ -3919,7 +3934,7 @@ yyreduce:
case 138:
/* Line 1464 of yacc.c */
-#line 997 "glsl_parser.ypp"
+#line 1012 "glsl_parser.ypp"
{
if (((yyvsp[(1) - (3)].type_qualifier).flags.i & (yyvsp[(3) - (3)].type_qualifier).flags.i) != 0) {
_mesa_glsl_error(& (yylsp[(3) - (3)]), state,
@@ -3940,7 +3955,7 @@ yyreduce:
case 139:
/* Line 1464 of yacc.c */
-#line 1016 "glsl_parser.ypp"
+#line 1031 "glsl_parser.ypp"
{
bool got_one = false;
@@ -3997,7 +4012,7 @@ yyreduce:
case 140:
/* Line 1464 of yacc.c */
-#line 1068 "glsl_parser.ypp"
+#line 1083 "glsl_parser.ypp"
{
bool got_one = false;
@@ -4040,7 +4055,7 @@ yyreduce:
case 141:
/* Line 1464 of yacc.c */
-#line 1109 "glsl_parser.ypp"
+#line 1124 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.smooth = 1;
@@ -4050,7 +4065,7 @@ yyreduce:
case 142:
/* Line 1464 of yacc.c */
-#line 1114 "glsl_parser.ypp"
+#line 1129 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.flat = 1;
@@ -4060,7 +4075,7 @@ yyreduce:
case 143:
/* Line 1464 of yacc.c */
-#line 1119 "glsl_parser.ypp"
+#line 1134 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.noperspective = 1;
@@ -4070,7 +4085,7 @@ yyreduce:
case 144:
/* Line 1464 of yacc.c */
-#line 1127 "glsl_parser.ypp"
+#line 1142 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.constant = 1;
@@ -4080,7 +4095,7 @@ yyreduce:
case 147:
/* Line 1464 of yacc.c */
-#line 1137 "glsl_parser.ypp"
+#line 1152 "glsl_parser.ypp"
{
(yyval.type_qualifier) = (yyvsp[(1) - (2)].type_qualifier);
(yyval.type_qualifier).flags.i |= (yyvsp[(2) - (2)].type_qualifier).flags.i;
@@ -4090,7 +4105,7 @@ yyreduce:
case 149:
/* Line 1464 of yacc.c */
-#line 1143 "glsl_parser.ypp"
+#line 1158 "glsl_parser.ypp"
{
(yyval.type_qualifier) = (yyvsp[(1) - (2)].type_qualifier);
(yyval.type_qualifier).flags.i |= (yyvsp[(2) - (2)].type_qualifier).flags.i;
@@ -4100,7 +4115,7 @@ yyreduce:
case 150:
/* Line 1464 of yacc.c */
-#line 1148 "glsl_parser.ypp"
+#line 1163 "glsl_parser.ypp"
{
(yyval.type_qualifier) = (yyvsp[(2) - (2)].type_qualifier);
(yyval.type_qualifier).flags.q.invariant = 1;
@@ -4110,7 +4125,7 @@ yyreduce:
case 151:
/* Line 1464 of yacc.c */
-#line 1153 "glsl_parser.ypp"
+#line 1168 "glsl_parser.ypp"
{
(yyval.type_qualifier) = (yyvsp[(2) - (3)].type_qualifier);
(yyval.type_qualifier).flags.i |= (yyvsp[(3) - (3)].type_qualifier).flags.i;
@@ -4121,7 +4136,7 @@ yyreduce:
case 152:
/* Line 1464 of yacc.c */
-#line 1159 "glsl_parser.ypp"
+#line 1174 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.invariant = 1;
@@ -4131,7 +4146,7 @@ yyreduce:
case 153:
/* Line 1464 of yacc.c */
-#line 1167 "glsl_parser.ypp"
+#line 1182 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.constant = 1;
@@ -4141,7 +4156,7 @@ yyreduce:
case 154:
/* Line 1464 of yacc.c */
-#line 1172 "glsl_parser.ypp"
+#line 1187 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.attribute = 1;
@@ -4151,7 +4166,7 @@ yyreduce:
case 155:
/* Line 1464 of yacc.c */
-#line 1177 "glsl_parser.ypp"
+#line 1192 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.varying = 1;
@@ -4161,7 +4176,7 @@ yyreduce:
case 156:
/* Line 1464 of yacc.c */
-#line 1182 "glsl_parser.ypp"
+#line 1197 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.centroid = 1;
@@ -4172,7 +4187,7 @@ yyreduce:
case 157:
/* Line 1464 of yacc.c */
-#line 1188 "glsl_parser.ypp"
+#line 1203 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.in = 1;
@@ -4182,7 +4197,7 @@ yyreduce:
case 158:
/* Line 1464 of yacc.c */
-#line 1193 "glsl_parser.ypp"
+#line 1208 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.out = 1;
@@ -4192,7 +4207,7 @@ yyreduce:
case 159:
/* Line 1464 of yacc.c */
-#line 1198 "glsl_parser.ypp"
+#line 1213 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.centroid = 1; (yyval.type_qualifier).flags.q.in = 1;
@@ -4202,7 +4217,7 @@ yyreduce:
case 160:
/* Line 1464 of yacc.c */
-#line 1203 "glsl_parser.ypp"
+#line 1218 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.centroid = 1; (yyval.type_qualifier).flags.q.out = 1;
@@ -4212,7 +4227,7 @@ yyreduce:
case 161:
/* Line 1464 of yacc.c */
-#line 1208 "glsl_parser.ypp"
+#line 1223 "glsl_parser.ypp"
{
memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier)));
(yyval.type_qualifier).flags.q.uniform = 1;
@@ -4222,7 +4237,7 @@ yyreduce:
case 162:
/* Line 1464 of yacc.c */
-#line 1216 "glsl_parser.ypp"
+#line 1231 "glsl_parser.ypp"
{
(yyval.type_specifier) = (yyvsp[(1) - (1)].type_specifier);
;}
@@ -4231,7 +4246,7 @@ yyreduce:
case 163:
/* Line 1464 of yacc.c */
-#line 1220 "glsl_parser.ypp"
+#line 1235 "glsl_parser.ypp"
{
(yyval.type_specifier) = (yyvsp[(2) - (2)].type_specifier);
(yyval.type_specifier)->precision = (yyvsp[(1) - (2)].n);
@@ -4241,7 +4256,7 @@ yyreduce:
case 165:
/* Line 1464 of yacc.c */
-#line 1229 "glsl_parser.ypp"
+#line 1244 "glsl_parser.ypp"
{
(yyval.type_specifier) = (yyvsp[(1) - (3)].type_specifier);
(yyval.type_specifier)->is_array = true;
@@ -4252,7 +4267,7 @@ yyreduce:
case 166:
/* Line 1464 of yacc.c */
-#line 1235 "glsl_parser.ypp"
+#line 1250 "glsl_parser.ypp"
{
(yyval.type_specifier) = (yyvsp[(1) - (4)].type_specifier);
(yyval.type_specifier)->is_array = true;
@@ -4263,7 +4278,7 @@ yyreduce:
case 167:
/* Line 1464 of yacc.c */
-#line 1244 "glsl_parser.ypp"
+#line 1259 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.type_specifier) = new(ctx) ast_type_specifier((yyvsp[(1) - (1)].n));
@@ -4274,7 +4289,7 @@ yyreduce:
case 168:
/* Line 1464 of yacc.c */
-#line 1250 "glsl_parser.ypp"
+#line 1265 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.type_specifier) = new(ctx) ast_type_specifier((yyvsp[(1) - (1)].struct_specifier));
@@ -4285,7 +4300,7 @@ yyreduce:
case 169:
/* Line 1464 of yacc.c */
-#line 1256 "glsl_parser.ypp"
+#line 1271 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.type_specifier) = new(ctx) ast_type_specifier((yyvsp[(1) - (1)].identifier));
@@ -4296,364 +4311,364 @@ yyreduce:
case 170:
/* Line 1464 of yacc.c */
-#line 1264 "glsl_parser.ypp"
+#line 1279 "glsl_parser.ypp"
{ (yyval.n) = ast_void; ;}
break;
case 171:
/* Line 1464 of yacc.c */
-#line 1265 "glsl_parser.ypp"
+#line 1280 "glsl_parser.ypp"
{ (yyval.n) = ast_float; ;}
break;
case 172:
/* Line 1464 of yacc.c */
-#line 1266 "glsl_parser.ypp"
+#line 1281 "glsl_parser.ypp"
{ (yyval.n) = ast_int; ;}
break;
case 173:
/* Line 1464 of yacc.c */
-#line 1267 "glsl_parser.ypp"
+#line 1282 "glsl_parser.ypp"
{ (yyval.n) = ast_uint; ;}
break;
case 174:
/* Line 1464 of yacc.c */
-#line 1268 "glsl_parser.ypp"
+#line 1283 "glsl_parser.ypp"
{ (yyval.n) = ast_bool; ;}
break;
case 175:
/* Line 1464 of yacc.c */
-#line 1269 "glsl_parser.ypp"
+#line 1284 "glsl_parser.ypp"
{ (yyval.n) = ast_vec2; ;}
break;
case 176:
/* Line 1464 of yacc.c */
-#line 1270 "glsl_parser.ypp"
+#line 1285 "glsl_parser.ypp"
{ (yyval.n) = ast_vec3; ;}
break;
case 177:
/* Line 1464 of yacc.c */
-#line 1271 "glsl_parser.ypp"
+#line 1286 "glsl_parser.ypp"
{ (yyval.n) = ast_vec4; ;}
break;
case 178:
/* Line 1464 of yacc.c */
-#line 1272 "glsl_parser.ypp"
+#line 1287 "glsl_parser.ypp"
{ (yyval.n) = ast_bvec2; ;}
break;
case 179:
/* Line 1464 of yacc.c */
-#line 1273 "glsl_parser.ypp"
+#line 1288 "glsl_parser.ypp"
{ (yyval.n) = ast_bvec3; ;}
break;
case 180:
/* Line 1464 of yacc.c */
-#line 1274 "glsl_parser.ypp"
+#line 1289 "glsl_parser.ypp"
{ (yyval.n) = ast_bvec4; ;}
break;
case 181:
/* Line 1464 of yacc.c */
-#line 1275 "glsl_parser.ypp"
+#line 1290 "glsl_parser.ypp"
{ (yyval.n) = ast_ivec2; ;}
break;
case 182:
/* Line 1464 of yacc.c */
-#line 1276 "glsl_parser.ypp"
+#line 1291 "glsl_parser.ypp"
{ (yyval.n) = ast_ivec3; ;}
break;
case 183:
/* Line 1464 of yacc.c */
-#line 1277 "glsl_parser.ypp"
+#line 1292 "glsl_parser.ypp"
{ (yyval.n) = ast_ivec4; ;}
break;
case 184:
/* Line 1464 of yacc.c */
-#line 1278 "glsl_parser.ypp"
+#line 1293 "glsl_parser.ypp"
{ (yyval.n) = ast_uvec2; ;}
break;
case 185:
/* Line 1464 of yacc.c */
-#line 1279 "glsl_parser.ypp"
+#line 1294 "glsl_parser.ypp"
{ (yyval.n) = ast_uvec3; ;}
break;
case 186:
/* Line 1464 of yacc.c */
-#line 1280 "glsl_parser.ypp"
+#line 1295 "glsl_parser.ypp"
{ (yyval.n) = ast_uvec4; ;}
break;
case 187:
/* Line 1464 of yacc.c */
-#line 1281 "glsl_parser.ypp"
+#line 1296 "glsl_parser.ypp"
{ (yyval.n) = ast_mat2; ;}
break;
case 188:
/* Line 1464 of yacc.c */
-#line 1282 "glsl_parser.ypp"
+#line 1297 "glsl_parser.ypp"
{ (yyval.n) = ast_mat2x3; ;}
break;
case 189:
/* Line 1464 of yacc.c */
-#line 1283 "glsl_parser.ypp"
+#line 1298 "glsl_parser.ypp"
{ (yyval.n) = ast_mat2x4; ;}
break;
case 190:
/* Line 1464 of yacc.c */
-#line 1284 "glsl_parser.ypp"
+#line 1299 "glsl_parser.ypp"
{ (yyval.n) = ast_mat3x2; ;}
break;
case 191:
/* Line 1464 of yacc.c */
-#line 1285 "glsl_parser.ypp"
+#line 1300 "glsl_parser.ypp"
{ (yyval.n) = ast_mat3; ;}
break;
case 192:
/* Line 1464 of yacc.c */
-#line 1286 "glsl_parser.ypp"
+#line 1301 "glsl_parser.ypp"
{ (yyval.n) = ast_mat3x4; ;}
break;
case 193:
/* Line 1464 of yacc.c */
-#line 1287 "glsl_parser.ypp"
+#line 1302 "glsl_parser.ypp"
{ (yyval.n) = ast_mat4x2; ;}
break;
case 194:
/* Line 1464 of yacc.c */
-#line 1288 "glsl_parser.ypp"
+#line 1303 "glsl_parser.ypp"
{ (yyval.n) = ast_mat4x3; ;}
break;
case 195:
/* Line 1464 of yacc.c */
-#line 1289 "glsl_parser.ypp"
+#line 1304 "glsl_parser.ypp"
{ (yyval.n) = ast_mat4; ;}
break;
case 196:
/* Line 1464 of yacc.c */
-#line 1290 "glsl_parser.ypp"
+#line 1305 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler1d; ;}
break;
case 197:
/* Line 1464 of yacc.c */
-#line 1291 "glsl_parser.ypp"
+#line 1306 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler2d; ;}
break;
case 198:
/* Line 1464 of yacc.c */
-#line 1292 "glsl_parser.ypp"
+#line 1307 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler2drect; ;}
break;
case 199:
/* Line 1464 of yacc.c */
-#line 1293 "glsl_parser.ypp"
+#line 1308 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler3d; ;}
break;
case 200:
/* Line 1464 of yacc.c */
-#line 1294 "glsl_parser.ypp"
+#line 1309 "glsl_parser.ypp"
{ (yyval.n) = ast_samplercube; ;}
break;
case 201:
/* Line 1464 of yacc.c */
-#line 1295 "glsl_parser.ypp"
+#line 1310 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler1dshadow; ;}
break;
case 202:
/* Line 1464 of yacc.c */
-#line 1296 "glsl_parser.ypp"
+#line 1311 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler2dshadow; ;}
break;
case 203:
/* Line 1464 of yacc.c */
-#line 1297 "glsl_parser.ypp"
+#line 1312 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler2drectshadow; ;}
break;
case 204:
/* Line 1464 of yacc.c */
-#line 1298 "glsl_parser.ypp"
+#line 1313 "glsl_parser.ypp"
{ (yyval.n) = ast_samplercubeshadow; ;}
break;
case 205:
/* Line 1464 of yacc.c */
-#line 1299 "glsl_parser.ypp"
+#line 1314 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler1darray; ;}
break;
case 206:
/* Line 1464 of yacc.c */
-#line 1300 "glsl_parser.ypp"
+#line 1315 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler2darray; ;}
break;
case 207:
/* Line 1464 of yacc.c */
-#line 1301 "glsl_parser.ypp"
+#line 1316 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler1darrayshadow; ;}
break;
case 208:
/* Line 1464 of yacc.c */
-#line 1302 "glsl_parser.ypp"
+#line 1317 "glsl_parser.ypp"
{ (yyval.n) = ast_sampler2darrayshadow; ;}
break;
case 209:
/* Line 1464 of yacc.c */
-#line 1303 "glsl_parser.ypp"
+#line 1318 "glsl_parser.ypp"
{ (yyval.n) = ast_isampler1d; ;}
break;
case 210:
/* Line 1464 of yacc.c */
-#line 1304 "glsl_parser.ypp"
+#line 1319 "glsl_parser.ypp"
{ (yyval.n) = ast_isampler2d; ;}
break;
case 211:
/* Line 1464 of yacc.c */
-#line 1305 "glsl_parser.ypp"
+#line 1320 "glsl_parser.ypp"
{ (yyval.n) = ast_isampler3d; ;}
break;
case 212:
/* Line 1464 of yacc.c */
-#line 1306 "glsl_parser.ypp"
+#line 1321 "glsl_parser.ypp"
{ (yyval.n) = ast_isamplercube; ;}
break;
case 213:
/* Line 1464 of yacc.c */
-#line 1307 "glsl_parser.ypp"
+#line 1322 "glsl_parser.ypp"
{ (yyval.n) = ast_isampler1darray; ;}
break;
case 214:
/* Line 1464 of yacc.c */
-#line 1308 "glsl_parser.ypp"
+#line 1323 "glsl_parser.ypp"
{ (yyval.n) = ast_isampler2darray; ;}
break;
case 215:
/* Line 1464 of yacc.c */
-#line 1309 "glsl_parser.ypp"
+#line 1324 "glsl_parser.ypp"
{ (yyval.n) = ast_usampler1d; ;}
break;
case 216:
/* Line 1464 of yacc.c */
-#line 1310 "glsl_parser.ypp"
+#line 1325 "glsl_parser.ypp"
{ (yyval.n) = ast_usampler2d; ;}
break;
case 217:
/* Line 1464 of yacc.c */
-#line 1311 "glsl_parser.ypp"
+#line 1326 "glsl_parser.ypp"
{ (yyval.n) = ast_usampler3d; ;}
break;
case 218:
/* Line 1464 of yacc.c */
-#line 1312 "glsl_parser.ypp"
+#line 1327 "glsl_parser.ypp"
{ (yyval.n) = ast_usamplercube; ;}
break;
case 219:
/* Line 1464 of yacc.c */
-#line 1313 "glsl_parser.ypp"
+#line 1328 "glsl_parser.ypp"
{ (yyval.n) = ast_usampler1darray; ;}
break;
case 220:
/* Line 1464 of yacc.c */
-#line 1314 "glsl_parser.ypp"
+#line 1329 "glsl_parser.ypp"
{ (yyval.n) = ast_usampler2darray; ;}
break;
case 221:
/* Line 1464 of yacc.c */
-#line 1318 "glsl_parser.ypp"
+#line 1333 "glsl_parser.ypp"
{
if (!state->es_shader && state->language_version < 130)
_mesa_glsl_error(& (yylsp[(1) - (1)]), state,
@@ -4669,7 +4684,7 @@ yyreduce:
case 222:
/* Line 1464 of yacc.c */
-#line 1328 "glsl_parser.ypp"
+#line 1343 "glsl_parser.ypp"
{
if (!state->es_shader && state->language_version < 130)
_mesa_glsl_error(& (yylsp[(1) - (1)]), state,
@@ -4685,7 +4700,7 @@ yyreduce:
case 223:
/* Line 1464 of yacc.c */
-#line 1338 "glsl_parser.ypp"
+#line 1353 "glsl_parser.ypp"
{
if (!state->es_shader && state->language_version < 130)
_mesa_glsl_error(& (yylsp[(1) - (1)]), state,
@@ -4701,7 +4716,7 @@ yyreduce:
case 224:
/* Line 1464 of yacc.c */
-#line 1352 "glsl_parser.ypp"
+#line 1367 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.struct_specifier) = new(ctx) ast_struct_specifier((yyvsp[(2) - (5)].identifier), (yyvsp[(4) - (5)].node));
@@ -4712,7 +4727,7 @@ yyreduce:
case 225:
/* Line 1464 of yacc.c */
-#line 1358 "glsl_parser.ypp"
+#line 1373 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.struct_specifier) = new(ctx) ast_struct_specifier(NULL, (yyvsp[(3) - (4)].node));
@@ -4723,7 +4738,7 @@ yyreduce:
case 226:
/* Line 1464 of yacc.c */
-#line 1367 "glsl_parser.ypp"
+#line 1382 "glsl_parser.ypp"
{
(yyval.node) = (ast_node *) (yyvsp[(1) - (1)].declarator_list);
(yyvsp[(1) - (1)].declarator_list)->link.self_link();
@@ -4733,7 +4748,7 @@ yyreduce:
case 227:
/* Line 1464 of yacc.c */
-#line 1372 "glsl_parser.ypp"
+#line 1387 "glsl_parser.ypp"
{
(yyval.node) = (ast_node *) (yyvsp[(1) - (2)].node);
(yyval.node)->link.insert_before(& (yyvsp[(2) - (2)].declarator_list)->link);
@@ -4743,7 +4758,7 @@ yyreduce:
case 228:
/* Line 1464 of yacc.c */
-#line 1380 "glsl_parser.ypp"
+#line 1395 "glsl_parser.ypp"
{
void *ctx = state;
ast_fully_specified_type *type = new(ctx) ast_fully_specified_type();
@@ -4760,7 +4775,7 @@ yyreduce:
case 229:
/* Line 1464 of yacc.c */
-#line 1395 "glsl_parser.ypp"
+#line 1410 "glsl_parser.ypp"
{
(yyval.declaration) = (yyvsp[(1) - (1)].declaration);
(yyvsp[(1) - (1)].declaration)->link.self_link();
@@ -4770,7 +4785,7 @@ yyreduce:
case 230:
/* Line 1464 of yacc.c */
-#line 1400 "glsl_parser.ypp"
+#line 1415 "glsl_parser.ypp"
{
(yyval.declaration) = (yyvsp[(1) - (3)].declaration);
(yyval.declaration)->link.insert_before(& (yyvsp[(3) - (3)].declaration)->link);
@@ -4780,7 +4795,7 @@ yyreduce:
case 231:
/* Line 1464 of yacc.c */
-#line 1408 "glsl_parser.ypp"
+#line 1423 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.declaration) = new(ctx) ast_declaration((yyvsp[(1) - (1)].identifier), false, NULL, NULL);
@@ -4791,7 +4806,7 @@ yyreduce:
case 232:
/* Line 1464 of yacc.c */
-#line 1414 "glsl_parser.ypp"
+#line 1429 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.declaration) = new(ctx) ast_declaration((yyvsp[(1) - (4)].identifier), true, (yyvsp[(3) - (4)].expression), NULL);
@@ -4802,28 +4817,28 @@ yyreduce:
case 235:
/* Line 1464 of yacc.c */
-#line 1432 "glsl_parser.ypp"
+#line 1447 "glsl_parser.ypp"
{ (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].compound_statement); ;}
break;
case 240:
/* Line 1464 of yacc.c */
-#line 1440 "glsl_parser.ypp"
+#line 1455 "glsl_parser.ypp"
{ (yyval.node) = NULL; ;}
break;
case 241:
/* Line 1464 of yacc.c */
-#line 1441 "glsl_parser.ypp"
+#line 1456 "glsl_parser.ypp"
{ (yyval.node) = NULL; ;}
break;
case 244:
/* Line 1464 of yacc.c */
-#line 1448 "glsl_parser.ypp"
+#line 1463 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.compound_statement) = new(ctx) ast_compound_statement(true, NULL);
@@ -4834,7 +4849,7 @@ yyreduce:
case 245:
/* Line 1464 of yacc.c */
-#line 1454 "glsl_parser.ypp"
+#line 1469 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.compound_statement) = new(ctx) ast_compound_statement(true, (yyvsp[(2) - (3)].node));
@@ -4845,14 +4860,14 @@ yyreduce:
case 246:
/* Line 1464 of yacc.c */
-#line 1462 "glsl_parser.ypp"
+#line 1477 "glsl_parser.ypp"
{ (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].compound_statement); ;}
break;
case 248:
/* Line 1464 of yacc.c */
-#line 1468 "glsl_parser.ypp"
+#line 1483 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.compound_statement) = new(ctx) ast_compound_statement(false, NULL);
@@ -4863,7 +4878,7 @@ yyreduce:
case 249:
/* Line 1464 of yacc.c */
-#line 1474 "glsl_parser.ypp"
+#line 1489 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.compound_statement) = new(ctx) ast_compound_statement(false, (yyvsp[(2) - (3)].node));
@@ -4874,7 +4889,7 @@ yyreduce:
case 250:
/* Line 1464 of yacc.c */
-#line 1483 "glsl_parser.ypp"
+#line 1498 "glsl_parser.ypp"
{
if ((yyvsp[(1) - (1)].node) == NULL) {
_mesa_glsl_error(& (yylsp[(1) - (1)]), state, "<nil> statement\n");
@@ -4889,7 +4904,7 @@ yyreduce:
case 251:
/* Line 1464 of yacc.c */
-#line 1493 "glsl_parser.ypp"
+#line 1508 "glsl_parser.ypp"
{
if ((yyvsp[(2) - (2)].node) == NULL) {
_mesa_glsl_error(& (yylsp[(2) - (2)]), state, "<nil> statement\n");
@@ -4903,7 +4918,7 @@ yyreduce:
case 252:
/* Line 1464 of yacc.c */
-#line 1505 "glsl_parser.ypp"
+#line 1520 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_expression_statement(NULL);
@@ -4914,7 +4929,7 @@ yyreduce:
case 253:
/* Line 1464 of yacc.c */
-#line 1511 "glsl_parser.ypp"
+#line 1526 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_expression_statement((yyvsp[(1) - (2)].expression));
@@ -4925,7 +4940,7 @@ yyreduce:
case 254:
/* Line 1464 of yacc.c */
-#line 1520 "glsl_parser.ypp"
+#line 1535 "glsl_parser.ypp"
{
(yyval.node) = new(state) ast_selection_statement((yyvsp[(3) - (5)].expression), (yyvsp[(5) - (5)].selection_rest_statement).then_statement,
(yyvsp[(5) - (5)].selection_rest_statement).else_statement);
@@ -4936,7 +4951,7 @@ yyreduce:
case 255:
/* Line 1464 of yacc.c */
-#line 1529 "glsl_parser.ypp"
+#line 1544 "glsl_parser.ypp"
{
(yyval.selection_rest_statement).then_statement = (yyvsp[(1) - (3)].node);
(yyval.selection_rest_statement).else_statement = (yyvsp[(3) - (3)].node);
@@ -4946,7 +4961,7 @@ yyreduce:
case 256:
/* Line 1464 of yacc.c */
-#line 1534 "glsl_parser.ypp"
+#line 1549 "glsl_parser.ypp"
{
(yyval.selection_rest_statement).then_statement = (yyvsp[(1) - (1)].node);
(yyval.selection_rest_statement).else_statement = NULL;
@@ -4956,7 +4971,7 @@ yyreduce:
case 257:
/* Line 1464 of yacc.c */
-#line 1542 "glsl_parser.ypp"
+#line 1557 "glsl_parser.ypp"
{
(yyval.node) = (ast_node *) (yyvsp[(1) - (1)].expression);
;}
@@ -4965,7 +4980,7 @@ yyreduce:
case 258:
/* Line 1464 of yacc.c */
-#line 1546 "glsl_parser.ypp"
+#line 1561 "glsl_parser.ypp"
{
void *ctx = state;
ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (4)].identifier), false, NULL, (yyvsp[(4) - (4)].expression));
@@ -4981,7 +4996,7 @@ yyreduce:
case 262:
/* Line 1464 of yacc.c */
-#line 1569 "glsl_parser.ypp"
+#line 1584 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_while,
@@ -4993,7 +5008,7 @@ yyreduce:
case 263:
/* Line 1464 of yacc.c */
-#line 1576 "glsl_parser.ypp"
+#line 1591 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_do_while,
@@ -5005,7 +5020,7 @@ yyreduce:
case 264:
/* Line 1464 of yacc.c */
-#line 1583 "glsl_parser.ypp"
+#line 1598 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_for,
@@ -5017,7 +5032,7 @@ yyreduce:
case 268:
/* Line 1464 of yacc.c */
-#line 1599 "glsl_parser.ypp"
+#line 1614 "glsl_parser.ypp"
{
(yyval.node) = NULL;
;}
@@ -5026,7 +5041,7 @@ yyreduce:
case 269:
/* Line 1464 of yacc.c */
-#line 1606 "glsl_parser.ypp"
+#line 1621 "glsl_parser.ypp"
{
(yyval.for_rest_statement).cond = (yyvsp[(1) - (2)].node);
(yyval.for_rest_statement).rest = NULL;
@@ -5036,7 +5051,7 @@ yyreduce:
case 270:
/* Line 1464 of yacc.c */
-#line 1611 "glsl_parser.ypp"
+#line 1626 "glsl_parser.ypp"
{
(yyval.for_rest_statement).cond = (yyvsp[(1) - (3)].node);
(yyval.for_rest_statement).rest = (yyvsp[(3) - (3)].expression);
@@ -5046,7 +5061,7 @@ yyreduce:
case 271:
/* Line 1464 of yacc.c */
-#line 1620 "glsl_parser.ypp"
+#line 1635 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_continue, NULL);
@@ -5057,7 +5072,7 @@ yyreduce:
case 272:
/* Line 1464 of yacc.c */
-#line 1626 "glsl_parser.ypp"
+#line 1641 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_break, NULL);
@@ -5068,7 +5083,7 @@ yyreduce:
case 273:
/* Line 1464 of yacc.c */
-#line 1632 "glsl_parser.ypp"
+#line 1647 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, NULL);
@@ -5079,7 +5094,7 @@ yyreduce:
case 274:
/* Line 1464 of yacc.c */
-#line 1638 "glsl_parser.ypp"
+#line 1653 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, (yyvsp[(2) - (3)].expression));
@@ -5090,7 +5105,7 @@ yyreduce:
case 275:
/* Line 1464 of yacc.c */
-#line 1644 "glsl_parser.ypp"
+#line 1659 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_discard, NULL);
@@ -5101,28 +5116,28 @@ yyreduce:
case 276:
/* Line 1464 of yacc.c */
-#line 1652 "glsl_parser.ypp"
+#line 1667 "glsl_parser.ypp"
{ (yyval.node) = (yyvsp[(1) - (1)].function_definition); ;}
break;
case 277:
/* Line 1464 of yacc.c */
-#line 1653 "glsl_parser.ypp"
+#line 1668 "glsl_parser.ypp"
{ (yyval.node) = (yyvsp[(1) - (1)].node); ;}
break;
case 278:
/* Line 1464 of yacc.c */
-#line 1654 "glsl_parser.ypp"
+#line 1669 "glsl_parser.ypp"
{ (yyval.node) = NULL; ;}
break;
case 279:
/* Line 1464 of yacc.c */
-#line 1659 "glsl_parser.ypp"
+#line 1674 "glsl_parser.ypp"
{
void *ctx = state;
(yyval.function_definition) = new(ctx) ast_function_definition();
@@ -5135,7 +5150,7 @@ yyreduce:
/* Line 1464 of yacc.c */
-#line 5139 "glsl_parser.cpp"
+#line 5154 "glsl_parser.cpp"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
diff --git a/mesalib/src/glsl/glsl_parser.ypp b/mesalib/src/glsl/glsl_parser.ypp
index 3955648eb..d0bebc7fe 100644
--- a/mesalib/src/glsl/glsl_parser.ypp
+++ b/mesalib/src/glsl/glsl_parser.ypp
@@ -220,25 +220,40 @@ version_statement:
/* blank - no #version specified: defaults are already set */
| VERSION INTCONSTANT EOL
{
+ bool supported = false;
+
switch ($2) {
case 100:
state->es_shader = true;
+ supported = state->Const.GLSL_100ES;
+ break;
case 110:
+ supported = state->Const.GLSL_110;
+ break;
case 120:
+ supported = state->Const.GLSL_120;
+ break;
case 130:
- /* FINISHME: Check against implementation support versions. */
- state->language_version = $2;
- state->version_string =
- talloc_asprintf(state, "GLSL%s %d.%02d",
- state->es_shader ? " ES" : "",
- state->language_version / 100,
- state->language_version % 100);
+ supported = state->Const.GLSL_130;
break;
default:
- _mesa_glsl_error(& @2, state, "Shading language version"
- "%u is not supported\n", $2);
+ supported = false;
break;
}
+
+ state->language_version = $2;
+ state->version_string =
+ ralloc_asprintf(state, "GLSL%s %d.%02d",
+ state->es_shader ? " ES" : "",
+ state->language_version / 100,
+ state->language_version % 100);
+
+ if (!supported) {
+ _mesa_glsl_error(& @2, state, "%s is not supported. "
+ "Supported versions are: %s\n",
+ state->version_string,
+ state->supported_version_string);
+ }
}
;
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index c9a8a2cb2..2ed8b843a 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -26,10 +26,10 @@
#include <assert.h>
extern "C" {
-#include <talloc.h>
#include "main/core.h" /* for struct gl_context */
}
+#include "ralloc.h"
#include "ast.h"
#include "glsl_parser_extras.h"
#include "glsl_parser.h"
@@ -48,7 +48,7 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx,
this->scanner = NULL;
this->translation_unit.make_empty();
this->symbols = new(mem_ctx) glsl_symbol_table;
- this->info_log = talloc_strdup(mem_ctx, "");
+ this->info_log = ralloc_strdup(mem_ctx, "");
this->error = false;
this->loop_or_switch_nesting = NULL;
@@ -79,6 +79,38 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx,
this->Const.MaxFragmentUniformComponents = ctx->Const.FragmentProgram.MaxUniformComponents;
this->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers;
+
+ /* Note: Once the OpenGL 3.0 'forward compatible' context or the OpenGL 3.2
+ * Core context is supported, this logic will need change. Older versions of
+ * GLSL are no longer supported outside the compatibility contexts of 3.x.
+ */
+ this->Const.GLSL_100ES = (ctx->API == API_OPENGLES2)
+ || ctx->Extensions.ARB_ES2_compatibility;
+ this->Const.GLSL_110 = (ctx->API == API_OPENGL);
+ this->Const.GLSL_120 = (ctx->API == API_OPENGL)
+ && (ctx->Const.GLSLVersion >= 120);
+ this->Const.GLSL_130 = (ctx->API == API_OPENGL)
+ && (ctx->Const.GLSLVersion >= 130);
+
+ const unsigned lowest_version =
+ (ctx->API == API_OPENGLES2) || ctx->Extensions.ARB_ES2_compatibility
+ ? 100 : 110;
+ const unsigned highest_version =
+ (ctx->API == API_OPENGL) ? ctx->Const.GLSLVersion : 100;
+ char *supported = (char *) ralloc_context(this);
+
+ for (unsigned ver = lowest_version; ver <= highest_version; ver += 10) {
+ const char *const prefix = (ver == lowest_version)
+ ? ""
+ : ((ver == highest_version) ? ", and " : ", ");
+
+ ralloc_asprintf_append(& supported, "%s%d.%02d%s",
+ prefix,
+ ver / 100, ver % 100,
+ (ver == 100) ? " ES" : "");
+ }
+
+ this->supported_version_string = supported;
}
const char *
@@ -104,15 +136,14 @@ _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
state->error = true;
assert(state->info_log != NULL);
- state->info_log = talloc_asprintf_append(state->info_log,
- "%u:%u(%u): error: ",
+ ralloc_asprintf_append(&state->info_log, "%u:%u(%u): error: ",
locp->source,
locp->first_line,
locp->first_column);
va_start(ap, fmt);
- state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap);
+ ralloc_vasprintf_append(&state->info_log, fmt, ap);
va_end(ap);
- state->info_log = talloc_strdup_append(state->info_log, "\n");
+ ralloc_strcat(&state->info_log, "\n");
}
@@ -123,15 +154,14 @@ _mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state,
va_list ap;
assert(state->info_log != NULL);
- state->info_log = talloc_asprintf_append(state->info_log,
- "%u:%u(%u): warning: ",
+ ralloc_asprintf_append(&state->info_log, "%u:%u(%u): warning: ",
locp->source,
locp->first_line,
locp->first_column);
va_start(ap, fmt);
- state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap);
+ ralloc_vasprintf_append(&state->info_log, fmt, ap);
va_end(ap);
- state->info_log = talloc_strdup_append(state->info_log, "\n");
+ ralloc_strcat(&state->info_log, "\n");
}
@@ -712,7 +742,7 @@ ast_struct_specifier::ast_struct_specifier(char *identifier,
{
if (identifier == NULL) {
static unsigned anon_count = 1;
- identifier = talloc_asprintf(this, "#anon_struct_%04x", anon_count);
+ identifier = ralloc_asprintf(this, "#anon_struct_%04x", anon_count);
anon_count++;
}
name = identifier;
diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h
index baba92bc6..c628db94e 100644
--- a/mesalib/src/glsl/glsl_parser_extras.h
+++ b/mesalib/src/glsl/glsl_parser_extras.h
@@ -46,25 +46,25 @@ struct _mesa_glsl_parse_state {
_mesa_glsl_parse_state(struct gl_context *ctx, GLenum target,
void *mem_ctx);
- /* Callers of this talloc-based new need not call delete. It's
- * easier to just talloc_free 'ctx' (or any of its ancestors). */
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
static void* operator new(size_t size, void *ctx)
{
- void *mem = talloc_zero_size(ctx, size);
+ void *mem = rzalloc_size(ctx, size);
assert(mem != NULL);
return mem;
}
/* If the user *does* call delete, that's OK, we will just
- * talloc_free in that case. */
+ * ralloc_free in that case. */
static void operator delete(void *mem, void *ctx)
{
- talloc_free(mem);
+ ralloc_free(mem);
}
static void operator delete(void *mem)
{
- talloc_free(mem);
+ ralloc_free(mem);
}
void *scanner;
@@ -77,6 +77,16 @@ struct _mesa_glsl_parse_state {
enum _mesa_glsl_parser_targets target;
/**
+ * Printable list of GLSL versions supported by the current context
+ *
+ * \note
+ * This string should probably be generated per-context instead of per
+ * invokation of the compiler. This should be changed when the method of
+ * tracking supported GLSL versions changes.
+ */
+ const char *supported_version_string;
+
+ /**
* Implementation defined limits that affect built-in variables, etc.
*
* \sa struct gl_constants (in mtypes.h)
@@ -97,6 +107,22 @@ struct _mesa_glsl_parse_state {
/* ARB_draw_buffers */
unsigned MaxDrawBuffers;
+
+ /**
+ * Set of GLSL versions supported by the current context
+ *
+ * Knowing that version X is supported doesn't mean that versions before
+ * X are also supported. Version 1.00 is only supported in an ES2
+ * context or when GL_ARB_ES2_compatibility is supported. In an OpenGL
+ * 3.0 "forward compatible" context, GLSL 1.10 and 1.20 are \b not
+ * supported.
+ */
+ /*@{*/
+ unsigned GLSL_100ES:1;
+ unsigned GLSL_110:1;
+ unsigned GLSL_120:1;
+ unsigned GLSL_130:1;
+ /*@}*/
} Const;
/**
diff --git a/mesalib/src/glsl/glsl_symbol_table.cpp b/mesalib/src/glsl/glsl_symbol_table.cpp
index f8c6c38fa..9714384eb 100644
--- a/mesalib/src/glsl/glsl_symbol_table.cpp
+++ b/mesalib/src/glsl/glsl_symbol_table.cpp
@@ -26,23 +26,23 @@
class symbol_table_entry {
public:
- /* Callers of this talloc-based new need not call delete. It's
- * easier to just talloc_free 'ctx' (or any of its ancestors). */
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
static void* operator new(size_t size, void *ctx)
{
- void *entry = talloc_size(ctx, size);
+ void *entry = ralloc_size(ctx, size);
assert(entry != NULL);
return entry;
}
- /* If the user *does* call delete, that's OK, we will just talloc_free. */
+ /* If the user *does* call delete, that's OK, we will just ralloc_free. */
static void operator delete(void *entry, void *ctx)
{
- talloc_free(entry);
+ ralloc_free(entry);
}
static void operator delete(void *entry)
{
- talloc_free(entry);
+ ralloc_free(entry);
}
symbol_table_entry(ir_variable *v) : v(v), f(0), t(0) {}
@@ -58,13 +58,13 @@ glsl_symbol_table::glsl_symbol_table()
{
this->language_version = 120;
this->table = _mesa_symbol_table_ctor();
- this->mem_ctx = talloc_init("symbol table entries");
+ this->mem_ctx = ralloc_context(NULL);
}
glsl_symbol_table::~glsl_symbol_table()
{
_mesa_symbol_table_dtor(table);
- talloc_free(mem_ctx);
+ ralloc_free(mem_ctx);
}
void glsl_symbol_table::push_scope()
diff --git a/mesalib/src/glsl/glsl_symbol_table.h b/mesalib/src/glsl/glsl_symbol_table.h
index 3890efd87..1afeddb33 100644
--- a/mesalib/src/glsl/glsl_symbol_table.h
+++ b/mesalib/src/glsl/glsl_symbol_table.h
@@ -1,131 +1,129 @@
-/* -*- c++ -*- */
-/*
- * 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_SYMBOL_TABLE
-#define GLSL_SYMBOL_TABLE
-
-#include <new>
-
-extern "C" {
-#include "program/symbol_table.h"
-}
-#include "ir.h"
-#include "glsl_types.h"
-
-class symbol_table_entry;
-
-/**
- * Facade class for _mesa_symbol_table
- *
- * Wraps the existing \c _mesa_symbol_table data structure to enforce some
- * type safe and some symbol table invariants.
- */
-struct glsl_symbol_table {
-private:
- static int
- _glsl_symbol_table_destructor (glsl_symbol_table *table)
- {
- table->~glsl_symbol_table();
-
- return 0;
- }
-
-public:
- /* Callers of this talloc-based new need not call delete. It's
- * easier to just talloc_free 'ctx' (or any of its ancestors). */
- static void* operator new(size_t size, void *ctx)
- {
- void *table;
-
- table = talloc_size(ctx, size);
- assert(table != NULL);
-
- talloc_set_destructor(table, (int (*)(void*)) _glsl_symbol_table_destructor);
-
- return table;
- }
-
- /* If the user *does* call delete, that's OK, we will just
- * talloc_free in that case. Here, C++ will have already called the
- * destructor so tell talloc not to do that again. */
- static void operator delete(void *table, void *ctx)
- {
- talloc_set_destructor(table, NULL);
- talloc_free(table);
- }
- static void operator delete(void *table)
- {
- talloc_set_destructor(table, NULL);
- talloc_free(table);
- }
-
- glsl_symbol_table();
- ~glsl_symbol_table();
-
- unsigned int language_version;
-
- void push_scope();
- void pop_scope();
-
- /**
- * Determine whether a name was declared at the current scope
- */
- bool name_declared_this_scope(const char *name);
-
- /**
- * \name Methods to add symbols to the table
- *
- * There is some temptation to rename all these functions to \c add_symbol
- * or similar. However, this breaks symmetry with the getter functions and
- * reduces the clarity of the intention of code that uses these methods.
- */
- /*@{*/
- bool add_variable(ir_variable *v);
- bool add_type(const char *name, const glsl_type *t);
- bool add_function(ir_function *f);
- /*@}*/
-
- /**
- * Add an function at global scope without checking for scoping conflicts.
- */
- void add_global_function(ir_function *f);
-
- /**
- * \name Methods to get symbols from the table
- */
- /*@{*/
- ir_variable *get_variable(const char *name);
- const glsl_type *get_type(const char *name);
- ir_function *get_function(const char *name);
- /*@}*/
-
-private:
- symbol_table_entry *get_entry(const char *name);
-
- struct _mesa_symbol_table *table;
- void *mem_ctx;
-};
-
-#endif /* GLSL_SYMBOL_TABLE */
+/* -*- c++ -*- */
+/*
+ * 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_SYMBOL_TABLE
+#define GLSL_SYMBOL_TABLE
+
+#include <new>
+
+extern "C" {
+#include "program/symbol_table.h"
+}
+#include "ir.h"
+#include "glsl_types.h"
+
+class symbol_table_entry;
+
+/**
+ * Facade class for _mesa_symbol_table
+ *
+ * Wraps the existing \c _mesa_symbol_table data structure to enforce some
+ * type safe and some symbol table invariants.
+ */
+struct glsl_symbol_table {
+private:
+ static void
+ _glsl_symbol_table_destructor (glsl_symbol_table *table)
+ {
+ table->~glsl_symbol_table();
+ }
+
+public:
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
+ static void* operator new(size_t size, void *ctx)
+ {
+ void *table;
+
+ table = ralloc_size(ctx, size);
+ assert(table != NULL);
+
+ ralloc_set_destructor(table, (void (*)(void*)) _glsl_symbol_table_destructor);
+
+ return table;
+ }
+
+ /* If the user *does* call delete, that's OK, we will just
+ * ralloc_free in that case. Here, C++ will have already called the
+ * destructor so tell ralloc not to do that again. */
+ static void operator delete(void *table, void *ctx)
+ {
+ ralloc_set_destructor(table, NULL);
+ ralloc_free(table);
+ }
+ static void operator delete(void *table)
+ {
+ ralloc_set_destructor(table, NULL);
+ ralloc_free(table);
+ }
+
+ glsl_symbol_table();
+ ~glsl_symbol_table();
+
+ unsigned int language_version;
+
+ void push_scope();
+ void pop_scope();
+
+ /**
+ * Determine whether a name was declared at the current scope
+ */
+ bool name_declared_this_scope(const char *name);
+
+ /**
+ * \name Methods to add symbols to the table
+ *
+ * There is some temptation to rename all these functions to \c add_symbol
+ * or similar. However, this breaks symmetry with the getter functions and
+ * reduces the clarity of the intention of code that uses these methods.
+ */
+ /*@{*/
+ bool add_variable(ir_variable *v);
+ bool add_type(const char *name, const glsl_type *t);
+ bool add_function(ir_function *f);
+ /*@}*/
+
+ /**
+ * Add an function at global scope without checking for scoping conflicts.
+ */
+ void add_global_function(ir_function *f);
+
+ /**
+ * \name Methods to get symbols from the table
+ */
+ /*@{*/
+ ir_variable *get_variable(const char *name);
+ const glsl_type *get_type(const char *name);
+ ir_function *get_function(const char *name);
+ /*@}*/
+
+private:
+ symbol_table_entry *get_entry(const char *name);
+
+ struct _mesa_symbol_table *table;
+ void *mem_ctx;
+};
+
+#endif /* GLSL_SYMBOL_TABLE */
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp
index 899e9c302..f4d9242b2 100644
--- a/mesalib/src/glsl/glsl_types.cpp
+++ b/mesalib/src/glsl/glsl_types.cpp
@@ -1,497 +1,497 @@
-/*
- * 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 <cstdio>
-#include <stdlib.h>
-#include "main/core.h" /* for Elements */
-#include "glsl_symbol_table.h"
-#include "glsl_parser_extras.h"
-#include "glsl_types.h"
-#include "builtin_types.h"
-extern "C" {
-#include "program/hash_table.h"
-}
-
-hash_table *glsl_type::array_types = NULL;
-hash_table *glsl_type::record_types = NULL;
-void *glsl_type::mem_ctx = NULL;
-
-void
-glsl_type::init_talloc_type_ctx(void)
-{
- if (glsl_type::mem_ctx == NULL) {
- glsl_type::mem_ctx = talloc_autofree_context();
- assert(glsl_type::mem_ctx != NULL);
- }
-}
-
-glsl_type::glsl_type(GLenum gl_type,
- glsl_base_type base_type, unsigned vector_elements,
- unsigned matrix_columns, const char *name) :
- gl_type(gl_type),
- base_type(base_type),
- sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
- sampler_type(0),
- vector_elements(vector_elements), matrix_columns(matrix_columns),
- length(0)
-{
- init_talloc_type_ctx();
- this->name = talloc_strdup(this->mem_ctx, name);
- /* Neither dimension is zero or both dimensions are zero.
- */
- assert((vector_elements == 0) == (matrix_columns == 0));
- memset(& fields, 0, sizeof(fields));
-}
-
-glsl_type::glsl_type(GLenum gl_type,
- enum glsl_sampler_dim dim, bool shadow, bool array,
- unsigned type, const char *name) :
- gl_type(gl_type),
- base_type(GLSL_TYPE_SAMPLER),
- sampler_dimensionality(dim), sampler_shadow(shadow),
- sampler_array(array), sampler_type(type),
- vector_elements(0), matrix_columns(0),
- length(0)
-{
- init_talloc_type_ctx();
- this->name = talloc_strdup(this->mem_ctx, name);
- memset(& fields, 0, sizeof(fields));
-}
-
-glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
- const char *name) :
- base_type(GLSL_TYPE_STRUCT),
- sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
- sampler_type(0),
- vector_elements(0), matrix_columns(0),
- length(num_fields)
-{
- unsigned int i;
-
- init_talloc_type_ctx();
- this->name = talloc_strdup(this->mem_ctx, name);
- this->fields.structure = talloc_array(this->mem_ctx,
- glsl_struct_field, length);
- for (i = 0; i < length; i++) {
- this->fields.structure[i].type = fields[i].type;
- this->fields.structure[i].name = talloc_strdup(this->fields.structure,
- fields[i].name);
- }
-}
-
-static void
-add_types_to_symbol_table(glsl_symbol_table *symtab,
- const struct glsl_type *types,
- unsigned num_types, bool warn)
-{
- (void) warn;
-
- for (unsigned i = 0; i < num_types; i++) {
- symtab->add_type(types[i].name, & types[i]);
- }
-}
-
-void
-glsl_type::generate_100ES_types(glsl_symbol_table *symtab)
-{
- add_types_to_symbol_table(symtab, builtin_core_types,
- Elements(builtin_core_types),
- false);
- add_types_to_symbol_table(symtab, builtin_structure_types,
- Elements(builtin_structure_types),
- false);
- add_types_to_symbol_table(symtab, void_type, 1, false);
-}
-
-void
-glsl_type::generate_110_types(glsl_symbol_table *symtab)
-{
- generate_100ES_types(symtab);
-
- add_types_to_symbol_table(symtab, builtin_110_types,
- Elements(builtin_110_types),
- false);
- add_types_to_symbol_table(symtab, builtin_110_deprecated_structure_types,
- Elements(builtin_110_deprecated_structure_types),
- false);
-}
-
-
-void
-glsl_type::generate_120_types(glsl_symbol_table *symtab)
-{
- generate_110_types(symtab);
-
- add_types_to_symbol_table(symtab, builtin_120_types,
- Elements(builtin_120_types), false);
-}
-
-
-void
-glsl_type::generate_130_types(glsl_symbol_table *symtab)
-{
- generate_120_types(symtab);
-
- add_types_to_symbol_table(symtab, builtin_130_types,
- Elements(builtin_130_types), false);
- generate_EXT_texture_array_types(symtab, false);
-}
-
-
-void
-glsl_type::generate_ARB_texture_rectangle_types(glsl_symbol_table *symtab,
- bool warn)
-{
- add_types_to_symbol_table(symtab, builtin_ARB_texture_rectangle_types,
- Elements(builtin_ARB_texture_rectangle_types),
- warn);
-}
-
-
-void
-glsl_type::generate_EXT_texture_array_types(glsl_symbol_table *symtab,
- bool warn)
-{
- add_types_to_symbol_table(symtab, builtin_EXT_texture_array_types,
- Elements(builtin_EXT_texture_array_types),
- warn);
-}
-
-
-void
-_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
-{
- switch (state->language_version) {
- case 100:
- assert(state->es_shader);
- glsl_type::generate_100ES_types(state->symbols);
- break;
- case 110:
- glsl_type::generate_110_types(state->symbols);
- break;
- case 120:
- glsl_type::generate_120_types(state->symbols);
- break;
- case 130:
- glsl_type::generate_130_types(state->symbols);
- break;
- default:
- /* error */
- break;
- }
-
- if (state->ARB_texture_rectangle_enable) {
- glsl_type::generate_ARB_texture_rectangle_types(state->symbols,
- state->ARB_texture_rectangle_warn);
- }
-
- if (state->EXT_texture_array_enable && state->language_version < 130) {
- // These are already included in 130; don't create twice.
- glsl_type::generate_EXT_texture_array_types(state->symbols,
- state->EXT_texture_array_warn);
- }
-}
-
-
-const glsl_type *glsl_type::get_base_type() const
-{
- switch (base_type) {
- case GLSL_TYPE_UINT:
- return uint_type;
- case GLSL_TYPE_INT:
- return int_type;
- case GLSL_TYPE_FLOAT:
- return float_type;
- case GLSL_TYPE_BOOL:
- return bool_type;
- default:
- return error_type;
- }
-}
-
-
-void
-_mesa_glsl_release_types(void)
-{
- if (glsl_type::array_types != NULL) {
- hash_table_dtor(glsl_type::array_types);
- glsl_type::array_types = NULL;
- }
-
- if (glsl_type::record_types != NULL) {
- hash_table_dtor(glsl_type::record_types);
- glsl_type::record_types = NULL;
- }
-}
-
-
-glsl_type::glsl_type(const glsl_type *array, unsigned length) :
- base_type(GLSL_TYPE_ARRAY),
- sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
- sampler_type(0),
- vector_elements(0), matrix_columns(0),
- name(NULL), length(length)
-{
- this->fields.array = array;
- /* Inherit the gl type of the base. The GL type is used for
- * uniform/statevar handling in Mesa and the arrayness of the type
- * is represented by the size rather than the type.
- */
- this->gl_type = array->gl_type;
-
- /* Allow a maximum of 10 characters for the array size. This is enough
- * for 32-bits of ~0. The extra 3 are for the '[', ']', and terminating
- * NUL.
- */
- const unsigned name_length = strlen(array->name) + 10 + 3;
- char *const n = (char *) talloc_size(this->mem_ctx, name_length);
-
- if (length == 0)
- snprintf(n, name_length, "%s[]", array->name);
- else
- snprintf(n, name_length, "%s[%u]", array->name, length);
-
- this->name = n;
-}
-
-
-const glsl_type *
-glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
-{
- if (base_type == GLSL_TYPE_VOID)
- return void_type;
-
- if ((rows < 1) || (rows > 4) || (columns < 1) || (columns > 4))
- return error_type;
-
- /* Treat GLSL vectors as Nx1 matrices.
- */
- if (columns == 1) {
- switch (base_type) {
- case GLSL_TYPE_UINT:
- return uint_type + (rows - 1);
- case GLSL_TYPE_INT:
- return int_type + (rows - 1);
- case GLSL_TYPE_FLOAT:
- return float_type + (rows - 1);
- case GLSL_TYPE_BOOL:
- return bool_type + (rows - 1);
- default:
- return error_type;
- }
- } else {
- if ((base_type != GLSL_TYPE_FLOAT) || (rows == 1))
- return error_type;
-
- /* GLSL matrix types are named mat{COLUMNS}x{ROWS}. Only the following
- * combinations are valid:
- *
- * 1 2 3 4
- * 1
- * 2 x x x
- * 3 x x x
- * 4 x x x
- */
-#define IDX(c,r) (((c-1)*3) + (r-1))
-
- switch (IDX(columns, rows)) {
- case IDX(2,2): return mat2_type;
- case IDX(2,3): return mat2x3_type;
- case IDX(2,4): return mat2x4_type;
- case IDX(3,2): return mat3x2_type;
- case IDX(3,3): return mat3_type;
- case IDX(3,4): return mat3x4_type;
- case IDX(4,2): return mat4x2_type;
- case IDX(4,3): return mat4x3_type;
- case IDX(4,4): return mat4_type;
- default: return error_type;
- }
- }
-
- assert(!"Should not get here.");
- return error_type;
-}
-
-
-const glsl_type *
-glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
-{
-
- if (array_types == NULL) {
- array_types = hash_table_ctor(64, hash_table_string_hash,
- hash_table_string_compare);
- }
-
- /* Generate a name using the base type pointer in the key. This is
- * done because the name of the base type may not be unique across
- * shaders. For example, two shaders may have different record types
- * named 'foo'.
- */
- char key[128];
- snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size);
-
- const glsl_type *t = (glsl_type *) hash_table_find(array_types, key);
- if (t == NULL) {
- t = new glsl_type(base, array_size);
-
- hash_table_insert(array_types, (void *) t, talloc_strdup(mem_ctx, key));
- }
-
- assert(t->base_type == GLSL_TYPE_ARRAY);
- assert(t->length == array_size);
- assert(t->fields.array == base);
-
- return t;
-}
-
-
-int
-glsl_type::record_key_compare(const void *a, const void *b)
-{
- const glsl_type *const key1 = (glsl_type *) a;
- const glsl_type *const key2 = (glsl_type *) b;
-
- /* Return zero is the types match (there is zero difference) or non-zero
- * otherwise.
- */
- if (strcmp(key1->name, key2->name) != 0)
- return 1;
-
- if (key1->length != key2->length)
- return 1;
-
- for (unsigned i = 0; i < key1->length; i++) {
- if (key1->fields.structure[i].type != key2->fields.structure[i].type)
- return 1;
- if (strcmp(key1->fields.structure[i].name,
- key2->fields.structure[i].name) != 0)
- return 1;
- }
-
- return 0;
-}
-
-
-unsigned
-glsl_type::record_key_hash(const void *a)
-{
- const glsl_type *const key = (glsl_type *) a;
- char hash_key[128];
- unsigned size = 0;
-
- size = snprintf(hash_key, sizeof(hash_key), "%08x", key->length);
-
- for (unsigned i = 0; i < key->length; i++) {
- if (size >= sizeof(hash_key))
- break;
-
- size += snprintf(& hash_key[size], sizeof(hash_key) - size,
- "%p", (void *) key->fields.structure[i].type);
- }
-
- return hash_table_string_hash(& hash_key);
-}
-
-
-const glsl_type *
-glsl_type::get_record_instance(const glsl_struct_field *fields,
- unsigned num_fields,
- const char *name)
-{
- const glsl_type key(fields, num_fields, name);
-
- if (record_types == NULL) {
- record_types = hash_table_ctor(64, record_key_hash, record_key_compare);
- }
-
- const glsl_type *t = (glsl_type *) hash_table_find(record_types, & key);
- if (t == NULL) {
- t = new glsl_type(fields, num_fields, name);
-
- hash_table_insert(record_types, (void *) t, t);
- }
-
- assert(t->base_type == GLSL_TYPE_STRUCT);
- assert(t->length == num_fields);
- assert(strcmp(t->name, name) == 0);
-
- return t;
-}
-
-
-const glsl_type *
-glsl_type::field_type(const char *name) const
-{
- if (this->base_type != GLSL_TYPE_STRUCT)
- return error_type;
-
- for (unsigned i = 0; i < this->length; i++) {
- if (strcmp(name, this->fields.structure[i].name) == 0)
- return this->fields.structure[i].type;
- }
-
- return error_type;
-}
-
-
-int
-glsl_type::field_index(const char *name) const
-{
- if (this->base_type != GLSL_TYPE_STRUCT)
- return -1;
-
- for (unsigned i = 0; i < this->length; i++) {
- if (strcmp(name, this->fields.structure[i].name) == 0)
- return i;
- }
-
- return -1;
-}
-
-
-unsigned
-glsl_type::component_slots() const
-{
- switch (this->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- case GLSL_TYPE_FLOAT:
- case GLSL_TYPE_BOOL:
- return this->components();
-
- case GLSL_TYPE_STRUCT: {
- unsigned size = 0;
-
- for (unsigned i = 0; i < this->length; i++)
- size += this->fields.structure[i].type->component_slots();
-
- return size;
- }
-
- case GLSL_TYPE_ARRAY:
- return this->length * this->fields.array->component_slots();
-
- default:
- return 0;
- }
-}
+/*
+ * 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 <cstdio>
+#include <stdlib.h>
+#include "main/core.h" /* for Elements */
+#include "glsl_symbol_table.h"
+#include "glsl_parser_extras.h"
+#include "glsl_types.h"
+#include "builtin_types.h"
+extern "C" {
+#include "program/hash_table.h"
+}
+
+hash_table *glsl_type::array_types = NULL;
+hash_table *glsl_type::record_types = NULL;
+void *glsl_type::mem_ctx = NULL;
+
+void
+glsl_type::init_ralloc_type_ctx(void)
+{
+ if (glsl_type::mem_ctx == NULL) {
+ glsl_type::mem_ctx = ralloc_autofree_context();
+ assert(glsl_type::mem_ctx != NULL);
+ }
+}
+
+glsl_type::glsl_type(GLenum gl_type,
+ glsl_base_type base_type, unsigned vector_elements,
+ unsigned matrix_columns, const char *name) :
+ gl_type(gl_type),
+ base_type(base_type),
+ sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
+ sampler_type(0),
+ vector_elements(vector_elements), matrix_columns(matrix_columns),
+ length(0)
+{
+ init_ralloc_type_ctx();
+ this->name = ralloc_strdup(this->mem_ctx, name);
+ /* Neither dimension is zero or both dimensions are zero.
+ */
+ assert((vector_elements == 0) == (matrix_columns == 0));
+ memset(& fields, 0, sizeof(fields));
+}
+
+glsl_type::glsl_type(GLenum gl_type,
+ enum glsl_sampler_dim dim, bool shadow, bool array,
+ unsigned type, const char *name) :
+ gl_type(gl_type),
+ base_type(GLSL_TYPE_SAMPLER),
+ sampler_dimensionality(dim), sampler_shadow(shadow),
+ sampler_array(array), sampler_type(type),
+ vector_elements(0), matrix_columns(0),
+ length(0)
+{
+ init_ralloc_type_ctx();
+ this->name = ralloc_strdup(this->mem_ctx, name);
+ memset(& fields, 0, sizeof(fields));
+}
+
+glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
+ const char *name) :
+ base_type(GLSL_TYPE_STRUCT),
+ sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
+ sampler_type(0),
+ vector_elements(0), matrix_columns(0),
+ length(num_fields)
+{
+ unsigned int i;
+
+ init_ralloc_type_ctx();
+ this->name = ralloc_strdup(this->mem_ctx, name);
+ this->fields.structure = ralloc_array(this->mem_ctx,
+ glsl_struct_field, length);
+ for (i = 0; i < length; i++) {
+ this->fields.structure[i].type = fields[i].type;
+ this->fields.structure[i].name = ralloc_strdup(this->fields.structure,
+ fields[i].name);
+ }
+}
+
+static void
+add_types_to_symbol_table(glsl_symbol_table *symtab,
+ const struct glsl_type *types,
+ unsigned num_types, bool warn)
+{
+ (void) warn;
+
+ for (unsigned i = 0; i < num_types; i++) {
+ symtab->add_type(types[i].name, & types[i]);
+ }
+}
+
+void
+glsl_type::generate_100ES_types(glsl_symbol_table *symtab)
+{
+ add_types_to_symbol_table(symtab, builtin_core_types,
+ Elements(builtin_core_types),
+ false);
+ add_types_to_symbol_table(symtab, builtin_structure_types,
+ Elements(builtin_structure_types),
+ false);
+ add_types_to_symbol_table(symtab, void_type, 1, false);
+}
+
+void
+glsl_type::generate_110_types(glsl_symbol_table *symtab)
+{
+ generate_100ES_types(symtab);
+
+ add_types_to_symbol_table(symtab, builtin_110_types,
+ Elements(builtin_110_types),
+ false);
+ add_types_to_symbol_table(symtab, builtin_110_deprecated_structure_types,
+ Elements(builtin_110_deprecated_structure_types),
+ false);
+}
+
+
+void
+glsl_type::generate_120_types(glsl_symbol_table *symtab)
+{
+ generate_110_types(symtab);
+
+ add_types_to_symbol_table(symtab, builtin_120_types,
+ Elements(builtin_120_types), false);
+}
+
+
+void
+glsl_type::generate_130_types(glsl_symbol_table *symtab)
+{
+ generate_120_types(symtab);
+
+ add_types_to_symbol_table(symtab, builtin_130_types,
+ Elements(builtin_130_types), false);
+ generate_EXT_texture_array_types(symtab, false);
+}
+
+
+void
+glsl_type::generate_ARB_texture_rectangle_types(glsl_symbol_table *symtab,
+ bool warn)
+{
+ add_types_to_symbol_table(symtab, builtin_ARB_texture_rectangle_types,
+ Elements(builtin_ARB_texture_rectangle_types),
+ warn);
+}
+
+
+void
+glsl_type::generate_EXT_texture_array_types(glsl_symbol_table *symtab,
+ bool warn)
+{
+ add_types_to_symbol_table(symtab, builtin_EXT_texture_array_types,
+ Elements(builtin_EXT_texture_array_types),
+ warn);
+}
+
+
+void
+_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
+{
+ switch (state->language_version) {
+ case 100:
+ assert(state->es_shader);
+ glsl_type::generate_100ES_types(state->symbols);
+ break;
+ case 110:
+ glsl_type::generate_110_types(state->symbols);
+ break;
+ case 120:
+ glsl_type::generate_120_types(state->symbols);
+ break;
+ case 130:
+ glsl_type::generate_130_types(state->symbols);
+ break;
+ default:
+ /* error */
+ break;
+ }
+
+ if (state->ARB_texture_rectangle_enable) {
+ glsl_type::generate_ARB_texture_rectangle_types(state->symbols,
+ state->ARB_texture_rectangle_warn);
+ }
+
+ if (state->EXT_texture_array_enable && state->language_version < 130) {
+ // These are already included in 130; don't create twice.
+ glsl_type::generate_EXT_texture_array_types(state->symbols,
+ state->EXT_texture_array_warn);
+ }
+}
+
+
+const glsl_type *glsl_type::get_base_type() const
+{
+ switch (base_type) {
+ case GLSL_TYPE_UINT:
+ return uint_type;
+ case GLSL_TYPE_INT:
+ return int_type;
+ case GLSL_TYPE_FLOAT:
+ return float_type;
+ case GLSL_TYPE_BOOL:
+ return bool_type;
+ default:
+ return error_type;
+ }
+}
+
+
+void
+_mesa_glsl_release_types(void)
+{
+ if (glsl_type::array_types != NULL) {
+ hash_table_dtor(glsl_type::array_types);
+ glsl_type::array_types = NULL;
+ }
+
+ if (glsl_type::record_types != NULL) {
+ hash_table_dtor(glsl_type::record_types);
+ glsl_type::record_types = NULL;
+ }
+}
+
+
+glsl_type::glsl_type(const glsl_type *array, unsigned length) :
+ base_type(GLSL_TYPE_ARRAY),
+ sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
+ sampler_type(0),
+ vector_elements(0), matrix_columns(0),
+ name(NULL), length(length)
+{
+ this->fields.array = array;
+ /* Inherit the gl type of the base. The GL type is used for
+ * uniform/statevar handling in Mesa and the arrayness of the type
+ * is represented by the size rather than the type.
+ */
+ this->gl_type = array->gl_type;
+
+ /* Allow a maximum of 10 characters for the array size. This is enough
+ * for 32-bits of ~0. The extra 3 are for the '[', ']', and terminating
+ * NUL.
+ */
+ const unsigned name_length = strlen(array->name) + 10 + 3;
+ char *const n = (char *) ralloc_size(this->mem_ctx, name_length);
+
+ if (length == 0)
+ snprintf(n, name_length, "%s[]", array->name);
+ else
+ snprintf(n, name_length, "%s[%u]", array->name, length);
+
+ this->name = n;
+}
+
+
+const glsl_type *
+glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
+{
+ if (base_type == GLSL_TYPE_VOID)
+ return void_type;
+
+ if ((rows < 1) || (rows > 4) || (columns < 1) || (columns > 4))
+ return error_type;
+
+ /* Treat GLSL vectors as Nx1 matrices.
+ */
+ if (columns == 1) {
+ switch (base_type) {
+ case GLSL_TYPE_UINT:
+ return uint_type + (rows - 1);
+ case GLSL_TYPE_INT:
+ return int_type + (rows - 1);
+ case GLSL_TYPE_FLOAT:
+ return float_type + (rows - 1);
+ case GLSL_TYPE_BOOL:
+ return bool_type + (rows - 1);
+ default:
+ return error_type;
+ }
+ } else {
+ if ((base_type != GLSL_TYPE_FLOAT) || (rows == 1))
+ return error_type;
+
+ /* GLSL matrix types are named mat{COLUMNS}x{ROWS}. Only the following
+ * combinations are valid:
+ *
+ * 1 2 3 4
+ * 1
+ * 2 x x x
+ * 3 x x x
+ * 4 x x x
+ */
+#define IDX(c,r) (((c-1)*3) + (r-1))
+
+ switch (IDX(columns, rows)) {
+ case IDX(2,2): return mat2_type;
+ case IDX(2,3): return mat2x3_type;
+ case IDX(2,4): return mat2x4_type;
+ case IDX(3,2): return mat3x2_type;
+ case IDX(3,3): return mat3_type;
+ case IDX(3,4): return mat3x4_type;
+ case IDX(4,2): return mat4x2_type;
+ case IDX(4,3): return mat4x3_type;
+ case IDX(4,4): return mat4_type;
+ default: return error_type;
+ }
+ }
+
+ assert(!"Should not get here.");
+ return error_type;
+}
+
+
+const glsl_type *
+glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
+{
+
+ if (array_types == NULL) {
+ array_types = hash_table_ctor(64, hash_table_string_hash,
+ hash_table_string_compare);
+ }
+
+ /* Generate a name using the base type pointer in the key. This is
+ * done because the name of the base type may not be unique across
+ * shaders. For example, two shaders may have different record types
+ * named 'foo'.
+ */
+ char key[128];
+ snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size);
+
+ const glsl_type *t = (glsl_type *) hash_table_find(array_types, key);
+ if (t == NULL) {
+ t = new glsl_type(base, array_size);
+
+ hash_table_insert(array_types, (void *) t, ralloc_strdup(mem_ctx, key));
+ }
+
+ assert(t->base_type == GLSL_TYPE_ARRAY);
+ assert(t->length == array_size);
+ assert(t->fields.array == base);
+
+ return t;
+}
+
+
+int
+glsl_type::record_key_compare(const void *a, const void *b)
+{
+ const glsl_type *const key1 = (glsl_type *) a;
+ const glsl_type *const key2 = (glsl_type *) b;
+
+ /* Return zero is the types match (there is zero difference) or non-zero
+ * otherwise.
+ */
+ if (strcmp(key1->name, key2->name) != 0)
+ return 1;
+
+ if (key1->length != key2->length)
+ return 1;
+
+ for (unsigned i = 0; i < key1->length; i++) {
+ if (key1->fields.structure[i].type != key2->fields.structure[i].type)
+ return 1;
+ if (strcmp(key1->fields.structure[i].name,
+ key2->fields.structure[i].name) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+unsigned
+glsl_type::record_key_hash(const void *a)
+{
+ const glsl_type *const key = (glsl_type *) a;
+ char hash_key[128];
+ unsigned size = 0;
+
+ size = snprintf(hash_key, sizeof(hash_key), "%08x", key->length);
+
+ for (unsigned i = 0; i < key->length; i++) {
+ if (size >= sizeof(hash_key))
+ break;
+
+ size += snprintf(& hash_key[size], sizeof(hash_key) - size,
+ "%p", (void *) key->fields.structure[i].type);
+ }
+
+ return hash_table_string_hash(& hash_key);
+}
+
+
+const glsl_type *
+glsl_type::get_record_instance(const glsl_struct_field *fields,
+ unsigned num_fields,
+ const char *name)
+{
+ const glsl_type key(fields, num_fields, name);
+
+ if (record_types == NULL) {
+ record_types = hash_table_ctor(64, record_key_hash, record_key_compare);
+ }
+
+ const glsl_type *t = (glsl_type *) hash_table_find(record_types, & key);
+ if (t == NULL) {
+ t = new glsl_type(fields, num_fields, name);
+
+ hash_table_insert(record_types, (void *) t, t);
+ }
+
+ assert(t->base_type == GLSL_TYPE_STRUCT);
+ assert(t->length == num_fields);
+ assert(strcmp(t->name, name) == 0);
+
+ return t;
+}
+
+
+const glsl_type *
+glsl_type::field_type(const char *name) const
+{
+ if (this->base_type != GLSL_TYPE_STRUCT)
+ return error_type;
+
+ for (unsigned i = 0; i < this->length; i++) {
+ if (strcmp(name, this->fields.structure[i].name) == 0)
+ return this->fields.structure[i].type;
+ }
+
+ return error_type;
+}
+
+
+int
+glsl_type::field_index(const char *name) const
+{
+ if (this->base_type != GLSL_TYPE_STRUCT)
+ return -1;
+
+ for (unsigned i = 0; i < this->length; i++) {
+ if (strcmp(name, this->fields.structure[i].name) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+
+unsigned
+glsl_type::component_slots() const
+{
+ switch (this->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ return this->components();
+
+ case GLSL_TYPE_STRUCT: {
+ unsigned size = 0;
+
+ for (unsigned i = 0; i < this->length; i++)
+ size += this->fields.structure[i].type->component_slots();
+
+ return size;
+ }
+
+ case GLSL_TYPE_ARRAY:
+ return this->length * this->fields.array->component_slots();
+
+ default:
+ return 0;
+ }
+}
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h
index 310747f57..ab6858faa 100644
--- a/mesalib/src/glsl/glsl_types.h
+++ b/mesalib/src/glsl/glsl_types.h
@@ -1,475 +1,476 @@
-/* -*- c++ -*- */
-/*
- * Copyright © 2009 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#pragma once
-#ifndef GLSL_TYPES_H
-#define GLSL_TYPES_H
-
-#include <cstring>
-#include <cassert>
-
-extern "C" {
-#include "GL/gl.h"
-#include <talloc.h>
-}
-
-struct _mesa_glsl_parse_state;
-struct glsl_symbol_table;
-
-extern "C" void
-_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state);
-
-extern "C" void
-_mesa_glsl_release_types(void);
-
-enum glsl_base_type {
- GLSL_TYPE_UINT = 0,
- GLSL_TYPE_INT,
- GLSL_TYPE_FLOAT,
- GLSL_TYPE_BOOL,
- GLSL_TYPE_SAMPLER,
- GLSL_TYPE_STRUCT,
- GLSL_TYPE_ARRAY,
- GLSL_TYPE_VOID,
- GLSL_TYPE_ERROR
-};
-
-enum glsl_sampler_dim {
- GLSL_SAMPLER_DIM_1D = 0,
- GLSL_SAMPLER_DIM_2D,
- GLSL_SAMPLER_DIM_3D,
- GLSL_SAMPLER_DIM_CUBE,
- GLSL_SAMPLER_DIM_RECT,
- GLSL_SAMPLER_DIM_BUF
-};
-
-
-struct glsl_type {
- GLenum gl_type;
- glsl_base_type base_type;
-
- unsigned sampler_dimensionality:3;
- unsigned sampler_shadow:1;
- unsigned sampler_array:1;
- unsigned sampler_type:2; /**< Type of data returned using this sampler.
- * only \c GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT,
- * and \c GLSL_TYPE_UINT are valid.
- */
-
- /* Callers of this talloc-based new need not call delete. It's
- * easier to just talloc_free 'mem_ctx' (or any of its ancestors). */
- static void* operator new(size_t size)
- {
- if (glsl_type::mem_ctx == NULL) {
- glsl_type::mem_ctx = talloc_init("glsl_type");
- assert(glsl_type::mem_ctx != NULL);
- }
-
- void *type;
-
- type = talloc_size(glsl_type::mem_ctx, size);
- assert(type != NULL);
-
- return type;
- }
-
- /* If the user *does* call delete, that's OK, we will just
- * talloc_free in that case. */
- static void operator delete(void *type)
- {
- talloc_free(type);
- }
-
- /**
- * \name Vector and matrix element counts
- *
- * For scalars, each of these values will be 1. For non-numeric types
- * these will be 0.
- */
- /*@{*/
- unsigned vector_elements:3; /**< 1, 2, 3, or 4 vector elements. */
- unsigned matrix_columns:3; /**< 1, 2, 3, or 4 matrix columns. */
- /*@}*/
-
- /**
- * Name of the data type
- *
- * This may be \c NULL for anonymous structures, for arrays, or for
- * function types.
- */
- const char *name;
-
- /**
- * For \c GLSL_TYPE_ARRAY, this is the length of the array. For
- * \c GLSL_TYPE_STRUCT, it is the number of elements in the structure and
- * the number of values pointed to by \c fields.structure (below).
- */
- unsigned length;
-
- /**
- * Subtype of composite data types.
- */
- union {
- const struct glsl_type *array; /**< Type of array elements. */
- const struct glsl_type *parameters; /**< Parameters to function. */
- struct glsl_struct_field *structure; /**< List of struct fields. */
- } fields;
-
-
- /**
- * \name Pointers to various public type singletons
- */
- /*@{*/
- static const glsl_type *const error_type;
- static const glsl_type *const void_type;
- static const glsl_type *const int_type;
- static const glsl_type *const ivec4_type;
- static const glsl_type *const uint_type;
- static const glsl_type *const uvec2_type;
- static const glsl_type *const uvec3_type;
- static const glsl_type *const uvec4_type;
- static const glsl_type *const float_type;
- static const glsl_type *const vec2_type;
- static const glsl_type *const vec3_type;
- static const glsl_type *const vec4_type;
- static const glsl_type *const bool_type;
- static const glsl_type *const mat2_type;
- static const glsl_type *const mat2x3_type;
- static const glsl_type *const mat2x4_type;
- static const glsl_type *const mat3x2_type;
- static const glsl_type *const mat3_type;
- static const glsl_type *const mat3x4_type;
- static const glsl_type *const mat4x2_type;
- static const glsl_type *const mat4x3_type;
- static const glsl_type *const mat4_type;
- /*@}*/
-
-
- /**
- * For numeric and boolean derrived types returns the basic scalar type
- *
- * If the type is a numeric or boolean scalar, vector, or matrix type,
- * this function gets the scalar type of the individual components. For
- * all other types, including arrays of numeric or boolean types, the
- * error type is returned.
- */
- const glsl_type *get_base_type() const;
-
- /**
- * Query the type of elements in an array
- *
- * \return
- * Pointer to the type of elements in the array for array types, or \c NULL
- * for non-array types.
- */
- const glsl_type *element_type() const
- {
- return is_array() ? fields.array : NULL;
- }
-
- /**
- * Get the instance of a built-in scalar, vector, or matrix type
- */
- static const glsl_type *get_instance(unsigned base_type, unsigned rows,
- unsigned columns);
-
- /**
- * Get the instance of an array type
- */
- static const glsl_type *get_array_instance(const glsl_type *base,
- unsigned elements);
-
- /**
- * Get the instance of a record type
- */
- static const glsl_type *get_record_instance(const glsl_struct_field *fields,
- unsigned num_fields,
- const char *name);
-
- /**
- * Query the total number of scalars that make up a scalar, vector or matrix
- */
- unsigned components() const
- {
- return vector_elements * matrix_columns;
- }
-
- /**
- * Calculate the number of components slots required to hold this type
- *
- * This is used to determine how many uniform or varying locations a type
- * might occupy.
- */
- unsigned component_slots() const;
-
-
- /**
- * Query whether or not a type is a scalar (non-vector and non-matrix).
- */
- bool is_scalar() const
- {
- return (vector_elements == 1)
- && (base_type >= GLSL_TYPE_UINT)
- && (base_type <= GLSL_TYPE_BOOL);
- }
-
- /**
- * Query whether or not a type is a vector
- */
- bool is_vector() const
- {
- return (vector_elements > 1)
- && (matrix_columns == 1)
- && (base_type >= GLSL_TYPE_UINT)
- && (base_type <= GLSL_TYPE_BOOL);
- }
-
- /**
- * Query whether or not a type is a matrix
- */
- bool is_matrix() const
- {
- /* GLSL only has float matrices. */
- return (matrix_columns > 1) && (base_type == GLSL_TYPE_FLOAT);
- }
-
- /**
- * Query whether or not a type is a non-array numeric type
- */
- bool is_numeric() const
- {
- return (base_type >= GLSL_TYPE_UINT) && (base_type <= GLSL_TYPE_FLOAT);
- }
-
- /**
- * Query whether or not a type is an integral type
- */
- bool is_integer() const
- {
- return (base_type == GLSL_TYPE_UINT) || (base_type == GLSL_TYPE_INT);
- }
-
- /**
- * Query whether or not a type is a float type
- */
- bool is_float() const
- {
- return base_type == GLSL_TYPE_FLOAT;
- }
-
- /**
- * Query whether or not a type is a non-array boolean type
- */
- bool is_boolean() const
- {
- return base_type == GLSL_TYPE_BOOL;
- }
-
- /**
- * Query whether or not a type is a sampler
- */
- bool is_sampler() const
- {
- return base_type == GLSL_TYPE_SAMPLER;
- }
-
- /**
- * Query whether or not a type is an array
- */
- bool is_array() const
- {
- return base_type == GLSL_TYPE_ARRAY;
- }
-
- /**
- * Query whether or not a type is a record
- */
- bool is_record() const
- {
- return base_type == GLSL_TYPE_STRUCT;
- }
-
- /**
- * Query whether or not a type is the void type singleton.
- */
- bool is_void() const
- {
- return base_type == GLSL_TYPE_VOID;
- }
-
- /**
- * Query whether or not a type is the error type singleton.
- */
- bool is_error() const
- {
- return base_type == GLSL_TYPE_ERROR;
- }
-
- /**
- * Query the full type of a matrix row
- *
- * \return
- * If the type is not a matrix, \c glsl_type::error_type is returned.
- * Otherwise a type matching the rows of the matrix is returned.
- */
- const glsl_type *row_type() const
- {
- return is_matrix()
- ? get_instance(base_type, matrix_columns, 1)
- : error_type;
- }
-
- /**
- * Query the full type of a matrix column
- *
- * \return
- * If the type is not a matrix, \c glsl_type::error_type is returned.
- * Otherwise a type matching the columns of the matrix is returned.
- */
- const glsl_type *column_type() const
- {
- return is_matrix()
- ? get_instance(base_type, vector_elements, 1)
- : error_type;
- }
-
-
- /**
- * Get the type of a structure field
- *
- * \return
- * Pointer to the type of the named field. If the type is not a structure
- * or the named field does not exist, \c glsl_type::error_type is returned.
- */
- const glsl_type *field_type(const char *name) const;
-
-
- /**
- * Get the location of a filed within a record type
- */
- int field_index(const char *name) const;
-
-
- /**
- * Query the number of elements in an array type
- *
- * \return
- * The number of elements in the array for array types or -1 for non-array
- * types. If the number of elements in the array has not yet been declared,
- * zero is returned.
- */
- int array_size() const
- {
- return is_array() ? length : -1;
- }
-
-private:
- /**
- * talloc context for all glsl_type allocations
- *
- * Set on the first call to \c glsl_type::new.
- */
- static void *mem_ctx;
-
- void init_talloc_type_ctx(void);
-
- /** Constructor for vector and matrix types */
- glsl_type(GLenum gl_type,
- glsl_base_type base_type, unsigned vector_elements,
- unsigned matrix_columns, const char *name);
-
- /** Constructor for sampler types */
- glsl_type(GLenum gl_type,
- enum glsl_sampler_dim dim, bool shadow, bool array,
- unsigned type, const char *name);
-
- /** Constructor for record types */
- glsl_type(const glsl_struct_field *fields, unsigned num_fields,
- const char *name);
-
- /** Constructor for array types */
- glsl_type(const glsl_type *array, unsigned length);
-
- /** Hash table containing the known array types. */
- static struct hash_table *array_types;
-
- /** Hash table containing the known record types. */
- static struct hash_table *record_types;
-
- static int record_key_compare(const void *a, const void *b);
- static unsigned record_key_hash(const void *key);
-
- /**
- * \name Pointers to various type singletons
- */
- /*@{*/
- static const glsl_type _error_type;
- static const glsl_type _void_type;
- static const glsl_type builtin_core_types[];
- static const glsl_type builtin_structure_types[];
- static const glsl_type builtin_110_deprecated_structure_types[];
- static const glsl_type builtin_110_types[];
- static const glsl_type builtin_120_types[];
- static const glsl_type builtin_130_types[];
- static const glsl_type builtin_ARB_texture_rectangle_types[];
- static const glsl_type builtin_EXT_texture_array_types[];
- static const glsl_type builtin_EXT_texture_buffer_object_types[];
- /*@}*/
-
- /**
- * \name Methods to populate a symbol table with built-in types.
- *
- * \internal
- * This is one of the truely annoying things about C++. Methods that are
- * completely internal and private to a type still have to be advertised to
- * the world in a public header file.
- */
- /*@{*/
- static void generate_100ES_types(glsl_symbol_table *);
- static void generate_110_types(glsl_symbol_table *);
- static void generate_120_types(glsl_symbol_table *);
- static void generate_130_types(glsl_symbol_table *);
- static void generate_ARB_texture_rectangle_types(glsl_symbol_table *, bool);
- static void generate_EXT_texture_array_types(glsl_symbol_table *, bool);
- /*@}*/
-
- /**
- * \name Friend functions.
- *
- * These functions are friends because they must have C linkage and the
- * need to call various private methods or access various private static
- * data.
- */
- /*@{*/
- friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *);
- friend void _mesa_glsl_release_types(void);
- /*@}*/
-};
-
-struct glsl_struct_field {
- const struct glsl_type *type;
- const char *name;
-};
-
-#endif /* GLSL_TYPES_H */
+/* -*- c++ -*- */
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+#ifndef GLSL_TYPES_H
+#define GLSL_TYPES_H
+
+#include <cstring>
+#include <cassert>
+
+extern "C" {
+#include "GL/gl.h"
+}
+
+#include "ralloc.h"
+
+struct _mesa_glsl_parse_state;
+struct glsl_symbol_table;
+
+extern "C" void
+_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state);
+
+extern "C" void
+_mesa_glsl_release_types(void);
+
+enum glsl_base_type {
+ GLSL_TYPE_UINT = 0,
+ GLSL_TYPE_INT,
+ GLSL_TYPE_FLOAT,
+ GLSL_TYPE_BOOL,
+ GLSL_TYPE_SAMPLER,
+ GLSL_TYPE_STRUCT,
+ GLSL_TYPE_ARRAY,
+ GLSL_TYPE_VOID,
+ GLSL_TYPE_ERROR
+};
+
+enum glsl_sampler_dim {
+ GLSL_SAMPLER_DIM_1D = 0,
+ GLSL_SAMPLER_DIM_2D,
+ GLSL_SAMPLER_DIM_3D,
+ GLSL_SAMPLER_DIM_CUBE,
+ GLSL_SAMPLER_DIM_RECT,
+ GLSL_SAMPLER_DIM_BUF
+};
+
+
+struct glsl_type {
+ GLenum gl_type;
+ glsl_base_type base_type;
+
+ unsigned sampler_dimensionality:3;
+ unsigned sampler_shadow:1;
+ unsigned sampler_array:1;
+ unsigned sampler_type:2; /**< Type of data returned using this sampler.
+ * only \c GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT,
+ * and \c GLSL_TYPE_UINT are valid.
+ */
+
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'mem_ctx' (or any of its ancestors). */
+ static void* operator new(size_t size)
+ {
+ if (glsl_type::mem_ctx == NULL) {
+ glsl_type::mem_ctx = ralloc_context(NULL);
+ assert(glsl_type::mem_ctx != NULL);
+ }
+
+ void *type;
+
+ type = ralloc_size(glsl_type::mem_ctx, size);
+ assert(type != NULL);
+
+ return type;
+ }
+
+ /* If the user *does* call delete, that's OK, we will just
+ * ralloc_free in that case. */
+ static void operator delete(void *type)
+ {
+ ralloc_free(type);
+ }
+
+ /**
+ * \name Vector and matrix element counts
+ *
+ * For scalars, each of these values will be 1. For non-numeric types
+ * these will be 0.
+ */
+ /*@{*/
+ unsigned vector_elements:3; /**< 1, 2, 3, or 4 vector elements. */
+ unsigned matrix_columns:3; /**< 1, 2, 3, or 4 matrix columns. */
+ /*@}*/
+
+ /**
+ * Name of the data type
+ *
+ * This may be \c NULL for anonymous structures, for arrays, or for
+ * function types.
+ */
+ const char *name;
+
+ /**
+ * For \c GLSL_TYPE_ARRAY, this is the length of the array. For
+ * \c GLSL_TYPE_STRUCT, it is the number of elements in the structure and
+ * the number of values pointed to by \c fields.structure (below).
+ */
+ unsigned length;
+
+ /**
+ * Subtype of composite data types.
+ */
+ union {
+ const struct glsl_type *array; /**< Type of array elements. */
+ const struct glsl_type *parameters; /**< Parameters to function. */
+ struct glsl_struct_field *structure; /**< List of struct fields. */
+ } fields;
+
+
+ /**
+ * \name Pointers to various public type singletons
+ */
+ /*@{*/
+ static const glsl_type *const error_type;
+ static const glsl_type *const void_type;
+ static const glsl_type *const int_type;
+ static const glsl_type *const ivec4_type;
+ static const glsl_type *const uint_type;
+ static const glsl_type *const uvec2_type;
+ static const glsl_type *const uvec3_type;
+ static const glsl_type *const uvec4_type;
+ static const glsl_type *const float_type;
+ static const glsl_type *const vec2_type;
+ static const glsl_type *const vec3_type;
+ static const glsl_type *const vec4_type;
+ static const glsl_type *const bool_type;
+ static const glsl_type *const mat2_type;
+ static const glsl_type *const mat2x3_type;
+ static const glsl_type *const mat2x4_type;
+ static const glsl_type *const mat3x2_type;
+ static const glsl_type *const mat3_type;
+ static const glsl_type *const mat3x4_type;
+ static const glsl_type *const mat4x2_type;
+ static const glsl_type *const mat4x3_type;
+ static const glsl_type *const mat4_type;
+ /*@}*/
+
+
+ /**
+ * For numeric and boolean derrived types returns the basic scalar type
+ *
+ * If the type is a numeric or boolean scalar, vector, or matrix type,
+ * this function gets the scalar type of the individual components. For
+ * all other types, including arrays of numeric or boolean types, the
+ * error type is returned.
+ */
+ const glsl_type *get_base_type() const;
+
+ /**
+ * Query the type of elements in an array
+ *
+ * \return
+ * Pointer to the type of elements in the array for array types, or \c NULL
+ * for non-array types.
+ */
+ const glsl_type *element_type() const
+ {
+ return is_array() ? fields.array : NULL;
+ }
+
+ /**
+ * Get the instance of a built-in scalar, vector, or matrix type
+ */
+ static const glsl_type *get_instance(unsigned base_type, unsigned rows,
+ unsigned columns);
+
+ /**
+ * Get the instance of an array type
+ */
+ static const glsl_type *get_array_instance(const glsl_type *base,
+ unsigned elements);
+
+ /**
+ * Get the instance of a record type
+ */
+ static const glsl_type *get_record_instance(const glsl_struct_field *fields,
+ unsigned num_fields,
+ const char *name);
+
+ /**
+ * Query the total number of scalars that make up a scalar, vector or matrix
+ */
+ unsigned components() const
+ {
+ return vector_elements * matrix_columns;
+ }
+
+ /**
+ * Calculate the number of components slots required to hold this type
+ *
+ * This is used to determine how many uniform or varying locations a type
+ * might occupy.
+ */
+ unsigned component_slots() const;
+
+
+ /**
+ * Query whether or not a type is a scalar (non-vector and non-matrix).
+ */
+ bool is_scalar() const
+ {
+ return (vector_elements == 1)
+ && (base_type >= GLSL_TYPE_UINT)
+ && (base_type <= GLSL_TYPE_BOOL);
+ }
+
+ /**
+ * Query whether or not a type is a vector
+ */
+ bool is_vector() const
+ {
+ return (vector_elements > 1)
+ && (matrix_columns == 1)
+ && (base_type >= GLSL_TYPE_UINT)
+ && (base_type <= GLSL_TYPE_BOOL);
+ }
+
+ /**
+ * Query whether or not a type is a matrix
+ */
+ bool is_matrix() const
+ {
+ /* GLSL only has float matrices. */
+ return (matrix_columns > 1) && (base_type == GLSL_TYPE_FLOAT);
+ }
+
+ /**
+ * Query whether or not a type is a non-array numeric type
+ */
+ bool is_numeric() const
+ {
+ return (base_type >= GLSL_TYPE_UINT) && (base_type <= GLSL_TYPE_FLOAT);
+ }
+
+ /**
+ * Query whether or not a type is an integral type
+ */
+ bool is_integer() const
+ {
+ return (base_type == GLSL_TYPE_UINT) || (base_type == GLSL_TYPE_INT);
+ }
+
+ /**
+ * Query whether or not a type is a float type
+ */
+ bool is_float() const
+ {
+ return base_type == GLSL_TYPE_FLOAT;
+ }
+
+ /**
+ * Query whether or not a type is a non-array boolean type
+ */
+ bool is_boolean() const
+ {
+ return base_type == GLSL_TYPE_BOOL;
+ }
+
+ /**
+ * Query whether or not a type is a sampler
+ */
+ bool is_sampler() const
+ {
+ return base_type == GLSL_TYPE_SAMPLER;
+ }
+
+ /**
+ * Query whether or not a type is an array
+ */
+ bool is_array() const
+ {
+ return base_type == GLSL_TYPE_ARRAY;
+ }
+
+ /**
+ * Query whether or not a type is a record
+ */
+ bool is_record() const
+ {
+ return base_type == GLSL_TYPE_STRUCT;
+ }
+
+ /**
+ * Query whether or not a type is the void type singleton.
+ */
+ bool is_void() const
+ {
+ return base_type == GLSL_TYPE_VOID;
+ }
+
+ /**
+ * Query whether or not a type is the error type singleton.
+ */
+ bool is_error() const
+ {
+ return base_type == GLSL_TYPE_ERROR;
+ }
+
+ /**
+ * Query the full type of a matrix row
+ *
+ * \return
+ * If the type is not a matrix, \c glsl_type::error_type is returned.
+ * Otherwise a type matching the rows of the matrix is returned.
+ */
+ const glsl_type *row_type() const
+ {
+ return is_matrix()
+ ? get_instance(base_type, matrix_columns, 1)
+ : error_type;
+ }
+
+ /**
+ * Query the full type of a matrix column
+ *
+ * \return
+ * If the type is not a matrix, \c glsl_type::error_type is returned.
+ * Otherwise a type matching the columns of the matrix is returned.
+ */
+ const glsl_type *column_type() const
+ {
+ return is_matrix()
+ ? get_instance(base_type, vector_elements, 1)
+ : error_type;
+ }
+
+
+ /**
+ * Get the type of a structure field
+ *
+ * \return
+ * Pointer to the type of the named field. If the type is not a structure
+ * or the named field does not exist, \c glsl_type::error_type is returned.
+ */
+ const glsl_type *field_type(const char *name) const;
+
+
+ /**
+ * Get the location of a filed within a record type
+ */
+ int field_index(const char *name) const;
+
+
+ /**
+ * Query the number of elements in an array type
+ *
+ * \return
+ * The number of elements in the array for array types or -1 for non-array
+ * types. If the number of elements in the array has not yet been declared,
+ * zero is returned.
+ */
+ int array_size() const
+ {
+ return is_array() ? length : -1;
+ }
+
+private:
+ /**
+ * ralloc context for all glsl_type allocations
+ *
+ * Set on the first call to \c glsl_type::new.
+ */
+ static void *mem_ctx;
+
+ void init_ralloc_type_ctx(void);
+
+ /** Constructor for vector and matrix types */
+ glsl_type(GLenum gl_type,
+ glsl_base_type base_type, unsigned vector_elements,
+ unsigned matrix_columns, const char *name);
+
+ /** Constructor for sampler types */
+ glsl_type(GLenum gl_type,
+ enum glsl_sampler_dim dim, bool shadow, bool array,
+ unsigned type, const char *name);
+
+ /** Constructor for record types */
+ glsl_type(const glsl_struct_field *fields, unsigned num_fields,
+ const char *name);
+
+ /** Constructor for array types */
+ glsl_type(const glsl_type *array, unsigned length);
+
+ /** Hash table containing the known array types. */
+ static struct hash_table *array_types;
+
+ /** Hash table containing the known record types. */
+ static struct hash_table *record_types;
+
+ static int record_key_compare(const void *a, const void *b);
+ static unsigned record_key_hash(const void *key);
+
+ /**
+ * \name Pointers to various type singletons
+ */
+ /*@{*/
+ static const glsl_type _error_type;
+ static const glsl_type _void_type;
+ static const glsl_type builtin_core_types[];
+ static const glsl_type builtin_structure_types[];
+ static const glsl_type builtin_110_deprecated_structure_types[];
+ static const glsl_type builtin_110_types[];
+ static const glsl_type builtin_120_types[];
+ static const glsl_type builtin_130_types[];
+ static const glsl_type builtin_ARB_texture_rectangle_types[];
+ static const glsl_type builtin_EXT_texture_array_types[];
+ static const glsl_type builtin_EXT_texture_buffer_object_types[];
+ /*@}*/
+
+ /**
+ * \name Methods to populate a symbol table with built-in types.
+ *
+ * \internal
+ * This is one of the truely annoying things about C++. Methods that are
+ * completely internal and private to a type still have to be advertised to
+ * the world in a public header file.
+ */
+ /*@{*/
+ static void generate_100ES_types(glsl_symbol_table *);
+ static void generate_110_types(glsl_symbol_table *);
+ static void generate_120_types(glsl_symbol_table *);
+ static void generate_130_types(glsl_symbol_table *);
+ static void generate_ARB_texture_rectangle_types(glsl_symbol_table *, bool);
+ static void generate_EXT_texture_array_types(glsl_symbol_table *, bool);
+ /*@}*/
+
+ /**
+ * \name Friend functions.
+ *
+ * These functions are friends because they must have C linkage and the
+ * need to call various private methods or access various private static
+ * data.
+ */
+ /*@{*/
+ friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *);
+ friend void _mesa_glsl_release_types(void);
+ /*@}*/
+};
+
+struct glsl_struct_field {
+ const struct glsl_type *type;
+ const char *name;
+};
+
+#endif /* GLSL_TYPES_H */
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index b4ceb5bba..fc356ba52 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -578,7 +578,7 @@ ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
|| type->is_record() || type->is_array());
if (type->is_array()) {
- this->array_elements = talloc_array(this, ir_constant *, type->length);
+ this->array_elements = ralloc_array(this, ir_constant *, type->length);
unsigned i = 0;
foreach_list(node, value_list) {
ir_constant *value = (ir_constant *) node;
@@ -1036,7 +1036,7 @@ ir_dereference_array::ir_dereference_array(ir_rvalue *value,
ir_dereference_array::ir_dereference_array(ir_variable *var,
ir_rvalue *array_index)
{
- void *ctx = talloc_parent(var);
+ void *ctx = ralloc_parent(var);
this->ir_type = ir_type_dereference_array;
this->array_index = array_index;
@@ -1069,7 +1069,7 @@ ir_dereference_record::ir_dereference_record(ir_rvalue *value,
{
this->ir_type = ir_type_dereference_record;
this->record = value;
- this->field = talloc_strdup(this, field);
+ this->field = ralloc_strdup(this, field);
this->type = (this->record != NULL)
? this->record->type->field_type(field) : glsl_type::error_type;
}
@@ -1078,11 +1078,11 @@ ir_dereference_record::ir_dereference_record(ir_rvalue *value,
ir_dereference_record::ir_dereference_record(ir_variable *var,
const char *field)
{
- void *ctx = talloc_parent(var);
+ void *ctx = ralloc_parent(var);
this->ir_type = ir_type_dereference_record;
this->record = new(ctx) ir_dereference_variable(var);
- this->field = talloc_strdup(this, field);
+ this->field = ralloc_strdup(this, field);
this->type = (this->record != NULL)
? this->record->type->field_type(field) : glsl_type::error_type;
}
@@ -1245,7 +1245,7 @@ ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask)
ir_swizzle *
ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length)
{
- void *ctx = talloc_parent(val);
+ void *ctx = ralloc_parent(val);
/* For each possible swizzle character, this table encodes the value in
* \c idx_map that represents the 0th element of the vector. For invalid
@@ -1334,7 +1334,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
{
this->ir_type = ir_type_variable;
this->type = type;
- this->name = talloc_strdup(this, name);
+ this->name = ralloc_strdup(this, name);
this->explicit_location = false;
this->location = -1;
this->warn_extension = NULL;
@@ -1379,6 +1379,21 @@ ir_function_signature::ir_function_signature(const glsl_type *return_type)
}
+static bool
+modes_match(unsigned a, unsigned b)
+{
+ if (a == b)
+ return true;
+
+ /* Accept "in" vs. "const in" */
+ if ((a == ir_var_const_in && b == ir_var_in) ||
+ (b == ir_var_const_in && a == ir_var_in))
+ return true;
+
+ return false;
+}
+
+
const char *
ir_function_signature::qualifiers_match(exec_list *params)
{
@@ -1391,7 +1406,7 @@ ir_function_signature::qualifiers_match(exec_list *params)
ir_variable *b = (ir_variable *)iter_b.get();
if (a->read_only != b->read_only ||
- a->mode != b->mode ||
+ !modes_match(a->mode, b->mode) ||
a->interpolation != b->interpolation ||
a->centroid != b->centroid) {
@@ -1426,7 +1441,7 @@ ir_function_signature::replace_parameters(exec_list *new_params)
ir_function::ir_function(const char *name)
{
this->ir_type = ir_type_function;
- this->name = talloc_strdup(this, name);
+ this->name = ralloc_strdup(this, name);
}
@@ -1492,7 +1507,7 @@ steal_memory(ir_instruction *ir, void *new_ctx)
}
}
- talloc_steal(new_ctx, ir);
+ ralloc_steal(new_ctx, ir);
}
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h
index 8d5056aa1..74a8b06b1 100644
--- a/mesalib/src/glsl/ir.h
+++ b/mesalib/src/glsl/ir.h
@@ -29,10 +29,7 @@
#include <cstdio>
#include <cstdlib>
-extern "C" {
-#include <talloc.h>
-}
-
+#include "ralloc.h"
#include "glsl_types.h"
#include "list.h"
#include "ir_visitor.h"
@@ -225,6 +222,7 @@ enum ir_variable_mode {
ir_var_in,
ir_var_out,
ir_var_inout,
+ ir_var_const_in, /**< "in" param that must be a constant expression */
ir_var_system_value, /**< Ex: front-face, instance-id, etc. */
ir_var_temporary /**< Temporary variable generated during compilation. */
};
@@ -986,7 +984,7 @@ public:
/**
* Get a generic ir_call object when an error occurs
*
- * Any allocation will be performed with 'ctx' as talloc owner.
+ * Any allocation will be performed with 'ctx' as ralloc owner.
*/
static ir_call *get_error_instruction(void *ctx);
@@ -1193,21 +1191,21 @@ enum ir_texture_opcode {
* selected from \c ir_texture_opcodes. In the printed IR, these will
* appear as:
*
- * Texel offset
- * | Projection divisor
- * | | Shadow comparitor
- * | | |
- * v v v
- * (tex (sampler) (coordinate) (0 0 0) (1) ( ))
- * (txb (sampler) (coordinate) (0 0 0) (1) ( ) (bias))
- * (txl (sampler) (coordinate) (0 0 0) (1) ( ) (lod))
- * (txd (sampler) (coordinate) (0 0 0) (1) ( ) (dPdx dPdy))
- * (txf (sampler) (coordinate) (0 0 0) (lod))
+ * Texel offset (0 or an expression)
+ * | Projection divisor
+ * | | Shadow comparitor
+ * | | |
+ * v v v
+ * (tex <sampler> <coordinate> 0 1 ( ))
+ * (txb <sampler> <coordinate> 0 1 ( ) <bias>)
+ * (txl <sampler> <coordinate> 0 1 ( ) <lod>)
+ * (txd <sampler> <coordinate> 0 1 ( ) (dPdx dPdy))
+ * (txf <sampler> <coordinate> 0 <lod>)
*/
class ir_texture : public ir_rvalue {
public:
ir_texture(enum ir_texture_opcode op)
- : op(op), projector(NULL), shadow_comparitor(NULL)
+ : op(op), projector(NULL), shadow_comparitor(NULL), offset(NULL)
{
this->ir_type = ir_type_texture;
}
@@ -1261,8 +1259,8 @@ public:
*/
ir_rvalue *shadow_comparitor;
- /** Explicit texel offsets. */
- signed char offsets[3];
+ /** Texel offset. */
+ ir_rvalue *offset;
union {
ir_rvalue *lod; /**< Floating point LOD */
diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp
index a3c35f042..2c0574dc6 100644
--- a/mesalib/src/glsl/ir_clone.cpp
+++ b/mesalib/src/glsl/ir_clone.cpp
@@ -1,420 +1,420 @@
-/*
- * 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 <string.h>
-#include "main/compiler.h"
-#include "ir.h"
-#include "glsl_types.h"
-extern "C" {
-#include "program/hash_table.h"
-}
-
-/**
- * Duplicate an IR variable
- *
- * \note
- * This will probably be made \c virtual and moved to the base class
- * eventually.
- */
-ir_variable *
-ir_variable::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_variable *var = new(mem_ctx) ir_variable(this->type, this->name,
- (ir_variable_mode) this->mode);
-
- var->max_array_access = this->max_array_access;
- var->read_only = this->read_only;
- var->centroid = this->centroid;
- var->invariant = this->invariant;
- var->interpolation = this->interpolation;
- var->array_lvalue = this->array_lvalue;
- var->location = this->location;
- var->warn_extension = this->warn_extension;
- var->origin_upper_left = this->origin_upper_left;
- var->pixel_center_integer = this->pixel_center_integer;
- var->explicit_location = this->explicit_location;
- if (this->explicit_location)
- var->location = this->location;
-
- if (this->constant_value)
- var->constant_value = this->constant_value->clone(mem_ctx, ht);
-
- if (ht) {
- hash_table_insert(ht, var, (void *)const_cast<ir_variable *>(this));
- }
-
- return var;
-}
-
-ir_swizzle *
-ir_swizzle::clone(void *mem_ctx, struct hash_table *ht) const
-{
- return new(mem_ctx) ir_swizzle(this->val->clone(mem_ctx, ht), this->mask);
-}
-
-ir_return *
-ir_return::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_rvalue *new_value = NULL;
-
- if (this->value)
- new_value = this->value->clone(mem_ctx, ht);
-
- return new(mem_ctx) ir_return(new_value);
-}
-
-ir_discard *
-ir_discard::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_rvalue *new_condition = NULL;
-
- if (this->condition != NULL)
- new_condition = this->condition->clone(mem_ctx, ht);
-
- return new(mem_ctx) ir_discard(new_condition);
-}
-
-ir_loop_jump *
-ir_loop_jump::clone(void *mem_ctx, struct hash_table *ht) const
-{
- (void)ht;
-
- return new(mem_ctx) ir_loop_jump(this->mode);
-}
-
-ir_if *
-ir_if::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_if *new_if = new(mem_ctx) ir_if(this->condition->clone(mem_ctx, ht));
-
- foreach_iter(exec_list_iterator, iter, this->then_instructions) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- new_if->then_instructions.push_tail(ir->clone(mem_ctx, ht));
- }
-
- foreach_iter(exec_list_iterator, iter, this->else_instructions) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- new_if->else_instructions.push_tail(ir->clone(mem_ctx, ht));
- }
-
- return new_if;
-}
-
-ir_loop *
-ir_loop::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_loop *new_loop = new(mem_ctx) ir_loop();
-
- if (this->from)
- new_loop->from = this->from->clone(mem_ctx, ht);
- if (this->to)
- new_loop->to = this->to->clone(mem_ctx, ht);
- if (this->increment)
- new_loop->increment = this->increment->clone(mem_ctx, ht);
- new_loop->counter = counter;
-
- foreach_iter(exec_list_iterator, iter, this->body_instructions) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- new_loop->body_instructions.push_tail(ir->clone(mem_ctx, ht));
- }
-
- new_loop->cmp = this->cmp;
- return new_loop;
-}
-
-ir_call *
-ir_call::clone(void *mem_ctx, struct hash_table *ht) const
-{
- if (this->type == glsl_type::error_type)
- return ir_call::get_error_instruction(mem_ctx);
-
- exec_list new_parameters;
-
- foreach_iter(exec_list_iterator, iter, this->actual_parameters) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- new_parameters.push_tail(ir->clone(mem_ctx, ht));
- }
-
- return new(mem_ctx) ir_call(this->callee, &new_parameters);
-}
-
-ir_expression *
-ir_expression::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_rvalue *op[Elements(this->operands)] = { NULL, };
- unsigned int i;
-
- for (i = 0; i < get_num_operands(); i++) {
- op[i] = this->operands[i]->clone(mem_ctx, ht);
- }
-
- return new(mem_ctx) ir_expression(this->operation, this->type,
- op[0], op[1], op[2], op[3]);
-}
-
-ir_dereference_variable *
-ir_dereference_variable::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_variable *new_var;
-
- if (ht) {
- new_var = (ir_variable *)hash_table_find(ht, this->var);
- if (!new_var)
- new_var = this->var;
- } else {
- new_var = this->var;
- }
-
- return new(mem_ctx) ir_dereference_variable(new_var);
-}
-
-ir_dereference_array *
-ir_dereference_array::clone(void *mem_ctx, struct hash_table *ht) const
-{
- return new(mem_ctx) ir_dereference_array(this->array->clone(mem_ctx, ht),
- this->array_index->clone(mem_ctx,
- ht));
-}
-
-ir_dereference_record *
-ir_dereference_record::clone(void *mem_ctx, struct hash_table *ht) const
-{
- return new(mem_ctx) ir_dereference_record(this->record->clone(mem_ctx, ht),
- this->field);
-}
-
-ir_texture *
-ir_texture::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_texture *new_tex = new(mem_ctx) ir_texture(this->op);
- new_tex->type = this->type;
-
- new_tex->sampler = this->sampler->clone(mem_ctx, ht);
- new_tex->coordinate = this->coordinate->clone(mem_ctx, ht);
- if (this->projector)
- new_tex->projector = this->projector->clone(mem_ctx, ht);
- if (this->shadow_comparitor) {
- new_tex->shadow_comparitor = this->shadow_comparitor->clone(mem_ctx, ht);
- }
-
- for (int i = 0; i < 3; i++)
- new_tex->offsets[i] = this->offsets[i];
-
- switch (this->op) {
- case ir_tex:
- break;
- case ir_txb:
- new_tex->lod_info.bias = this->lod_info.bias->clone(mem_ctx, ht);
- break;
- case ir_txl:
- case ir_txf:
- new_tex->lod_info.lod = this->lod_info.lod->clone(mem_ctx, ht);
- break;
- case ir_txd:
- new_tex->lod_info.grad.dPdx = this->lod_info.grad.dPdx->clone(mem_ctx, ht);
- new_tex->lod_info.grad.dPdy = this->lod_info.grad.dPdy->clone(mem_ctx, ht);
- break;
- }
-
- return new_tex;
-}
-
-ir_assignment *
-ir_assignment::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_rvalue *new_condition = NULL;
-
- if (this->condition)
- new_condition = this->condition->clone(mem_ctx, ht);
-
- return new(mem_ctx) ir_assignment(this->lhs->clone(mem_ctx, ht),
- this->rhs->clone(mem_ctx, ht),
- new_condition,
- this->write_mask);
-}
-
-ir_function *
-ir_function::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_function *copy = new(mem_ctx) ir_function(this->name);
-
- foreach_list_const(node, &this->signatures) {
- const ir_function_signature *const sig =
- (const ir_function_signature *const) node;
-
- ir_function_signature *sig_copy = sig->clone(mem_ctx, ht);
- copy->add_signature(sig_copy);
-
- if (ht != NULL)
- hash_table_insert(ht, sig_copy,
- (void *)const_cast<ir_function_signature *>(sig));
- }
-
- return copy;
-}
-
-ir_function_signature *
-ir_function_signature::clone(void *mem_ctx, struct hash_table *ht) const
-{
- ir_function_signature *copy = this->clone_prototype(mem_ctx, ht);
-
- copy->is_defined = this->is_defined;
-
- /* Clone the instruction list.
- */
- foreach_list_const(node, &this->body) {
- const ir_instruction *const inst = (const ir_instruction *) node;
-
- ir_instruction *const inst_copy = inst->clone(mem_ctx, ht);
- copy->body.push_tail(inst_copy);
- }
-
- return copy;
-}
-
-ir_function_signature *
-ir_function_signature::clone_prototype(void *mem_ctx, struct hash_table *ht) const
-{
- ir_function_signature *copy =
- new(mem_ctx) ir_function_signature(this->return_type);
-
- copy->is_defined = false;
- copy->is_builtin = this->is_builtin;
-
- /* Clone the parameter list, but NOT the body.
- */
- foreach_list_const(node, &this->parameters) {
- const ir_variable *const param = (const ir_variable *) node;
-
- assert(const_cast<ir_variable *>(param)->as_variable() != NULL);
-
- ir_variable *const param_copy = param->clone(mem_ctx, ht);
- copy->parameters.push_tail(param_copy);
- }
-
- return copy;
-}
-
-ir_constant *
-ir_constant::clone(void *mem_ctx, struct hash_table *ht) const
-{
- (void)ht;
-
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- case GLSL_TYPE_FLOAT:
- case GLSL_TYPE_BOOL:
- return new(mem_ctx) ir_constant(this->type, &this->value);
-
- case GLSL_TYPE_STRUCT: {
- ir_constant *c = new(mem_ctx) ir_constant;
-
- c->type = this->type;
- for (exec_node *node = this->components.head
- ; !node->is_tail_sentinel()
- ; node = node->next) {
- ir_constant *const orig = (ir_constant *) node;
-
- c->components.push_tail(orig->clone(mem_ctx, NULL));
- }
-
- return c;
- }
-
- case GLSL_TYPE_ARRAY: {
- ir_constant *c = new(mem_ctx) ir_constant;
-
- c->type = this->type;
- c->array_elements = talloc_array(c, ir_constant *, this->type->length);
- for (unsigned i = 0; i < this->type->length; i++) {
- c->array_elements[i] = this->array_elements[i]->clone(mem_ctx, NULL);
- }
- return c;
- }
-
- default:
- assert(!"Should not get here.");
- return NULL;
- }
-}
-
-
-class fixup_ir_call_visitor : public ir_hierarchical_visitor {
-public:
- fixup_ir_call_visitor(struct hash_table *ht)
- {
- this->ht = ht;
- }
-
- virtual ir_visitor_status visit_enter(ir_call *ir)
- {
- /* Try to find the function signature referenced by the ir_call in the
- * table. If it is found, replace it with the value from the table.
- */
- ir_function_signature *sig =
- (ir_function_signature *) hash_table_find(this->ht, ir->get_callee());
- if (sig != NULL)
- ir->set_callee(sig);
-
- /* Since this may be used before function call parameters are flattened,
- * the children also need to be processed.
- */
- return visit_continue;
- }
-
-private:
- struct hash_table *ht;
-};
-
-
-static void
-fixup_function_calls(struct hash_table *ht, exec_list *instructions)
-{
- fixup_ir_call_visitor v(ht);
- v.run(instructions);
-}
-
-
-void
-clone_ir_list(void *mem_ctx, exec_list *out, const exec_list *in)
-{
- struct hash_table *ht =
- hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
-
- foreach_list_const(node, in) {
- const ir_instruction *const original = (ir_instruction *) node;
- ir_instruction *copy = original->clone(mem_ctx, ht);
-
- out->push_tail(copy);
- }
-
- /* Make a pass over the cloned tree to fix up ir_call nodes to point to the
- * cloned ir_function_signature nodes. This cannot be done automatically
- * during cloning because the ir_call might be a forward reference (i.e.,
- * the function signature that it references may not have been cloned yet).
- */
- fixup_function_calls(ht, out);
-
- hash_table_dtor(ht);
-}
+/*
+ * 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 <string.h>
+#include "main/compiler.h"
+#include "ir.h"
+#include "glsl_types.h"
+extern "C" {
+#include "program/hash_table.h"
+}
+
+/**
+ * Duplicate an IR variable
+ *
+ * \note
+ * This will probably be made \c virtual and moved to the base class
+ * eventually.
+ */
+ir_variable *
+ir_variable::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_variable *var = new(mem_ctx) ir_variable(this->type, this->name,
+ (ir_variable_mode) this->mode);
+
+ var->max_array_access = this->max_array_access;
+ var->read_only = this->read_only;
+ var->centroid = this->centroid;
+ var->invariant = this->invariant;
+ var->interpolation = this->interpolation;
+ var->array_lvalue = this->array_lvalue;
+ var->location = this->location;
+ var->warn_extension = this->warn_extension;
+ var->origin_upper_left = this->origin_upper_left;
+ var->pixel_center_integer = this->pixel_center_integer;
+ var->explicit_location = this->explicit_location;
+ if (this->explicit_location)
+ var->location = this->location;
+
+ if (this->constant_value)
+ var->constant_value = this->constant_value->clone(mem_ctx, ht);
+
+ if (ht) {
+ hash_table_insert(ht, var, (void *)const_cast<ir_variable *>(this));
+ }
+
+ return var;
+}
+
+ir_swizzle *
+ir_swizzle::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ return new(mem_ctx) ir_swizzle(this->val->clone(mem_ctx, ht), this->mask);
+}
+
+ir_return *
+ir_return::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_rvalue *new_value = NULL;
+
+ if (this->value)
+ new_value = this->value->clone(mem_ctx, ht);
+
+ return new(mem_ctx) ir_return(new_value);
+}
+
+ir_discard *
+ir_discard::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_rvalue *new_condition = NULL;
+
+ if (this->condition != NULL)
+ new_condition = this->condition->clone(mem_ctx, ht);
+
+ return new(mem_ctx) ir_discard(new_condition);
+}
+
+ir_loop_jump *
+ir_loop_jump::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ (void)ht;
+
+ return new(mem_ctx) ir_loop_jump(this->mode);
+}
+
+ir_if *
+ir_if::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_if *new_if = new(mem_ctx) ir_if(this->condition->clone(mem_ctx, ht));
+
+ foreach_iter(exec_list_iterator, iter, this->then_instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ new_if->then_instructions.push_tail(ir->clone(mem_ctx, ht));
+ }
+
+ foreach_iter(exec_list_iterator, iter, this->else_instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ new_if->else_instructions.push_tail(ir->clone(mem_ctx, ht));
+ }
+
+ return new_if;
+}
+
+ir_loop *
+ir_loop::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_loop *new_loop = new(mem_ctx) ir_loop();
+
+ if (this->from)
+ new_loop->from = this->from->clone(mem_ctx, ht);
+ if (this->to)
+ new_loop->to = this->to->clone(mem_ctx, ht);
+ if (this->increment)
+ new_loop->increment = this->increment->clone(mem_ctx, ht);
+ new_loop->counter = counter;
+
+ foreach_iter(exec_list_iterator, iter, this->body_instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ new_loop->body_instructions.push_tail(ir->clone(mem_ctx, ht));
+ }
+
+ new_loop->cmp = this->cmp;
+ return new_loop;
+}
+
+ir_call *
+ir_call::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ if (this->type == glsl_type::error_type)
+ return ir_call::get_error_instruction(mem_ctx);
+
+ exec_list new_parameters;
+
+ foreach_iter(exec_list_iterator, iter, this->actual_parameters) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ new_parameters.push_tail(ir->clone(mem_ctx, ht));
+ }
+
+ return new(mem_ctx) ir_call(this->callee, &new_parameters);
+}
+
+ir_expression *
+ir_expression::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_rvalue *op[Elements(this->operands)] = { NULL, };
+ unsigned int i;
+
+ for (i = 0; i < get_num_operands(); i++) {
+ op[i] = this->operands[i]->clone(mem_ctx, ht);
+ }
+
+ return new(mem_ctx) ir_expression(this->operation, this->type,
+ op[0], op[1], op[2], op[3]);
+}
+
+ir_dereference_variable *
+ir_dereference_variable::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_variable *new_var;
+
+ if (ht) {
+ new_var = (ir_variable *)hash_table_find(ht, this->var);
+ if (!new_var)
+ new_var = this->var;
+ } else {
+ new_var = this->var;
+ }
+
+ return new(mem_ctx) ir_dereference_variable(new_var);
+}
+
+ir_dereference_array *
+ir_dereference_array::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ return new(mem_ctx) ir_dereference_array(this->array->clone(mem_ctx, ht),
+ this->array_index->clone(mem_ctx,
+ ht));
+}
+
+ir_dereference_record *
+ir_dereference_record::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ return new(mem_ctx) ir_dereference_record(this->record->clone(mem_ctx, ht),
+ this->field);
+}
+
+ir_texture *
+ir_texture::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_texture *new_tex = new(mem_ctx) ir_texture(this->op);
+ new_tex->type = this->type;
+
+ new_tex->sampler = this->sampler->clone(mem_ctx, ht);
+ new_tex->coordinate = this->coordinate->clone(mem_ctx, ht);
+ if (this->projector)
+ new_tex->projector = this->projector->clone(mem_ctx, ht);
+ if (this->shadow_comparitor) {
+ new_tex->shadow_comparitor = this->shadow_comparitor->clone(mem_ctx, ht);
+ }
+
+ if (this->offset != NULL)
+ new_tex->offset = this->offset->clone(mem_ctx, ht);
+
+ switch (this->op) {
+ case ir_tex:
+ break;
+ case ir_txb:
+ new_tex->lod_info.bias = this->lod_info.bias->clone(mem_ctx, ht);
+ break;
+ case ir_txl:
+ case ir_txf:
+ new_tex->lod_info.lod = this->lod_info.lod->clone(mem_ctx, ht);
+ break;
+ case ir_txd:
+ new_tex->lod_info.grad.dPdx = this->lod_info.grad.dPdx->clone(mem_ctx, ht);
+ new_tex->lod_info.grad.dPdy = this->lod_info.grad.dPdy->clone(mem_ctx, ht);
+ break;
+ }
+
+ return new_tex;
+}
+
+ir_assignment *
+ir_assignment::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_rvalue *new_condition = NULL;
+
+ if (this->condition)
+ new_condition = this->condition->clone(mem_ctx, ht);
+
+ return new(mem_ctx) ir_assignment(this->lhs->clone(mem_ctx, ht),
+ this->rhs->clone(mem_ctx, ht),
+ new_condition,
+ this->write_mask);
+}
+
+ir_function *
+ir_function::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_function *copy = new(mem_ctx) ir_function(this->name);
+
+ foreach_list_const(node, &this->signatures) {
+ const ir_function_signature *const sig =
+ (const ir_function_signature *const) node;
+
+ ir_function_signature *sig_copy = sig->clone(mem_ctx, ht);
+ copy->add_signature(sig_copy);
+
+ if (ht != NULL)
+ hash_table_insert(ht, sig_copy,
+ (void *)const_cast<ir_function_signature *>(sig));
+ }
+
+ return copy;
+}
+
+ir_function_signature *
+ir_function_signature::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_function_signature *copy = this->clone_prototype(mem_ctx, ht);
+
+ copy->is_defined = this->is_defined;
+
+ /* Clone the instruction list.
+ */
+ foreach_list_const(node, &this->body) {
+ const ir_instruction *const inst = (const ir_instruction *) node;
+
+ ir_instruction *const inst_copy = inst->clone(mem_ctx, ht);
+ copy->body.push_tail(inst_copy);
+ }
+
+ return copy;
+}
+
+ir_function_signature *
+ir_function_signature::clone_prototype(void *mem_ctx, struct hash_table *ht) const
+{
+ ir_function_signature *copy =
+ new(mem_ctx) ir_function_signature(this->return_type);
+
+ copy->is_defined = false;
+ copy->is_builtin = this->is_builtin;
+
+ /* Clone the parameter list, but NOT the body.
+ */
+ foreach_list_const(node, &this->parameters) {
+ const ir_variable *const param = (const ir_variable *) node;
+
+ assert(const_cast<ir_variable *>(param)->as_variable() != NULL);
+
+ ir_variable *const param_copy = param->clone(mem_ctx, ht);
+ copy->parameters.push_tail(param_copy);
+ }
+
+ return copy;
+}
+
+ir_constant *
+ir_constant::clone(void *mem_ctx, struct hash_table *ht) const
+{
+ (void)ht;
+
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ return new(mem_ctx) ir_constant(this->type, &this->value);
+
+ case GLSL_TYPE_STRUCT: {
+ ir_constant *c = new(mem_ctx) ir_constant;
+
+ c->type = this->type;
+ for (exec_node *node = this->components.head
+ ; !node->is_tail_sentinel()
+ ; node = node->next) {
+ ir_constant *const orig = (ir_constant *) node;
+
+ c->components.push_tail(orig->clone(mem_ctx, NULL));
+ }
+
+ return c;
+ }
+
+ case GLSL_TYPE_ARRAY: {
+ ir_constant *c = new(mem_ctx) ir_constant;
+
+ c->type = this->type;
+ c->array_elements = ralloc_array(c, ir_constant *, this->type->length);
+ for (unsigned i = 0; i < this->type->length; i++) {
+ c->array_elements[i] = this->array_elements[i]->clone(mem_ctx, NULL);
+ }
+ return c;
+ }
+
+ default:
+ assert(!"Should not get here.");
+ return NULL;
+ }
+}
+
+
+class fixup_ir_call_visitor : public ir_hierarchical_visitor {
+public:
+ fixup_ir_call_visitor(struct hash_table *ht)
+ {
+ this->ht = ht;
+ }
+
+ virtual ir_visitor_status visit_enter(ir_call *ir)
+ {
+ /* Try to find the function signature referenced by the ir_call in the
+ * table. If it is found, replace it with the value from the table.
+ */
+ ir_function_signature *sig =
+ (ir_function_signature *) hash_table_find(this->ht, ir->get_callee());
+ if (sig != NULL)
+ ir->set_callee(sig);
+
+ /* Since this may be used before function call parameters are flattened,
+ * the children also need to be processed.
+ */
+ return visit_continue;
+ }
+
+private:
+ struct hash_table *ht;
+};
+
+
+static void
+fixup_function_calls(struct hash_table *ht, exec_list *instructions)
+{
+ fixup_ir_call_visitor v(ht);
+ v.run(instructions);
+}
+
+
+void
+clone_ir_list(void *mem_ctx, exec_list *out, const exec_list *in)
+{
+ struct hash_table *ht =
+ hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
+
+ foreach_list_const(node, in) {
+ const ir_instruction *const original = (ir_instruction *) node;
+ ir_instruction *copy = original->clone(mem_ctx, ht);
+
+ out->push_tail(copy);
+ }
+
+ /* Make a pass over the cloned tree to fix up ir_call nodes to point to the
+ * cloned ir_function_signature nodes. This cannot be done automatically
+ * during cloning because the ir_call might be a forward reference (i.e.,
+ * the function signature that it references may not have been cloned yet).
+ */
+ fixup_function_calls(ht, out);
+
+ hash_table_dtor(ht);
+}
diff --git a/mesalib/src/glsl/ir_constant_expression.cpp b/mesalib/src/glsl/ir_constant_expression.cpp
index 53162f127..cf958aa7a 100644
--- a/mesalib/src/glsl/ir_constant_expression.cpp
+++ b/mesalib/src/glsl/ir_constant_expression.cpp
@@ -1,1354 +1,1354 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_constant_expression.cpp
- * Evaluate and process constant valued expressions
- *
- * In GLSL, constant valued expressions are used in several places. These
- * must be processed and evaluated very early in the compilation process.
- *
- * * Sizes of arrays
- * * Initializers for uniforms
- * * Initializers for \c const variables
- */
-
-#include <math.h>
-#include "main/core.h" /* for MAX2, MIN2, CLAMP */
-#include "ir.h"
-#include "ir_visitor.h"
-#include "glsl_types.h"
-
-static float
-dot(ir_constant *op0, ir_constant *op1)
-{
- assert(op0->type->is_float() && op1->type->is_float());
-
- float result = 0;
- for (unsigned c = 0; c < op0->type->components(); c++)
- result += op0->value.f[c] * op1->value.f[c];
-
- return result;
-}
-
-ir_constant *
-ir_expression::constant_expression_value()
-{
- if (this->type->is_error())
- return NULL;
-
- ir_constant *op[Elements(this->operands)] = { NULL, };
- ir_constant_data data;
-
- memset(&data, 0, sizeof(data));
-
- for (unsigned operand = 0; operand < this->get_num_operands(); operand++) {
- op[operand] = this->operands[operand]->constant_expression_value();
- if (!op[operand])
- return NULL;
- }
-
- if (op[1] != NULL)
- assert(op[0]->type->base_type == op[1]->type->base_type);
-
- bool op0_scalar = op[0]->type->is_scalar();
- bool op1_scalar = op[1] != NULL && op[1]->type->is_scalar();
-
- /* When iterating over a vector or matrix's components, we want to increase
- * the loop counter. However, for scalars, we want to stay at 0.
- */
- unsigned c0_inc = op0_scalar ? 0 : 1;
- unsigned c1_inc = op1_scalar ? 0 : 1;
- unsigned components;
- if (op1_scalar || !op[1]) {
- components = op[0]->type->components();
- } else {
- components = op[1]->type->components();
- }
-
- void *ctx = talloc_parent(this);
-
- /* Handle array operations here, rather than below. */
- if (op[0]->type->is_array()) {
- assert(op[1] != NULL && op[1]->type->is_array());
- switch (this->operation) {
- case ir_binop_all_equal:
- return new(ctx) ir_constant(op[0]->has_value(op[1]));
- case ir_binop_any_nequal:
- return new(ctx) ir_constant(!op[0]->has_value(op[1]));
- default:
- break;
- }
- return NULL;
- }
-
- switch (this->operation) {
- case ir_unop_bit_not:
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_INT:
- for (unsigned c = 0; c < components; c++)
- data.i[c] = ~ op[0]->value.i[c];
- break;
- case GLSL_TYPE_UINT:
- for (unsigned c = 0; c < components; c++)
- data.u[c] = ~ op[0]->value.u[c];
- break;
- default:
- assert(0);
- }
- break;
-
- case ir_unop_logic_not:
- assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.b[c] = !op[0]->value.b[c];
- break;
-
- case ir_unop_f2i:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.i[c] = (int) op[0]->value.f[c];
- }
- break;
- case ir_unop_i2f:
- assert(op[0]->type->base_type == GLSL_TYPE_INT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = (float) op[0]->value.i[c];
- }
- break;
- case ir_unop_u2f:
- assert(op[0]->type->base_type == GLSL_TYPE_UINT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = (float) op[0]->value.u[c];
- }
- break;
- case ir_unop_b2f:
- assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = op[0]->value.b[c] ? 1.0F : 0.0F;
- }
- break;
- case ir_unop_f2b:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.b[c] = op[0]->value.f[c] != 0.0F ? true : false;
- }
- break;
- case ir_unop_b2i:
- assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.u[c] = op[0]->value.b[c] ? 1 : 0;
- }
- break;
- case ir_unop_i2b:
- assert(op[0]->type->is_integer());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.b[c] = op[0]->value.u[c] ? true : false;
- }
- break;
-
- case ir_unop_any:
- assert(op[0]->type->is_boolean());
- data.b[0] = false;
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- if (op[0]->value.b[c])
- data.b[0] = true;
- }
- break;
-
- case ir_unop_trunc:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = truncf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_ceil:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = ceilf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_floor:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = floorf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_fract:
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = 0;
- break;
- case GLSL_TYPE_INT:
- data.i[c] = 0;
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = op[0]->value.f[c] - floor(op[0]->value.f[c]);
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_unop_sin:
- case ir_unop_sin_reduced:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = sinf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_cos:
- case ir_unop_cos_reduced:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = cosf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_neg:
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = -((int) op[0]->value.u[c]);
- break;
- case GLSL_TYPE_INT:
- data.i[c] = -op[0]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = -op[0]->value.f[c];
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_unop_abs:
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c];
- if (data.i[c] < 0)
- data.i[c] = -data.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = fabs(op[0]->value.f[c]);
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_unop_sign:
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.i[c] > 0;
- break;
- case GLSL_TYPE_INT:
- data.i[c] = (op[0]->value.i[c] > 0) - (op[0]->value.i[c] < 0);
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = float((op[0]->value.f[c] > 0)-(op[0]->value.f[c] < 0));
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_unop_rcp:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT:
- if (op[0]->value.u[c] != 0.0)
- data.u[c] = 1 / op[0]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- if (op[0]->value.i[c] != 0.0)
- data.i[c] = 1 / op[0]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- if (op[0]->value.f[c] != 0.0)
- data.f[c] = 1.0F / op[0]->value.f[c];
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_unop_rsq:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = 1.0F / sqrtf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_sqrt:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = sqrtf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_exp:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = expf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_exp2:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = exp2f(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_log:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = logf(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_log2:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = log2f(op[0]->value.f[c]);
- }
- break;
-
- case ir_unop_dFdx:
- case ir_unop_dFdy:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = 0.0;
- }
- break;
-
- case ir_binop_pow:
- assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- data.f[c] = powf(op[0]->value.f[c], op[1]->value.f[c]);
- }
- break;
-
- case ir_binop_dot:
- data.f[0] = dot(op[0], op[1]);
- break;
-
- case ir_binop_min:
- assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = MIN2(op[0]->value.u[c0], op[1]->value.u[c1]);
- break;
- case GLSL_TYPE_INT:
- data.i[c] = MIN2(op[0]->value.i[c0], op[1]->value.i[c1]);
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = MIN2(op[0]->value.f[c0], op[1]->value.f[c1]);
- break;
- default:
- assert(0);
- }
- }
-
- break;
- case ir_binop_max:
- assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = MAX2(op[0]->value.u[c0], op[1]->value.u[c1]);
- break;
- case GLSL_TYPE_INT:
- data.i[c] = MAX2(op[0]->value.i[c0], op[1]->value.i[c1]);
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = MAX2(op[0]->value.f[c0], op[1]->value.f[c1]);
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_binop_add:
- assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c0] + op[1]->value.u[c1];
- break;
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c0] + op[1]->value.i[c1];
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = op[0]->value.f[c0] + op[1]->value.f[c1];
- break;
- default:
- assert(0);
- }
- }
-
- break;
- case ir_binop_sub:
- assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c0] - op[1]->value.u[c1];
- break;
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c0] - op[1]->value.i[c1];
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = op[0]->value.f[c0] - op[1]->value.f[c1];
- break;
- default:
- assert(0);
- }
- }
-
- break;
- case ir_binop_mul:
- /* Check for equal types, or unequal types involving scalars */
- if ((op[0]->type == op[1]->type && !op[0]->type->is_matrix())
- || op0_scalar || op1_scalar) {
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c0] * op[1]->value.u[c1];
- break;
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c0] * op[1]->value.i[c1];
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = op[0]->value.f[c0] * op[1]->value.f[c1];
- break;
- default:
- assert(0);
- }
- }
- } else {
- assert(op[0]->type->is_matrix() || op[1]->type->is_matrix());
-
- /* Multiply an N-by-M matrix with an M-by-P matrix. Since either
- * matrix can be a GLSL vector, either N or P can be 1.
- *
- * For vec*mat, the vector is treated as a row vector. This
- * means the vector is a 1-row x M-column matrix.
- *
- * For mat*vec, the vector is treated as a column vector. Since
- * matrix_columns is 1 for vectors, this just works.
- */
- const unsigned n = op[0]->type->is_vector()
- ? 1 : op[0]->type->vector_elements;
- const unsigned m = op[1]->type->vector_elements;
- const unsigned p = op[1]->type->matrix_columns;
- for (unsigned j = 0; j < p; j++) {
- for (unsigned i = 0; i < n; i++) {
- for (unsigned k = 0; k < m; k++) {
- data.f[i+n*j] += op[0]->value.f[i+n*k]*op[1]->value.f[k+m*j];
- }
- }
- }
- }
-
- break;
- case ir_binop_div:
- assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c0] / op[1]->value.u[c1];
- break;
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c0] / op[1]->value.i[c1];
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = op[0]->value.f[c0] / op[1]->value.f[c1];
- break;
- default:
- assert(0);
- }
- }
-
- break;
- case ir_binop_mod:
- assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c0] % op[1]->value.u[c1];
- break;
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c0] % op[1]->value.i[c1];
- break;
- case GLSL_TYPE_FLOAT:
- /* We don't use fmod because it rounds toward zero; GLSL specifies
- * the use of floor.
- */
- data.f[c] = op[0]->value.f[c0] - op[1]->value.f[c1]
- * floorf(op[0]->value.f[c0] / op[1]->value.f[c1]);
- break;
- default:
- assert(0);
- }
- }
-
- break;
-
- case ir_binop_logic_and:
- assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.b[c] = op[0]->value.b[c] && op[1]->value.b[c];
- break;
- case ir_binop_logic_xor:
- assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.b[c] = op[0]->value.b[c] ^ op[1]->value.b[c];
- break;
- case ir_binop_logic_or:
- assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.b[c] = op[0]->value.b[c] || op[1]->value.b[c];
- break;
-
- case ir_binop_less:
- assert(op[0]->type == op[1]->type);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[0] = op[0]->value.u[0] < op[1]->value.u[0];
- break;
- case GLSL_TYPE_INT:
- data.b[0] = op[0]->value.i[0] < op[1]->value.i[0];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[0] = op[0]->value.f[0] < op[1]->value.f[0];
- break;
- default:
- assert(0);
- }
- }
- break;
- case ir_binop_greater:
- assert(op[0]->type == op[1]->type);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] > op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] > op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] > op[1]->value.f[c];
- break;
- default:
- assert(0);
- }
- }
- break;
- case ir_binop_lequal:
- assert(op[0]->type == op[1]->type);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[0] = op[0]->value.u[0] <= op[1]->value.u[0];
- break;
- case GLSL_TYPE_INT:
- data.b[0] = op[0]->value.i[0] <= op[1]->value.i[0];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[0] = op[0]->value.f[0] <= op[1]->value.f[0];
- break;
- default:
- assert(0);
- }
- }
- break;
- case ir_binop_gequal:
- assert(op[0]->type == op[1]->type);
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[0] = op[0]->value.u[0] >= op[1]->value.u[0];
- break;
- case GLSL_TYPE_INT:
- data.b[0] = op[0]->value.i[0] >= op[1]->value.i[0];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[0] = op[0]->value.f[0] >= op[1]->value.f[0];
- break;
- default:
- assert(0);
- }
- }
- break;
- case ir_binop_equal:
- assert(op[0]->type == op[1]->type);
- for (unsigned c = 0; c < components; c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] == op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] == op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] == op[1]->value.f[c];
- break;
- default:
- assert(0);
- }
- }
- break;
- case ir_binop_nequal:
- assert(op[0]->type != op[1]->type);
- for (unsigned c = 0; c < components; c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] != op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] != op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] != op[1]->value.f[c];
- break;
- default:
- assert(0);
- }
- }
- break;
- case ir_binop_all_equal:
- data.b[0] = op[0]->has_value(op[1]);
- break;
- case ir_binop_any_nequal:
- data.b[0] = !op[0]->has_value(op[1]);
- break;
-
- case ir_binop_lshift:
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- if (op[0]->type->base_type == GLSL_TYPE_INT &&
- op[1]->type->base_type == GLSL_TYPE_INT) {
- data.i[c] = op[0]->value.i[c0] << op[1]->value.i[c1];
-
- } else if (op[0]->type->base_type == GLSL_TYPE_INT &&
- op[1]->type->base_type == GLSL_TYPE_UINT) {
- data.i[c] = op[0]->value.i[c0] << op[1]->value.u[c1];
-
- } else if (op[0]->type->base_type == GLSL_TYPE_UINT &&
- op[1]->type->base_type == GLSL_TYPE_INT) {
- data.u[c] = op[0]->value.u[c0] << op[1]->value.i[c1];
-
- } else if (op[0]->type->base_type == GLSL_TYPE_UINT &&
- op[1]->type->base_type == GLSL_TYPE_UINT) {
- data.u[c] = op[0]->value.u[c0] << op[1]->value.u[c1];
- }
- }
- break;
-
- case ir_binop_rshift:
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- if (op[0]->type->base_type == GLSL_TYPE_INT &&
- op[1]->type->base_type == GLSL_TYPE_INT) {
- data.i[c] = op[0]->value.i[c0] >> op[1]->value.i[c1];
-
- } else if (op[0]->type->base_type == GLSL_TYPE_INT &&
- op[1]->type->base_type == GLSL_TYPE_UINT) {
- data.i[c] = op[0]->value.i[c0] >> op[1]->value.u[c1];
-
- } else if (op[0]->type->base_type == GLSL_TYPE_UINT &&
- op[1]->type->base_type == GLSL_TYPE_INT) {
- data.u[c] = op[0]->value.u[c0] >> op[1]->value.i[c1];
-
- } else if (op[0]->type->base_type == GLSL_TYPE_UINT &&
- op[1]->type->base_type == GLSL_TYPE_UINT) {
- data.u[c] = op[0]->value.u[c0] >> op[1]->value.u[c1];
- }
- }
- break;
-
- case ir_binop_bit_and:
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c0] & op[1]->value.i[c1];
- break;
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c0] & op[1]->value.u[c1];
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_binop_bit_or:
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c0] | op[1]->value.i[c1];
- break;
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c0] | op[1]->value.u[c1];
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_binop_bit_xor:
- for (unsigned c = 0, c0 = 0, c1 = 0;
- c < components;
- c0 += c0_inc, c1 += c1_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_INT:
- data.i[c] = op[0]->value.i[c0] ^ op[1]->value.i[c1];
- break;
- case GLSL_TYPE_UINT:
- data.u[c] = op[0]->value.u[c0] ^ op[1]->value.u[c1];
- break;
- default:
- assert(0);
- }
- }
- break;
-
- case ir_quadop_vector:
- for (unsigned c = 0; c < this->type->vector_elements; c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_INT:
- data.i[c] = op[c]->value.i[0];
- break;
- case GLSL_TYPE_UINT:
- data.u[c] = op[c]->value.u[0];
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = op[c]->value.f[0];
- break;
- default:
- assert(0);
- }
- }
- break;
-
- default:
- /* FINISHME: Should handle all expression types. */
- return NULL;
- }
-
- return new(ctx) ir_constant(this->type, &data);
-}
-
-
-ir_constant *
-ir_texture::constant_expression_value()
-{
- /* texture lookups aren't constant expressions */
- return NULL;
-}
-
-
-ir_constant *
-ir_swizzle::constant_expression_value()
-{
- ir_constant *v = this->val->constant_expression_value();
-
- if (v != NULL) {
- ir_constant_data data = { { 0 } };
-
- const unsigned swiz_idx[4] = {
- this->mask.x, this->mask.y, this->mask.z, this->mask.w
- };
-
- for (unsigned i = 0; i < this->mask.num_components; i++) {
- switch (v->type->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT: data.u[i] = v->value.u[swiz_idx[i]]; break;
- case GLSL_TYPE_FLOAT: data.f[i] = v->value.f[swiz_idx[i]]; break;
- case GLSL_TYPE_BOOL: data.b[i] = v->value.b[swiz_idx[i]]; break;
- default: assert(!"Should not get here."); break;
- }
- }
-
- void *ctx = talloc_parent(this);
- return new(ctx) ir_constant(this->type, &data);
- }
- return NULL;
-}
-
-
-ir_constant *
-ir_dereference_variable::constant_expression_value()
-{
- /* This may occur during compile and var->type is glsl_type::error_type */
- if (!var)
- return NULL;
-
- /* The constant_value of a uniform variable is its initializer,
- * not the lifetime constant value of the uniform.
- */
- if (var->mode == ir_var_uniform)
- return NULL;
-
- if (!var->constant_value)
- return NULL;
-
- return var->constant_value->clone(talloc_parent(var), NULL);
-}
-
-
-ir_constant *
-ir_dereference_array::constant_expression_value()
-{
- ir_constant *array = this->array->constant_expression_value();
- ir_constant *idx = this->array_index->constant_expression_value();
-
- if ((array != NULL) && (idx != NULL)) {
- void *ctx = talloc_parent(this);
- if (array->type->is_matrix()) {
- /* Array access of a matrix results in a vector.
- */
- const unsigned column = idx->value.u[0];
-
- const glsl_type *const column_type = array->type->column_type();
-
- /* Offset in the constant matrix to the first element of the column
- * to be extracted.
- */
- const unsigned mat_idx = column * column_type->vector_elements;
-
- ir_constant_data data = { { 0 } };
-
- switch (column_type->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- for (unsigned i = 0; i < column_type->vector_elements; i++)
- data.u[i] = array->value.u[mat_idx + i];
-
- break;
-
- case GLSL_TYPE_FLOAT:
- for (unsigned i = 0; i < column_type->vector_elements; i++)
- data.f[i] = array->value.f[mat_idx + i];
-
- break;
-
- default:
- assert(!"Should not get here.");
- break;
- }
-
- return new(ctx) ir_constant(column_type, &data);
- } else if (array->type->is_vector()) {
- const unsigned component = idx->value.u[0];
-
- return new(ctx) ir_constant(array, component);
- } else {
- const unsigned index = idx->value.u[0];
- return array->get_array_element(index)->clone(ctx, NULL);
- }
- }
- return NULL;
-}
-
-
-ir_constant *
-ir_dereference_record::constant_expression_value()
-{
- ir_constant *v = this->record->constant_expression_value();
-
- return (v != NULL) ? v->get_record_field(this->field) : NULL;
-}
-
-
-ir_constant *
-ir_assignment::constant_expression_value()
-{
- /* FINISHME: Handle CEs involving assignment (return RHS) */
- return NULL;
-}
-
-
-ir_constant *
-ir_constant::constant_expression_value()
-{
- return this;
-}
-
-
-ir_constant *
-ir_call::constant_expression_value()
-{
- if (this->type == glsl_type::error_type)
- return NULL;
-
- /* From the GLSL 1.20 spec, page 23:
- * "Function calls to user-defined functions (non-built-in functions)
- * cannot be used to form constant expressions."
- */
- if (!this->callee->is_builtin)
- return NULL;
-
- unsigned num_parameters = 0;
-
- /* Check if all parameters are constant */
- ir_constant *op[3];
- foreach_list(n, &this->actual_parameters) {
- ir_constant *constant = ((ir_rvalue *) n)->constant_expression_value();
- if (constant == NULL)
- return NULL;
-
- op[num_parameters] = constant;
-
- assert(num_parameters < 3);
- num_parameters++;
- }
-
- /* Individual cases below can either:
- * - Assign "expr" a new ir_expression to evaluate (for basic opcodes)
- * - Fill "data" with appopriate constant data
- * - Return an ir_constant directly.
- */
- void *mem_ctx = talloc_parent(this);
- ir_expression *expr = NULL;
-
- ir_constant_data data;
- memset(&data, 0, sizeof(data));
-
- const char *callee = this->callee_name();
- if (strcmp(callee, "abs") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_abs, type, op[0], NULL);
- } else if (strcmp(callee, "all") == 0) {
- assert(op[0]->type->is_boolean());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- if (!op[0]->value.b[c])
- return new(mem_ctx) ir_constant(false);
- }
- return new(mem_ctx) ir_constant(true);
- } else if (strcmp(callee, "any") == 0) {
- assert(op[0]->type->is_boolean());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- if (op[0]->value.b[c])
- return new(mem_ctx) ir_constant(true);
- }
- return new(mem_ctx) ir_constant(false);
- } else if (strcmp(callee, "acos") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = acosf(op[0]->value.f[c]);
- } else if (strcmp(callee, "acosh") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = acoshf(op[0]->value.f[c]);
- } else if (strcmp(callee, "asin") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = asinf(op[0]->value.f[c]);
- } else if (strcmp(callee, "asinh") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = asinhf(op[0]->value.f[c]);
- } else if (strcmp(callee, "atan") == 0) {
- assert(op[0]->type->is_float());
- if (num_parameters == 2) {
- assert(op[1]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = atan2f(op[0]->value.f[c], op[1]->value.f[c]);
- } else {
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = atanf(op[0]->value.f[c]);
- }
- } else if (strcmp(callee, "atanh") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = atanhf(op[0]->value.f[c]);
- } else if (strcmp(callee, "dFdx") == 0 || strcmp(callee, "dFdy") == 0) {
- return ir_constant::zero(mem_ctx, this->type);
- } else if (strcmp(callee, "ceil") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_ceil, type, op[0], NULL);
- } else if (strcmp(callee, "clamp") == 0) {
- assert(num_parameters == 3);
- unsigned c1_inc = op[1]->type->is_scalar() ? 0 : 1;
- unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
- for (unsigned c = 0, c1 = 0, c2 = 0;
- c < op[0]->type->components();
- c1 += c1_inc, c2 += c2_inc, c++) {
-
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.u[c] = CLAMP(op[0]->value.u[c], op[1]->value.u[c1],
- op[2]->value.u[c2]);
- break;
- case GLSL_TYPE_INT:
- data.i[c] = CLAMP(op[0]->value.i[c], op[1]->value.i[c1],
- op[2]->value.i[c2]);
- break;
- case GLSL_TYPE_FLOAT:
- data.f[c] = CLAMP(op[0]->value.f[c], op[1]->value.f[c1],
- op[2]->value.f[c2]);
- break;
- default:
- assert(!"Should not get here.");
- }
- }
- } else if (strcmp(callee, "cos") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_cos, type, op[0], NULL);
- } else if (strcmp(callee, "cosh") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = coshf(op[0]->value.f[c]);
- } else if (strcmp(callee, "cross") == 0) {
- assert(op[0]->type == glsl_type::vec3_type);
- assert(op[1]->type == glsl_type::vec3_type);
- data.f[0] = (op[0]->value.f[1] * op[1]->value.f[2] -
- op[1]->value.f[1] * op[0]->value.f[2]);
- data.f[1] = (op[0]->value.f[2] * op[1]->value.f[0] -
- op[1]->value.f[2] * op[0]->value.f[0]);
- data.f[2] = (op[0]->value.f[0] * op[1]->value.f[1] -
- op[1]->value.f[0] * op[0]->value.f[1]);
- } else if (strcmp(callee, "degrees") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = 180.0F / M_PI * op[0]->value.f[c];
- } else if (strcmp(callee, "distance") == 0) {
- assert(op[0]->type->is_float() && op[1]->type->is_float());
- float length_squared = 0.0;
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- float t = op[0]->value.f[c] - op[1]->value.f[c];
- length_squared += t * t;
- }
- return new(mem_ctx) ir_constant(sqrtf(length_squared));
- } else if (strcmp(callee, "dot") == 0) {
- return new(mem_ctx) ir_constant(dot(op[0], op[1]));
- } else if (strcmp(callee, "equal") == 0) {
- assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] == op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] == op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] == op[1]->value.f[c];
- break;
- case GLSL_TYPE_BOOL:
- data.b[c] = op[0]->value.b[c] == op[1]->value.b[c];
- break;
- default:
- assert(!"Should not get here.");
- }
- }
- } else if (strcmp(callee, "exp") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_exp, type, op[0], NULL);
- } else if (strcmp(callee, "exp2") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_exp2, type, op[0], NULL);
- } else if (strcmp(callee, "faceforward") == 0) {
- if (dot(op[2], op[1]) < 0)
- return op[0];
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = -op[0]->value.f[c];
- } else if (strcmp(callee, "floor") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_floor, type, op[0], NULL);
- } else if (strcmp(callee, "fract") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_fract, type, op[0], NULL);
- } else if (strcmp(callee, "fwidth") == 0) {
- return ir_constant::zero(mem_ctx, this->type);
- } else if (strcmp(callee, "greaterThan") == 0) {
- assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] > op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] > op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] > op[1]->value.f[c];
- break;
- default:
- assert(!"Should not get here.");
- }
- }
- } else if (strcmp(callee, "greaterThanEqual") == 0) {
- assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] >= op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] >= op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] >= op[1]->value.f[c];
- break;
- default:
- assert(!"Should not get here.");
- }
- }
- } else if (strcmp(callee, "inversesqrt") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_rsq, type, op[0], NULL);
- } else if (strcmp(callee, "length") == 0) {
- return new(mem_ctx) ir_constant(sqrtf(dot(op[0], op[0])));
- } else if (strcmp(callee, "lessThan") == 0) {
- assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] < op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] < op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] < op[1]->value.f[c];
- break;
- default:
- assert(!"Should not get here.");
- }
- }
- } else if (strcmp(callee, "lessThanEqual") == 0) {
- assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] <= op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] <= op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] <= op[1]->value.f[c];
- break;
- default:
- assert(!"Should not get here.");
- }
- }
- } else if (strcmp(callee, "log") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_log, type, op[0], NULL);
- } else if (strcmp(callee, "log2") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_log2, type, op[0], NULL);
- } else if (strcmp(callee, "matrixCompMult") == 0) {
- assert(op[0]->type->is_float() && op[1]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = op[0]->value.f[c] * op[1]->value.f[c];
- } else if (strcmp(callee, "max") == 0) {
- expr = new(mem_ctx) ir_expression(ir_binop_max, type, op[0], op[1]);
- } else if (strcmp(callee, "min") == 0) {
- expr = new(mem_ctx) ir_expression(ir_binop_min, type, op[0], op[1]);
- } else if (strcmp(callee, "mix") == 0) {
- assert(op[0]->type->is_float() && op[1]->type->is_float());
- if (op[2]->type->is_float()) {
- unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
- unsigned components = op[0]->type->components();
- for (unsigned c = 0, c2 = 0; c < components; c2 += c2_inc, c++) {
- data.f[c] = op[0]->value.f[c] * (1 - op[2]->value.f[c2]) +
- op[1]->value.f[c] * op[2]->value.f[c2];
- }
- } else {
- assert(op[2]->type->is_boolean());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = op[op[2]->value.b[c] ? 1 : 0]->value.f[c];
- }
- } else if (strcmp(callee, "mod") == 0) {
- expr = new(mem_ctx) ir_expression(ir_binop_mod, type, op[0], op[1]);
- } else if (strcmp(callee, "normalize") == 0) {
- assert(op[0]->type->is_float());
- float length = sqrtf(dot(op[0], op[0]));
-
- if (length == 0)
- return ir_constant::zero(mem_ctx, this->type);
-
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = op[0]->value.f[c] / length;
- } else if (strcmp(callee, "not") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_logic_not, type, op[0], NULL);
- } else if (strcmp(callee, "notEqual") == 0) {
- assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
- for (unsigned c = 0; c < op[0]->type->components(); c++) {
- switch (op[0]->type->base_type) {
- case GLSL_TYPE_UINT:
- data.b[c] = op[0]->value.u[c] != op[1]->value.u[c];
- break;
- case GLSL_TYPE_INT:
- data.b[c] = op[0]->value.i[c] != op[1]->value.i[c];
- break;
- case GLSL_TYPE_FLOAT:
- data.b[c] = op[0]->value.f[c] != op[1]->value.f[c];
- break;
- case GLSL_TYPE_BOOL:
- data.b[c] = op[0]->value.b[c] != op[1]->value.b[c];
- break;
- default:
- assert(!"Should not get here.");
- }
- }
- } else if (strcmp(callee, "outerProduct") == 0) {
- assert(op[0]->type->is_vector() && op[1]->type->is_vector());
- const unsigned m = op[0]->type->vector_elements;
- const unsigned n = op[1]->type->vector_elements;
- for (unsigned j = 0; j < n; j++) {
- for (unsigned i = 0; i < m; i++) {
- data.f[i+m*j] = op[0]->value.f[i] * op[1]->value.f[j];
- }
- }
- } else if (strcmp(callee, "pow") == 0) {
- expr = new(mem_ctx) ir_expression(ir_binop_pow, type, op[0], op[1]);
- } else if (strcmp(callee, "radians") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = M_PI / 180.0F * op[0]->value.f[c];
- } else if (strcmp(callee, "reflect") == 0) {
- assert(op[0]->type->is_float());
- float dot_NI = dot(op[1], op[0]);
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = op[0]->value.f[c] - 2 * dot_NI * op[1]->value.f[c];
- } else if (strcmp(callee, "refract") == 0) {
- const float eta = op[2]->value.f[0];
- const float dot_NI = dot(op[1], op[0]);
- const float k = 1.0F - eta * eta * (1.0F - dot_NI * dot_NI);
- if (k < 0.0) {
- return ir_constant::zero(mem_ctx, this->type);
- } else {
- for (unsigned c = 0; c < type->components(); c++) {
- data.f[c] = eta * op[0]->value.f[c] - (eta * dot_NI + sqrtf(k))
- * op[1]->value.f[c];
- }
- }
- } else if (strcmp(callee, "sign") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_sign, type, op[0], NULL);
- } else if (strcmp(callee, "sin") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_sin, type, op[0], NULL);
- } else if (strcmp(callee, "sinh") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = sinhf(op[0]->value.f[c]);
- } else if (strcmp(callee, "smoothstep") == 0) {
- assert(num_parameters == 3);
- assert(op[1]->type == op[0]->type);
- unsigned edge_inc = op[0]->type->is_scalar() ? 0 : 1;
- for (unsigned c = 0, e = 0; c < type->components(); e += edge_inc, c++) {
- const float edge0 = op[0]->value.f[e];
- const float edge1 = op[1]->value.f[e];
- if (edge0 == edge1) {
- data.f[c] = 0.0; /* Avoid a crash - results are undefined anyway */
- } else {
- const float numerator = op[2]->value.f[c] - edge0;
- const float denominator = edge1 - edge0;
- const float t = CLAMP(numerator/denominator, 0, 1);
- data.f[c] = t * t * (3 - 2 * t);
- }
- }
- } else if (strcmp(callee, "sqrt") == 0) {
- expr = new(mem_ctx) ir_expression(ir_unop_sqrt, type, op[0], NULL);
- } else if (strcmp(callee, "step") == 0) {
- assert(op[0]->type->is_float() && op[1]->type->is_float());
- /* op[0] (edge) may be either a scalar or a vector */
- const unsigned c0_inc = op[0]->type->is_scalar() ? 0 : 1;
- for (unsigned c = 0, c0 = 0; c < type->components(); c0 += c0_inc, c++)
- data.f[c] = (op[1]->value.f[c] < op[0]->value.f[c0]) ? 0.0F : 1.0F;
- } else if (strcmp(callee, "tan") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = tanf(op[0]->value.f[c]);
- } else if (strcmp(callee, "tanh") == 0) {
- assert(op[0]->type->is_float());
- for (unsigned c = 0; c < op[0]->type->components(); c++)
- data.f[c] = tanhf(op[0]->value.f[c]);
- } else if (strcmp(callee, "transpose") == 0) {
- assert(op[0]->type->is_matrix());
- const unsigned n = op[0]->type->vector_elements;
- const unsigned m = op[0]->type->matrix_columns;
- for (unsigned j = 0; j < m; j++) {
- for (unsigned i = 0; i < n; i++) {
- data.f[m*i+j] += op[0]->value.f[i+n*j];
- }
- }
- } else {
- /* Unsupported builtin - some are not allowed in constant expressions. */
- return NULL;
- }
-
- if (expr != NULL)
- return expr->constant_expression_value();
-
- return new(mem_ctx) ir_constant(this->type, &data);
-}
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_constant_expression.cpp
+ * Evaluate and process constant valued expressions
+ *
+ * In GLSL, constant valued expressions are used in several places. These
+ * must be processed and evaluated very early in the compilation process.
+ *
+ * * Sizes of arrays
+ * * Initializers for uniforms
+ * * Initializers for \c const variables
+ */
+
+#include <math.h>
+#include "main/core.h" /* for MAX2, MIN2, CLAMP */
+#include "ir.h"
+#include "ir_visitor.h"
+#include "glsl_types.h"
+
+static float
+dot(ir_constant *op0, ir_constant *op1)
+{
+ assert(op0->type->is_float() && op1->type->is_float());
+
+ float result = 0;
+ for (unsigned c = 0; c < op0->type->components(); c++)
+ result += op0->value.f[c] * op1->value.f[c];
+
+ return result;
+}
+
+ir_constant *
+ir_expression::constant_expression_value()
+{
+ if (this->type->is_error())
+ return NULL;
+
+ ir_constant *op[Elements(this->operands)] = { NULL, };
+ ir_constant_data data;
+
+ memset(&data, 0, sizeof(data));
+
+ for (unsigned operand = 0; operand < this->get_num_operands(); operand++) {
+ op[operand] = this->operands[operand]->constant_expression_value();
+ if (!op[operand])
+ return NULL;
+ }
+
+ if (op[1] != NULL)
+ assert(op[0]->type->base_type == op[1]->type->base_type);
+
+ bool op0_scalar = op[0]->type->is_scalar();
+ bool op1_scalar = op[1] != NULL && op[1]->type->is_scalar();
+
+ /* When iterating over a vector or matrix's components, we want to increase
+ * the loop counter. However, for scalars, we want to stay at 0.
+ */
+ unsigned c0_inc = op0_scalar ? 0 : 1;
+ unsigned c1_inc = op1_scalar ? 0 : 1;
+ unsigned components;
+ if (op1_scalar || !op[1]) {
+ components = op[0]->type->components();
+ } else {
+ components = op[1]->type->components();
+ }
+
+ void *ctx = ralloc_parent(this);
+
+ /* Handle array operations here, rather than below. */
+ if (op[0]->type->is_array()) {
+ assert(op[1] != NULL && op[1]->type->is_array());
+ switch (this->operation) {
+ case ir_binop_all_equal:
+ return new(ctx) ir_constant(op[0]->has_value(op[1]));
+ case ir_binop_any_nequal:
+ return new(ctx) ir_constant(!op[0]->has_value(op[1]));
+ default:
+ break;
+ }
+ return NULL;
+ }
+
+ switch (this->operation) {
+ case ir_unop_bit_not:
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_INT:
+ for (unsigned c = 0; c < components; c++)
+ data.i[c] = ~ op[0]->value.i[c];
+ break;
+ case GLSL_TYPE_UINT:
+ for (unsigned c = 0; c < components; c++)
+ data.u[c] = ~ op[0]->value.u[c];
+ break;
+ default:
+ assert(0);
+ }
+ break;
+
+ case ir_unop_logic_not:
+ assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.b[c] = !op[0]->value.b[c];
+ break;
+
+ case ir_unop_f2i:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.i[c] = (int) op[0]->value.f[c];
+ }
+ break;
+ case ir_unop_i2f:
+ assert(op[0]->type->base_type == GLSL_TYPE_INT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = (float) op[0]->value.i[c];
+ }
+ break;
+ case ir_unop_u2f:
+ assert(op[0]->type->base_type == GLSL_TYPE_UINT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = (float) op[0]->value.u[c];
+ }
+ break;
+ case ir_unop_b2f:
+ assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = op[0]->value.b[c] ? 1.0F : 0.0F;
+ }
+ break;
+ case ir_unop_f2b:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.b[c] = op[0]->value.f[c] != 0.0F ? true : false;
+ }
+ break;
+ case ir_unop_b2i:
+ assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.u[c] = op[0]->value.b[c] ? 1 : 0;
+ }
+ break;
+ case ir_unop_i2b:
+ assert(op[0]->type->is_integer());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.b[c] = op[0]->value.u[c] ? true : false;
+ }
+ break;
+
+ case ir_unop_any:
+ assert(op[0]->type->is_boolean());
+ data.b[0] = false;
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ if (op[0]->value.b[c])
+ data.b[0] = true;
+ }
+ break;
+
+ case ir_unop_trunc:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = truncf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_ceil:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = ceilf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_floor:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = floorf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_fract:
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = 0;
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = 0;
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = op[0]->value.f[c] - floor(op[0]->value.f[c]);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_unop_sin:
+ case ir_unop_sin_reduced:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = sinf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_cos:
+ case ir_unop_cos_reduced:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = cosf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_neg:
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = -((int) op[0]->value.u[c]);
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = -op[0]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = -op[0]->value.f[c];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_unop_abs:
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c];
+ if (data.i[c] < 0)
+ data.i[c] = -data.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = fabs(op[0]->value.f[c]);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_unop_sign:
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.i[c] > 0;
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = (op[0]->value.i[c] > 0) - (op[0]->value.i[c] < 0);
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = float((op[0]->value.f[c] > 0)-(op[0]->value.f[c] < 0));
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_unop_rcp:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT:
+ if (op[0]->value.u[c] != 0.0)
+ data.u[c] = 1 / op[0]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ if (op[0]->value.i[c] != 0.0)
+ data.i[c] = 1 / op[0]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ if (op[0]->value.f[c] != 0.0)
+ data.f[c] = 1.0F / op[0]->value.f[c];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_unop_rsq:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = 1.0F / sqrtf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_sqrt:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = sqrtf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_exp:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = expf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_exp2:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = exp2f(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_log:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = logf(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_log2:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = log2f(op[0]->value.f[c]);
+ }
+ break;
+
+ case ir_unop_dFdx:
+ case ir_unop_dFdy:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = 0.0;
+ }
+ break;
+
+ case ir_binop_pow:
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ data.f[c] = powf(op[0]->value.f[c], op[1]->value.f[c]);
+ }
+ break;
+
+ case ir_binop_dot:
+ data.f[0] = dot(op[0], op[1]);
+ break;
+
+ case ir_binop_min:
+ assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = MIN2(op[0]->value.u[c0], op[1]->value.u[c1]);
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = MIN2(op[0]->value.i[c0], op[1]->value.i[c1]);
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = MIN2(op[0]->value.f[c0], op[1]->value.f[c1]);
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ break;
+ case ir_binop_max:
+ assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = MAX2(op[0]->value.u[c0], op[1]->value.u[c1]);
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = MAX2(op[0]->value.i[c0], op[1]->value.i[c1]);
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = MAX2(op[0]->value.f[c0], op[1]->value.f[c1]);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_binop_add:
+ assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c0] + op[1]->value.u[c1];
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c0] + op[1]->value.i[c1];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = op[0]->value.f[c0] + op[1]->value.f[c1];
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ break;
+ case ir_binop_sub:
+ assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c0] - op[1]->value.u[c1];
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c0] - op[1]->value.i[c1];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = op[0]->value.f[c0] - op[1]->value.f[c1];
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ break;
+ case ir_binop_mul:
+ /* Check for equal types, or unequal types involving scalars */
+ if ((op[0]->type == op[1]->type && !op[0]->type->is_matrix())
+ || op0_scalar || op1_scalar) {
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c0] * op[1]->value.u[c1];
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c0] * op[1]->value.i[c1];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = op[0]->value.f[c0] * op[1]->value.f[c1];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ } else {
+ assert(op[0]->type->is_matrix() || op[1]->type->is_matrix());
+
+ /* Multiply an N-by-M matrix with an M-by-P matrix. Since either
+ * matrix can be a GLSL vector, either N or P can be 1.
+ *
+ * For vec*mat, the vector is treated as a row vector. This
+ * means the vector is a 1-row x M-column matrix.
+ *
+ * For mat*vec, the vector is treated as a column vector. Since
+ * matrix_columns is 1 for vectors, this just works.
+ */
+ const unsigned n = op[0]->type->is_vector()
+ ? 1 : op[0]->type->vector_elements;
+ const unsigned m = op[1]->type->vector_elements;
+ const unsigned p = op[1]->type->matrix_columns;
+ for (unsigned j = 0; j < p; j++) {
+ for (unsigned i = 0; i < n; i++) {
+ for (unsigned k = 0; k < m; k++) {
+ data.f[i+n*j] += op[0]->value.f[i+n*k]*op[1]->value.f[k+m*j];
+ }
+ }
+ }
+ }
+
+ break;
+ case ir_binop_div:
+ assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c0] / op[1]->value.u[c1];
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c0] / op[1]->value.i[c1];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = op[0]->value.f[c0] / op[1]->value.f[c1];
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ break;
+ case ir_binop_mod:
+ assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c0] % op[1]->value.u[c1];
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c0] % op[1]->value.i[c1];
+ break;
+ case GLSL_TYPE_FLOAT:
+ /* We don't use fmod because it rounds toward zero; GLSL specifies
+ * the use of floor.
+ */
+ data.f[c] = op[0]->value.f[c0] - op[1]->value.f[c1]
+ * floorf(op[0]->value.f[c0] / op[1]->value.f[c1]);
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ break;
+
+ case ir_binop_logic_and:
+ assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.b[c] = op[0]->value.b[c] && op[1]->value.b[c];
+ break;
+ case ir_binop_logic_xor:
+ assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.b[c] = op[0]->value.b[c] ^ op[1]->value.b[c];
+ break;
+ case ir_binop_logic_or:
+ assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.b[c] = op[0]->value.b[c] || op[1]->value.b[c];
+ break;
+
+ case ir_binop_less:
+ assert(op[0]->type == op[1]->type);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[0] = op[0]->value.u[0] < op[1]->value.u[0];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[0] = op[0]->value.i[0] < op[1]->value.i[0];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[0] = op[0]->value.f[0] < op[1]->value.f[0];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+ case ir_binop_greater:
+ assert(op[0]->type == op[1]->type);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] > op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] > op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] > op[1]->value.f[c];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+ case ir_binop_lequal:
+ assert(op[0]->type == op[1]->type);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[0] = op[0]->value.u[0] <= op[1]->value.u[0];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[0] = op[0]->value.i[0] <= op[1]->value.i[0];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[0] = op[0]->value.f[0] <= op[1]->value.f[0];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+ case ir_binop_gequal:
+ assert(op[0]->type == op[1]->type);
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[0] = op[0]->value.u[0] >= op[1]->value.u[0];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[0] = op[0]->value.i[0] >= op[1]->value.i[0];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[0] = op[0]->value.f[0] >= op[1]->value.f[0];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+ case ir_binop_equal:
+ assert(op[0]->type == op[1]->type);
+ for (unsigned c = 0; c < components; c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] == op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] == op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] == op[1]->value.f[c];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+ case ir_binop_nequal:
+ assert(op[0]->type != op[1]->type);
+ for (unsigned c = 0; c < components; c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] != op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] != op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] != op[1]->value.f[c];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+ case ir_binop_all_equal:
+ data.b[0] = op[0]->has_value(op[1]);
+ break;
+ case ir_binop_any_nequal:
+ data.b[0] = !op[0]->has_value(op[1]);
+ break;
+
+ case ir_binop_lshift:
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ if (op[0]->type->base_type == GLSL_TYPE_INT &&
+ op[1]->type->base_type == GLSL_TYPE_INT) {
+ data.i[c] = op[0]->value.i[c0] << op[1]->value.i[c1];
+
+ } else if (op[0]->type->base_type == GLSL_TYPE_INT &&
+ op[1]->type->base_type == GLSL_TYPE_UINT) {
+ data.i[c] = op[0]->value.i[c0] << op[1]->value.u[c1];
+
+ } else if (op[0]->type->base_type == GLSL_TYPE_UINT &&
+ op[1]->type->base_type == GLSL_TYPE_INT) {
+ data.u[c] = op[0]->value.u[c0] << op[1]->value.i[c1];
+
+ } else if (op[0]->type->base_type == GLSL_TYPE_UINT &&
+ op[1]->type->base_type == GLSL_TYPE_UINT) {
+ data.u[c] = op[0]->value.u[c0] << op[1]->value.u[c1];
+ }
+ }
+ break;
+
+ case ir_binop_rshift:
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ if (op[0]->type->base_type == GLSL_TYPE_INT &&
+ op[1]->type->base_type == GLSL_TYPE_INT) {
+ data.i[c] = op[0]->value.i[c0] >> op[1]->value.i[c1];
+
+ } else if (op[0]->type->base_type == GLSL_TYPE_INT &&
+ op[1]->type->base_type == GLSL_TYPE_UINT) {
+ data.i[c] = op[0]->value.i[c0] >> op[1]->value.u[c1];
+
+ } else if (op[0]->type->base_type == GLSL_TYPE_UINT &&
+ op[1]->type->base_type == GLSL_TYPE_INT) {
+ data.u[c] = op[0]->value.u[c0] >> op[1]->value.i[c1];
+
+ } else if (op[0]->type->base_type == GLSL_TYPE_UINT &&
+ op[1]->type->base_type == GLSL_TYPE_UINT) {
+ data.u[c] = op[0]->value.u[c0] >> op[1]->value.u[c1];
+ }
+ }
+ break;
+
+ case ir_binop_bit_and:
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c0] & op[1]->value.i[c1];
+ break;
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c0] & op[1]->value.u[c1];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_binop_bit_or:
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c0] | op[1]->value.i[c1];
+ break;
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c0] | op[1]->value.u[c1];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_binop_bit_xor:
+ for (unsigned c = 0, c0 = 0, c1 = 0;
+ c < components;
+ c0 += c0_inc, c1 += c1_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_INT:
+ data.i[c] = op[0]->value.i[c0] ^ op[1]->value.i[c1];
+ break;
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[0]->value.u[c0] ^ op[1]->value.u[c1];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ case ir_quadop_vector:
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_INT:
+ data.i[c] = op[c]->value.i[0];
+ break;
+ case GLSL_TYPE_UINT:
+ data.u[c] = op[c]->value.u[0];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = op[c]->value.f[0];
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+
+ default:
+ /* FINISHME: Should handle all expression types. */
+ return NULL;
+ }
+
+ return new(ctx) ir_constant(this->type, &data);
+}
+
+
+ir_constant *
+ir_texture::constant_expression_value()
+{
+ /* texture lookups aren't constant expressions */
+ return NULL;
+}
+
+
+ir_constant *
+ir_swizzle::constant_expression_value()
+{
+ ir_constant *v = this->val->constant_expression_value();
+
+ if (v != NULL) {
+ ir_constant_data data = { { 0 } };
+
+ const unsigned swiz_idx[4] = {
+ this->mask.x, this->mask.y, this->mask.z, this->mask.w
+ };
+
+ for (unsigned i = 0; i < this->mask.num_components; i++) {
+ switch (v->type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT: data.u[i] = v->value.u[swiz_idx[i]]; break;
+ case GLSL_TYPE_FLOAT: data.f[i] = v->value.f[swiz_idx[i]]; break;
+ case GLSL_TYPE_BOOL: data.b[i] = v->value.b[swiz_idx[i]]; break;
+ default: assert(!"Should not get here."); break;
+ }
+ }
+
+ void *ctx = ralloc_parent(this);
+ return new(ctx) ir_constant(this->type, &data);
+ }
+ return NULL;
+}
+
+
+ir_constant *
+ir_dereference_variable::constant_expression_value()
+{
+ /* This may occur during compile and var->type is glsl_type::error_type */
+ if (!var)
+ return NULL;
+
+ /* The constant_value of a uniform variable is its initializer,
+ * not the lifetime constant value of the uniform.
+ */
+ if (var->mode == ir_var_uniform)
+ return NULL;
+
+ if (!var->constant_value)
+ return NULL;
+
+ return var->constant_value->clone(ralloc_parent(var), NULL);
+}
+
+
+ir_constant *
+ir_dereference_array::constant_expression_value()
+{
+ ir_constant *array = this->array->constant_expression_value();
+ ir_constant *idx = this->array_index->constant_expression_value();
+
+ if ((array != NULL) && (idx != NULL)) {
+ void *ctx = ralloc_parent(this);
+ if (array->type->is_matrix()) {
+ /* Array access of a matrix results in a vector.
+ */
+ const unsigned column = idx->value.u[0];
+
+ const glsl_type *const column_type = array->type->column_type();
+
+ /* Offset in the constant matrix to the first element of the column
+ * to be extracted.
+ */
+ const unsigned mat_idx = column * column_type->vector_elements;
+
+ ir_constant_data data = { { 0 } };
+
+ switch (column_type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ for (unsigned i = 0; i < column_type->vector_elements; i++)
+ data.u[i] = array->value.u[mat_idx + i];
+
+ break;
+
+ case GLSL_TYPE_FLOAT:
+ for (unsigned i = 0; i < column_type->vector_elements; i++)
+ data.f[i] = array->value.f[mat_idx + i];
+
+ break;
+
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+
+ return new(ctx) ir_constant(column_type, &data);
+ } else if (array->type->is_vector()) {
+ const unsigned component = idx->value.u[0];
+
+ return new(ctx) ir_constant(array, component);
+ } else {
+ const unsigned index = idx->value.u[0];
+ return array->get_array_element(index)->clone(ctx, NULL);
+ }
+ }
+ return NULL;
+}
+
+
+ir_constant *
+ir_dereference_record::constant_expression_value()
+{
+ ir_constant *v = this->record->constant_expression_value();
+
+ return (v != NULL) ? v->get_record_field(this->field) : NULL;
+}
+
+
+ir_constant *
+ir_assignment::constant_expression_value()
+{
+ /* FINISHME: Handle CEs involving assignment (return RHS) */
+ return NULL;
+}
+
+
+ir_constant *
+ir_constant::constant_expression_value()
+{
+ return this;
+}
+
+
+ir_constant *
+ir_call::constant_expression_value()
+{
+ if (this->type == glsl_type::error_type)
+ return NULL;
+
+ /* From the GLSL 1.20 spec, page 23:
+ * "Function calls to user-defined functions (non-built-in functions)
+ * cannot be used to form constant expressions."
+ */
+ if (!this->callee->is_builtin)
+ return NULL;
+
+ unsigned num_parameters = 0;
+
+ /* Check if all parameters are constant */
+ ir_constant *op[3];
+ foreach_list(n, &this->actual_parameters) {
+ ir_constant *constant = ((ir_rvalue *) n)->constant_expression_value();
+ if (constant == NULL)
+ return NULL;
+
+ op[num_parameters] = constant;
+
+ assert(num_parameters < 3);
+ num_parameters++;
+ }
+
+ /* Individual cases below can either:
+ * - Assign "expr" a new ir_expression to evaluate (for basic opcodes)
+ * - Fill "data" with appopriate constant data
+ * - Return an ir_constant directly.
+ */
+ void *mem_ctx = ralloc_parent(this);
+ ir_expression *expr = NULL;
+
+ ir_constant_data data;
+ memset(&data, 0, sizeof(data));
+
+ const char *callee = this->callee_name();
+ if (strcmp(callee, "abs") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_abs, type, op[0], NULL);
+ } else if (strcmp(callee, "all") == 0) {
+ assert(op[0]->type->is_boolean());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ if (!op[0]->value.b[c])
+ return new(mem_ctx) ir_constant(false);
+ }
+ return new(mem_ctx) ir_constant(true);
+ } else if (strcmp(callee, "any") == 0) {
+ assert(op[0]->type->is_boolean());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ if (op[0]->value.b[c])
+ return new(mem_ctx) ir_constant(true);
+ }
+ return new(mem_ctx) ir_constant(false);
+ } else if (strcmp(callee, "acos") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = acosf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "acosh") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = acoshf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "asin") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = asinf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "asinh") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = asinhf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "atan") == 0) {
+ assert(op[0]->type->is_float());
+ if (num_parameters == 2) {
+ assert(op[1]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = atan2f(op[0]->value.f[c], op[1]->value.f[c]);
+ } else {
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = atanf(op[0]->value.f[c]);
+ }
+ } else if (strcmp(callee, "atanh") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = atanhf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "dFdx") == 0 || strcmp(callee, "dFdy") == 0) {
+ return ir_constant::zero(mem_ctx, this->type);
+ } else if (strcmp(callee, "ceil") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_ceil, type, op[0], NULL);
+ } else if (strcmp(callee, "clamp") == 0) {
+ assert(num_parameters == 3);
+ unsigned c1_inc = op[1]->type->is_scalar() ? 0 : 1;
+ unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
+ for (unsigned c = 0, c1 = 0, c2 = 0;
+ c < op[0]->type->components();
+ c1 += c1_inc, c2 += c2_inc, c++) {
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[c] = CLAMP(op[0]->value.u[c], op[1]->value.u[c1],
+ op[2]->value.u[c2]);
+ break;
+ case GLSL_TYPE_INT:
+ data.i[c] = CLAMP(op[0]->value.i[c], op[1]->value.i[c1],
+ op[2]->value.i[c2]);
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[c] = CLAMP(op[0]->value.f[c], op[1]->value.f[c1],
+ op[2]->value.f[c2]);
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+ }
+ } else if (strcmp(callee, "cos") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_cos, type, op[0], NULL);
+ } else if (strcmp(callee, "cosh") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = coshf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "cross") == 0) {
+ assert(op[0]->type == glsl_type::vec3_type);
+ assert(op[1]->type == glsl_type::vec3_type);
+ data.f[0] = (op[0]->value.f[1] * op[1]->value.f[2] -
+ op[1]->value.f[1] * op[0]->value.f[2]);
+ data.f[1] = (op[0]->value.f[2] * op[1]->value.f[0] -
+ op[1]->value.f[2] * op[0]->value.f[0]);
+ data.f[2] = (op[0]->value.f[0] * op[1]->value.f[1] -
+ op[1]->value.f[0] * op[0]->value.f[1]);
+ } else if (strcmp(callee, "degrees") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = 180.0F / M_PI * op[0]->value.f[c];
+ } else if (strcmp(callee, "distance") == 0) {
+ assert(op[0]->type->is_float() && op[1]->type->is_float());
+ float length_squared = 0.0;
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ float t = op[0]->value.f[c] - op[1]->value.f[c];
+ length_squared += t * t;
+ }
+ return new(mem_ctx) ir_constant(sqrtf(length_squared));
+ } else if (strcmp(callee, "dot") == 0) {
+ return new(mem_ctx) ir_constant(dot(op[0], op[1]));
+ } else if (strcmp(callee, "equal") == 0) {
+ assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] == op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] == op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] == op[1]->value.f[c];
+ break;
+ case GLSL_TYPE_BOOL:
+ data.b[c] = op[0]->value.b[c] == op[1]->value.b[c];
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+ }
+ } else if (strcmp(callee, "exp") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_exp, type, op[0], NULL);
+ } else if (strcmp(callee, "exp2") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_exp2, type, op[0], NULL);
+ } else if (strcmp(callee, "faceforward") == 0) {
+ if (dot(op[2], op[1]) < 0)
+ return op[0];
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = -op[0]->value.f[c];
+ } else if (strcmp(callee, "floor") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_floor, type, op[0], NULL);
+ } else if (strcmp(callee, "fract") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_fract, type, op[0], NULL);
+ } else if (strcmp(callee, "fwidth") == 0) {
+ return ir_constant::zero(mem_ctx, this->type);
+ } else if (strcmp(callee, "greaterThan") == 0) {
+ assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] > op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] > op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] > op[1]->value.f[c];
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+ }
+ } else if (strcmp(callee, "greaterThanEqual") == 0) {
+ assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] >= op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] >= op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] >= op[1]->value.f[c];
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+ }
+ } else if (strcmp(callee, "inversesqrt") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_rsq, type, op[0], NULL);
+ } else if (strcmp(callee, "length") == 0) {
+ return new(mem_ctx) ir_constant(sqrtf(dot(op[0], op[0])));
+ } else if (strcmp(callee, "lessThan") == 0) {
+ assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] < op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] < op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] < op[1]->value.f[c];
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+ }
+ } else if (strcmp(callee, "lessThanEqual") == 0) {
+ assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] <= op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] <= op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] <= op[1]->value.f[c];
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+ }
+ } else if (strcmp(callee, "log") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_log, type, op[0], NULL);
+ } else if (strcmp(callee, "log2") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_log2, type, op[0], NULL);
+ } else if (strcmp(callee, "matrixCompMult") == 0) {
+ assert(op[0]->type->is_float() && op[1]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = op[0]->value.f[c] * op[1]->value.f[c];
+ } else if (strcmp(callee, "max") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_binop_max, type, op[0], op[1]);
+ } else if (strcmp(callee, "min") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_binop_min, type, op[0], op[1]);
+ } else if (strcmp(callee, "mix") == 0) {
+ assert(op[0]->type->is_float() && op[1]->type->is_float());
+ if (op[2]->type->is_float()) {
+ unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
+ unsigned components = op[0]->type->components();
+ for (unsigned c = 0, c2 = 0; c < components; c2 += c2_inc, c++) {
+ data.f[c] = op[0]->value.f[c] * (1 - op[2]->value.f[c2]) +
+ op[1]->value.f[c] * op[2]->value.f[c2];
+ }
+ } else {
+ assert(op[2]->type->is_boolean());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = op[op[2]->value.b[c] ? 1 : 0]->value.f[c];
+ }
+ } else if (strcmp(callee, "mod") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_binop_mod, type, op[0], op[1]);
+ } else if (strcmp(callee, "normalize") == 0) {
+ assert(op[0]->type->is_float());
+ float length = sqrtf(dot(op[0], op[0]));
+
+ if (length == 0)
+ return ir_constant::zero(mem_ctx, this->type);
+
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = op[0]->value.f[c] / length;
+ } else if (strcmp(callee, "not") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_logic_not, type, op[0], NULL);
+ } else if (strcmp(callee, "notEqual") == 0) {
+ assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
+ for (unsigned c = 0; c < op[0]->type->components(); c++) {
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.b[c] = op[0]->value.u[c] != op[1]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.b[c] = op[0]->value.i[c] != op[1]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.b[c] = op[0]->value.f[c] != op[1]->value.f[c];
+ break;
+ case GLSL_TYPE_BOOL:
+ data.b[c] = op[0]->value.b[c] != op[1]->value.b[c];
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+ }
+ } else if (strcmp(callee, "outerProduct") == 0) {
+ assert(op[0]->type->is_vector() && op[1]->type->is_vector());
+ const unsigned m = op[0]->type->vector_elements;
+ const unsigned n = op[1]->type->vector_elements;
+ for (unsigned j = 0; j < n; j++) {
+ for (unsigned i = 0; i < m; i++) {
+ data.f[i+m*j] = op[0]->value.f[i] * op[1]->value.f[j];
+ }
+ }
+ } else if (strcmp(callee, "pow") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_binop_pow, type, op[0], op[1]);
+ } else if (strcmp(callee, "radians") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = M_PI / 180.0F * op[0]->value.f[c];
+ } else if (strcmp(callee, "reflect") == 0) {
+ assert(op[0]->type->is_float());
+ float dot_NI = dot(op[1], op[0]);
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = op[0]->value.f[c] - 2 * dot_NI * op[1]->value.f[c];
+ } else if (strcmp(callee, "refract") == 0) {
+ const float eta = op[2]->value.f[0];
+ const float dot_NI = dot(op[1], op[0]);
+ const float k = 1.0F - eta * eta * (1.0F - dot_NI * dot_NI);
+ if (k < 0.0) {
+ return ir_constant::zero(mem_ctx, this->type);
+ } else {
+ for (unsigned c = 0; c < type->components(); c++) {
+ data.f[c] = eta * op[0]->value.f[c] - (eta * dot_NI + sqrtf(k))
+ * op[1]->value.f[c];
+ }
+ }
+ } else if (strcmp(callee, "sign") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_sign, type, op[0], NULL);
+ } else if (strcmp(callee, "sin") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_sin, type, op[0], NULL);
+ } else if (strcmp(callee, "sinh") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = sinhf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "smoothstep") == 0) {
+ assert(num_parameters == 3);
+ assert(op[1]->type == op[0]->type);
+ unsigned edge_inc = op[0]->type->is_scalar() ? 0 : 1;
+ for (unsigned c = 0, e = 0; c < type->components(); e += edge_inc, c++) {
+ const float edge0 = op[0]->value.f[e];
+ const float edge1 = op[1]->value.f[e];
+ if (edge0 == edge1) {
+ data.f[c] = 0.0; /* Avoid a crash - results are undefined anyway */
+ } else {
+ const float numerator = op[2]->value.f[c] - edge0;
+ const float denominator = edge1 - edge0;
+ const float t = CLAMP(numerator/denominator, 0, 1);
+ data.f[c] = t * t * (3 - 2 * t);
+ }
+ }
+ } else if (strcmp(callee, "sqrt") == 0) {
+ expr = new(mem_ctx) ir_expression(ir_unop_sqrt, type, op[0], NULL);
+ } else if (strcmp(callee, "step") == 0) {
+ assert(op[0]->type->is_float() && op[1]->type->is_float());
+ /* op[0] (edge) may be either a scalar or a vector */
+ const unsigned c0_inc = op[0]->type->is_scalar() ? 0 : 1;
+ for (unsigned c = 0, c0 = 0; c < type->components(); c0 += c0_inc, c++)
+ data.f[c] = (op[1]->value.f[c] < op[0]->value.f[c0]) ? 0.0F : 1.0F;
+ } else if (strcmp(callee, "tan") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = tanf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "tanh") == 0) {
+ assert(op[0]->type->is_float());
+ for (unsigned c = 0; c < op[0]->type->components(); c++)
+ data.f[c] = tanhf(op[0]->value.f[c]);
+ } else if (strcmp(callee, "transpose") == 0) {
+ assert(op[0]->type->is_matrix());
+ const unsigned n = op[0]->type->vector_elements;
+ const unsigned m = op[0]->type->matrix_columns;
+ for (unsigned j = 0; j < m; j++) {
+ for (unsigned i = 0; i < n; i++) {
+ data.f[m*i+j] += op[0]->value.f[i+n*j];
+ }
+ }
+ } else {
+ /* Unsupported builtin - some are not allowed in constant expressions. */
+ return NULL;
+ }
+
+ if (expr != NULL)
+ return expr->constant_expression_value();
+
+ return new(mem_ctx) ir_constant(this->type, &data);
+}
diff --git a/mesalib/src/glsl/ir_expression_flattening.cpp b/mesalib/src/glsl/ir_expression_flattening.cpp
index 7b1b8dbfe..0b7c537bd 100644
--- a/mesalib/src/glsl/ir_expression_flattening.cpp
+++ b/mesalib/src/glsl/ir_expression_flattening.cpp
@@ -78,7 +78,7 @@ ir_expression_flattening_visitor::handle_rvalue(ir_rvalue **rvalue)
if (!ir || !this->predicate(ir))
return;
- void *ctx = talloc_parent(ir);
+ void *ctx = ralloc_parent(ir);
var = new(ctx) ir_variable(ir->type, "flattening_tmp", ir_var_temporary);
base_ir->insert_before(var);
diff --git a/mesalib/src/glsl/ir_function.cpp b/mesalib/src/glsl/ir_function.cpp
index 4997570d0..caee9296a 100644
--- a/mesalib/src/glsl/ir_function.cpp
+++ b/mesalib/src/glsl/ir_function.cpp
@@ -1,226 +1,227 @@
-/*
- * 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 "glsl_types.h"
-#include "ir.h"
-
-int
-type_compare(const glsl_type *a, const glsl_type *b)
-{
- /* If the types are the same, they trivially match.
- */
- if (a == b)
- return 0;
-
- switch (a->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- case GLSL_TYPE_BOOL:
- /* There is no implicit conversion to or from integer types or bool.
- */
- if ((a->is_integer() != b->is_integer())
- || (a->is_boolean() != b->is_boolean()))
- return -1;
-
- /* FALLTHROUGH */
-
- case GLSL_TYPE_FLOAT:
- if ((a->vector_elements != b->vector_elements)
- || (a->matrix_columns != b->matrix_columns))
- return -1;
-
- return 1;
-
- case GLSL_TYPE_SAMPLER:
- case GLSL_TYPE_STRUCT:
- /* Samplers and structures must match exactly.
- */
- return -1;
-
- case GLSL_TYPE_ARRAY:
- if ((b->base_type != GLSL_TYPE_ARRAY)
- || (a->length != b->length))
- return -1;
-
- /* From GLSL 1.50 spec, page 27 (page 33 of the PDF):
- * "There are no implicit array or structure conversions."
- *
- * If the comparison of the array element types detects that a conversion
- * would be required, the array types do not match.
- */
- return (type_compare(a->fields.array, b->fields.array) == 0) ? 0 : -1;
-
- case GLSL_TYPE_VOID:
- case GLSL_TYPE_ERROR:
- default:
- /* These are all error conditions. It is invalid for a parameter to
- * a function to be declared as error, void, or a function.
- */
- return -1;
- }
-
- /* This point should be unreachable.
- */
- assert(0);
-}
-
-
-static int
-parameter_lists_match(const exec_list *list_a, const exec_list *list_b)
-{
- const exec_node *node_a = list_a->head;
- const exec_node *node_b = list_b->head;
- int total_score = 0;
-
- for (/* empty */
- ; !node_a->is_tail_sentinel()
- ; node_a = node_a->next, node_b = node_b->next) {
- /* 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 (node_b->is_tail_sentinel())
- return -1;
-
-
- const ir_variable *const param = (ir_variable *) node_a;
- const ir_instruction *const actual = (ir_instruction *) node_b;
-
- /* Determine whether or not the types match. If the types are an
- * exact match, the match score is zero. If the types don't match
- * but the actual parameter can be coerced to the type of the declared
- * parameter, the match score is one.
- */
- int score;
- switch ((enum ir_variable_mode)(param->mode)) {
- case ir_var_auto:
- case ir_var_uniform:
- case ir_var_temporary:
- /* These are all error conditions. It is invalid for a parameter to
- * a function to be declared as auto (not in, out, or inout) or
- * as uniform.
- */
- assert(0);
- return -1;
-
- case ir_var_in:
- score = type_compare(param->type, actual->type);
- break;
-
- case ir_var_out:
- score = type_compare(actual->type, param->type);
- break;
-
- case ir_var_inout:
- /* Since there are no bi-directional automatic conversions (e.g.,
- * there is int -> float but no float -> int), inout parameters must
- * be exact matches.
- */
- score = (type_compare(actual->type, param->type) == 0) ? 0 : -1;
- break;
-
- default:
- assert(false);
- }
-
- if (score < 0)
- return -1;
-
- total_score += score;
- }
-
- /* 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 (!node_b->is_tail_sentinel())
- return -1;
-
- return total_score;
-}
-
-
-ir_function_signature *
-ir_function::matching_signature(const exec_list *actual_parameters)
-{
- ir_function_signature *match = NULL;
-
- foreach_iter(exec_list_iterator, iter, signatures) {
- ir_function_signature *const sig =
- (ir_function_signature *) iter.get();
-
- const int score = parameter_lists_match(& sig->parameters,
- actual_parameters);
-
- if (score == 0)
- return sig;
-
- if (score > 0) {
- if (match != NULL)
- return NULL;
-
- match = sig;
- }
- }
-
- return match;
-}
-
-
-static bool
-parameter_lists_match_exact(const exec_list *list_a, const exec_list *list_b)
-{
- const exec_node *node_a = list_a->head;
- const exec_node *node_b = list_b->head;
-
- for (/* empty */
- ; !node_a->is_tail_sentinel() && !node_b->is_tail_sentinel()
- ; node_a = node_a->next, node_b = node_b->next) {
- ir_variable *a = (ir_variable *) node_a;
- ir_variable *b = (ir_variable *) node_b;
-
- /* If the types of the parameters do not match, the parameters lists
- * are different.
- */
- if (a->type != b->type)
- return false;
- }
-
- /* Unless both lists are exhausted, they differ in length and, by
- * definition, do not match.
- */
- return (node_a->is_tail_sentinel() == node_b->is_tail_sentinel());
-}
-
-ir_function_signature *
-ir_function::exact_matching_signature(const exec_list *actual_parameters)
-{
- foreach_iter(exec_list_iterator, iter, signatures) {
- ir_function_signature *const sig =
- (ir_function_signature *) iter.get();
-
- if (parameter_lists_match_exact(&sig->parameters, actual_parameters))
- return sig;
- }
- return NULL;
-}
+/*
+ * 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 "glsl_types.h"
+#include "ir.h"
+
+int
+type_compare(const glsl_type *a, const glsl_type *b)
+{
+ /* If the types are the same, they trivially match.
+ */
+ if (a == b)
+ return 0;
+
+ switch (a->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_BOOL:
+ /* There is no implicit conversion to or from integer types or bool.
+ */
+ if ((a->is_integer() != b->is_integer())
+ || (a->is_boolean() != b->is_boolean()))
+ return -1;
+
+ /* FALLTHROUGH */
+
+ case GLSL_TYPE_FLOAT:
+ if ((a->vector_elements != b->vector_elements)
+ || (a->matrix_columns != b->matrix_columns))
+ return -1;
+
+ return 1;
+
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_STRUCT:
+ /* Samplers and structures must match exactly.
+ */
+ return -1;
+
+ case GLSL_TYPE_ARRAY:
+ if ((b->base_type != GLSL_TYPE_ARRAY)
+ || (a->length != b->length))
+ return -1;
+
+ /* From GLSL 1.50 spec, page 27 (page 33 of the PDF):
+ * "There are no implicit array or structure conversions."
+ *
+ * If the comparison of the array element types detects that a conversion
+ * would be required, the array types do not match.
+ */
+ return (type_compare(a->fields.array, b->fields.array) == 0) ? 0 : -1;
+
+ case GLSL_TYPE_VOID:
+ case GLSL_TYPE_ERROR:
+ default:
+ /* These are all error conditions. It is invalid for a parameter to
+ * a function to be declared as error, void, or a function.
+ */
+ return -1;
+ }
+
+ /* This point should be unreachable.
+ */
+ assert(0);
+}
+
+
+static int
+parameter_lists_match(const exec_list *list_a, const exec_list *list_b)
+{
+ const exec_node *node_a = list_a->head;
+ const exec_node *node_b = list_b->head;
+ int total_score = 0;
+
+ for (/* empty */
+ ; !node_a->is_tail_sentinel()
+ ; node_a = node_a->next, node_b = node_b->next) {
+ /* 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 (node_b->is_tail_sentinel())
+ return -1;
+
+
+ const ir_variable *const param = (ir_variable *) node_a;
+ const ir_instruction *const actual = (ir_instruction *) node_b;
+
+ /* Determine whether or not the types match. If the types are an
+ * exact match, the match score is zero. If the types don't match
+ * but the actual parameter can be coerced to the type of the declared
+ * parameter, the match score is one.
+ */
+ int score;
+ switch ((enum ir_variable_mode)(param->mode)) {
+ case ir_var_auto:
+ case ir_var_uniform:
+ case ir_var_temporary:
+ /* These are all error conditions. It is invalid for a parameter to
+ * a function to be declared as auto (not in, out, or inout) or
+ * as uniform.
+ */
+ assert(0);
+ return -1;
+
+ case ir_var_const_in:
+ case ir_var_in:
+ score = type_compare(param->type, actual->type);
+ break;
+
+ case ir_var_out:
+ score = type_compare(actual->type, param->type);
+ break;
+
+ case ir_var_inout:
+ /* Since there are no bi-directional automatic conversions (e.g.,
+ * there is int -> float but no float -> int), inout parameters must
+ * be exact matches.
+ */
+ score = (type_compare(actual->type, param->type) == 0) ? 0 : -1;
+ break;
+
+ default:
+ assert(false);
+ }
+
+ if (score < 0)
+ return -1;
+
+ total_score += score;
+ }
+
+ /* 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 (!node_b->is_tail_sentinel())
+ return -1;
+
+ return total_score;
+}
+
+
+ir_function_signature *
+ir_function::matching_signature(const exec_list *actual_parameters)
+{
+ ir_function_signature *match = NULL;
+
+ foreach_iter(exec_list_iterator, iter, signatures) {
+ ir_function_signature *const sig =
+ (ir_function_signature *) iter.get();
+
+ const int score = parameter_lists_match(& sig->parameters,
+ actual_parameters);
+
+ if (score == 0)
+ return sig;
+
+ if (score > 0) {
+ if (match != NULL)
+ return NULL;
+
+ match = sig;
+ }
+ }
+
+ return match;
+}
+
+
+static bool
+parameter_lists_match_exact(const exec_list *list_a, const exec_list *list_b)
+{
+ const exec_node *node_a = list_a->head;
+ const exec_node *node_b = list_b->head;
+
+ for (/* empty */
+ ; !node_a->is_tail_sentinel() && !node_b->is_tail_sentinel()
+ ; node_a = node_a->next, node_b = node_b->next) {
+ ir_variable *a = (ir_variable *) node_a;
+ ir_variable *b = (ir_variable *) node_b;
+
+ /* If the types of the parameters do not match, the parameters lists
+ * are different.
+ */
+ if (a->type != b->type)
+ return false;
+ }
+
+ /* Unless both lists are exhausted, they differ in length and, by
+ * definition, do not match.
+ */
+ return (node_a->is_tail_sentinel() == node_b->is_tail_sentinel());
+}
+
+ir_function_signature *
+ir_function::exact_matching_signature(const exec_list *actual_parameters)
+{
+ foreach_iter(exec_list_iterator, iter, signatures) {
+ ir_function_signature *const sig =
+ (ir_function_signature *) iter.get();
+
+ if (parameter_lists_match_exact(&sig->parameters, actual_parameters))
+ return sig;
+ }
+ return NULL;
+}
diff --git a/mesalib/src/glsl/ir_hv_accept.cpp b/mesalib/src/glsl/ir_hv_accept.cpp
index be8b36a7c..4a607dc87 100644
--- a/mesalib/src/glsl/ir_hv_accept.cpp
+++ b/mesalib/src/glsl/ir_hv_accept.cpp
@@ -187,6 +187,12 @@ ir_texture::accept(ir_hierarchical_visitor *v)
return (s == visit_continue_with_parent) ? visit_continue : s;
}
+ if (this->offset) {
+ s = this->offset->accept(v);
+ if (s != visit_continue)
+ return (s == visit_continue_with_parent) ? visit_continue : s;
+ }
+
switch (this->op) {
case ir_tex:
break;
diff --git a/mesalib/src/glsl/ir_import_prototypes.cpp b/mesalib/src/glsl/ir_import_prototypes.cpp
index fcd552870..be5e0c1d3 100644
--- a/mesalib/src/glsl/ir_import_prototypes.cpp
+++ b/mesalib/src/glsl/ir_import_prototypes.cpp
@@ -1,123 +1,123 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_import_prototypes.cpp
- * Import function prototypes from one IR tree into another.
- *
- * \author Ian Romanick
- */
-#include <cstdio>
-#include "ir.h"
-#include "glsl_symbol_table.h"
-
-/**
- * Visitor used to import function prototypes
- *
- * Normally the \c clone method of either \c ir_function or
- * \c ir_function_signature could be used. However, we don't want a complete
- * clone of the \c ir_function_signature. We want everything \b except the
- * body of the function.
- */
-class import_prototype_visitor : public ir_hierarchical_visitor {
-public:
- /**
- */
- import_prototype_visitor(exec_list *list, glsl_symbol_table *symbols,
- void *mem_ctx)
- {
- this->mem_ctx = mem_ctx;
- this->list = list;
- this->symbols = symbols;
- this->function = NULL;
- }
-
- virtual ir_visitor_status visit_enter(ir_function *ir)
- {
- assert(this->function == NULL);
-
- this->function = this->symbols->get_function(ir->name);
- if (!this->function) {
- this->function = new(this->mem_ctx) ir_function(ir->name);
-
- list->push_tail(this->function);
-
- /* Add the new function to the symbol table.
- */
- this->symbols->add_function(this->function);
- }
- return visit_continue;
- }
-
- virtual ir_visitor_status visit_leave(ir_function *ir)
- {
- (void) ir;
- assert(this->function != NULL);
-
- this->function = NULL;
- return visit_continue;
- }
-
- ir_visitor_status visit_enter(ir_function_signature *ir)
- {
- assert(this->function != NULL);
-
- ir_function_signature *copy = ir->clone_prototype(mem_ctx, NULL);
-
- this->function->add_signature(copy);
-
- /* Do not process child nodes of the ir_function_signature. There can
- * never be any nodes inside the ir_function_signature that we care
- * about. Instead continue with the next sibling.
- */
- return visit_continue_with_parent;
- }
-
-private:
- exec_list *list;
- ir_function *function;
- glsl_symbol_table *symbols;
- void *mem_ctx;
-};
-
-
-/**
- * Import function prototypes from one IR tree into another
- *
- * \param source Source instruction stream containing functions whose
- * prototypes are to be imported
- * \param dest Destination instruction stream where new \c ir_function and
- * \c ir_function_signature nodes will be stored
- * \param symbols Symbol table where new functions will be stored
- * \param mem_ctx talloc memory context used for new allocations
- */
-void
-import_prototypes(const exec_list *source, exec_list *dest,
- glsl_symbol_table *symbols, void *mem_ctx)
-{
- import_prototype_visitor v(dest, symbols, mem_ctx);
-
- /* Making source be const is just extra documentation.
- */
- v.run(const_cast<exec_list *>(source));
-}
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_import_prototypes.cpp
+ * Import function prototypes from one IR tree into another.
+ *
+ * \author Ian Romanick
+ */
+#include <cstdio>
+#include "ir.h"
+#include "glsl_symbol_table.h"
+
+/**
+ * Visitor used to import function prototypes
+ *
+ * Normally the \c clone method of either \c ir_function or
+ * \c ir_function_signature could be used. However, we don't want a complete
+ * clone of the \c ir_function_signature. We want everything \b except the
+ * body of the function.
+ */
+class import_prototype_visitor : public ir_hierarchical_visitor {
+public:
+ /**
+ */
+ import_prototype_visitor(exec_list *list, glsl_symbol_table *symbols,
+ void *mem_ctx)
+ {
+ this->mem_ctx = mem_ctx;
+ this->list = list;
+ this->symbols = symbols;
+ this->function = NULL;
+ }
+
+ virtual ir_visitor_status visit_enter(ir_function *ir)
+ {
+ assert(this->function == NULL);
+
+ this->function = this->symbols->get_function(ir->name);
+ if (!this->function) {
+ this->function = new(this->mem_ctx) ir_function(ir->name);
+
+ list->push_tail(this->function);
+
+ /* Add the new function to the symbol table.
+ */
+ this->symbols->add_function(this->function);
+ }
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_function *ir)
+ {
+ (void) ir;
+ assert(this->function != NULL);
+
+ this->function = NULL;
+ return visit_continue;
+ }
+
+ ir_visitor_status visit_enter(ir_function_signature *ir)
+ {
+ assert(this->function != NULL);
+
+ ir_function_signature *copy = ir->clone_prototype(mem_ctx, NULL);
+
+ this->function->add_signature(copy);
+
+ /* Do not process child nodes of the ir_function_signature. There can
+ * never be any nodes inside the ir_function_signature that we care
+ * about. Instead continue with the next sibling.
+ */
+ return visit_continue_with_parent;
+ }
+
+private:
+ exec_list *list;
+ ir_function *function;
+ glsl_symbol_table *symbols;
+ void *mem_ctx;
+};
+
+
+/**
+ * Import function prototypes from one IR tree into another
+ *
+ * \param source Source instruction stream containing functions whose
+ * prototypes are to be imported
+ * \param dest Destination instruction stream where new \c ir_function and
+ * \c ir_function_signature nodes will be stored
+ * \param symbols Symbol table where new functions will be stored
+ * \param mem_ctx ralloc memory context used for new allocations
+ */
+void
+import_prototypes(const exec_list *source, exec_list *dest,
+ glsl_symbol_table *symbols, void *mem_ctx)
+{
+ import_prototype_visitor v(dest, symbols, mem_ctx);
+
+ /* Making source be const is just extra documentation.
+ */
+ v.run(const_cast<exec_list *>(source));
+}
diff --git a/mesalib/src/glsl/ir_print_visitor.cpp b/mesalib/src/glsl/ir_print_visitor.cpp
index 3609c0e12..82ccc722f 100644
--- a/mesalib/src/glsl/ir_print_visitor.cpp
+++ b/mesalib/src/glsl/ir_print_visitor.cpp
@@ -1,463 +1,471 @@
-/*
- * 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 "ir_print_visitor.h"
-#include "glsl_types.h"
-#include "glsl_parser_extras.h"
-
-static void print_type(const glsl_type *t);
-
-void
-ir_instruction::print(void) const
-{
- ir_instruction *deconsted = const_cast<ir_instruction *>(this);
-
- ir_print_visitor v;
- deconsted->accept(&v);
-}
-
-void
-_mesa_print_ir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- if (state) {
- for (unsigned i = 0; i < state->num_user_structures; i++) {
- const glsl_type *const s = state->user_structures[i];
-
- printf("(structure (%s) (%s@%p) (%u) (\n",
- s->name, s->name, (void *) s, s->length);
-
- for (unsigned j = 0; j < s->length; j++) {
- printf("\t((");
- print_type(s->fields.structure[j].type);
- printf(")(%s))\n", s->fields.structure[j].name);
- }
-
- printf(")\n");
- }
- }
-
- printf("(\n");
- foreach_iter(exec_list_iterator, iter, *instructions) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- ir->print();
- if (ir->ir_type != ir_type_function)
- printf("\n");
- }
- printf("\n)");
-}
-
-
-void ir_print_visitor::indent(void)
-{
- for (int i = 0; i < indentation; i++)
- printf(" ");
-}
-
-static void
-print_type(const glsl_type *t)
-{
- if (t->base_type == GLSL_TYPE_ARRAY) {
- printf("(array ");
- print_type(t->fields.array);
- printf(" %u)", t->length);
- } else if ((t->base_type == GLSL_TYPE_STRUCT)
- && (strncmp("gl_", t->name, 3) != 0)) {
- printf("%s@%p", t->name, (void *) t);
- } else {
- printf("%s", t->name);
- }
-}
-
-
-void ir_print_visitor::visit(ir_variable *ir)
-{
- printf("(declare ");
-
- const char *const cent = (ir->centroid) ? "centroid " : "";
- const char *const inv = (ir->invariant) ? "invariant " : "";
- const char *const mode[] = { "", "uniform ", "in ", "out ", "inout ",
- "temporary " };
- const char *const interp[] = { "", "flat", "noperspective" };
-
- printf("(%s%s%s%s) ",
- cent, inv, mode[ir->mode], interp[ir->interpolation]);
-
- print_type(ir->type);
- printf(" %s@%p)", ir->name, (void *) ir);
-}
-
-
-void ir_print_visitor::visit(ir_function_signature *ir)
-{
- printf("(signature ");
- indentation++;
-
- print_type(ir->return_type);
- printf("\n");
- indent();
-
- printf("(parameters\n");
- indentation++;
-
- foreach_iter(exec_list_iterator, iter, ir->parameters) {
- ir_variable *const inst = (ir_variable *) iter.get();
-
- indent();
- inst->accept(this);
- printf("\n");
- }
- indentation--;
-
- indent();
- printf(")\n");
-
- indent();
-
- printf("(\n");
- indentation++;
-
- foreach_iter(exec_list_iterator, iter, ir->body) {
- ir_instruction *const inst = (ir_instruction *) iter.get();
-
- indent();
- inst->accept(this);
- printf("\n");
- }
- indentation--;
- indent();
- printf("))\n");
- indentation--;
-}
-
-
-void ir_print_visitor::visit(ir_function *ir)
-{
- printf("(function %s\n", ir->name);
- indentation++;
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_function_signature *const sig = (ir_function_signature *) iter.get();
- indent();
- sig->accept(this);
- printf("\n");
- }
- indentation--;
- indent();
- printf(")\n\n");
-}
-
-
-void ir_print_visitor::visit(ir_expression *ir)
-{
- printf("(expression ");
-
- print_type(ir->type);
-
- printf(" %s ", ir->operator_string());
-
- for (unsigned i = 0; i < ir->get_num_operands(); i++) {
- ir->operands[i]->accept(this);
- }
-
- printf(") ");
-}
-
-
-void ir_print_visitor::visit(ir_texture *ir)
-{
- printf("(%s ", ir->opcode_string());
-
- ir->sampler->accept(this);
- printf(" ");
-
- ir->coordinate->accept(this);
-
- printf(" (%d %d %d) ", ir->offsets[0], ir->offsets[1], ir->offsets[2]);
-
- if (ir->op != ir_txf) {
- if (ir->projector)
- ir->projector->accept(this);
- else
- printf("1");
-
- if (ir->shadow_comparitor) {
- printf(" ");
- ir->shadow_comparitor->accept(this);
- } else {
- printf(" ()");
- }
- }
-
- printf(" ");
- switch (ir->op)
- {
- case ir_tex:
- break;
- case ir_txb:
- ir->lod_info.bias->accept(this);
- break;
- case ir_txl:
- case ir_txf:
- ir->lod_info.lod->accept(this);
- break;
- case ir_txd:
- printf("(");
- ir->lod_info.grad.dPdx->accept(this);
- printf(" ");
- ir->lod_info.grad.dPdy->accept(this);
- printf(")");
- break;
- };
- printf(")");
-}
-
-
-void ir_print_visitor::visit(ir_swizzle *ir)
-{
- const unsigned swiz[4] = {
- ir->mask.x,
- ir->mask.y,
- ir->mask.z,
- ir->mask.w,
- };
-
- printf("(swiz ");
- for (unsigned i = 0; i < ir->mask.num_components; i++) {
- printf("%c", "xyzw"[swiz[i]]);
- }
- printf(" ");
- ir->val->accept(this);
- printf(")");
-}
-
-
-void ir_print_visitor::visit(ir_dereference_variable *ir)
-{
- ir_variable *var = ir->variable_referenced();
- printf("(var_ref %s@%p) ", var->name, (void *) var);
-}
-
-
-void ir_print_visitor::visit(ir_dereference_array *ir)
-{
- printf("(array_ref ");
- ir->array->accept(this);
- ir->array_index->accept(this);
- printf(") ");
-}
-
-
-void ir_print_visitor::visit(ir_dereference_record *ir)
-{
- printf("(record_ref ");
- ir->record->accept(this);
- printf(" %s) ", ir->field);
-}
-
-
-void ir_print_visitor::visit(ir_assignment *ir)
-{
- printf("(assign ");
-
- if (ir->condition)
- ir->condition->accept(this);
-
- char mask[5];
- unsigned j = 0;
-
- for (unsigned i = 0; i < 4; i++) {
- if ((ir->write_mask & (1 << i)) != 0) {
- mask[j] = "xyzw"[i];
- j++;
- }
- }
- mask[j] = '\0';
-
- printf(" (%s) ", mask);
-
- ir->lhs->accept(this);
-
- printf(" ");
-
- ir->rhs->accept(this);
- printf(") ");
-}
-
-
-void ir_print_visitor::visit(ir_constant *ir)
-{
- const glsl_type *const base_type = ir->type->get_base_type();
-
- printf("(constant ");
- print_type(ir->type);
- printf(" (");
-
- if (ir->type->is_array()) {
- for (unsigned i = 0; i < ir->type->length; i++)
- ir->get_array_element(i)->accept(this);
- } else if (ir->type->is_record()) {
- ir_constant *value = (ir_constant *) ir->components.get_head();
- for (unsigned i = 0; i < ir->type->length; i++) {
- printf("(%s ", ir->type->fields.structure->name);
- value->accept(this);
- printf(")");
-
- value = (ir_constant *) value->next;
- }
- } else {
- for (unsigned i = 0; i < ir->type->components(); i++) {
- if (i != 0)
- printf(" ");
- switch (base_type->base_type) {
- case GLSL_TYPE_UINT: printf("%u", ir->value.u[i]); break;
- case GLSL_TYPE_INT: printf("%d", ir->value.i[i]); break;
- case GLSL_TYPE_FLOAT: printf("%f", ir->value.f[i]); break;
- case GLSL_TYPE_BOOL: printf("%d", ir->value.b[i]); break;
- default: assert(0);
- }
- }
- }
- printf(")) ");
-}
-
-
-void
-ir_print_visitor::visit(ir_call *ir)
-{
- printf("(call %s (", ir->callee_name());
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_instruction *const inst = (ir_instruction *) iter.get();
-
- inst->accept(this);
- }
- printf("))\n");
-}
-
-
-void
-ir_print_visitor::visit(ir_return *ir)
-{
- printf("(return");
-
- ir_rvalue *const value = ir->get_value();
- if (value) {
- printf(" ");
- value->accept(this);
- }
-
- printf(")");
-}
-
-
-void
-ir_print_visitor::visit(ir_discard *ir)
-{
- printf("(discard ");
-
- if (ir->condition != NULL) {
- printf(" ");
- ir->condition->accept(this);
- }
-
- printf(")");
-}
-
-
-void
-ir_print_visitor::visit(ir_if *ir)
-{
- printf("(if ");
- ir->condition->accept(this);
-
- printf("(\n");
- indentation++;
-
- foreach_iter(exec_list_iterator, iter, ir->then_instructions) {
- ir_instruction *const inst = (ir_instruction *) iter.get();
-
- indent();
- inst->accept(this);
- printf("\n");
- }
-
- indentation--;
- indent();
- printf(")\n");
-
- indent();
- if (!ir->else_instructions.is_empty()) {
- printf("(\n");
- indentation++;
-
- foreach_iter(exec_list_iterator, iter, ir->else_instructions) {
- ir_instruction *const inst = (ir_instruction *) iter.get();
-
- indent();
- inst->accept(this);
- printf("\n");
- }
- indentation--;
- indent();
- printf("))\n");
- } else {
- printf("())\n");
- }
-}
-
-
-void
-ir_print_visitor::visit(ir_loop *ir)
-{
- printf("(loop (");
- if (ir->counter != NULL)
- ir->counter->accept(this);
- printf(") (");
- if (ir->from != NULL)
- ir->from->accept(this);
- printf(") (");
- if (ir->to != NULL)
- ir->to->accept(this);
- printf(") (");
- if (ir->increment != NULL)
- ir->increment->accept(this);
- printf(") (\n");
- indentation++;
-
- foreach_iter(exec_list_iterator, iter, ir->body_instructions) {
- ir_instruction *const inst = (ir_instruction *) iter.get();
-
- indent();
- inst->accept(this);
- printf("\n");
- }
- indentation--;
- indent();
- printf("))\n");
-}
-
-
-void
-ir_print_visitor::visit(ir_loop_jump *ir)
-{
- printf("%s", ir->is_break() ? "break" : "continue");
-}
+/*
+ * 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 "ir_print_visitor.h"
+#include "glsl_types.h"
+#include "glsl_parser_extras.h"
+
+static void print_type(const glsl_type *t);
+
+void
+ir_instruction::print(void) const
+{
+ ir_instruction *deconsted = const_cast<ir_instruction *>(this);
+
+ ir_print_visitor v;
+ deconsted->accept(&v);
+}
+
+void
+_mesa_print_ir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ if (state) {
+ for (unsigned i = 0; i < state->num_user_structures; i++) {
+ const glsl_type *const s = state->user_structures[i];
+
+ printf("(structure (%s) (%s@%p) (%u) (\n",
+ s->name, s->name, (void *) s, s->length);
+
+ for (unsigned j = 0; j < s->length; j++) {
+ printf("\t((");
+ print_type(s->fields.structure[j].type);
+ printf(")(%s))\n", s->fields.structure[j].name);
+ }
+
+ printf(")\n");
+ }
+ }
+
+ printf("(\n");
+ foreach_iter(exec_list_iterator, iter, *instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir->print();
+ if (ir->ir_type != ir_type_function)
+ printf("\n");
+ }
+ printf("\n)");
+}
+
+
+void ir_print_visitor::indent(void)
+{
+ for (int i = 0; i < indentation; i++)
+ printf(" ");
+}
+
+static void
+print_type(const glsl_type *t)
+{
+ if (t->base_type == GLSL_TYPE_ARRAY) {
+ printf("(array ");
+ print_type(t->fields.array);
+ printf(" %u)", t->length);
+ } else if ((t->base_type == GLSL_TYPE_STRUCT)
+ && (strncmp("gl_", t->name, 3) != 0)) {
+ printf("%s@%p", t->name, (void *) t);
+ } else {
+ printf("%s", t->name);
+ }
+}
+
+
+void ir_print_visitor::visit(ir_variable *ir)
+{
+ printf("(declare ");
+
+ const char *const cent = (ir->centroid) ? "centroid " : "";
+ const char *const inv = (ir->invariant) ? "invariant " : "";
+ const char *const mode[] = { "", "uniform ", "in ", "out ", "inout ",
+ "const_in ", "sys ", "temporary " };
+ const char *const interp[] = { "", "flat", "noperspective" };
+
+ printf("(%s%s%s%s) ",
+ cent, inv, mode[ir->mode], interp[ir->interpolation]);
+
+ print_type(ir->type);
+ printf(" %s@%p)", ir->name, (void *) ir);
+}
+
+
+void ir_print_visitor::visit(ir_function_signature *ir)
+{
+ printf("(signature ");
+ indentation++;
+
+ print_type(ir->return_type);
+ printf("\n");
+ indent();
+
+ printf("(parameters\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->parameters) {
+ ir_variable *const inst = (ir_variable *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+ indentation--;
+
+ indent();
+ printf(")\n");
+
+ indent();
+
+ printf("(\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->body) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+ indentation--;
+ indent();
+ printf("))\n");
+ indentation--;
+}
+
+
+void ir_print_visitor::visit(ir_function *ir)
+{
+ printf("(function %s\n", ir->name);
+ indentation++;
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_function_signature *const sig = (ir_function_signature *) iter.get();
+ indent();
+ sig->accept(this);
+ printf("\n");
+ }
+ indentation--;
+ indent();
+ printf(")\n\n");
+}
+
+
+void ir_print_visitor::visit(ir_expression *ir)
+{
+ printf("(expression ");
+
+ print_type(ir->type);
+
+ printf(" %s ", ir->operator_string());
+
+ for (unsigned i = 0; i < ir->get_num_operands(); i++) {
+ ir->operands[i]->accept(this);
+ }
+
+ printf(") ");
+}
+
+
+void ir_print_visitor::visit(ir_texture *ir)
+{
+ printf("(%s ", ir->opcode_string());
+
+ ir->sampler->accept(this);
+ printf(" ");
+
+ ir->coordinate->accept(this);
+
+ printf(" ");
+
+ if (ir->offset != NULL) {
+ ir->offset->accept(this);
+ } else {
+ printf("0");
+ }
+
+ printf(" ");
+
+ if (ir->op != ir_txf) {
+ if (ir->projector)
+ ir->projector->accept(this);
+ else
+ printf("1");
+
+ if (ir->shadow_comparitor) {
+ printf(" ");
+ ir->shadow_comparitor->accept(this);
+ } else {
+ printf(" ()");
+ }
+ }
+
+ printf(" ");
+ switch (ir->op)
+ {
+ case ir_tex:
+ break;
+ case ir_txb:
+ ir->lod_info.bias->accept(this);
+ break;
+ case ir_txl:
+ case ir_txf:
+ ir->lod_info.lod->accept(this);
+ break;
+ case ir_txd:
+ printf("(");
+ ir->lod_info.grad.dPdx->accept(this);
+ printf(" ");
+ ir->lod_info.grad.dPdy->accept(this);
+ printf(")");
+ break;
+ };
+ printf(")");
+}
+
+
+void ir_print_visitor::visit(ir_swizzle *ir)
+{
+ const unsigned swiz[4] = {
+ ir->mask.x,
+ ir->mask.y,
+ ir->mask.z,
+ ir->mask.w,
+ };
+
+ printf("(swiz ");
+ for (unsigned i = 0; i < ir->mask.num_components; i++) {
+ printf("%c", "xyzw"[swiz[i]]);
+ }
+ printf(" ");
+ ir->val->accept(this);
+ printf(")");
+}
+
+
+void ir_print_visitor::visit(ir_dereference_variable *ir)
+{
+ ir_variable *var = ir->variable_referenced();
+ printf("(var_ref %s@%p) ", var->name, (void *) var);
+}
+
+
+void ir_print_visitor::visit(ir_dereference_array *ir)
+{
+ printf("(array_ref ");
+ ir->array->accept(this);
+ ir->array_index->accept(this);
+ printf(") ");
+}
+
+
+void ir_print_visitor::visit(ir_dereference_record *ir)
+{
+ printf("(record_ref ");
+ ir->record->accept(this);
+ printf(" %s) ", ir->field);
+}
+
+
+void ir_print_visitor::visit(ir_assignment *ir)
+{
+ printf("(assign ");
+
+ if (ir->condition)
+ ir->condition->accept(this);
+
+ char mask[5];
+ unsigned j = 0;
+
+ for (unsigned i = 0; i < 4; i++) {
+ if ((ir->write_mask & (1 << i)) != 0) {
+ mask[j] = "xyzw"[i];
+ j++;
+ }
+ }
+ mask[j] = '\0';
+
+ printf(" (%s) ", mask);
+
+ ir->lhs->accept(this);
+
+ printf(" ");
+
+ ir->rhs->accept(this);
+ printf(") ");
+}
+
+
+void ir_print_visitor::visit(ir_constant *ir)
+{
+ const glsl_type *const base_type = ir->type->get_base_type();
+
+ printf("(constant ");
+ print_type(ir->type);
+ printf(" (");
+
+ if (ir->type->is_array()) {
+ for (unsigned i = 0; i < ir->type->length; i++)
+ ir->get_array_element(i)->accept(this);
+ } else if (ir->type->is_record()) {
+ ir_constant *value = (ir_constant *) ir->components.get_head();
+ for (unsigned i = 0; i < ir->type->length; i++) {
+ printf("(%s ", ir->type->fields.structure->name);
+ value->accept(this);
+ printf(")");
+
+ value = (ir_constant *) value->next;
+ }
+ } else {
+ for (unsigned i = 0; i < ir->type->components(); i++) {
+ if (i != 0)
+ printf(" ");
+ switch (base_type->base_type) {
+ case GLSL_TYPE_UINT: printf("%u", ir->value.u[i]); break;
+ case GLSL_TYPE_INT: printf("%d", ir->value.i[i]); break;
+ case GLSL_TYPE_FLOAT: printf("%f", ir->value.f[i]); break;
+ case GLSL_TYPE_BOOL: printf("%d", ir->value.b[i]); break;
+ default: assert(0);
+ }
+ }
+ }
+ printf(")) ");
+}
+
+
+void
+ir_print_visitor::visit(ir_call *ir)
+{
+ printf("(call %s (", ir->callee_name());
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ inst->accept(this);
+ }
+ printf("))\n");
+}
+
+
+void
+ir_print_visitor::visit(ir_return *ir)
+{
+ printf("(return");
+
+ ir_rvalue *const value = ir->get_value();
+ if (value) {
+ printf(" ");
+ value->accept(this);
+ }
+
+ printf(")");
+}
+
+
+void
+ir_print_visitor::visit(ir_discard *ir)
+{
+ printf("(discard ");
+
+ if (ir->condition != NULL) {
+ printf(" ");
+ ir->condition->accept(this);
+ }
+
+ printf(")");
+}
+
+
+void
+ir_print_visitor::visit(ir_if *ir)
+{
+ printf("(if ");
+ ir->condition->accept(this);
+
+ printf("(\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->then_instructions) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+
+ indentation--;
+ indent();
+ printf(")\n");
+
+ indent();
+ if (!ir->else_instructions.is_empty()) {
+ printf("(\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->else_instructions) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+ indentation--;
+ indent();
+ printf("))\n");
+ } else {
+ printf("())\n");
+ }
+}
+
+
+void
+ir_print_visitor::visit(ir_loop *ir)
+{
+ printf("(loop (");
+ if (ir->counter != NULL)
+ ir->counter->accept(this);
+ printf(") (");
+ if (ir->from != NULL)
+ ir->from->accept(this);
+ printf(") (");
+ if (ir->to != NULL)
+ ir->to->accept(this);
+ printf(") (");
+ if (ir->increment != NULL)
+ ir->increment->accept(this);
+ printf(") (\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->body_instructions) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+ indentation--;
+ indent();
+ printf("))\n");
+}
+
+
+void
+ir_print_visitor::visit(ir_loop_jump *ir)
+{
+ printf("%s", ir->is_break() ? "break" : "continue");
+}
diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp
index b78aa051b..af85e06ae 100644
--- a/mesalib/src/glsl/ir_reader.cpp
+++ b/mesalib/src/glsl/ir_reader.cpp
@@ -92,7 +92,7 @@ ir_reader::read(exec_list *instructions, const char *src, bool scan_for_protos)
}
read_instructions(instructions, expr, NULL);
- talloc_free(expr);
+ ralloc_free(expr);
if (debug)
validate_ir_tree(instructions);
@@ -106,21 +106,19 @@ ir_reader::ir_read_error(s_expression *expr, const char *fmt, ...)
state->error = true;
if (state->current_function != NULL)
- state->info_log = talloc_asprintf_append(state->info_log,
- "In function %s:\n",
- state->current_function->function_name());
- state->info_log = talloc_strdup_append(state->info_log, "error: ");
+ ralloc_asprintf_append(&state->info_log, "In function %s:\n",
+ state->current_function->function_name());
+ ralloc_strcat(&state->info_log, "error: ");
va_start(ap, fmt);
- state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap);
+ ralloc_vasprintf_append(&state->info_log, fmt, ap);
va_end(ap);
- state->info_log = talloc_strdup_append(state->info_log, "\n");
+ ralloc_strcat(&state->info_log, "\n");
if (expr != NULL) {
- state->info_log = talloc_strdup_append(state->info_log,
- "...in this context:\n ");
+ ralloc_strcat(&state->info_log, "...in this context:\n ");
expr->print();
- state->info_log = talloc_strdup_append(state->info_log, "\n\n");
+ ralloc_strcat(&state->info_log, "\n\n");
}
}
@@ -399,6 +397,8 @@ ir_reader::read_declaration(s_expression *expr)
var->mode = ir_var_auto;
} else if (strcmp(qualifier->value(), "in") == 0) {
var->mode = ir_var_in;
+ } else if (strcmp(qualifier->value(), "const_in") == 0) {
+ var->mode = ir_var_const_in;
} else if (strcmp(qualifier->value(), "out") == 0) {
var->mode = ir_var_out;
} else if (strcmp(qualifier->value(), "inout") == 0) {
@@ -871,7 +871,7 @@ ir_reader::read_texture(s_expression *expr)
s_symbol *tag = NULL;
s_expression *s_sampler = NULL;
s_expression *s_coord = NULL;
- s_list *s_offset = NULL;
+ s_expression *s_offset = NULL;
s_expression *s_proj = NULL;
s_list *s_shadow = NULL;
s_expression *s_lod = NULL;
@@ -917,18 +917,15 @@ ir_reader::read_texture(s_expression *expr)
return NULL;
}
- // Read texel offset, i.e. (0 0 0)
- s_int *offset_x;
- s_int *offset_y;
- s_int *offset_z;
- s_pattern offset_pat[] = { offset_x, offset_y, offset_z };
- if (!MATCH(s_offset, offset_pat)) {
- ir_read_error(s_offset, "expected (<int> <int> <int>)");
- return NULL;
+ // Read texel offset - either 0 or an rvalue.
+ s_int *si_offset = SX_AS_INT(s_offset);
+ if (si_offset == NULL || si_offset->value() != 0) {
+ tex->offset = read_rvalue(s_offset);
+ if (tex->offset == NULL) {
+ ir_read_error(s_offset, "expected 0 or an expression");
+ return NULL;
+ }
}
- tex->offsets[0] = offset_x->value();
- tex->offsets[1] = offset_y->value();
- tex->offsets[2] = offset_z->value();
if (op != ir_txf) {
s_int *proj_as_int = SX_AS_INT(s_proj);
diff --git a/mesalib/src/glsl/ir_rvalue_visitor.cpp b/mesalib/src/glsl/ir_rvalue_visitor.cpp
index 773bfcfa3..ed6c7cb6a 100644
--- a/mesalib/src/glsl/ir_rvalue_visitor.cpp
+++ b/mesalib/src/glsl/ir_rvalue_visitor.cpp
@@ -53,6 +53,7 @@ ir_rvalue_visitor::visit_leave(ir_texture *ir)
handle_rvalue(&ir->coordinate);
handle_rvalue(&ir->projector);
handle_rvalue(&ir->shadow_comparitor);
+ handle_rvalue(&ir->offset);
switch (ir->op) {
case ir_tex:
diff --git a/mesalib/src/glsl/ir_validate.cpp b/mesalib/src/glsl/ir_validate.cpp
index 9e2f7751c..44d7549ea 100644
--- a/mesalib/src/glsl/ir_validate.cpp
+++ b/mesalib/src/glsl/ir_validate.cpp
@@ -1,529 +1,529 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_validate.cpp
- *
- * Attempts to verify that various invariants of the IR tree are true.
- *
- * In particular, at the moment it makes sure that no single
- * ir_instruction node except for ir_variable appears multiple times
- * in the ir tree. ir_variable does appear multiple times: Once as a
- * declaration in an exec_list, and multiple times as the endpoint of
- * a dereference chain.
- */
-
-#include <inttypes.h>
-#include "ir.h"
-#include "ir_hierarchical_visitor.h"
-#include "program/hash_table.h"
-#include "glsl_types.h"
-
-class ir_validate : public ir_hierarchical_visitor {
-public:
- ir_validate()
- {
- this->ht = hash_table_ctor(0, hash_table_pointer_hash,
- hash_table_pointer_compare);
-
- this->current_function = NULL;
-
- this->callback = ir_validate::validate_ir;
- this->data = ht;
- }
-
- ~ir_validate()
- {
- hash_table_dtor(this->ht);
- }
-
- virtual ir_visitor_status visit(ir_variable *v);
- virtual ir_visitor_status visit(ir_dereference_variable *ir);
- virtual ir_visitor_status visit(ir_if *ir);
-
- virtual ir_visitor_status visit_leave(ir_loop *ir);
- virtual ir_visitor_status visit_enter(ir_function *ir);
- virtual ir_visitor_status visit_leave(ir_function *ir);
- virtual ir_visitor_status visit_enter(ir_function_signature *ir);
-
- virtual ir_visitor_status visit_leave(ir_expression *ir);
- virtual ir_visitor_status visit_leave(ir_swizzle *ir);
-
- virtual ir_visitor_status visit_enter(ir_assignment *ir);
-
- static void validate_ir(ir_instruction *ir, void *data);
-
- ir_function *current_function;
-
- struct hash_table *ht;
-};
-
-
-ir_visitor_status
-ir_validate::visit(ir_dereference_variable *ir)
-{
- if ((ir->var == NULL) || (ir->var->as_variable() == NULL)) {
- printf("ir_dereference_variable @ %p does not specify a variable %p\n",
- (void *) ir, (void *) ir->var);
- abort();
- }
-
- if (hash_table_find(ht, ir->var) == NULL) {
- printf("ir_dereference_variable @ %p specifies undeclared variable "
- "`%s' @ %p\n",
- (void *) ir, ir->var->name, (void *) ir->var);
- abort();
- }
-
- this->validate_ir(ir, this->data);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_validate::visit(ir_if *ir)
-{
- if (ir->condition->type != glsl_type::bool_type) {
- printf("ir_if condition %s type instead of bool.\n",
- ir->condition->type->name);
- ir->print();
- printf("\n");
- abort();
- }
-
- return visit_continue;
-}
-
-
-ir_visitor_status
-ir_validate::visit_leave(ir_loop *ir)
-{
- if (ir->counter != NULL) {
- if ((ir->from == NULL) || (ir->from == NULL) || (ir->increment == NULL)) {
- printf("ir_loop has invalid loop controls:\n"
- " counter: %p\n"
- " from: %p\n"
- " to: %p\n"
- " increment: %p\n",
- (void *) ir->counter, (void *) ir->from, (void *) ir->to,
- (void *) ir->increment);
- abort();
- }
-
- if ((ir->cmp < ir_binop_less) || (ir->cmp > ir_binop_nequal)) {
- printf("ir_loop has invalid comparitor %d\n", ir->cmp);
- abort();
- }
- } else {
- if ((ir->from != NULL) || (ir->from != NULL) || (ir->increment != NULL)) {
- printf("ir_loop has invalid loop controls:\n"
- " counter: %p\n"
- " from: %p\n"
- " to: %p\n"
- " increment: %p\n",
- (void *) ir->counter, (void *) ir->from, (void *) ir->to,
- (void *) ir->increment);
- abort();
- }
- }
-
- return visit_continue;
-}
-
-
-ir_visitor_status
-ir_validate::visit_enter(ir_function *ir)
-{
- /* Function definitions cannot be nested.
- */
- if (this->current_function != NULL) {
- printf("Function definition nested inside another function "
- "definition:\n");
- printf("%s %p inside %s %p\n",
- ir->name, (void *) ir,
- this->current_function->name, (void *) this->current_function);
- abort();
- }
-
- /* Store the current function hierarchy being traversed. This is used
- * by the function signature visitor to ensure that the signatures are
- * linked with the correct functions.
- */
- this->current_function = ir;
-
- this->validate_ir(ir, this->data);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_validate::visit_leave(ir_function *ir)
-{
- assert(talloc_parent(ir->name) == ir);
-
- this->current_function = NULL;
- return visit_continue;
-}
-
-ir_visitor_status
-ir_validate::visit_enter(ir_function_signature *ir)
-{
- if (this->current_function != ir->function()) {
- printf("Function signature nested inside wrong function "
- "definition:\n");
- printf("%p inside %s %p instead of %s %p\n",
- (void *) ir,
- this->current_function->name, (void *) this->current_function,
- ir->function_name(), (void *) ir->function());
- abort();
- }
-
- this->validate_ir(ir, this->data);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_validate::visit_leave(ir_expression *ir)
-{
- switch (ir->operation) {
- case ir_unop_bit_not:
- assert(ir->operands[0]->type == ir->type);
- break;
- case ir_unop_logic_not:
- assert(ir->type->base_type == GLSL_TYPE_BOOL);
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
- break;
-
- case ir_unop_neg:
- case ir_unop_abs:
- case ir_unop_sign:
- case ir_unop_rcp:
- case ir_unop_rsq:
- case ir_unop_sqrt:
- assert(ir->type == ir->operands[0]->type);
- break;
-
- case ir_unop_exp:
- case ir_unop_log:
- case ir_unop_exp2:
- case ir_unop_log2:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
- assert(ir->type == ir->operands[0]->type);
- break;
-
- case ir_unop_f2i:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
- assert(ir->type->base_type == GLSL_TYPE_INT);
- break;
- case ir_unop_i2f:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT);
- assert(ir->type->base_type == GLSL_TYPE_FLOAT);
- break;
- case ir_unop_f2b:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
- assert(ir->type->base_type == GLSL_TYPE_BOOL);
- break;
- case ir_unop_b2f:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
- assert(ir->type->base_type == GLSL_TYPE_FLOAT);
- break;
- case ir_unop_i2b:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT);
- assert(ir->type->base_type == GLSL_TYPE_BOOL);
- break;
- case ir_unop_b2i:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
- assert(ir->type->base_type == GLSL_TYPE_INT);
- break;
- case ir_unop_u2f:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_UINT);
- assert(ir->type->base_type == GLSL_TYPE_FLOAT);
- break;
-
- case ir_unop_any:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
- assert(ir->type == glsl_type::bool_type);
- break;
-
- case ir_unop_trunc:
- case ir_unop_round_even:
- case ir_unop_ceil:
- case ir_unop_floor:
- case ir_unop_fract:
- case ir_unop_sin:
- case ir_unop_cos:
- case ir_unop_sin_reduced:
- case ir_unop_cos_reduced:
- case ir_unop_dFdx:
- case ir_unop_dFdy:
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
- assert(ir->operands[0]->type == ir->type);
- break;
-
- case ir_unop_noise:
- /* XXX what can we assert here? */
- break;
-
- case ir_binop_add:
- case ir_binop_sub:
- case ir_binop_mul:
- case ir_binop_div:
- case ir_binop_mod:
- case ir_binop_min:
- case ir_binop_max:
- case ir_binop_pow:
- if (ir->operands[0]->type->is_scalar())
- assert(ir->operands[1]->type == ir->type);
- else if (ir->operands[1]->type->is_scalar())
- assert(ir->operands[0]->type == ir->type);
- else if (ir->operands[0]->type->is_vector() &&
- ir->operands[1]->type->is_vector()) {
- assert(ir->operands[0]->type == ir->operands[1]->type);
- assert(ir->operands[0]->type == ir->type);
- }
- break;
-
- case ir_binop_less:
- case ir_binop_greater:
- case ir_binop_lequal:
- case ir_binop_gequal:
- case ir_binop_equal:
- case ir_binop_nequal:
- /* The semantics of the IR operators differ from the GLSL <, >, <=, >=,
- * ==, and != operators. The IR operators perform a component-wise
- * comparison on scalar or vector types and return a boolean scalar or
- * vector type of the same size.
- */
- assert(ir->type->base_type == GLSL_TYPE_BOOL);
- assert(ir->operands[0]->type == ir->operands[1]->type);
- assert(ir->operands[0]->type->is_vector()
- || ir->operands[0]->type->is_scalar());
- assert(ir->operands[0]->type->vector_elements
- == ir->type->vector_elements);
- break;
-
- case ir_binop_all_equal:
- case ir_binop_any_nequal:
- /* GLSL == and != operate on scalars, vectors, matrices and arrays, and
- * return a scalar boolean. The IR matches that.
- */
- assert(ir->type == glsl_type::bool_type);
- assert(ir->operands[0]->type == ir->operands[1]->type);
- break;
-
- case ir_binop_lshift:
- case ir_binop_rshift:
- assert(ir->operands[0]->type->is_integer() &&
- ir->operands[1]->type->is_integer());
- if (ir->operands[0]->type->is_scalar()) {
- assert(ir->operands[1]->type->is_scalar());
- }
- if (ir->operands[0]->type->is_vector() &&
- ir->operands[1]->type->is_vector()) {
- assert(ir->operands[0]->type->components() ==
- ir->operands[1]->type->components());
- }
- assert(ir->type == ir->operands[0]->type);
- break;
-
- case ir_binop_bit_and:
- case ir_binop_bit_xor:
- case ir_binop_bit_or:
- assert(ir->operands[0]->type->base_type ==
- ir->operands[1]->type->base_type);
- assert(ir->type->is_integer());
- if (ir->operands[0]->type->is_vector() &&
- ir->operands[1]->type->is_vector()) {
- assert(ir->operands[0]->type->vector_elements ==
- ir->operands[1]->type->vector_elements);
- }
- break;
-
- case ir_binop_logic_and:
- case ir_binop_logic_xor:
- case ir_binop_logic_or:
- assert(ir->type == glsl_type::bool_type);
- assert(ir->operands[0]->type == glsl_type::bool_type);
- assert(ir->operands[1]->type == glsl_type::bool_type);
- break;
-
- case ir_binop_dot:
- assert(ir->type == glsl_type::float_type);
- assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
- assert(ir->operands[0]->type->is_vector());
- assert(ir->operands[0]->type == ir->operands[1]->type);
- break;
-
- case ir_quadop_vector:
- /* The vector operator collects some number of scalars and generates a
- * vector from them.
- *
- * - All of the operands must be scalar.
- * - Number of operands must matche the size of the resulting vector.
- * - Base type of the operands must match the base type of the result.
- */
- assert(ir->type->is_vector());
- switch (ir->type->vector_elements) {
- case 2:
- assert(ir->operands[0]->type->is_scalar());
- assert(ir->operands[0]->type->base_type == ir->type->base_type);
- assert(ir->operands[1]->type->is_scalar());
- assert(ir->operands[1]->type->base_type == ir->type->base_type);
- assert(ir->operands[2] == NULL);
- assert(ir->operands[3] == NULL);
- break;
- case 3:
- assert(ir->operands[0]->type->is_scalar());
- assert(ir->operands[0]->type->base_type == ir->type->base_type);
- assert(ir->operands[1]->type->is_scalar());
- assert(ir->operands[1]->type->base_type == ir->type->base_type);
- assert(ir->operands[2]->type->is_scalar());
- assert(ir->operands[2]->type->base_type == ir->type->base_type);
- assert(ir->operands[3] == NULL);
- break;
- case 4:
- assert(ir->operands[0]->type->is_scalar());
- assert(ir->operands[0]->type->base_type == ir->type->base_type);
- assert(ir->operands[1]->type->is_scalar());
- assert(ir->operands[1]->type->base_type == ir->type->base_type);
- assert(ir->operands[2]->type->is_scalar());
- assert(ir->operands[2]->type->base_type == ir->type->base_type);
- assert(ir->operands[3]->type->is_scalar());
- assert(ir->operands[3]->type->base_type == ir->type->base_type);
- break;
- default:
- /* The is_vector assertion above should prevent execution from ever
- * getting here.
- */
- assert(!"Should not get here.");
- break;
- }
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_validate::visit_leave(ir_swizzle *ir)
-{
- int chans[4] = {ir->mask.x, ir->mask.y, ir->mask.z, ir->mask.w};
-
- for (unsigned int i = 0; i < ir->type->vector_elements; i++) {
- if (chans[i] >= ir->val->type->vector_elements) {
- printf("ir_swizzle @ %p specifies a channel not present "
- "in the value.\n", (void *) ir);
- ir->print();
- abort();
- }
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_validate::visit(ir_variable *ir)
-{
- /* An ir_variable is the one thing that can (and will) appear multiple times
- * in an IR tree. It is added to the hashtable so that it can be used
- * in the ir_dereference_variable handler to ensure that a variable is
- * declared before it is dereferenced.
- */
- if (ir->name)
- assert(talloc_parent(ir->name) == ir);
-
- hash_table_insert(ht, ir, ir);
- return visit_continue;
-}
-
-ir_visitor_status
-ir_validate::visit_enter(ir_assignment *ir)
-{
- const ir_dereference *const lhs = ir->lhs;
- if (lhs->type->is_scalar() || lhs->type->is_vector()) {
- if (ir->write_mask == 0) {
- printf("Assignment LHS is %s, but write mask is 0:\n",
- lhs->type->is_scalar() ? "scalar" : "vector");
- ir->print();
- abort();
- }
-
- int lhs_components = 0;
- for (int i = 0; i < 4; i++) {
- if (ir->write_mask & (1 << i))
- lhs_components++;
- }
-
- if (lhs_components != ir->rhs->type->vector_elements) {
- printf("Assignment count of LHS write mask channels enabled not\n"
- "matching RHS vector size (%d LHS, %d RHS).\n",
- lhs_components, ir->rhs->type->vector_elements);
- ir->print();
- abort();
- }
- }
-
- this->validate_ir(ir, this->data);
-
- return visit_continue;
-}
-
-void
-ir_validate::validate_ir(ir_instruction *ir, void *data)
-{
- struct hash_table *ht = (struct hash_table *) data;
-
- if (hash_table_find(ht, ir)) {
- printf("Instruction node present twice in ir tree:\n");
- ir->print();
- printf("\n");
- abort();
- }
- hash_table_insert(ht, ir, ir);
-}
-
-void
-check_node_type(ir_instruction *ir, void *data)
-{
- (void) data;
-
- if (ir->ir_type <= ir_type_unset || ir->ir_type >= ir_type_max) {
- printf("Instruction node with unset type\n");
- ir->print(); printf("\n");
- }
- assert(ir->type != glsl_type::error_type);
-}
-
-void
-validate_ir_tree(exec_list *instructions)
-{
- ir_validate v;
-
- v.run(instructions);
-
- foreach_iter(exec_list_iterator, iter, *instructions) {
- ir_instruction *ir = (ir_instruction *)iter.get();
-
- visit_tree(ir, check_node_type, NULL);
- }
-}
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_validate.cpp
+ *
+ * Attempts to verify that various invariants of the IR tree are true.
+ *
+ * In particular, at the moment it makes sure that no single
+ * ir_instruction node except for ir_variable appears multiple times
+ * in the ir tree. ir_variable does appear multiple times: Once as a
+ * declaration in an exec_list, and multiple times as the endpoint of
+ * a dereference chain.
+ */
+
+#include <inttypes.h>
+#include "ir.h"
+#include "ir_hierarchical_visitor.h"
+#include "program/hash_table.h"
+#include "glsl_types.h"
+
+class ir_validate : public ir_hierarchical_visitor {
+public:
+ ir_validate()
+ {
+ this->ht = hash_table_ctor(0, hash_table_pointer_hash,
+ hash_table_pointer_compare);
+
+ this->current_function = NULL;
+
+ this->callback = ir_validate::validate_ir;
+ this->data = ht;
+ }
+
+ ~ir_validate()
+ {
+ hash_table_dtor(this->ht);
+ }
+
+ virtual ir_visitor_status visit(ir_variable *v);
+ virtual ir_visitor_status visit(ir_dereference_variable *ir);
+ virtual ir_visitor_status visit(ir_if *ir);
+
+ virtual ir_visitor_status visit_leave(ir_loop *ir);
+ virtual ir_visitor_status visit_enter(ir_function *ir);
+ virtual ir_visitor_status visit_leave(ir_function *ir);
+ virtual ir_visitor_status visit_enter(ir_function_signature *ir);
+
+ virtual ir_visitor_status visit_leave(ir_expression *ir);
+ virtual ir_visitor_status visit_leave(ir_swizzle *ir);
+
+ virtual ir_visitor_status visit_enter(ir_assignment *ir);
+
+ static void validate_ir(ir_instruction *ir, void *data);
+
+ ir_function *current_function;
+
+ struct hash_table *ht;
+};
+
+
+ir_visitor_status
+ir_validate::visit(ir_dereference_variable *ir)
+{
+ if ((ir->var == NULL) || (ir->var->as_variable() == NULL)) {
+ printf("ir_dereference_variable @ %p does not specify a variable %p\n",
+ (void *) ir, (void *) ir->var);
+ abort();
+ }
+
+ if (hash_table_find(ht, ir->var) == NULL) {
+ printf("ir_dereference_variable @ %p specifies undeclared variable "
+ "`%s' @ %p\n",
+ (void *) ir, ir->var->name, (void *) ir->var);
+ abort();
+ }
+
+ this->validate_ir(ir, this->data);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_validate::visit(ir_if *ir)
+{
+ if (ir->condition->type != glsl_type::bool_type) {
+ printf("ir_if condition %s type instead of bool.\n",
+ ir->condition->type->name);
+ ir->print();
+ printf("\n");
+ abort();
+ }
+
+ return visit_continue;
+}
+
+
+ir_visitor_status
+ir_validate::visit_leave(ir_loop *ir)
+{
+ if (ir->counter != NULL) {
+ if ((ir->from == NULL) || (ir->from == NULL) || (ir->increment == NULL)) {
+ printf("ir_loop has invalid loop controls:\n"
+ " counter: %p\n"
+ " from: %p\n"
+ " to: %p\n"
+ " increment: %p\n",
+ (void *) ir->counter, (void *) ir->from, (void *) ir->to,
+ (void *) ir->increment);
+ abort();
+ }
+
+ if ((ir->cmp < ir_binop_less) || (ir->cmp > ir_binop_nequal)) {
+ printf("ir_loop has invalid comparitor %d\n", ir->cmp);
+ abort();
+ }
+ } else {
+ if ((ir->from != NULL) || (ir->from != NULL) || (ir->increment != NULL)) {
+ printf("ir_loop has invalid loop controls:\n"
+ " counter: %p\n"
+ " from: %p\n"
+ " to: %p\n"
+ " increment: %p\n",
+ (void *) ir->counter, (void *) ir->from, (void *) ir->to,
+ (void *) ir->increment);
+ abort();
+ }
+ }
+
+ return visit_continue;
+}
+
+
+ir_visitor_status
+ir_validate::visit_enter(ir_function *ir)
+{
+ /* Function definitions cannot be nested.
+ */
+ if (this->current_function != NULL) {
+ printf("Function definition nested inside another function "
+ "definition:\n");
+ printf("%s %p inside %s %p\n",
+ ir->name, (void *) ir,
+ this->current_function->name, (void *) this->current_function);
+ abort();
+ }
+
+ /* Store the current function hierarchy being traversed. This is used
+ * by the function signature visitor to ensure that the signatures are
+ * linked with the correct functions.
+ */
+ this->current_function = ir;
+
+ this->validate_ir(ir, this->data);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_validate::visit_leave(ir_function *ir)
+{
+ assert(ralloc_parent(ir->name) == ir);
+
+ this->current_function = NULL;
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_validate::visit_enter(ir_function_signature *ir)
+{
+ if (this->current_function != ir->function()) {
+ printf("Function signature nested inside wrong function "
+ "definition:\n");
+ printf("%p inside %s %p instead of %s %p\n",
+ (void *) ir,
+ this->current_function->name, (void *) this->current_function,
+ ir->function_name(), (void *) ir->function());
+ abort();
+ }
+
+ this->validate_ir(ir, this->data);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_validate::visit_leave(ir_expression *ir)
+{
+ switch (ir->operation) {
+ case ir_unop_bit_not:
+ assert(ir->operands[0]->type == ir->type);
+ break;
+ case ir_unop_logic_not:
+ assert(ir->type->base_type == GLSL_TYPE_BOOL);
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
+ break;
+
+ case ir_unop_neg:
+ case ir_unop_abs:
+ case ir_unop_sign:
+ case ir_unop_rcp:
+ case ir_unop_rsq:
+ case ir_unop_sqrt:
+ assert(ir->type == ir->operands[0]->type);
+ break;
+
+ case ir_unop_exp:
+ case ir_unop_log:
+ case ir_unop_exp2:
+ case ir_unop_log2:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
+ assert(ir->type == ir->operands[0]->type);
+ break;
+
+ case ir_unop_f2i:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
+ assert(ir->type->base_type == GLSL_TYPE_INT);
+ break;
+ case ir_unop_i2f:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT);
+ assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+ break;
+ case ir_unop_f2b:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
+ assert(ir->type->base_type == GLSL_TYPE_BOOL);
+ break;
+ case ir_unop_b2f:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
+ assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+ break;
+ case ir_unop_i2b:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT);
+ assert(ir->type->base_type == GLSL_TYPE_BOOL);
+ break;
+ case ir_unop_b2i:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
+ assert(ir->type->base_type == GLSL_TYPE_INT);
+ break;
+ case ir_unop_u2f:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_UINT);
+ assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+ break;
+
+ case ir_unop_any:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
+ assert(ir->type == glsl_type::bool_type);
+ break;
+
+ case ir_unop_trunc:
+ case ir_unop_round_even:
+ case ir_unop_ceil:
+ case ir_unop_floor:
+ case ir_unop_fract:
+ case ir_unop_sin:
+ case ir_unop_cos:
+ case ir_unop_sin_reduced:
+ case ir_unop_cos_reduced:
+ case ir_unop_dFdx:
+ case ir_unop_dFdy:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
+ assert(ir->operands[0]->type == ir->type);
+ break;
+
+ case ir_unop_noise:
+ /* XXX what can we assert here? */
+ break;
+
+ case ir_binop_add:
+ case ir_binop_sub:
+ case ir_binop_mul:
+ case ir_binop_div:
+ case ir_binop_mod:
+ case ir_binop_min:
+ case ir_binop_max:
+ case ir_binop_pow:
+ if (ir->operands[0]->type->is_scalar())
+ assert(ir->operands[1]->type == ir->type);
+ else if (ir->operands[1]->type->is_scalar())
+ assert(ir->operands[0]->type == ir->type);
+ else if (ir->operands[0]->type->is_vector() &&
+ ir->operands[1]->type->is_vector()) {
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ assert(ir->operands[0]->type == ir->type);
+ }
+ break;
+
+ case ir_binop_less:
+ case ir_binop_greater:
+ case ir_binop_lequal:
+ case ir_binop_gequal:
+ case ir_binop_equal:
+ case ir_binop_nequal:
+ /* The semantics of the IR operators differ from the GLSL <, >, <=, >=,
+ * ==, and != operators. The IR operators perform a component-wise
+ * comparison on scalar or vector types and return a boolean scalar or
+ * vector type of the same size.
+ */
+ assert(ir->type->base_type == GLSL_TYPE_BOOL);
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ assert(ir->operands[0]->type->is_vector()
+ || ir->operands[0]->type->is_scalar());
+ assert(ir->operands[0]->type->vector_elements
+ == ir->type->vector_elements);
+ break;
+
+ case ir_binop_all_equal:
+ case ir_binop_any_nequal:
+ /* GLSL == and != operate on scalars, vectors, matrices and arrays, and
+ * return a scalar boolean. The IR matches that.
+ */
+ assert(ir->type == glsl_type::bool_type);
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ break;
+
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ assert(ir->operands[0]->type->is_integer() &&
+ ir->operands[1]->type->is_integer());
+ if (ir->operands[0]->type->is_scalar()) {
+ assert(ir->operands[1]->type->is_scalar());
+ }
+ if (ir->operands[0]->type->is_vector() &&
+ ir->operands[1]->type->is_vector()) {
+ assert(ir->operands[0]->type->components() ==
+ ir->operands[1]->type->components());
+ }
+ assert(ir->type == ir->operands[0]->type);
+ break;
+
+ case ir_binop_bit_and:
+ case ir_binop_bit_xor:
+ case ir_binop_bit_or:
+ assert(ir->operands[0]->type->base_type ==
+ ir->operands[1]->type->base_type);
+ assert(ir->type->is_integer());
+ if (ir->operands[0]->type->is_vector() &&
+ ir->operands[1]->type->is_vector()) {
+ assert(ir->operands[0]->type->vector_elements ==
+ ir->operands[1]->type->vector_elements);
+ }
+ break;
+
+ case ir_binop_logic_and:
+ case ir_binop_logic_xor:
+ case ir_binop_logic_or:
+ assert(ir->type == glsl_type::bool_type);
+ assert(ir->operands[0]->type == glsl_type::bool_type);
+ assert(ir->operands[1]->type == glsl_type::bool_type);
+ break;
+
+ case ir_binop_dot:
+ assert(ir->type == glsl_type::float_type);
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
+ assert(ir->operands[0]->type->is_vector());
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ break;
+
+ case ir_quadop_vector:
+ /* The vector operator collects some number of scalars and generates a
+ * vector from them.
+ *
+ * - All of the operands must be scalar.
+ * - Number of operands must matche the size of the resulting vector.
+ * - Base type of the operands must match the base type of the result.
+ */
+ assert(ir->type->is_vector());
+ switch (ir->type->vector_elements) {
+ case 2:
+ assert(ir->operands[0]->type->is_scalar());
+ assert(ir->operands[0]->type->base_type == ir->type->base_type);
+ assert(ir->operands[1]->type->is_scalar());
+ assert(ir->operands[1]->type->base_type == ir->type->base_type);
+ assert(ir->operands[2] == NULL);
+ assert(ir->operands[3] == NULL);
+ break;
+ case 3:
+ assert(ir->operands[0]->type->is_scalar());
+ assert(ir->operands[0]->type->base_type == ir->type->base_type);
+ assert(ir->operands[1]->type->is_scalar());
+ assert(ir->operands[1]->type->base_type == ir->type->base_type);
+ assert(ir->operands[2]->type->is_scalar());
+ assert(ir->operands[2]->type->base_type == ir->type->base_type);
+ assert(ir->operands[3] == NULL);
+ break;
+ case 4:
+ assert(ir->operands[0]->type->is_scalar());
+ assert(ir->operands[0]->type->base_type == ir->type->base_type);
+ assert(ir->operands[1]->type->is_scalar());
+ assert(ir->operands[1]->type->base_type == ir->type->base_type);
+ assert(ir->operands[2]->type->is_scalar());
+ assert(ir->operands[2]->type->base_type == ir->type->base_type);
+ assert(ir->operands[3]->type->is_scalar());
+ assert(ir->operands[3]->type->base_type == ir->type->base_type);
+ break;
+ default:
+ /* The is_vector assertion above should prevent execution from ever
+ * getting here.
+ */
+ assert(!"Should not get here.");
+ break;
+ }
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_validate::visit_leave(ir_swizzle *ir)
+{
+ int chans[4] = {ir->mask.x, ir->mask.y, ir->mask.z, ir->mask.w};
+
+ for (unsigned int i = 0; i < ir->type->vector_elements; i++) {
+ if (chans[i] >= ir->val->type->vector_elements) {
+ printf("ir_swizzle @ %p specifies a channel not present "
+ "in the value.\n", (void *) ir);
+ ir->print();
+ abort();
+ }
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_validate::visit(ir_variable *ir)
+{
+ /* An ir_variable is the one thing that can (and will) appear multiple times
+ * in an IR tree. It is added to the hashtable so that it can be used
+ * in the ir_dereference_variable handler to ensure that a variable is
+ * declared before it is dereferenced.
+ */
+ if (ir->name)
+ assert(ralloc_parent(ir->name) == ir);
+
+ hash_table_insert(ht, ir, ir);
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_validate::visit_enter(ir_assignment *ir)
+{
+ const ir_dereference *const lhs = ir->lhs;
+ if (lhs->type->is_scalar() || lhs->type->is_vector()) {
+ if (ir->write_mask == 0) {
+ printf("Assignment LHS is %s, but write mask is 0:\n",
+ lhs->type->is_scalar() ? "scalar" : "vector");
+ ir->print();
+ abort();
+ }
+
+ int lhs_components = 0;
+ for (int i = 0; i < 4; i++) {
+ if (ir->write_mask & (1 << i))
+ lhs_components++;
+ }
+
+ if (lhs_components != ir->rhs->type->vector_elements) {
+ printf("Assignment count of LHS write mask channels enabled not\n"
+ "matching RHS vector size (%d LHS, %d RHS).\n",
+ lhs_components, ir->rhs->type->vector_elements);
+ ir->print();
+ abort();
+ }
+ }
+
+ this->validate_ir(ir, this->data);
+
+ return visit_continue;
+}
+
+void
+ir_validate::validate_ir(ir_instruction *ir, void *data)
+{
+ struct hash_table *ht = (struct hash_table *) data;
+
+ if (hash_table_find(ht, ir)) {
+ printf("Instruction node present twice in ir tree:\n");
+ ir->print();
+ printf("\n");
+ abort();
+ }
+ hash_table_insert(ht, ir, ir);
+}
+
+void
+check_node_type(ir_instruction *ir, void *data)
+{
+ (void) data;
+
+ if (ir->ir_type <= ir_type_unset || ir->ir_type >= ir_type_max) {
+ printf("Instruction node with unset type\n");
+ ir->print(); printf("\n");
+ }
+ assert(ir->type != glsl_type::error_type);
+}
+
+void
+validate_ir_tree(exec_list *instructions)
+{
+ ir_validate v;
+
+ v.run(instructions);
+
+ foreach_iter(exec_list_iterator, iter, *instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+
+ visit_tree(ir, check_node_type, NULL);
+ }
+}
diff --git a/mesalib/src/glsl/ir_variable.cpp b/mesalib/src/glsl/ir_variable.cpp
index 1cf450e20..18a3e0fb0 100644
--- a/mesalib/src/glsl/ir_variable.cpp
+++ b/mesalib/src/glsl/ir_variable.cpp
@@ -1,540 +1,541 @@
-/*
- * 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 "ir.h"
-#include "glsl_parser_extras.h"
-#include "glsl_symbol_table.h"
-#include "builtin_variables.h"
-
-static void generate_ARB_draw_buffers_variables(exec_list *,
- struct _mesa_glsl_parse_state *,
- bool, _mesa_glsl_parser_targets);
-
-static void
-generate_ARB_draw_instanced_variables(exec_list *,
- struct _mesa_glsl_parse_state *,
- bool, _mesa_glsl_parser_targets);
-
-static ir_variable *
-add_variable(const char *name, enum ir_variable_mode mode, int slot,
- const glsl_type *type, exec_list *instructions,
- glsl_symbol_table *symtab)
-{
- ir_variable *var = new(symtab) ir_variable(type, name, mode);
-
- switch (var->mode) {
- case ir_var_auto:
- case ir_var_in:
- case ir_var_uniform:
- case ir_var_system_value:
- var->read_only = true;
- break;
- case ir_var_inout:
- case ir_var_out:
- break;
- default:
- assert(0);
- break;
- }
-
- var->location = slot;
- var->explicit_location = (slot >= 0);
-
- /* Once the variable is created an initialized, add it to the symbol table
- * and add the declaration to the IR stream.
- */
- instructions->push_tail(var);
-
- symtab->add_variable(var);
- return var;
-}
-
-static ir_variable *
-add_uniform(exec_list *instructions,
- struct _mesa_glsl_parse_state *state,
- const char *name, const glsl_type *type)
-{
- return add_variable(name, ir_var_uniform, -1, type, instructions,
- state->symbols);
-}
-
-static void
-add_builtin_variable(const builtin_variable *proto, exec_list *instructions,
- glsl_symbol_table *symtab)
-{
- /* Create a new variable declaration from the description supplied by
- * the caller.
- */
- const glsl_type *const type = symtab->get_type(proto->type);
-
- assert(type != NULL);
-
- add_variable(proto->name, proto->mode, proto->slot, type, instructions,
- symtab);
-}
-
-static void
-add_builtin_constant(exec_list *instructions,
- struct _mesa_glsl_parse_state *state,
- const char *name, int value)
-{
- ir_variable *const var = add_variable(name, ir_var_auto,
- -1, glsl_type::int_type,
- instructions, state->symbols);
- var->constant_value = new(var) ir_constant(value);
-}
-
-/* Several constants in GLSL ES have different names than normal desktop GLSL.
- * Therefore, this function should only be called on the ES path.
- */
-static void
-generate_100ES_uniforms(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- add_builtin_constant(instructions, state, "gl_MaxVertexAttribs",
- state->Const.MaxVertexAttribs);
- add_builtin_constant(instructions, state, "gl_MaxVertexUniformVectors",
- state->Const.MaxVertexUniformComponents);
- add_builtin_constant(instructions, state, "gl_MaxVaryingVectors",
- state->Const.MaxVaryingFloats / 4);
- add_builtin_constant(instructions, state, "gl_MaxVertexTextureImageUnits",
- state->Const.MaxVertexTextureImageUnits);
- add_builtin_constant(instructions, state, "gl_MaxCombinedTextureImageUnits",
- state->Const.MaxCombinedTextureImageUnits);
- add_builtin_constant(instructions, state, "gl_MaxTextureImageUnits",
- state->Const.MaxTextureImageUnits);
- add_builtin_constant(instructions, state, "gl_MaxFragmentUniformVectors",
- state->Const.MaxFragmentUniformComponents);
-
- add_uniform(instructions, state, "gl_DepthRange",
- state->symbols->get_type("gl_DepthRangeParameters"));
-}
-
-static void
-generate_110_uniforms(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- for (unsigned i = 0
- ; i < Elements(builtin_110_deprecated_uniforms)
- ; i++) {
- add_builtin_variable(& builtin_110_deprecated_uniforms[i],
- instructions, state->symbols);
- }
-
- add_builtin_constant(instructions, state, "gl_MaxLights",
- state->Const.MaxLights);
- add_builtin_constant(instructions, state, "gl_MaxClipPlanes",
- state->Const.MaxClipPlanes);
- add_builtin_constant(instructions, state, "gl_MaxTextureUnits",
- state->Const.MaxTextureUnits);
- add_builtin_constant(instructions, state, "gl_MaxTextureCoords",
- state->Const.MaxTextureCoords);
- add_builtin_constant(instructions, state, "gl_MaxVertexAttribs",
- state->Const.MaxVertexAttribs);
- add_builtin_constant(instructions, state, "gl_MaxVertexUniformComponents",
- state->Const.MaxVertexUniformComponents);
- add_builtin_constant(instructions, state, "gl_MaxVaryingFloats",
- state->Const.MaxVaryingFloats);
- add_builtin_constant(instructions, state, "gl_MaxVertexTextureImageUnits",
- state->Const.MaxVertexTextureImageUnits);
- add_builtin_constant(instructions, state, "gl_MaxCombinedTextureImageUnits",
- state->Const.MaxCombinedTextureImageUnits);
- add_builtin_constant(instructions, state, "gl_MaxTextureImageUnits",
- state->Const.MaxTextureImageUnits);
- add_builtin_constant(instructions, state, "gl_MaxFragmentUniformComponents",
- state->Const.MaxFragmentUniformComponents);
-
- const glsl_type *const mat4_array_type =
- glsl_type::get_array_instance(glsl_type::mat4_type,
- state->Const.MaxTextureCoords);
-
- add_uniform(instructions, state, "gl_TextureMatrix", mat4_array_type);
- add_uniform(instructions, state, "gl_TextureMatrixInverse", mat4_array_type);
- add_uniform(instructions, state, "gl_TextureMatrixTranspose", mat4_array_type);
- add_uniform(instructions, state, "gl_TextureMatrixInverseTranspose", mat4_array_type);
-
- add_uniform(instructions, state, "gl_DepthRange",
- state->symbols->get_type("gl_DepthRangeParameters"));
-
- add_uniform(instructions, state, "gl_ClipPlane",
- glsl_type::get_array_instance(glsl_type::vec4_type,
- state->Const.MaxClipPlanes));
- add_uniform(instructions, state, "gl_Point",
- state->symbols->get_type("gl_PointParameters"));
-
- const glsl_type *const material_parameters_type =
- state->symbols->get_type("gl_MaterialParameters");
- add_uniform(instructions, state, "gl_FrontMaterial", material_parameters_type);
- add_uniform(instructions, state, "gl_BackMaterial", material_parameters_type);
-
- const glsl_type *const light_source_array_type =
- glsl_type::get_array_instance(state->symbols->get_type("gl_LightSourceParameters"), state->Const.MaxLights);
-
- add_uniform(instructions, state, "gl_LightSource", light_source_array_type);
-
- const glsl_type *const light_model_products_type =
- state->symbols->get_type("gl_LightModelProducts");
- add_uniform(instructions, state, "gl_FrontLightModelProduct",
- light_model_products_type);
- add_uniform(instructions, state, "gl_BackLightModelProduct",
- light_model_products_type);
-
- const glsl_type *const light_products_type =
- glsl_type::get_array_instance(state->symbols->get_type("gl_LightProducts"),
- state->Const.MaxLights);
- add_uniform(instructions, state, "gl_FrontLightProduct", light_products_type);
- add_uniform(instructions, state, "gl_BackLightProduct", light_products_type);
-
- add_uniform(instructions, state, "gl_TextureEnvColor",
- glsl_type::get_array_instance(glsl_type::vec4_type,
- state->Const.MaxTextureUnits));
-
- const glsl_type *const texcoords_vec4 =
- glsl_type::get_array_instance(glsl_type::vec4_type,
- state->Const.MaxTextureCoords);
- add_uniform(instructions, state, "gl_EyePlaneS", texcoords_vec4);
- add_uniform(instructions, state, "gl_EyePlaneT", texcoords_vec4);
- add_uniform(instructions, state, "gl_EyePlaneR", texcoords_vec4);
- add_uniform(instructions, state, "gl_EyePlaneQ", texcoords_vec4);
- add_uniform(instructions, state, "gl_ObjectPlaneS", texcoords_vec4);
- add_uniform(instructions, state, "gl_ObjectPlaneT", texcoords_vec4);
- add_uniform(instructions, state, "gl_ObjectPlaneR", texcoords_vec4);
- add_uniform(instructions, state, "gl_ObjectPlaneQ", texcoords_vec4);
-
- add_uniform(instructions, state, "gl_Fog",
- state->symbols->get_type("gl_FogParameters"));
-}
-
-/* This function should only be called for ES, not desktop GL. */
-static void
-generate_100ES_vs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- for (unsigned i = 0; i < Elements(builtin_core_vs_variables); i++) {
- add_builtin_variable(& builtin_core_vs_variables[i],
- instructions, state->symbols);
- }
-
- generate_100ES_uniforms(instructions, state);
-
- generate_ARB_draw_buffers_variables(instructions, state, false,
- vertex_shader);
-}
-
-
-static void
-generate_110_vs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- for (unsigned i = 0; i < Elements(builtin_core_vs_variables); i++) {
- add_builtin_variable(& builtin_core_vs_variables[i],
- instructions, state->symbols);
- }
-
- for (unsigned i = 0
- ; i < Elements(builtin_110_deprecated_vs_variables)
- ; i++) {
- add_builtin_variable(& builtin_110_deprecated_vs_variables[i],
- instructions, state->symbols);
- }
- generate_110_uniforms(instructions, state);
-
- /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
- *
- * "As with all arrays, indices used to subscript gl_TexCoord must
- * either be an integral constant expressions, or this array must be
- * re-declared by the shader with a size. The size can be at most
- * gl_MaxTextureCoords. Using indexes close to 0 may aid the
- * implementation in preserving varying resources."
- */
- const glsl_type *const vec4_array_type =
- glsl_type::get_array_instance(glsl_type::vec4_type, 0);
-
- add_variable("gl_TexCoord", ir_var_out, VERT_RESULT_TEX0, vec4_array_type,
- instructions, state->symbols);
-
- generate_ARB_draw_buffers_variables(instructions, state, false,
- vertex_shader);
-}
-
-
-static void
-generate_120_vs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- /* GLSL version 1.20 did not add any built-in variables in the vertex
- * shader.
- */
- generate_110_vs_variables(instructions, state);
-}
-
-
-static void
-generate_130_vs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- generate_120_vs_variables(instructions, state);
-
- for (unsigned i = 0; i < Elements(builtin_130_vs_variables); i++) {
- add_builtin_variable(& builtin_130_vs_variables[i],
- instructions, state->symbols);
- }
-
- const glsl_type *const clip_distance_array_type =
- glsl_type::get_array_instance(glsl_type::float_type,
- state->Const.MaxClipPlanes);
-
- /* FINISHME: gl_ClipDistance needs a real location assigned. */
- add_variable("gl_ClipDistance", ir_var_out, -1, clip_distance_array_type,
- instructions, state->symbols);
-
-}
-
-
-static void
-initialize_vs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
-
- switch (state->language_version) {
- case 100:
- generate_100ES_vs_variables(instructions, state);
- break;
- case 110:
- generate_110_vs_variables(instructions, state);
- break;
- case 120:
- generate_120_vs_variables(instructions, state);
- break;
- case 130:
- generate_130_vs_variables(instructions, state);
- break;
- }
-
- if (state->ARB_draw_instanced_enable)
- generate_ARB_draw_instanced_variables(instructions, state, false,
- vertex_shader);
-}
-
-
-/* This function should only be called for ES, not desktop GL. */
-static void
-generate_100ES_fs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- for (unsigned i = 0; i < Elements(builtin_core_fs_variables); i++) {
- add_builtin_variable(& builtin_core_fs_variables[i],
- instructions, state->symbols);
- }
-
- for (unsigned i = 0; i < Elements(builtin_100ES_fs_variables); i++) {
- add_builtin_variable(& builtin_100ES_fs_variables[i],
- instructions, state->symbols);
- }
-
- generate_100ES_uniforms(instructions, state);
-
- generate_ARB_draw_buffers_variables(instructions, state, false,
- fragment_shader);
-}
-
-static void
-generate_110_fs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- for (unsigned i = 0; i < Elements(builtin_core_fs_variables); i++) {
- add_builtin_variable(& builtin_core_fs_variables[i],
- instructions, state->symbols);
- }
-
- for (unsigned i = 0; i < Elements(builtin_110_fs_variables); i++) {
- add_builtin_variable(& builtin_110_fs_variables[i],
- instructions, state->symbols);
- }
-
- for (unsigned i = 0
- ; i < Elements(builtin_110_deprecated_fs_variables)
- ; i++) {
- add_builtin_variable(& builtin_110_deprecated_fs_variables[i],
- instructions, state->symbols);
- }
- generate_110_uniforms(instructions, state);
-
- /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
- *
- * "As with all arrays, indices used to subscript gl_TexCoord must
- * either be an integral constant expressions, or this array must be
- * re-declared by the shader with a size. The size can be at most
- * gl_MaxTextureCoords. Using indexes close to 0 may aid the
- * implementation in preserving varying resources."
- */
- const glsl_type *const vec4_array_type =
- glsl_type::get_array_instance(glsl_type::vec4_type, 0);
-
- add_variable("gl_TexCoord", ir_var_in, FRAG_ATTRIB_TEX0, vec4_array_type,
- instructions, state->symbols);
-
- generate_ARB_draw_buffers_variables(instructions, state, false,
- fragment_shader);
-}
-
-
-static void
-generate_ARB_draw_buffers_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state,
- bool warn, _mesa_glsl_parser_targets target)
-{
- /* gl_MaxDrawBuffers is available in all shader stages.
- */
- ir_variable *const mdb =
- add_variable("gl_MaxDrawBuffers", ir_var_auto, -1,
- glsl_type::int_type, instructions, state->symbols);
-
- if (warn)
- mdb->warn_extension = "GL_ARB_draw_buffers";
-
- mdb->constant_value = new(mdb)
- ir_constant(int(state->Const.MaxDrawBuffers));
-
-
- /* gl_FragData is only available in the fragment shader.
- */
- if (target == fragment_shader) {
- const glsl_type *const vec4_array_type =
- glsl_type::get_array_instance(glsl_type::vec4_type,
- state->Const.MaxDrawBuffers);
-
- ir_variable *const fd =
- add_variable("gl_FragData", ir_var_out, FRAG_RESULT_DATA0,
- vec4_array_type, instructions, state->symbols);
-
- if (warn)
- fd->warn_extension = "GL_ARB_draw_buffers";
- }
-}
-
-
-static void
-generate_ARB_draw_instanced_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state,
- bool warn,
- _mesa_glsl_parser_targets target)
-{
- /* gl_InstanceIDARB is only available in the vertex shader.
- */
- if (target == vertex_shader) {
- ir_variable *const inst =
- add_variable("gl_InstanceIDARB", ir_var_system_value,
- SYSTEM_VALUE_INSTANCE_ID,
- glsl_type::int_type, instructions, state->symbols);
-
- if (warn)
- inst->warn_extension = "GL_ARB_draw_instanced";
- }
-}
-
-
-static void
-generate_ARB_shader_stencil_export_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state,
- bool warn)
-{
- /* gl_FragStencilRefARB is only available in the fragment shader.
- */
- ir_variable *const fd =
- add_variable("gl_FragStencilRefARB", ir_var_out, FRAG_RESULT_STENCIL,
- glsl_type::int_type, instructions, state->symbols);
-
- if (warn)
- fd->warn_extension = "GL_ARB_shader_stencil_export";
-}
-
-static void
-generate_120_fs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- generate_110_fs_variables(instructions, state);
-
- for (unsigned i = 0
- ; i < Elements(builtin_120_fs_variables)
- ; i++) {
- add_builtin_variable(& builtin_120_fs_variables[i],
- instructions, state->symbols);
- }
-}
-
-static void
-generate_130_fs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- generate_120_fs_variables(instructions, state);
-
- const glsl_type *const clip_distance_array_type =
- glsl_type::get_array_instance(glsl_type::float_type,
- state->Const.MaxClipPlanes);
-
- /* FINISHME: gl_ClipDistance needs a real location assigned. */
- add_variable("gl_ClipDistance", ir_var_in, -1, clip_distance_array_type,
- instructions, state->symbols);
-}
-
-static void
-initialize_fs_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
-
- switch (state->language_version) {
- case 100:
- generate_100ES_fs_variables(instructions, state);
- break;
- case 110:
- generate_110_fs_variables(instructions, state);
- break;
- case 120:
- generate_120_fs_variables(instructions, state);
- break;
- case 130:
- generate_130_fs_variables(instructions, state);
- break;
- }
-
- if (state->ARB_shader_stencil_export_enable)
- generate_ARB_shader_stencil_export_variables(instructions, state,
- state->ARB_shader_stencil_export_warn);
-}
-
-void
-_mesa_glsl_initialize_variables(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- switch (state->target) {
- case vertex_shader:
- initialize_vs_variables(instructions, state);
- break;
- case geometry_shader:
- break;
- case fragment_shader:
- initialize_fs_variables(instructions, state);
- break;
- }
-}
+/*
+ * 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 "ir.h"
+#include "glsl_parser_extras.h"
+#include "glsl_symbol_table.h"
+#include "builtin_variables.h"
+
+static void generate_ARB_draw_buffers_variables(exec_list *,
+ struct _mesa_glsl_parse_state *,
+ bool, _mesa_glsl_parser_targets);
+
+static void
+generate_ARB_draw_instanced_variables(exec_list *,
+ struct _mesa_glsl_parse_state *,
+ bool, _mesa_glsl_parser_targets);
+
+static ir_variable *
+add_variable(const char *name, enum ir_variable_mode mode, int slot,
+ const glsl_type *type, exec_list *instructions,
+ glsl_symbol_table *symtab)
+{
+ ir_variable *var = new(symtab) ir_variable(type, name, mode);
+
+ switch (var->mode) {
+ case ir_var_auto:
+ case ir_var_in:
+ case ir_var_const_in:
+ case ir_var_uniform:
+ case ir_var_system_value:
+ var->read_only = true;
+ break;
+ case ir_var_inout:
+ case ir_var_out:
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ var->location = slot;
+ var->explicit_location = (slot >= 0);
+
+ /* Once the variable is created an initialized, add it to the symbol table
+ * and add the declaration to the IR stream.
+ */
+ instructions->push_tail(var);
+
+ symtab->add_variable(var);
+ return var;
+}
+
+static ir_variable *
+add_uniform(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ const char *name, const glsl_type *type)
+{
+ return add_variable(name, ir_var_uniform, -1, type, instructions,
+ state->symbols);
+}
+
+static void
+add_builtin_variable(const builtin_variable *proto, exec_list *instructions,
+ glsl_symbol_table *symtab)
+{
+ /* Create a new variable declaration from the description supplied by
+ * the caller.
+ */
+ const glsl_type *const type = symtab->get_type(proto->type);
+
+ assert(type != NULL);
+
+ add_variable(proto->name, proto->mode, proto->slot, type, instructions,
+ symtab);
+}
+
+static void
+add_builtin_constant(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ const char *name, int value)
+{
+ ir_variable *const var = add_variable(name, ir_var_auto,
+ -1, glsl_type::int_type,
+ instructions, state->symbols);
+ var->constant_value = new(var) ir_constant(value);
+}
+
+/* Several constants in GLSL ES have different names than normal desktop GLSL.
+ * Therefore, this function should only be called on the ES path.
+ */
+static void
+generate_100ES_uniforms(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ add_builtin_constant(instructions, state, "gl_MaxVertexAttribs",
+ state->Const.MaxVertexAttribs);
+ add_builtin_constant(instructions, state, "gl_MaxVertexUniformVectors",
+ state->Const.MaxVertexUniformComponents);
+ add_builtin_constant(instructions, state, "gl_MaxVaryingVectors",
+ state->Const.MaxVaryingFloats / 4);
+ add_builtin_constant(instructions, state, "gl_MaxVertexTextureImageUnits",
+ state->Const.MaxVertexTextureImageUnits);
+ add_builtin_constant(instructions, state, "gl_MaxCombinedTextureImageUnits",
+ state->Const.MaxCombinedTextureImageUnits);
+ add_builtin_constant(instructions, state, "gl_MaxTextureImageUnits",
+ state->Const.MaxTextureImageUnits);
+ add_builtin_constant(instructions, state, "gl_MaxFragmentUniformVectors",
+ state->Const.MaxFragmentUniformComponents);
+
+ add_uniform(instructions, state, "gl_DepthRange",
+ state->symbols->get_type("gl_DepthRangeParameters"));
+}
+
+static void
+generate_110_uniforms(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ for (unsigned i = 0
+ ; i < Elements(builtin_110_deprecated_uniforms)
+ ; i++) {
+ add_builtin_variable(& builtin_110_deprecated_uniforms[i],
+ instructions, state->symbols);
+ }
+
+ add_builtin_constant(instructions, state, "gl_MaxLights",
+ state->Const.MaxLights);
+ add_builtin_constant(instructions, state, "gl_MaxClipPlanes",
+ state->Const.MaxClipPlanes);
+ add_builtin_constant(instructions, state, "gl_MaxTextureUnits",
+ state->Const.MaxTextureUnits);
+ add_builtin_constant(instructions, state, "gl_MaxTextureCoords",
+ state->Const.MaxTextureCoords);
+ add_builtin_constant(instructions, state, "gl_MaxVertexAttribs",
+ state->Const.MaxVertexAttribs);
+ add_builtin_constant(instructions, state, "gl_MaxVertexUniformComponents",
+ state->Const.MaxVertexUniformComponents);
+ add_builtin_constant(instructions, state, "gl_MaxVaryingFloats",
+ state->Const.MaxVaryingFloats);
+ add_builtin_constant(instructions, state, "gl_MaxVertexTextureImageUnits",
+ state->Const.MaxVertexTextureImageUnits);
+ add_builtin_constant(instructions, state, "gl_MaxCombinedTextureImageUnits",
+ state->Const.MaxCombinedTextureImageUnits);
+ add_builtin_constant(instructions, state, "gl_MaxTextureImageUnits",
+ state->Const.MaxTextureImageUnits);
+ add_builtin_constant(instructions, state, "gl_MaxFragmentUniformComponents",
+ state->Const.MaxFragmentUniformComponents);
+
+ const glsl_type *const mat4_array_type =
+ glsl_type::get_array_instance(glsl_type::mat4_type,
+ state->Const.MaxTextureCoords);
+
+ add_uniform(instructions, state, "gl_TextureMatrix", mat4_array_type);
+ add_uniform(instructions, state, "gl_TextureMatrixInverse", mat4_array_type);
+ add_uniform(instructions, state, "gl_TextureMatrixTranspose", mat4_array_type);
+ add_uniform(instructions, state, "gl_TextureMatrixInverseTranspose", mat4_array_type);
+
+ add_uniform(instructions, state, "gl_DepthRange",
+ state->symbols->get_type("gl_DepthRangeParameters"));
+
+ add_uniform(instructions, state, "gl_ClipPlane",
+ glsl_type::get_array_instance(glsl_type::vec4_type,
+ state->Const.MaxClipPlanes));
+ add_uniform(instructions, state, "gl_Point",
+ state->symbols->get_type("gl_PointParameters"));
+
+ const glsl_type *const material_parameters_type =
+ state->symbols->get_type("gl_MaterialParameters");
+ add_uniform(instructions, state, "gl_FrontMaterial", material_parameters_type);
+ add_uniform(instructions, state, "gl_BackMaterial", material_parameters_type);
+
+ const glsl_type *const light_source_array_type =
+ glsl_type::get_array_instance(state->symbols->get_type("gl_LightSourceParameters"), state->Const.MaxLights);
+
+ add_uniform(instructions, state, "gl_LightSource", light_source_array_type);
+
+ const glsl_type *const light_model_products_type =
+ state->symbols->get_type("gl_LightModelProducts");
+ add_uniform(instructions, state, "gl_FrontLightModelProduct",
+ light_model_products_type);
+ add_uniform(instructions, state, "gl_BackLightModelProduct",
+ light_model_products_type);
+
+ const glsl_type *const light_products_type =
+ glsl_type::get_array_instance(state->symbols->get_type("gl_LightProducts"),
+ state->Const.MaxLights);
+ add_uniform(instructions, state, "gl_FrontLightProduct", light_products_type);
+ add_uniform(instructions, state, "gl_BackLightProduct", light_products_type);
+
+ add_uniform(instructions, state, "gl_TextureEnvColor",
+ glsl_type::get_array_instance(glsl_type::vec4_type,
+ state->Const.MaxTextureUnits));
+
+ const glsl_type *const texcoords_vec4 =
+ glsl_type::get_array_instance(glsl_type::vec4_type,
+ state->Const.MaxTextureCoords);
+ add_uniform(instructions, state, "gl_EyePlaneS", texcoords_vec4);
+ add_uniform(instructions, state, "gl_EyePlaneT", texcoords_vec4);
+ add_uniform(instructions, state, "gl_EyePlaneR", texcoords_vec4);
+ add_uniform(instructions, state, "gl_EyePlaneQ", texcoords_vec4);
+ add_uniform(instructions, state, "gl_ObjectPlaneS", texcoords_vec4);
+ add_uniform(instructions, state, "gl_ObjectPlaneT", texcoords_vec4);
+ add_uniform(instructions, state, "gl_ObjectPlaneR", texcoords_vec4);
+ add_uniform(instructions, state, "gl_ObjectPlaneQ", texcoords_vec4);
+
+ add_uniform(instructions, state, "gl_Fog",
+ state->symbols->get_type("gl_FogParameters"));
+}
+
+/* This function should only be called for ES, not desktop GL. */
+static void
+generate_100ES_vs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ for (unsigned i = 0; i < Elements(builtin_core_vs_variables); i++) {
+ add_builtin_variable(& builtin_core_vs_variables[i],
+ instructions, state->symbols);
+ }
+
+ generate_100ES_uniforms(instructions, state);
+
+ generate_ARB_draw_buffers_variables(instructions, state, false,
+ vertex_shader);
+}
+
+
+static void
+generate_110_vs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ for (unsigned i = 0; i < Elements(builtin_core_vs_variables); i++) {
+ add_builtin_variable(& builtin_core_vs_variables[i],
+ instructions, state->symbols);
+ }
+
+ for (unsigned i = 0
+ ; i < Elements(builtin_110_deprecated_vs_variables)
+ ; i++) {
+ add_builtin_variable(& builtin_110_deprecated_vs_variables[i],
+ instructions, state->symbols);
+ }
+ generate_110_uniforms(instructions, state);
+
+ /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "As with all arrays, indices used to subscript gl_TexCoord must
+ * either be an integral constant expressions, or this array must be
+ * re-declared by the shader with a size. The size can be at most
+ * gl_MaxTextureCoords. Using indexes close to 0 may aid the
+ * implementation in preserving varying resources."
+ */
+ const glsl_type *const vec4_array_type =
+ glsl_type::get_array_instance(glsl_type::vec4_type, 0);
+
+ add_variable("gl_TexCoord", ir_var_out, VERT_RESULT_TEX0, vec4_array_type,
+ instructions, state->symbols);
+
+ generate_ARB_draw_buffers_variables(instructions, state, false,
+ vertex_shader);
+}
+
+
+static void
+generate_120_vs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ /* GLSL version 1.20 did not add any built-in variables in the vertex
+ * shader.
+ */
+ generate_110_vs_variables(instructions, state);
+}
+
+
+static void
+generate_130_vs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ generate_120_vs_variables(instructions, state);
+
+ for (unsigned i = 0; i < Elements(builtin_130_vs_variables); i++) {
+ add_builtin_variable(& builtin_130_vs_variables[i],
+ instructions, state->symbols);
+ }
+
+ const glsl_type *const clip_distance_array_type =
+ glsl_type::get_array_instance(glsl_type::float_type,
+ state->Const.MaxClipPlanes);
+
+ /* FINISHME: gl_ClipDistance needs a real location assigned. */
+ add_variable("gl_ClipDistance", ir_var_out, -1, clip_distance_array_type,
+ instructions, state->symbols);
+
+}
+
+
+static void
+initialize_vs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+
+ switch (state->language_version) {
+ case 100:
+ generate_100ES_vs_variables(instructions, state);
+ break;
+ case 110:
+ generate_110_vs_variables(instructions, state);
+ break;
+ case 120:
+ generate_120_vs_variables(instructions, state);
+ break;
+ case 130:
+ generate_130_vs_variables(instructions, state);
+ break;
+ }
+
+ if (state->ARB_draw_instanced_enable)
+ generate_ARB_draw_instanced_variables(instructions, state, false,
+ vertex_shader);
+}
+
+
+/* This function should only be called for ES, not desktop GL. */
+static void
+generate_100ES_fs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ for (unsigned i = 0; i < Elements(builtin_core_fs_variables); i++) {
+ add_builtin_variable(& builtin_core_fs_variables[i],
+ instructions, state->symbols);
+ }
+
+ for (unsigned i = 0; i < Elements(builtin_100ES_fs_variables); i++) {
+ add_builtin_variable(& builtin_100ES_fs_variables[i],
+ instructions, state->symbols);
+ }
+
+ generate_100ES_uniforms(instructions, state);
+
+ generate_ARB_draw_buffers_variables(instructions, state, false,
+ fragment_shader);
+}
+
+static void
+generate_110_fs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ for (unsigned i = 0; i < Elements(builtin_core_fs_variables); i++) {
+ add_builtin_variable(& builtin_core_fs_variables[i],
+ instructions, state->symbols);
+ }
+
+ for (unsigned i = 0; i < Elements(builtin_110_fs_variables); i++) {
+ add_builtin_variable(& builtin_110_fs_variables[i],
+ instructions, state->symbols);
+ }
+
+ for (unsigned i = 0
+ ; i < Elements(builtin_110_deprecated_fs_variables)
+ ; i++) {
+ add_builtin_variable(& builtin_110_deprecated_fs_variables[i],
+ instructions, state->symbols);
+ }
+ generate_110_uniforms(instructions, state);
+
+ /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "As with all arrays, indices used to subscript gl_TexCoord must
+ * either be an integral constant expressions, or this array must be
+ * re-declared by the shader with a size. The size can be at most
+ * gl_MaxTextureCoords. Using indexes close to 0 may aid the
+ * implementation in preserving varying resources."
+ */
+ const glsl_type *const vec4_array_type =
+ glsl_type::get_array_instance(glsl_type::vec4_type, 0);
+
+ add_variable("gl_TexCoord", ir_var_in, FRAG_ATTRIB_TEX0, vec4_array_type,
+ instructions, state->symbols);
+
+ generate_ARB_draw_buffers_variables(instructions, state, false,
+ fragment_shader);
+}
+
+
+static void
+generate_ARB_draw_buffers_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ bool warn, _mesa_glsl_parser_targets target)
+{
+ /* gl_MaxDrawBuffers is available in all shader stages.
+ */
+ ir_variable *const mdb =
+ add_variable("gl_MaxDrawBuffers", ir_var_auto, -1,
+ glsl_type::int_type, instructions, state->symbols);
+
+ if (warn)
+ mdb->warn_extension = "GL_ARB_draw_buffers";
+
+ mdb->constant_value = new(mdb)
+ ir_constant(int(state->Const.MaxDrawBuffers));
+
+
+ /* gl_FragData is only available in the fragment shader.
+ */
+ if (target == fragment_shader) {
+ const glsl_type *const vec4_array_type =
+ glsl_type::get_array_instance(glsl_type::vec4_type,
+ state->Const.MaxDrawBuffers);
+
+ ir_variable *const fd =
+ add_variable("gl_FragData", ir_var_out, FRAG_RESULT_DATA0,
+ vec4_array_type, instructions, state->symbols);
+
+ if (warn)
+ fd->warn_extension = "GL_ARB_draw_buffers";
+ }
+}
+
+
+static void
+generate_ARB_draw_instanced_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ bool warn,
+ _mesa_glsl_parser_targets target)
+{
+ /* gl_InstanceIDARB is only available in the vertex shader.
+ */
+ if (target == vertex_shader) {
+ ir_variable *const inst =
+ add_variable("gl_InstanceIDARB", ir_var_system_value,
+ SYSTEM_VALUE_INSTANCE_ID,
+ glsl_type::int_type, instructions, state->symbols);
+
+ if (warn)
+ inst->warn_extension = "GL_ARB_draw_instanced";
+ }
+}
+
+
+static void
+generate_ARB_shader_stencil_export_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ bool warn)
+{
+ /* gl_FragStencilRefARB is only available in the fragment shader.
+ */
+ ir_variable *const fd =
+ add_variable("gl_FragStencilRefARB", ir_var_out, FRAG_RESULT_STENCIL,
+ glsl_type::int_type, instructions, state->symbols);
+
+ if (warn)
+ fd->warn_extension = "GL_ARB_shader_stencil_export";
+}
+
+static void
+generate_120_fs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ generate_110_fs_variables(instructions, state);
+
+ for (unsigned i = 0
+ ; i < Elements(builtin_120_fs_variables)
+ ; i++) {
+ add_builtin_variable(& builtin_120_fs_variables[i],
+ instructions, state->symbols);
+ }
+}
+
+static void
+generate_130_fs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ generate_120_fs_variables(instructions, state);
+
+ const glsl_type *const clip_distance_array_type =
+ glsl_type::get_array_instance(glsl_type::float_type,
+ state->Const.MaxClipPlanes);
+
+ /* FINISHME: gl_ClipDistance needs a real location assigned. */
+ add_variable("gl_ClipDistance", ir_var_in, -1, clip_distance_array_type,
+ instructions, state->symbols);
+}
+
+static void
+initialize_fs_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+
+ switch (state->language_version) {
+ case 100:
+ generate_100ES_fs_variables(instructions, state);
+ break;
+ case 110:
+ generate_110_fs_variables(instructions, state);
+ break;
+ case 120:
+ generate_120_fs_variables(instructions, state);
+ break;
+ case 130:
+ generate_130_fs_variables(instructions, state);
+ break;
+ }
+
+ if (state->ARB_shader_stencil_export_enable)
+ generate_ARB_shader_stencil_export_variables(instructions, state,
+ state->ARB_shader_stencil_export_warn);
+}
+
+void
+_mesa_glsl_initialize_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ switch (state->target) {
+ case vertex_shader:
+ initialize_vs_variables(instructions, state);
+ break;
+ case geometry_shader:
+ break;
+ case fragment_shader:
+ initialize_fs_variables(instructions, state);
+ break;
+ }
+}
diff --git a/mesalib/src/glsl/ir_variable_refcount.h b/mesalib/src/glsl/ir_variable_refcount.h
index 8b43bad71..906135a9e 100644
--- a/mesalib/src/glsl/ir_variable_refcount.h
+++ b/mesalib/src/glsl/ir_variable_refcount.h
@@ -54,13 +54,13 @@ class ir_variable_refcount_visitor : public ir_hierarchical_visitor {
public:
ir_variable_refcount_visitor(void)
{
- this->mem_ctx = talloc_new(NULL);
+ this->mem_ctx = ralloc_context(NULL);
this->variable_list.make_empty();
}
~ir_variable_refcount_visitor(void)
{
- talloc_free(this->mem_ctx);
+ ralloc_free(this->mem_ctx);
}
virtual ir_visitor_status visit(ir_variable *);
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 4332338df..c7fb62437 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -172,9 +172,9 @@ linker_error_printf(gl_shader_program *prog, const char *fmt, ...)
{
va_list ap;
- prog->InfoLog = talloc_strdup_append(prog->InfoLog, "error: ");
+ ralloc_strcat(&prog->InfoLog, "error: ");
va_start(ap, fmt);
- prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, ap);
+ ralloc_vasprintf_append(&prog->InfoLog, fmt, ap);
va_end(ap);
}
@@ -299,6 +299,7 @@ mode_string(const ir_variable *var)
case ir_var_out: return "shader output";
case ir_var_inout: return "shader inout";
+ case ir_var_const_in:
case ir_var_temporary:
default:
assert(!"Should not get here.");
@@ -432,7 +433,7 @@ cross_validate_globals(struct gl_shader_program *prog,
* FINISHME: will fail.
*/
existing->constant_value =
- var->constant_value->clone(talloc_parent(existing), NULL);
+ var->constant_value->clone(ralloc_parent(existing), NULL);
}
if (existing->invariant != var->invariant) {
@@ -1015,7 +1016,7 @@ add_uniform(void *mem_ctx, exec_list *uniforms, struct hash_table *ht,
if (type->is_record()) {
for (unsigned int i = 0; i < type->length; i++) {
const glsl_type *field_type = type->fields.structure[i].type;
- char *field_name = talloc_asprintf(mem_ctx, "%s.%s", name,
+ char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name,
type->fields.structure[i].name);
add_uniform(mem_ctx, uniforms, ht, field_name, field_type,
@@ -1031,7 +1032,7 @@ add_uniform(void *mem_ctx, exec_list *uniforms, struct hash_table *ht,
/* Array of structures. */
if (array_elem_type->is_record()) {
for (unsigned int i = 0; i < type->length; i++) {
- char *elem_name = talloc_asprintf(mem_ctx, "%s[%d]", name, i);
+ char *elem_name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i);
add_uniform(mem_ctx, uniforms, ht, elem_name, array_elem_type,
shader_type, next_shader_pos, total_uniforms);
}
@@ -1093,7 +1094,7 @@ assign_uniform_locations(struct gl_shader_program *prog)
unsigned total_uniforms = 0;
hash_table *ht = hash_table_ctor(32, hash_table_string_hash,
hash_table_string_compare);
- void *mem_ctx = talloc_new(NULL);
+ void *mem_ctx = ralloc_context(NULL);
for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] == NULL)
@@ -1122,7 +1123,7 @@ assign_uniform_locations(struct gl_shader_program *prog)
}
}
- talloc_free(mem_ctx);
+ ralloc_free(mem_ctx);
gl_uniform_list *ul = (gl_uniform_list *)
calloc(1, sizeof(gl_uniform_list));
@@ -1490,16 +1491,16 @@ assign_varying_locations(struct gl_shader_program *prog,
void
link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
{
- void *mem_ctx = talloc_init("temporary linker context");
+ void *mem_ctx = ralloc_context(NULL); // temporary linker context
prog->LinkStatus = false;
prog->Validated = false;
prog->_Used = false;
if (prog->InfoLog != NULL)
- talloc_free(prog->InfoLog);
+ ralloc_free(prog->InfoLog);
- prog->InfoLog = talloc_strdup(NULL, "");
+ prog->InfoLog = ralloc_strdup(NULL, "");
/* Separate the shaders into groups based on their type.
*/
@@ -1694,5 +1695,5 @@ done:
reparent_ir(prog->_LinkedShaders[i]->ir, prog->_LinkedShaders[i]->ir);
}
- talloc_free(mem_ctx);
+ ralloc_free(mem_ctx);
}
diff --git a/mesalib/src/glsl/list.h b/mesalib/src/glsl/list.h
index 9c39855ad..fb6f0fbba 100644
--- a/mesalib/src/glsl/list.h
+++ b/mesalib/src/glsl/list.h
@@ -66,41 +66,37 @@
#ifndef __cplusplus
#include <stddef.h>
-#include <talloc.h>
-#else
-extern "C" {
-#include <talloc.h>
-}
#endif
-
#include <assert.h>
+#include "ralloc.h"
+
struct exec_node {
struct exec_node *next;
struct exec_node *prev;
#ifdef __cplusplus
- /* Callers of this talloc-based new need not call delete. It's
- * easier to just talloc_free 'ctx' (or any of its ancestors). */
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
static void* operator new(size_t size, void *ctx)
{
void *node;
- node = talloc_size(ctx, size);
+ node = ralloc_size(ctx, size);
assert(node != NULL);
return node;
}
/* If the user *does* call delete, that's OK, we will just
- * talloc_free in that case. */
+ * ralloc_free in that case. */
static void operator delete(void *node, void *ctx)
{
- talloc_free(node);
+ ralloc_free(node);
}
static void operator delete(void *node)
{
- talloc_free(node);
+ ralloc_free(node);
}
exec_node() : next(NULL), prev(NULL)
@@ -293,27 +289,27 @@ struct exec_list {
struct exec_node *tail_pred;
#ifdef __cplusplus
- /* Callers of this talloc-based new need not call delete. It's
- * easier to just talloc_free 'ctx' (or any of its ancestors). */
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
static void* operator new(size_t size, void *ctx)
{
void *node;
- node = talloc_size(ctx, size);
+ node = ralloc_size(ctx, size);
assert(node != NULL);
return node;
}
/* If the user *does* call delete, that's OK, we will just
- * talloc_free in that case. */
+ * ralloc_free in that case. */
static void operator delete(void *node, void *ctx)
{
- talloc_free(node);
+ ralloc_free(node);
}
static void operator delete(void *node)
{
- talloc_free(node);
+ ralloc_free(node);
}
exec_list()
diff --git a/mesalib/src/glsl/loop_analysis.cpp b/mesalib/src/glsl/loop_analysis.cpp
index 3cf86ebaa..9bba6a97c 100644
--- a/mesalib/src/glsl/loop_analysis.cpp
+++ b/mesalib/src/glsl/loop_analysis.cpp
@@ -37,7 +37,7 @@ loop_state::loop_state()
{
this->ht = hash_table_ctor(0, hash_table_pointer_hash,
hash_table_pointer_compare);
- this->mem_ctx = talloc_init("loop state");
+ this->mem_ctx = ralloc_context(NULL);
this->loop_found = false;
}
@@ -45,7 +45,7 @@ loop_state::loop_state()
loop_state::~loop_state()
{
hash_table_dtor(this->ht);
- talloc_free(this->mem_ctx);
+ ralloc_free(this->mem_ctx);
}
@@ -78,8 +78,8 @@ loop_variable_state::get(const ir_variable *ir)
loop_variable *
loop_variable_state::insert(ir_variable *var)
{
- void *mem_ctx = talloc_parent(this);
- loop_variable *lv = talloc_zero(mem_ctx, loop_variable);
+ void *mem_ctx = ralloc_parent(this);
+ loop_variable *lv = rzalloc(mem_ctx, loop_variable);
lv->var = var;
@@ -93,8 +93,8 @@ loop_variable_state::insert(ir_variable *var)
loop_terminator *
loop_variable_state::insert(ir_if *if_stmt)
{
- void *mem_ctx = talloc_parent(this);
- loop_terminator *t = talloc_zero(mem_ctx, loop_terminator);
+ void *mem_ctx = ralloc_parent(this);
+ loop_terminator *t = rzalloc(mem_ctx, loop_terminator);
t->ir = if_stmt;
this->terminators.push_tail(t);
@@ -450,7 +450,7 @@ get_basic_induction_increment(ir_assignment *ir, hash_table *var_hash)
}
if ((inc != NULL) && (rhs->operation == ir_binop_sub)) {
- void *mem_ctx = talloc_parent(ir);
+ void *mem_ctx = ralloc_parent(ir);
inc = new(mem_ctx) ir_expression(ir_unop_neg,
inc->type,
diff --git a/mesalib/src/glsl/loop_controls.cpp b/mesalib/src/glsl/loop_controls.cpp
index fb13439a1..9eaa50f22 100644
--- a/mesalib/src/glsl/loop_controls.cpp
+++ b/mesalib/src/glsl/loop_controls.cpp
@@ -1,304 +1,304 @@
-/*
- * 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 <climits>
-#include "main/compiler.h"
-#include "glsl_types.h"
-#include "loop_analysis.h"
-#include "ir_hierarchical_visitor.h"
-
-/**
- * Find an initializer of a variable outside a loop
- *
- * Works backwards from the loop to find the pre-loop value of the variable.
- * This is used, for example, to find the initial value of loop induction
- * variables.
- *
- * \param loop Loop where \c var is an induction variable
- * \param var Variable whose initializer is to be found
- *
- * \return
- * The \c ir_rvalue assigned to the variable outside the loop. May return
- * \c NULL if no initializer can be found.
- */
-ir_rvalue *
-find_initial_value(ir_loop *loop, ir_variable *var)
-{
- for (exec_node *node = loop->prev;
- !node->is_head_sentinel();
- node = node->prev) {
- ir_instruction *ir = (ir_instruction *) node;
-
- switch (ir->ir_type) {
- case ir_type_call:
- case ir_type_loop:
- case ir_type_loop_jump:
- case ir_type_return:
- case ir_type_if:
- return NULL;
-
- case ir_type_function:
- case ir_type_function_signature:
- assert(!"Should not get here.");
- return NULL;
-
- case ir_type_assignment: {
- ir_assignment *assign = ir->as_assignment();
- ir_variable *assignee = assign->lhs->whole_variable_referenced();
-
- if (assignee == var)
- return (assign->condition != NULL) ? NULL : assign->rhs;
-
- break;
- }
-
- default:
- break;
- }
- }
-
- return NULL;
-}
-
-
-int
-calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
- enum ir_expression_operation op)
-{
- if (from == NULL || to == NULL || increment == NULL)
- return -1;
-
- void *mem_ctx = talloc_init("%s", __func__);
-
- ir_expression *const sub =
- new(mem_ctx) ir_expression(ir_binop_sub, from->type, to, from);
-
- ir_expression *const div =
- new(mem_ctx) ir_expression(ir_binop_div, sub->type, sub, increment);
-
- ir_constant *iter = div->constant_expression_value();
-
- if (iter == NULL)
- return -1;
-
- if (!iter->type->is_integer()) {
- ir_rvalue *cast =
- new(mem_ctx) ir_expression(ir_unop_f2i, glsl_type::int_type, iter,
- NULL);
-
- iter = cast->constant_expression_value();
- }
-
- int iter_value = iter->get_int_component(0);
-
- /* Make sure that the calculated number of iterations satisfies the exit
- * condition. This is needed to catch off-by-one errors and some types of
- * ill-formed loops. For example, we need to detect that the following
- * loop does not have a maximum iteration count.
- *
- * for (float x = 0.0; x != 0.9; x += 0.2)
- * ;
- */
- const int bias[] = { -1, 0, 1 };
- bool valid_loop = false;
-
- for (unsigned i = 0; i < Elements(bias); i++) {
- iter = (increment->type->is_integer())
- ? new(mem_ctx) ir_constant(iter_value + bias[i])
- : new(mem_ctx) ir_constant(float(iter_value + bias[i]));
-
- ir_expression *const mul =
- new(mem_ctx) ir_expression(ir_binop_mul, increment->type, iter,
- increment);
-
- ir_expression *const add =
- new(mem_ctx) ir_expression(ir_binop_add, mul->type, mul, from);
-
- ir_expression *const cmp =
- new(mem_ctx) ir_expression(op, glsl_type::bool_type, add, to);
-
- ir_constant *const cmp_result = cmp->constant_expression_value();
-
- assert(cmp_result != NULL);
- if (cmp_result->get_bool_component(0)) {
- iter_value += bias[i];
- valid_loop = true;
- break;
- }
- }
-
- talloc_free(mem_ctx);
- return (valid_loop) ? iter_value : -1;
-}
-
-
-class loop_control_visitor : public ir_hierarchical_visitor {
-public:
- loop_control_visitor(loop_state *state)
- {
- this->state = state;
- this->progress = false;
- }
-
- virtual ir_visitor_status visit_leave(ir_loop *ir);
-
- loop_state *state;
-
- bool progress;
-};
-
-
-ir_visitor_status
-loop_control_visitor::visit_leave(ir_loop *ir)
-{
- loop_variable_state *const ls = this->state->get(ir);
-
- /* If we've entered a loop that hasn't been analyzed, something really,
- * really bad has happened.
- */
- if (ls == NULL) {
- assert(ls != NULL);
- return visit_continue;
- }
-
- /* Search the loop terminating conditions for one of the form 'i < c' where
- * i is a loop induction variable, c is a constant, and < is any relative
- * operator.
- */
- int max_iterations = ls->max_iterations;
-
- if(ir->from && ir->to && ir->increment)
- max_iterations = calculate_iterations(ir->from, ir->to, ir->increment, (ir_expression_operation)ir->cmp);
-
- if(max_iterations < 0)
- max_iterations = INT_MAX;
-
- foreach_list(node, &ls->terminators) {
- loop_terminator *t = (loop_terminator *) node;
- ir_if *if_stmt = t->ir;
-
- /* If-statements can be either 'if (expr)' or 'if (deref)'. We only care
- * about the former here.
- */
- ir_expression *cond = if_stmt->condition->as_expression();
- if (cond == NULL)
- continue;
-
- switch (cond->operation) {
- case ir_binop_less:
- case ir_binop_greater:
- case ir_binop_lequal:
- case ir_binop_gequal: {
- /* The expressions that we care about will either be of the form
- * 'counter < limit' or 'limit < counter'. Figure out which is
- * which.
- */
- ir_rvalue *counter = cond->operands[0]->as_dereference_variable();
- ir_constant *limit = cond->operands[1]->as_constant();
- enum ir_expression_operation cmp = cond->operation;
-
- if (limit == NULL) {
- counter = cond->operands[1]->as_dereference_variable();
- limit = cond->operands[0]->as_constant();
-
- switch (cmp) {
- case ir_binop_less: cmp = ir_binop_gequal; break;
- case ir_binop_greater: cmp = ir_binop_lequal; break;
- case ir_binop_lequal: cmp = ir_binop_greater; break;
- case ir_binop_gequal: cmp = ir_binop_less; break;
- default: assert(!"Should not get here.");
- }
- }
-
- if ((counter == NULL) || (limit == NULL))
- break;
-
- ir_variable *var = counter->variable_referenced();
-
- ir_rvalue *init = find_initial_value(ir, var);
-
- foreach_list(iv_node, &ls->induction_variables) {
- loop_variable *lv = (loop_variable *) iv_node;
-
- if (lv->var == var) {
- const int iterations = calculate_iterations(init, limit,
- lv->increment,
- cmp);
- if (iterations >= 0) {
- /* If the new iteration count is lower than the previously
- * believed iteration count, update the loop control values.
- */
- if (iterations < max_iterations) {
- ir->from = init->clone(ir, NULL);
- ir->to = limit->clone(ir, NULL);
- ir->increment = lv->increment->clone(ir, NULL);
- ir->counter = lv->var;
- ir->cmp = cmp;
-
- max_iterations = iterations;
- }
-
- /* Remove the conditional break statement. The loop
- * controls are now set such that the exit condition will be
- * satisfied.
- */
- if_stmt->remove();
-
- assert(ls->num_loop_jumps > 0);
- ls->num_loop_jumps--;
-
- this->progress = true;
- }
-
- break;
- }
- }
- break;
- }
-
- default:
- break;
- }
- }
-
- /* If we have proven the one of the loop exit conditions is satisifed before
- * running the loop once, remove the loop.
- */
- if (max_iterations == 0)
- ir->remove();
- else
- ls->max_iterations = max_iterations;
-
- return visit_continue;
-}
-
-
-bool
-set_loop_controls(exec_list *instructions, loop_state *ls)
-{
- loop_control_visitor v(ls);
-
- v.run(instructions);
-
- return v.progress;
-}
+/*
+ * 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 <climits>
+#include "main/compiler.h"
+#include "glsl_types.h"
+#include "loop_analysis.h"
+#include "ir_hierarchical_visitor.h"
+
+/**
+ * Find an initializer of a variable outside a loop
+ *
+ * Works backwards from the loop to find the pre-loop value of the variable.
+ * This is used, for example, to find the initial value of loop induction
+ * variables.
+ *
+ * \param loop Loop where \c var is an induction variable
+ * \param var Variable whose initializer is to be found
+ *
+ * \return
+ * The \c ir_rvalue assigned to the variable outside the loop. May return
+ * \c NULL if no initializer can be found.
+ */
+ir_rvalue *
+find_initial_value(ir_loop *loop, ir_variable *var)
+{
+ for (exec_node *node = loop->prev;
+ !node->is_head_sentinel();
+ node = node->prev) {
+ ir_instruction *ir = (ir_instruction *) node;
+
+ switch (ir->ir_type) {
+ case ir_type_call:
+ case ir_type_loop:
+ case ir_type_loop_jump:
+ case ir_type_return:
+ case ir_type_if:
+ return NULL;
+
+ case ir_type_function:
+ case ir_type_function_signature:
+ assert(!"Should not get here.");
+ return NULL;
+
+ case ir_type_assignment: {
+ ir_assignment *assign = ir->as_assignment();
+ ir_variable *assignee = assign->lhs->whole_variable_referenced();
+
+ if (assignee == var)
+ return (assign->condition != NULL) ? NULL : assign->rhs;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+
+int
+calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
+ enum ir_expression_operation op)
+{
+ if (from == NULL || to == NULL || increment == NULL)
+ return -1;
+
+ void *mem_ctx = ralloc_context(NULL);
+
+ ir_expression *const sub =
+ new(mem_ctx) ir_expression(ir_binop_sub, from->type, to, from);
+
+ ir_expression *const div =
+ new(mem_ctx) ir_expression(ir_binop_div, sub->type, sub, increment);
+
+ ir_constant *iter = div->constant_expression_value();
+
+ if (iter == NULL)
+ return -1;
+
+ if (!iter->type->is_integer()) {
+ ir_rvalue *cast =
+ new(mem_ctx) ir_expression(ir_unop_f2i, glsl_type::int_type, iter,
+ NULL);
+
+ iter = cast->constant_expression_value();
+ }
+
+ int iter_value = iter->get_int_component(0);
+
+ /* Make sure that the calculated number of iterations satisfies the exit
+ * condition. This is needed to catch off-by-one errors and some types of
+ * ill-formed loops. For example, we need to detect that the following
+ * loop does not have a maximum iteration count.
+ *
+ * for (float x = 0.0; x != 0.9; x += 0.2)
+ * ;
+ */
+ const int bias[] = { -1, 0, 1 };
+ bool valid_loop = false;
+
+ for (unsigned i = 0; i < Elements(bias); i++) {
+ iter = (increment->type->is_integer())
+ ? new(mem_ctx) ir_constant(iter_value + bias[i])
+ : new(mem_ctx) ir_constant(float(iter_value + bias[i]));
+
+ ir_expression *const mul =
+ new(mem_ctx) ir_expression(ir_binop_mul, increment->type, iter,
+ increment);
+
+ ir_expression *const add =
+ new(mem_ctx) ir_expression(ir_binop_add, mul->type, mul, from);
+
+ ir_expression *const cmp =
+ new(mem_ctx) ir_expression(op, glsl_type::bool_type, add, to);
+
+ ir_constant *const cmp_result = cmp->constant_expression_value();
+
+ assert(cmp_result != NULL);
+ if (cmp_result->get_bool_component(0)) {
+ iter_value += bias[i];
+ valid_loop = true;
+ break;
+ }
+ }
+
+ ralloc_free(mem_ctx);
+ return (valid_loop) ? iter_value : -1;
+}
+
+
+class loop_control_visitor : public ir_hierarchical_visitor {
+public:
+ loop_control_visitor(loop_state *state)
+ {
+ this->state = state;
+ this->progress = false;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_loop *ir);
+
+ loop_state *state;
+
+ bool progress;
+};
+
+
+ir_visitor_status
+loop_control_visitor::visit_leave(ir_loop *ir)
+{
+ loop_variable_state *const ls = this->state->get(ir);
+
+ /* If we've entered a loop that hasn't been analyzed, something really,
+ * really bad has happened.
+ */
+ if (ls == NULL) {
+ assert(ls != NULL);
+ return visit_continue;
+ }
+
+ /* Search the loop terminating conditions for one of the form 'i < c' where
+ * i is a loop induction variable, c is a constant, and < is any relative
+ * operator.
+ */
+ int max_iterations = ls->max_iterations;
+
+ if(ir->from && ir->to && ir->increment)
+ max_iterations = calculate_iterations(ir->from, ir->to, ir->increment, (ir_expression_operation)ir->cmp);
+
+ if(max_iterations < 0)
+ max_iterations = INT_MAX;
+
+ foreach_list(node, &ls->terminators) {
+ loop_terminator *t = (loop_terminator *) node;
+ ir_if *if_stmt = t->ir;
+
+ /* If-statements can be either 'if (expr)' or 'if (deref)'. We only care
+ * about the former here.
+ */
+ ir_expression *cond = if_stmt->condition->as_expression();
+ if (cond == NULL)
+ continue;
+
+ switch (cond->operation) {
+ case ir_binop_less:
+ case ir_binop_greater:
+ case ir_binop_lequal:
+ case ir_binop_gequal: {
+ /* The expressions that we care about will either be of the form
+ * 'counter < limit' or 'limit < counter'. Figure out which is
+ * which.
+ */
+ ir_rvalue *counter = cond->operands[0]->as_dereference_variable();
+ ir_constant *limit = cond->operands[1]->as_constant();
+ enum ir_expression_operation cmp = cond->operation;
+
+ if (limit == NULL) {
+ counter = cond->operands[1]->as_dereference_variable();
+ limit = cond->operands[0]->as_constant();
+
+ switch (cmp) {
+ case ir_binop_less: cmp = ir_binop_gequal; break;
+ case ir_binop_greater: cmp = ir_binop_lequal; break;
+ case ir_binop_lequal: cmp = ir_binop_greater; break;
+ case ir_binop_gequal: cmp = ir_binop_less; break;
+ default: assert(!"Should not get here.");
+ }
+ }
+
+ if ((counter == NULL) || (limit == NULL))
+ break;
+
+ ir_variable *var = counter->variable_referenced();
+
+ ir_rvalue *init = find_initial_value(ir, var);
+
+ foreach_list(iv_node, &ls->induction_variables) {
+ loop_variable *lv = (loop_variable *) iv_node;
+
+ if (lv->var == var) {
+ const int iterations = calculate_iterations(init, limit,
+ lv->increment,
+ cmp);
+ if (iterations >= 0) {
+ /* If the new iteration count is lower than the previously
+ * believed iteration count, update the loop control values.
+ */
+ if (iterations < max_iterations) {
+ ir->from = init->clone(ir, NULL);
+ ir->to = limit->clone(ir, NULL);
+ ir->increment = lv->increment->clone(ir, NULL);
+ ir->counter = lv->var;
+ ir->cmp = cmp;
+
+ max_iterations = iterations;
+ }
+
+ /* Remove the conditional break statement. The loop
+ * controls are now set such that the exit condition will be
+ * satisfied.
+ */
+ if_stmt->remove();
+
+ assert(ls->num_loop_jumps > 0);
+ ls->num_loop_jumps--;
+
+ this->progress = true;
+ }
+
+ break;
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ /* If we have proven the one of the loop exit conditions is satisifed before
+ * running the loop once, remove the loop.
+ */
+ if (max_iterations == 0)
+ ir->remove();
+ else
+ ls->max_iterations = max_iterations;
+
+ return visit_continue;
+}
+
+
+bool
+set_loop_controls(exec_list *instructions, loop_state *ls)
+{
+ loop_control_visitor v(ls);
+
+ v.run(instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/loop_unroll.cpp b/mesalib/src/glsl/loop_unroll.cpp
index c54f2ca3d..5b84e1014 100644
--- a/mesalib/src/glsl/loop_unroll.cpp
+++ b/mesalib/src/glsl/loop_unroll.cpp
@@ -1,214 +1,214 @@
-/*
- * 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 "glsl_types.h"
-#include "loop_analysis.h"
-#include "ir_hierarchical_visitor.h"
-
-class loop_unroll_visitor : public ir_hierarchical_visitor {
-public:
- loop_unroll_visitor(loop_state *state, unsigned max_iterations)
- {
- this->state = state;
- this->progress = false;
- this->max_iterations = max_iterations;
- }
-
- virtual ir_visitor_status visit_leave(ir_loop *ir);
-
- loop_state *state;
-
- bool progress;
- unsigned max_iterations;
-};
-
-
-static bool
-is_break(ir_instruction *ir)
-{
- return ir != NULL && ir->ir_type == ir_type_loop_jump
- && ((ir_loop_jump *) ir)->is_break();
-}
-
-
-ir_visitor_status
-loop_unroll_visitor::visit_leave(ir_loop *ir)
-{
- loop_variable_state *const ls = this->state->get(ir);
- int iterations;
-
- /* If we've entered a loop that hasn't been analyzed, something really,
- * really bad has happened.
- */
- if (ls == NULL) {
- assert(ls != NULL);
- return visit_continue;
- }
-
- iterations = ls->max_iterations;
-
- /* Don't try to unroll loops where the number of iterations is not known
- * at compile-time.
- */
- if (iterations < 0)
- return visit_continue;
-
- /* Don't try to unroll loops that have zillions of iterations either.
- */
- if (iterations > (int) max_iterations)
- return visit_continue;
-
- if (ls->num_loop_jumps > 1)
- return visit_continue;
- else if (ls->num_loop_jumps) {
- ir_instruction *last_ir = (ir_instruction *) ir->body_instructions.get_tail();
- assert(last_ir != NULL);
-
- if (is_break(last_ir)) {
- /* If the only loop-jump is a break at the end of the loop, the loop
- * will execute exactly once. Remove the break, set the iteration
- * count, and fall through to the normal unroller.
- */
- last_ir->remove();
- iterations = 1;
-
- this->progress = true;
- } else {
- ir_if *ir_if = NULL;
- ir_instruction *break_ir = NULL;
- bool continue_from_then_branch = false;
-
- foreach_list(node, &ir->body_instructions) {
- /* recognize loops in the form produced by ir_lower_jumps */
- ir_instruction *cur_ir = (ir_instruction *) node;
-
- ir_if = cur_ir->as_if();
- if (ir_if != NULL) {
- /* Determine which if-statement branch, if any, ends with a
- * break. The branch that did *not* have the break will get a
- * temporary continue inserted in each iteration of the loop
- * unroll.
- *
- * Note that since ls->num_loop_jumps is <= 1, it is impossible
- * for both branches to end with a break.
- */
- ir_instruction *ir_if_last =
- (ir_instruction *) ir_if->then_instructions.get_tail();
-
- if (is_break(ir_if_last)) {
- continue_from_then_branch = false;
- break_ir = ir_if_last;
- break;
- } else {
- ir_if_last =
- (ir_instruction *) ir_if->else_instructions.get_tail();
-
- if (is_break(ir_if_last)) {
- break_ir = ir_if_last;
- continue_from_then_branch = true;
- break;
- }
- }
- }
- }
-
- if (break_ir == NULL)
- return visit_continue;
-
- /* move instructions after then if in the continue branch */
- while (!ir_if->get_next()->is_tail_sentinel()) {
- ir_instruction *move_ir = (ir_instruction *) ir_if->get_next();
-
- move_ir->remove();
- if (continue_from_then_branch)
- ir_if->then_instructions.push_tail(move_ir);
- else
- ir_if->else_instructions.push_tail(move_ir);
- }
-
- /* Remove the break from the if-statement.
- */
- break_ir->remove();
-
- void *const mem_ctx = talloc_parent(ir);
- ir_instruction *ir_to_replace = ir;
-
- for (int i = 0; i < iterations; i++) {
- exec_list copy_list;
-
- copy_list.make_empty();
- clone_ir_list(mem_ctx, &copy_list, &ir->body_instructions);
-
- ir_if = ((ir_instruction *) copy_list.get_tail())->as_if();
- assert(ir_if != NULL);
-
- ir_to_replace->insert_before(&copy_list);
- ir_to_replace->remove();
-
- /* placeholder that will be removed in the next iteration */
- ir_to_replace =
- new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue);
-
- exec_list *const list = (continue_from_then_branch)
- ? &ir_if->then_instructions : &ir_if->else_instructions;
-
- list->push_tail(ir_to_replace);
- }
-
- ir_to_replace->remove();
-
- this->progress = true;
- return visit_continue;
- }
- }
-
- void *const mem_ctx = talloc_parent(ir);
-
- for (int i = 0; i < iterations; i++) {
- exec_list copy_list;
-
- copy_list.make_empty();
- clone_ir_list(mem_ctx, &copy_list, &ir->body_instructions);
-
- ir->insert_before(&copy_list);
- }
-
- /* The loop has been replaced by the unrolled copies. Remove the original
- * loop from the IR sequence.
- */
- ir->remove();
-
- this->progress = true;
- return visit_continue;
-}
-
-
-bool
-unroll_loops(exec_list *instructions, loop_state *ls, unsigned max_iterations)
-{
- loop_unroll_visitor v(ls, max_iterations);
-
- v.run(instructions);
-
- return v.progress;
-}
+/*
+ * 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 "glsl_types.h"
+#include "loop_analysis.h"
+#include "ir_hierarchical_visitor.h"
+
+class loop_unroll_visitor : public ir_hierarchical_visitor {
+public:
+ loop_unroll_visitor(loop_state *state, unsigned max_iterations)
+ {
+ this->state = state;
+ this->progress = false;
+ this->max_iterations = max_iterations;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_loop *ir);
+
+ loop_state *state;
+
+ bool progress;
+ unsigned max_iterations;
+};
+
+
+static bool
+is_break(ir_instruction *ir)
+{
+ return ir != NULL && ir->ir_type == ir_type_loop_jump
+ && ((ir_loop_jump *) ir)->is_break();
+}
+
+
+ir_visitor_status
+loop_unroll_visitor::visit_leave(ir_loop *ir)
+{
+ loop_variable_state *const ls = this->state->get(ir);
+ int iterations;
+
+ /* If we've entered a loop that hasn't been analyzed, something really,
+ * really bad has happened.
+ */
+ if (ls == NULL) {
+ assert(ls != NULL);
+ return visit_continue;
+ }
+
+ iterations = ls->max_iterations;
+
+ /* Don't try to unroll loops where the number of iterations is not known
+ * at compile-time.
+ */
+ if (iterations < 0)
+ return visit_continue;
+
+ /* Don't try to unroll loops that have zillions of iterations either.
+ */
+ if (iterations > (int) max_iterations)
+ return visit_continue;
+
+ if (ls->num_loop_jumps > 1)
+ return visit_continue;
+ else if (ls->num_loop_jumps) {
+ ir_instruction *last_ir = (ir_instruction *) ir->body_instructions.get_tail();
+ assert(last_ir != NULL);
+
+ if (is_break(last_ir)) {
+ /* If the only loop-jump is a break at the end of the loop, the loop
+ * will execute exactly once. Remove the break, set the iteration
+ * count, and fall through to the normal unroller.
+ */
+ last_ir->remove();
+ iterations = 1;
+
+ this->progress = true;
+ } else {
+ ir_if *ir_if = NULL;
+ ir_instruction *break_ir = NULL;
+ bool continue_from_then_branch = false;
+
+ foreach_list(node, &ir->body_instructions) {
+ /* recognize loops in the form produced by ir_lower_jumps */
+ ir_instruction *cur_ir = (ir_instruction *) node;
+
+ ir_if = cur_ir->as_if();
+ if (ir_if != NULL) {
+ /* Determine which if-statement branch, if any, ends with a
+ * break. The branch that did *not* have the break will get a
+ * temporary continue inserted in each iteration of the loop
+ * unroll.
+ *
+ * Note that since ls->num_loop_jumps is <= 1, it is impossible
+ * for both branches to end with a break.
+ */
+ ir_instruction *ir_if_last =
+ (ir_instruction *) ir_if->then_instructions.get_tail();
+
+ if (is_break(ir_if_last)) {
+ continue_from_then_branch = false;
+ break_ir = ir_if_last;
+ break;
+ } else {
+ ir_if_last =
+ (ir_instruction *) ir_if->else_instructions.get_tail();
+
+ if (is_break(ir_if_last)) {
+ break_ir = ir_if_last;
+ continue_from_then_branch = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (break_ir == NULL)
+ return visit_continue;
+
+ /* move instructions after then if in the continue branch */
+ while (!ir_if->get_next()->is_tail_sentinel()) {
+ ir_instruction *move_ir = (ir_instruction *) ir_if->get_next();
+
+ move_ir->remove();
+ if (continue_from_then_branch)
+ ir_if->then_instructions.push_tail(move_ir);
+ else
+ ir_if->else_instructions.push_tail(move_ir);
+ }
+
+ /* Remove the break from the if-statement.
+ */
+ break_ir->remove();
+
+ void *const mem_ctx = ralloc_parent(ir);
+ ir_instruction *ir_to_replace = ir;
+
+ for (int i = 0; i < iterations; i++) {
+ exec_list copy_list;
+
+ copy_list.make_empty();
+ clone_ir_list(mem_ctx, &copy_list, &ir->body_instructions);
+
+ ir_if = ((ir_instruction *) copy_list.get_tail())->as_if();
+ assert(ir_if != NULL);
+
+ ir_to_replace->insert_before(&copy_list);
+ ir_to_replace->remove();
+
+ /* placeholder that will be removed in the next iteration */
+ ir_to_replace =
+ new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue);
+
+ exec_list *const list = (continue_from_then_branch)
+ ? &ir_if->then_instructions : &ir_if->else_instructions;
+
+ list->push_tail(ir_to_replace);
+ }
+
+ ir_to_replace->remove();
+
+ this->progress = true;
+ return visit_continue;
+ }
+ }
+
+ void *const mem_ctx = ralloc_parent(ir);
+
+ for (int i = 0; i < iterations; i++) {
+ exec_list copy_list;
+
+ copy_list.make_empty();
+ clone_ir_list(mem_ctx, &copy_list, &ir->body_instructions);
+
+ ir->insert_before(&copy_list);
+ }
+
+ /* The loop has been replaced by the unrolled copies. Remove the original
+ * loop from the IR sequence.
+ */
+ ir->remove();
+
+ this->progress = true;
+ return visit_continue;
+}
+
+
+bool
+unroll_loops(exec_list *instructions, loop_state *ls, unsigned max_iterations)
+{
+ loop_unroll_visitor v(ls, max_iterations);
+
+ v.run(instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/lower_discard.cpp b/mesalib/src/glsl/lower_discard.cpp
index 5c3603ed7..cafd2dd3b 100644
--- a/mesalib/src/glsl/lower_discard.cpp
+++ b/mesalib/src/glsl/lower_discard.cpp
@@ -1,198 +1,198 @@
-/*
- * 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 lower_discard.cpp
- *
- * This pass moves discards out of if-statements.
- *
- * Case 1: The "then" branch contains a conditional discard:
- * ---------------------------------------------------------
- *
- * if (cond1) {
- * s1;
- * discard cond2;
- * s2;
- * } else {
- * s3;
- * }
- *
- * becomes:
- *
- * temp = false;
- * if (cond1) {
- * s1;
- * temp = cond2;
- * s2;
- * } else {
- * s3;
- * }
- * discard temp;
- *
- * Case 2: The "else" branch contains a conditional discard:
- * ---------------------------------------------------------
- *
- * if (cond1) {
- * s1;
- * } else {
- * s2;
- * discard cond2;
- * s3;
- * }
- *
- * becomes:
- *
- * temp = false;
- * if (cond1) {
- * s1;
- * } else {
- * s2;
- * temp = cond2;
- * s3;
- * }
- * discard temp;
- *
- * Case 3: Both branches contain a conditional discard:
- * ----------------------------------------------------
- *
- * if (cond1) {
- * s1;
- * discard cond2;
- * s2;
- * } else {
- * s3;
- * discard cond3;
- * s4;
- * }
- *
- * becomes:
- *
- * temp = false;
- * if (cond1) {
- * s1;
- * temp = cond2;
- * s2;
- * } else {
- * s3;
- * temp = cond3;
- * s4;
- * }
- * discard temp;
- *
- * If there are multiple conditional discards, we need only deal with one of
- * them. Repeatedly applying this pass will take care of the others.
- *
- * Unconditional discards are treated as having a condition of "true".
- */
-
-#include "glsl_types.h"
-#include "ir.h"
-
-class lower_discard_visitor : public ir_hierarchical_visitor {
-public:
- lower_discard_visitor()
- {
- this->progress = false;
- }
-
- ir_visitor_status visit_leave(ir_if *);
-
- bool progress;
-};
-
-
-bool
-lower_discard(exec_list *instructions)
-{
- lower_discard_visitor v;
-
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
-
-
-static ir_discard *
-find_discard(exec_list &instructions)
-{
- foreach_list(n, &instructions) {
- ir_discard *ir = ((ir_instruction *) n)->as_discard();
- if (ir != NULL)
- return ir;
- }
- return NULL;
-}
-
-
-static void
-replace_discard(void *mem_ctx, ir_variable *var, ir_discard *ir)
-{
- ir_rvalue *condition = ir->condition;
-
- /* For unconditional discards, use "true" as the condition. */
- if (condition == NULL)
- condition = new(mem_ctx) ir_constant(true);
-
- ir_assignment *assignment =
- new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(var),
- condition, NULL);
-
- ir->replace_with(assignment);
-}
-
-
-ir_visitor_status
-lower_discard_visitor::visit_leave(ir_if *ir)
-{
- ir_discard *then_discard = find_discard(ir->then_instructions);
- ir_discard *else_discard = find_discard(ir->else_instructions);
-
- if (then_discard == NULL && else_discard == NULL)
- return visit_continue;
-
- void *mem_ctx = talloc_parent(ir);
-
- ir_variable *temp = new(mem_ctx) ir_variable(glsl_type::bool_type,
- "discard_cond_temp",
- ir_var_temporary);
- ir_assignment *temp_initializer =
- new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(temp),
- new(mem_ctx) ir_constant(false), NULL);
-
- ir->insert_before(temp);
- ir->insert_before(temp_initializer);
-
- if (then_discard != NULL)
- replace_discard(mem_ctx, temp, then_discard);
-
- if (else_discard != NULL)
- replace_discard(mem_ctx, temp, else_discard);
-
- ir_discard *discard = then_discard != NULL ? then_discard : else_discard;
- discard->condition = new(mem_ctx) ir_dereference_variable(temp);
- ir->insert_after(discard);
-
- this->progress = true;
-
- return visit_continue;
-}
+/*
+ * 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 lower_discard.cpp
+ *
+ * This pass moves discards out of if-statements.
+ *
+ * Case 1: The "then" branch contains a conditional discard:
+ * ---------------------------------------------------------
+ *
+ * if (cond1) {
+ * s1;
+ * discard cond2;
+ * s2;
+ * } else {
+ * s3;
+ * }
+ *
+ * becomes:
+ *
+ * temp = false;
+ * if (cond1) {
+ * s1;
+ * temp = cond2;
+ * s2;
+ * } else {
+ * s3;
+ * }
+ * discard temp;
+ *
+ * Case 2: The "else" branch contains a conditional discard:
+ * ---------------------------------------------------------
+ *
+ * if (cond1) {
+ * s1;
+ * } else {
+ * s2;
+ * discard cond2;
+ * s3;
+ * }
+ *
+ * becomes:
+ *
+ * temp = false;
+ * if (cond1) {
+ * s1;
+ * } else {
+ * s2;
+ * temp = cond2;
+ * s3;
+ * }
+ * discard temp;
+ *
+ * Case 3: Both branches contain a conditional discard:
+ * ----------------------------------------------------
+ *
+ * if (cond1) {
+ * s1;
+ * discard cond2;
+ * s2;
+ * } else {
+ * s3;
+ * discard cond3;
+ * s4;
+ * }
+ *
+ * becomes:
+ *
+ * temp = false;
+ * if (cond1) {
+ * s1;
+ * temp = cond2;
+ * s2;
+ * } else {
+ * s3;
+ * temp = cond3;
+ * s4;
+ * }
+ * discard temp;
+ *
+ * If there are multiple conditional discards, we need only deal with one of
+ * them. Repeatedly applying this pass will take care of the others.
+ *
+ * Unconditional discards are treated as having a condition of "true".
+ */
+
+#include "glsl_types.h"
+#include "ir.h"
+
+class lower_discard_visitor : public ir_hierarchical_visitor {
+public:
+ lower_discard_visitor()
+ {
+ this->progress = false;
+ }
+
+ ir_visitor_status visit_leave(ir_if *);
+
+ bool progress;
+};
+
+
+bool
+lower_discard(exec_list *instructions)
+{
+ lower_discard_visitor v;
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
+
+
+static ir_discard *
+find_discard(exec_list &instructions)
+{
+ foreach_list(n, &instructions) {
+ ir_discard *ir = ((ir_instruction *) n)->as_discard();
+ if (ir != NULL)
+ return ir;
+ }
+ return NULL;
+}
+
+
+static void
+replace_discard(void *mem_ctx, ir_variable *var, ir_discard *ir)
+{
+ ir_rvalue *condition = ir->condition;
+
+ /* For unconditional discards, use "true" as the condition. */
+ if (condition == NULL)
+ condition = new(mem_ctx) ir_constant(true);
+
+ ir_assignment *assignment =
+ new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(var),
+ condition, NULL);
+
+ ir->replace_with(assignment);
+}
+
+
+ir_visitor_status
+lower_discard_visitor::visit_leave(ir_if *ir)
+{
+ ir_discard *then_discard = find_discard(ir->then_instructions);
+ ir_discard *else_discard = find_discard(ir->else_instructions);
+
+ if (then_discard == NULL && else_discard == NULL)
+ return visit_continue;
+
+ void *mem_ctx = ralloc_parent(ir);
+
+ ir_variable *temp = new(mem_ctx) ir_variable(glsl_type::bool_type,
+ "discard_cond_temp",
+ ir_var_temporary);
+ ir_assignment *temp_initializer =
+ new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(temp),
+ new(mem_ctx) ir_constant(false), NULL);
+
+ ir->insert_before(temp);
+ ir->insert_before(temp_initializer);
+
+ if (then_discard != NULL)
+ replace_discard(mem_ctx, temp, then_discard);
+
+ if (else_discard != NULL)
+ replace_discard(mem_ctx, temp, else_discard);
+
+ ir_discard *discard = then_discard != NULL ? then_discard : else_discard;
+ discard->condition = new(mem_ctx) ir_dereference_variable(temp);
+ ir->insert_after(discard);
+
+ this->progress = true;
+
+ return visit_continue;
+}
diff --git a/mesalib/src/glsl/lower_if_to_cond_assign.cpp b/mesalib/src/glsl/lower_if_to_cond_assign.cpp
index 9212ae21e..e3a1065d9 100644
--- a/mesalib/src/glsl/lower_if_to_cond_assign.cpp
+++ b/mesalib/src/glsl/lower_if_to_cond_assign.cpp
@@ -1,200 +1,200 @@
-/*
- * 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 lower_if_to_cond_assign.cpp
- *
- * This attempts to flatten if-statements to conditional assignments for
- * GPUs with limited or no flow control support.
- *
- * It can't handle other control flow being inside of its block, such
- * as calls or loops. Hopefully loop unrolling and inlining will take
- * care of those.
- *
- * Drivers for GPUs with no control flow support should simply call
- *
- * lower_if_to_cond_assign(instructions)
- *
- * to attempt to flatten all if-statements.
- *
- * Some GPUs (such as i965 prior to gen6) do support control flow, but have a
- * maximum nesting depth N. Drivers for such hardware can call
- *
- * lower_if_to_cond_assign(instructions, N)
- *
- * to attempt to flatten any if-statements appearing at depth > N.
- */
-
-#include "glsl_types.h"
-#include "ir.h"
-
-class ir_if_to_cond_assign_visitor : public ir_hierarchical_visitor {
-public:
- ir_if_to_cond_assign_visitor(unsigned max_depth)
- {
- this->progress = false;
- this->max_depth = max_depth;
- this->depth = 0;
- }
-
- ir_visitor_status visit_enter(ir_if *);
- ir_visitor_status visit_leave(ir_if *);
-
- bool progress;
- unsigned max_depth;
- unsigned depth;
-};
-
-bool
-lower_if_to_cond_assign(exec_list *instructions, unsigned max_depth)
-{
- ir_if_to_cond_assign_visitor v(max_depth);
-
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
-
-void
-check_control_flow(ir_instruction *ir, void *data)
-{
- bool *found_control_flow = (bool *)data;
- switch (ir->ir_type) {
- case ir_type_call:
- case ir_type_discard:
- case ir_type_loop:
- case ir_type_loop_jump:
- case ir_type_return:
- *found_control_flow = true;
- break;
- default:
- break;
- }
-}
-
-void
-move_block_to_cond_assign(void *mem_ctx,
- ir_if *if_ir, ir_variable *cond_var, bool then)
-{
- exec_list *instructions;
-
- if (then) {
- instructions = &if_ir->then_instructions;
- } else {
- instructions = &if_ir->else_instructions;
- }
-
- foreach_iter(exec_list_iterator, iter, *instructions) {
- ir_instruction *ir = (ir_instruction *)iter.get();
-
- if (ir->ir_type == ir_type_assignment) {
- ir_assignment *assign = (ir_assignment *)ir;
- ir_rvalue *cond_expr;
- ir_dereference *deref = new(mem_ctx) ir_dereference_variable(cond_var);
-
- if (then) {
- cond_expr = deref;
- } else {
- cond_expr = new(mem_ctx) ir_expression(ir_unop_logic_not,
- glsl_type::bool_type,
- deref,
- NULL);
- }
-
- if (!assign->condition) {
- assign->condition = cond_expr;
- } else {
- assign->condition = new(mem_ctx) ir_expression(ir_binop_logic_and,
- glsl_type::bool_type,
- cond_expr,
- assign->condition);
- }
- }
-
- /* Now, move from the if block to the block surrounding it. */
- ir->remove();
- if_ir->insert_before(ir);
- }
-}
-
-ir_visitor_status
-ir_if_to_cond_assign_visitor::visit_enter(ir_if *ir)
-{
- (void) ir;
- this->depth++;
- return visit_continue;
-}
-
-ir_visitor_status
-ir_if_to_cond_assign_visitor::visit_leave(ir_if *ir)
-{
- /* Only flatten when beyond the GPU's maximum supported nesting depth. */
- if (this->depth <= this->max_depth)
- return visit_continue;
-
- this->depth--;
-
- bool found_control_flow = false;
- ir_variable *cond_var;
- ir_assignment *assign;
- ir_dereference_variable *deref;
-
- /* Check that both blocks don't contain anything we can't support. */
- foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) {
- ir_instruction *then_ir = (ir_instruction *)then_iter.get();
- visit_tree(then_ir, check_control_flow, &found_control_flow);
- }
- foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) {
- ir_instruction *else_ir = (ir_instruction *)else_iter.get();
- visit_tree(else_ir, check_control_flow, &found_control_flow);
- }
- if (found_control_flow)
- return visit_continue;
-
- void *mem_ctx = talloc_parent(ir);
-
- /* Store the condition to a variable so the assignment conditions are
- * simpler.
- */
- cond_var = new(mem_ctx) ir_variable(glsl_type::bool_type,
- "if_to_cond_assign_condition",
- ir_var_temporary);
- ir->insert_before(cond_var);
-
- deref = new(mem_ctx) ir_dereference_variable(cond_var);
- assign = new(mem_ctx) ir_assignment(deref,
- ir->condition, NULL);
- ir->insert_before(assign);
-
- /* Now, move all of the instructions out of the if blocks, putting
- * conditions on assignments.
- */
- move_block_to_cond_assign(mem_ctx, ir, cond_var, true);
- move_block_to_cond_assign(mem_ctx, ir, cond_var, false);
-
- ir->remove();
-
- this->progress = true;
-
- return visit_continue;
-}
+/*
+ * 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 lower_if_to_cond_assign.cpp
+ *
+ * This attempts to flatten if-statements to conditional assignments for
+ * GPUs with limited or no flow control support.
+ *
+ * It can't handle other control flow being inside of its block, such
+ * as calls or loops. Hopefully loop unrolling and inlining will take
+ * care of those.
+ *
+ * Drivers for GPUs with no control flow support should simply call
+ *
+ * lower_if_to_cond_assign(instructions)
+ *
+ * to attempt to flatten all if-statements.
+ *
+ * Some GPUs (such as i965 prior to gen6) do support control flow, but have a
+ * maximum nesting depth N. Drivers for such hardware can call
+ *
+ * lower_if_to_cond_assign(instructions, N)
+ *
+ * to attempt to flatten any if-statements appearing at depth > N.
+ */
+
+#include "glsl_types.h"
+#include "ir.h"
+
+class ir_if_to_cond_assign_visitor : public ir_hierarchical_visitor {
+public:
+ ir_if_to_cond_assign_visitor(unsigned max_depth)
+ {
+ this->progress = false;
+ this->max_depth = max_depth;
+ this->depth = 0;
+ }
+
+ ir_visitor_status visit_enter(ir_if *);
+ ir_visitor_status visit_leave(ir_if *);
+
+ bool progress;
+ unsigned max_depth;
+ unsigned depth;
+};
+
+bool
+lower_if_to_cond_assign(exec_list *instructions, unsigned max_depth)
+{
+ ir_if_to_cond_assign_visitor v(max_depth);
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
+
+void
+check_control_flow(ir_instruction *ir, void *data)
+{
+ bool *found_control_flow = (bool *)data;
+ switch (ir->ir_type) {
+ case ir_type_call:
+ case ir_type_discard:
+ case ir_type_loop:
+ case ir_type_loop_jump:
+ case ir_type_return:
+ *found_control_flow = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+move_block_to_cond_assign(void *mem_ctx,
+ ir_if *if_ir, ir_variable *cond_var, bool then)
+{
+ exec_list *instructions;
+
+ if (then) {
+ instructions = &if_ir->then_instructions;
+ } else {
+ instructions = &if_ir->else_instructions;
+ }
+
+ foreach_iter(exec_list_iterator, iter, *instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+
+ if (ir->ir_type == ir_type_assignment) {
+ ir_assignment *assign = (ir_assignment *)ir;
+ ir_rvalue *cond_expr;
+ ir_dereference *deref = new(mem_ctx) ir_dereference_variable(cond_var);
+
+ if (then) {
+ cond_expr = deref;
+ } else {
+ cond_expr = new(mem_ctx) ir_expression(ir_unop_logic_not,
+ glsl_type::bool_type,
+ deref,
+ NULL);
+ }
+
+ if (!assign->condition) {
+ assign->condition = cond_expr;
+ } else {
+ assign->condition = new(mem_ctx) ir_expression(ir_binop_logic_and,
+ glsl_type::bool_type,
+ cond_expr,
+ assign->condition);
+ }
+ }
+
+ /* Now, move from the if block to the block surrounding it. */
+ ir->remove();
+ if_ir->insert_before(ir);
+ }
+}
+
+ir_visitor_status
+ir_if_to_cond_assign_visitor::visit_enter(ir_if *ir)
+{
+ (void) ir;
+ this->depth++;
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_if_to_cond_assign_visitor::visit_leave(ir_if *ir)
+{
+ /* Only flatten when beyond the GPU's maximum supported nesting depth. */
+ if (this->depth <= this->max_depth)
+ return visit_continue;
+
+ this->depth--;
+
+ bool found_control_flow = false;
+ ir_variable *cond_var;
+ ir_assignment *assign;
+ ir_dereference_variable *deref;
+
+ /* Check that both blocks don't contain anything we can't support. */
+ foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) {
+ ir_instruction *then_ir = (ir_instruction *)then_iter.get();
+ visit_tree(then_ir, check_control_flow, &found_control_flow);
+ }
+ foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) {
+ ir_instruction *else_ir = (ir_instruction *)else_iter.get();
+ visit_tree(else_ir, check_control_flow, &found_control_flow);
+ }
+ if (found_control_flow)
+ return visit_continue;
+
+ void *mem_ctx = ralloc_parent(ir);
+
+ /* Store the condition to a variable so the assignment conditions are
+ * simpler.
+ */
+ cond_var = new(mem_ctx) ir_variable(glsl_type::bool_type,
+ "if_to_cond_assign_condition",
+ ir_var_temporary);
+ ir->insert_before(cond_var);
+
+ deref = new(mem_ctx) ir_dereference_variable(cond_var);
+ assign = new(mem_ctx) ir_assignment(deref,
+ ir->condition, NULL);
+ ir->insert_before(assign);
+
+ /* Now, move all of the instructions out of the if blocks, putting
+ * conditions on assignments.
+ */
+ move_block_to_cond_assign(mem_ctx, ir, cond_var, true);
+ move_block_to_cond_assign(mem_ctx, ir, cond_var, false);
+
+ ir->remove();
+
+ this->progress = true;
+
+ return visit_continue;
+}
diff --git a/mesalib/src/glsl/lower_mat_op_to_vec.cpp b/mesalib/src/glsl/lower_mat_op_to_vec.cpp
index d61d94443..8cbbfa713 100644
--- a/mesalib/src/glsl/lower_mat_op_to_vec.cpp
+++ b/mesalib/src/glsl/lower_mat_op_to_vec.cpp
@@ -1,490 +1,490 @@
-/*
- * 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 lower_mat_op_to_vec.cpp
- *
- * Breaks matrix operation expressions down to a series of vector operations.
- *
- * Generally this is how we have to codegen matrix operations for a
- * GPU, so this gives us the chance to constant fold operations on a
- * column or row.
- */
-
-#include "ir.h"
-#include "ir_expression_flattening.h"
-#include "glsl_types.h"
-
-class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor {
-public:
- ir_mat_op_to_vec_visitor()
- {
- this->made_progress = false;
- this->mem_ctx = NULL;
- }
-
- ir_visitor_status visit_leave(ir_assignment *);
-
- ir_dereference *get_column(ir_variable *var, int col);
- ir_rvalue *get_element(ir_variable *var, int col, int row);
-
- void do_mul_mat_mat(ir_variable *result_var,
- ir_variable *a_var, ir_variable *b_var);
- void do_mul_mat_vec(ir_variable *result_var,
- ir_variable *a_var, ir_variable *b_var);
- void do_mul_vec_mat(ir_variable *result_var,
- ir_variable *a_var, ir_variable *b_var);
- void do_mul_mat_scalar(ir_variable *result_var,
- ir_variable *a_var, ir_variable *b_var);
- void do_equal_mat_mat(ir_variable *result_var, ir_variable *a_var,
- ir_variable *b_var, bool test_equal);
-
- void *mem_ctx;
- bool made_progress;
-};
-
-static bool
-mat_op_to_vec_predicate(ir_instruction *ir)
-{
- ir_expression *expr = ir->as_expression();
- unsigned int i;
-
- if (!expr)
- return false;
-
- for (i = 0; i < expr->get_num_operands(); i++) {
- if (expr->operands[i]->type->is_matrix())
- return true;
- }
-
- return false;
-}
-
-bool
-do_mat_op_to_vec(exec_list *instructions)
-{
- ir_mat_op_to_vec_visitor v;
-
- /* Pull out any matrix expression to a separate assignment to a
- * temp. This will make our handling of the breakdown to
- * operations on the matrix's vector components much easier.
- */
- do_expression_flattening(instructions, mat_op_to_vec_predicate);
-
- visit_list_elements(&v, instructions);
-
- return v.made_progress;
-}
-
-ir_rvalue *
-ir_mat_op_to_vec_visitor::get_element(ir_variable *var, int col, int row)
-{
- ir_dereference *deref;
-
- deref = new(mem_ctx) ir_dereference_variable(var);
-
- if (var->type->is_matrix()) {
- deref = new(mem_ctx) ir_dereference_array(var,
- new(mem_ctx) ir_constant(col));
- } else {
- assert(col == 0);
- }
-
- return new(mem_ctx) ir_swizzle(deref, row, 0, 0, 0, 1);
-}
-
-ir_dereference *
-ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int row)
-{
- ir_dereference *deref;
-
- if (!var->type->is_matrix()) {
- deref = new(mem_ctx) ir_dereference_variable(var);
- } else {
- deref = new(mem_ctx) ir_dereference_variable(var);
- deref = new(mem_ctx) ir_dereference_array(deref,
- new(mem_ctx) ir_constant(row));
- }
-
- return deref;
-}
-
-void
-ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var)
-{
- int b_col, i;
- ir_assignment *assign;
- ir_expression *expr;
-
- for (b_col = 0; b_col < b_var->type->matrix_columns; b_col++) {
- ir_rvalue *a = get_column(a_var, 0);
- ir_rvalue *b = get_element(b_var, b_col, 0);
-
- /* first column */
- expr = new(mem_ctx) ir_expression(ir_binop_mul,
- a->type,
- a,
- b);
-
- /* following columns */
- for (i = 1; i < a_var->type->matrix_columns; i++) {
- ir_expression *mul_expr;
-
- a = get_column(a_var, i);
- b = get_element(b_var, b_col, i);
-
- mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
- a->type,
- a,
- b);
- expr = new(mem_ctx) ir_expression(ir_binop_add,
- a->type,
- expr,
- mul_expr);
- }
-
- ir_rvalue *result = get_column(result_var, b_col);
- assign = new(mem_ctx) ir_assignment(result,
- expr,
- NULL);
- base_ir->insert_before(assign);
- }
-}
-
-void
-ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var)
-{
- int i;
- ir_rvalue *a = get_column(a_var, 0);
- ir_rvalue *b = get_element(b_var, 0, 0);
- ir_assignment *assign;
- ir_expression *expr;
-
- /* first column */
- expr = new(mem_ctx) ir_expression(ir_binop_mul,
- result_var->type,
- a,
- b);
-
- /* following columns */
- for (i = 1; i < a_var->type->matrix_columns; i++) {
- ir_expression *mul_expr;
-
- a = get_column(a_var, i);
- b = get_element(b_var, 0, i);
-
- mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
- result_var->type,
- a,
- b);
- expr = new(mem_ctx) ir_expression(ir_binop_add,
- result_var->type,
- expr,
- mul_expr);
- }
-
- ir_rvalue *result = new(mem_ctx) ir_dereference_variable(result_var);
- assign = new(mem_ctx) ir_assignment(result,
- expr,
- NULL);
- base_ir->insert_before(assign);
-}
-
-void
-ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var)
-{
- int i;
-
- for (i = 0; i < b_var->type->matrix_columns; i++) {
- ir_rvalue *a = new(mem_ctx) ir_dereference_variable(a_var);
- ir_rvalue *b = get_column(b_var, i);
- ir_rvalue *result;
- ir_expression *column_expr;
- ir_assignment *column_assign;
-
- result = new(mem_ctx) ir_dereference_variable(result_var);
- result = new(mem_ctx) ir_swizzle(result, i, 0, 0, 0, 1);
-
- column_expr = new(mem_ctx) ir_expression(ir_binop_dot,
- result->type,
- a,
- b);
-
- column_assign = new(mem_ctx) ir_assignment(result,
- column_expr,
- NULL);
- base_ir->insert_before(column_assign);
- }
-}
-
-void
-ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var)
-{
- int i;
-
- for (i = 0; i < a_var->type->matrix_columns; i++) {
- ir_rvalue *a = get_column(a_var, i);
- ir_rvalue *b = new(mem_ctx) ir_dereference_variable(b_var);
- ir_rvalue *result = get_column(result_var, i);
- ir_expression *column_expr;
- ir_assignment *column_assign;
-
- column_expr = new(mem_ctx) ir_expression(ir_binop_mul,
- result->type,
- a,
- b);
-
- column_assign = new(mem_ctx) ir_assignment(result,
- column_expr,
- NULL);
- base_ir->insert_before(column_assign);
- }
-}
-
-void
-ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var,
- bool test_equal)
-{
- /* This essentially implements the following GLSL:
- *
- * bool equal(mat4 a, mat4 b)
- * {
- * return !any(bvec4(a[0] != b[0],
- * a[1] != b[1],
- * a[2] != b[2],
- * a[3] != b[3]);
- * }
- *
- * bool nequal(mat4 a, mat4 b)
- * {
- * return any(bvec4(a[0] != b[0],
- * a[1] != b[1],
- * a[2] != b[2],
- * a[3] != b[3]);
- * }
- */
- const unsigned columns = a_var->type->matrix_columns;
- const glsl_type *const bvec_type =
- glsl_type::get_instance(GLSL_TYPE_BOOL, columns, 1);
-
- ir_variable *const tmp_bvec =
- new(this->mem_ctx) ir_variable(bvec_type, "mat_cmp_bvec",
- ir_var_temporary);
- this->base_ir->insert_before(tmp_bvec);
-
- for (unsigned i = 0; i < columns; i++) {
- ir_dereference *const op0 = get_column(a_var, i);
- ir_dereference *const op1 = get_column(b_var, i);
-
- ir_expression *const cmp =
- new(this->mem_ctx) ir_expression(ir_binop_any_nequal,
- glsl_type::bool_type, op0, op1);
-
- ir_dereference *const lhs =
- new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
-
- ir_assignment *const assign =
- new(this->mem_ctx) ir_assignment(lhs, cmp, NULL, (1U << i));
-
- this->base_ir->insert_before(assign);
- }
-
- ir_rvalue *const val =
- new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
-
- ir_expression *any =
- new(this->mem_ctx) ir_expression(ir_unop_any, glsl_type::bool_type,
- val, NULL);
-
- if (test_equal)
- any = new(this->mem_ctx) ir_expression(ir_unop_logic_not,
- glsl_type::bool_type,
- any, NULL);
-
- ir_rvalue *const result =
- new(this->mem_ctx) ir_dereference_variable(result_var);
-
- ir_assignment *const assign =
- new(mem_ctx) ir_assignment(result, any, NULL);
- base_ir->insert_before(assign);
-}
-
-static bool
-has_matrix_operand(const ir_expression *expr, unsigned &columns)
-{
- for (unsigned i = 0; i < expr->get_num_operands(); i++) {
- if (expr->operands[i]->type->is_matrix()) {
- columns = expr->operands[i]->type->matrix_columns;
- return true;
- }
- }
-
- return false;
-}
-
-
-ir_visitor_status
-ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign)
-{
- ir_expression *orig_expr = orig_assign->rhs->as_expression();
- unsigned int i, matrix_columns = 1;
- ir_variable *op_var[2];
-
- if (!orig_expr)
- return visit_continue;
-
- if (!has_matrix_operand(orig_expr, matrix_columns))
- return visit_continue;
-
- assert(orig_expr->get_num_operands() <= 2);
-
- mem_ctx = talloc_parent(orig_assign);
-
- ir_dereference_variable *lhs_deref =
- orig_assign->lhs->as_dereference_variable();
- assert(lhs_deref);
-
- ir_variable *result_var = lhs_deref->var;
-
- /* Store the expression operands in temps so we can use them
- * multiple times.
- */
- for (i = 0; i < orig_expr->get_num_operands(); i++) {
- ir_assignment *assign;
-
- op_var[i] = new(mem_ctx) ir_variable(orig_expr->operands[i]->type,
- "mat_op_to_vec",
- ir_var_temporary);
- base_ir->insert_before(op_var[i]);
-
- lhs_deref = new(mem_ctx) ir_dereference_variable(op_var[i]);
- assign = new(mem_ctx) ir_assignment(lhs_deref,
- orig_expr->operands[i],
- NULL);
- base_ir->insert_before(assign);
- }
-
- /* OK, time to break down this matrix operation. */
- switch (orig_expr->operation) {
- case ir_unop_neg: {
- const unsigned mask = (1U << result_var->type->vector_elements) - 1;
-
- /* Apply the operation to each column.*/
- for (i = 0; i < matrix_columns; i++) {
- ir_rvalue *op0 = get_column(op_var[0], i);
- ir_dereference *result = get_column(result_var, i);
- ir_expression *column_expr;
- ir_assignment *column_assign;
-
- column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
- result->type,
- op0,
- NULL);
-
- column_assign = new(mem_ctx) ir_assignment(result,
- column_expr,
- NULL,
- mask);
- assert(column_assign->write_mask != 0);
- base_ir->insert_before(column_assign);
- }
- break;
- }
- case ir_binop_add:
- case ir_binop_sub:
- case ir_binop_div:
- case ir_binop_mod: {
- const unsigned mask = (1U << result_var->type->vector_elements) - 1;
-
- /* For most operations, the matrix version is just going
- * column-wise through and applying the operation to each column
- * if available.
- */
- for (i = 0; i < matrix_columns; i++) {
- ir_rvalue *op0 = get_column(op_var[0], i);
- ir_rvalue *op1 = get_column(op_var[1], i);
- ir_dereference *result = get_column(result_var, i);
- ir_expression *column_expr;
- ir_assignment *column_assign;
-
- column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
- result->type,
- op0,
- op1);
-
- column_assign = new(mem_ctx) ir_assignment(result,
- column_expr,
- NULL,
- mask);
- assert(column_assign->write_mask != 0);
- base_ir->insert_before(column_assign);
- }
- break;
- }
- case ir_binop_mul:
- if (op_var[0]->type->is_matrix()) {
- if (op_var[1]->type->is_matrix()) {
- do_mul_mat_mat(result_var, op_var[0], op_var[1]);
- } else if (op_var[1]->type->is_vector()) {
- do_mul_mat_vec(result_var, op_var[0], op_var[1]);
- } else {
- assert(op_var[1]->type->is_scalar());
- do_mul_mat_scalar(result_var, op_var[0], op_var[1]);
- }
- } else {
- assert(op_var[1]->type->is_matrix());
- if (op_var[0]->type->is_vector()) {
- do_mul_vec_mat(result_var, op_var[0], op_var[1]);
- } else {
- assert(op_var[0]->type->is_scalar());
- do_mul_mat_scalar(result_var, op_var[1], op_var[0]);
- }
- }
- break;
-
- case ir_binop_all_equal:
- case ir_binop_any_nequal:
- do_equal_mat_mat(result_var, op_var[1], op_var[0],
- (orig_expr->operation == ir_binop_all_equal));
- break;
-
- default:
- printf("FINISHME: Handle matrix operation for %s\n",
- orig_expr->operator_string());
- abort();
- }
- orig_assign->remove();
- this->made_progress = true;
-
- return visit_continue;
-}
+/*
+ * 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 lower_mat_op_to_vec.cpp
+ *
+ * Breaks matrix operation expressions down to a series of vector operations.
+ *
+ * Generally this is how we have to codegen matrix operations for a
+ * GPU, so this gives us the chance to constant fold operations on a
+ * column or row.
+ */
+
+#include "ir.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+
+class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor {
+public:
+ ir_mat_op_to_vec_visitor()
+ {
+ this->made_progress = false;
+ this->mem_ctx = NULL;
+ }
+
+ ir_visitor_status visit_leave(ir_assignment *);
+
+ ir_dereference *get_column(ir_variable *var, int col);
+ ir_rvalue *get_element(ir_variable *var, int col, int row);
+
+ void do_mul_mat_mat(ir_variable *result_var,
+ ir_variable *a_var, ir_variable *b_var);
+ void do_mul_mat_vec(ir_variable *result_var,
+ ir_variable *a_var, ir_variable *b_var);
+ void do_mul_vec_mat(ir_variable *result_var,
+ ir_variable *a_var, ir_variable *b_var);
+ void do_mul_mat_scalar(ir_variable *result_var,
+ ir_variable *a_var, ir_variable *b_var);
+ void do_equal_mat_mat(ir_variable *result_var, ir_variable *a_var,
+ ir_variable *b_var, bool test_equal);
+
+ void *mem_ctx;
+ bool made_progress;
+};
+
+static bool
+mat_op_to_vec_predicate(ir_instruction *ir)
+{
+ ir_expression *expr = ir->as_expression();
+ unsigned int i;
+
+ if (!expr)
+ return false;
+
+ for (i = 0; i < expr->get_num_operands(); i++) {
+ if (expr->operands[i]->type->is_matrix())
+ return true;
+ }
+
+ return false;
+}
+
+bool
+do_mat_op_to_vec(exec_list *instructions)
+{
+ ir_mat_op_to_vec_visitor v;
+
+ /* Pull out any matrix expression to a separate assignment to a
+ * temp. This will make our handling of the breakdown to
+ * operations on the matrix's vector components much easier.
+ */
+ do_expression_flattening(instructions, mat_op_to_vec_predicate);
+
+ visit_list_elements(&v, instructions);
+
+ return v.made_progress;
+}
+
+ir_rvalue *
+ir_mat_op_to_vec_visitor::get_element(ir_variable *var, int col, int row)
+{
+ ir_dereference *deref;
+
+ deref = new(mem_ctx) ir_dereference_variable(var);
+
+ if (var->type->is_matrix()) {
+ deref = new(mem_ctx) ir_dereference_array(var,
+ new(mem_ctx) ir_constant(col));
+ } else {
+ assert(col == 0);
+ }
+
+ return new(mem_ctx) ir_swizzle(deref, row, 0, 0, 0, 1);
+}
+
+ir_dereference *
+ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int row)
+{
+ ir_dereference *deref;
+
+ if (!var->type->is_matrix()) {
+ deref = new(mem_ctx) ir_dereference_variable(var);
+ } else {
+ deref = new(mem_ctx) ir_dereference_variable(var);
+ deref = new(mem_ctx) ir_dereference_array(deref,
+ new(mem_ctx) ir_constant(row));
+ }
+
+ return deref;
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable *result_var,
+ ir_variable *a_var,
+ ir_variable *b_var)
+{
+ int b_col, i;
+ ir_assignment *assign;
+ ir_expression *expr;
+
+ for (b_col = 0; b_col < b_var->type->matrix_columns; b_col++) {
+ ir_rvalue *a = get_column(a_var, 0);
+ ir_rvalue *b = get_element(b_var, b_col, 0);
+
+ /* first column */
+ expr = new(mem_ctx) ir_expression(ir_binop_mul,
+ a->type,
+ a,
+ b);
+
+ /* following columns */
+ for (i = 1; i < a_var->type->matrix_columns; i++) {
+ ir_expression *mul_expr;
+
+ a = get_column(a_var, i);
+ b = get_element(b_var, b_col, i);
+
+ mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
+ a->type,
+ a,
+ b);
+ expr = new(mem_ctx) ir_expression(ir_binop_add,
+ a->type,
+ expr,
+ mul_expr);
+ }
+
+ ir_rvalue *result = get_column(result_var, b_col);
+ assign = new(mem_ctx) ir_assignment(result,
+ expr,
+ NULL);
+ base_ir->insert_before(assign);
+ }
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable *result_var,
+ ir_variable *a_var,
+ ir_variable *b_var)
+{
+ int i;
+ ir_rvalue *a = get_column(a_var, 0);
+ ir_rvalue *b = get_element(b_var, 0, 0);
+ ir_assignment *assign;
+ ir_expression *expr;
+
+ /* first column */
+ expr = new(mem_ctx) ir_expression(ir_binop_mul,
+ result_var->type,
+ a,
+ b);
+
+ /* following columns */
+ for (i = 1; i < a_var->type->matrix_columns; i++) {
+ ir_expression *mul_expr;
+
+ a = get_column(a_var, i);
+ b = get_element(b_var, 0, i);
+
+ mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
+ result_var->type,
+ a,
+ b);
+ expr = new(mem_ctx) ir_expression(ir_binop_add,
+ result_var->type,
+ expr,
+ mul_expr);
+ }
+
+ ir_rvalue *result = new(mem_ctx) ir_dereference_variable(result_var);
+ assign = new(mem_ctx) ir_assignment(result,
+ expr,
+ NULL);
+ base_ir->insert_before(assign);
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable *result_var,
+ ir_variable *a_var,
+ ir_variable *b_var)
+{
+ int i;
+
+ for (i = 0; i < b_var->type->matrix_columns; i++) {
+ ir_rvalue *a = new(mem_ctx) ir_dereference_variable(a_var);
+ ir_rvalue *b = get_column(b_var, i);
+ ir_rvalue *result;
+ ir_expression *column_expr;
+ ir_assignment *column_assign;
+
+ result = new(mem_ctx) ir_dereference_variable(result_var);
+ result = new(mem_ctx) ir_swizzle(result, i, 0, 0, 0, 1);
+
+ column_expr = new(mem_ctx) ir_expression(ir_binop_dot,
+ result->type,
+ a,
+ b);
+
+ column_assign = new(mem_ctx) ir_assignment(result,
+ column_expr,
+ NULL);
+ base_ir->insert_before(column_assign);
+ }
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable *result_var,
+ ir_variable *a_var,
+ ir_variable *b_var)
+{
+ int i;
+
+ for (i = 0; i < a_var->type->matrix_columns; i++) {
+ ir_rvalue *a = get_column(a_var, i);
+ ir_rvalue *b = new(mem_ctx) ir_dereference_variable(b_var);
+ ir_rvalue *result = get_column(result_var, i);
+ ir_expression *column_expr;
+ ir_assignment *column_assign;
+
+ column_expr = new(mem_ctx) ir_expression(ir_binop_mul,
+ result->type,
+ a,
+ b);
+
+ column_assign = new(mem_ctx) ir_assignment(result,
+ column_expr,
+ NULL);
+ base_ir->insert_before(column_assign);
+ }
+}
+
+void
+ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_variable *result_var,
+ ir_variable *a_var,
+ ir_variable *b_var,
+ bool test_equal)
+{
+ /* This essentially implements the following GLSL:
+ *
+ * bool equal(mat4 a, mat4 b)
+ * {
+ * return !any(bvec4(a[0] != b[0],
+ * a[1] != b[1],
+ * a[2] != b[2],
+ * a[3] != b[3]);
+ * }
+ *
+ * bool nequal(mat4 a, mat4 b)
+ * {
+ * return any(bvec4(a[0] != b[0],
+ * a[1] != b[1],
+ * a[2] != b[2],
+ * a[3] != b[3]);
+ * }
+ */
+ const unsigned columns = a_var->type->matrix_columns;
+ const glsl_type *const bvec_type =
+ glsl_type::get_instance(GLSL_TYPE_BOOL, columns, 1);
+
+ ir_variable *const tmp_bvec =
+ new(this->mem_ctx) ir_variable(bvec_type, "mat_cmp_bvec",
+ ir_var_temporary);
+ this->base_ir->insert_before(tmp_bvec);
+
+ for (unsigned i = 0; i < columns; i++) {
+ ir_dereference *const op0 = get_column(a_var, i);
+ ir_dereference *const op1 = get_column(b_var, i);
+
+ ir_expression *const cmp =
+ new(this->mem_ctx) ir_expression(ir_binop_any_nequal,
+ glsl_type::bool_type, op0, op1);
+
+ ir_dereference *const lhs =
+ new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
+
+ ir_assignment *const assign =
+ new(this->mem_ctx) ir_assignment(lhs, cmp, NULL, (1U << i));
+
+ this->base_ir->insert_before(assign);
+ }
+
+ ir_rvalue *const val =
+ new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
+
+ ir_expression *any =
+ new(this->mem_ctx) ir_expression(ir_unop_any, glsl_type::bool_type,
+ val, NULL);
+
+ if (test_equal)
+ any = new(this->mem_ctx) ir_expression(ir_unop_logic_not,
+ glsl_type::bool_type,
+ any, NULL);
+
+ ir_rvalue *const result =
+ new(this->mem_ctx) ir_dereference_variable(result_var);
+
+ ir_assignment *const assign =
+ new(mem_ctx) ir_assignment(result, any, NULL);
+ base_ir->insert_before(assign);
+}
+
+static bool
+has_matrix_operand(const ir_expression *expr, unsigned &columns)
+{
+ for (unsigned i = 0; i < expr->get_num_operands(); i++) {
+ if (expr->operands[i]->type->is_matrix()) {
+ columns = expr->operands[i]->type->matrix_columns;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+ir_visitor_status
+ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign)
+{
+ ir_expression *orig_expr = orig_assign->rhs->as_expression();
+ unsigned int i, matrix_columns = 1;
+ ir_variable *op_var[2];
+
+ if (!orig_expr)
+ return visit_continue;
+
+ if (!has_matrix_operand(orig_expr, matrix_columns))
+ return visit_continue;
+
+ assert(orig_expr->get_num_operands() <= 2);
+
+ mem_ctx = ralloc_parent(orig_assign);
+
+ ir_dereference_variable *lhs_deref =
+ orig_assign->lhs->as_dereference_variable();
+ assert(lhs_deref);
+
+ ir_variable *result_var = lhs_deref->var;
+
+ /* Store the expression operands in temps so we can use them
+ * multiple times.
+ */
+ for (i = 0; i < orig_expr->get_num_operands(); i++) {
+ ir_assignment *assign;
+
+ op_var[i] = new(mem_ctx) ir_variable(orig_expr->operands[i]->type,
+ "mat_op_to_vec",
+ ir_var_temporary);
+ base_ir->insert_before(op_var[i]);
+
+ lhs_deref = new(mem_ctx) ir_dereference_variable(op_var[i]);
+ assign = new(mem_ctx) ir_assignment(lhs_deref,
+ orig_expr->operands[i],
+ NULL);
+ base_ir->insert_before(assign);
+ }
+
+ /* OK, time to break down this matrix operation. */
+ switch (orig_expr->operation) {
+ case ir_unop_neg: {
+ const unsigned mask = (1U << result_var->type->vector_elements) - 1;
+
+ /* Apply the operation to each column.*/
+ for (i = 0; i < matrix_columns; i++) {
+ ir_rvalue *op0 = get_column(op_var[0], i);
+ ir_dereference *result = get_column(result_var, i);
+ ir_expression *column_expr;
+ ir_assignment *column_assign;
+
+ column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
+ result->type,
+ op0,
+ NULL);
+
+ column_assign = new(mem_ctx) ir_assignment(result,
+ column_expr,
+ NULL,
+ mask);
+ assert(column_assign->write_mask != 0);
+ base_ir->insert_before(column_assign);
+ }
+ break;
+ }
+ case ir_binop_add:
+ case ir_binop_sub:
+ case ir_binop_div:
+ case ir_binop_mod: {
+ const unsigned mask = (1U << result_var->type->vector_elements) - 1;
+
+ /* For most operations, the matrix version is just going
+ * column-wise through and applying the operation to each column
+ * if available.
+ */
+ for (i = 0; i < matrix_columns; i++) {
+ ir_rvalue *op0 = get_column(op_var[0], i);
+ ir_rvalue *op1 = get_column(op_var[1], i);
+ ir_dereference *result = get_column(result_var, i);
+ ir_expression *column_expr;
+ ir_assignment *column_assign;
+
+ column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
+ result->type,
+ op0,
+ op1);
+
+ column_assign = new(mem_ctx) ir_assignment(result,
+ column_expr,
+ NULL,
+ mask);
+ assert(column_assign->write_mask != 0);
+ base_ir->insert_before(column_assign);
+ }
+ break;
+ }
+ case ir_binop_mul:
+ if (op_var[0]->type->is_matrix()) {
+ if (op_var[1]->type->is_matrix()) {
+ do_mul_mat_mat(result_var, op_var[0], op_var[1]);
+ } else if (op_var[1]->type->is_vector()) {
+ do_mul_mat_vec(result_var, op_var[0], op_var[1]);
+ } else {
+ assert(op_var[1]->type->is_scalar());
+ do_mul_mat_scalar(result_var, op_var[0], op_var[1]);
+ }
+ } else {
+ assert(op_var[1]->type->is_matrix());
+ if (op_var[0]->type->is_vector()) {
+ do_mul_vec_mat(result_var, op_var[0], op_var[1]);
+ } else {
+ assert(op_var[0]->type->is_scalar());
+ do_mul_mat_scalar(result_var, op_var[1], op_var[0]);
+ }
+ }
+ break;
+
+ case ir_binop_all_equal:
+ case ir_binop_any_nequal:
+ do_equal_mat_mat(result_var, op_var[1], op_var[0],
+ (orig_expr->operation == ir_binop_all_equal));
+ break;
+
+ default:
+ printf("FINISHME: Handle matrix operation for %s\n",
+ orig_expr->operator_string());
+ abort();
+ }
+ orig_assign->remove();
+ this->made_progress = true;
+
+ return visit_continue;
+}
diff --git a/mesalib/src/glsl/lower_noise.cpp b/mesalib/src/glsl/lower_noise.cpp
index cb32d2834..85f59b675 100644
--- a/mesalib/src/glsl/lower_noise.cpp
+++ b/mesalib/src/glsl/lower_noise.cpp
@@ -51,7 +51,7 @@ public:
* that implements noise. No hardware has a noise instruction.
*/
if (expr->operation == ir_unop_noise) {
- *rvalue = ir_constant::zero(talloc_parent(expr), expr->type);
+ *rvalue = ir_constant::zero(ralloc_parent(expr), expr->type);
this->progress = true;
}
}
diff --git a/mesalib/src/glsl/lower_texture_projection.cpp b/mesalib/src/glsl/lower_texture_projection.cpp
index 7d4f647e9..6e3aaecce 100644
--- a/mesalib/src/glsl/lower_texture_projection.cpp
+++ b/mesalib/src/glsl/lower_texture_projection.cpp
@@ -1,99 +1,99 @@
-/*
- * 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 lower_texture_projection.cpp
- *
- * IR lower pass to perform the division of texture coordinates by the texture
- * projector if present.
- *
- * Many GPUs have a texture sampling opcode that takes the projector
- * and does the divide internally, thus the presence of the projector
- * in the IR. For GPUs that don't, this saves the driver needing the
- * logic for handling the divide.
- *
- * \author Eric Anholt <eric@anholt.net>
- */
-
-#include "ir.h"
-
-class lower_texture_projection_visitor : public ir_hierarchical_visitor {
-public:
- lower_texture_projection_visitor()
- {
- progress = false;
- }
-
- ir_visitor_status visit_leave(ir_texture *ir);
-
- bool progress;
-};
-
-ir_visitor_status
-lower_texture_projection_visitor::visit_leave(ir_texture *ir)
-{
- if (!ir->projector)
- return visit_continue;
-
- void *mem_ctx = talloc_parent(ir);
-
- ir_variable *var = new(mem_ctx) ir_variable(ir->projector->type,
- "projector", ir_var_auto);
- base_ir->insert_before(var);
- ir_dereference *deref = new(mem_ctx) ir_dereference_variable(var);
- ir_expression *expr = new(mem_ctx) ir_expression(ir_unop_rcp,
- ir->projector->type,
- ir->projector,
- NULL);
- ir_assignment *assign = new(mem_ctx) ir_assignment(deref, expr, NULL);
- base_ir->insert_before(assign);
-
- deref = new(mem_ctx) ir_dereference_variable(var);
- ir->coordinate = new(mem_ctx) ir_expression(ir_binop_mul,
- ir->coordinate->type,
- ir->coordinate,
- deref);
-
- if (ir->shadow_comparitor) {
- deref = new(mem_ctx) ir_dereference_variable(var);
- ir->shadow_comparitor = new(mem_ctx) ir_expression(ir_binop_mul,
- ir->shadow_comparitor->type,
- ir->shadow_comparitor,
- deref);
- }
-
- ir->projector = NULL;
-
- progress = true;
- return visit_continue;
-}
-
-bool
-do_lower_texture_projection(exec_list *instructions)
-{
- lower_texture_projection_visitor v;
-
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
+/*
+ * 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 lower_texture_projection.cpp
+ *
+ * IR lower pass to perform the division of texture coordinates by the texture
+ * projector if present.
+ *
+ * Many GPUs have a texture sampling opcode that takes the projector
+ * and does the divide internally, thus the presence of the projector
+ * in the IR. For GPUs that don't, this saves the driver needing the
+ * logic for handling the divide.
+ *
+ * \author Eric Anholt <eric@anholt.net>
+ */
+
+#include "ir.h"
+
+class lower_texture_projection_visitor : public ir_hierarchical_visitor {
+public:
+ lower_texture_projection_visitor()
+ {
+ progress = false;
+ }
+
+ ir_visitor_status visit_leave(ir_texture *ir);
+
+ bool progress;
+};
+
+ir_visitor_status
+lower_texture_projection_visitor::visit_leave(ir_texture *ir)
+{
+ if (!ir->projector)
+ return visit_continue;
+
+ void *mem_ctx = ralloc_parent(ir);
+
+ ir_variable *var = new(mem_ctx) ir_variable(ir->projector->type,
+ "projector", ir_var_auto);
+ base_ir->insert_before(var);
+ ir_dereference *deref = new(mem_ctx) ir_dereference_variable(var);
+ ir_expression *expr = new(mem_ctx) ir_expression(ir_unop_rcp,
+ ir->projector->type,
+ ir->projector,
+ NULL);
+ ir_assignment *assign = new(mem_ctx) ir_assignment(deref, expr, NULL);
+ base_ir->insert_before(assign);
+
+ deref = new(mem_ctx) ir_dereference_variable(var);
+ ir->coordinate = new(mem_ctx) ir_expression(ir_binop_mul,
+ ir->coordinate->type,
+ ir->coordinate,
+ deref);
+
+ if (ir->shadow_comparitor) {
+ deref = new(mem_ctx) ir_dereference_variable(var);
+ ir->shadow_comparitor = new(mem_ctx) ir_expression(ir_binop_mul,
+ ir->shadow_comparitor->type,
+ ir->shadow_comparitor,
+ deref);
+ }
+
+ ir->projector = NULL;
+
+ progress = true;
+ return visit_continue;
+}
+
+bool
+do_lower_texture_projection(exec_list *instructions)
+{
+ lower_texture_projection_visitor v;
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp b/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp
index faff760ea..8eb1612f0 100644
--- a/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp
+++ b/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp
@@ -1,382 +1,383 @@
-/*
- * Copyright © 2010 Luca Barbieri
- *
- * 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 lower_variable_index_to_cond_assign.cpp
- *
- * Turns non-constant indexing into array types to a series of
- * conditional moves of each element into a temporary.
- *
- * Pre-DX10 GPUs often don't have a native way to do this operation,
- * and this works around that.
- */
-
-#include "ir.h"
-#include "ir_rvalue_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-#include "main/macros.h"
-
-struct assignment_generator
-{
- ir_instruction* base_ir;
- ir_rvalue* array;
- bool is_write;
- unsigned int write_mask;
- ir_variable* var;
-
- assignment_generator()
- {
- }
-
- void generate(unsigned i, ir_rvalue* condition, exec_list *list) const
- {
- /* Just clone the rest of the deref chain when trying to get at the
- * underlying variable.
- */
- void *mem_ctx = talloc_parent(base_ir);
- ir_dereference *element =
- new(mem_ctx) ir_dereference_array(this->array->clone(mem_ctx, NULL),
- new(mem_ctx) ir_constant(i));
- ir_rvalue *variable = new(mem_ctx) ir_dereference_variable(this->var);
-
- ir_assignment *assignment;
- if (is_write) {
- assignment = new(mem_ctx) ir_assignment(element, variable, condition,
- write_mask);
- } else {
- assignment = new(mem_ctx) ir_assignment(variable, element, condition);
- }
-
- list->push_tail(assignment);
- }
-};
-
-struct switch_generator
-{
- /* make TFunction a template parameter if you need to use other generators */
- typedef assignment_generator TFunction;
- const TFunction& generator;
-
- ir_variable* index;
- unsigned linear_sequence_max_length;
- unsigned condition_components;
-
- void *mem_ctx;
-
- switch_generator(const TFunction& generator, ir_variable *index,
- unsigned linear_sequence_max_length,
- unsigned condition_components)
- : generator(generator), index(index),
- linear_sequence_max_length(linear_sequence_max_length),
- condition_components(condition_components)
- {
- this->mem_ctx = talloc_parent(index);
- }
-
- void linear_sequence(unsigned begin, unsigned end, exec_list *list)
- {
- if (begin == end)
- return;
-
- /* If the array access is a read, read the first element of this subregion
- * unconditionally. The remaining tests will possibly overwrite this
- * value with one of the other array elements.
- *
- * This optimization cannot be done for writes because it will cause the
- * first element of the subregion to be written possibly *in addition* to
- * one of the other elements.
- */
- unsigned first;
- if (!this->generator.is_write) {
- this->generator.generate(begin, 0, list);
- first = begin + 1;
- } else {
- first = begin;
- }
-
- for (unsigned i = first; i < end; i += 4) {
- const unsigned comps = MIN2(condition_components, end - i);
-
- ir_rvalue *broadcast_index =
- new(this->mem_ctx) ir_dereference_variable(index);
-
- if (comps) {
- const ir_swizzle_mask m = { 0, 0, 0, 0, comps, false };
- broadcast_index = new(this->mem_ctx) ir_swizzle(broadcast_index, m);
- }
-
- /* Compare the desired index value with the next block of four indices.
- */
- ir_constant_data test_indices_data;
- memset(&test_indices_data, 0, sizeof(test_indices_data));
- test_indices_data.i[0] = i;
- test_indices_data.i[1] = i + 1;
- test_indices_data.i[2] = i + 2;
- test_indices_data.i[3] = i + 3;
- ir_constant *const test_indices =
- new(this->mem_ctx) ir_constant(broadcast_index->type,
- &test_indices_data);
-
- ir_rvalue *const condition_val =
- new(this->mem_ctx) ir_expression(ir_binop_equal,
- &glsl_type::bool_type[comps - 1],
- broadcast_index,
- test_indices);
-
- ir_variable *const condition =
- new(this->mem_ctx) ir_variable(condition_val->type,
- "dereference_array_condition",
- ir_var_temporary);
- list->push_tail(condition);
-
- ir_rvalue *const cond_deref =
- new(this->mem_ctx) ir_dereference_variable(condition);
- list->push_tail(new(this->mem_ctx) ir_assignment(cond_deref,
- condition_val, 0));
-
- if (comps == 1) {
- ir_rvalue *const cond_deref =
- new(this->mem_ctx) ir_dereference_variable(condition);
-
- this->generator.generate(i, cond_deref, list);
- } else {
- for (unsigned j = 0; j < comps; j++) {
- ir_rvalue *const cond_deref =
- new(this->mem_ctx) ir_dereference_variable(condition);
- ir_rvalue *const cond_swiz =
- new(this->mem_ctx) ir_swizzle(cond_deref, j, 0, 0, 0, 1);
-
- this->generator.generate(i + j, cond_swiz, list);
- }
- }
- }
- }
-
- void bisect(unsigned begin, unsigned end, exec_list *list)
- {
- unsigned middle = (begin + end) >> 1;
-
- assert(index->type->is_integer());
-
- ir_constant *const middle_c = (index->type->base_type == GLSL_TYPE_UINT)
- ? new(this->mem_ctx) ir_constant((unsigned)middle)
- : new(this->mem_ctx) ir_constant((int)middle);
-
-
- ir_dereference_variable *deref =
- new(this->mem_ctx) ir_dereference_variable(this->index);
-
- ir_expression *less =
- new(this->mem_ctx) ir_expression(ir_binop_less, glsl_type::bool_type,
- deref, middle_c);
-
- ir_if *if_less = new(this->mem_ctx) ir_if(less);
-
- generate(begin, middle, &if_less->then_instructions);
- generate(middle, end, &if_less->else_instructions);
-
- list->push_tail(if_less);
- }
-
- void generate(unsigned begin, unsigned end, exec_list *list)
- {
- unsigned length = end - begin;
- if (length <= this->linear_sequence_max_length)
- return linear_sequence(begin, end, list);
- else
- return bisect(begin, end, list);
- }
-};
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class variable_index_to_cond_assign_visitor : public ir_rvalue_visitor {
-public:
- variable_index_to_cond_assign_visitor(bool lower_input,
- bool lower_output,
- bool lower_temp,
- bool lower_uniform)
- {
- this->progress = false;
- this->lower_inputs = lower_input;
- this->lower_outputs = lower_output;
- this->lower_temps = lower_temp;
- this->lower_uniforms = lower_uniform;
- }
-
- bool progress;
- bool lower_inputs;
- bool lower_outputs;
- bool lower_temps;
- bool lower_uniforms;
-
- bool is_array_or_matrix(const ir_instruction *ir) const
- {
- return (ir->type->is_array() || ir->type->is_matrix());
- }
-
- bool needs_lowering(ir_dereference_array *deref) const
- {
- if (deref == NULL || deref->array_index->as_constant()
- || !is_array_or_matrix(deref->array))
- return false;
-
- if (deref->array->ir_type == ir_type_constant)
- return this->lower_temps;
-
- const ir_variable *const var = deref->array->variable_referenced();
- switch (var->mode) {
- case ir_var_auto:
- case ir_var_temporary:
- return this->lower_temps;
- case ir_var_uniform:
- return this->lower_uniforms;
- case ir_var_in:
- return (var->location == -1) ? this->lower_temps : this->lower_inputs;
- case ir_var_out:
- return (var->location == -1) ? this->lower_temps : this->lower_outputs;
- case ir_var_inout:
- return this->lower_temps;
- }
-
- assert(!"Should not get here.");
- return false;
- }
-
- ir_variable *convert_dereference_array(ir_dereference_array *orig_deref,
- ir_assignment* orig_assign)
- {
- assert(is_array_or_matrix(orig_deref->array));
-
- const unsigned length = (orig_deref->array->type->is_array())
- ? orig_deref->array->type->length
- : orig_deref->array->type->matrix_columns;
-
- void *const mem_ctx = talloc_parent(base_ir);
-
- /* Temporary storage for either the result of the dereference of
- * the array, or the RHS that's being assigned into the
- * dereference of the array.
- */
- ir_variable *var;
-
- if (orig_assign) {
- var = new(mem_ctx) ir_variable(orig_assign->rhs->type,
- "dereference_array_value",
- ir_var_temporary);
- base_ir->insert_before(var);
-
- ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(var);
- ir_assignment *assign = new(mem_ctx) ir_assignment(lhs,
- orig_assign->rhs,
- NULL);
-
- base_ir->insert_before(assign);
- } else {
- var = new(mem_ctx) ir_variable(orig_deref->type,
- "dereference_array_value",
- ir_var_temporary);
- base_ir->insert_before(var);
- }
-
- /* Store the index to a temporary to avoid reusing its tree. */
- ir_variable *index =
- new(mem_ctx) ir_variable(orig_deref->array_index->type,
- "dereference_array_index", ir_var_temporary);
- base_ir->insert_before(index);
-
- ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(index);
- ir_assignment *assign =
- new(mem_ctx) ir_assignment(lhs, orig_deref->array_index, NULL);
- base_ir->insert_before(assign);
-
- assignment_generator ag;
- ag.array = orig_deref->array;
- ag.base_ir = base_ir;
- ag.var = var;
- if (orig_assign) {
- ag.is_write = true;
- ag.write_mask = orig_assign->write_mask;
- } else {
- ag.is_write = false;
- }
-
- switch_generator sg(ag, index, 4, 4);
-
- exec_list list;
- sg.generate(0, length, &list);
- base_ir->insert_before(&list);
-
- return var;
- }
-
- virtual void handle_rvalue(ir_rvalue **pir)
- {
- if (!*pir)
- return;
-
- ir_dereference_array* orig_deref = (*pir)->as_dereference_array();
- if (needs_lowering(orig_deref)) {
- ir_variable* var = convert_dereference_array(orig_deref, 0);
- assert(var);
- *pir = new(talloc_parent(base_ir)) ir_dereference_variable(var);
- this->progress = true;
- }
- }
-
- ir_visitor_status
- visit_leave(ir_assignment *ir)
- {
- ir_rvalue_visitor::visit_leave(ir);
-
- ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
-
- if (needs_lowering(orig_deref)) {
- convert_dereference_array(orig_deref, ir);
- ir->remove();
- this->progress = true;
- }
-
- return visit_continue;
- }
-};
-
-bool
-lower_variable_index_to_cond_assign(exec_list *instructions,
- bool lower_input,
- bool lower_output,
- bool lower_temp,
- bool lower_uniform)
-{
- variable_index_to_cond_assign_visitor v(lower_input,
- lower_output,
- lower_temp,
- lower_uniform);
-
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
+/*
+ * Copyright © 2010 Luca Barbieri
+ *
+ * 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 lower_variable_index_to_cond_assign.cpp
+ *
+ * Turns non-constant indexing into array types to a series of
+ * conditional moves of each element into a temporary.
+ *
+ * Pre-DX10 GPUs often don't have a native way to do this operation,
+ * and this works around that.
+ */
+
+#include "ir.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+#include "main/macros.h"
+
+struct assignment_generator
+{
+ ir_instruction* base_ir;
+ ir_rvalue* array;
+ bool is_write;
+ unsigned int write_mask;
+ ir_variable* var;
+
+ assignment_generator()
+ {
+ }
+
+ void generate(unsigned i, ir_rvalue* condition, exec_list *list) const
+ {
+ /* Just clone the rest of the deref chain when trying to get at the
+ * underlying variable.
+ */
+ void *mem_ctx = ralloc_parent(base_ir);
+ ir_dereference *element =
+ new(mem_ctx) ir_dereference_array(this->array->clone(mem_ctx, NULL),
+ new(mem_ctx) ir_constant(i));
+ ir_rvalue *variable = new(mem_ctx) ir_dereference_variable(this->var);
+
+ ir_assignment *assignment;
+ if (is_write) {
+ assignment = new(mem_ctx) ir_assignment(element, variable, condition,
+ write_mask);
+ } else {
+ assignment = new(mem_ctx) ir_assignment(variable, element, condition);
+ }
+
+ list->push_tail(assignment);
+ }
+};
+
+struct switch_generator
+{
+ /* make TFunction a template parameter if you need to use other generators */
+ typedef assignment_generator TFunction;
+ const TFunction& generator;
+
+ ir_variable* index;
+ unsigned linear_sequence_max_length;
+ unsigned condition_components;
+
+ void *mem_ctx;
+
+ switch_generator(const TFunction& generator, ir_variable *index,
+ unsigned linear_sequence_max_length,
+ unsigned condition_components)
+ : generator(generator), index(index),
+ linear_sequence_max_length(linear_sequence_max_length),
+ condition_components(condition_components)
+ {
+ this->mem_ctx = ralloc_parent(index);
+ }
+
+ void linear_sequence(unsigned begin, unsigned end, exec_list *list)
+ {
+ if (begin == end)
+ return;
+
+ /* If the array access is a read, read the first element of this subregion
+ * unconditionally. The remaining tests will possibly overwrite this
+ * value with one of the other array elements.
+ *
+ * This optimization cannot be done for writes because it will cause the
+ * first element of the subregion to be written possibly *in addition* to
+ * one of the other elements.
+ */
+ unsigned first;
+ if (!this->generator.is_write) {
+ this->generator.generate(begin, 0, list);
+ first = begin + 1;
+ } else {
+ first = begin;
+ }
+
+ for (unsigned i = first; i < end; i += 4) {
+ const unsigned comps = MIN2(condition_components, end - i);
+
+ ir_rvalue *broadcast_index =
+ new(this->mem_ctx) ir_dereference_variable(index);
+
+ if (comps) {
+ const ir_swizzle_mask m = { 0, 0, 0, 0, comps, false };
+ broadcast_index = new(this->mem_ctx) ir_swizzle(broadcast_index, m);
+ }
+
+ /* Compare the desired index value with the next block of four indices.
+ */
+ ir_constant_data test_indices_data;
+ memset(&test_indices_data, 0, sizeof(test_indices_data));
+ test_indices_data.i[0] = i;
+ test_indices_data.i[1] = i + 1;
+ test_indices_data.i[2] = i + 2;
+ test_indices_data.i[3] = i + 3;
+ ir_constant *const test_indices =
+ new(this->mem_ctx) ir_constant(broadcast_index->type,
+ &test_indices_data);
+
+ ir_rvalue *const condition_val =
+ new(this->mem_ctx) ir_expression(ir_binop_equal,
+ &glsl_type::bool_type[comps - 1],
+ broadcast_index,
+ test_indices);
+
+ ir_variable *const condition =
+ new(this->mem_ctx) ir_variable(condition_val->type,
+ "dereference_array_condition",
+ ir_var_temporary);
+ list->push_tail(condition);
+
+ ir_rvalue *const cond_deref =
+ new(this->mem_ctx) ir_dereference_variable(condition);
+ list->push_tail(new(this->mem_ctx) ir_assignment(cond_deref,
+ condition_val, 0));
+
+ if (comps == 1) {
+ ir_rvalue *const cond_deref =
+ new(this->mem_ctx) ir_dereference_variable(condition);
+
+ this->generator.generate(i, cond_deref, list);
+ } else {
+ for (unsigned j = 0; j < comps; j++) {
+ ir_rvalue *const cond_deref =
+ new(this->mem_ctx) ir_dereference_variable(condition);
+ ir_rvalue *const cond_swiz =
+ new(this->mem_ctx) ir_swizzle(cond_deref, j, 0, 0, 0, 1);
+
+ this->generator.generate(i + j, cond_swiz, list);
+ }
+ }
+ }
+ }
+
+ void bisect(unsigned begin, unsigned end, exec_list *list)
+ {
+ unsigned middle = (begin + end) >> 1;
+
+ assert(index->type->is_integer());
+
+ ir_constant *const middle_c = (index->type->base_type == GLSL_TYPE_UINT)
+ ? new(this->mem_ctx) ir_constant((unsigned)middle)
+ : new(this->mem_ctx) ir_constant((int)middle);
+
+
+ ir_dereference_variable *deref =
+ new(this->mem_ctx) ir_dereference_variable(this->index);
+
+ ir_expression *less =
+ new(this->mem_ctx) ir_expression(ir_binop_less, glsl_type::bool_type,
+ deref, middle_c);
+
+ ir_if *if_less = new(this->mem_ctx) ir_if(less);
+
+ generate(begin, middle, &if_less->then_instructions);
+ generate(middle, end, &if_less->else_instructions);
+
+ list->push_tail(if_less);
+ }
+
+ void generate(unsigned begin, unsigned end, exec_list *list)
+ {
+ unsigned length = end - begin;
+ if (length <= this->linear_sequence_max_length)
+ return linear_sequence(begin, end, list);
+ else
+ return bisect(begin, end, list);
+ }
+};
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class variable_index_to_cond_assign_visitor : public ir_rvalue_visitor {
+public:
+ variable_index_to_cond_assign_visitor(bool lower_input,
+ bool lower_output,
+ bool lower_temp,
+ bool lower_uniform)
+ {
+ this->progress = false;
+ this->lower_inputs = lower_input;
+ this->lower_outputs = lower_output;
+ this->lower_temps = lower_temp;
+ this->lower_uniforms = lower_uniform;
+ }
+
+ bool progress;
+ bool lower_inputs;
+ bool lower_outputs;
+ bool lower_temps;
+ bool lower_uniforms;
+
+ bool is_array_or_matrix(const ir_instruction *ir) const
+ {
+ return (ir->type->is_array() || ir->type->is_matrix());
+ }
+
+ bool needs_lowering(ir_dereference_array *deref) const
+ {
+ if (deref == NULL || deref->array_index->as_constant()
+ || !is_array_or_matrix(deref->array))
+ return false;
+
+ if (deref->array->ir_type == ir_type_constant)
+ return this->lower_temps;
+
+ const ir_variable *const var = deref->array->variable_referenced();
+ switch (var->mode) {
+ case ir_var_auto:
+ case ir_var_temporary:
+ return this->lower_temps;
+ case ir_var_uniform:
+ return this->lower_uniforms;
+ case ir_var_in:
+ case ir_var_const_in:
+ return (var->location == -1) ? this->lower_temps : this->lower_inputs;
+ case ir_var_out:
+ return (var->location == -1) ? this->lower_temps : this->lower_outputs;
+ case ir_var_inout:
+ return this->lower_temps;
+ }
+
+ assert(!"Should not get here.");
+ return false;
+ }
+
+ ir_variable *convert_dereference_array(ir_dereference_array *orig_deref,
+ ir_assignment* orig_assign)
+ {
+ assert(is_array_or_matrix(orig_deref->array));
+
+ const unsigned length = (orig_deref->array->type->is_array())
+ ? orig_deref->array->type->length
+ : orig_deref->array->type->matrix_columns;
+
+ void *const mem_ctx = ralloc_parent(base_ir);
+
+ /* Temporary storage for either the result of the dereference of
+ * the array, or the RHS that's being assigned into the
+ * dereference of the array.
+ */
+ ir_variable *var;
+
+ if (orig_assign) {
+ var = new(mem_ctx) ir_variable(orig_assign->rhs->type,
+ "dereference_array_value",
+ ir_var_temporary);
+ base_ir->insert_before(var);
+
+ ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(var);
+ ir_assignment *assign = new(mem_ctx) ir_assignment(lhs,
+ orig_assign->rhs,
+ NULL);
+
+ base_ir->insert_before(assign);
+ } else {
+ var = new(mem_ctx) ir_variable(orig_deref->type,
+ "dereference_array_value",
+ ir_var_temporary);
+ base_ir->insert_before(var);
+ }
+
+ /* Store the index to a temporary to avoid reusing its tree. */
+ ir_variable *index =
+ new(mem_ctx) ir_variable(orig_deref->array_index->type,
+ "dereference_array_index", ir_var_temporary);
+ base_ir->insert_before(index);
+
+ ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(index);
+ ir_assignment *assign =
+ new(mem_ctx) ir_assignment(lhs, orig_deref->array_index, NULL);
+ base_ir->insert_before(assign);
+
+ assignment_generator ag;
+ ag.array = orig_deref->array;
+ ag.base_ir = base_ir;
+ ag.var = var;
+ if (orig_assign) {
+ ag.is_write = true;
+ ag.write_mask = orig_assign->write_mask;
+ } else {
+ ag.is_write = false;
+ }
+
+ switch_generator sg(ag, index, 4, 4);
+
+ exec_list list;
+ sg.generate(0, length, &list);
+ base_ir->insert_before(&list);
+
+ return var;
+ }
+
+ virtual void handle_rvalue(ir_rvalue **pir)
+ {
+ if (!*pir)
+ return;
+
+ ir_dereference_array* orig_deref = (*pir)->as_dereference_array();
+ if (needs_lowering(orig_deref)) {
+ ir_variable* var = convert_dereference_array(orig_deref, 0);
+ assert(var);
+ *pir = new(ralloc_parent(base_ir)) ir_dereference_variable(var);
+ this->progress = true;
+ }
+ }
+
+ ir_visitor_status
+ visit_leave(ir_assignment *ir)
+ {
+ ir_rvalue_visitor::visit_leave(ir);
+
+ ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
+
+ if (needs_lowering(orig_deref)) {
+ convert_dereference_array(orig_deref, ir);
+ ir->remove();
+ this->progress = true;
+ }
+
+ return visit_continue;
+ }
+};
+
+bool
+lower_variable_index_to_cond_assign(exec_list *instructions,
+ bool lower_input,
+ bool lower_output,
+ bool lower_temp,
+ bool lower_uniform)
+{
+ variable_index_to_cond_assign_visitor v(lower_input,
+ lower_output,
+ lower_temp,
+ lower_uniform);
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp b/mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp
index 2e196f9e1..3c4d93201 100644
--- a/mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp
+++ b/mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp
@@ -1,258 +1,258 @@
-/*
- * 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 lower_vec_index_to_cond_assign.cpp
- *
- * Turns indexing into vector types to a series of conditional moves
- * of each channel's swizzle into a temporary.
- *
- * Most GPUs don't have a native way to do this operation, and this
- * works around that. For drivers using both this pass and
- * ir_vec_index_to_swizzle, there's a risk that this pass will happen
- * before sufficient constant folding to find that the array index is
- * constant. However, we hope that other optimization passes,
- * particularly constant folding of assignment conditions and copy
- * propagation, will result in the same code in the end.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
-public:
- ir_vec_index_to_cond_assign_visitor()
- {
- progress = false;
- }
-
- ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);
-
- virtual ir_visitor_status visit_enter(ir_expression *);
- virtual ir_visitor_status visit_enter(ir_swizzle *);
- virtual ir_visitor_status visit_leave(ir_assignment *);
- virtual ir_visitor_status visit_enter(ir_return *);
- virtual ir_visitor_status visit_enter(ir_call *);
- virtual ir_visitor_status visit_enter(ir_if *);
-
- bool progress;
-};
-
-ir_rvalue *
-ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
-{
- ir_dereference_array *orig_deref = ir->as_dereference_array();
- ir_assignment *assign;
- ir_variable *index, *var;
- ir_dereference *deref;
- ir_expression *condition;
- ir_swizzle *swizzle;
- int i;
-
- if (!orig_deref)
- return ir;
-
- if (orig_deref->array->type->is_matrix() ||
- orig_deref->array->type->is_array())
- return ir;
-
- void *mem_ctx = talloc_parent(ir);
-
- assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
-
- /* Store the index to a temporary to avoid reusing its tree. */
- index = new(base_ir) ir_variable(glsl_type::int_type,
- "vec_index_tmp_i",
- ir_var_temporary);
- base_ir->insert_before(index);
- deref = new(base_ir) ir_dereference_variable(index);
- assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
- base_ir->insert_before(assign);
-
- /* Temporary where we store whichever value we swizzle out. */
- var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
- ir_var_temporary);
- base_ir->insert_before(var);
-
- /* Generate a conditional move of each vector element to the temp. */
- for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
- deref = new(base_ir) ir_dereference_variable(index);
- condition = new(base_ir) ir_expression(ir_binop_equal,
- glsl_type::bool_type,
- deref,
- new(base_ir) ir_constant(i));
-
- /* Just clone the rest of the deref chain when trying to get at the
- * underlying variable.
- */
- swizzle = new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
- i, 0, 0, 0, 1);
-
- deref = new(base_ir) ir_dereference_variable(var);
- assign = new(base_ir) ir_assignment(deref, swizzle, condition);
- base_ir->insert_before(assign);
- }
-
- this->progress = true;
- return new(base_ir) ir_dereference_variable(var);
-}
-
-ir_visitor_status
-ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
-{
- unsigned int i;
-
- for (i = 0; i < ir->get_num_operands(); i++) {
- ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
-{
- /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
- * the result of indexing a vector is. But maybe at some point we'll end up
- * using swizzling of scalars for vector construction.
- */
- ir->val = convert_vec_index_to_cond_assign(ir->val);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
-{
- ir_variable *index, *var;
- ir_dereference_variable *deref;
- ir_assignment *assign;
- int i;
-
- ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
- if (ir->condition)
- ir->condition = convert_vec_index_to_cond_assign(ir->condition);
-
- /* Last, handle the LHS */
- ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
-
- if (!orig_deref ||
- orig_deref->array->type->is_matrix() ||
- orig_deref->array->type->is_array())
- return visit_continue;
-
- void *mem_ctx = talloc_parent(ir);
-
- assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
-
- /* Store the index to a temporary to avoid reusing its tree. */
- index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
- ir_var_temporary);
- ir->insert_before(index);
- deref = new(ir) ir_dereference_variable(index);
- assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
- ir->insert_before(assign);
-
- /* Store the RHS to a temporary to avoid reusing its tree. */
- var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
- ir_var_temporary);
- ir->insert_before(var);
- deref = new(ir) ir_dereference_variable(var);
- assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
- ir->insert_before(assign);
-
- /* Generate a conditional move of each vector element to the temp. */
- for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
- ir_rvalue *condition, *swizzle;
-
- deref = new(ir) ir_dereference_variable(index);
- condition = new(ir) ir_expression(ir_binop_equal,
- glsl_type::bool_type,
- deref,
- new(ir) ir_constant(i));
-
- /* Just clone the rest of the deref chain when trying to get at the
- * underlying variable.
- */
- swizzle = new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
- i, 0, 0, 0, 1);
-
- deref = new(ir) ir_dereference_variable(var);
- assign = new(ir) ir_assignment(swizzle, deref, condition);
- ir->insert_before(assign);
- }
- ir->remove();
-
- this->progress = true;
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
-{
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_rvalue *param = (ir_rvalue *)iter.get();
- ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);
-
- if (new_param != param) {
- param->replace_with(new_param);
- }
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
-{
- if (ir->value) {
- ir->value = convert_vec_index_to_cond_assign(ir->value);
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
-{
- ir->condition = convert_vec_index_to_cond_assign(ir->condition);
-
- return visit_continue;
-}
-
-bool
-do_vec_index_to_cond_assign(exec_list *instructions)
-{
- ir_vec_index_to_cond_assign_visitor v;
-
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
+/*
+ * 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 lower_vec_index_to_cond_assign.cpp
+ *
+ * Turns indexing into vector types to a series of conditional moves
+ * of each channel's swizzle into a temporary.
+ *
+ * Most GPUs don't have a native way to do this operation, and this
+ * works around that. For drivers using both this pass and
+ * ir_vec_index_to_swizzle, there's a risk that this pass will happen
+ * before sufficient constant folding to find that the array index is
+ * constant. However, we hope that other optimization passes,
+ * particularly constant folding of assignment conditions and copy
+ * propagation, will result in the same code in the end.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
+public:
+ ir_vec_index_to_cond_assign_visitor()
+ {
+ progress = false;
+ }
+
+ ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);
+
+ virtual ir_visitor_status visit_enter(ir_expression *);
+ virtual ir_visitor_status visit_enter(ir_swizzle *);
+ virtual ir_visitor_status visit_leave(ir_assignment *);
+ virtual ir_visitor_status visit_enter(ir_return *);
+ virtual ir_visitor_status visit_enter(ir_call *);
+ virtual ir_visitor_status visit_enter(ir_if *);
+
+ bool progress;
+};
+
+ir_rvalue *
+ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
+{
+ ir_dereference_array *orig_deref = ir->as_dereference_array();
+ ir_assignment *assign;
+ ir_variable *index, *var;
+ ir_dereference *deref;
+ ir_expression *condition;
+ ir_swizzle *swizzle;
+ int i;
+
+ if (!orig_deref)
+ return ir;
+
+ if (orig_deref->array->type->is_matrix() ||
+ orig_deref->array->type->is_array())
+ return ir;
+
+ void *mem_ctx = ralloc_parent(ir);
+
+ assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
+
+ /* Store the index to a temporary to avoid reusing its tree. */
+ index = new(base_ir) ir_variable(glsl_type::int_type,
+ "vec_index_tmp_i",
+ ir_var_temporary);
+ base_ir->insert_before(index);
+ deref = new(base_ir) ir_dereference_variable(index);
+ assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
+ base_ir->insert_before(assign);
+
+ /* Temporary where we store whichever value we swizzle out. */
+ var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
+ ir_var_temporary);
+ base_ir->insert_before(var);
+
+ /* Generate a conditional move of each vector element to the temp. */
+ for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
+ deref = new(base_ir) ir_dereference_variable(index);
+ condition = new(base_ir) ir_expression(ir_binop_equal,
+ glsl_type::bool_type,
+ deref,
+ new(base_ir) ir_constant(i));
+
+ /* Just clone the rest of the deref chain when trying to get at the
+ * underlying variable.
+ */
+ swizzle = new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
+ i, 0, 0, 0, 1);
+
+ deref = new(base_ir) ir_dereference_variable(var);
+ assign = new(base_ir) ir_assignment(deref, swizzle, condition);
+ base_ir->insert_before(assign);
+ }
+
+ this->progress = true;
+ return new(base_ir) ir_dereference_variable(var);
+}
+
+ir_visitor_status
+ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
+{
+ unsigned int i;
+
+ for (i = 0; i < ir->get_num_operands(); i++) {
+ ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
+{
+ /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
+ * the result of indexing a vector is. But maybe at some point we'll end up
+ * using swizzling of scalars for vector construction.
+ */
+ ir->val = convert_vec_index_to_cond_assign(ir->val);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
+{
+ ir_variable *index, *var;
+ ir_dereference_variable *deref;
+ ir_assignment *assign;
+ int i;
+
+ ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
+ if (ir->condition)
+ ir->condition = convert_vec_index_to_cond_assign(ir->condition);
+
+ /* Last, handle the LHS */
+ ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
+
+ if (!orig_deref ||
+ orig_deref->array->type->is_matrix() ||
+ orig_deref->array->type->is_array())
+ return visit_continue;
+
+ void *mem_ctx = ralloc_parent(ir);
+
+ assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
+
+ /* Store the index to a temporary to avoid reusing its tree. */
+ index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
+ ir_var_temporary);
+ ir->insert_before(index);
+ deref = new(ir) ir_dereference_variable(index);
+ assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
+ ir->insert_before(assign);
+
+ /* Store the RHS to a temporary to avoid reusing its tree. */
+ var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
+ ir_var_temporary);
+ ir->insert_before(var);
+ deref = new(ir) ir_dereference_variable(var);
+ assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
+ ir->insert_before(assign);
+
+ /* Generate a conditional move of each vector element to the temp. */
+ for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
+ ir_rvalue *condition, *swizzle;
+
+ deref = new(ir) ir_dereference_variable(index);
+ condition = new(ir) ir_expression(ir_binop_equal,
+ glsl_type::bool_type,
+ deref,
+ new(ir) ir_constant(i));
+
+ /* Just clone the rest of the deref chain when trying to get at the
+ * underlying variable.
+ */
+ swizzle = new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
+ i, 0, 0, 0, 1);
+
+ deref = new(ir) ir_dereference_variable(var);
+ assign = new(ir) ir_assignment(swizzle, deref, condition);
+ ir->insert_before(assign);
+ }
+ ir->remove();
+
+ this->progress = true;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
+{
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param = (ir_rvalue *)iter.get();
+ ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);
+
+ if (new_param != param) {
+ param->replace_with(new_param);
+ }
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
+{
+ if (ir->value) {
+ ir->value = convert_vec_index_to_cond_assign(ir->value);
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
+{
+ ir->condition = convert_vec_index_to_cond_assign(ir->condition);
+
+ return visit_continue;
+}
+
+bool
+do_vec_index_to_cond_assign(exec_list *instructions)
+{
+ ir_vec_index_to_cond_assign_visitor v;
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp b/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
index e0d641549..c7630c28a 100644
--- a/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
+++ b/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
@@ -1,157 +1,157 @@
-/*
- * 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 lower_vec_index_to_swizzle.cpp
- *
- * Turns constant indexing into vector types to swizzles. This will
- * let other swizzle-aware optimization passes catch these constructs,
- * and codegen backends not have to worry about this case.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class ir_vec_index_to_swizzle_visitor : public ir_hierarchical_visitor {
-public:
- ir_vec_index_to_swizzle_visitor()
- {
- progress = false;
- }
-
- ir_rvalue *convert_vec_index_to_swizzle(ir_rvalue *val);
-
- virtual ir_visitor_status visit_enter(ir_expression *);
- virtual ir_visitor_status visit_enter(ir_swizzle *);
- virtual ir_visitor_status visit_enter(ir_assignment *);
- virtual ir_visitor_status visit_enter(ir_return *);
- virtual ir_visitor_status visit_enter(ir_call *);
- virtual ir_visitor_status visit_enter(ir_if *);
-
- bool progress;
-};
-
-ir_rvalue *
-ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir)
-{
- ir_dereference_array *deref = ir->as_dereference_array();
- ir_constant *ir_constant;
-
- if (!deref)
- return ir;
-
- if (deref->array->type->is_matrix() || deref->array->type->is_array())
- return ir;
-
- assert(deref->array_index->type->base_type == GLSL_TYPE_INT);
- ir_constant = deref->array_index->constant_expression_value();
- if (!ir_constant)
- return ir;
-
- void *ctx = talloc_parent(ir);
- this->progress = true;
- return new(ctx) ir_swizzle(deref->array,
- ir_constant->value.i[0], 0, 0, 0, 1);
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_expression *ir)
-{
- unsigned int i;
-
- for (i = 0; i < ir->get_num_operands(); i++) {
- ir->operands[i] = convert_vec_index_to_swizzle(ir->operands[i]);
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)
-{
- /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
- * the result of indexing a vector is. But maybe at some point we'll end up
- * using swizzling of scalars for vector construction.
- */
- ir->val = convert_vec_index_to_swizzle(ir->val);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir)
-{
- ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs));
- ir->rhs = convert_vec_index_to_swizzle(ir->rhs);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_call *ir)
-{
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_rvalue *param = (ir_rvalue *)iter.get();
- ir_rvalue *new_param = convert_vec_index_to_swizzle(param);
-
- if (new_param != param) {
- param->replace_with(new_param);
- }
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_return *ir)
-{
- if (ir->value) {
- ir->value = convert_vec_index_to_swizzle(ir->value);
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_if *ir)
-{
- ir->condition = convert_vec_index_to_swizzle(ir->condition);
-
- return visit_continue;
-}
-
-bool
-do_vec_index_to_swizzle(exec_list *instructions)
-{
- ir_vec_index_to_swizzle_visitor v;
-
- v.run(instructions);
-
- return v.progress;
-}
+/*
+ * 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 lower_vec_index_to_swizzle.cpp
+ *
+ * Turns constant indexing into vector types to swizzles. This will
+ * let other swizzle-aware optimization passes catch these constructs,
+ * and codegen backends not have to worry about this case.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class ir_vec_index_to_swizzle_visitor : public ir_hierarchical_visitor {
+public:
+ ir_vec_index_to_swizzle_visitor()
+ {
+ progress = false;
+ }
+
+ ir_rvalue *convert_vec_index_to_swizzle(ir_rvalue *val);
+
+ virtual ir_visitor_status visit_enter(ir_expression *);
+ virtual ir_visitor_status visit_enter(ir_swizzle *);
+ virtual ir_visitor_status visit_enter(ir_assignment *);
+ virtual ir_visitor_status visit_enter(ir_return *);
+ virtual ir_visitor_status visit_enter(ir_call *);
+ virtual ir_visitor_status visit_enter(ir_if *);
+
+ bool progress;
+};
+
+ir_rvalue *
+ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir)
+{
+ ir_dereference_array *deref = ir->as_dereference_array();
+ ir_constant *ir_constant;
+
+ if (!deref)
+ return ir;
+
+ if (deref->array->type->is_matrix() || deref->array->type->is_array())
+ return ir;
+
+ assert(deref->array_index->type->base_type == GLSL_TYPE_INT);
+ ir_constant = deref->array_index->constant_expression_value();
+ if (!ir_constant)
+ return ir;
+
+ void *ctx = ralloc_parent(ir);
+ this->progress = true;
+ return new(ctx) ir_swizzle(deref->array,
+ ir_constant->value.i[0], 0, 0, 0, 1);
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_expression *ir)
+{
+ unsigned int i;
+
+ for (i = 0; i < ir->get_num_operands(); i++) {
+ ir->operands[i] = convert_vec_index_to_swizzle(ir->operands[i]);
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)
+{
+ /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
+ * the result of indexing a vector is. But maybe at some point we'll end up
+ * using swizzling of scalars for vector construction.
+ */
+ ir->val = convert_vec_index_to_swizzle(ir->val);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir)
+{
+ ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs));
+ ir->rhs = convert_vec_index_to_swizzle(ir->rhs);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_call *ir)
+{
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param = (ir_rvalue *)iter.get();
+ ir_rvalue *new_param = convert_vec_index_to_swizzle(param);
+
+ if (new_param != param) {
+ param->replace_with(new_param);
+ }
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_return *ir)
+{
+ if (ir->value) {
+ ir->value = convert_vec_index_to_swizzle(ir->value);
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_if *ir)
+{
+ ir->condition = convert_vec_index_to_swizzle(ir->condition);
+
+ return visit_continue;
+}
+
+bool
+do_vec_index_to_swizzle(exec_list *instructions)
+{
+ ir_vec_index_to_swizzle_visitor v;
+
+ v.run(instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/lower_vector.cpp b/mesalib/src/glsl/lower_vector.cpp
index 3ed8d05d6..57963a121 100644
--- a/mesalib/src/glsl/lower_vector.cpp
+++ b/mesalib/src/glsl/lower_vector.cpp
@@ -1,224 +1,224 @@
-/*
- * 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 lower_vector.cpp
- * IR lowering pass to remove some types of ir_quadop_vector
- *
- * \author Ian Romanick <ian.d.romanick@intel.com>
- */
-
-#include "ir.h"
-#include "ir_rvalue_visitor.h"
-
-class lower_vector_visitor : public ir_rvalue_visitor {
-public:
- lower_vector_visitor() : progress(false)
- {
- /* empty */
- }
-
- void handle_rvalue(ir_rvalue **rvalue);
-
- /**
- * Should SWZ-like expressions be lowered?
- */
- bool dont_lower_swz;
-
- bool progress;
-};
-
-/**
- * Determine if an IR expression tree looks like an extended swizzle
- *
- * Extended swizzles consist of access of a single vector source (with possible
- * per component negation) and the constants -1, 0, or 1.
- */
-bool
-is_extended_swizzle(ir_expression *ir)
-{
- /* Track any variables that are accessed by this expression.
- */
- ir_variable *var = NULL;
-
- assert(ir->operation == ir_quadop_vector);
-
- for (unsigned i = 0; i < ir->type->vector_elements; i++) {
- ir_rvalue *op = ir->operands[i];
-
- while (op != NULL) {
- switch (op->ir_type) {
- case ir_type_constant: {
- const ir_constant *const c = op->as_constant();
-
- if (!c->is_one() && !c->is_zero() && !c->is_negative_one())
- return false;
-
- op = NULL;
- break;
- }
-
- case ir_type_dereference_variable: {
- ir_dereference_variable *const d = (ir_dereference_variable *) op;
-
- if ((var != NULL) && (var != d->var))
- return false;
-
- var = d->var;
- op = NULL;
- break;
- }
-
- case ir_type_expression: {
- ir_expression *const ex = (ir_expression *) op;
-
- if (ex->operation != ir_unop_neg)
- return false;
-
- op = ex->operands[0];
- break;
- }
-
- case ir_type_swizzle:
- op = ((ir_swizzle *) op)->val;
- break;
-
- default:
- return false;
- }
- }
- }
-
- return true;
-}
-
-void
-lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
- if (!*rvalue)
- return;
-
- ir_expression *expr = (*rvalue)->as_expression();
- if ((expr == NULL) || (expr->operation != ir_quadop_vector))
- return;
-
- if (this->dont_lower_swz && is_extended_swizzle(expr))
- return;
-
- /* FINISHME: Is this the right thing to use for the talloc context?
- */
- void *const mem_ctx = expr;
-
- assert(expr->type->vector_elements == expr->get_num_operands());
-
- /* Generate a temporary with the same type as the ir_quadop_operation.
- */
- ir_variable *const temp =
- new(mem_ctx) ir_variable(expr->type, "vecop_tmp", ir_var_temporary);
-
- this->base_ir->insert_before(temp);
-
- /* Counter of the number of components collected so far.
- */
- unsigned assigned;
-
- /* Write-mask in the destination that receives counted by 'assigned'.
- */
- unsigned write_mask;
-
-
- /* Generate upto four assignments to that variable. Try to group component
- * assignments together:
- *
- * - All constant components can be assigned at once.
- * - All assigments of components from a single variable with the same
- * unary operator can be assigned at once.
- */
- ir_constant_data d = { { 0 } };
-
- assigned = 0;
- write_mask = 0;
- for (unsigned i = 0; i < expr->type->vector_elements; i++) {
- const ir_constant *const c = expr->operands[i]->as_constant();
-
- if (c == NULL)
- continue;
-
- switch (expr->type->base_type) {
- case GLSL_TYPE_UINT: d.u[assigned] = c->value.u[0]; break;
- case GLSL_TYPE_INT: d.i[assigned] = c->value.i[0]; break;
- case GLSL_TYPE_FLOAT: d.f[assigned] = c->value.f[0]; break;
- case GLSL_TYPE_BOOL: d.b[assigned] = c->value.b[0]; break;
- default: assert(!"Should not get here."); break;
- }
-
- write_mask |= (1U << i);
- assigned++;
- }
-
- assert((write_mask == 0) == (assigned == 0));
-
- /* If there were constant values, generate an assignment.
- */
- if (assigned > 0) {
- ir_constant *const c =
- new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type,
- assigned, 0),
- &d);
- ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
- ir_assignment *const assign =
- new(mem_ctx) ir_assignment(lhs, c, NULL, write_mask);
-
- this->base_ir->insert_before(assign);
- }
-
- /* FINISHME: This should try to coalesce assignments.
- */
- for (unsigned i = 0; i < expr->type->vector_elements; i++) {
- if (expr->operands[i]->ir_type == ir_type_constant)
- continue;
-
- ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
- ir_assignment *const assign =
- new(mem_ctx) ir_assignment(lhs, expr->operands[i], NULL, (1U << i));
-
- this->base_ir->insert_before(assign);
- assigned++;
- }
-
- assert(assigned == expr->type->vector_elements);
-
- *rvalue = new(mem_ctx) ir_dereference_variable(temp);
- this->progress = true;
-}
-
-bool
-lower_quadop_vector(exec_list *instructions, bool dont_lower_swz)
-{
- lower_vector_visitor v;
-
- v.dont_lower_swz = dont_lower_swz;
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
+/*
+ * 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 lower_vector.cpp
+ * IR lowering pass to remove some types of ir_quadop_vector
+ *
+ * \author Ian Romanick <ian.d.romanick@intel.com>
+ */
+
+#include "ir.h"
+#include "ir_rvalue_visitor.h"
+
+class lower_vector_visitor : public ir_rvalue_visitor {
+public:
+ lower_vector_visitor() : progress(false)
+ {
+ /* empty */
+ }
+
+ void handle_rvalue(ir_rvalue **rvalue);
+
+ /**
+ * Should SWZ-like expressions be lowered?
+ */
+ bool dont_lower_swz;
+
+ bool progress;
+};
+
+/**
+ * Determine if an IR expression tree looks like an extended swizzle
+ *
+ * Extended swizzles consist of access of a single vector source (with possible
+ * per component negation) and the constants -1, 0, or 1.
+ */
+bool
+is_extended_swizzle(ir_expression *ir)
+{
+ /* Track any variables that are accessed by this expression.
+ */
+ ir_variable *var = NULL;
+
+ assert(ir->operation == ir_quadop_vector);
+
+ for (unsigned i = 0; i < ir->type->vector_elements; i++) {
+ ir_rvalue *op = ir->operands[i];
+
+ while (op != NULL) {
+ switch (op->ir_type) {
+ case ir_type_constant: {
+ const ir_constant *const c = op->as_constant();
+
+ if (!c->is_one() && !c->is_zero() && !c->is_negative_one())
+ return false;
+
+ op = NULL;
+ break;
+ }
+
+ case ir_type_dereference_variable: {
+ ir_dereference_variable *const d = (ir_dereference_variable *) op;
+
+ if ((var != NULL) && (var != d->var))
+ return false;
+
+ var = d->var;
+ op = NULL;
+ break;
+ }
+
+ case ir_type_expression: {
+ ir_expression *const ex = (ir_expression *) op;
+
+ if (ex->operation != ir_unop_neg)
+ return false;
+
+ op = ex->operands[0];
+ break;
+ }
+
+ case ir_type_swizzle:
+ op = ((ir_swizzle *) op)->val;
+ break;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void
+lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+ if (!*rvalue)
+ return;
+
+ ir_expression *expr = (*rvalue)->as_expression();
+ if ((expr == NULL) || (expr->operation != ir_quadop_vector))
+ return;
+
+ if (this->dont_lower_swz && is_extended_swizzle(expr))
+ return;
+
+ /* FINISHME: Is this the right thing to use for the ralloc context?
+ */
+ void *const mem_ctx = expr;
+
+ assert(expr->type->vector_elements == expr->get_num_operands());
+
+ /* Generate a temporary with the same type as the ir_quadop_operation.
+ */
+ ir_variable *const temp =
+ new(mem_ctx) ir_variable(expr->type, "vecop_tmp", ir_var_temporary);
+
+ this->base_ir->insert_before(temp);
+
+ /* Counter of the number of components collected so far.
+ */
+ unsigned assigned;
+
+ /* Write-mask in the destination that receives counted by 'assigned'.
+ */
+ unsigned write_mask;
+
+
+ /* Generate upto four assignments to that variable. Try to group component
+ * assignments together:
+ *
+ * - All constant components can be assigned at once.
+ * - All assigments of components from a single variable with the same
+ * unary operator can be assigned at once.
+ */
+ ir_constant_data d = { { 0 } };
+
+ assigned = 0;
+ write_mask = 0;
+ for (unsigned i = 0; i < expr->type->vector_elements; i++) {
+ const ir_constant *const c = expr->operands[i]->as_constant();
+
+ if (c == NULL)
+ continue;
+
+ switch (expr->type->base_type) {
+ case GLSL_TYPE_UINT: d.u[assigned] = c->value.u[0]; break;
+ case GLSL_TYPE_INT: d.i[assigned] = c->value.i[0]; break;
+ case GLSL_TYPE_FLOAT: d.f[assigned] = c->value.f[0]; break;
+ case GLSL_TYPE_BOOL: d.b[assigned] = c->value.b[0]; break;
+ default: assert(!"Should not get here."); break;
+ }
+
+ write_mask |= (1U << i);
+ assigned++;
+ }
+
+ assert((write_mask == 0) == (assigned == 0));
+
+ /* If there were constant values, generate an assignment.
+ */
+ if (assigned > 0) {
+ ir_constant *const c =
+ new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type,
+ assigned, 0),
+ &d);
+ ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
+ ir_assignment *const assign =
+ new(mem_ctx) ir_assignment(lhs, c, NULL, write_mask);
+
+ this->base_ir->insert_before(assign);
+ }
+
+ /* FINISHME: This should try to coalesce assignments.
+ */
+ for (unsigned i = 0; i < expr->type->vector_elements; i++) {
+ if (expr->operands[i]->ir_type == ir_type_constant)
+ continue;
+
+ ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
+ ir_assignment *const assign =
+ new(mem_ctx) ir_assignment(lhs, expr->operands[i], NULL, (1U << i));
+
+ this->base_ir->insert_before(assign);
+ assigned++;
+ }
+
+ assert(assigned == expr->type->vector_elements);
+
+ *rvalue = new(mem_ctx) ir_dereference_variable(temp);
+ this->progress = true;
+}
+
+bool
+lower_quadop_vector(exec_list *instructions, bool dont_lower_swz)
+{
+ lower_vector_visitor v;
+
+ v.dont_lower_swz = dont_lower_swz;
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/main.cpp b/mesalib/src/glsl/main.cpp
index a51062456..6321a4a17 100644
--- a/mesalib/src/glsl/main.cpp
+++ b/mesalib/src/glsl/main.cpp
@@ -1,341 +1,347 @@
-/*
- * 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 <cstdlib>
-#include <cstdio>
-#include <io.h>
-
-#ifdef _MSC_VER
-#define __STDC__ 1
-#include <getopt.h>
-#define open _open
-#define read _read
-#define fstat _fstat
-#define stat _stat
-#define close _close
-#define O_RDONLY _O_RDONLY
-#endif
-
-#include "ast.h"
-#include "glsl_parser_extras.h"
-#include "glsl_parser.h"
-#include "ir_optimization.h"
-#include "ir_print_visitor.h"
-#include "program.h"
-#include "loop_analysis.h"
-
-extern "C" struct gl_shader *
-_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);
-
-extern "C" void
-_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
- struct gl_shader *sh);
-
-/* Copied from shader_api.c for the stand-alone compiler.
- */
-void
-_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
- struct gl_shader *sh)
-{
- *ptr = sh;
-}
-
-struct gl_shader *
-_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
-{
- struct gl_shader *shader;
-
- (void) ctx;
-
- assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
- shader = talloc_zero(NULL, struct gl_shader);
- if (shader) {
- shader->Type = type;
- shader->Name = name;
- shader->RefCount = 1;
- }
- return shader;
-}
-
-static void
-initialize_context(struct gl_context *ctx, gl_api api)
-{
- memset(ctx, 0, sizeof(*ctx));
-
- ctx->API = api;
-
- ctx->Extensions.ARB_draw_buffers = GL_TRUE;
- ctx->Extensions.ARB_draw_instanced = GL_TRUE;
- ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
- ctx->Extensions.EXT_texture_array = GL_TRUE;
- ctx->Extensions.NV_texture_rectangle = GL_TRUE;
-
- /* 1.10 minimums. */
- ctx->Const.MaxLights = 8;
- ctx->Const.MaxClipPlanes = 8;
- ctx->Const.MaxTextureUnits = 2;
-
- /* More than the 1.10 minimum to appease parser tests taken from
- * apps that (hopefully) already checked the number of coords.
- */
- ctx->Const.MaxTextureCoordUnits = 4;
-
- ctx->Const.VertexProgram.MaxAttribs = 16;
- ctx->Const.VertexProgram.MaxUniformComponents = 512;
- ctx->Const.MaxVarying = 8;
- ctx->Const.MaxVertexTextureImageUnits = 0;
- ctx->Const.MaxCombinedTextureImageUnits = 2;
- ctx->Const.MaxTextureImageUnits = 2;
- ctx->Const.FragmentProgram.MaxUniformComponents = 64;
-
- ctx->Const.MaxDrawBuffers = 2;
-
- ctx->Driver.NewShader = _mesa_new_shader;
-}
-
-/* Returned string will have 'ctx' as its talloc owner. */
-static char *
-load_text_file(void *ctx, const char *file_name)
-{
- char *text = NULL;
- size_t size;
- size_t total_read = 0;
- FILE *fp = fopen(file_name, "rb");
-
- if (!fp) {
- return NULL;
- }
-
- fseek(fp, 0L, SEEK_END);
- size = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
-
- text = (char *) talloc_size(ctx, size + 1);
- if (text != NULL) {
- do {
- size_t bytes = fread(text + total_read,
- 1, size - total_read, fp);
- if (bytes < size - total_read) {
- free(text);
- text = NULL;
- break;
- }
-
- if (bytes == 0) {
- break;
- }
-
- total_read += bytes;
- } while (total_read < size);
-
- text[total_read] = '\0';
- }
-
- fclose(fp);
-
- return text;
-}
-
-int glsl_es = 0;
-int dump_ast = 0;
-int dump_hir = 0;
-int dump_lir = 0;
-int do_link = 0;
-
-const struct option compiler_opts[] = {
- { "glsl-es", 0, &glsl_es, 1 },
- { "dump-ast", 0, &dump_ast, 1 },
- { "dump-hir", 0, &dump_hir, 1 },
- { "dump-lir", 0, &dump_lir, 1 },
- { "link", 0, &do_link, 1 },
- { NULL, 0, NULL, 0 }
-};
-
-/**
- * \brief Print proper usage and exit with failure.
- */
-void
-usage_fail(const char *name)
-{
-
- const char *header =
- "usage: %s [options] <file.vert | file.geom | file.frag>\n"
- "\n"
- "Possible options are:\n";
- printf(header, name, name);
- for (const struct option *o = compiler_opts; o->name != 0; ++o) {
- printf(" --%s\n", o->name);
- }
- exit(EXIT_FAILURE);
-}
-
-
-void
-compile_shader(struct gl_context *ctx, struct gl_shader *shader)
-{
- struct _mesa_glsl_parse_state *state =
- new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
-
- const char *source = shader->Source;
- state->error = preprocess(state, &source, &state->info_log,
- state->extensions, ctx->API) != 0;
-
- if (!state->error) {
- _mesa_glsl_lexer_ctor(state, source);
- _mesa_glsl_parse(state);
- _mesa_glsl_lexer_dtor(state);
- }
-
- if (dump_ast) {
- foreach_list_const(n, &state->translation_unit) {
- ast_node *ast = exec_node_data(ast_node, n, link);
- ast->print();
- }
- printf("\n\n");
- }
-
- shader->ir = new(shader) exec_list;
- if (!state->error && !state->translation_unit.is_empty())
- _mesa_ast_to_hir(shader->ir, state);
-
- /* Print out the unoptimized IR. */
- if (!state->error && dump_hir) {
- validate_ir_tree(shader->ir);
- _mesa_print_ir(shader->ir, state);
- }
-
- /* Optimization passes */
- if (!state->error && !shader->ir->is_empty()) {
- bool progress;
- do {
- progress = do_common_optimization(shader->ir, false, 32);
- } while (progress);
-
- validate_ir_tree(shader->ir);
- }
-
-
- /* Print out the resulting IR */
- if (!state->error && dump_lir) {
- _mesa_print_ir(shader->ir, state);
- }
-
- shader->symbols = state->symbols;
- shader->CompileStatus = !state->error;
- shader->Version = state->language_version;
- memcpy(shader->builtins_to_link, state->builtins_to_link,
- sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
- shader->num_builtins_to_link = state->num_builtins_to_link;
-
- if (shader->InfoLog)
- talloc_free(shader->InfoLog);
-
- shader->InfoLog = state->info_log;
-
- /* Retain any live IR, but trash the rest. */
- reparent_ir(shader->ir, shader);
-
- talloc_free(state);
-
- return;
-}
-
-int
-main(int argc, char **argv)
-{
- int status = EXIT_SUCCESS;
- struct gl_context local_ctx;
- struct gl_context *ctx = &local_ctx;
-
- int c;
- int idx = 0;
- while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1)
- /* empty */ ;
-
-
- if (argc <= optind)
- usage_fail(argv[0]);
-
- initialize_context(ctx, (glsl_es) ? API_OPENGLES2 : API_OPENGL);
-
- struct gl_shader_program *whole_program;
-
- whole_program = talloc_zero (NULL, struct gl_shader_program);
- assert(whole_program != NULL);
-
- for (/* empty */; argc > optind; optind++) {
- whole_program->Shaders = (struct gl_shader **)
- talloc_realloc(whole_program, whole_program->Shaders,
- struct gl_shader *, whole_program->NumShaders + 1);
- assert(whole_program->Shaders != NULL);
-
- struct gl_shader *shader = talloc_zero(whole_program, gl_shader);
-
- whole_program->Shaders[whole_program->NumShaders] = shader;
- whole_program->NumShaders++;
-
- const unsigned len = strlen(argv[optind]);
- if (len < 6)
- usage_fail(argv[0]);
-
- const char *const ext = & argv[optind][len - 5];
- if (strncmp(".vert", ext, 5) == 0)
- shader->Type = GL_VERTEX_SHADER;
- else if (strncmp(".geom", ext, 5) == 0)
- shader->Type = GL_GEOMETRY_SHADER;
- else if (strncmp(".frag", ext, 5) == 0)
- shader->Type = GL_FRAGMENT_SHADER;
- else
- usage_fail(argv[0]);
-
- shader->Source = load_text_file(whole_program, argv[optind]);
- if (shader->Source == NULL) {
- printf("File \"%s\" does not exist.\n", argv[optind]);
- exit(EXIT_FAILURE);
- }
-
- compile_shader(ctx, shader);
-
- if (!shader->CompileStatus) {
- printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog);
- status = EXIT_FAILURE;
- break;
- }
- }
-
- if ((status == EXIT_SUCCESS) && do_link) {
- link_shaders(ctx, whole_program);
- status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;
-
- if (strlen(whole_program->InfoLog) > 0)
- printf("Info log for linking:\n%s\n", whole_program->InfoLog);
- }
-
- for (unsigned i = 0; i < MESA_SHADER_TYPES; i++)
- talloc_free(whole_program->_LinkedShaders[i]);
-
- talloc_free(whole_program);
- _mesa_glsl_release_types();
- _mesa_glsl_release_functions();
-
- return status;
-}
+/*
+ * 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 <cstdlib>
+#include <cstdio>
+#include <io.h>
+
+#ifdef _MSC_VER
+#define __STDC__ 1
+#include <getopt.h>
+#define open _open
+#define read _read
+#define fstat _fstat
+#define stat _stat
+#define close _close
+#define O_RDONLY _O_RDONLY
+#endif
+
+#include "ast.h"
+#include "glsl_parser_extras.h"
+#include "glsl_parser.h"
+#include "ir_optimization.h"
+#include "ir_print_visitor.h"
+#include "program.h"
+#include "loop_analysis.h"
+
+extern "C" struct gl_shader *
+_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);
+
+extern "C" void
+_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
+ struct gl_shader *sh);
+
+/* Copied from shader_api.c for the stand-alone compiler.
+ */
+void
+_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
+ struct gl_shader *sh)
+{
+ *ptr = sh;
+}
+
+struct gl_shader *
+_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
+{
+ struct gl_shader *shader;
+
+ (void) ctx;
+
+ assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
+ shader = rzalloc(NULL, struct gl_shader);
+ if (shader) {
+ shader->Type = type;
+ shader->Name = name;
+ shader->RefCount = 1;
+ }
+ return shader;
+}
+
+static void
+initialize_context(struct gl_context *ctx, gl_api api)
+{
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->API = api;
+
+ ctx->Extensions.ARB_ES2_compatibility = GL_TRUE;
+ ctx->Extensions.ARB_draw_buffers = GL_TRUE;
+ ctx->Extensions.ARB_draw_instanced = GL_TRUE;
+ ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
+ ctx->Extensions.EXT_texture_array = GL_TRUE;
+ ctx->Extensions.NV_texture_rectangle = GL_TRUE;
+
+ /* GLSL 1.30 isn't fully supported, but we need to advertise 1.30 so that
+ * the built-in functions for 1.30 can be built.
+ */
+ ctx->Const.GLSLVersion = 130;
+
+ /* 1.10 minimums. */
+ ctx->Const.MaxLights = 8;
+ ctx->Const.MaxClipPlanes = 8;
+ ctx->Const.MaxTextureUnits = 2;
+
+ /* More than the 1.10 minimum to appease parser tests taken from
+ * apps that (hopefully) already checked the number of coords.
+ */
+ ctx->Const.MaxTextureCoordUnits = 4;
+
+ ctx->Const.VertexProgram.MaxAttribs = 16;
+ ctx->Const.VertexProgram.MaxUniformComponents = 512;
+ ctx->Const.MaxVarying = 8;
+ ctx->Const.MaxVertexTextureImageUnits = 0;
+ ctx->Const.MaxCombinedTextureImageUnits = 2;
+ ctx->Const.MaxTextureImageUnits = 2;
+ ctx->Const.FragmentProgram.MaxUniformComponents = 64;
+
+ ctx->Const.MaxDrawBuffers = 2;
+
+ ctx->Driver.NewShader = _mesa_new_shader;
+}
+
+/* Returned string will have 'ctx' as its ralloc owner. */
+static char *
+load_text_file(void *ctx, const char *file_name)
+{
+ char *text = NULL;
+ size_t size;
+ size_t total_read = 0;
+ FILE *fp = fopen(file_name, "rb");
+
+ if (!fp) {
+ return NULL;
+ }
+
+ fseek(fp, 0L, SEEK_END);
+ size = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ text = (char *) ralloc_size(ctx, size + 1);
+ if (text != NULL) {
+ do {
+ size_t bytes = fread(text + total_read,
+ 1, size - total_read, fp);
+ if (bytes < size - total_read) {
+ free(text);
+ text = NULL;
+ break;
+ }
+
+ if (bytes == 0) {
+ break;
+ }
+
+ total_read += bytes;
+ } while (total_read < size);
+
+ text[total_read] = '\0';
+ }
+
+ fclose(fp);
+
+ return text;
+}
+
+int glsl_es = 0;
+int dump_ast = 0;
+int dump_hir = 0;
+int dump_lir = 0;
+int do_link = 0;
+
+const struct option compiler_opts[] = {
+ { "glsl-es", 0, &glsl_es, 1 },
+ { "dump-ast", 0, &dump_ast, 1 },
+ { "dump-hir", 0, &dump_hir, 1 },
+ { "dump-lir", 0, &dump_lir, 1 },
+ { "link", 0, &do_link, 1 },
+ { NULL, 0, NULL, 0 }
+};
+
+/**
+ * \brief Print proper usage and exit with failure.
+ */
+void
+usage_fail(const char *name)
+{
+
+ const char *header =
+ "usage: %s [options] <file.vert | file.geom | file.frag>\n"
+ "\n"
+ "Possible options are:\n";
+ printf(header, name, name);
+ for (const struct option *o = compiler_opts; o->name != 0; ++o) {
+ printf(" --%s\n", o->name);
+ }
+ exit(EXIT_FAILURE);
+}
+
+
+void
+compile_shader(struct gl_context *ctx, struct gl_shader *shader)
+{
+ struct _mesa_glsl_parse_state *state =
+ new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
+
+ const char *source = shader->Source;
+ state->error = preprocess(state, &source, &state->info_log,
+ state->extensions, ctx->API) != 0;
+
+ if (!state->error) {
+ _mesa_glsl_lexer_ctor(state, source);
+ _mesa_glsl_parse(state);
+ _mesa_glsl_lexer_dtor(state);
+ }
+
+ if (dump_ast) {
+ foreach_list_const(n, &state->translation_unit) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ }
+ printf("\n\n");
+ }
+
+ shader->ir = new(shader) exec_list;
+ if (!state->error && !state->translation_unit.is_empty())
+ _mesa_ast_to_hir(shader->ir, state);
+
+ /* Print out the unoptimized IR. */
+ if (!state->error && dump_hir) {
+ validate_ir_tree(shader->ir);
+ _mesa_print_ir(shader->ir, state);
+ }
+
+ /* Optimization passes */
+ if (!state->error && !shader->ir->is_empty()) {
+ bool progress;
+ do {
+ progress = do_common_optimization(shader->ir, false, 32);
+ } while (progress);
+
+ validate_ir_tree(shader->ir);
+ }
+
+
+ /* Print out the resulting IR */
+ if (!state->error && dump_lir) {
+ _mesa_print_ir(shader->ir, state);
+ }
+
+ shader->symbols = state->symbols;
+ shader->CompileStatus = !state->error;
+ shader->Version = state->language_version;
+ memcpy(shader->builtins_to_link, state->builtins_to_link,
+ sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
+ shader->num_builtins_to_link = state->num_builtins_to_link;
+
+ if (shader->InfoLog)
+ ralloc_free(shader->InfoLog);
+
+ shader->InfoLog = state->info_log;
+
+ /* Retain any live IR, but trash the rest. */
+ reparent_ir(shader->ir, shader);
+
+ ralloc_free(state);
+
+ return;
+}
+
+int
+main(int argc, char **argv)
+{
+ int status = EXIT_SUCCESS;
+ struct gl_context local_ctx;
+ struct gl_context *ctx = &local_ctx;
+
+ int c;
+ int idx = 0;
+ while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1)
+ /* empty */ ;
+
+
+ if (argc <= optind)
+ usage_fail(argv[0]);
+
+ initialize_context(ctx, (glsl_es) ? API_OPENGLES2 : API_OPENGL);
+
+ struct gl_shader_program *whole_program;
+
+ whole_program = rzalloc (NULL, struct gl_shader_program);
+ assert(whole_program != NULL);
+
+ for (/* empty */; argc > optind; optind++) {
+ whole_program->Shaders =
+ reralloc(whole_program, whole_program->Shaders,
+ struct gl_shader *, whole_program->NumShaders + 1);
+ assert(whole_program->Shaders != NULL);
+
+ struct gl_shader *shader = rzalloc(whole_program, gl_shader);
+
+ whole_program->Shaders[whole_program->NumShaders] = shader;
+ whole_program->NumShaders++;
+
+ const unsigned len = strlen(argv[optind]);
+ if (len < 6)
+ usage_fail(argv[0]);
+
+ const char *const ext = & argv[optind][len - 5];
+ if (strncmp(".vert", ext, 5) == 0)
+ shader->Type = GL_VERTEX_SHADER;
+ else if (strncmp(".geom", ext, 5) == 0)
+ shader->Type = GL_GEOMETRY_SHADER;
+ else if (strncmp(".frag", ext, 5) == 0)
+ shader->Type = GL_FRAGMENT_SHADER;
+ else
+ usage_fail(argv[0]);
+
+ shader->Source = load_text_file(whole_program, argv[optind]);
+ if (shader->Source == NULL) {
+ printf("File \"%s\" does not exist.\n", argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+
+ compile_shader(ctx, shader);
+
+ if (!shader->CompileStatus) {
+ printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog);
+ status = EXIT_FAILURE;
+ break;
+ }
+ }
+
+ if ((status == EXIT_SUCCESS) && do_link) {
+ link_shaders(ctx, whole_program);
+ status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ if (strlen(whole_program->InfoLog) > 0)
+ printf("Info log for linking:\n%s\n", whole_program->InfoLog);
+ }
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++)
+ ralloc_free(whole_program->_LinkedShaders[i]);
+
+ ralloc_free(whole_program);
+ _mesa_glsl_release_types();
+ _mesa_glsl_release_functions();
+
+ return status;
+}
diff --git a/mesalib/src/glsl/opt_algebraic.cpp b/mesalib/src/glsl/opt_algebraic.cpp
index 82f90197d..cade9611d 100644
--- a/mesalib/src/glsl/opt_algebraic.cpp
+++ b/mesalib/src/glsl/opt_algebraic.cpp
@@ -1,411 +1,411 @@
-/*
- * 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 opt_algebraic.cpp
- *
- * Takes advantage of association, commutivity, and other algebraic
- * properties to simplify expressions.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class ir_algebraic_visitor : public ir_rvalue_visitor {
-public:
- ir_algebraic_visitor()
- {
- this->progress = false;
- this->mem_ctx = NULL;
- }
-
- virtual ~ir_algebraic_visitor()
- {
- }
-
- ir_rvalue *handle_expression(ir_expression *ir);
- void handle_rvalue(ir_rvalue **rvalue);
- bool reassociate_constant(ir_expression *ir1,
- int const_index,
- ir_constant *constant,
- ir_expression *ir2);
- void reassociate_operands(ir_expression *ir1,
- int op1,
- ir_expression *ir2,
- int op2);
- ir_rvalue *swizzle_if_required(ir_expression *expr,
- ir_rvalue *operand);
-
- void *mem_ctx;
-
- bool progress;
-};
-
-static inline bool
-is_vec_zero(ir_constant *ir)
-{
- return (ir == NULL) ? false : ir->is_zero();
-}
-
-static inline bool
-is_vec_one(ir_constant *ir)
-{
- return (ir == NULL) ? false : ir->is_one();
-}
-
-static void
-update_type(ir_expression *ir)
-{
- if (ir->operands[0]->type->is_vector())
- ir->type = ir->operands[0]->type;
- else
- ir->type = ir->operands[1]->type;
-}
-
-void
-ir_algebraic_visitor::reassociate_operands(ir_expression *ir1,
- int op1,
- ir_expression *ir2,
- int op2)
-{
- ir_rvalue *temp = ir2->operands[op2];
- ir2->operands[op2] = ir1->operands[op1];
- ir1->operands[op1] = temp;
-
- /* Update the type of ir2. The type of ir1 won't have changed --
- * base types matched, and at least one of the operands of the 2
- * binops is still a vector if any of them were.
- */
- update_type(ir2);
-
- this->progress = true;
-}
-
-/**
- * Reassociates a constant down a tree of adds or multiplies.
- *
- * Consider (2 * (a * (b * 0.5))). We want to send up with a * b.
- */
-bool
-ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
- ir_constant *constant,
- ir_expression *ir2)
-{
- if (!ir2 || ir1->operation != ir2->operation)
- return false;
-
- /* Don't want to even think about matrices. */
- if (ir1->operands[0]->type->is_matrix() ||
- ir1->operands[1]->type->is_matrix() ||
- ir2->operands[0]->type->is_matrix() ||
- ir2->operands[1]->type->is_matrix())
- return false;
-
- ir_constant *ir2_const[2];
- ir2_const[0] = ir2->operands[0]->constant_expression_value();
- ir2_const[1] = ir2->operands[1]->constant_expression_value();
-
- if (ir2_const[0] && ir2_const[1])
- return false;
-
- if (ir2_const[0]) {
- reassociate_operands(ir1, const_index, ir2, 1);
- return true;
- } else if (ir2_const[1]) {
- reassociate_operands(ir1, const_index, ir2, 0);
- return true;
- }
-
- if (reassociate_constant(ir1, const_index, constant,
- ir2->operands[0]->as_expression())) {
- update_type(ir2);
- return true;
- }
-
- if (reassociate_constant(ir1, const_index, constant,
- ir2->operands[1]->as_expression())) {
- update_type(ir2);
- return true;
- }
-
- return false;
-}
-
-/* When eliminating an expression and just returning one of its operands,
- * we may need to swizzle that operand out to a vector if the expression was
- * vector type.
- */
-ir_rvalue *
-ir_algebraic_visitor::swizzle_if_required(ir_expression *expr,
- ir_rvalue *operand)
-{
- if (expr->type->is_vector() && operand->type->is_scalar()) {
- return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0,
- expr->type->vector_elements);
- } else
- return operand;
-}
-
-ir_rvalue *
-ir_algebraic_visitor::handle_expression(ir_expression *ir)
-{
- ir_constant *op_const[2] = {NULL, NULL};
- ir_expression *op_expr[2] = {NULL, NULL};
- ir_expression *temp;
- unsigned int i;
-
- assert(ir->get_num_operands() <= 2);
- for (i = 0; i < ir->get_num_operands(); i++) {
- if (ir->operands[i]->type->is_matrix())
- return ir;
-
- op_const[i] = ir->operands[i]->constant_expression_value();
- op_expr[i] = ir->operands[i]->as_expression();
- }
-
- if (this->mem_ctx == NULL)
- this->mem_ctx = talloc_parent(ir);
-
- switch (ir->operation) {
- case ir_unop_logic_not: {
- enum ir_expression_operation new_op = ir_unop_logic_not;
-
- if (op_expr[0] == NULL)
- break;
-
- switch (op_expr[0]->operation) {
- case ir_binop_less: new_op = ir_binop_gequal; break;
- case ir_binop_greater: new_op = ir_binop_lequal; break;
- case ir_binop_lequal: new_op = ir_binop_greater; break;
- case ir_binop_gequal: new_op = ir_binop_less; break;
- case ir_binop_equal: new_op = ir_binop_nequal; break;
- case ir_binop_nequal: new_op = ir_binop_equal; break;
- case ir_binop_all_equal: new_op = ir_binop_any_nequal; break;
- case ir_binop_any_nequal: new_op = ir_binop_all_equal; break;
-
- default:
- /* The default case handler is here to silence a warning from GCC.
- */
- break;
- }
-
- if (new_op != ir_unop_logic_not) {
- this->progress = true;
- return new(mem_ctx) ir_expression(new_op,
- ir->type,
- op_expr[0]->operands[0],
- op_expr[0]->operands[1]);
- }
-
- break;
- }
-
- case ir_binop_add:
- if (is_vec_zero(op_const[0])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[1]);
- }
- if (is_vec_zero(op_const[1])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
- }
-
- /* Reassociate addition of constants so that we can do constant
- * folding.
- */
- if (op_const[0] && !op_const[1])
- reassociate_constant(ir, 0, op_const[0],
- ir->operands[1]->as_expression());
- if (op_const[1] && !op_const[0])
- reassociate_constant(ir, 1, op_const[1],
- ir->operands[0]->as_expression());
- break;
-
- case ir_binop_sub:
- if (is_vec_zero(op_const[0])) {
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_neg,
- ir->operands[1]->type,
- ir->operands[1],
- NULL);
- return swizzle_if_required(ir, temp);
- }
- if (is_vec_zero(op_const[1])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
- }
- break;
-
- case ir_binop_mul:
- if (is_vec_one(op_const[0])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[1]);
- }
- if (is_vec_one(op_const[1])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
- }
-
- if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
- this->progress = true;
- return ir_constant::zero(ir, ir->type);
- }
-
- /* Reassociate multiplication of constants so that we can do
- * constant folding.
- */
- if (op_const[0] && !op_const[1])
- reassociate_constant(ir, 0, op_const[0],
- ir->operands[1]->as_expression());
- if (op_const[1] && !op_const[0])
- reassociate_constant(ir, 1, op_const[1],
- ir->operands[0]->as_expression());
-
- break;
-
- case ir_binop_div:
- if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) {
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_rcp,
- ir->operands[1]->type,
- ir->operands[1],
- NULL);
- return swizzle_if_required(ir, temp);
- }
- if (is_vec_one(op_const[1])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
- }
- break;
-
- case ir_binop_logic_and:
- /* FINISHME: Also simplify (a && a) to (a). */
- if (is_vec_one(op_const[0])) {
- this->progress = true;
- return ir->operands[1];
- } else if (is_vec_one(op_const[1])) {
- this->progress = true;
- return ir->operands[0];
- } else if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
- this->progress = true;
- return ir_constant::zero(mem_ctx, ir->type);
- }
- break;
-
- case ir_binop_logic_xor:
- /* FINISHME: Also simplify (a ^^ a) to (false). */
- if (is_vec_zero(op_const[0])) {
- this->progress = true;
- return ir->operands[1];
- } else if (is_vec_zero(op_const[1])) {
- this->progress = true;
- return ir->operands[0];
- } else if (is_vec_one(op_const[0])) {
- this->progress = true;
- return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
- ir->operands[1], NULL);
- } else if (is_vec_one(op_const[1])) {
- this->progress = true;
- return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
- ir->operands[0], NULL);
- }
- break;
-
- case ir_binop_logic_or:
- /* FINISHME: Also simplify (a || a) to (a). */
- if (is_vec_zero(op_const[0])) {
- this->progress = true;
- return ir->operands[1];
- } else if (is_vec_zero(op_const[1])) {
- this->progress = true;
- return ir->operands[0];
- } else if (is_vec_one(op_const[0]) || is_vec_one(op_const[1])) {
- ir_constant_data data;
-
- for (unsigned i = 0; i < 16; i++)
- data.b[i] = true;
-
- this->progress = true;
- return new(mem_ctx) ir_constant(ir->type, &data);
- }
- break;
-
- case ir_unop_rcp:
- if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) {
- this->progress = true;
- return op_expr[0]->operands[0];
- }
-
- /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
- * backends, except that some backends will have done sqrt ->
- * rcp(rsq(x)) and we don't want to undo it for them.
- */
-
- /* As far as we know, all backends are OK with rsq. */
- if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) {
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_rsq,
- op_expr[0]->operands[0]->type,
- op_expr[0]->operands[0],
- NULL);
- return swizzle_if_required(ir, temp);
- }
-
- break;
-
- default:
- break;
- }
-
- return ir;
-}
-
-void
-ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
- if (!*rvalue)
- return;
-
- ir_expression *expr = (*rvalue)->as_expression();
- if (!expr || expr->operation == ir_quadop_vector)
- return;
-
- *rvalue = handle_expression(expr);
-}
-
-bool
-do_algebraic(exec_list *instructions)
-{
- ir_algebraic_visitor v;
-
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
+/*
+ * 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 opt_algebraic.cpp
+ *
+ * Takes advantage of association, commutivity, and other algebraic
+ * properties to simplify expressions.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class ir_algebraic_visitor : public ir_rvalue_visitor {
+public:
+ ir_algebraic_visitor()
+ {
+ this->progress = false;
+ this->mem_ctx = NULL;
+ }
+
+ virtual ~ir_algebraic_visitor()
+ {
+ }
+
+ ir_rvalue *handle_expression(ir_expression *ir);
+ void handle_rvalue(ir_rvalue **rvalue);
+ bool reassociate_constant(ir_expression *ir1,
+ int const_index,
+ ir_constant *constant,
+ ir_expression *ir2);
+ void reassociate_operands(ir_expression *ir1,
+ int op1,
+ ir_expression *ir2,
+ int op2);
+ ir_rvalue *swizzle_if_required(ir_expression *expr,
+ ir_rvalue *operand);
+
+ void *mem_ctx;
+
+ bool progress;
+};
+
+static inline bool
+is_vec_zero(ir_constant *ir)
+{
+ return (ir == NULL) ? false : ir->is_zero();
+}
+
+static inline bool
+is_vec_one(ir_constant *ir)
+{
+ return (ir == NULL) ? false : ir->is_one();
+}
+
+static void
+update_type(ir_expression *ir)
+{
+ if (ir->operands[0]->type->is_vector())
+ ir->type = ir->operands[0]->type;
+ else
+ ir->type = ir->operands[1]->type;
+}
+
+void
+ir_algebraic_visitor::reassociate_operands(ir_expression *ir1,
+ int op1,
+ ir_expression *ir2,
+ int op2)
+{
+ ir_rvalue *temp = ir2->operands[op2];
+ ir2->operands[op2] = ir1->operands[op1];
+ ir1->operands[op1] = temp;
+
+ /* Update the type of ir2. The type of ir1 won't have changed --
+ * base types matched, and at least one of the operands of the 2
+ * binops is still a vector if any of them were.
+ */
+ update_type(ir2);
+
+ this->progress = true;
+}
+
+/**
+ * Reassociates a constant down a tree of adds or multiplies.
+ *
+ * Consider (2 * (a * (b * 0.5))). We want to send up with a * b.
+ */
+bool
+ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
+ ir_constant *constant,
+ ir_expression *ir2)
+{
+ if (!ir2 || ir1->operation != ir2->operation)
+ return false;
+
+ /* Don't want to even think about matrices. */
+ if (ir1->operands[0]->type->is_matrix() ||
+ ir1->operands[1]->type->is_matrix() ||
+ ir2->operands[0]->type->is_matrix() ||
+ ir2->operands[1]->type->is_matrix())
+ return false;
+
+ ir_constant *ir2_const[2];
+ ir2_const[0] = ir2->operands[0]->constant_expression_value();
+ ir2_const[1] = ir2->operands[1]->constant_expression_value();
+
+ if (ir2_const[0] && ir2_const[1])
+ return false;
+
+ if (ir2_const[0]) {
+ reassociate_operands(ir1, const_index, ir2, 1);
+ return true;
+ } else if (ir2_const[1]) {
+ reassociate_operands(ir1, const_index, ir2, 0);
+ return true;
+ }
+
+ if (reassociate_constant(ir1, const_index, constant,
+ ir2->operands[0]->as_expression())) {
+ update_type(ir2);
+ return true;
+ }
+
+ if (reassociate_constant(ir1, const_index, constant,
+ ir2->operands[1]->as_expression())) {
+ update_type(ir2);
+ return true;
+ }
+
+ return false;
+}
+
+/* When eliminating an expression and just returning one of its operands,
+ * we may need to swizzle that operand out to a vector if the expression was
+ * vector type.
+ */
+ir_rvalue *
+ir_algebraic_visitor::swizzle_if_required(ir_expression *expr,
+ ir_rvalue *operand)
+{
+ if (expr->type->is_vector() && operand->type->is_scalar()) {
+ return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0,
+ expr->type->vector_elements);
+ } else
+ return operand;
+}
+
+ir_rvalue *
+ir_algebraic_visitor::handle_expression(ir_expression *ir)
+{
+ ir_constant *op_const[2] = {NULL, NULL};
+ ir_expression *op_expr[2] = {NULL, NULL};
+ ir_expression *temp;
+ unsigned int i;
+
+ assert(ir->get_num_operands() <= 2);
+ for (i = 0; i < ir->get_num_operands(); i++) {
+ if (ir->operands[i]->type->is_matrix())
+ return ir;
+
+ op_const[i] = ir->operands[i]->constant_expression_value();
+ op_expr[i] = ir->operands[i]->as_expression();
+ }
+
+ if (this->mem_ctx == NULL)
+ this->mem_ctx = ralloc_parent(ir);
+
+ switch (ir->operation) {
+ case ir_unop_logic_not: {
+ enum ir_expression_operation new_op = ir_unop_logic_not;
+
+ if (op_expr[0] == NULL)
+ break;
+
+ switch (op_expr[0]->operation) {
+ case ir_binop_less: new_op = ir_binop_gequal; break;
+ case ir_binop_greater: new_op = ir_binop_lequal; break;
+ case ir_binop_lequal: new_op = ir_binop_greater; break;
+ case ir_binop_gequal: new_op = ir_binop_less; break;
+ case ir_binop_equal: new_op = ir_binop_nequal; break;
+ case ir_binop_nequal: new_op = ir_binop_equal; break;
+ case ir_binop_all_equal: new_op = ir_binop_any_nequal; break;
+ case ir_binop_any_nequal: new_op = ir_binop_all_equal; break;
+
+ default:
+ /* The default case handler is here to silence a warning from GCC.
+ */
+ break;
+ }
+
+ if (new_op != ir_unop_logic_not) {
+ this->progress = true;
+ return new(mem_ctx) ir_expression(new_op,
+ ir->type,
+ op_expr[0]->operands[0],
+ op_expr[0]->operands[1]);
+ }
+
+ break;
+ }
+
+ case ir_binop_add:
+ if (is_vec_zero(op_const[0])) {
+ this->progress = true;
+ return swizzle_if_required(ir, ir->operands[1]);
+ }
+ if (is_vec_zero(op_const[1])) {
+ this->progress = true;
+ return swizzle_if_required(ir, ir->operands[0]);
+ }
+
+ /* Reassociate addition of constants so that we can do constant
+ * folding.
+ */
+ if (op_const[0] && !op_const[1])
+ reassociate_constant(ir, 0, op_const[0],
+ ir->operands[1]->as_expression());
+ if (op_const[1] && !op_const[0])
+ reassociate_constant(ir, 1, op_const[1],
+ ir->operands[0]->as_expression());
+ break;
+
+ case ir_binop_sub:
+ if (is_vec_zero(op_const[0])) {
+ this->progress = true;
+ temp = new(mem_ctx) ir_expression(ir_unop_neg,
+ ir->operands[1]->type,
+ ir->operands[1],
+ NULL);
+ return swizzle_if_required(ir, temp);
+ }
+ if (is_vec_zero(op_const[1])) {
+ this->progress = true;
+ return swizzle_if_required(ir, ir->operands[0]);
+ }
+ break;
+
+ case ir_binop_mul:
+ if (is_vec_one(op_const[0])) {
+ this->progress = true;
+ return swizzle_if_required(ir, ir->operands[1]);
+ }
+ if (is_vec_one(op_const[1])) {
+ this->progress = true;
+ return swizzle_if_required(ir, ir->operands[0]);
+ }
+
+ if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
+ this->progress = true;
+ return ir_constant::zero(ir, ir->type);
+ }
+
+ /* Reassociate multiplication of constants so that we can do
+ * constant folding.
+ */
+ if (op_const[0] && !op_const[1])
+ reassociate_constant(ir, 0, op_const[0],
+ ir->operands[1]->as_expression());
+ if (op_const[1] && !op_const[0])
+ reassociate_constant(ir, 1, op_const[1],
+ ir->operands[0]->as_expression());
+
+ break;
+
+ case ir_binop_div:
+ if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) {
+ this->progress = true;
+ temp = new(mem_ctx) ir_expression(ir_unop_rcp,
+ ir->operands[1]->type,
+ ir->operands[1],
+ NULL);
+ return swizzle_if_required(ir, temp);
+ }
+ if (is_vec_one(op_const[1])) {
+ this->progress = true;
+ return swizzle_if_required(ir, ir->operands[0]);
+ }
+ break;
+
+ case ir_binop_logic_and:
+ /* FINISHME: Also simplify (a && a) to (a). */
+ if (is_vec_one(op_const[0])) {
+ this->progress = true;
+ return ir->operands[1];
+ } else if (is_vec_one(op_const[1])) {
+ this->progress = true;
+ return ir->operands[0];
+ } else if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
+ this->progress = true;
+ return ir_constant::zero(mem_ctx, ir->type);
+ }
+ break;
+
+ case ir_binop_logic_xor:
+ /* FINISHME: Also simplify (a ^^ a) to (false). */
+ if (is_vec_zero(op_const[0])) {
+ this->progress = true;
+ return ir->operands[1];
+ } else if (is_vec_zero(op_const[1])) {
+ this->progress = true;
+ return ir->operands[0];
+ } else if (is_vec_one(op_const[0])) {
+ this->progress = true;
+ return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
+ ir->operands[1], NULL);
+ } else if (is_vec_one(op_const[1])) {
+ this->progress = true;
+ return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
+ ir->operands[0], NULL);
+ }
+ break;
+
+ case ir_binop_logic_or:
+ /* FINISHME: Also simplify (a || a) to (a). */
+ if (is_vec_zero(op_const[0])) {
+ this->progress = true;
+ return ir->operands[1];
+ } else if (is_vec_zero(op_const[1])) {
+ this->progress = true;
+ return ir->operands[0];
+ } else if (is_vec_one(op_const[0]) || is_vec_one(op_const[1])) {
+ ir_constant_data data;
+
+ for (unsigned i = 0; i < 16; i++)
+ data.b[i] = true;
+
+ this->progress = true;
+ return new(mem_ctx) ir_constant(ir->type, &data);
+ }
+ break;
+
+ case ir_unop_rcp:
+ if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) {
+ this->progress = true;
+ return op_expr[0]->operands[0];
+ }
+
+ /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
+ * backends, except that some backends will have done sqrt ->
+ * rcp(rsq(x)) and we don't want to undo it for them.
+ */
+
+ /* As far as we know, all backends are OK with rsq. */
+ if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) {
+ this->progress = true;
+ temp = new(mem_ctx) ir_expression(ir_unop_rsq,
+ op_expr[0]->operands[0]->type,
+ op_expr[0]->operands[0],
+ NULL);
+ return swizzle_if_required(ir, temp);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return ir;
+}
+
+void
+ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+ if (!*rvalue)
+ return;
+
+ ir_expression *expr = (*rvalue)->as_expression();
+ if (!expr || expr->operation == ir_quadop_vector)
+ return;
+
+ *rvalue = handle_expression(expr);
+}
+
+bool
+do_algebraic(exec_list *instructions)
+{
+ ir_algebraic_visitor v;
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/opt_constant_folding.cpp b/mesalib/src/glsl/opt_constant_folding.cpp
index d2234b354..599b21525 100644
--- a/mesalib/src/glsl/opt_constant_folding.cpp
+++ b/mesalib/src/glsl/opt_constant_folding.cpp
@@ -1,147 +1,147 @@
-/*
- * 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 opt_constant_folding.cpp
- * Replace constant-valued expressions with references to constant values.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class ir_constant_folding_visitor : public ir_rvalue_visitor {
-public:
- ir_constant_folding_visitor()
- {
- this->progress = false;
- }
-
- virtual ~ir_constant_folding_visitor()
- {
- /* empty */
- }
-
- virtual ir_visitor_status visit_enter(ir_assignment *ir);
- virtual ir_visitor_status visit_enter(ir_call *ir);
-
- virtual void handle_rvalue(ir_rvalue **rvalue);
-
- bool progress;
-};
-
-void
-ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
- if (*rvalue == NULL || (*rvalue)->ir_type == ir_type_constant)
- return;
-
- /* Note that we do rvalue visitoring on leaving. So if an
- * expression has a non-constant operand, no need to go looking
- * down it to find if it's constant. This cuts the time of this
- * pass down drastically.
- */
- ir_expression *expr = (*rvalue)->as_expression();
- if (expr) {
- for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
- if (!expr->operands[i]->as_constant())
- return;
- }
- }
-
- ir_constant *constant = (*rvalue)->constant_expression_value();
- if (constant) {
- *rvalue = constant;
- this->progress = true;
- } else {
- (*rvalue)->accept(this);
- }
-}
-
-ir_visitor_status
-ir_constant_folding_visitor::visit_enter(ir_assignment *ir)
-{
- ir->rhs->accept(this);
- handle_rvalue(&ir->rhs);
-
- if (ir->condition) {
- ir->condition->accept(this);
- handle_rvalue(&ir->condition);
-
- ir_constant *const_val = ir->condition->as_constant();
- /* If the condition is constant, either remove the condition or
- * remove the never-executed assignment.
- */
- if (const_val) {
- if (const_val->value.b[0])
- ir->condition = NULL;
- else
- ir->remove();
- this->progress = true;
- }
- }
-
- /* Don't descend into the LHS because we want it to stay as a
- * variable dereference. FINISHME: We probably should to get array
- * indices though.
- */
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_constant_folding_visitor::visit_enter(ir_call *ir)
-{
- exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_rvalue *param_rval = (ir_rvalue *)iter.get();
- ir_variable *sig_param = (ir_variable *)sig_iter.get();
-
- if (sig_param->mode == ir_var_in) {
- ir_rvalue *new_param = param_rval;
-
- handle_rvalue(&new_param);
- if (new_param != param_rval) {
- param_rval->replace_with(new_param);
- }
- }
- sig_iter.next();
- }
-
- return visit_continue_with_parent;
-}
-
-bool
-do_constant_folding(exec_list *instructions)
-{
- ir_constant_folding_visitor constant_folding;
-
- visit_list_elements(&constant_folding, instructions);
-
- return constant_folding.progress;
-}
+/*
+ * 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 opt_constant_folding.cpp
+ * Replace constant-valued expressions with references to constant values.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class ir_constant_folding_visitor : public ir_rvalue_visitor {
+public:
+ ir_constant_folding_visitor()
+ {
+ this->progress = false;
+ }
+
+ virtual ~ir_constant_folding_visitor()
+ {
+ /* empty */
+ }
+
+ virtual ir_visitor_status visit_enter(ir_assignment *ir);
+ virtual ir_visitor_status visit_enter(ir_call *ir);
+
+ virtual void handle_rvalue(ir_rvalue **rvalue);
+
+ bool progress;
+};
+
+void
+ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+ if (*rvalue == NULL || (*rvalue)->ir_type == ir_type_constant)
+ return;
+
+ /* Note that we do rvalue visitoring on leaving. So if an
+ * expression has a non-constant operand, no need to go looking
+ * down it to find if it's constant. This cuts the time of this
+ * pass down drastically.
+ */
+ ir_expression *expr = (*rvalue)->as_expression();
+ if (expr) {
+ for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
+ if (!expr->operands[i]->as_constant())
+ return;
+ }
+ }
+
+ ir_constant *constant = (*rvalue)->constant_expression_value();
+ if (constant) {
+ *rvalue = constant;
+ this->progress = true;
+ } else {
+ (*rvalue)->accept(this);
+ }
+}
+
+ir_visitor_status
+ir_constant_folding_visitor::visit_enter(ir_assignment *ir)
+{
+ ir->rhs->accept(this);
+ handle_rvalue(&ir->rhs);
+
+ if (ir->condition) {
+ ir->condition->accept(this);
+ handle_rvalue(&ir->condition);
+
+ ir_constant *const_val = ir->condition->as_constant();
+ /* If the condition is constant, either remove the condition or
+ * remove the never-executed assignment.
+ */
+ if (const_val) {
+ if (const_val->value.b[0])
+ ir->condition = NULL;
+ else
+ ir->remove();
+ this->progress = true;
+ }
+ }
+
+ /* Don't descend into the LHS because we want it to stay as a
+ * variable dereference. FINISHME: We probably should to get array
+ * indices though.
+ */
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_constant_folding_visitor::visit_enter(ir_call *ir)
+{
+ exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *sig_param = (ir_variable *)sig_iter.get();
+
+ if (sig_param->mode == ir_var_in || sig_param->mode == ir_var_const_in) {
+ ir_rvalue *new_param = param_rval;
+
+ handle_rvalue(&new_param);
+ if (new_param != param_rval) {
+ param_rval->replace_with(new_param);
+ }
+ }
+ sig_iter.next();
+ }
+
+ return visit_continue_with_parent;
+}
+
+bool
+do_constant_folding(exec_list *instructions)
+{
+ ir_constant_folding_visitor constant_folding;
+
+ visit_list_elements(&constant_folding, instructions);
+
+ return constant_folding.progress;
+}
diff --git a/mesalib/src/glsl/opt_constant_propagation.cpp b/mesalib/src/glsl/opt_constant_propagation.cpp
index db797a85f..e1f68892f 100644
--- a/mesalib/src/glsl/opt_constant_propagation.cpp
+++ b/mesalib/src/glsl/opt_constant_propagation.cpp
@@ -1,437 +1,437 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * constant of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, constant, 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 constantright 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 CONSTANTRIGHT 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 opt_constant_propagation.cpp
- *
- * Tracks assignments of constants to channels of variables, and
- * usage of those constant channels with direct usage of the constants.
- *
- * This can lead to constant folding and algebraic optimizations in
- * those later expressions, while causing no increase in instruction
- * count (due to constants being generally free to load from a
- * constant push buffer or as instruction immediate values) and
- * possibly reducing register pressure.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "ir_basic_block.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-class acp_entry : public exec_node
-{
-public:
- acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant)
- {
- assert(var);
- assert(constant);
- this->var = var;
- this->write_mask = write_mask;
- this->constant = constant;
- }
-
- ir_variable *var;
- ir_constant *constant;
- unsigned write_mask;
-};
-
-
-class kill_entry : public exec_node
-{
-public:
- kill_entry(ir_variable *var, unsigned write_mask)
- {
- assert(var);
- this->var = var;
- this->write_mask = write_mask;
- }
-
- ir_variable *var;
- unsigned write_mask;
-};
-
-class ir_constant_propagation_visitor : public ir_rvalue_visitor {
-public:
- ir_constant_propagation_visitor()
- {
- progress = false;
- mem_ctx = talloc_new(0);
- this->acp = new(mem_ctx) exec_list;
- this->kills = new(mem_ctx) exec_list;
- }
- ~ir_constant_propagation_visitor()
- {
- talloc_free(mem_ctx);
- }
-
- virtual ir_visitor_status visit_enter(class ir_loop *);
- virtual ir_visitor_status visit_enter(class ir_function_signature *);
- virtual ir_visitor_status visit_enter(class ir_function *);
- virtual ir_visitor_status visit_leave(class ir_assignment *);
- virtual ir_visitor_status visit_enter(class ir_call *);
- virtual ir_visitor_status visit_enter(class ir_if *);
-
- void add_constant(ir_assignment *ir);
- void kill(ir_variable *ir, unsigned write_mask);
- void handle_if_block(exec_list *instructions);
- void handle_rvalue(ir_rvalue **rvalue);
-
- /** List of acp_entry: The available constants to propagate */
- exec_list *acp;
-
- /**
- * List of kill_entry: The masks of variables whose values were
- * killed in this block.
- */
- exec_list *kills;
-
- bool progress;
-
- bool killed_all;
-
- void *mem_ctx;
-};
-
-
-void
-ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
- if (this->in_assignee || !*rvalue)
- return;
-
- const glsl_type *type = (*rvalue)->type;
- if (!type->is_scalar() && !type->is_vector())
- return;
-
- ir_swizzle *swiz = NULL;
- ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
- if (!deref) {
- swiz = (*rvalue)->as_swizzle();
- if (!swiz)
- return;
-
- deref = swiz->val->as_dereference_variable();
- if (!deref)
- return;
- }
-
- ir_constant_data data;
- memset(&data, 0, sizeof(data));
-
- for (unsigned int i = 0; i < type->components(); i++) {
- int channel;
- acp_entry *found = NULL;
-
- if (swiz) {
- switch (i) {
- case 0: channel = swiz->mask.x; break;
- case 1: channel = swiz->mask.y; break;
- case 2: channel = swiz->mask.z; break;
- case 3: channel = swiz->mask.w; break;
- default: assert(!"shouldn't be reached"); channel = 0; break;
- }
- } else {
- channel = i;
- }
-
- foreach_iter(exec_list_iterator, iter, *this->acp) {
- acp_entry *entry = (acp_entry *)iter.get();
- if (entry->var == deref->var && entry->write_mask & (1 << channel)) {
- found = entry;
- break;
- }
- }
-
- if (!found)
- return;
-
- int rhs_channel = 0;
- for (int j = 0; j < 4; j++) {
- if (j == channel)
- break;
- if (found->write_mask & (1 << j))
- rhs_channel++;
- }
-
- switch (type->base_type) {
- case GLSL_TYPE_FLOAT:
- data.f[i] = found->constant->value.f[rhs_channel];
- break;
- case GLSL_TYPE_INT:
- data.i[i] = found->constant->value.i[rhs_channel];
- break;
- case GLSL_TYPE_UINT:
- data.u[i] = found->constant->value.u[rhs_channel];
- break;
- case GLSL_TYPE_BOOL:
- data.b[i] = found->constant->value.b[rhs_channel];
- break;
- default:
- assert(!"not reached");
- break;
- }
- }
-
- *rvalue = new(talloc_parent(deref)) ir_constant(type, &data);
- this->progress = true;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
-{
- /* Treat entry into a function signature as a completely separate
- * block. Any instructions at global scope will be shuffled into
- * main() at link time, so they're irrelevant to us.
- */
- exec_list *orig_acp = this->acp;
- exec_list *orig_kills = this->kills;
- bool orig_killed_all = this->killed_all;
-
- this->acp = new(mem_ctx) exec_list;
- this->kills = new(mem_ctx) exec_list;
- this->killed_all = false;
-
- visit_list_elements(this, &ir->body);
-
- this->kills = orig_kills;
- this->acp = orig_acp;
- this->killed_all = orig_killed_all;
-
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_leave(ir_assignment *ir)
-{
- if (this->in_assignee)
- return visit_continue;
-
- kill(ir->lhs->variable_referenced(), ir->write_mask);
-
- add_constant(ir);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_function *ir)
-{
- (void) ir;
- return visit_continue;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_call *ir)
-{
- /* Do constant propagation on call parameters, but skip any out params */
- exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
- foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
- ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
- ir_rvalue *param = (ir_rvalue *)iter.get();
- if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
- ir_rvalue *new_param = param;
- handle_rvalue(&new_param);
- if (new_param != param)
- param->replace_with(new_param);
- else
- param->accept(this);
- }
- sig_param_iter.next();
- }
-
- /* Since we're unlinked, we don't (necssarily) know the side effects of
- * this call. So kill all copies.
- */
- acp->make_empty();
- this->killed_all = true;
-
- return visit_continue_with_parent;
-}
-
-void
-ir_constant_propagation_visitor::handle_if_block(exec_list *instructions)
-{
- exec_list *orig_acp = this->acp;
- exec_list *orig_kills = this->kills;
- bool orig_killed_all = this->killed_all;
-
- this->acp = new(mem_ctx) exec_list;
- this->kills = new(mem_ctx) exec_list;
- this->killed_all = false;
-
- /* Populate the initial acp with a constant of the original */
- foreach_iter(exec_list_iterator, iter, *orig_acp) {
- acp_entry *a = (acp_entry *)iter.get();
- this->acp->push_tail(new(this->mem_ctx) acp_entry(a->var, a->write_mask,
- a->constant));
- }
-
- visit_list_elements(this, instructions);
-
- if (this->killed_all) {
- orig_acp->make_empty();
- }
-
- exec_list *new_kills = this->kills;
- this->kills = orig_kills;
- this->acp = orig_acp;
- this->killed_all = this->killed_all || orig_killed_all;
-
- foreach_iter(exec_list_iterator, iter, *new_kills) {
- kill_entry *k = (kill_entry *)iter.get();
- kill(k->var, k->write_mask);
- }
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_if *ir)
-{
- ir->condition->accept(this);
- handle_rvalue(&ir->condition);
-
- handle_if_block(&ir->then_instructions);
- handle_if_block(&ir->else_instructions);
-
- /* handle_if_block() already descended into the children. */
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_loop *ir)
-{
- exec_list *orig_acp = this->acp;
- exec_list *orig_kills = this->kills;
- bool orig_killed_all = this->killed_all;
-
- /* FINISHME: For now, the initial acp for loops is totally empty.
- * We could go through once, then go through again with the acp
- * cloned minus the killed entries after the first run through.
- */
- this->acp = new(mem_ctx) exec_list;
- this->kills = new(mem_ctx) exec_list;
- this->killed_all = false;
-
- visit_list_elements(this, &ir->body_instructions);
-
- if (this->killed_all) {
- orig_acp->make_empty();
- }
-
- exec_list *new_kills = this->kills;
- this->kills = orig_kills;
- this->acp = orig_acp;
- this->killed_all = this->killed_all || orig_killed_all;
-
- foreach_iter(exec_list_iterator, iter, *new_kills) {
- kill_entry *k = (kill_entry *)iter.get();
- kill(k->var, k->write_mask);
- }
-
- /* already descended into the children. */
- return visit_continue_with_parent;
-}
-
-void
-ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask)
-{
- assert(var != NULL);
-
- /* We don't track non-vectors. */
- if (!var->type->is_vector() && !var->type->is_scalar())
- return;
-
- /* Remove any entries currently in the ACP for this kill. */
- foreach_iter(exec_list_iterator, iter, *this->acp) {
- acp_entry *entry = (acp_entry *)iter.get();
-
- if (entry->var == var) {
- entry->write_mask &= ~write_mask;
- if (entry->write_mask == 0)
- entry->remove();
- }
- }
-
- /* Add this writemask of the variable to the list of killed
- * variables in this block.
- */
- foreach_iter(exec_list_iterator, iter, *this->kills) {
- kill_entry *entry = (kill_entry *)iter.get();
-
- if (entry->var == var) {
- entry->write_mask |= write_mask;
- return;
- }
- }
- /* Not already in the list. Make new entry. */
- this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask));
-}
-
-/**
- * Adds an entry to the available constant list if it's a plain assignment
- * of a variable to a variable.
- */
-void
-ir_constant_propagation_visitor::add_constant(ir_assignment *ir)
-{
- acp_entry *entry;
-
- if (ir->condition) {
- ir_constant *condition = ir->condition->as_constant();
- if (!condition || !condition->value.b[0])
- return;
- }
-
- if (!ir->write_mask)
- return;
-
- ir_dereference_variable *deref = ir->lhs->as_dereference_variable();
- ir_constant *constant = ir->rhs->as_constant();
-
- if (!deref || !constant)
- return;
-
- /* Only do constant propagation on vectors. Constant matrices,
- * arrays, or structures would require more work elsewhere.
- */
- if (!deref->var->type->is_vector() && !deref->var->type->is_scalar())
- return;
-
- entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant);
- this->acp->push_tail(entry);
-}
-
-/**
- * Does a constant propagation pass on the code present in the instruction stream.
- */
-bool
-do_constant_propagation(exec_list *instructions)
-{
- ir_constant_propagation_visitor v;
-
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * constant of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, constant, 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 constantright 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 CONSTANTRIGHT 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 opt_constant_propagation.cpp
+ *
+ * Tracks assignments of constants to channels of variables, and
+ * usage of those constant channels with direct usage of the constants.
+ *
+ * This can lead to constant folding and algebraic optimizations in
+ * those later expressions, while causing no increase in instruction
+ * count (due to constants being generally free to load from a
+ * constant push buffer or as instruction immediate values) and
+ * possibly reducing register pressure.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_basic_block.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+class acp_entry : public exec_node
+{
+public:
+ acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant)
+ {
+ assert(var);
+ assert(constant);
+ this->var = var;
+ this->write_mask = write_mask;
+ this->constant = constant;
+ }
+
+ ir_variable *var;
+ ir_constant *constant;
+ unsigned write_mask;
+};
+
+
+class kill_entry : public exec_node
+{
+public:
+ kill_entry(ir_variable *var, unsigned write_mask)
+ {
+ assert(var);
+ this->var = var;
+ this->write_mask = write_mask;
+ }
+
+ ir_variable *var;
+ unsigned write_mask;
+};
+
+class ir_constant_propagation_visitor : public ir_rvalue_visitor {
+public:
+ ir_constant_propagation_visitor()
+ {
+ progress = false;
+ mem_ctx = ralloc_context(0);
+ this->acp = new(mem_ctx) exec_list;
+ this->kills = new(mem_ctx) exec_list;
+ }
+ ~ir_constant_propagation_visitor()
+ {
+ ralloc_free(mem_ctx);
+ }
+
+ virtual ir_visitor_status visit_enter(class ir_loop *);
+ virtual ir_visitor_status visit_enter(class ir_function_signature *);
+ virtual ir_visitor_status visit_enter(class ir_function *);
+ virtual ir_visitor_status visit_leave(class ir_assignment *);
+ virtual ir_visitor_status visit_enter(class ir_call *);
+ virtual ir_visitor_status visit_enter(class ir_if *);
+
+ void add_constant(ir_assignment *ir);
+ void kill(ir_variable *ir, unsigned write_mask);
+ void handle_if_block(exec_list *instructions);
+ void handle_rvalue(ir_rvalue **rvalue);
+
+ /** List of acp_entry: The available constants to propagate */
+ exec_list *acp;
+
+ /**
+ * List of kill_entry: The masks of variables whose values were
+ * killed in this block.
+ */
+ exec_list *kills;
+
+ bool progress;
+
+ bool killed_all;
+
+ void *mem_ctx;
+};
+
+
+void
+ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+ if (this->in_assignee || !*rvalue)
+ return;
+
+ const glsl_type *type = (*rvalue)->type;
+ if (!type->is_scalar() && !type->is_vector())
+ return;
+
+ ir_swizzle *swiz = NULL;
+ ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
+ if (!deref) {
+ swiz = (*rvalue)->as_swizzle();
+ if (!swiz)
+ return;
+
+ deref = swiz->val->as_dereference_variable();
+ if (!deref)
+ return;
+ }
+
+ ir_constant_data data;
+ memset(&data, 0, sizeof(data));
+
+ for (unsigned int i = 0; i < type->components(); i++) {
+ int channel;
+ acp_entry *found = NULL;
+
+ if (swiz) {
+ switch (i) {
+ case 0: channel = swiz->mask.x; break;
+ case 1: channel = swiz->mask.y; break;
+ case 2: channel = swiz->mask.z; break;
+ case 3: channel = swiz->mask.w; break;
+ default: assert(!"shouldn't be reached"); channel = 0; break;
+ }
+ } else {
+ channel = i;
+ }
+
+ foreach_iter(exec_list_iterator, iter, *this->acp) {
+ acp_entry *entry = (acp_entry *)iter.get();
+ if (entry->var == deref->var && entry->write_mask & (1 << channel)) {
+ found = entry;
+ break;
+ }
+ }
+
+ if (!found)
+ return;
+
+ int rhs_channel = 0;
+ for (int j = 0; j < 4; j++) {
+ if (j == channel)
+ break;
+ if (found->write_mask & (1 << j))
+ rhs_channel++;
+ }
+
+ switch (type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ data.f[i] = found->constant->value.f[rhs_channel];
+ break;
+ case GLSL_TYPE_INT:
+ data.i[i] = found->constant->value.i[rhs_channel];
+ break;
+ case GLSL_TYPE_UINT:
+ data.u[i] = found->constant->value.u[rhs_channel];
+ break;
+ case GLSL_TYPE_BOOL:
+ data.b[i] = found->constant->value.b[rhs_channel];
+ break;
+ default:
+ assert(!"not reached");
+ break;
+ }
+ }
+
+ *rvalue = new(ralloc_parent(deref)) ir_constant(type, &data);
+ this->progress = true;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
+{
+ /* Treat entry into a function signature as a completely separate
+ * block. Any instructions at global scope will be shuffled into
+ * main() at link time, so they're irrelevant to us.
+ */
+ exec_list *orig_acp = this->acp;
+ exec_list *orig_kills = this->kills;
+ bool orig_killed_all = this->killed_all;
+
+ this->acp = new(mem_ctx) exec_list;
+ this->kills = new(mem_ctx) exec_list;
+ this->killed_all = false;
+
+ visit_list_elements(this, &ir->body);
+
+ this->kills = orig_kills;
+ this->acp = orig_acp;
+ this->killed_all = orig_killed_all;
+
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_leave(ir_assignment *ir)
+{
+ if (this->in_assignee)
+ return visit_continue;
+
+ kill(ir->lhs->variable_referenced(), ir->write_mask);
+
+ add_constant(ir);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_function *ir)
+{
+ (void) ir;
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_call *ir)
+{
+ /* Do constant propagation on call parameters, but skip any out params */
+ exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
+ ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
+ ir_rvalue *param = (ir_rvalue *)iter.get();
+ if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
+ ir_rvalue *new_param = param;
+ handle_rvalue(&new_param);
+ if (new_param != param)
+ param->replace_with(new_param);
+ else
+ param->accept(this);
+ }
+ sig_param_iter.next();
+ }
+
+ /* Since we're unlinked, we don't (necssarily) know the side effects of
+ * this call. So kill all copies.
+ */
+ acp->make_empty();
+ this->killed_all = true;
+
+ return visit_continue_with_parent;
+}
+
+void
+ir_constant_propagation_visitor::handle_if_block(exec_list *instructions)
+{
+ exec_list *orig_acp = this->acp;
+ exec_list *orig_kills = this->kills;
+ bool orig_killed_all = this->killed_all;
+
+ this->acp = new(mem_ctx) exec_list;
+ this->kills = new(mem_ctx) exec_list;
+ this->killed_all = false;
+
+ /* Populate the initial acp with a constant of the original */
+ foreach_iter(exec_list_iterator, iter, *orig_acp) {
+ acp_entry *a = (acp_entry *)iter.get();
+ this->acp->push_tail(new(this->mem_ctx) acp_entry(a->var, a->write_mask,
+ a->constant));
+ }
+
+ visit_list_elements(this, instructions);
+
+ if (this->killed_all) {
+ orig_acp->make_empty();
+ }
+
+ exec_list *new_kills = this->kills;
+ this->kills = orig_kills;
+ this->acp = orig_acp;
+ this->killed_all = this->killed_all || orig_killed_all;
+
+ foreach_iter(exec_list_iterator, iter, *new_kills) {
+ kill_entry *k = (kill_entry *)iter.get();
+ kill(k->var, k->write_mask);
+ }
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_if *ir)
+{
+ ir->condition->accept(this);
+ handle_rvalue(&ir->condition);
+
+ handle_if_block(&ir->then_instructions);
+ handle_if_block(&ir->else_instructions);
+
+ /* handle_if_block() already descended into the children. */
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_loop *ir)
+{
+ exec_list *orig_acp = this->acp;
+ exec_list *orig_kills = this->kills;
+ bool orig_killed_all = this->killed_all;
+
+ /* FINISHME: For now, the initial acp for loops is totally empty.
+ * We could go through once, then go through again with the acp
+ * cloned minus the killed entries after the first run through.
+ */
+ this->acp = new(mem_ctx) exec_list;
+ this->kills = new(mem_ctx) exec_list;
+ this->killed_all = false;
+
+ visit_list_elements(this, &ir->body_instructions);
+
+ if (this->killed_all) {
+ orig_acp->make_empty();
+ }
+
+ exec_list *new_kills = this->kills;
+ this->kills = orig_kills;
+ this->acp = orig_acp;
+ this->killed_all = this->killed_all || orig_killed_all;
+
+ foreach_iter(exec_list_iterator, iter, *new_kills) {
+ kill_entry *k = (kill_entry *)iter.get();
+ kill(k->var, k->write_mask);
+ }
+
+ /* already descended into the children. */
+ return visit_continue_with_parent;
+}
+
+void
+ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask)
+{
+ assert(var != NULL);
+
+ /* We don't track non-vectors. */
+ if (!var->type->is_vector() && !var->type->is_scalar())
+ return;
+
+ /* Remove any entries currently in the ACP for this kill. */
+ foreach_iter(exec_list_iterator, iter, *this->acp) {
+ acp_entry *entry = (acp_entry *)iter.get();
+
+ if (entry->var == var) {
+ entry->write_mask &= ~write_mask;
+ if (entry->write_mask == 0)
+ entry->remove();
+ }
+ }
+
+ /* Add this writemask of the variable to the list of killed
+ * variables in this block.
+ */
+ foreach_iter(exec_list_iterator, iter, *this->kills) {
+ kill_entry *entry = (kill_entry *)iter.get();
+
+ if (entry->var == var) {
+ entry->write_mask |= write_mask;
+ return;
+ }
+ }
+ /* Not already in the list. Make new entry. */
+ this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask));
+}
+
+/**
+ * Adds an entry to the available constant list if it's a plain assignment
+ * of a variable to a variable.
+ */
+void
+ir_constant_propagation_visitor::add_constant(ir_assignment *ir)
+{
+ acp_entry *entry;
+
+ if (ir->condition) {
+ ir_constant *condition = ir->condition->as_constant();
+ if (!condition || !condition->value.b[0])
+ return;
+ }
+
+ if (!ir->write_mask)
+ return;
+
+ ir_dereference_variable *deref = ir->lhs->as_dereference_variable();
+ ir_constant *constant = ir->rhs->as_constant();
+
+ if (!deref || !constant)
+ return;
+
+ /* Only do constant propagation on vectors. Constant matrices,
+ * arrays, or structures would require more work elsewhere.
+ */
+ if (!deref->var->type->is_vector() && !deref->var->type->is_scalar())
+ return;
+
+ entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant);
+ this->acp->push_tail(entry);
+}
+
+/**
+ * Does a constant propagation pass on the code present in the instruction stream.
+ */
+bool
+do_constant_propagation(exec_list *instructions)
+{
+ ir_constant_propagation_visitor v;
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/opt_copy_propagation.cpp b/mesalib/src/glsl/opt_copy_propagation.cpp
index 088c4bdbc..4ab23bf9b 100644
--- a/mesalib/src/glsl/opt_copy_propagation.cpp
+++ b/mesalib/src/glsl/opt_copy_propagation.cpp
@@ -1,348 +1,348 @@
-/*
- * 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 opt_copy_propagation.cpp
- *
- * Moves usage of recently-copied variables to the previous copy of
- * the variable.
- *
- * This should reduce the number of MOV instructions in the generated
- * programs unless copy propagation is also done on the LIR, and may
- * help anyway by triggering other optimizations that live in the HIR.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_basic_block.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-class acp_entry : public exec_node
-{
-public:
- acp_entry(ir_variable *lhs, ir_variable *rhs)
- {
- assert(lhs);
- assert(rhs);
- this->lhs = lhs;
- this->rhs = rhs;
- }
-
- ir_variable *lhs;
- ir_variable *rhs;
-};
-
-
-class kill_entry : public exec_node
-{
-public:
- kill_entry(ir_variable *var)
- {
- assert(var);
- this->var = var;
- }
-
- ir_variable *var;
-};
-
-class ir_copy_propagation_visitor : public ir_hierarchical_visitor {
-public:
- ir_copy_propagation_visitor()
- {
- progress = false;
- mem_ctx = talloc_new(0);
- this->acp = new(mem_ctx) exec_list;
- this->kills = new(mem_ctx) exec_list;
- }
- ~ir_copy_propagation_visitor()
- {
- talloc_free(mem_ctx);
- }
-
- virtual ir_visitor_status visit(class ir_dereference_variable *);
- virtual ir_visitor_status visit_enter(class ir_loop *);
- virtual ir_visitor_status visit_enter(class ir_function_signature *);
- virtual ir_visitor_status visit_enter(class ir_function *);
- virtual ir_visitor_status visit_leave(class ir_assignment *);
- virtual ir_visitor_status visit_enter(class ir_call *);
- virtual ir_visitor_status visit_enter(class ir_if *);
-
- void add_copy(ir_assignment *ir);
- void kill(ir_variable *ir);
- void handle_if_block(exec_list *instructions);
-
- /** List of acp_entry: The available copies to propagate */
- exec_list *acp;
- /**
- * List of kill_entry: The variables whose values were killed in this
- * block.
- */
- exec_list *kills;
-
- bool progress;
-
- bool killed_all;
-
- void *mem_ctx;
-};
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_function_signature *ir)
-{
- /* Treat entry into a function signature as a completely separate
- * block. Any instructions at global scope will be shuffled into
- * main() at link time, so they're irrelevant to us.
- */
- exec_list *orig_acp = this->acp;
- exec_list *orig_kills = this->kills;
- bool orig_killed_all = this->killed_all;
-
- this->acp = new(mem_ctx) exec_list;
- this->kills = new(mem_ctx) exec_list;
- this->killed_all = false;
-
- visit_list_elements(this, &ir->body);
-
- this->kills = orig_kills;
- this->acp = orig_acp;
- this->killed_all = orig_killed_all;
-
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_leave(ir_assignment *ir)
-{
- kill(ir->lhs->variable_referenced());
-
- add_copy(ir);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_function *ir)
-{
- (void) ir;
- return visit_continue;
-}
-
-/**
- * Replaces dereferences of ACP RHS variables with ACP LHS variables.
- *
- * This is where the actual copy propagation occurs. Note that the
- * rewriting of ir_dereference means that the ir_dereference instance
- * must not be shared by multiple IR operations!
- */
-ir_visitor_status
-ir_copy_propagation_visitor::visit(ir_dereference_variable *ir)
-{
- if (this->in_assignee)
- return visit_continue;
-
- ir_variable *var = ir->var;
-
- foreach_iter(exec_list_iterator, iter, *this->acp) {
- acp_entry *entry = (acp_entry *)iter.get();
-
- if (var == entry->lhs) {
- ir->var = entry->rhs;
- this->progress = true;
- break;
- }
- }
-
- return visit_continue;
-}
-
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_call *ir)
-{
- /* Do copy propagation on call parameters, but skip any out params */
- exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
- foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
- ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
- ir_instruction *ir = (ir_instruction *)iter.get();
- if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
- ir->accept(this);
- }
- sig_param_iter.next();
- }
-
- /* Since we're unlinked, we don't (necssarily) know the side effects of
- * this call. So kill all copies.
- */
- acp->make_empty();
- this->killed_all = true;
-
- return visit_continue_with_parent;
-}
-
-void
-ir_copy_propagation_visitor::handle_if_block(exec_list *instructions)
-{
- exec_list *orig_acp = this->acp;
- exec_list *orig_kills = this->kills;
- bool orig_killed_all = this->killed_all;
-
- this->acp = new(mem_ctx) exec_list;
- this->kills = new(mem_ctx) exec_list;
- this->killed_all = false;
-
- /* Populate the initial acp with a copy of the original */
- foreach_iter(exec_list_iterator, iter, *orig_acp) {
- acp_entry *a = (acp_entry *)iter.get();
- this->acp->push_tail(new(this->mem_ctx) acp_entry(a->lhs, a->rhs));
- }
-
- visit_list_elements(this, instructions);
-
- if (this->killed_all) {
- orig_acp->make_empty();
- }
-
- exec_list *new_kills = this->kills;
- this->kills = orig_kills;
- this->acp = orig_acp;
- this->killed_all = this->killed_all || orig_killed_all;
-
- foreach_iter(exec_list_iterator, iter, *new_kills) {
- kill_entry *k = (kill_entry *)iter.get();
- kill(k->var);
- }
-}
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_if *ir)
-{
- ir->condition->accept(this);
-
- handle_if_block(&ir->then_instructions);
- handle_if_block(&ir->else_instructions);
-
- /* handle_if_block() already descended into the children. */
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_loop *ir)
-{
- exec_list *orig_acp = this->acp;
- exec_list *orig_kills = this->kills;
- bool orig_killed_all = this->killed_all;
-
- /* FINISHME: For now, the initial acp for loops is totally empty.
- * We could go through once, then go through again with the acp
- * cloned minus the killed entries after the first run through.
- */
- this->acp = new(mem_ctx) exec_list;
- this->kills = new(mem_ctx) exec_list;
- this->killed_all = false;
-
- visit_list_elements(this, &ir->body_instructions);
-
- if (this->killed_all) {
- orig_acp->make_empty();
- }
-
- exec_list *new_kills = this->kills;
- this->kills = orig_kills;
- this->acp = orig_acp;
- this->killed_all = this->killed_all || orig_killed_all;
-
- foreach_iter(exec_list_iterator, iter, *new_kills) {
- kill_entry *k = (kill_entry *)iter.get();
- kill(k->var);
- }
-
- /* already descended into the children. */
- return visit_continue_with_parent;
-}
-
-void
-ir_copy_propagation_visitor::kill(ir_variable *var)
-{
- assert(var != NULL);
-
- /* Remove any entries currently in the ACP for this kill. */
- foreach_iter(exec_list_iterator, iter, *acp) {
- acp_entry *entry = (acp_entry *)iter.get();
-
- if (entry->lhs == var || entry->rhs == var) {
- entry->remove();
- }
- }
-
- /* Add the LHS variable to the list of killed variables in this block.
- */
- this->kills->push_tail(new(this->mem_ctx) kill_entry(var));
-}
-
-/**
- * Adds an entry to the available copy list if it's a plain assignment
- * of a variable to a variable.
- */
-void
-ir_copy_propagation_visitor::add_copy(ir_assignment *ir)
-{
- acp_entry *entry;
-
- if (ir->condition) {
- ir_constant *condition = ir->condition->as_constant();
- if (!condition || !condition->value.b[0])
- return;
- }
-
- ir_variable *lhs_var = ir->whole_variable_written();
- ir_variable *rhs_var = ir->rhs->whole_variable_referenced();
-
- if ((lhs_var != NULL) && (rhs_var != NULL)) {
- if (lhs_var == rhs_var) {
- /* This is a dumb assignment, but we've conveniently noticed
- * it here. Removing it now would mess up the loop iteration
- * calling us. Just flag it to not execute, and someone else
- * will clean up the mess.
- */
- ir->condition = new(talloc_parent(ir)) ir_constant(false);
- this->progress = true;
- } else {
- entry = new(this->mem_ctx) acp_entry(lhs_var, rhs_var);
- this->acp->push_tail(entry);
- }
- }
-}
-
-/**
- * Does a copy propagation pass on the code present in the instruction stream.
- */
-bool
-do_copy_propagation(exec_list *instructions)
-{
- ir_copy_propagation_visitor v;
-
- visit_list_elements(&v, instructions);
-
- return v.progress;
-}
+/*
+ * 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 opt_copy_propagation.cpp
+ *
+ * Moves usage of recently-copied variables to the previous copy of
+ * the variable.
+ *
+ * This should reduce the number of MOV instructions in the generated
+ * programs unless copy propagation is also done on the LIR, and may
+ * help anyway by triggering other optimizations that live in the HIR.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_basic_block.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+class acp_entry : public exec_node
+{
+public:
+ acp_entry(ir_variable *lhs, ir_variable *rhs)
+ {
+ assert(lhs);
+ assert(rhs);
+ this->lhs = lhs;
+ this->rhs = rhs;
+ }
+
+ ir_variable *lhs;
+ ir_variable *rhs;
+};
+
+
+class kill_entry : public exec_node
+{
+public:
+ kill_entry(ir_variable *var)
+ {
+ assert(var);
+ this->var = var;
+ }
+
+ ir_variable *var;
+};
+
+class ir_copy_propagation_visitor : public ir_hierarchical_visitor {
+public:
+ ir_copy_propagation_visitor()
+ {
+ progress = false;
+ mem_ctx = ralloc_context(0);
+ this->acp = new(mem_ctx) exec_list;
+ this->kills = new(mem_ctx) exec_list;
+ }
+ ~ir_copy_propagation_visitor()
+ {
+ ralloc_free(mem_ctx);
+ }
+
+ virtual ir_visitor_status visit(class ir_dereference_variable *);
+ virtual ir_visitor_status visit_enter(class ir_loop *);
+ virtual ir_visitor_status visit_enter(class ir_function_signature *);
+ virtual ir_visitor_status visit_enter(class ir_function *);
+ virtual ir_visitor_status visit_leave(class ir_assignment *);
+ virtual ir_visitor_status visit_enter(class ir_call *);
+ virtual ir_visitor_status visit_enter(class ir_if *);
+
+ void add_copy(ir_assignment *ir);
+ void kill(ir_variable *ir);
+ void handle_if_block(exec_list *instructions);
+
+ /** List of acp_entry: The available copies to propagate */
+ exec_list *acp;
+ /**
+ * List of kill_entry: The variables whose values were killed in this
+ * block.
+ */
+ exec_list *kills;
+
+ bool progress;
+
+ bool killed_all;
+
+ void *mem_ctx;
+};
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_function_signature *ir)
+{
+ /* Treat entry into a function signature as a completely separate
+ * block. Any instructions at global scope will be shuffled into
+ * main() at link time, so they're irrelevant to us.
+ */
+ exec_list *orig_acp = this->acp;
+ exec_list *orig_kills = this->kills;
+ bool orig_killed_all = this->killed_all;
+
+ this->acp = new(mem_ctx) exec_list;
+ this->kills = new(mem_ctx) exec_list;
+ this->killed_all = false;
+
+ visit_list_elements(this, &ir->body);
+
+ this->kills = orig_kills;
+ this->acp = orig_acp;
+ this->killed_all = orig_killed_all;
+
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_leave(ir_assignment *ir)
+{
+ kill(ir->lhs->variable_referenced());
+
+ add_copy(ir);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_function *ir)
+{
+ (void) ir;
+ return visit_continue;
+}
+
+/**
+ * Replaces dereferences of ACP RHS variables with ACP LHS variables.
+ *
+ * This is where the actual copy propagation occurs. Note that the
+ * rewriting of ir_dereference means that the ir_dereference instance
+ * must not be shared by multiple IR operations!
+ */
+ir_visitor_status
+ir_copy_propagation_visitor::visit(ir_dereference_variable *ir)
+{
+ if (this->in_assignee)
+ return visit_continue;
+
+ ir_variable *var = ir->var;
+
+ foreach_iter(exec_list_iterator, iter, *this->acp) {
+ acp_entry *entry = (acp_entry *)iter.get();
+
+ if (var == entry->lhs) {
+ ir->var = entry->rhs;
+ this->progress = true;
+ break;
+ }
+ }
+
+ return visit_continue;
+}
+
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_call *ir)
+{
+ /* Do copy propagation on call parameters, but skip any out params */
+ exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
+ ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
+ ir->accept(this);
+ }
+ sig_param_iter.next();
+ }
+
+ /* Since we're unlinked, we don't (necssarily) know the side effects of
+ * this call. So kill all copies.
+ */
+ acp->make_empty();
+ this->killed_all = true;
+
+ return visit_continue_with_parent;
+}
+
+void
+ir_copy_propagation_visitor::handle_if_block(exec_list *instructions)
+{
+ exec_list *orig_acp = this->acp;
+ exec_list *orig_kills = this->kills;
+ bool orig_killed_all = this->killed_all;
+
+ this->acp = new(mem_ctx) exec_list;
+ this->kills = new(mem_ctx) exec_list;
+ this->killed_all = false;
+
+ /* Populate the initial acp with a copy of the original */
+ foreach_iter(exec_list_iterator, iter, *orig_acp) {
+ acp_entry *a = (acp_entry *)iter.get();
+ this->acp->push_tail(new(this->mem_ctx) acp_entry(a->lhs, a->rhs));
+ }
+
+ visit_list_elements(this, instructions);
+
+ if (this->killed_all) {
+ orig_acp->make_empty();
+ }
+
+ exec_list *new_kills = this->kills;
+ this->kills = orig_kills;
+ this->acp = orig_acp;
+ this->killed_all = this->killed_all || orig_killed_all;
+
+ foreach_iter(exec_list_iterator, iter, *new_kills) {
+ kill_entry *k = (kill_entry *)iter.get();
+ kill(k->var);
+ }
+}
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_if *ir)
+{
+ ir->condition->accept(this);
+
+ handle_if_block(&ir->then_instructions);
+ handle_if_block(&ir->else_instructions);
+
+ /* handle_if_block() already descended into the children. */
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_loop *ir)
+{
+ exec_list *orig_acp = this->acp;
+ exec_list *orig_kills = this->kills;
+ bool orig_killed_all = this->killed_all;
+
+ /* FINISHME: For now, the initial acp for loops is totally empty.
+ * We could go through once, then go through again with the acp
+ * cloned minus the killed entries after the first run through.
+ */
+ this->acp = new(mem_ctx) exec_list;
+ this->kills = new(mem_ctx) exec_list;
+ this->killed_all = false;
+
+ visit_list_elements(this, &ir->body_instructions);
+
+ if (this->killed_all) {
+ orig_acp->make_empty();
+ }
+
+ exec_list *new_kills = this->kills;
+ this->kills = orig_kills;
+ this->acp = orig_acp;
+ this->killed_all = this->killed_all || orig_killed_all;
+
+ foreach_iter(exec_list_iterator, iter, *new_kills) {
+ kill_entry *k = (kill_entry *)iter.get();
+ kill(k->var);
+ }
+
+ /* already descended into the children. */
+ return visit_continue_with_parent;
+}
+
+void
+ir_copy_propagation_visitor::kill(ir_variable *var)
+{
+ assert(var != NULL);
+
+ /* Remove any entries currently in the ACP for this kill. */
+ foreach_iter(exec_list_iterator, iter, *acp) {
+ acp_entry *entry = (acp_entry *)iter.get();
+
+ if (entry->lhs == var || entry->rhs == var) {
+ entry->remove();
+ }
+ }
+
+ /* Add the LHS variable to the list of killed variables in this block.
+ */
+ this->kills->push_tail(new(this->mem_ctx) kill_entry(var));
+}
+
+/**
+ * Adds an entry to the available copy list if it's a plain assignment
+ * of a variable to a variable.
+ */
+void
+ir_copy_propagation_visitor::add_copy(ir_assignment *ir)
+{
+ acp_entry *entry;
+
+ if (ir->condition) {
+ ir_constant *condition = ir->condition->as_constant();
+ if (!condition || !condition->value.b[0])
+ return;
+ }
+
+ ir_variable *lhs_var = ir->whole_variable_written();
+ ir_variable *rhs_var = ir->rhs->whole_variable_referenced();
+
+ if ((lhs_var != NULL) && (rhs_var != NULL)) {
+ if (lhs_var == rhs_var) {
+ /* This is a dumb assignment, but we've conveniently noticed
+ * it here. Removing it now would mess up the loop iteration
+ * calling us. Just flag it to not execute, and someone else
+ * will clean up the mess.
+ */
+ ir->condition = new(ralloc_parent(ir)) ir_constant(false);
+ this->progress = true;
+ } else {
+ entry = new(this->mem_ctx) acp_entry(lhs_var, rhs_var);
+ this->acp->push_tail(entry);
+ }
+ }
+}
+
+/**
+ * Does a copy propagation pass on the code present in the instruction stream.
+ */
+bool
+do_copy_propagation(exec_list *instructions)
+{
+ ir_copy_propagation_visitor v;
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/opt_dead_code_local.cpp b/mesalib/src/glsl/opt_dead_code_local.cpp
index 182eccac2..2610b6981 100644
--- a/mesalib/src/glsl/opt_dead_code_local.cpp
+++ b/mesalib/src/glsl/opt_dead_code_local.cpp
@@ -1,229 +1,229 @@
-/*
- * 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 opt_dead_code_local.cpp
- *
- * Eliminates local dead assignments from the code.
- *
- * This operates on basic blocks, tracking assignments and finding if
- * they're used before the variable is completely reassigned.
- *
- * Compare this to ir_dead_code.cpp, which operates globally looking
- * for assignments to variables that are never read.
- */
-
-#include "ir.h"
-#include "ir_basic_block.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-static bool debug = false;
-
-class assignment_entry : public exec_node
-{
-public:
- assignment_entry(ir_variable *lhs, ir_instruction *ir)
- {
- assert(lhs);
- assert(ir);
- this->lhs = lhs;
- this->ir = ir;
- }
-
- ir_variable *lhs;
- ir_instruction *ir;
-};
-
-class kill_for_derefs_visitor : public ir_hierarchical_visitor {
-public:
- kill_for_derefs_visitor(exec_list *assignments)
- {
- this->assignments = assignments;
- }
-
- virtual ir_visitor_status visit(ir_dereference_variable *ir)
- {
- ir_variable *const var = ir->variable_referenced();
-
- foreach_iter(exec_list_iterator, iter, *this->assignments) {
- assignment_entry *entry = (assignment_entry *)iter.get();
-
- if (entry->lhs == var) {
- if (debug)
- printf("kill %s\n", entry->lhs->name);
- entry->remove();
- }
- }
-
- return visit_continue;
- }
-
-private:
- exec_list *assignments;
-};
-
-class array_index_visit : public ir_hierarchical_visitor {
-public:
- array_index_visit(ir_hierarchical_visitor *v)
- {
- this->visitor = v;
- }
-
- virtual ir_visitor_status visit_enter(class ir_dereference_array *ir)
- {
- ir->array_index->accept(visitor);
- return visit_continue;
- }
-
- static void run(ir_instruction *ir, ir_hierarchical_visitor *v)
- {
- array_index_visit top_visit(v);
- ir->accept(& top_visit);
- }
-
- ir_hierarchical_visitor *visitor;
-};
-
-
-/**
- * Adds an entry to the available copy list if it's a plain assignment
- * of a variable to a variable.
- */
-static bool
-process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
-{
- ir_variable *var = NULL;
- bool progress = false;
- kill_for_derefs_visitor v(assignments);
-
- /* Kill assignment entries for things used to produce this assignment. */
- ir->rhs->accept(&v);
- if (ir->condition) {
- ir->condition->accept(&v);
- }
-
- /* Kill assignment enties used as array indices.
- */
- array_index_visit::run(ir->lhs, &v);
- var = ir->lhs->variable_referenced();
- assert(var);
-
- bool always_assign = true;
- if (ir->condition) {
- ir_constant *condition = ir->condition->as_constant();
- if (!condition || !condition->value.b[0])
- always_assign = false;
- }
-
- /* Now, check if we did a whole-variable assignment. */
- if (always_assign && (ir->whole_variable_written() != NULL)) {
- /* We did a whole-variable assignment. So, any instruction in
- * the assignment list with the same LHS is dead.
- */
- if (debug)
- printf("looking for %s to remove\n", var->name);
- foreach_iter(exec_list_iterator, iter, *assignments) {
- assignment_entry *entry = (assignment_entry *)iter.get();
-
- if (entry->lhs == var) {
- if (debug)
- printf("removing %s\n", var->name);
- entry->ir->remove();
- entry->remove();
- progress = true;
- }
- }
- }
-
- /* Add this instruction to the assignment list available to be removed.
- * But not if the assignment has other side effects.
- */
- if (ir_has_call(ir))
- return progress;
-
- assignment_entry *entry = new(ctx) assignment_entry(var, ir);
- assignments->push_tail(entry);
-
- if (debug) {
- printf("add %s\n", var->name);
-
- printf("current entries\n");
- foreach_iter(exec_list_iterator, iter, *assignments) {
- assignment_entry *entry = (assignment_entry *)iter.get();
-
- printf(" %s\n", entry->lhs->name);
- }
- }
-
- return progress;
-}
-
-static void
-dead_code_local_basic_block(ir_instruction *first,
- ir_instruction *last,
- void *data)
-{
- ir_instruction *ir, *ir_next;
- /* List of avaialble_copy */
- exec_list assignments;
- bool *out_progress = (bool *)data;
- bool progress = false;
-
- void *ctx = talloc_new(NULL);
- /* Safe looping, since process_assignment */
- for (ir = first, ir_next = (ir_instruction *)first->next;;
- ir = ir_next, ir_next = (ir_instruction *)ir->next) {
- ir_assignment *ir_assign = ir->as_assignment();
-
- if (debug) {
- ir->print();
- printf("\n");
- }
-
- if (ir_assign) {
- progress = process_assignment(ctx, ir_assign, &assignments) || progress;
- } else {
- kill_for_derefs_visitor kill(&assignments);
- ir->accept(&kill);
- }
-
- if (ir == last)
- break;
- }
- *out_progress = progress;
- talloc_free(ctx);
-}
-
-/**
- * Does a copy propagation pass on the code present in the instruction stream.
- */
-bool
-do_dead_code_local(exec_list *instructions)
-{
- bool progress = false;
-
- call_for_basic_blocks(instructions, dead_code_local_basic_block, &progress);
-
- return progress;
-}
+/*
+ * 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 opt_dead_code_local.cpp
+ *
+ * Eliminates local dead assignments from the code.
+ *
+ * This operates on basic blocks, tracking assignments and finding if
+ * they're used before the variable is completely reassigned.
+ *
+ * Compare this to ir_dead_code.cpp, which operates globally looking
+ * for assignments to variables that are never read.
+ */
+
+#include "ir.h"
+#include "ir_basic_block.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+static bool debug = false;
+
+class assignment_entry : public exec_node
+{
+public:
+ assignment_entry(ir_variable *lhs, ir_instruction *ir)
+ {
+ assert(lhs);
+ assert(ir);
+ this->lhs = lhs;
+ this->ir = ir;
+ }
+
+ ir_variable *lhs;
+ ir_instruction *ir;
+};
+
+class kill_for_derefs_visitor : public ir_hierarchical_visitor {
+public:
+ kill_for_derefs_visitor(exec_list *assignments)
+ {
+ this->assignments = assignments;
+ }
+
+ virtual ir_visitor_status visit(ir_dereference_variable *ir)
+ {
+ ir_variable *const var = ir->variable_referenced();
+
+ foreach_iter(exec_list_iterator, iter, *this->assignments) {
+ assignment_entry *entry = (assignment_entry *)iter.get();
+
+ if (entry->lhs == var) {
+ if (debug)
+ printf("kill %s\n", entry->lhs->name);
+ entry->remove();
+ }
+ }
+
+ return visit_continue;
+ }
+
+private:
+ exec_list *assignments;
+};
+
+class array_index_visit : public ir_hierarchical_visitor {
+public:
+ array_index_visit(ir_hierarchical_visitor *v)
+ {
+ this->visitor = v;
+ }
+
+ virtual ir_visitor_status visit_enter(class ir_dereference_array *ir)
+ {
+ ir->array_index->accept(visitor);
+ return visit_continue;
+ }
+
+ static void run(ir_instruction *ir, ir_hierarchical_visitor *v)
+ {
+ array_index_visit top_visit(v);
+ ir->accept(& top_visit);
+ }
+
+ ir_hierarchical_visitor *visitor;
+};
+
+
+/**
+ * Adds an entry to the available copy list if it's a plain assignment
+ * of a variable to a variable.
+ */
+static bool
+process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
+{
+ ir_variable *var = NULL;
+ bool progress = false;
+ kill_for_derefs_visitor v(assignments);
+
+ /* Kill assignment entries for things used to produce this assignment. */
+ ir->rhs->accept(&v);
+ if (ir->condition) {
+ ir->condition->accept(&v);
+ }
+
+ /* Kill assignment enties used as array indices.
+ */
+ array_index_visit::run(ir->lhs, &v);
+ var = ir->lhs->variable_referenced();
+ assert(var);
+
+ bool always_assign = true;
+ if (ir->condition) {
+ ir_constant *condition = ir->condition->as_constant();
+ if (!condition || !condition->value.b[0])
+ always_assign = false;
+ }
+
+ /* Now, check if we did a whole-variable assignment. */
+ if (always_assign && (ir->whole_variable_written() != NULL)) {
+ /* We did a whole-variable assignment. So, any instruction in
+ * the assignment list with the same LHS is dead.
+ */
+ if (debug)
+ printf("looking for %s to remove\n", var->name);
+ foreach_iter(exec_list_iterator, iter, *assignments) {
+ assignment_entry *entry = (assignment_entry *)iter.get();
+
+ if (entry->lhs == var) {
+ if (debug)
+ printf("removing %s\n", var->name);
+ entry->ir->remove();
+ entry->remove();
+ progress = true;
+ }
+ }
+ }
+
+ /* Add this instruction to the assignment list available to be removed.
+ * But not if the assignment has other side effects.
+ */
+ if (ir_has_call(ir))
+ return progress;
+
+ assignment_entry *entry = new(ctx) assignment_entry(var, ir);
+ assignments->push_tail(entry);
+
+ if (debug) {
+ printf("add %s\n", var->name);
+
+ printf("current entries\n");
+ foreach_iter(exec_list_iterator, iter, *assignments) {
+ assignment_entry *entry = (assignment_entry *)iter.get();
+
+ printf(" %s\n", entry->lhs->name);
+ }
+ }
+
+ return progress;
+}
+
+static void
+dead_code_local_basic_block(ir_instruction *first,
+ ir_instruction *last,
+ void *data)
+{
+ ir_instruction *ir, *ir_next;
+ /* List of avaialble_copy */
+ exec_list assignments;
+ bool *out_progress = (bool *)data;
+ bool progress = false;
+
+ void *ctx = ralloc_context(NULL);
+ /* Safe looping, since process_assignment */
+ for (ir = first, ir_next = (ir_instruction *)first->next;;
+ ir = ir_next, ir_next = (ir_instruction *)ir->next) {
+ ir_assignment *ir_assign = ir->as_assignment();
+
+ if (debug) {
+ ir->print();
+ printf("\n");
+ }
+
+ if (ir_assign) {
+ progress = process_assignment(ctx, ir_assign, &assignments) || progress;
+ } else {
+ kill_for_derefs_visitor kill(&assignments);
+ ir->accept(&kill);
+ }
+
+ if (ir == last)
+ break;
+ }
+ *out_progress = progress;
+ ralloc_free(ctx);
+}
+
+/**
+ * Does a copy propagation pass on the code present in the instruction stream.
+ */
+bool
+do_dead_code_local(exec_list *instructions)
+{
+ bool progress = false;
+
+ call_for_basic_blocks(instructions, dead_code_local_basic_block, &progress);
+
+ return progress;
+}
diff --git a/mesalib/src/glsl/opt_dead_functions.cpp b/mesalib/src/glsl/opt_dead_functions.cpp
index 6f0761bcc..ceb79080a 100644
--- a/mesalib/src/glsl/opt_dead_functions.cpp
+++ b/mesalib/src/glsl/opt_dead_functions.cpp
@@ -1,153 +1,153 @@
- /*
- * 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 opt_dead_functions.cpp
- *
- * Eliminates unused functions from the linked program.
- */
-
- #include "ir.h"
- #include "ir_visitor.h"
- #include "ir_expression_flattening.h"
- #include "glsl_types.h"
-
- class signature_entry : public exec_node
- {
- public:
- signature_entry(ir_function_signature *sig)
- {
- this->signature = sig;
- this->used = false;
- }
-
- ir_function_signature *signature;
- bool used;
- };
-
- class ir_dead_functions_visitor : public ir_hierarchical_visitor {
- public:
- ir_dead_functions_visitor()
- {
- this->mem_ctx = talloc_new(NULL);
- }
-
- ~ir_dead_functions_visitor()
- {
- talloc_free(this->mem_ctx);
- }
-
- virtual ir_visitor_status visit_enter(ir_function_signature *);
- virtual ir_visitor_status visit_enter(ir_call *);
-
- signature_entry *get_signature_entry(ir_function_signature *var);
-
- bool (*predicate)(ir_instruction *ir);
-
- /* List of signature_entry */
- exec_list signature_list;
- void *mem_ctx;
- };
-
-
- signature_entry *
- ir_dead_functions_visitor::get_signature_entry(ir_function_signature *sig)
- {
- foreach_iter(exec_list_iterator, iter, this->signature_list) {
- signature_entry *entry = (signature_entry *)iter.get();
- if (entry->signature == sig)
- return entry;
- }
-
- signature_entry *entry = new(mem_ctx) signature_entry(sig);
- this->signature_list.push_tail(entry);
- return entry;
- }
-
-
- ir_visitor_status
- ir_dead_functions_visitor::visit_enter(ir_function_signature *ir)
- {
- signature_entry *entry = this->get_signature_entry(ir);
-
- if (strcmp(ir->function_name(), "main") == 0) {
- entry->used = true;
- }
-
- return visit_continue;
- }
-
-
- ir_visitor_status
- ir_dead_functions_visitor::visit_enter(ir_call *ir)
- {
- signature_entry *entry = this->get_signature_entry(ir->get_callee());
-
- entry->used = true;
-
- return visit_continue;
-}
-
-bool
-do_dead_functions(exec_list *instructions)
-{
- ir_dead_functions_visitor v;
- bool progress = false;
-
- visit_list_elements(&v, instructions);
-
- /* Now that we've figured out which function signatures are used, remove
- * the unused ones, and remove function definitions that have no more
- * signatures.
- */
- foreach_iter(exec_list_iterator, iter, v.signature_list) {
- signature_entry *entry = (signature_entry *)iter.get();
-
- if (!entry->used) {
- entry->signature->remove();
- delete entry->signature;
- progress = true;
- }
- delete(entry);
- }
-
- /* We don't just do this above when we nuked a signature because of
- * const pointers.
- */
- foreach_iter(exec_list_iterator, iter, *instructions) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- ir_function *func = ir->as_function();
-
- if (func && func->signatures.is_empty()) {
- /* At this point (post-linking), the symbol table is no
- * longer in use, so not removing the function from the
- * symbol table should be OK.
- */
- func->remove();
- delete func;
- progress = true;
- }
- }
-
- return progress;
-}
+ /*
+ * 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 opt_dead_functions.cpp
+ *
+ * Eliminates unused functions from the linked program.
+ */
+
+ #include "ir.h"
+ #include "ir_visitor.h"
+ #include "ir_expression_flattening.h"
+ #include "glsl_types.h"
+
+ class signature_entry : public exec_node
+ {
+ public:
+ signature_entry(ir_function_signature *sig)
+ {
+ this->signature = sig;
+ this->used = false;
+ }
+
+ ir_function_signature *signature;
+ bool used;
+ };
+
+ class ir_dead_functions_visitor : public ir_hierarchical_visitor {
+ public:
+ ir_dead_functions_visitor()
+ {
+ this->mem_ctx = ralloc_context(NULL);
+ }
+
+ ~ir_dead_functions_visitor()
+ {
+ ralloc_free(this->mem_ctx);
+ }
+
+ virtual ir_visitor_status visit_enter(ir_function_signature *);
+ virtual ir_visitor_status visit_enter(ir_call *);
+
+ signature_entry *get_signature_entry(ir_function_signature *var);
+
+ bool (*predicate)(ir_instruction *ir);
+
+ /* List of signature_entry */
+ exec_list signature_list;
+ void *mem_ctx;
+ };
+
+
+ signature_entry *
+ ir_dead_functions_visitor::get_signature_entry(ir_function_signature *sig)
+ {
+ foreach_iter(exec_list_iterator, iter, this->signature_list) {
+ signature_entry *entry = (signature_entry *)iter.get();
+ if (entry->signature == sig)
+ return entry;
+ }
+
+ signature_entry *entry = new(mem_ctx) signature_entry(sig);
+ this->signature_list.push_tail(entry);
+ return entry;
+ }
+
+
+ ir_visitor_status
+ ir_dead_functions_visitor::visit_enter(ir_function_signature *ir)
+ {
+ signature_entry *entry = this->get_signature_entry(ir);
+
+ if (strcmp(ir->function_name(), "main") == 0) {
+ entry->used = true;
+ }
+
+ return visit_continue;
+ }
+
+
+ ir_visitor_status
+ ir_dead_functions_visitor::visit_enter(ir_call *ir)
+ {
+ signature_entry *entry = this->get_signature_entry(ir->get_callee());
+
+ entry->used = true;
+
+ return visit_continue;
+}
+
+bool
+do_dead_functions(exec_list *instructions)
+{
+ ir_dead_functions_visitor v;
+ bool progress = false;
+
+ visit_list_elements(&v, instructions);
+
+ /* Now that we've figured out which function signatures are used, remove
+ * the unused ones, and remove function definitions that have no more
+ * signatures.
+ */
+ foreach_iter(exec_list_iterator, iter, v.signature_list) {
+ signature_entry *entry = (signature_entry *)iter.get();
+
+ if (!entry->used) {
+ entry->signature->remove();
+ delete entry->signature;
+ progress = true;
+ }
+ delete(entry);
+ }
+
+ /* We don't just do this above when we nuked a signature because of
+ * const pointers.
+ */
+ foreach_iter(exec_list_iterator, iter, *instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir_function *func = ir->as_function();
+
+ if (func && func->signatures.is_empty()) {
+ /* At this point (post-linking), the symbol table is no
+ * longer in use, so not removing the function from the
+ * symbol table should be OK.
+ */
+ func->remove();
+ delete func;
+ progress = true;
+ }
+ }
+
+ return progress;
+}
diff --git a/mesalib/src/glsl/opt_function_inlining.cpp b/mesalib/src/glsl/opt_function_inlining.cpp
index 83197e11a..2e7831dcb 100644
--- a/mesalib/src/glsl/opt_function_inlining.cpp
+++ b/mesalib/src/glsl/opt_function_inlining.cpp
@@ -1,424 +1,425 @@
-/*
- * 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 opt_function_inlining.cpp
- *
- * Replaces calls to functions with the body of the function.
- */
-
-#include <inttypes.h>
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_function_inlining.h"
-#include "ir_expression_flattening.h"
-#include "glsl_types.h"
-#include "program/hash_table.h"
-
-static void
-do_sampler_replacement(exec_list *instructions,
- ir_variable *sampler,
- ir_dereference *deref);
-
-class ir_function_inlining_visitor : public ir_hierarchical_visitor {
-public:
- ir_function_inlining_visitor()
- {
- progress = false;
- }
-
- virtual ~ir_function_inlining_visitor()
- {
- /* empty */
- }
-
- virtual ir_visitor_status visit_enter(ir_expression *);
- virtual ir_visitor_status visit_enter(ir_call *);
- virtual ir_visitor_status visit_enter(ir_assignment *);
- virtual ir_visitor_status visit_enter(ir_return *);
- virtual ir_visitor_status visit_enter(ir_texture *);
- virtual ir_visitor_status visit_enter(ir_swizzle *);
-
- bool progress;
-};
-
-
-bool
-automatic_inlining_predicate(ir_instruction *ir)
-{
- ir_call *call = ir->as_call();
-
- if (call && can_inline(call))
- return true;
-
- return false;
-}
-
-bool
-do_function_inlining(exec_list *instructions)
-{
- ir_function_inlining_visitor v;
-
- do_expression_flattening(instructions, automatic_inlining_predicate);
-
- v.run(instructions);
-
- return v.progress;
-}
-
-static void
-replace_return_with_assignment(ir_instruction *ir, void *data)
-{
- void *ctx = talloc_parent(ir);
- ir_variable *retval = (ir_variable *)data;
- ir_return *ret = ir->as_return();
-
- if (ret) {
- if (ret->value) {
- ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
- ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
- } else {
- /* un-valued return has to be the last return, or we shouldn't
- * have reached here. (see can_inline()).
- */
- assert(ret->next->is_tail_sentinel());
- ret->remove();
- }
- }
-}
-
-ir_rvalue *
-ir_call::generate_inline(ir_instruction *next_ir)
-{
- void *ctx = talloc_parent(this);
- ir_variable **parameters;
- int num_parameters;
- int i;
- ir_variable *retval = NULL;
- struct hash_table *ht;
-
- ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
-
- num_parameters = 0;
- foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
- num_parameters++;
-
- parameters = new ir_variable *[num_parameters];
-
- /* Generate storage for the return value. */
- if (this->callee->return_type) {
- retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val",
- ir_var_auto);
- next_ir->insert_before(retval);
- }
-
- /* Generate the declarations for the parameters to our inlined code,
- * and set up the mapping of real function body variables to ours.
- */
- i = 0;
- exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
- exec_list_iterator param_iter = this->actual_parameters.iterator();
- for (i = 0; i < num_parameters; i++) {
- ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
- ir_rvalue *param = (ir_rvalue *) param_iter.get();
-
- /* Generate a new variable for the parameter. */
- if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
- /* For samplers, we want the inlined sampler references
- * referencing the passed in sampler variable, since that
- * will have the location information, which an assignment of
- * a sampler wouldn't. Fix it up below.
- */
- parameters[i] = NULL;
- } else {
- parameters[i] = sig_param->clone(ctx, ht);
- parameters[i]->mode = ir_var_auto;
-
- /* Remove the read-only decoration becuase we're going to write
- * directly to this variable. If the cloned variable is left
- * read-only and the inlined function is inside a loop, the loop
- * analysis code will get confused.
- */
- parameters[i]->read_only = false;
- next_ir->insert_before(parameters[i]);
- }
-
- /* Move the actual param into our param variable if it's an 'in' type. */
- if (parameters[i] && (sig_param->mode == ir_var_in ||
- sig_param->mode == ir_var_inout)) {
- ir_assignment *assign;
-
- assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
- param, NULL);
- next_ir->insert_before(assign);
- }
-
- sig_param_iter.next();
- param_iter.next();
- }
-
- exec_list new_instructions;
-
- /* Generate the inlined body of the function to a new list */
- foreach_iter(exec_list_iterator, iter, callee->body) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- ir_instruction *new_ir = ir->clone(ctx, ht);
-
- new_instructions.push_tail(new_ir);
- visit_tree(new_ir, replace_return_with_assignment, retval);
- }
-
- /* If any samplers were passed in, replace any deref of the sampler
- * with a deref of the sampler argument.
- */
- param_iter = this->actual_parameters.iterator();
- sig_param_iter = this->callee->parameters.iterator();
- for (i = 0; i < num_parameters; i++) {
- ir_instruction *const param = (ir_instruction *) param_iter.get();
- ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
-
- if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
- ir_dereference *deref = param->as_dereference();
-
- assert(deref);
- do_sampler_replacement(&new_instructions, sig_param, deref);
- }
- param_iter.next();
- sig_param_iter.next();
- }
-
- /* Now push those new instructions in. */
- foreach_iter(exec_list_iterator, iter, new_instructions) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- next_ir->insert_before(ir);
- }
-
- /* Copy back the value of any 'out' parameters from the function body
- * variables to our own.
- */
- i = 0;
- param_iter = this->actual_parameters.iterator();
- sig_param_iter = this->callee->parameters.iterator();
- for (i = 0; i < num_parameters; i++) {
- ir_instruction *const param = (ir_instruction *) param_iter.get();
- const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();
-
- /* Move our param variable into the actual param if it's an 'out' type. */
- if (parameters[i] && (sig_param->mode == ir_var_out ||
- sig_param->mode == ir_var_inout)) {
- ir_assignment *assign;
-
- assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
- new(ctx) ir_dereference_variable(parameters[i]),
- NULL);
- next_ir->insert_before(assign);
- }
-
- param_iter.next();
- sig_param_iter.next();
- }
-
- delete [] parameters;
-
- hash_table_dtor(ht);
-
- if (retval)
- return new(ctx) ir_dereference_variable(retval);
- else
- return NULL;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_expression *ir)
-{
- (void) ir;
- return visit_continue_with_parent;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_return *ir)
-{
- (void) ir;
- return visit_continue_with_parent;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_texture *ir)
-{
- (void) ir;
- return visit_continue_with_parent;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
-{
- (void) ir;
- return visit_continue_with_parent;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_call *ir)
-{
- if (can_inline(ir)) {
- /* If the call was part of some tree, then it should have been
- * flattened out or we shouldn't have seen it because of a
- * visit_continue_with_parent in this visitor.
- */
- assert(ir == base_ir);
-
- (void) ir->generate_inline(ir);
- ir->remove();
- this->progress = true;
- }
-
- return visit_continue;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
-{
- ir_call *call = ir->rhs->as_call();
- if (!call || !can_inline(call))
- return visit_continue;
-
- /* generates the parameter setup, function body, and returns the return
- * value of the function
- */
- ir_rvalue *rhs = call->generate_inline(ir);
- assert(rhs);
-
- ir->rhs = rhs;
- this->progress = true;
-
- return visit_continue;
-}
-
-/**
- * Replaces references to the "sampler" variable with a clone of "deref."
- *
- * From the spec, samplers can appear in the tree as function
- * (non-out) parameters and as the result of array indexing and
- * structure field selection. In our builtin implementation, they
- * also appear in the sampler field of an ir_tex instruction.
- */
-
-class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
-public:
- ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
- {
- this->sampler = sampler;
- this->deref = deref;
- }
-
- virtual ~ir_sampler_replacement_visitor()
- {
- }
-
- virtual ir_visitor_status visit_leave(ir_call *);
- virtual ir_visitor_status visit_leave(ir_dereference_array *);
- virtual ir_visitor_status visit_leave(ir_dereference_record *);
- virtual ir_visitor_status visit_leave(ir_texture *);
-
- void replace_deref(ir_dereference **deref);
- void replace_rvalue(ir_rvalue **rvalue);
-
- ir_variable *sampler;
- ir_dereference *deref;
-};
-
-void
-ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
-{
- ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
- if (deref_var && deref_var->var == this->sampler) {
- *deref = this->deref->clone(talloc_parent(*deref), NULL);
- }
-}
-
-void
-ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
-{
- if (!*rvalue)
- return;
-
- ir_dereference *deref = (*rvalue)->as_dereference();
-
- if (!deref)
- return;
-
- replace_deref(&deref);
- *rvalue = deref;
-}
-
-ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
-{
- replace_deref(&ir->sampler);
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
-{
- replace_rvalue(&ir->array);
- return visit_continue;
-}
-
-ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
-{
- replace_rvalue(&ir->record);
- return visit_continue;
-}
-
-ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
-{
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_rvalue *param = (ir_rvalue *)iter.get();
- ir_rvalue *new_param = param;
- replace_rvalue(&new_param);
-
- if (new_param != param) {
- param->replace_with(new_param);
- }
- }
- return visit_continue;
-}
-
-static void
-do_sampler_replacement(exec_list *instructions,
- ir_variable *sampler,
- ir_dereference *deref)
-{
- ir_sampler_replacement_visitor v(sampler, deref);
-
- visit_list_elements(&v, instructions);
-}
+/*
+ * 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 opt_function_inlining.cpp
+ *
+ * Replaces calls to functions with the body of the function.
+ */
+
+#include <inttypes.h>
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_function_inlining.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+#include "program/hash_table.h"
+
+static void
+do_sampler_replacement(exec_list *instructions,
+ ir_variable *sampler,
+ ir_dereference *deref);
+
+class ir_function_inlining_visitor : public ir_hierarchical_visitor {
+public:
+ ir_function_inlining_visitor()
+ {
+ progress = false;
+ }
+
+ virtual ~ir_function_inlining_visitor()
+ {
+ /* empty */
+ }
+
+ virtual ir_visitor_status visit_enter(ir_expression *);
+ virtual ir_visitor_status visit_enter(ir_call *);
+ virtual ir_visitor_status visit_enter(ir_assignment *);
+ virtual ir_visitor_status visit_enter(ir_return *);
+ virtual ir_visitor_status visit_enter(ir_texture *);
+ virtual ir_visitor_status visit_enter(ir_swizzle *);
+
+ bool progress;
+};
+
+
+bool
+automatic_inlining_predicate(ir_instruction *ir)
+{
+ ir_call *call = ir->as_call();
+
+ if (call && can_inline(call))
+ return true;
+
+ return false;
+}
+
+bool
+do_function_inlining(exec_list *instructions)
+{
+ ir_function_inlining_visitor v;
+
+ do_expression_flattening(instructions, automatic_inlining_predicate);
+
+ v.run(instructions);
+
+ return v.progress;
+}
+
+static void
+replace_return_with_assignment(ir_instruction *ir, void *data)
+{
+ void *ctx = ralloc_parent(ir);
+ ir_variable *retval = (ir_variable *)data;
+ ir_return *ret = ir->as_return();
+
+ if (ret) {
+ if (ret->value) {
+ ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
+ ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
+ } else {
+ /* un-valued return has to be the last return, or we shouldn't
+ * have reached here. (see can_inline()).
+ */
+ assert(ret->next->is_tail_sentinel());
+ ret->remove();
+ }
+ }
+}
+
+ir_rvalue *
+ir_call::generate_inline(ir_instruction *next_ir)
+{
+ void *ctx = ralloc_parent(this);
+ ir_variable **parameters;
+ int num_parameters;
+ int i;
+ ir_variable *retval = NULL;
+ struct hash_table *ht;
+
+ ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
+
+ num_parameters = 0;
+ foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
+ num_parameters++;
+
+ parameters = new ir_variable *[num_parameters];
+
+ /* Generate storage for the return value. */
+ if (this->callee->return_type) {
+ retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val",
+ ir_var_auto);
+ next_ir->insert_before(retval);
+ }
+
+ /* Generate the declarations for the parameters to our inlined code,
+ * and set up the mapping of real function body variables to ours.
+ */
+ i = 0;
+ exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
+ exec_list_iterator param_iter = this->actual_parameters.iterator();
+ for (i = 0; i < num_parameters; i++) {
+ ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
+ ir_rvalue *param = (ir_rvalue *) param_iter.get();
+
+ /* Generate a new variable for the parameter. */
+ if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
+ /* For samplers, we want the inlined sampler references
+ * referencing the passed in sampler variable, since that
+ * will have the location information, which an assignment of
+ * a sampler wouldn't. Fix it up below.
+ */
+ parameters[i] = NULL;
+ } else {
+ parameters[i] = sig_param->clone(ctx, ht);
+ parameters[i]->mode = ir_var_auto;
+
+ /* Remove the read-only decoration becuase we're going to write
+ * directly to this variable. If the cloned variable is left
+ * read-only and the inlined function is inside a loop, the loop
+ * analysis code will get confused.
+ */
+ parameters[i]->read_only = false;
+ next_ir->insert_before(parameters[i]);
+ }
+
+ /* Move the actual param into our param variable if it's an 'in' type. */
+ if (parameters[i] && (sig_param->mode == ir_var_in ||
+ sig_param->mode == ir_var_const_in ||
+ sig_param->mode == ir_var_inout)) {
+ ir_assignment *assign;
+
+ assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
+ param, NULL);
+ next_ir->insert_before(assign);
+ }
+
+ sig_param_iter.next();
+ param_iter.next();
+ }
+
+ exec_list new_instructions;
+
+ /* Generate the inlined body of the function to a new list */
+ foreach_iter(exec_list_iterator, iter, callee->body) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir_instruction *new_ir = ir->clone(ctx, ht);
+
+ new_instructions.push_tail(new_ir);
+ visit_tree(new_ir, replace_return_with_assignment, retval);
+ }
+
+ /* If any samplers were passed in, replace any deref of the sampler
+ * with a deref of the sampler argument.
+ */
+ param_iter = this->actual_parameters.iterator();
+ sig_param_iter = this->callee->parameters.iterator();
+ for (i = 0; i < num_parameters; i++) {
+ ir_instruction *const param = (ir_instruction *) param_iter.get();
+ ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
+
+ if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
+ ir_dereference *deref = param->as_dereference();
+
+ assert(deref);
+ do_sampler_replacement(&new_instructions, sig_param, deref);
+ }
+ param_iter.next();
+ sig_param_iter.next();
+ }
+
+ /* Now push those new instructions in. */
+ foreach_iter(exec_list_iterator, iter, new_instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ next_ir->insert_before(ir);
+ }
+
+ /* Copy back the value of any 'out' parameters from the function body
+ * variables to our own.
+ */
+ i = 0;
+ param_iter = this->actual_parameters.iterator();
+ sig_param_iter = this->callee->parameters.iterator();
+ for (i = 0; i < num_parameters; i++) {
+ ir_instruction *const param = (ir_instruction *) param_iter.get();
+ const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();
+
+ /* Move our param variable into the actual param if it's an 'out' type. */
+ if (parameters[i] && (sig_param->mode == ir_var_out ||
+ sig_param->mode == ir_var_inout)) {
+ ir_assignment *assign;
+
+ assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
+ new(ctx) ir_dereference_variable(parameters[i]),
+ NULL);
+ next_ir->insert_before(assign);
+ }
+
+ param_iter.next();
+ sig_param_iter.next();
+ }
+
+ delete [] parameters;
+
+ hash_table_dtor(ht);
+
+ if (retval)
+ return new(ctx) ir_dereference_variable(retval);
+ else
+ return NULL;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_expression *ir)
+{
+ (void) ir;
+ return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_return *ir)
+{
+ (void) ir;
+ return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_texture *ir)
+{
+ (void) ir;
+ return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
+{
+ (void) ir;
+ return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_call *ir)
+{
+ if (can_inline(ir)) {
+ /* If the call was part of some tree, then it should have been
+ * flattened out or we shouldn't have seen it because of a
+ * visit_continue_with_parent in this visitor.
+ */
+ assert(ir == base_ir);
+
+ (void) ir->generate_inline(ir);
+ ir->remove();
+ this->progress = true;
+ }
+
+ return visit_continue;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
+{
+ ir_call *call = ir->rhs->as_call();
+ if (!call || !can_inline(call))
+ return visit_continue;
+
+ /* generates the parameter setup, function body, and returns the return
+ * value of the function
+ */
+ ir_rvalue *rhs = call->generate_inline(ir);
+ assert(rhs);
+
+ ir->rhs = rhs;
+ this->progress = true;
+
+ return visit_continue;
+}
+
+/**
+ * Replaces references to the "sampler" variable with a clone of "deref."
+ *
+ * From the spec, samplers can appear in the tree as function
+ * (non-out) parameters and as the result of array indexing and
+ * structure field selection. In our builtin implementation, they
+ * also appear in the sampler field of an ir_tex instruction.
+ */
+
+class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
+public:
+ ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
+ {
+ this->sampler = sampler;
+ this->deref = deref;
+ }
+
+ virtual ~ir_sampler_replacement_visitor()
+ {
+ }
+
+ virtual ir_visitor_status visit_leave(ir_call *);
+ virtual ir_visitor_status visit_leave(ir_dereference_array *);
+ virtual ir_visitor_status visit_leave(ir_dereference_record *);
+ virtual ir_visitor_status visit_leave(ir_texture *);
+
+ void replace_deref(ir_dereference **deref);
+ void replace_rvalue(ir_rvalue **rvalue);
+
+ ir_variable *sampler;
+ ir_dereference *deref;
+};
+
+void
+ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
+{
+ ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
+ if (deref_var && deref_var->var == this->sampler) {
+ *deref = this->deref->clone(ralloc_parent(*deref), NULL);
+ }
+}
+
+void
+ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
+{
+ if (!*rvalue)
+ return;
+
+ ir_dereference *deref = (*rvalue)->as_dereference();
+
+ if (!deref)
+ return;
+
+ replace_deref(&deref);
+ *rvalue = deref;
+}
+
+ir_visitor_status
+ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
+{
+ replace_deref(&ir->sampler);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
+{
+ replace_rvalue(&ir->array);
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
+{
+ replace_rvalue(&ir->record);
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
+{
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param = (ir_rvalue *)iter.get();
+ ir_rvalue *new_param = param;
+ replace_rvalue(&new_param);
+
+ if (new_param != param) {
+ param->replace_with(new_param);
+ }
+ }
+ return visit_continue;
+}
+
+static void
+do_sampler_replacement(exec_list *instructions,
+ ir_variable *sampler,
+ ir_dereference *deref)
+{
+ ir_sampler_replacement_visitor v(sampler, deref);
+
+ visit_list_elements(&v, instructions);
+}
diff --git a/mesalib/src/glsl/opt_structure_splitting.cpp b/mesalib/src/glsl/opt_structure_splitting.cpp
index fead62e21..014407c0b 100644
--- a/mesalib/src/glsl/opt_structure_splitting.cpp
+++ b/mesalib/src/glsl/opt_structure_splitting.cpp
@@ -1,361 +1,361 @@
-/*
- * 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 opt_structure_splitting.cpp
- *
- * If a structure is only ever referenced by its components, then
- * split those components out to individual variables so they can be
- * handled normally by other optimization passes.
- *
- * This skips structures like uniforms, which need to be accessible as
- * structures for their access by the GL.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_print_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "glsl_types.h"
-
-static bool debug = false;
-
-// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined
-// function) with the variable_entry class seen in ir_variable_refcount.h
-// Perhaps we can use the one in ir_variable_refcount.h and make this class
-// here go away?
-class variable_entry2 : public exec_node
-{
-public:
- variable_entry2(ir_variable *var)
- {
- this->var = var;
- this->whole_structure_access = 0;
- this->declaration = false;
- this->components = NULL;
- this->mem_ctx = NULL;
- }
-
- ir_variable *var; /* The key: the variable's pointer. */
-
- /** Number of times the variable is referenced, including assignments. */
- unsigned whole_structure_access;
-
- bool declaration; /* If the variable had a decl in the instruction stream */
-
- ir_variable **components;
-
- /** talloc_parent(this->var) -- the shader's talloc context. */
- void *mem_ctx;
-};
-
-
-class ir_structure_reference_visitor : public ir_hierarchical_visitor {
-public:
- ir_structure_reference_visitor(void)
- {
- this->mem_ctx = talloc_new(NULL);
- this->variable_list.make_empty();
- }
-
- ~ir_structure_reference_visitor(void)
- {
- talloc_free(mem_ctx);
- }
-
- virtual ir_visitor_status visit(ir_variable *);
- virtual ir_visitor_status visit(ir_dereference_variable *);
- virtual ir_visitor_status visit_enter(ir_dereference_record *);
- virtual ir_visitor_status visit_enter(ir_assignment *);
- virtual ir_visitor_status visit_enter(ir_function_signature *);
-
- variable_entry2 *get_variable_entry2(ir_variable *var);
-
- /* List of variable_entry */
- exec_list variable_list;
-
- void *mem_ctx;
-};
-
-variable_entry2 *
-ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
-{
- assert(var);
-
- if (!var->type->is_record() || var->mode == ir_var_uniform)
- return NULL;
-
- foreach_iter(exec_list_iterator, iter, this->variable_list) {
- variable_entry2 *entry = (variable_entry2 *)iter.get();
- if (entry->var == var)
- return entry;
- }
-
- variable_entry2 *entry = new(mem_ctx) variable_entry2(var);
- this->variable_list.push_tail(entry);
- return entry;
-}
-
-
-ir_visitor_status
-ir_structure_reference_visitor::visit(ir_variable *ir)
-{
- variable_entry2 *entry = this->get_variable_entry2(ir);
-
- if (entry)
- entry->declaration = true;
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit(ir_dereference_variable *ir)
-{
- ir_variable *const var = ir->variable_referenced();
- variable_entry2 *entry = this->get_variable_entry2(var);
-
- if (entry)
- entry->whole_structure_access++;
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
-{
- (void) ir;
- /* Don't descend into the ir_dereference_variable below. */
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
-{
- if (ir->lhs->as_dereference_variable() &&
- ir->rhs->as_dereference_variable() &&
- !ir->condition) {
- /* We'll split copies of a structure to copies of components, so don't
- * descend to the ir_dereference_variables.
- */
- return visit_continue_with_parent;
- }
- return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
-{
- /* We don't want to descend into the function parameters and
- * dead-code eliminate them, so just accept the body here.
- */
- visit_list_elements(this, &ir->body);
- return visit_continue_with_parent;
-}
-
-class ir_structure_splitting_visitor : public ir_rvalue_visitor {
-public:
- ir_structure_splitting_visitor(exec_list *vars)
- {
- this->variable_list = vars;
- }
-
- virtual ~ir_structure_splitting_visitor()
- {
- }
-
- virtual ir_visitor_status visit_leave(ir_assignment *);
-
- void split_deref(ir_dereference **deref);
- void handle_rvalue(ir_rvalue **rvalue);
- variable_entry2 *get_splitting_entry(ir_variable *var);
-
- exec_list *variable_list;
- void *mem_ctx;
-};
-
-variable_entry2 *
-ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
-{
- assert(var);
-
- if (!var->type->is_record())
- return NULL;
-
- foreach_iter(exec_list_iterator, iter, *this->variable_list) {
- variable_entry2 *entry = (variable_entry2 *)iter.get();
- if (entry->var == var) {
- return entry;
- }
- }
-
- return NULL;
-}
-
-void
-ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
-{
- if ((*deref)->ir_type != ir_type_dereference_record)
- return;
-
- ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
- ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
- if (!deref_var)
- return;
-
- variable_entry2 *entry = get_splitting_entry(deref_var->var);
- if (!entry)
- return;
-
- unsigned int i;
- for (i = 0; i < entry->var->type->length; i++) {
- if (strcmp(deref_record->field,
- entry->var->type->fields.structure[i].name) == 0)
- break;
- }
- assert(i != entry->var->type->length);
-
- *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
-}
-
-void
-ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
- if (!*rvalue)
- return;
-
- ir_dereference *deref = (*rvalue)->as_dereference();
-
- if (!deref)
- return;
-
- split_deref(&deref);
- *rvalue = deref;
-}
-
-ir_visitor_status
-ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
-{
- ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
- ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
- variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
- variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
- const glsl_type *type = ir->rhs->type;
-
- if ((lhs_entry || rhs_entry) && !ir->condition) {
- for (unsigned int i = 0; i < type->length; i++) {
- ir_dereference *new_lhs, *new_rhs;
- void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
-
- if (lhs_entry) {
- new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
- } else {
- new_lhs = new(mem_ctx)
- ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
- type->fields.structure[i].name);
- }
-
- if (rhs_entry) {
- new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
- } else {
- new_rhs = new(mem_ctx)
- ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
- type->fields.structure[i].name);
- }
-
- ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
- new_rhs,
- NULL));
- }
- ir->remove();
- } else {
- handle_rvalue(&ir->rhs);
- split_deref(&ir->lhs);
- }
-
- handle_rvalue(&ir->condition);
-
- return visit_continue;
-}
-
-bool
-do_structure_splitting(exec_list *instructions)
-{
- ir_structure_reference_visitor refs;
-
- visit_list_elements(&refs, instructions);
-
- /* Trim out variables we can't split. */
- foreach_iter(exec_list_iterator, iter, refs.variable_list) {
- variable_entry2 *entry = (variable_entry2 *)iter.get();
-
- if (debug) {
- printf("structure %s@%p: decl %d, whole_access %d\n",
- entry->var->name, (void *) entry->var, entry->declaration,
- entry->whole_structure_access);
- }
-
- if (!entry->declaration || entry->whole_structure_access) {
- entry->remove();
- }
- }
-
- if (refs.variable_list.is_empty())
- return false;
-
- void *mem_ctx = talloc_new(NULL);
-
- /* Replace the decls of the structures to be split with their split
- * components.
- */
- foreach_iter(exec_list_iterator, iter, refs.variable_list) {
- variable_entry2 *entry = (variable_entry2 *)iter.get();
- const struct glsl_type *type = entry->var->type;
-
- entry->mem_ctx = talloc_parent(entry->var);
-
- entry->components = talloc_array(mem_ctx,
- ir_variable *,
- type->length);
-
- for (unsigned int i = 0; i < entry->var->type->length; i++) {
- const char *name = talloc_asprintf(mem_ctx, "%s_%s",
- entry->var->name,
- type->fields.structure[i].name);
-
- entry->components[i] =
- new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
- name,
- ir_var_temporary);
- entry->var->insert_before(entry->components[i]);
- }
-
- entry->var->remove();
- }
-
- ir_structure_splitting_visitor split(&refs.variable_list);
- visit_list_elements(&split, instructions);
-
- talloc_free(mem_ctx);
-
- return true;
-}
+/*
+ * 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 opt_structure_splitting.cpp
+ *
+ * If a structure is only ever referenced by its components, then
+ * split those components out to individual variables so they can be
+ * handled normally by other optimization passes.
+ *
+ * This skips structures like uniforms, which need to be accessible as
+ * structures for their access by the GL.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_print_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "glsl_types.h"
+
+static bool debug = false;
+
+// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined
+// function) with the variable_entry class seen in ir_variable_refcount.h
+// Perhaps we can use the one in ir_variable_refcount.h and make this class
+// here go away?
+class variable_entry2 : public exec_node
+{
+public:
+ variable_entry2(ir_variable *var)
+ {
+ this->var = var;
+ this->whole_structure_access = 0;
+ this->declaration = false;
+ this->components = NULL;
+ this->mem_ctx = NULL;
+ }
+
+ ir_variable *var; /* The key: the variable's pointer. */
+
+ /** Number of times the variable is referenced, including assignments. */
+ unsigned whole_structure_access;
+
+ bool declaration; /* If the variable had a decl in the instruction stream */
+
+ ir_variable **components;
+
+ /** ralloc_parent(this->var) -- the shader's ralloc context. */
+ void *mem_ctx;
+};
+
+
+class ir_structure_reference_visitor : public ir_hierarchical_visitor {
+public:
+ ir_structure_reference_visitor(void)
+ {
+ this->mem_ctx = ralloc_context(NULL);
+ this->variable_list.make_empty();
+ }
+
+ ~ir_structure_reference_visitor(void)
+ {
+ ralloc_free(mem_ctx);
+ }
+
+ virtual ir_visitor_status visit(ir_variable *);
+ virtual ir_visitor_status visit(ir_dereference_variable *);
+ virtual ir_visitor_status visit_enter(ir_dereference_record *);
+ virtual ir_visitor_status visit_enter(ir_assignment *);
+ virtual ir_visitor_status visit_enter(ir_function_signature *);
+
+ variable_entry2 *get_variable_entry2(ir_variable *var);
+
+ /* List of variable_entry */
+ exec_list variable_list;
+
+ void *mem_ctx;
+};
+
+variable_entry2 *
+ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
+{
+ assert(var);
+
+ if (!var->type->is_record() || var->mode == ir_var_uniform)
+ return NULL;
+
+ foreach_iter(exec_list_iterator, iter, this->variable_list) {
+ variable_entry2 *entry = (variable_entry2 *)iter.get();
+ if (entry->var == var)
+ return entry;
+ }
+
+ variable_entry2 *entry = new(mem_ctx) variable_entry2(var);
+ this->variable_list.push_tail(entry);
+ return entry;
+}
+
+
+ir_visitor_status
+ir_structure_reference_visitor::visit(ir_variable *ir)
+{
+ variable_entry2 *entry = this->get_variable_entry2(ir);
+
+ if (entry)
+ entry->declaration = true;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit(ir_dereference_variable *ir)
+{
+ ir_variable *const var = ir->variable_referenced();
+ variable_entry2 *entry = this->get_variable_entry2(var);
+
+ if (entry)
+ entry->whole_structure_access++;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
+{
+ (void) ir;
+ /* Don't descend into the ir_dereference_variable below. */
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
+{
+ if (ir->lhs->as_dereference_variable() &&
+ ir->rhs->as_dereference_variable() &&
+ !ir->condition) {
+ /* We'll split copies of a structure to copies of components, so don't
+ * descend to the ir_dereference_variables.
+ */
+ return visit_continue_with_parent;
+ }
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
+{
+ /* We don't want to descend into the function parameters and
+ * dead-code eliminate them, so just accept the body here.
+ */
+ visit_list_elements(this, &ir->body);
+ return visit_continue_with_parent;
+}
+
+class ir_structure_splitting_visitor : public ir_rvalue_visitor {
+public:
+ ir_structure_splitting_visitor(exec_list *vars)
+ {
+ this->variable_list = vars;
+ }
+
+ virtual ~ir_structure_splitting_visitor()
+ {
+ }
+
+ virtual ir_visitor_status visit_leave(ir_assignment *);
+
+ void split_deref(ir_dereference **deref);
+ void handle_rvalue(ir_rvalue **rvalue);
+ variable_entry2 *get_splitting_entry(ir_variable *var);
+
+ exec_list *variable_list;
+ void *mem_ctx;
+};
+
+variable_entry2 *
+ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
+{
+ assert(var);
+
+ if (!var->type->is_record())
+ return NULL;
+
+ foreach_iter(exec_list_iterator, iter, *this->variable_list) {
+ variable_entry2 *entry = (variable_entry2 *)iter.get();
+ if (entry->var == var) {
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+void
+ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
+{
+ if ((*deref)->ir_type != ir_type_dereference_record)
+ return;
+
+ ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
+ ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
+ if (!deref_var)
+ return;
+
+ variable_entry2 *entry = get_splitting_entry(deref_var->var);
+ if (!entry)
+ return;
+
+ unsigned int i;
+ for (i = 0; i < entry->var->type->length; i++) {
+ if (strcmp(deref_record->field,
+ entry->var->type->fields.structure[i].name) == 0)
+ break;
+ }
+ assert(i != entry->var->type->length);
+
+ *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
+}
+
+void
+ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+ if (!*rvalue)
+ return;
+
+ ir_dereference *deref = (*rvalue)->as_dereference();
+
+ if (!deref)
+ return;
+
+ split_deref(&deref);
+ *rvalue = deref;
+}
+
+ir_visitor_status
+ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
+{
+ ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
+ ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
+ variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
+ variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
+ const glsl_type *type = ir->rhs->type;
+
+ if ((lhs_entry || rhs_entry) && !ir->condition) {
+ for (unsigned int i = 0; i < type->length; i++) {
+ ir_dereference *new_lhs, *new_rhs;
+ void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
+
+ if (lhs_entry) {
+ new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
+ } else {
+ new_lhs = new(mem_ctx)
+ ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
+ type->fields.structure[i].name);
+ }
+
+ if (rhs_entry) {
+ new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
+ } else {
+ new_rhs = new(mem_ctx)
+ ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
+ type->fields.structure[i].name);
+ }
+
+ ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
+ new_rhs,
+ NULL));
+ }
+ ir->remove();
+ } else {
+ handle_rvalue(&ir->rhs);
+ split_deref(&ir->lhs);
+ }
+
+ handle_rvalue(&ir->condition);
+
+ return visit_continue;
+}
+
+bool
+do_structure_splitting(exec_list *instructions)
+{
+ ir_structure_reference_visitor refs;
+
+ visit_list_elements(&refs, instructions);
+
+ /* Trim out variables we can't split. */
+ foreach_iter(exec_list_iterator, iter, refs.variable_list) {
+ variable_entry2 *entry = (variable_entry2 *)iter.get();
+
+ if (debug) {
+ printf("structure %s@%p: decl %d, whole_access %d\n",
+ entry->var->name, (void *) entry->var, entry->declaration,
+ entry->whole_structure_access);
+ }
+
+ if (!entry->declaration || entry->whole_structure_access) {
+ entry->remove();
+ }
+ }
+
+ if (refs.variable_list.is_empty())
+ return false;
+
+ void *mem_ctx = ralloc_context(NULL);
+
+ /* Replace the decls of the structures to be split with their split
+ * components.
+ */
+ foreach_iter(exec_list_iterator, iter, refs.variable_list) {
+ variable_entry2 *entry = (variable_entry2 *)iter.get();
+ const struct glsl_type *type = entry->var->type;
+
+ entry->mem_ctx = ralloc_parent(entry->var);
+
+ entry->components = ralloc_array(mem_ctx,
+ ir_variable *,
+ type->length);
+
+ for (unsigned int i = 0; i < entry->var->type->length; i++) {
+ const char *name = ralloc_asprintf(mem_ctx, "%s_%s",
+ entry->var->name,
+ type->fields.structure[i].name);
+
+ entry->components[i] =
+ new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
+ name,
+ ir_var_temporary);
+ entry->var->insert_before(entry->components[i]);
+ }
+
+ entry->var->remove();
+ }
+
+ ir_structure_splitting_visitor split(&refs.variable_list);
+ visit_list_elements(&split, instructions);
+
+ ralloc_free(mem_ctx);
+
+ return true;
+}
diff --git a/mesalib/src/glsl/opt_tree_grafting.cpp b/mesalib/src/glsl/opt_tree_grafting.cpp
index 556f8258b..1ef940f9c 100644
--- a/mesalib/src/glsl/opt_tree_grafting.cpp
+++ b/mesalib/src/glsl/opt_tree_grafting.cpp
@@ -1,367 +1,368 @@
-/*
- * 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 opt_tree_grafting.cpp
- *
- * Takes assignments to variables that are dereferenced only once and
- * pastes the RHS expression into where the variable is dereferenced.
- *
- * In the process of various operations like function inlining and
- * tertiary op handling, we'll end up with our expression trees having
- * been chopped up into a series of assignments of short expressions
- * to temps. Other passes like ir_algebraic.cpp would prefer to see
- * the deepest expression trees they can to try to optimize them.
- *
- * This is a lot like copy propagaton. In comparison, copy
- * propagation only acts on plain copies, not arbitrary expressions on
- * the RHS. Generally, we wouldn't want to go pasting some
- * complicated expression everywhere it got used, though, so we don't
- * handle expressions in that pass.
- *
- * The hard part is making sure we don't move an expression across
- * some other assignments that would change the value of the
- * expression. So we split this into two passes: First, find the
- * variables in our scope which are written to once and read once, and
- * then go through basic blocks seeing if we find an opportunity to
- * move those expressions safely.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_variable_refcount.h"
-#include "ir_basic_block.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-static bool debug = false;
-
-class ir_tree_grafting_visitor : public ir_hierarchical_visitor {
-public:
- ir_tree_grafting_visitor(ir_assignment *graft_assign,
- ir_variable *graft_var)
- {
- this->progress = false;
- this->graft_assign = graft_assign;
- this->graft_var = graft_var;
- }
-
- virtual ir_visitor_status visit_leave(class ir_assignment *);
- virtual ir_visitor_status visit_enter(class ir_call *);
- virtual ir_visitor_status visit_enter(class ir_expression *);
- virtual ir_visitor_status visit_enter(class ir_function *);
- virtual ir_visitor_status visit_enter(class ir_function_signature *);
- virtual ir_visitor_status visit_enter(class ir_if *);
- virtual ir_visitor_status visit_enter(class ir_loop *);
- virtual ir_visitor_status visit_enter(class ir_swizzle *);
- virtual ir_visitor_status visit_enter(class ir_texture *);
-
- bool do_graft(ir_rvalue **rvalue);
-
- bool progress;
- ir_variable *graft_var;
- ir_assignment *graft_assign;
-};
-
-struct find_deref_info {
- ir_variable *var;
- bool found;
-};
-
-void
-dereferences_variable_callback(ir_instruction *ir, void *data)
-{
- struct find_deref_info *info = (struct find_deref_info *)data;
- ir_dereference_variable *deref = ir->as_dereference_variable();
-
- if (deref && deref->var == info->var)
- info->found = true;
-}
-
-static bool
-dereferences_variable(ir_instruction *ir, ir_variable *var)
-{
- struct find_deref_info info;
-
- info.var = var;
- info.found = false;
-
- visit_tree(ir, dereferences_variable_callback, &info);
-
- return info.found;
-}
-
-bool
-ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue)
-{
- if (!*rvalue)
- return false;
-
- ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
-
- if (!deref || deref->var != this->graft_var)
- return false;
-
- if (debug) {
- printf("GRAFTING:\n");
- this->graft_assign->print();
- printf("\n");
- printf("TO:\n");
- (*rvalue)->print();
- printf("\n");
- }
-
- this->graft_assign->remove();
- *rvalue = this->graft_assign->rhs;
-
- this->progress = true;
- return true;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_loop *ir)
-{
- (void)ir;
- /* Do not traverse into the body of the loop since that is a
- * different basic block.
- */
- return visit_stop;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_leave(ir_assignment *ir)
-{
- if (do_graft(&ir->rhs) ||
- do_graft(&ir->condition))
- return visit_stop;
-
- /* If this assignment updates a variable used in the assignment
- * we're trying to graft, then we're done.
- */
- if (dereferences_variable(this->graft_assign->rhs,
- ir->lhs->variable_referenced())) {
- if (debug) {
- printf("graft killed by: ");
- ir->print();
- printf("\n");
- }
- return visit_stop;
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_function *ir)
-{
- (void) ir;
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir)
-{
- (void)ir;
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_call *ir)
-{
- exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
- /* Reminder: iterating ir_call iterates its parameters. */
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_variable *sig_param = (ir_variable *)sig_iter.get();
- ir_rvalue *ir = (ir_rvalue *)iter.get();
- ir_rvalue *new_ir = ir;
-
- if (sig_param->mode != ir_var_in)
- continue;
-
- if (do_graft(&new_ir)) {
- ir->replace_with(new_ir);
- return visit_stop;
- }
- sig_iter.next();
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_expression *ir)
-{
- for (unsigned int i = 0; i < ir->get_num_operands(); i++) {
- if (do_graft(&ir->operands[i]))
- return visit_stop;
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_if *ir)
-{
- if (do_graft(&ir->condition))
- return visit_stop;
-
- /* Do not traverse into the body of the if-statement since that is a
- * different basic block.
- */
- return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_swizzle *ir)
-{
- if (do_graft(&ir->val))
- return visit_stop;
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_texture *ir)
-{
- if (do_graft(&ir->coordinate) ||
- do_graft(&ir->projector) ||
- do_graft(&ir->shadow_comparitor))
- return visit_stop;
-
- switch (ir->op) {
- case ir_tex:
- break;
- case ir_txb:
- if (do_graft(&ir->lod_info.bias))
- return visit_stop;
- break;
- case ir_txf:
- case ir_txl:
- if (do_graft(&ir->lod_info.lod))
- return visit_stop;
- break;
- case ir_txd:
- if (do_graft(&ir->lod_info.grad.dPdx) ||
- do_graft(&ir->lod_info.grad.dPdy))
- return visit_stop;
- break;
- }
-
- return visit_continue;
-}
-
-struct tree_grafting_info {
- ir_variable_refcount_visitor *refs;
- bool progress;
-};
-
-static bool
-try_tree_grafting(ir_assignment *start,
- ir_variable *lhs_var,
- ir_instruction *bb_last)
-{
- ir_tree_grafting_visitor v(start, lhs_var);
-
- if (debug) {
- printf("trying to graft: ");
- lhs_var->print();
- printf("\n");
- }
-
- for (ir_instruction *ir = (ir_instruction *)start->next;
- ir != bb_last->next;
- ir = (ir_instruction *)ir->next) {
-
- if (debug) {
- printf("- ");
- ir->print();
- printf("\n");
- }
-
- ir_visitor_status s = ir->accept(&v);
- if (s == visit_stop)
- return v.progress;
- }
-
- return false;
-}
-
-static void
-tree_grafting_basic_block(ir_instruction *bb_first,
- ir_instruction *bb_last,
- void *data)
-{
- struct tree_grafting_info *info = (struct tree_grafting_info *)data;
- ir_instruction *ir, *next;
-
- for (ir = bb_first, next = (ir_instruction *)ir->next;
- ir != bb_last->next;
- ir = next, next = (ir_instruction *)ir->next) {
- ir_assignment *assign = ir->as_assignment();
-
- if (!assign)
- continue;
-
- ir_variable *lhs_var = assign->whole_variable_written();
- if (!lhs_var)
- continue;
-
- if (lhs_var->mode == ir_var_out ||
- lhs_var->mode == ir_var_inout)
- continue;
-
- variable_entry *entry = info->refs->get_variable_entry(lhs_var);
-
- if (!entry->declaration ||
- entry->assigned_count != 1 ||
- entry->referenced_count != 2)
- continue;
-
- assert(assign == entry->assign);
-
- /* Found a possibly graftable assignment. Now, walk through the
- * rest of the BB seeing if the deref is here, and if nothing interfered with
- * pasting its expression's values in between.
- */
- info->progress |= try_tree_grafting(assign, lhs_var, bb_last);
- }
-}
-
-/**
- * Does a copy propagation pass on the code present in the instruction stream.
- */
-bool
-do_tree_grafting(exec_list *instructions)
-{
- ir_variable_refcount_visitor refs;
- struct tree_grafting_info info;
-
- info.progress = false;
- info.refs = &refs;
-
- visit_list_elements(info.refs, instructions);
-
- call_for_basic_blocks(instructions, tree_grafting_basic_block, &info);
-
- return info.progress;
-}
+/*
+ * 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 opt_tree_grafting.cpp
+ *
+ * Takes assignments to variables that are dereferenced only once and
+ * pastes the RHS expression into where the variable is dereferenced.
+ *
+ * In the process of various operations like function inlining and
+ * tertiary op handling, we'll end up with our expression trees having
+ * been chopped up into a series of assignments of short expressions
+ * to temps. Other passes like ir_algebraic.cpp would prefer to see
+ * the deepest expression trees they can to try to optimize them.
+ *
+ * This is a lot like copy propagaton. In comparison, copy
+ * propagation only acts on plain copies, not arbitrary expressions on
+ * the RHS. Generally, we wouldn't want to go pasting some
+ * complicated expression everywhere it got used, though, so we don't
+ * handle expressions in that pass.
+ *
+ * The hard part is making sure we don't move an expression across
+ * some other assignments that would change the value of the
+ * expression. So we split this into two passes: First, find the
+ * variables in our scope which are written to once and read once, and
+ * then go through basic blocks seeing if we find an opportunity to
+ * move those expressions safely.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_variable_refcount.h"
+#include "ir_basic_block.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+static bool debug = false;
+
+class ir_tree_grafting_visitor : public ir_hierarchical_visitor {
+public:
+ ir_tree_grafting_visitor(ir_assignment *graft_assign,
+ ir_variable *graft_var)
+ {
+ this->progress = false;
+ this->graft_assign = graft_assign;
+ this->graft_var = graft_var;
+ }
+
+ virtual ir_visitor_status visit_leave(class ir_assignment *);
+ virtual ir_visitor_status visit_enter(class ir_call *);
+ virtual ir_visitor_status visit_enter(class ir_expression *);
+ virtual ir_visitor_status visit_enter(class ir_function *);
+ virtual ir_visitor_status visit_enter(class ir_function_signature *);
+ virtual ir_visitor_status visit_enter(class ir_if *);
+ virtual ir_visitor_status visit_enter(class ir_loop *);
+ virtual ir_visitor_status visit_enter(class ir_swizzle *);
+ virtual ir_visitor_status visit_enter(class ir_texture *);
+
+ bool do_graft(ir_rvalue **rvalue);
+
+ bool progress;
+ ir_variable *graft_var;
+ ir_assignment *graft_assign;
+};
+
+struct find_deref_info {
+ ir_variable *var;
+ bool found;
+};
+
+void
+dereferences_variable_callback(ir_instruction *ir, void *data)
+{
+ struct find_deref_info *info = (struct find_deref_info *)data;
+ ir_dereference_variable *deref = ir->as_dereference_variable();
+
+ if (deref && deref->var == info->var)
+ info->found = true;
+}
+
+static bool
+dereferences_variable(ir_instruction *ir, ir_variable *var)
+{
+ struct find_deref_info info;
+
+ info.var = var;
+ info.found = false;
+
+ visit_tree(ir, dereferences_variable_callback, &info);
+
+ return info.found;
+}
+
+bool
+ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue)
+{
+ if (!*rvalue)
+ return false;
+
+ ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
+
+ if (!deref || deref->var != this->graft_var)
+ return false;
+
+ if (debug) {
+ printf("GRAFTING:\n");
+ this->graft_assign->print();
+ printf("\n");
+ printf("TO:\n");
+ (*rvalue)->print();
+ printf("\n");
+ }
+
+ this->graft_assign->remove();
+ *rvalue = this->graft_assign->rhs;
+
+ this->progress = true;
+ return true;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_loop *ir)
+{
+ (void)ir;
+ /* Do not traverse into the body of the loop since that is a
+ * different basic block.
+ */
+ return visit_stop;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_leave(ir_assignment *ir)
+{
+ if (do_graft(&ir->rhs) ||
+ do_graft(&ir->condition))
+ return visit_stop;
+
+ /* If this assignment updates a variable used in the assignment
+ * we're trying to graft, then we're done.
+ */
+ if (dereferences_variable(this->graft_assign->rhs,
+ ir->lhs->variable_referenced())) {
+ if (debug) {
+ printf("graft killed by: ");
+ ir->print();
+ printf("\n");
+ }
+ return visit_stop;
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_function *ir)
+{
+ (void) ir;
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir)
+{
+ (void)ir;
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_call *ir)
+{
+ exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+ /* Reminder: iterating ir_call iterates its parameters. */
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_variable *sig_param = (ir_variable *)sig_iter.get();
+ ir_rvalue *ir = (ir_rvalue *)iter.get();
+ ir_rvalue *new_ir = ir;
+
+ if (sig_param->mode != ir_var_in && sig_param->mode != ir_var_const_in)
+ continue;
+
+ if (do_graft(&new_ir)) {
+ ir->replace_with(new_ir);
+ return visit_stop;
+ }
+ sig_iter.next();
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_expression *ir)
+{
+ for (unsigned int i = 0; i < ir->get_num_operands(); i++) {
+ if (do_graft(&ir->operands[i]))
+ return visit_stop;
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_if *ir)
+{
+ if (do_graft(&ir->condition))
+ return visit_stop;
+
+ /* Do not traverse into the body of the if-statement since that is a
+ * different basic block.
+ */
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_swizzle *ir)
+{
+ if (do_graft(&ir->val))
+ return visit_stop;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_texture *ir)
+{
+ if (do_graft(&ir->coordinate) ||
+ do_graft(&ir->projector) ||
+ do_graft(&ir->offset) ||
+ do_graft(&ir->shadow_comparitor))
+ return visit_stop;
+
+ switch (ir->op) {
+ case ir_tex:
+ break;
+ case ir_txb:
+ if (do_graft(&ir->lod_info.bias))
+ return visit_stop;
+ break;
+ case ir_txf:
+ case ir_txl:
+ if (do_graft(&ir->lod_info.lod))
+ return visit_stop;
+ break;
+ case ir_txd:
+ if (do_graft(&ir->lod_info.grad.dPdx) ||
+ do_graft(&ir->lod_info.grad.dPdy))
+ return visit_stop;
+ break;
+ }
+
+ return visit_continue;
+}
+
+struct tree_grafting_info {
+ ir_variable_refcount_visitor *refs;
+ bool progress;
+};
+
+static bool
+try_tree_grafting(ir_assignment *start,
+ ir_variable *lhs_var,
+ ir_instruction *bb_last)
+{
+ ir_tree_grafting_visitor v(start, lhs_var);
+
+ if (debug) {
+ printf("trying to graft: ");
+ lhs_var->print();
+ printf("\n");
+ }
+
+ for (ir_instruction *ir = (ir_instruction *)start->next;
+ ir != bb_last->next;
+ ir = (ir_instruction *)ir->next) {
+
+ if (debug) {
+ printf("- ");
+ ir->print();
+ printf("\n");
+ }
+
+ ir_visitor_status s = ir->accept(&v);
+ if (s == visit_stop)
+ return v.progress;
+ }
+
+ return false;
+}
+
+static void
+tree_grafting_basic_block(ir_instruction *bb_first,
+ ir_instruction *bb_last,
+ void *data)
+{
+ struct tree_grafting_info *info = (struct tree_grafting_info *)data;
+ ir_instruction *ir, *next;
+
+ for (ir = bb_first, next = (ir_instruction *)ir->next;
+ ir != bb_last->next;
+ ir = next, next = (ir_instruction *)ir->next) {
+ ir_assignment *assign = ir->as_assignment();
+
+ if (!assign)
+ continue;
+
+ ir_variable *lhs_var = assign->whole_variable_written();
+ if (!lhs_var)
+ continue;
+
+ if (lhs_var->mode == ir_var_out ||
+ lhs_var->mode == ir_var_inout)
+ continue;
+
+ variable_entry *entry = info->refs->get_variable_entry(lhs_var);
+
+ if (!entry->declaration ||
+ entry->assigned_count != 1 ||
+ entry->referenced_count != 2)
+ continue;
+
+ assert(assign == entry->assign);
+
+ /* Found a possibly graftable assignment. Now, walk through the
+ * rest of the BB seeing if the deref is here, and if nothing interfered with
+ * pasting its expression's values in between.
+ */
+ info->progress |= try_tree_grafting(assign, lhs_var, bb_last);
+ }
+}
+
+/**
+ * Does a copy propagation pass on the code present in the instruction stream.
+ */
+bool
+do_tree_grafting(exec_list *instructions)
+{
+ ir_variable_refcount_visitor refs;
+ struct tree_grafting_info info;
+
+ info.progress = false;
+ info.refs = &refs;
+
+ visit_list_elements(info.refs, instructions);
+
+ call_for_basic_blocks(instructions, tree_grafting_basic_block, &info);
+
+ return info.progress;
+}
diff --git a/mesalib/src/glsl/ralloc.c b/mesalib/src/glsl/ralloc.c
new file mode 100644
index 000000000..fa2dd8b01
--- /dev/null
+++ b/mesalib/src/glsl/ralloc.c
@@ -0,0 +1,448 @@
+/*
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "ralloc.h"
+
+#ifdef __GNUC__
+#define likely(x) __builtin_expect(!!(x),1)
+#define unlikely(x) __builtin_expect(!!(x),0)
+#else
+#define likely(x) !!(x)
+#define unlikely(x) !!(x)
+#endif
+
+#ifndef va_copy
+#ifdef __va_copy
+#define va_copy(dest, src) __va_copy((dest), (src))
+#else
+#define va_copy(dest, src) (dest) = (src)
+#endif
+#endif
+
+#define CANARY 0x5A1106
+
+struct ralloc_header
+{
+ /* A canary value used to determine whether a pointer is ralloc'd. */
+ unsigned canary;
+
+ struct ralloc_header *parent;
+
+ /* The first child (head of a linked list) */
+ struct ralloc_header *child;
+
+ /* Linked list of siblings */
+ struct ralloc_header *prev;
+ struct ralloc_header *next;
+
+ void (*destructor)(void *);
+};
+
+typedef struct ralloc_header ralloc_header;
+
+static void unlink_block(ralloc_header *info);
+static void unsafe_free(ralloc_header *info);
+
+static ralloc_header *
+get_header(const void *ptr)
+{
+ ralloc_header *info = (ralloc_header *) (((char *) ptr) -
+ sizeof(ralloc_header));
+ assert(info->canary == CANARY);
+ return info;
+}
+
+#define PTR_FROM_HEADER(info) (((char *) info) + sizeof(ralloc_header))
+
+static void
+add_child(ralloc_header *parent, ralloc_header *info)
+{
+ if (parent != NULL) {
+ info->parent = parent;
+ info->next = parent->child;
+ parent->child = info;
+
+ if (info->next != NULL)
+ info->next->prev = info;
+ }
+}
+
+void *
+ralloc_context(const void *ctx)
+{
+ return ralloc_size(ctx, 0);
+}
+
+void *
+ralloc_size(const void *ctx, size_t size)
+{
+ void *block = calloc(1, size + sizeof(ralloc_header));
+
+ ralloc_header *info = (ralloc_header *) block;
+ ralloc_header *parent = ctx != NULL ? get_header(ctx) : NULL;
+
+ add_child(parent, info);
+
+ info->canary = CANARY;
+
+ return PTR_FROM_HEADER(info);
+}
+
+void *
+rzalloc_size(const void *ctx, size_t size)
+{
+ void *ptr = ralloc_size(ctx, size);
+ if (likely(ptr != NULL))
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+/* helper function - assumes ptr != NULL */
+static void *
+resize(void *ptr, size_t size)
+{
+ ralloc_header *child, *old, *info;
+
+ old = get_header(ptr);
+ info = realloc(old, size + sizeof(ralloc_header));
+
+ if (info == NULL)
+ return NULL;
+
+ /* Update parent and sibling's links to the reallocated node. */
+ if (info != old && info->parent != NULL) {
+ if (info->parent->child == old)
+ info->parent->child = info;
+
+ if (info->prev != NULL)
+ info->prev->next = info;
+
+ if (info->next != NULL)
+ info->next->prev = info;
+ }
+
+ /* Update child->parent links for all children */
+ for (child = info->child; child != NULL; child = child->next)
+ child->parent = info;
+
+ return PTR_FROM_HEADER(info);
+}
+
+void *
+reralloc_size(const void *ctx, void *ptr, size_t size)
+{
+ if (unlikely(ptr == NULL))
+ return ralloc_size(ctx, size);
+
+ assert(ralloc_parent(ptr) == ctx);
+ return resize(ptr, size);
+}
+
+void *
+ralloc_array_size(const void *ctx, size_t size, unsigned count)
+{
+ if (count > SIZE_MAX/size)
+ return NULL;
+
+ return ralloc_size(ctx, size * count);
+}
+
+void *
+rzalloc_array_size(const void *ctx, size_t size, unsigned count)
+{
+ if (count > SIZE_MAX/size)
+ return NULL;
+
+ return rzalloc_size(ctx, size * count);
+}
+
+void *
+reralloc_array_size(const void *ctx, void *ptr, size_t size, unsigned count)
+{
+ if (count > SIZE_MAX/size)
+ return NULL;
+
+ return reralloc_size(ctx, ptr, size * count);
+}
+
+void
+ralloc_free(void *ptr)
+{
+ ralloc_header *info;
+
+ if (ptr == NULL)
+ return;
+
+ info = get_header(ptr);
+ unlink_block(info);
+ unsafe_free(info);
+}
+
+static void
+unlink_block(ralloc_header *info)
+{
+ /* Unlink from parent & siblings */
+ if (info->parent != NULL) {
+ if (info->parent->child == info)
+ info->parent->child = info->next;
+
+ if (info->prev != NULL)
+ info->prev->next = info->next;
+
+ if (info->next != NULL)
+ info->next->prev = info->prev;
+ }
+ info->parent = NULL;
+ info->prev = NULL;
+ info->next = NULL;
+}
+
+static void
+unsafe_free(ralloc_header *info)
+{
+ /* Recursively free any children...don't waste time unlinking them. */
+ ralloc_header *temp;
+ while (info->child != NULL) {
+ temp = info->child;
+ info->child = temp->next;
+ unsafe_free(temp);
+ }
+
+ /* Free the block itself. Call the destructor first, if any. */
+ if (info->destructor != NULL)
+ info->destructor(PTR_FROM_HEADER(info));
+
+ free(info);
+}
+
+void
+ralloc_steal(const void *new_ctx, void *ptr)
+{
+ ralloc_header *info, *parent;
+
+ if (unlikely(ptr == NULL))
+ return;
+
+ info = get_header(ptr);
+ parent = get_header(new_ctx);
+
+ unlink_block(info);
+
+ add_child(parent, info);
+}
+
+void *
+ralloc_parent(const void *ptr)
+{
+ ralloc_header *info;
+
+ if (unlikely(ptr == NULL))
+ return NULL;
+
+ info = get_header(ptr);
+ return PTR_FROM_HEADER(info->parent);
+}
+
+static void *autofree_context = NULL;
+
+static void
+autofree(void)
+{
+ ralloc_free(autofree_context);
+}
+
+void *
+ralloc_autofree_context(void)
+{
+ if (unlikely(autofree_context == NULL)) {
+ autofree_context = ralloc_context(NULL);
+ atexit(autofree);
+ }
+ return autofree_context;
+}
+
+void
+ralloc_set_destructor(const void *ptr, void(*destructor)(void *))
+{
+ ralloc_header *info = get_header(ptr);
+ info->destructor = destructor;
+}
+
+char *
+ralloc_strdup(const void *ctx, const char *str)
+{
+ size_t n;
+ char *ptr;
+
+ if (unlikely(str == NULL))
+ return NULL;
+
+ n = strlen(str);
+ ptr = ralloc_array(ctx, char, n + 1);
+ memcpy(ptr, str, n);
+ ptr[n] = '\0';
+ return ptr;
+}
+
+char *
+ralloc_strndup(const void *ctx, const char *str, size_t max)
+{
+ size_t n;
+ char *ptr;
+
+ if (unlikely(str == NULL))
+ return NULL;
+
+ n = strlen(str);
+ if (n > max)
+ n = max;
+
+ ptr = ralloc_array(ctx, char, n + 1);
+ memcpy(ptr, str, n);
+ ptr[n] = '\0';
+ return ptr;
+}
+
+/* helper routine for strcat/strncat - n is the exact amount to copy */
+static bool
+cat(char **dest, const char *str, size_t n)
+{
+ char *both;
+ size_t existing_length;
+ assert(dest != NULL && *dest != NULL);
+
+ existing_length = strlen(*dest);
+ both = resize(*dest, existing_length + n + 1);
+ if (unlikely(both == NULL))
+ return false;
+
+ memcpy(both + existing_length, str, n);
+ both[existing_length + n] = '\0';
+
+ *dest = both;
+ return true;
+}
+
+
+bool
+ralloc_strcat(char **dest, const char *str)
+{
+ return cat(dest, str, strlen(str));
+}
+
+bool
+ralloc_strncat(char **dest, const char *str, size_t n)
+{
+ /* Clamp n to the string length */
+ size_t str_length = strlen(str);
+ if (str_length < n)
+ n = str_length;
+
+ return cat(dest, str, n);
+}
+
+char *
+ralloc_asprintf(const void *ctx, const char *fmt, ...)
+{
+ char *ptr;
+ va_list args;
+ va_start(args, fmt);
+ ptr = ralloc_vasprintf(ctx, fmt, args);
+ va_end(args);
+ return ptr;
+}
+
+/* Return the length of the string that would be generated by a printf-style
+ * format and argument list, not including the \0 byte.
+ */
+static size_t
+printf_length(const char *fmt, va_list untouched_args)
+{
+ int size;
+ char junk;
+
+ /* Make a copy of the va_list so the original caller can still use it */
+ va_list args;
+ va_copy(args, untouched_args);
+
+ size = vsnprintf(&junk, 1, fmt, args);
+ assert(size >= 0);
+
+ return size;
+}
+
+char *
+ralloc_vasprintf(const void *ctx, const char *fmt, va_list args)
+{
+ size_t size = printf_length(fmt, args) + 1;
+
+ char *ptr = ralloc_size(ctx, size);
+ if (ptr != NULL)
+ vsnprintf(ptr, size, fmt, args);
+
+ return ptr;
+}
+
+bool
+ralloc_asprintf_append(char **str, const char *fmt, ...)
+{
+ bool success;
+ va_list args;
+ va_start(args, fmt);
+ success = ralloc_vasprintf_append(str, fmt, args);
+ va_end(args);
+ return success;
+}
+
+bool
+ralloc_vasprintf_append(char **str, const char *fmt, va_list args)
+{
+ size_t existing_length, new_length;
+ char *ptr;
+
+ assert(str != NULL);
+
+ if (unlikely(*str == NULL)) {
+ // Assuming a NULL context is probably bad, but it's expected behavior.
+ *str = ralloc_vasprintf(NULL, fmt, args);
+ return true;
+ }
+
+ existing_length = strlen(*str);
+ new_length = printf_length(fmt, args);
+
+ ptr = resize(*str, existing_length + new_length + 1);
+ if (unlikely(ptr == NULL))
+ return false;
+
+ vsnprintf(ptr + existing_length, new_length + 1, fmt, args);
+ *str = ptr;
+ return true;
+}
diff --git a/mesalib/src/glsl/ralloc.h b/mesalib/src/glsl/ralloc.h
new file mode 100644
index 000000000..d5338152f
--- /dev/null
+++ b/mesalib/src/glsl/ralloc.h
@@ -0,0 +1,345 @@
+/*
+ * 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 ralloc.h
+ *
+ * ralloc: a recursive memory allocator
+ *
+ * The ralloc memory allocator creates a hierarchy of allocated
+ * objects. Every allocation is in reference to some parent, and
+ * every allocated object can in turn be used as the parent of a
+ * subsequent allocation. This allows for extremely convenient
+ * discarding of an entire tree/sub-tree of allocations by calling
+ * ralloc_free on any particular object to free it and all of its
+ * children.
+ *
+ * The conceptual working of ralloc was directly inspired by Andrew
+ * Tridgell's talloc, but ralloc is an independent implementation
+ * released under the MIT license and tuned for Mesa.
+ *
+ * The talloc implementation is available under the GNU Lesser
+ * General Public License (GNU LGPL), version 3 or later. It is
+ * more sophisticated than ralloc in that it includes reference
+ * counting and debugging features. See: http://talloc.samba.org/
+ */
+
+#ifndef RALLOC_H
+#define RALLOC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+/**
+ * \def ralloc(ctx, type)
+ * Allocate a new object chained off of the given context.
+ *
+ * This is equivalent to:
+ * \code
+ * ((type *) ralloc_size(ctx, sizeof(type))
+ * \endcode
+ */
+#define ralloc(ctx, type) ((type *) ralloc_size(ctx, sizeof(type)))
+
+/**
+ * \def rzalloc(ctx, type)
+ * Allocate a new object out of the given context and initialize it to zero.
+ *
+ * This is equivalent to:
+ * \code
+ * ((type *) rzalloc_size(ctx, sizeof(type))
+ * \endcode
+ */
+#define rzalloc(ctx, type) ((type *) rzalloc_size(ctx, sizeof(type)))
+
+/**
+ * Allocate a new ralloc context.
+ *
+ * While any ralloc'd pointer can be used as a context, sometimes it is useful
+ * to simply allocate a context with no associated memory.
+ *
+ * It is equivalent to:
+ * \code
+ * ((type *) ralloc_size(ctx, 0)
+ * \endcode
+ */
+void *ralloc_context(const void *ctx);
+
+/**
+ * Allocate memory chained off of the given context.
+ *
+ * This is the core allocation routine which is used by all others. It
+ * simply allocates storage for \p size bytes and returns the pointer,
+ * similar to \c malloc.
+ */
+void *ralloc_size(const void *ctx, size_t size);
+
+/**
+ * Allocate zero-initialized memory chained off of the given context.
+ *
+ * This is similar to \c calloc with a size of 1.
+ */
+void *rzalloc_size(const void *ctx, size_t size);
+
+/**
+ * Resize a piece of ralloc-managed memory, preserving data.
+ *
+ * Similar to \c realloc. Unlike C89, passing 0 for \p size does not free the
+ * memory. Instead, it resizes it to a 0-byte ralloc context, just like
+ * calling ralloc_size(ctx, 0). This is different from talloc.
+ *
+ * \param ctx The context to use for new allocation. If \p ptr != NULL,
+ * it must be the same as ralloc_parent(\p ptr).
+ * \param ptr Pointer to the memory to be resized. May be NULL.
+ * \param size The amount of memory to allocate, in bytes.
+ */
+void *reralloc_size(const void *ctx, void *ptr, size_t size);
+
+/// \defgroup array Array Allocators @{
+
+/**
+ * \def ralloc_array(ctx, type, count)
+ * Allocate an array of objects chained off the given context.
+ *
+ * Similar to \c calloc, but does not initialize the memory to zero.
+ *
+ * More than a convenience function, this also checks for integer overflow when
+ * multiplying \c sizeof(type) and \p count. This is necessary for security.
+ *
+ * This is equivalent to:
+ * \code
+ * ((type *) ralloc_array_size(ctx, sizeof(type), count)
+ * \endcode
+ */
+#define ralloc_array(ctx, type, count) \
+ ((type *) ralloc_array_size(ctx, sizeof(type), count))
+
+/**
+ * \def rzalloc_array(ctx, type, count)
+ * Allocate a zero-initialized array chained off the given context.
+ *
+ * Similar to \c calloc.
+ *
+ * More than a convenience function, this also checks for integer overflow when
+ * multiplying \c sizeof(type) and \p count. This is necessary for security.
+ *
+ * This is equivalent to:
+ * \code
+ * ((type *) rzalloc_array_size(ctx, sizeof(type), count)
+ * \endcode
+ */
+#define rzalloc_array(ctx, type, count) \
+ ((type *) rzalloc_array_size(ctx, sizeof(type), count))
+
+/**
+ * \def reralloc(ctx, ptr, type, count)
+ * Resize a ralloc-managed array, preserving data.
+ *
+ * Similar to \c realloc. Unlike C89, passing 0 for \p size does not free the
+ * memory. Instead, it resizes it to a 0-byte ralloc context, just like
+ * calling ralloc_size(ctx, 0). This is different from talloc.
+ *
+ * More than a convenience function, this also checks for integer overflow when
+ * multiplying \c sizeof(type) and \p count. This is necessary for security.
+ *
+ * \param ctx The context to use for new allocation. If \p ptr != NULL,
+ * it must be the same as ralloc_parent(\p ptr).
+ * \param ptr Pointer to the array to be resized. May be NULL.
+ * \param type The element type.
+ * \param count The number of elements to allocate.
+ */
+#define reralloc(ctx, ptr, type, count) \
+ ((type *) reralloc_array_size(ctx, ptr, sizeof(type), count))
+
+/**
+ * Allocate memory for an array chained off the given context.
+ *
+ * Similar to \c calloc, but does not initialize the memory to zero.
+ *
+ * More than a convenience function, this also checks for integer overflow when
+ * multiplying \p size and \p count. This is necessary for security.
+ */
+void *ralloc_array_size(const void *ctx, size_t size, unsigned count);
+
+/**
+ * Allocate a zero-initialized array chained off the given context.
+ *
+ * Similar to \c calloc.
+ *
+ * More than a convenience function, this also checks for integer overflow when
+ * multiplying \p size and \p count. This is necessary for security.
+ */
+void *rzalloc_array_size(const void *ctx, size_t size, unsigned count);
+
+/**
+ * Resize a ralloc-managed array, preserving data.
+ *
+ * Similar to \c realloc. Unlike C89, passing 0 for \p size does not free the
+ * memory. Instead, it resizes it to a 0-byte ralloc context, just like
+ * calling ralloc_size(ctx, 0). This is different from talloc.
+ *
+ * More than a convenience function, this also checks for integer overflow when
+ * multiplying \c sizeof(type) and \p count. This is necessary for security.
+ *
+ * \param ctx The context to use for new allocation. If \p ptr != NULL,
+ * it must be the same as ralloc_parent(\p ptr).
+ * \param ptr Pointer to the array to be resized. May be NULL.
+ * \param size The size of an individual element.
+ * \param count The number of elements to allocate.
+ *
+ * \return True unless allocation failed.
+ */
+void *reralloc_array_size(const void *ctx, void *ptr, size_t size,
+ unsigned count);
+/// @}
+
+/**
+ * Free a piece of ralloc-managed memory.
+ *
+ * This will also free the memory of any children allocated this context.
+ */
+void ralloc_free(void *ptr);
+
+/**
+ * "Steal" memory from one context, changing it to another.
+ *
+ * This changes \p ptr's context to \p new_ctx. This is quite useful if
+ * memory is allocated out of a temporary context.
+ */
+void ralloc_steal(const void *new_ctx, void *ptr);
+
+/**
+ * Return the given pointer's ralloc context.
+ */
+void *ralloc_parent(const void *ptr);
+
+/**
+ * Return a context whose memory will be automatically freed at program exit.
+ *
+ * The first call to this function creates a context and registers a handler
+ * to free it using \c atexit. This may cause trouble if used in a library
+ * loaded with \c dlopen.
+ */
+void *ralloc_autofree_context(void);
+
+/**
+ * Set a callback to occur just before an object is freed.
+ */
+void ralloc_set_destructor(const void *ptr, void(*destructor)(void *));
+
+/// \defgroup array String Functions @{
+/**
+ * Duplicate a string, allocating the memory from the given context.
+ */
+char *ralloc_strdup(const void *ctx, const char *str);
+
+/**
+ * Duplicate a string, allocating the memory from the given context.
+ *
+ * Like \c strndup, at most \p n characters are copied. If \p str is longer
+ * than \p n characters, \p n are copied, and a termining \c '\0' byte is added.
+ */
+char *ralloc_strndup(const void *ctx, const char *str, size_t n);
+
+/**
+ * Concatenate two strings, allocating the necessary space.
+ *
+ * This appends \p str to \p *dest, similar to \c strcat, using ralloc_resize
+ * to expand \p *dest to the appropriate size. \p dest will be updated to the
+ * new pointer unless allocation fails.
+ *
+ * The result will always be null-terminated.
+ *
+ * \return True unless allocation failed.
+ */
+bool ralloc_strcat(char **dest, const char *str);
+
+/**
+ * Concatenate two strings, allocating the necessary space.
+ *
+ * This appends at most \p n bytes of \p str to \p *dest, using ralloc_resize
+ * to expand \p *dest to the appropriate size. \p dest will be updated to the
+ * new pointer unless allocation fails.
+ *
+ * The result will always be null-terminated; \p str does not need to be null
+ * terminated if it is longer than \p n.
+ *
+ * \return True unless allocation failed.
+ */
+bool ralloc_strncat(char **dest, const char *str, size_t n);
+
+/**
+ * Print to a string.
+ *
+ * This is analogous to \c sprintf, but allocates enough space (using \p ctx
+ * as the context) for the resulting string.
+ *
+ * \return The newly allocated string.
+ */
+char *ralloc_asprintf (const void *ctx, const char *fmt, ...);
+
+/**
+ * Print to a string, given a va_list.
+ *
+ * This is analogous to \c vsprintf, but allocates enough space (using \p ctx
+ * as the context) for the resulting string.
+ *
+ * \return The newly allocated string.
+ */
+char *ralloc_vasprintf(const void *ctx, const char *fmt, va_list args);
+
+/**
+ * Append formatted text to the supplied string.
+ *
+ * \sa ralloc_asprintf
+ * \sa ralloc_strcat
+ *
+ * \p str will be updated to the new pointer unless allocation fails.
+ *
+ * \return True unless allocation failed.
+ */
+bool ralloc_asprintf_append (char **str, const char *fmt, ...);
+
+/**
+ * Append formatted text to the supplied string, given a va_list.
+ *
+ * \sa ralloc_vasprintf
+ * \sa ralloc_strcat
+ *
+ * \p str will be updated to the new pointer unless allocation fails.
+ *
+ * \return True unless allocation failed.
+ */
+bool ralloc_vasprintf_append(char **str, const char *fmt, va_list args);
+/// @}
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif
diff --git a/mesalib/src/glsl/s_expression.cpp b/mesalib/src/glsl/s_expression.cpp
index 36624541b..77ac08ac7 100644
--- a/mesalib/src/glsl/s_expression.cpp
+++ b/mesalib/src/glsl/s_expression.cpp
@@ -1,186 +1,186 @@
-/* -*- c++ -*- */
-/*
- * 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 <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <assert.h>
-#include "s_expression.h"
-
-s_symbol::s_symbol(const char *tmp, size_t n)
-{
- this->str = talloc_strndup (this, tmp, n);
- assert(this->str != NULL);
-}
-
-s_list::s_list()
-{
-}
-
-static void
-skip_whitespace(const char *& src)
-{
- src += strspn(src, " \v\t\r\n");
- /* Also skip Scheme-style comments: semi-colon 'til end of line */
- if (src[0] == ';') {
- src += strcspn(src, "\n");
- skip_whitespace(src);
- }
-}
-
-static s_expression *
-read_atom(void *ctx, const char *& src)
-{
- s_expression *expr = NULL;
-
- skip_whitespace(src);
-
- size_t n = strcspn(src, "( \v\t\r\n);");
- if (n == 0)
- return NULL; // no atom
-
- // Check if the atom is a number.
- char *float_end = NULL;
- double f = glsl_strtod(src, &float_end);
- if (float_end != src) {
- char *int_end = NULL;
- int i = strtol(src, &int_end, 10);
- // If strtod matched more characters, it must have a decimal part
- if (float_end > int_end)
- expr = new(ctx) s_float(f);
- else
- expr = new(ctx) s_int(i);
- } else {
- // Not a number; return a symbol.
- expr = new(ctx) s_symbol(src, n);
- }
-
- src += n;
-
- return expr;
-}
-
-s_expression *
-s_expression::read_expression(void *ctx, const char *&src)
-{
- assert(src != NULL);
-
- s_expression *atom = read_atom(ctx, src);
- if (atom != NULL)
- return atom;
-
- skip_whitespace(src);
- if (src[0] == '(') {
- ++src;
-
- s_list *list = new(ctx) s_list;
- s_expression *expr;
-
- while ((expr = read_expression(ctx, src)) != NULL) {
- list->subexpressions.push_tail(expr);
- }
- skip_whitespace(src);
- if (src[0] != ')') {
- printf("Unclosed expression (check your parenthesis).\n");
- return NULL;
- }
- ++src;
- return list;
- }
- return NULL;
-}
-
-void s_int::print()
-{
- printf("%d", this->val);
-}
-
-void s_float::print()
-{
- printf("%f", this->val);
-}
-
-void s_symbol::print()
-{
- printf("%s", this->str);
-}
-
-void s_list::print()
-{
- printf("(");
- foreach_iter(exec_list_iterator, it, this->subexpressions) {
- s_expression *expr = (s_expression*) it.get();
- expr->print();
- if (!expr->next->is_tail_sentinel())
- printf(" ");
- }
- printf(")");
-}
-
-// --------------------------------------------------
-
-bool
-s_pattern::match(s_expression *expr)
-{
- switch (type)
- {
- case EXPR: *p_expr = expr; break;
- case LIST: if (expr->is_list()) *p_list = (s_list *) expr; break;
- case SYMBOL: if (expr->is_symbol()) *p_symbol = (s_symbol *) expr; break;
- case NUMBER: if (expr->is_number()) *p_number = (s_number *) expr; break;
- case INT: if (expr->is_int()) *p_int = (s_int *) expr; break;
- case STRING:
- s_symbol *sym = SX_AS_SYMBOL(expr);
- if (sym != NULL && strcmp(sym->value(), literal) == 0)
- return true;
- return false;
- };
-
- return *p_expr == expr;
-}
-
-bool
-s_match(s_expression *top, unsigned n, s_pattern *pattern, bool partial)
-{
- s_list *list = SX_AS_LIST(top);
- if (list == NULL)
- return false;
-
- unsigned i = 0;
- foreach_iter(exec_list_iterator, it, list->subexpressions) {
- if (i >= n)
- return partial; /* More actual items than the pattern expected */
-
- s_expression *expr = (s_expression *) it.get();
- if (expr == NULL || !pattern[i].match(expr))
- return false;
-
- i++;
- }
-
- if (i < n)
- return false; /* Less actual items than the pattern expected */
-
- return true;
-}
+/* -*- c++ -*- */
+/*
+ * 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 <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <assert.h>
+#include "s_expression.h"
+
+s_symbol::s_symbol(const char *tmp, size_t n)
+{
+ this->str = ralloc_strndup (this, tmp, n);
+ assert(this->str != NULL);
+}
+
+s_list::s_list()
+{
+}
+
+static void
+skip_whitespace(const char *& src)
+{
+ src += strspn(src, " \v\t\r\n");
+ /* Also skip Scheme-style comments: semi-colon 'til end of line */
+ if (src[0] == ';') {
+ src += strcspn(src, "\n");
+ skip_whitespace(src);
+ }
+}
+
+static s_expression *
+read_atom(void *ctx, const char *& src)
+{
+ s_expression *expr = NULL;
+
+ skip_whitespace(src);
+
+ size_t n = strcspn(src, "( \v\t\r\n);");
+ if (n == 0)
+ return NULL; // no atom
+
+ // Check if the atom is a number.
+ char *float_end = NULL;
+ double f = glsl_strtod(src, &float_end);
+ if (float_end != src) {
+ char *int_end = NULL;
+ int i = strtol(src, &int_end, 10);
+ // If strtod matched more characters, it must have a decimal part
+ if (float_end > int_end)
+ expr = new(ctx) s_float(f);
+ else
+ expr = new(ctx) s_int(i);
+ } else {
+ // Not a number; return a symbol.
+ expr = new(ctx) s_symbol(src, n);
+ }
+
+ src += n;
+
+ return expr;
+}
+
+s_expression *
+s_expression::read_expression(void *ctx, const char *&src)
+{
+ assert(src != NULL);
+
+ s_expression *atom = read_atom(ctx, src);
+ if (atom != NULL)
+ return atom;
+
+ skip_whitespace(src);
+ if (src[0] == '(') {
+ ++src;
+
+ s_list *list = new(ctx) s_list;
+ s_expression *expr;
+
+ while ((expr = read_expression(ctx, src)) != NULL) {
+ list->subexpressions.push_tail(expr);
+ }
+ skip_whitespace(src);
+ if (src[0] != ')') {
+ printf("Unclosed expression (check your parenthesis).\n");
+ return NULL;
+ }
+ ++src;
+ return list;
+ }
+ return NULL;
+}
+
+void s_int::print()
+{
+ printf("%d", this->val);
+}
+
+void s_float::print()
+{
+ printf("%f", this->val);
+}
+
+void s_symbol::print()
+{
+ printf("%s", this->str);
+}
+
+void s_list::print()
+{
+ printf("(");
+ foreach_iter(exec_list_iterator, it, this->subexpressions) {
+ s_expression *expr = (s_expression*) it.get();
+ expr->print();
+ if (!expr->next->is_tail_sentinel())
+ printf(" ");
+ }
+ printf(")");
+}
+
+// --------------------------------------------------
+
+bool
+s_pattern::match(s_expression *expr)
+{
+ switch (type)
+ {
+ case EXPR: *p_expr = expr; break;
+ case LIST: if (expr->is_list()) *p_list = (s_list *) expr; break;
+ case SYMBOL: if (expr->is_symbol()) *p_symbol = (s_symbol *) expr; break;
+ case NUMBER: if (expr->is_number()) *p_number = (s_number *) expr; break;
+ case INT: if (expr->is_int()) *p_int = (s_int *) expr; break;
+ case STRING:
+ s_symbol *sym = SX_AS_SYMBOL(expr);
+ if (sym != NULL && strcmp(sym->value(), literal) == 0)
+ return true;
+ return false;
+ };
+
+ return *p_expr == expr;
+}
+
+bool
+s_match(s_expression *top, unsigned n, s_pattern *pattern, bool partial)
+{
+ s_list *list = SX_AS_LIST(top);
+ if (list == NULL)
+ return false;
+
+ unsigned i = 0;
+ foreach_iter(exec_list_iterator, it, list->subexpressions) {
+ if (i >= n)
+ return partial; /* More actual items than the pattern expected */
+
+ s_expression *expr = (s_expression *) it.get();
+ if (expr == NULL || !pattern[i].match(expr))
+ return false;
+
+ i++;
+ }
+
+ if (i < n)
+ return false; /* Less actual items than the pattern expected */
+
+ return true;
+}
diff --git a/mesalib/src/glsl/s_expression.h b/mesalib/src/glsl/s_expression.h
index 1bb437736..c9dc676b3 100644
--- a/mesalib/src/glsl/s_expression.h
+++ b/mesalib/src/glsl/s_expression.h
@@ -1,180 +1,180 @@
-/* -*- c++ -*- */
-/*
- * 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 S_EXPRESSION_H
-#define S_EXPRESSION_H
-
-#include "main/core.h" /* for Elements */
-#include "strtod.h"
-#include "list.h"
-
-/* Type-safe downcasting macros (also safe to pass NULL) */
-#define SX_AS_(t,x) ((x) && ((s_expression*) x)->is_##t()) ? ((s_##t*) (x)) \
- : NULL
-#define SX_AS_LIST(x) SX_AS_(list, x)
-#define SX_AS_SYMBOL(x) SX_AS_(symbol, x)
-#define SX_AS_NUMBER(x) SX_AS_(number, x)
-#define SX_AS_INT(x) SX_AS_(int, x)
-
-/* Pattern matching macros */
-#define MATCH(list, pat) s_match(list, Elements(pat), pat, false)
-#define PARTIAL_MATCH(list, pat) s_match(list, Elements(pat), pat, true)
-
-/* For our purposes, S-Expressions are:
- * - <int>
- * - <float>
- * - symbol
- * - (expr1 expr2 ... exprN) where exprN is an S-Expression
- *
- * Unlike LISP/Scheme, we do not support (foo . bar) pairs.
- */
-class s_expression : public exec_node
-{
-public:
- /**
- * Read an S-Expression from the given string.
- * Advances the supplied pointer to just after the expression read.
- *
- * Any allocation will be performed with 'ctx' as the talloc owner.
- */
- static s_expression *read_expression(void *ctx, const char *&src);
-
- /**
- * Print out an S-Expression. Useful for debugging.
- */
- virtual void print() = 0;
-
- virtual bool is_list() const { return false; }
- virtual bool is_symbol() const { return false; }
- virtual bool is_number() const { return false; }
- virtual bool is_int() const { return false; }
-
-protected:
- s_expression() { }
-};
-
-/* Atoms */
-
-class s_number : public s_expression
-{
-public:
- bool is_number() const { return true; }
-
- virtual float fvalue() = 0;
-
-protected:
- s_number() { }
-};
-
-class s_int : public s_number
-{
-public:
- s_int(int x) : val(x) { }
-
- bool is_int() const { return true; }
-
- float fvalue() { return float(this->val); }
- int value() { return this->val; }
-
- void print();
-
-private:
- int val;
-};
-
-class s_float : public s_number
-{
-public:
- s_float(float x) : val(x) { }
-
- float fvalue() { return this->val; }
-
- void print();
-
-private:
- float val;
-};
-
-class s_symbol : public s_expression
-{
-public:
- s_symbol(const char *, size_t);
-
- bool is_symbol() const { return true; }
-
- const char *value() { return this->str; }
-
- void print();
-
-private:
- char *str;
-};
-
-/* Lists of expressions: (expr1 ... exprN) */
-class s_list : public s_expression
-{
-public:
- s_list();
-
- virtual bool is_list() const { return true; }
-
- void print();
-
- exec_list subexpressions;
-};
-
-// ------------------------------------------------------------
-
-/**
- * Part of a pattern to match - essentially a record holding a pointer to the
- * storage for the component to match, along with the appropriate type.
- */
-class s_pattern {
-public:
- s_pattern(s_expression *&s) : p_expr(&s), type(EXPR) { }
- s_pattern(s_list *&s) : p_list(&s), type(LIST) { }
- s_pattern(s_symbol *&s) : p_symbol(&s), type(SYMBOL) { }
- s_pattern(s_number *&s) : p_number(&s), type(NUMBER) { }
- s_pattern(s_int *&s) : p_int(&s), type(INT) { }
- s_pattern(const char *str) : literal(str), type(STRING) { }
-
- bool match(s_expression *expr);
-
-private:
- union {
- s_expression **p_expr;
- s_list **p_list;
- s_symbol **p_symbol;
- s_number **p_number;
- s_int **p_int;
- const char *literal;
- };
- enum { EXPR, LIST, SYMBOL, NUMBER, INT, STRING } type;
-};
-
-bool
-s_match(s_expression *top, unsigned n, s_pattern *pattern, bool partial);
-
-#endif /* S_EXPRESSION_H */
+/* -*- c++ -*- */
+/*
+ * 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 S_EXPRESSION_H
+#define S_EXPRESSION_H
+
+#include "main/core.h" /* for Elements */
+#include "strtod.h"
+#include "list.h"
+
+/* Type-safe downcasting macros (also safe to pass NULL) */
+#define SX_AS_(t,x) ((x) && ((s_expression*) x)->is_##t()) ? ((s_##t*) (x)) \
+ : NULL
+#define SX_AS_LIST(x) SX_AS_(list, x)
+#define SX_AS_SYMBOL(x) SX_AS_(symbol, x)
+#define SX_AS_NUMBER(x) SX_AS_(number, x)
+#define SX_AS_INT(x) SX_AS_(int, x)
+
+/* Pattern matching macros */
+#define MATCH(list, pat) s_match(list, Elements(pat), pat, false)
+#define PARTIAL_MATCH(list, pat) s_match(list, Elements(pat), pat, true)
+
+/* For our purposes, S-Expressions are:
+ * - <int>
+ * - <float>
+ * - symbol
+ * - (expr1 expr2 ... exprN) where exprN is an S-Expression
+ *
+ * Unlike LISP/Scheme, we do not support (foo . bar) pairs.
+ */
+class s_expression : public exec_node
+{
+public:
+ /**
+ * Read an S-Expression from the given string.
+ * Advances the supplied pointer to just after the expression read.
+ *
+ * Any allocation will be performed with 'ctx' as the ralloc owner.
+ */
+ static s_expression *read_expression(void *ctx, const char *&src);
+
+ /**
+ * Print out an S-Expression. Useful for debugging.
+ */
+ virtual void print() = 0;
+
+ virtual bool is_list() const { return false; }
+ virtual bool is_symbol() const { return false; }
+ virtual bool is_number() const { return false; }
+ virtual bool is_int() const { return false; }
+
+protected:
+ s_expression() { }
+};
+
+/* Atoms */
+
+class s_number : public s_expression
+{
+public:
+ bool is_number() const { return true; }
+
+ virtual float fvalue() = 0;
+
+protected:
+ s_number() { }
+};
+
+class s_int : public s_number
+{
+public:
+ s_int(int x) : val(x) { }
+
+ bool is_int() const { return true; }
+
+ float fvalue() { return float(this->val); }
+ int value() { return this->val; }
+
+ void print();
+
+private:
+ int val;
+};
+
+class s_float : public s_number
+{
+public:
+ s_float(float x) : val(x) { }
+
+ float fvalue() { return this->val; }
+
+ void print();
+
+private:
+ float val;
+};
+
+class s_symbol : public s_expression
+{
+public:
+ s_symbol(const char *, size_t);
+
+ bool is_symbol() const { return true; }
+
+ const char *value() { return this->str; }
+
+ void print();
+
+private:
+ char *str;
+};
+
+/* Lists of expressions: (expr1 ... exprN) */
+class s_list : public s_expression
+{
+public:
+ s_list();
+
+ virtual bool is_list() const { return true; }
+
+ void print();
+
+ exec_list subexpressions;
+};
+
+// ------------------------------------------------------------
+
+/**
+ * Part of a pattern to match - essentially a record holding a pointer to the
+ * storage for the component to match, along with the appropriate type.
+ */
+class s_pattern {
+public:
+ s_pattern(s_expression *&s) : p_expr(&s), type(EXPR) { }
+ s_pattern(s_list *&s) : p_list(&s), type(LIST) { }
+ s_pattern(s_symbol *&s) : p_symbol(&s), type(SYMBOL) { }
+ s_pattern(s_number *&s) : p_number(&s), type(NUMBER) { }
+ s_pattern(s_int *&s) : p_int(&s), type(INT) { }
+ s_pattern(const char *str) : literal(str), type(STRING) { }
+
+ bool match(s_expression *expr);
+
+private:
+ union {
+ s_expression **p_expr;
+ s_list **p_list;
+ s_symbol **p_symbol;
+ s_number **p_number;
+ s_int **p_int;
+ const char *literal;
+ };
+ enum { EXPR, LIST, SYMBOL, NUMBER, INT, STRING } type;
+};
+
+bool
+s_match(s_expression *top, unsigned n, s_pattern *pattern, bool partial);
+
+#endif /* S_EXPRESSION_H */