diff options
author | Ian Romanick <[email protected]> | 2010-06-29 18:53:38 -0700 |
---|---|---|
committer | Ian Romanick <[email protected]> | 2010-07-12 18:51:55 -0700 |
commit | 13f782c4ae4e38e64ec4fe87a1c24597a5e894c3 (patch) | |
tree | 073251c0f9c563a0f1ea59a6c274d03ac2c4714b | |
parent | e2e5d0def490ed03970efa0a7468fef0623ae617 (diff) |
linker: Implement first bits of intrastage linking
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.
-rw-r--r-- | src/glsl/ir.h | 3 | ||||
-rw-r--r-- | src/glsl/ir_clone.cpp | 1 | ||||
-rw-r--r-- | src/glsl/ir_reader.cpp | 1 | ||||
-rw-r--r-- | src/glsl/linker.cpp | 60 |
4 files changed, 63 insertions, 2 deletions
diff --git a/src/glsl/ir.h b/src/glsl/ir.h index fb94b5a560d..25bf6c6d151 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -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; diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp index f1547d9106f..2562ad91187 100644 --- a/src/glsl/ir_clone.cpp +++ b/src/glsl/ir_clone.cpp @@ -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. */ diff --git a/src/glsl/ir_reader.cpp b/src/glsl/ir_reader.cpp index 03212830cdb..c83f92ef575 100644 --- a/src/glsl/ir_reader.cpp +++ b/src/glsl/ir_reader.cpp @@ -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); } diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 04b4efd84ba..3d8f24bb444 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -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; |