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