link_functions.cpp revision 8273bd46877e2ea2b8a02b87a11c68102d07e1f2
1/* 2 * Copyright © 2010 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include <cstdlib> 25#include <cstdio> 26#include <cstdarg> 27 28extern "C" { 29#include <talloc.h> 30} 31 32#include "main/mtypes.h" 33#include "glsl_symbol_table.h" 34#include "glsl_parser_extras.h" 35#include "ir.h" 36#include "program.h" 37#include "program/hash_table.h" 38#include "linker.h" 39 40static ir_function_signature * 41find_matching_signature(const char *name, const exec_list *actual_parameters, 42 gl_shader **shader_list, unsigned num_shaders); 43 44class call_link_visitor : public ir_hierarchical_visitor { 45public: 46 call_link_visitor(gl_shader_program *prog, gl_shader *linked, 47 gl_shader **shader_list, unsigned num_shaders) 48 { 49 this->prog = prog; 50 this->shader_list = shader_list; 51 this->num_shaders = num_shaders; 52 this->success = true; 53 this->linked = linked; 54 55 this->locals = hash_table_ctor(0, hash_table_pointer_hash, 56 hash_table_pointer_compare); 57 } 58 59 ~call_link_visitor() 60 { 61 hash_table_dtor(this->locals); 62 } 63 64 virtual ir_visitor_status visit(ir_variable *ir) 65 { 66 hash_table_insert(locals, ir, ir); 67 return visit_continue; 68 } 69 70 virtual ir_visitor_status visit_enter(ir_call *ir) 71 { 72 /* If ir is an ir_call from a function that was imported from another 73 * shader callee will point to an ir_function_signature in the original 74 * shader. In this case the function signature MUST NOT BE MODIFIED. 75 * Doing so will modify the original shader. This may prevent that 76 * shader from being linkable in other programs. 77 */ 78 const ir_function_signature *const callee = ir->get_callee(); 79 assert(callee != NULL); 80 const char *const name = callee->function_name(); 81 82 /* Determine if the requested function signature already exists in the 83 * final linked shader. If it does, use it as the target of the call. 84 */ 85 ir_function_signature *sig = 86 find_matching_signature(name, &callee->parameters, &linked, 1); 87 if (sig != NULL) { 88 ir->set_callee(sig); 89 return visit_continue; 90 } 91 92 /* Try to find the signature in one of the other shaders that is being 93 * linked. If it's not found there, return an error. 94 */ 95 sig = find_matching_signature(name, &ir->actual_parameters, shader_list, 96 num_shaders); 97 if (sig == NULL) { 98 /* FINISHME: Log the full signature of unresolved function. 99 */ 100 linker_error_printf(this->prog, "unresolved reference to function " 101 "`%s'\n", name); 102 this->success = false; 103 return visit_stop; 104 } 105 106 /* Find the prototype information in the linked shader. Generate any 107 * details that may be missing. 108 */ 109 ir_function *f = linked->symbols->get_function(name); 110 if (f == NULL) 111 f = new(linked) ir_function(name); 112 113 ir_function_signature *linked_sig = 114 f->matching_signature(&callee->parameters); 115 if (linked_sig == NULL) { 116 linked_sig = new(linked) ir_function_signature(callee->return_type); 117 f->add_signature(linked_sig); 118 } 119 120 /* At this point linked_sig and called may be the same. If ir is an 121 * ir_call from linked then linked_sig and callee will be 122 * ir_function_signatures that have no definitions (is_defined is false). 123 */ 124 assert(!linked_sig->is_defined); 125 assert(linked_sig->body.is_empty()); 126 127 /* Create an in-place clone of the function definition. This multistep 128 * process introduces some complexity here, but it has some advantages. 129 * The parameter list and the and function body are cloned separately. 130 * The clone of the parameter list is used to prime the hashtable used 131 * to replace variable references in the cloned body. 132 * 133 * The big advantage is that the ir_function_signature does not change. 134 * This means that we don't have to process the rest of the IR tree to 135 * patch ir_call nodes. In addition, there is no way to remove or 136 * replace signature stored in a function. One could easily be added, 137 * but this avoids the need. 138 */ 139 struct hash_table *ht = hash_table_ctor(0, hash_table_pointer_hash, 140 hash_table_pointer_compare); 141 exec_list formal_parameters; 142 foreach_list_const(node, &sig->parameters) { 143 const ir_instruction *const original = (ir_instruction *) node; 144 assert(const_cast<ir_instruction *>(original)->as_variable()); 145 146 ir_instruction *copy = original->clone(linked, ht); 147 formal_parameters.push_tail(copy); 148 } 149 150 linked_sig->replace_parameters(&formal_parameters); 151 152 foreach_list_const(node, &sig->body) { 153 const ir_instruction *const original = (ir_instruction *) node; 154 155 ir_instruction *copy = original->clone(linked, ht); 156 linked_sig->body.push_tail(copy); 157 } 158 159 linked_sig->is_defined = true; 160 hash_table_dtor(ht); 161 162 /* Patch references inside the function to things outside the function 163 * (i.e., function calls and global variables). 164 */ 165 linked_sig->accept(this); 166 167 ir->set_callee(linked_sig); 168 169 return visit_continue; 170 } 171 172 virtual ir_visitor_status visit(ir_dereference_variable *ir) 173 { 174 if (hash_table_find(locals, ir->var) == NULL) { 175 /* The non-function variable must be a global, so try to find the 176 * variable in the shader's symbol table. If the variable is not 177 * found, then it's a global that *MUST* be defined in the original 178 * shader. 179 */ 180 ir_variable *var = linked->symbols->get_variable(ir->var->name); 181 if (var == NULL) { 182 /* Clone the ir_variable that the dereference already has and add 183 * it to the linked shader. 184 */ 185 var = ir->var->clone(linked, NULL); 186 linked->symbols->add_variable(var->name, var); 187 linked->ir->push_head(var); 188 } 189 190 ir->var = var; 191 } 192 193 return visit_continue; 194 } 195 196 /** Was function linking successful? */ 197 bool success; 198 199private: 200 /** 201 * Shader program being linked 202 * 203 * This is only used for logging error messages. 204 */ 205 gl_shader_program *prog; 206 207 /** List of shaders available for linking. */ 208 gl_shader **shader_list; 209 210 /** Number of shaders available for linking. */ 211 unsigned num_shaders; 212 213 /** 214 * Final linked shader 215 * 216 * This is used two ways. It is used to find global variables in the 217 * linked shader that are accessed by the function. It is also used to add 218 * global variables from the shader where the function originated. 219 */ 220 gl_shader *linked; 221 222 /** 223 * Table of variables local to the function. 224 */ 225 hash_table *locals; 226}; 227 228 229/** 230 * Searches a list of shaders for a particular function definition 231 */ 232ir_function_signature * 233find_matching_signature(const char *name, const exec_list *actual_parameters, 234 gl_shader **shader_list, unsigned num_shaders) 235{ 236 for (unsigned i = 0; i < num_shaders; i++) { 237 ir_function *const f = shader_list[i]->symbols->get_function(name); 238 239 if (f == NULL) 240 continue; 241 242 ir_function_signature *sig = f->matching_signature(actual_parameters); 243 244 if ((sig == NULL) || !sig->is_defined) 245 continue; 246 247 return sig; 248 } 249 250 return NULL; 251} 252 253 254bool 255link_function_calls(gl_shader_program *prog, gl_shader *main, 256 gl_shader **shader_list, unsigned num_shaders) 257{ 258 call_link_visitor v(prog, main, shader_list, num_shaders); 259 260 v.run(main->ir); 261 return v.success; 262} 263