Fix the swizzling of vector constructors from scalars.
[mesa.git] / glsl_parser_extras.cpp
index 222f06b5263028898828a2725d251be15b890a08..c808052ee78c45eb28282997fbf5c82c8cf53aa4 100644 (file)
 #include "ast.h"
 #include "glsl_parser_extras.h"
 #include "glsl_parser.h"
-#include "symbol_table.h"
+#include "ir_constant_folding.h"
+#include "ir_dead_code.h"
+#include "ir_function_inlining.h"
+#include "ir_if_simplification.h"
 #include "ir_print_visitor.h"
 
+const char *
+_mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target)
+{
+   switch (target) {
+   case vertex_shader:   return "vertex";
+   case fragment_shader: return "fragment";
+   case geometry_shader: return "geometry";
+   }
+
+   assert(!"Should not get here.");
+}
+
+
 void
-_mesa_glsl_error(YYLTYPE *locp, void *state, const char *fmt, ...)
+_mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
+                const char *fmt, ...)
 {
    char buf[1024];
    int len;
    va_list ap;
 
-   (void) state;
+   state->error = true;
+
    len = snprintf(buf, sizeof(buf), "%u:%u(%u): error: ",
                  locp->source, locp->first_line, locp->first_column);
 
@@ -56,6 +74,94 @@ _mesa_glsl_error(YYLTYPE *locp, void *state, const char *fmt, ...)
 }
 
 
+void
+_mesa_glsl_warning(const YYLTYPE *locp, const _mesa_glsl_parse_state *state,
+                  const char *fmt, ...)
+{
+   char buf[1024];
+   int len;
+   va_list ap;
+
+   len = snprintf(buf, sizeof(buf), "%u:%u(%u): warning: ",
+                 locp->source, locp->first_line, locp->first_column);
+
+   va_start(ap, fmt);
+   vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
+   va_end(ap);
+
+   printf("%s\n", buf);
+}
+
+
+bool
+_mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
+                            const char *behavior, YYLTYPE *behavior_locp,
+                            _mesa_glsl_parse_state *state)
+{
+   enum {
+      extension_disable,
+      extension_enable,
+      extension_require,
+      extension_warn
+   } ext_mode;
+
+   if (strcmp(behavior, "warn") == 0) {
+      ext_mode = extension_warn;
+   } else if (strcmp(behavior, "require") == 0) {
+      ext_mode = extension_require;
+   } else if (strcmp(behavior, "enable") == 0) {
+      ext_mode = extension_enable;
+   } else if (strcmp(behavior, "disable") == 0) {
+      ext_mode = extension_disable;
+   } else {
+      _mesa_glsl_error(behavior_locp, state,
+                      "Unknown extension behavior `%s'",
+                      behavior);
+      return false;
+   }
+
+   bool unsupported = false;
+
+   if (strcmp(name, "all") == 0) {
+      if ((ext_mode == extension_enable) || (ext_mode == extension_require)) {
+        _mesa_glsl_error(name_locp, state, "Cannot %s all extensions",
+                         (ext_mode == extension_enable)
+                         ? "enable" : "require");
+        return false;
+      }
+   } else if (strcmp(name, "GL_ARB_draw_buffers") == 0) {
+      /* This extension is only supported in fragment shaders.
+       */
+      if (state->target != fragment_shader) {
+        unsupported = true;
+      } else {
+        state->ARB_draw_buffers_enable = (ext_mode != extension_disable);
+        state->ARB_draw_buffers_warn = (ext_mode == extension_warn);
+      }
+   } else if (strcmp(name, "GL_ARB_texture_rectangle") == 0) {
+      state->ARB_texture_rectangle_enable = (ext_mode != extension_disable);
+      state->ARB_texture_rectangle_warn = (ext_mode == extension_warn);
+   } else {
+      unsupported = true;
+   }
+
+   if (unsupported) {
+      static const char *const fmt = "extension `%s' unsupported in %s shader";
+
+      if (ext_mode == extension_require) {
+        _mesa_glsl_error(name_locp, state, fmt,
+                         name, _mesa_glsl_shader_target_name(state->target));
+        return false;
+      } else {
+        _mesa_glsl_warning(name_locp, state, fmt,
+                           name, _mesa_glsl_shader_target_name(state->target));
+      }
+   }
+
+   return true;
+}
+
+
 ast_node::~ast_node()
 {
    /* empty */
@@ -103,7 +209,7 @@ _mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
 void
 ast_node::print(void) const
 {
-   printf("node_%d ", type);
+   printf("unhandled node ");
 }
 
 
@@ -112,77 +218,6 @@ ast_node::ast_node(void)
    make_empty_list(this);
 }
 
-void
-ast_type_specifier::print(void) const
-{
-   switch (type_specifier) {
-   case ast_void: printf("void "); break;
-   case ast_float: printf("float "); break;
-   case ast_int: printf("int "); break;
-   case ast_uint: printf("uint "); break;
-   case ast_bool: printf("bool "); break;
-   case ast_vec2: printf("vec2 "); break;
-   case ast_vec3: printf("vec3 "); break;
-   case ast_vec4: printf("vec4 "); break;
-   case ast_bvec2: printf("bvec2 "); break;
-   case ast_bvec3: printf("bvec3 "); break;
-   case ast_bvec4: printf("bvec4 "); break;
-   case ast_ivec2: printf("ivec2 "); break;
-   case ast_ivec3: printf("ivec3 "); break;
-   case ast_ivec4: printf("ivec4 "); break;
-   case ast_uvec2: printf("uvec2 "); break;
-   case ast_uvec3: printf("uvec3 "); break;
-   case ast_uvec4: printf("uvec4 "); break;
-   case ast_mat2: printf("mat2 "); break;
-   case ast_mat2x3: printf("mat2x3 "); break;
-   case ast_mat2x4: printf("mat2x4 "); break;
-   case ast_mat3x2: printf("mat3x2 "); break;
-   case ast_mat3: printf("mat3 "); break;
-   case ast_mat3x4: printf("mat3x4 "); break;
-   case ast_mat4x2: printf("mat4x2 "); break;
-   case ast_mat4x3: printf("mat4x3 "); break;
-   case ast_mat4: printf("mat4 "); break;
-   case ast_sampler1d: printf("sampler1d "); break;
-   case ast_sampler2d: printf("sampler2d "); break;
-   case ast_sampler3d: printf("sampler3d "); break;
-   case ast_samplercube: printf("samplercube "); break;
-   case ast_sampler1dshadow: printf("sampler1dshadow "); break;
-   case ast_sampler2dshadow: printf("sampler2dshadow "); break;
-   case ast_samplercubeshadow: printf("samplercubeshadow "); break;
-   case ast_sampler1darray: printf("sampler1darray "); break;
-   case ast_sampler2darray: printf("sampler2darray "); break;
-   case ast_sampler1darrayshadow: printf("sampler1darrayshadow "); break;
-   case ast_sampler2darrayshadow: printf("sampler2darrayshadow "); break;
-   case ast_isampler1d: printf("isampler1d "); break;
-   case ast_isampler2d: printf("isampler2d "); break;
-   case ast_isampler3d: printf("isampler3d "); break;
-   case ast_isamplercube: printf("isamplercube "); break;
-   case ast_isampler1darray: printf("isampler1darray "); break;
-   case ast_isampler2darray: printf("isampler2darray "); break;
-   case ast_usampler1d: printf("usampler1d "); break;
-   case ast_usampler2d: printf("usampler2d "); break;
-   case ast_usampler3d: printf("usampler3d "); break;
-   case ast_usamplercube: printf("usamplercube "); break;
-   case ast_usampler1darray: printf("usampler1darray "); break;
-   case ast_usampler2darray: printf("usampler2darray "); break;
-
-   case ast_struct:
-      structure->print();
-      break;
-
-   case ast_type_name: printf("%s ", type_name); break;
-   }
-
-   if (is_array) {
-      printf("[ ");
-
-      if (array_size) {
-        array_size->print();
-      }
-
-      printf("] ");
-   }
-}
 
 static void
 ast_opt_array_size_print(bool is_array, const ast_expression *array_size)
@@ -198,12 +233,6 @@ ast_opt_array_size_print(bool is_array, const ast_expression *array_size)
 }
 
 
-ast_type_specifier::ast_type_specifier(int specifier)
-{
-   type_specifier = ast_types(specifier);
-}
-
-
 void
 ast_compound_statement::print(void) const
 {
@@ -403,6 +432,7 @@ ast_function::print(void) const
 
 
 ast_function::ast_function(void)
+   : is_definition(false), signature(NULL)
 {
    make_empty_list(& parameters);
 }
@@ -689,6 +719,8 @@ main(int argc, char **argv)
       return EXIT_FAILURE;
    }
 
+   memset(& state, 0, sizeof(state));
+
    switch (argv[1][0]) {
    case 'v':
       state.target = vertex_shader;
@@ -708,7 +740,11 @@ main(int argc, char **argv)
 
    state.scanner = NULL;
    make_empty_list(& state.translation_unit);
-   state.symbols = _mesa_symbol_table_ctor();
+   state.symbols = new glsl_symbol_table;
+   state.error = false;
+   state.temp_index = 0;
+   state.loop_or_switch_nesting = NULL;
+   state.ARB_texture_rectangle_enable = true;
 
    _mesa_glsl_lexer_ctor(& state, shader, shader_len);
    _mesa_glsl_parse(& state);
@@ -718,18 +754,37 @@ main(int argc, char **argv)
       ((ast_node *)ptr)->print();
    }
 
-   foreach (ptr, & state.translation_unit) {
-      ((ast_node *)ptr)->hir(&instructions, &state);
+   _mesa_ast_to_hir(&instructions, &state);
+
+   /* Optimization passes */
+   if (!state.error) {
+      bool progress;
+      do {
+        progress = false;
+
+        progress = do_function_inlining(&instructions) || progress;
+        progress = do_if_simplification(&instructions) || progress;
+        progress = do_dead_code_unlinked(&instructions) || progress;
+
+        /* Constant folding */
+        ir_constant_folding_visitor constant_folding;
+        visit_exec_list(&instructions, &constant_folding);
+      } while (progress);
    }
 
+   /* Print out the resulting IR */
    printf("\n\n");
-   foreach_iter(exec_list_iterator, iter, instructions) {
-      ir_print_visitor v;
 
-      ((ir_instruction *)iter.get())->accept(& v);
+   if (!state.error) {
+      foreach_iter(exec_list_iterator, iter, instructions) {
+        ir_print_visitor v;
+
+        ((ir_instruction *)iter.get())->accept(& v);
+        printf("\n");
+      }
    }
 
-   _mesa_symbol_table_dtor(state.symbols);
+   delete state.symbols;
 
-   return 0;
+   return state.error != 0;
 }