X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Flink_functions.cpp;h=537f4dc77ac7532c50bf48b0ebd34cfb2ec02a3b;hb=0e94f350eeecd84cd5f15b10837b285bc9120684;hp=dfda05fcbe508fac69e773e78923bfc9e7421ff1;hpb=443a7e4e9a360acbc3e662c098be436f180bf81d;p=mesa.git diff --git a/src/glsl/link_functions.cpp b/src/glsl/link_functions.cpp index dfda05fcbe5..537f4dc77ac 100644 --- a/src/glsl/link_functions.cpp +++ b/src/glsl/link_functions.cpp @@ -21,15 +21,7 @@ * DEALINGS IN THE SOFTWARE. */ -#include -#include -#include - -extern "C" { -#include -} - -#include "main/mtypes.h" +#include "main/core.h" #include "glsl_symbol_table.h" #include "glsl_parser_extras.h" #include "ir.h" @@ -39,7 +31,10 @@ extern "C" { static ir_function_signature * find_matching_signature(const char *name, const exec_list *actual_parameters, - gl_shader **shader_list, unsigned num_shaders); + gl_shader **shader_list, unsigned num_shaders, + bool use_builtin); + +namespace { class call_link_visitor : public ir_hierarchical_visitor { public: @@ -75,7 +70,7 @@ public: * Doing so will modify the original shader. This may prevent that * shader from being linkable in other programs. */ - const ir_function_signature *const callee = ir->get_callee(); + const ir_function_signature *const callee = ir->callee; assert(callee != NULL); const char *const name = callee->function_name(); @@ -83,9 +78,10 @@ public: * final linked shader. If it does, use it as the target of the call. */ ir_function_signature *sig = - find_matching_signature(name, &callee->parameters, &linked, 1); + find_matching_signature(name, &callee->parameters, &linked, 1, + ir->use_builtin); if (sig != NULL) { - ir->set_callee(sig); + ir->callee = sig; return visit_continue; } @@ -93,12 +89,12 @@ public: * linked. If it's not found there, return an error. */ sig = find_matching_signature(name, &ir->actual_parameters, shader_list, - num_shaders); + num_shaders, ir->use_builtin); if (sig == NULL) { /* FINISHME: Log the full signature of unresolved function. */ - linker_error_printf(this->prog, "unresolved reference to function " - "`%s'\n", name); + linker_error(this->prog, "unresolved reference to function `%s'\n", + name); this->success = false; return visit_stop; } @@ -107,12 +103,22 @@ public: * details that may be missing. */ ir_function *f = linked->symbols->get_function(name); - if (f == NULL) + if (f == NULL) { f = new(linked) ir_function(name); + /* Add the new function to the linked IR. Put it at the end + * so that it comes after any global variable declarations + * that it refers to. + */ + linked->symbols->add_function(f); + linked->ir->push_tail(f); + } + ir_function_signature *linked_sig = - f->matching_signature(&callee->parameters); - if (linked_sig == NULL) { + f->exact_matching_signature(NULL, &callee->parameters); + if ((linked_sig == NULL) + || ((linked_sig != NULL) + && (linked_sig->is_builtin() != ir->use_builtin))) { linked_sig = new(linked) ir_function_signature(callee->return_type); f->add_signature(linked_sig); } @@ -139,8 +145,7 @@ public: struct hash_table *ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare); exec_list formal_parameters; - foreach_list_const(node, &sig->parameters) { - const ir_instruction *const original = (ir_instruction *) node; + foreach_in_list(const ir_instruction, original, &sig->parameters) { assert(const_cast(original)->as_variable()); ir_instruction *copy = original->clone(linked, ht); @@ -149,14 +154,17 @@ public: linked_sig->replace_parameters(&formal_parameters); - foreach_list_const(node, &sig->body) { - const ir_instruction *const original = (ir_instruction *) node; + linked_sig->is_intrinsic = sig->is_intrinsic; - ir_instruction *copy = original->clone(linked, ht); - linked_sig->body.push_tail(copy); + if (sig->is_defined) { + foreach_in_list(const ir_instruction, original, &sig->body) { + ir_instruction *copy = original->clone(linked, ht); + linked_sig->body.push_tail(copy); + } + + linked_sig->is_defined = true; } - linked_sig->is_defined = true; hash_table_dtor(ht); /* Patch references inside the function to things outside the function @@ -164,11 +172,44 @@ public: */ linked_sig->accept(this); - ir->set_callee(linked_sig); + ir->callee = linked_sig; return visit_continue; } + virtual ir_visitor_status visit_leave(ir_call *ir) + { + /* Traverse list of function parameters, and for array parameters + * propagate max_array_access. Otherwise arrays that are only referenced + * from inside functions via function parameters will be incorrectly + * optimized. This will lead to incorrect code being generated (or worse). + * Do it when leaving the node so the children would propagate their + * array accesses first. + */ + + const exec_node *formal_param_node = ir->callee->parameters.get_head(); + if (formal_param_node) { + const exec_node *actual_param_node = ir->actual_parameters.get_head(); + while (!actual_param_node->is_tail_sentinel()) { + ir_variable *formal_param = (ir_variable *) formal_param_node; + ir_rvalue *actual_param = (ir_rvalue *) actual_param_node; + + formal_param_node = formal_param_node->get_next(); + actual_param_node = actual_param_node->get_next(); + + if (formal_param->type->is_array()) { + ir_dereference_variable *deref = actual_param->as_dereference_variable(); + if (deref && deref->var && deref->var->type->is_array()) { + deref->var->data.max_array_access = + MAX2(formal_param->data.max_array_access, + deref->var->data.max_array_access); + } + } + } + } + return visit_continue; + } + virtual ir_visitor_status visit(ir_dereference_variable *ir) { if (hash_table_find(locals, ir->var) == NULL) { @@ -183,8 +224,42 @@ public: * it to the linked shader. */ var = ir->var->clone(linked, NULL); - linked->symbols->add_variable(var->name, var); + linked->symbols->add_variable(var); linked->ir->push_head(var); + } else { + if (var->type->is_array()) { + /* It is possible to have a global array declared in multiple + * shaders without a size. The array is implicitly sized by + * the maximal access to it in *any* shader. Because of this, + * we need to track the maximal access to the array as linking + * pulls more functions in that access the array. + */ + var->data.max_array_access = + MAX2(var->data.max_array_access, + ir->var->data.max_array_access); + + if (var->type->length == 0 && ir->var->type->length != 0) + var->type = ir->var->type; + } + if (var->is_interface_instance()) { + /* Similarly, we need implicit sizes of arrays within interface + * blocks to be sized by the maximal access in *any* shader. + */ + unsigned *const linked_max_ifc_array_access = + var->get_max_ifc_array_access(); + unsigned *const ir_max_ifc_array_access = + ir->var->get_max_ifc_array_access(); + + assert(linked_max_ifc_array_access != NULL); + assert(ir_max_ifc_array_access != NULL); + + for (unsigned i = 0; i < var->get_interface_type()->length; + i++) { + linked_max_ifc_array_access[i] = + MAX2(linked_max_ifc_array_access[i], + ir_max_ifc_array_access[i]); + } + } } ir->var = var; @@ -225,13 +300,15 @@ private: hash_table *locals; }; +} /* anonymous namespace */ /** * Searches a list of shaders for a particular function definition */ ir_function_signature * find_matching_signature(const char *name, const exec_list *actual_parameters, - gl_shader **shader_list, unsigned num_shaders) + gl_shader **shader_list, unsigned num_shaders, + bool use_builtin) { for (unsigned i = 0; i < num_shaders; i++) { ir_function *const f = shader_list[i]->symbols->get_function(name); @@ -239,11 +316,20 @@ find_matching_signature(const char *name, const exec_list *actual_parameters, if (f == NULL) continue; - ir_function_signature *sig = f->matching_signature(actual_parameters); + ir_function_signature *sig = + f->matching_signature(NULL, actual_parameters, use_builtin); - if ((sig == NULL) || !sig->is_defined) + if ((sig == NULL) || + (!sig->is_defined && !sig->is_intrinsic)) continue; + /* If this function expects to bind to a built-in function and the + * signature that we found isn't a built-in, keep looking. Also keep + * looking if we expect a non-built-in but found a built-in. + */ + if (use_builtin != sig->is_builtin()) + continue; + return sig; }