Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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 <stdlib.h>
  25. #include <stdio.h>
  26. #include <stdarg.h>
  27.  
  28. #include "main/core.h"
  29. #include "glsl_symbol_table.h"
  30. #include "glsl_parser_extras.h"
  31. #include "ir.h"
  32. #include "program.h"
  33. #include "program/hash_table.h"
  34. #include "linker.h"
  35.  
  36. static ir_function_signature *
  37. find_matching_signature(const char *name, const exec_list *actual_parameters,
  38.                         gl_shader **shader_list, unsigned num_shaders);
  39.  
  40. class call_link_visitor : public ir_hierarchical_visitor {
  41. public:
  42.    call_link_visitor(gl_shader_program *prog, gl_shader *linked,
  43.                      gl_shader **shader_list, unsigned num_shaders)
  44.    {
  45.       this->prog = prog;
  46.       this->shader_list = shader_list;
  47.       this->num_shaders = num_shaders;
  48.       this->success = true;
  49.       this->linked = linked;
  50.  
  51.       this->locals = hash_table_ctor(0, hash_table_pointer_hash,
  52.                                      hash_table_pointer_compare);
  53.    }
  54.  
  55.    ~call_link_visitor()
  56.    {
  57.       hash_table_dtor(this->locals);
  58.    }
  59.  
  60.    virtual ir_visitor_status visit(ir_variable *ir)
  61.    {
  62.       hash_table_insert(locals, ir, ir);
  63.       return visit_continue;
  64.    }
  65.  
  66.    virtual ir_visitor_status visit_enter(ir_call *ir)
  67.    {
  68.       /* If ir is an ir_call from a function that was imported from another
  69.        * shader callee will point to an ir_function_signature in the original
  70.        * shader.  In this case the function signature MUST NOT BE MODIFIED.
  71.        * Doing so will modify the original shader.  This may prevent that
  72.        * shader from being linkable in other programs.
  73.        */
  74.       const ir_function_signature *const callee = ir->get_callee();
  75.       assert(callee != NULL);
  76.       const char *const name = callee->function_name();
  77.  
  78.       /* Determine if the requested function signature already exists in the
  79.        * final linked shader.  If it does, use it as the target of the call.
  80.        */
  81.       ir_function_signature *sig =
  82.          find_matching_signature(name, &callee->parameters, &linked, 1);
  83.       if (sig != NULL) {
  84.          ir->set_callee(sig);
  85.          return visit_continue;
  86.       }
  87.  
  88.       /* Try to find the signature in one of the other shaders that is being
  89.        * linked.  If it's not found there, return an error.
  90.        */
  91.       sig = find_matching_signature(name, &ir->actual_parameters, shader_list,
  92.                                     num_shaders);
  93.       if (sig == NULL) {
  94.          /* FINISHME: Log the full signature of unresolved function.
  95.           */
  96.          linker_error_printf(this->prog, "unresolved reference to function "
  97.                              "`%s'\n", name);
  98.          this->success = false;
  99.          return visit_stop;
  100.       }
  101.  
  102.       /* Find the prototype information in the linked shader.  Generate any
  103.        * details that may be missing.
  104.        */
  105.       ir_function *f = linked->symbols->get_function(name);
  106.       if (f == NULL)
  107.          f = new(linked) ir_function(name);
  108.  
  109.       ir_function_signature *linked_sig =
  110.          f->exact_matching_signature(&callee->parameters);
  111.       if (linked_sig == NULL) {
  112.          linked_sig = new(linked) ir_function_signature(callee->return_type);
  113.          f->add_signature(linked_sig);
  114.       }
  115.  
  116.       /* At this point linked_sig and called may be the same.  If ir is an
  117.        * ir_call from linked then linked_sig and callee will be
  118.        * ir_function_signatures that have no definitions (is_defined is false).
  119.        */
  120.       assert(!linked_sig->is_defined);
  121.       assert(linked_sig->body.is_empty());
  122.  
  123.       /* Create an in-place clone of the function definition.  This multistep
  124.        * process introduces some complexity here, but it has some advantages.
  125.        * The parameter list and the and function body are cloned separately.
  126.        * The clone of the parameter list is used to prime the hashtable used
  127.        * to replace variable references in the cloned body.
  128.        *
  129.        * The big advantage is that the ir_function_signature does not change.
  130.        * This means that we don't have to process the rest of the IR tree to
  131.        * patch ir_call nodes.  In addition, there is no way to remove or
  132.        * replace signature stored in a function.  One could easily be added,
  133.        * but this avoids the need.
  134.        */
  135.       struct hash_table *ht = hash_table_ctor(0, hash_table_pointer_hash,
  136.                                               hash_table_pointer_compare);
  137.       exec_list formal_parameters;
  138.       foreach_list_const(node, &sig->parameters) {
  139.          const ir_instruction *const original = (ir_instruction *) node;
  140.          assert(const_cast<ir_instruction *>(original)->as_variable());
  141.  
  142.          ir_instruction *copy = original->clone(linked, ht);
  143.          formal_parameters.push_tail(copy);
  144.       }
  145.  
  146.       linked_sig->replace_parameters(&formal_parameters);
  147.  
  148.       foreach_list_const(node, &sig->body) {
  149.          const ir_instruction *const original = (ir_instruction *) node;
  150.  
  151.          ir_instruction *copy = original->clone(linked, ht);
  152.          linked_sig->body.push_tail(copy);
  153.       }
  154.  
  155.       linked_sig->is_defined = true;
  156.       hash_table_dtor(ht);
  157.  
  158.       /* Patch references inside the function to things outside the function
  159.        * (i.e., function calls and global variables).
  160.        */
  161.       linked_sig->accept(this);
  162.  
  163.       ir->set_callee(linked_sig);
  164.  
  165.       return visit_continue;
  166.    }
  167.  
  168.    virtual ir_visitor_status visit(ir_dereference_variable *ir)
  169.    {
  170.       if (hash_table_find(locals, ir->var) == NULL) {
  171.          /* The non-function variable must be a global, so try to find the
  172.           * variable in the shader's symbol table.  If the variable is not
  173.           * found, then it's a global that *MUST* be defined in the original
  174.           * shader.
  175.           */
  176.          ir_variable *var = linked->symbols->get_variable(ir->var->name);
  177.          if (var == NULL) {
  178.             /* Clone the ir_variable that the dereference already has and add
  179.              * it to the linked shader.
  180.              */
  181.             var = ir->var->clone(linked, NULL);
  182.             linked->symbols->add_variable(var);
  183.             linked->ir->push_head(var);
  184.          } else if (var->type->is_array()) {
  185.             /* It is possible to have a global array declared in multiple
  186.              * shaders without a size.  The array is implicitly sized by the
  187.              * maximal access to it in *any* shader.  Because of this, we
  188.              * need to track the maximal access to the array as linking pulls
  189.              * more functions in that access the array.
  190.              */
  191.             var->max_array_access =
  192.                MAX2(var->max_array_access, ir->var->max_array_access);
  193.  
  194.             if (var->type->length == 0 && ir->var->type->length != 0)
  195.                var->type = ir->var->type;
  196.          }
  197.  
  198.          ir->var = var;
  199.       }
  200.  
  201.       return visit_continue;
  202.    }
  203.  
  204.    /** Was function linking successful? */
  205.    bool success;
  206.  
  207. private:
  208.    /**
  209.     * Shader program being linked
  210.     *
  211.     * This is only used for logging error messages.
  212.     */
  213.    gl_shader_program *prog;
  214.  
  215.    /** List of shaders available for linking. */
  216.    gl_shader **shader_list;
  217.  
  218.    /** Number of shaders available for linking. */
  219.    unsigned num_shaders;
  220.  
  221.    /**
  222.     * Final linked shader
  223.     *
  224.     * This is used two ways.  It is used to find global variables in the
  225.     * linked shader that are accessed by the function.  It is also used to add
  226.     * global variables from the shader where the function originated.
  227.     */
  228.    gl_shader *linked;
  229.  
  230.    /**
  231.     * Table of variables local to the function.
  232.     */
  233.    hash_table *locals;
  234. };
  235.  
  236.  
  237. /**
  238.  * Searches a list of shaders for a particular function definition
  239.  */
  240. ir_function_signature *
  241. find_matching_signature(const char *name, const exec_list *actual_parameters,
  242.                         gl_shader **shader_list, unsigned num_shaders)
  243. {
  244.    for (unsigned i = 0; i < num_shaders; i++) {
  245.       ir_function *const f = shader_list[i]->symbols->get_function(name);
  246.  
  247.       if (f == NULL)
  248.          continue;
  249.  
  250.       ir_function_signature *sig = f->matching_signature(actual_parameters);
  251.  
  252.       if ((sig == NULL) || !sig->is_defined)
  253.          continue;
  254.  
  255.       return sig;
  256.    }
  257.  
  258.    return NULL;
  259. }
  260.  
  261.  
  262. bool
  263. link_function_calls(gl_shader_program *prog, gl_shader *main,
  264.                     gl_shader **shader_list, unsigned num_shaders)
  265. {
  266.    call_link_visitor v(prog, main, shader_list, num_shaders);
  267.  
  268.    v.run(main->ir);
  269.    return v.success;
  270. }
  271.