Set language_version to 130 (the max currently supported) when reading IR.
[mesa.git] / glsl_parser_extras.cpp
index d57a68efb7551040cb2b67f5a1e8d31ce022885a..efcb125dfc54a5d4762a9b35dbaa8d2eb66f4128 100644 (file)
 #include "ast.h"
 #include "glsl_parser_extras.h"
 #include "glsl_parser.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"
+#include "ir_reader.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, _mesa_glsl_parse_state *state,
@@ -57,6 +75,94 @@ _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
 }
 
 
+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 */
@@ -104,7 +210,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 ");
 }
 
 
@@ -327,6 +433,7 @@ ast_function::print(void) const
 
 
 ast_function::ast_function(void)
+   : is_definition(false), signature(NULL)
 {
    make_empty_list(& parameters);
 }
@@ -609,10 +716,12 @@ main(int argc, char **argv)
    exec_list instructions;
 
    if (argc < 3) {
-      printf("Usage: %s [v|g|f] <shader_file>\n", argv[0]);
+      printf("Usage: %s [v|g|f|i] <shader_file>\n", argv[0]);
       return EXIT_FAILURE;
    }
 
+   memset(& state, 0, sizeof(state));
+
    switch (argv[1][0]) {
    case 'v':
       state.target = vertex_shader;
@@ -623,8 +732,11 @@ main(int argc, char **argv)
    case 'f':
       state.target = fragment_shader;
       break;
+   case 'i':
+      state.target = ir_shader;
+      break;
    default:
-      printf("Usage: %s [v|g|f] <shader_file>\n", argv[0]);
+      printf("Usage: %s [v|g|f|i] <shader_file>\n", argv[0]);
       return EXIT_FAILURE;
    }
 
@@ -634,26 +746,57 @@ main(int argc, char **argv)
    make_empty_list(& state.translation_unit);
    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);
-   _mesa_glsl_lexer_dtor(& state);
+   if (state.target != ir_shader) {
+      _mesa_glsl_lexer_ctor(& state, shader, shader_len);
+      _mesa_glsl_parse(& state);
+      _mesa_glsl_lexer_dtor(& state);
 
-   foreach (ptr, & state.translation_unit) {
-      ((ast_node *)ptr)->print();
+      foreach (ptr, & state.translation_unit) {
+        ((ast_node *)ptr)->print();
+      }
+
+      _mesa_ast_to_hir(&instructions, &state);
+   } else {
+      /* FINISHME: We should initialize this to the max GLSL version supported
+       * FINISHME: by the driver.  At the moment, we don't know what that is.
+       */
+      state.language_version = 130;
+
+      _mesa_glsl_read_ir(&state, &instructions, shader);
    }
 
-   _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");
 
    if (!state.error) {
+      printf("(\n");
       foreach_iter(exec_list_iterator, iter, instructions) {
         ir_print_visitor v;
 
         ((ir_instruction *)iter.get())->accept(& v);
         printf("\n");
       }
+      printf("\n)");
    }
 
    delete state.symbols;