glsl2: Fix warning from always-false assert not being known to not return.
[mesa.git] / src / glsl / linker.cpp
index ba382fe8816520de7caa97a76a75cfcc0f1dbe1a..c71c07d6e97fef3912f62757e2ebc6a9bbdc4f0a 100644 (file)
@@ -78,6 +78,7 @@ extern "C" {
 #include "ir_optimization.h"
 #include "program.h"
 #include "hash_table.h"
+#include "shader_api.h"
 
 /**
  * Visitor that determines whether or not a variable is ever written.
@@ -114,7 +115,7 @@ private:
 
 
 void
-linker_error_printf(glsl_program *prog, const char *fmt, ...)
+linker_error_printf(gl_shader_program *prog, const char *fmt, ...)
 {
    va_list ap;
 
@@ -126,10 +127,10 @@ linker_error_printf(glsl_program *prog, const char *fmt, ...)
 
 
 void
-invalidate_variable_locations(glsl_shader *sh, enum ir_variable_mode mode,
+invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode,
                              int generic_base)
 {
-   foreach_list(node, &sh->ir) {
+   foreach_list(node, sh->ir) {
       ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
       if ((var == NULL) || (var->mode != (unsigned) mode))
@@ -184,8 +185,8 @@ count_attribute_slots(const glsl_type *t)
  * \param shader  Vertex shader executable to be verified
  */
 bool
-validate_vertex_shader_executable(struct glsl_program *prog,
-                                 struct glsl_shader *shader)
+validate_vertex_shader_executable(struct gl_shader_program *prog,
+                                 struct gl_shader *shader)
 {
    if (shader == NULL)
       return true;
@@ -196,7 +197,7 @@ validate_vertex_shader_executable(struct glsl_program *prog,
    }
 
    find_assignment_visitor find("gl_Position");
-   find.run(&shader->ir);
+   find.run(shader->ir);
    if (!find.variable_found()) {
       linker_error_printf(prog,
                          "vertex shader does not write to `gl_Position'\n");
@@ -213,8 +214,8 @@ validate_vertex_shader_executable(struct glsl_program *prog,
  * \param shader  Fragment shader executable to be verified
  */
 bool
-validate_fragment_shader_executable(struct glsl_program *prog,
-                                   struct glsl_shader *shader)
+validate_fragment_shader_executable(struct gl_shader_program *prog,
+                                   struct gl_shader *shader)
 {
    if (shader == NULL)
       return true;
@@ -227,14 +228,8 @@ validate_fragment_shader_executable(struct glsl_program *prog,
    find_assignment_visitor frag_color("gl_FragColor");
    find_assignment_visitor frag_data("gl_FragData");
 
-   frag_color.run(&shader->ir);
-   frag_data.run(&shader->ir);
-
-   if (!frag_color.variable_found() && !frag_data.variable_found()) {
-      linker_error_printf(prog, "fragment shader does not write to "
-                         "`gl_FragColor' or `gl_FragData'\n");
-      return false;
-   }
+   frag_color.run(shader->ir);
+   frag_data.run(shader->ir);
 
    if (frag_color.variable_found() && frag_data.variable_found()) {
       linker_error_printf(prog,  "fragment shader writes to both "
@@ -247,42 +242,72 @@ validate_fragment_shader_executable(struct glsl_program *prog,
 
 
 /**
- * Perform validation of uniforms used across multiple shader stages
+ * Generate a string describing the mode of a variable
+ */
+static const char *
+mode_string(const ir_variable *var)
+{
+   switch (var->mode) {
+   case ir_var_auto:
+      return (var->read_only) ? "global constant" : "global variable";
+
+   case ir_var_uniform: return "uniform";
+   case ir_var_in:      return "shader input";
+   case ir_var_out:     return "shader output";
+   case ir_var_inout:   return "shader inout";
+   default:
+      assert(!"Should not get here.");
+      return "invalid variable";
+   }
+}
+
+
+/**
+ * Perform validation of global variables used across multiple shaders
  */
 bool
-cross_validate_uniforms(struct glsl_program *prog)
+cross_validate_globals(struct gl_shader_program *prog,
+                      struct gl_shader **shader_list,
+                      unsigned num_shaders,
+                      bool uniforms_only)
 {
    /* Examine all of the uniforms in all of the shaders and cross validate
     * them.
     */
-   glsl_symbol_table uniforms;
-   for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) {
-      foreach_list(node, &prog->_LinkedShaders[i]->ir) {
+   glsl_symbol_table variables;
+   for (unsigned i = 0; i < num_shaders; i++) {
+      foreach_list(node, shader_list[i]->ir) {
         ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
-        if ((var == NULL) || (var->mode != ir_var_uniform))
+        if (var == NULL)
            continue;
 
-        /* If a uniform with this name has already been seen, verify that the
-         * new instance has the same type.  In addition, if the uniforms have
+        if (uniforms_only && (var->mode != ir_var_uniform))
+           continue;
+
+        /* If a global with this name has already been seen, verify that the
+         * new instance has the same type.  In addition, if the globals have
          * initializers, the values of the initializers must be the same.
          */
-        ir_variable *const existing = uniforms.get_variable(var->name);
+        ir_variable *const existing = variables.get_variable(var->name);
         if (existing != NULL) {
            if (var->type != existing->type) {
-              linker_error_printf(prog, "uniform `%s' declared as type "
+              linker_error_printf(prog, "%s `%s' declared as type "
                                   "`%s' and type `%s'\n",
+                                  mode_string(var),
                                   var->name, var->type->name,
                                   existing->type->name);
               return false;
            }
 
+           /* FINISHME: Handle non-constant initializers.
+            */
            if (var->constant_value != NULL) {
               if (existing->constant_value != NULL) {
                  if (!var->constant_value->has_value(existing->constant_value)) {
-                    linker_error_printf(prog, "initializers for uniform "
+                    linker_error_printf(prog, "initializers for %s "
                                         "`%s' have differing values\n",
-                                        var->name);
+                                        mode_string(var), var->name);
                     return false;
                  }
               } else
@@ -290,11 +315,10 @@ cross_validate_uniforms(struct glsl_program *prog)
                   * have an initializer but a later instance does, copy the
                   * initializer to the version stored in the symbol table.
                   */
-                 existing->constant_value =
-                    (ir_constant *)var->constant_value->clone(NULL);
+                 existing->constant_value = var->constant_value->clone(NULL);
            }
         } else
-           uniforms.add_variable(var->name, var);
+           variables.add_variable(var->name, var);
       }
    }
 
@@ -302,12 +326,23 @@ cross_validate_uniforms(struct glsl_program *prog)
 }
 
 
+/**
+ * Perform validation of uniforms used across multiple shader stages
+ */
+bool
+cross_validate_uniforms(struct gl_shader_program *prog)
+{
+   return cross_validate_globals(prog, prog->_LinkedShaders,
+                                prog->_NumLinkedShaders, true);
+}
+
+
 /**
  * Validate that outputs from one stage match inputs of another
  */
 bool
-cross_validate_outputs_to_inputs(struct glsl_program *prog,
-                                glsl_shader *producer, glsl_shader *consumer)
+cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
+                                gl_shader *producer, gl_shader *consumer)
 {
    glsl_symbol_table parameters;
    /* FINISHME: Figure these out dynamically. */
@@ -316,7 +351,7 @@ cross_validate_outputs_to_inputs(struct glsl_program *prog,
 
    /* Find all shader outputs in the "producer" stage.
     */
-   foreach_list(node, &producer->ir) {
+   foreach_list(node, producer->ir) {
       ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
       /* FINISHME: For geometry shaders, this should also look for inout
@@ -333,7 +368,7 @@ cross_validate_outputs_to_inputs(struct glsl_program *prog,
     * matching outputs already in the symbol table must have the same type and
     * qualifiers.
     */
-   foreach_list(node, &consumer->ir) {
+   foreach_list(node, consumer->ir) {
       ir_variable *const input = ((ir_instruction *) node)->as_variable();
 
       /* FINISHME: For geometry shaders, this should also look for inout
@@ -403,6 +438,270 @@ cross_validate_outputs_to_inputs(struct glsl_program *prog,
 }
 
 
+/**
+ * Populates a shaders symbol table with all global declarations
+ */
+static void
+populate_symbol_table(gl_shader *sh)
+{
+   sh->symbols = new(sh) glsl_symbol_table;
+
+   foreach_list(node, sh->ir) {
+      ir_instruction *const inst = (ir_instruction *) node;
+      ir_variable *var;
+      ir_function *func;
+
+      if ((func = inst->as_function()) != NULL) {
+        sh->symbols->add_function(func->name, func);
+      } else if ((var = inst->as_variable()) != NULL) {
+        sh->symbols->add_variable(var->name, var);
+      }
+   }
+}
+
+
+/**
+ * Remap variables referenced in an instruction tree
+ *
+ * This is used when instruction trees are cloned from one shader and placed in
+ * another.  These trees will contain references to \c ir_variable nodes that
+ * do not exist in the target shader.  This function finds these \c ir_variable
+ * references and replaces the references with matching variables in the target
+ * shader.
+ *
+ * If there is no matching variable in the target shader, a clone of the
+ * \c ir_variable is made and added to the target shader.  The new variable is
+ * added to \b both the instruction stream and the symbol table.
+ *
+ * \param inst         IR tree that is to be processed.
+ * \param symbols      Symbol table containing global scope symbols in the
+ *                     linked shader.
+ * \param instructions Instruction stream where new variable declarations
+ *                     should be added.
+ */
+void
+remap_variables(ir_instruction *inst, glsl_symbol_table *symbols,
+               exec_list *instructions)
+{
+   class remap_visitor : public ir_hierarchical_visitor {
+   public:
+      remap_visitor(glsl_symbol_table *symbols, exec_list *instructions)
+      {
+        this->symbols = symbols;
+        this->instructions = instructions;
+      }
+
+      virtual ir_visitor_status visit(ir_dereference_variable *ir)
+      {
+        ir_variable *const existing =
+           this->symbols->get_variable(ir->var->name);
+        if (existing != NULL)
+           ir->var = existing;
+        else {
+           ir_variable *copy = ir->var->clone(NULL);
+
+           this->symbols->add_variable(copy->name, copy);
+           this->instructions->push_head(copy);
+        }
+
+        return visit_continue;
+      }
+
+   private:
+      glsl_symbol_table *symbols;
+      exec_list *instructions;
+   };
+
+   remap_visitor v(symbols, instructions);
+
+   inst->accept(&v);
+}
+
+
+/**
+ * Move non-declarations from one instruction stream to another
+ *
+ * The intended usage pattern of this function is to pass the pointer to the
+ * head sentinal of a list (i.e., a pointer to the list cast to an \c exec_node
+ * pointer) for \c last and \c false for \c make_copies on the first
+ * call.  Successive calls pass the return value of the previous call for
+ * \c last and \c true for \c make_copies.
+ *
+ * \param instructions Source instruction stream
+ * \param last         Instruction after which new instructions should be
+ *                     inserted in the target instruction stream
+ * \param make_copies  Flag selecting whether instructions in \c instructions
+ *                     should be copied (via \c ir_instruction::clone) into the
+ *                     target list or moved.
+ *
+ * \return
+ * The new "last" instruction in the target instruction stream.  This pointer
+ * is suitable for use as the \c last parameter of a later call to this
+ * function.
+ */
+exec_node *
+move_non_declarations(exec_list *instructions, exec_node *last,
+                     bool make_copies, gl_shader *target)
+{
+   foreach_list(node, instructions) {
+      ir_instruction *inst = (ir_instruction *) node;
+
+      if (inst->as_variable() || inst->as_function())
+        continue;
+
+      assert(inst->as_assignment());
+
+      if (make_copies) {
+        inst = inst->clone(NULL);
+        remap_variables(inst, target->symbols, target->ir);
+      } else {
+        inst->remove();
+      }
+
+      last->insert_after(inst);
+      last = inst;
+   }
+
+   return last;
+}
+
+/**
+ * Get the function signature for main from a shader
+ */
+static ir_function_signature *
+get_main_function_signature(gl_shader *sh)
+{
+   ir_function *const f = sh->symbols->get_function("main");
+   if (f != NULL) {
+      exec_list void_parameters;
+
+      /* Look for the 'void main()' signature and ensure that it's defined.
+       * This keeps the linker from accidentally pick a shader that just
+       * contains a prototype for main.
+       *
+       * We don't have to check for multiple definitions of main (in multiple
+       * shaders) because that would have already been caught above.
+       */
+      ir_function_signature *sig = f->matching_signature(&void_parameters);
+      if ((sig != NULL) && sig->is_defined) {
+        return sig;
+      }
+   }
+
+   return NULL;
+}
+
+
+/**
+ * Combine a group of shaders for a single stage to generate a linked shader
+ *
+ * \note
+ * If this function is supplied a single shader, it is cloned, and the new
+ * shader is returned.
+ */
+static struct gl_shader *
+link_intrastage_shaders(struct gl_shader_program *prog,
+                       struct gl_shader **shader_list,
+                       unsigned num_shaders)
+{
+   /* Check that global variables defined in multiple shaders are consistent.
+    */
+   if (!cross_validate_globals(prog, shader_list, num_shaders, false))
+      return NULL;
+
+   /* Check that there is only a single definition of each function signature
+    * across all shaders.
+    */
+   for (unsigned i = 0; i < (num_shaders - 1); i++) {
+      foreach_list(node, shader_list[i]->ir) {
+        ir_function *const f = ((ir_instruction *) node)->as_function();
+
+        if (f == NULL)
+           continue;
+
+        for (unsigned j = i + 1; j < num_shaders; j++) {
+           ir_function *const other =
+              shader_list[j]->symbols->get_function(f->name);
+
+           /* If the other shader has no function (and therefore no function
+            * signatures) with the same name, skip to the next shader.
+            */
+           if (other == NULL)
+              continue;
+
+           foreach_iter (exec_list_iterator, iter, *f) {
+              ir_function_signature *sig =
+                 (ir_function_signature *) iter.get();
+
+              if (!sig->is_defined || sig->is_built_in)
+                 continue;
+
+              ir_function_signature *other_sig =
+                 other->exact_matching_signature(& sig->parameters);
+
+              if ((other_sig != NULL) && other_sig->is_defined
+                  && !other_sig->is_built_in) {
+                 linker_error_printf(prog,
+                                     "function `%s' is multiply defined",
+                                     f->name);
+                 return NULL;
+              }
+           }
+        }
+      }
+   }
+
+   /* Find the shader that defines main, and make a clone of it.
+    *
+    * Starting with the clone, search for undefined references.  If one is
+    * found, find the shader that defines it.  Clone the reference and add
+    * it to the shader.  Repeat until there are no undefined references or
+    * until a reference cannot be resolved.
+    */
+   gl_shader *main = NULL;
+   for (unsigned i = 0; i < num_shaders; i++) {
+      if (get_main_function_signature(shader_list[i]) != NULL) {
+        main = shader_list[i];
+        break;
+      }
+   }
+
+   if (main == NULL) {
+      linker_error_printf(prog, "%s shader lacks `main'\n",
+                         (shader_list[0]->Type == GL_VERTEX_SHADER)
+                         ? "vertex" : "fragment");
+      return NULL;
+   }
+
+   gl_shader *const linked = _mesa_new_shader(NULL, 0, main->Type);
+   linked->ir = new(linked) exec_list;
+   clone_ir_list(linked->ir, main->ir);
+
+   populate_symbol_table(linked);
+
+   /* The a pointer to the main function in the final linked shader (i.e., the
+    * copy of the original shader that contained the main function).
+    */
+   ir_function_signature *const main_sig = get_main_function_signature(linked);
+
+   /* Move any instructions other than variable declarations or function
+    * declarations into main.
+    */
+   exec_node *insertion_point = (exec_node *) &main_sig->body;
+   for (unsigned i = 0; i < num_shaders; i++) {
+      insertion_point = move_non_declarations(shader_list[i]->ir,
+                                             insertion_point,
+                                             (shader_list[i] != main),
+                                             linked);
+   }
+
+   /* Resolve initializers for global variables in the linked shader.
+    */
+
+   return linked;
+}
+
+
 struct uniform_node {
    exec_node link;
    struct gl_uniform *u;
@@ -410,7 +709,7 @@ struct uniform_node {
 };
 
 void
-assign_uniform_locations(struct glsl_program *prog)
+assign_uniform_locations(struct gl_shader_program *prog)
 {
    /* */
    exec_list uniforms;
@@ -421,7 +720,7 @@ assign_uniform_locations(struct glsl_program *prog)
    for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) {
       unsigned next_position = 0;
 
-      foreach_list(node, &prog->_LinkedShaders[i]->ir) {
+      foreach_list(node, prog->_LinkedShaders[i]->ir) {
         ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
         if ((var == NULL) || (var->mode != ir_var_uniform))
@@ -531,14 +830,14 @@ find_available_slots(unsigned used_mask, unsigned needed_count)
 
 
 bool
-assign_attribute_locations(glsl_program *prog, unsigned max_attribute_index)
+assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index)
 {
    /* Mark invalid attribute locations as being used.
     */
    unsigned used_locations = (max_attribute_index >= 32)
       ? ~0 : ~((1 << max_attribute_index) - 1);
 
-   glsl_shader *const sh = prog->_LinkedShaders[0];
+   gl_shader *const sh = prog->_LinkedShaders[0];
    assert(sh->Type == GL_VERTEX_SHADER);
 
    /* Operate in a total of four passes.
@@ -642,7 +941,7 @@ assign_attribute_locations(glsl_program *prog, unsigned max_attribute_index)
 
    unsigned num_attr = 0;
 
-   foreach_list(node, &sh->ir) {
+   foreach_list(node, sh->ir) {
       ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
       if ((var == NULL) || (var->mode != ir_var_in))
@@ -667,6 +966,12 @@ assign_attribute_locations(glsl_program *prog, unsigned max_attribute_index)
 
    qsort(to_assign, num_attr, sizeof(to_assign[0]), temp_attr::compare);
 
+   /* VERT_ATTRIB_GENERIC0 is a psdueo-alias for VERT_ATTRIB_POS.  It can only
+    * be explicitly assigned by via glBindAttribLocation.  Mark it as reserved
+    * to prevent it from being automatically allocated below.
+    */
+   used_locations |= (1 << 0);
+
    for (unsigned i = 0; i < num_attr; i++) {
       /* Mask representing the contiguous slots that will be used by this
        * attribute.
@@ -692,7 +997,7 @@ assign_attribute_locations(glsl_program *prog, unsigned max_attribute_index)
 
 
 void
-assign_varying_locations(glsl_shader *producer, glsl_shader *consumer)
+assign_varying_locations(gl_shader *producer, gl_shader *consumer)
 {
    /* FINISHME: Set dynamically when geometry shader support is added. */
    unsigned output_index = VERT_RESULT_VAR0;
@@ -712,7 +1017,7 @@ assign_varying_locations(glsl_shader *producer, glsl_shader *consumer)
    invalidate_variable_locations(producer, ir_var_out, VERT_RESULT_VAR0);
    invalidate_variable_locations(consumer, ir_var_in, FRAG_ATTRIB_VAR0);
 
-   foreach_list(node, &producer->ir) {
+   foreach_list(node, producer->ir) {
       ir_variable *const output_var = ((ir_instruction *) node)->as_variable();
 
       if ((output_var == NULL) || (output_var->mode != ir_var_out)
@@ -738,7 +1043,7 @@ assign_varying_locations(glsl_shader *producer, glsl_shader *consumer)
       input_index++;
    }
 
-   foreach_list(node, &producer->ir) {
+   foreach_list(node, producer->ir) {
       ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
       if ((var == NULL) || (var->mode != ir_var_out))
@@ -747,10 +1052,13 @@ assign_varying_locations(glsl_shader *producer, glsl_shader *consumer)
       /* An 'out' variable is only really a shader output if its value is read
        * by the following stage.
        */
-      var->shader_out = (var->location != -1);
+      if (var->location == -1) {
+        var->shader_out = false;
+        var->mode = ir_var_auto;
+      }
    }
 
-   foreach_list(node, &consumer->ir) {
+   foreach_list(node, consumer->ir) {
       ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
       if ((var == NULL) || (var->mode != ir_var_in))
@@ -765,7 +1073,7 @@ assign_varying_locations(glsl_shader *producer, glsl_shader *consumer)
 
 
 void
-link_shaders(struct glsl_program *prog)
+link_shaders(struct gl_shader_program *prog)
 {
    prog->LinkStatus = false;
    prog->Validated = false;
@@ -778,13 +1086,13 @@ link_shaders(struct glsl_program *prog)
 
    /* Separate the shaders into groups based on their type.
     */
-   struct glsl_shader **vert_shader_list;
+   struct gl_shader **vert_shader_list;
    unsigned num_vert_shaders = 0;
-   struct glsl_shader **frag_shader_list;
+   struct gl_shader **frag_shader_list;
    unsigned num_frag_shaders = 0;
 
-   vert_shader_list = (struct glsl_shader **)
-      calloc(2 * prog->NumShaders, sizeof(struct glsl_shader *));
+   vert_shader_list = (struct gl_shader **)
+      calloc(2 * prog->NumShaders, sizeof(struct gl_shader *));
    frag_shader_list =  &vert_shader_list[prog->NumShaders];
 
    for (unsigned i = 0; i < prog->NumShaders; i++) {
@@ -805,27 +1113,32 @@ link_shaders(struct glsl_program *prog)
    }
 
    /* FINISHME: Implement intra-stage linking. */
-   assert(num_vert_shaders <= 1);
-   assert(num_frag_shaders <= 1);
-
-   /* Verify that each of the per-target executables is valid.
-    */
-   if (!validate_vertex_shader_executable(prog, vert_shader_list[0])
-       || !validate_fragment_shader_executable(prog, frag_shader_list[0]))
-      goto done;
+   prog->_NumLinkedShaders = 0;
+   if (num_vert_shaders > 0) {
+      gl_shader *const sh =
+        link_intrastage_shaders(prog, vert_shader_list, num_vert_shaders);
 
+      if (sh == NULL)
+        goto done;
 
-   prog->_LinkedShaders = (struct glsl_shader **)
-      calloc(2, sizeof(struct glsl_shader *));
-   prog->_NumLinkedShaders = 0;
+      if (!validate_vertex_shader_executable(prog, sh))
+         goto done;
 
-   if (num_vert_shaders > 0) {
-      prog->_LinkedShaders[prog->_NumLinkedShaders] = vert_shader_list[0];
+      prog->_LinkedShaders[prog->_NumLinkedShaders] = sh;
       prog->_NumLinkedShaders++;
    }
 
    if (num_frag_shaders > 0) {
-      prog->_LinkedShaders[prog->_NumLinkedShaders] = frag_shader_list[0];
+      gl_shader *const sh =
+        link_intrastage_shaders(prog, frag_shader_list, num_frag_shaders);
+
+      if (sh == NULL)
+        goto done;
+
+      if (!validate_fragment_shader_executable(prog, sh))
+         goto done;
+
+      prog->_LinkedShaders[prog->_NumLinkedShaders] = sh;
       prog->_NumLinkedShaders++;
    }