linker: Implement first bits of intrastage linking
authorIan Romanick <ian.d.romanick@intel.com>
Wed, 30 Jun 2010 01:53:38 +0000 (18:53 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Tue, 13 Jul 2010 01:51:55 +0000 (18:51 -0700)
This currently involves an ugly hack so that every link doesn't result
in all the built-in functions showing up as multiply defined.  As soon
as the built-in functions are stored in a separate compilation unit,
ir_function_signature::is_built_in can be removed.

src/glsl/ir.h
src/glsl/ir_clone.cpp
src/glsl/ir_reader.cpp
src/glsl/linker.cpp

index fb94b5a560d645cdfeaf36843ad2739b53c1ef14..25bf6c6d151ad5b29fd5e77e20955629bd105c3a 100644 (file)
@@ -324,6 +324,9 @@ public:
    /** Whether or not this function has a body (which may be empty). */
    unsigned is_defined:1;
 
+   /** Whether or not this function signature is a built-in. */
+   unsigned is_built_in:1;
+
    /** Body of instructions in the function. */
    struct exec_list body;
 
index f1547d9106f7ca38ff5bb6bdd09b7f16d49cf2de..2562ad9118720eac4ba5617ecfa4fb7c63e10b99 100644 (file)
@@ -287,6 +287,7 @@ ir_function_signature::clone(struct hash_table *ht) const
       new(mem_ctx) ir_function_signature(this->return_type);
 
    copy->is_defined = this->is_defined;
+   copy->is_built_in = this->is_built_in;
 
    /* Clone the parameter list.
     */
index 03212830cdb8238cbeb0447f721cc4d85365fbba..c83f92ef575ab8d58b2e5776ac22e4400a562709 100644 (file)
@@ -291,6 +291,7 @@ read_function_sig(_mesa_glsl_parse_state *st, ir_function *f, s_list *list,
       }
    } else {
       sig = new(ctx) ir_function_signature(return_type);
+      sig->is_built_in = true;
       f->add_signature(sig);
    }
 
index 04b4efd84baf8290707ab197e96a919fd728302f..3d8f24bb4443b3456df449f2081034f174fc8cbe 100644 (file)
@@ -473,8 +473,64 @@ link_intrastage_shaders(struct gl_shader_program *prog,
                        struct gl_shader **shader_list,
                        unsigned num_shaders)
 {
-   (void) prog;
-   assert(num_shaders == 1);
+   /* 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.
+    */
+
+
+   /* Resolve initializers for global variables in the linked shader.
+    */
 
    gl_shader *const linked = _mesa_new_shader(NULL, 0, shader_list[0]->Type);
    linked->ir = new(linked) exec_list;