Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2011 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. /**
  25.  * \file ir_function_detect_recursion.cpp
  26.  * Determine whether a shader contains static recursion.
  27.  *
  28.  * Consider the (possibly disjoint) graph of function calls in a shader.  If a
  29.  * program contains recursion, this graph will contain a cycle.  If a function
  30.  * is part of a cycle, it will have a caller and it will have a callee (it
  31.  * calls another function).
  32.  *
  33.  * To detect recursion, the function call graph is constructed.  The graph is
  34.  * repeatedly reduced by removing any function that either has no callees
  35.  * (leaf functions) or has no caller.  Eventually the only functions that
  36.  * remain will be the functions in the cycles.
  37.  *
  38.  * The GLSL spec is a bit wishy-washy about recursion.
  39.  *
  40.  * From page 39 (page 45 of the PDF) of the GLSL 1.10 spec:
  41.  *
  42.  *     "Behavior is undefined if recursion is used. Recursion means having any
  43.  *     function appearing more than once at any one time in the run-time stack
  44.  *     of function calls. That is, a function may not call itself either
  45.  *     directly or indirectly. Compilers may give diagnostic messages when
  46.  *     this is detectable at compile time, but not all such cases can be
  47.  *     detected at compile time."
  48.  *
  49.  * From page 79 (page 85 of the PDF):
  50.  *
  51.  *     "22) Should recursion be supported?
  52.  *
  53.  *      DISCUSSION: Probably not necessary, but another example of limiting
  54.  *      the language based on how it would directly map to hardware. One
  55.  *      thought is that recursion would benefit ray tracing shaders. On the
  56.  *      other hand, many recursion operations can also be implemented with the
  57.  *      user managing the recursion through arrays. RenderMan doesn't support
  58.  *      recursion. This could be added at a later date, if it proved to be
  59.  *      necessary.
  60.  *
  61.  *      RESOLVED on September 10, 2002: Implementations are not required to
  62.  *      support recursion.
  63.  *
  64.  *      CLOSED on September 10, 2002."
  65.  *
  66.  * From page 79 (page 85 of the PDF):
  67.  *
  68.  *     "56) Is it an error for an implementation to support recursion if the
  69.  *     specification says recursion is not supported?
  70.  *
  71.  *     ADDED on September 10, 2002.
  72.  *
  73.  *     DISCUSSION: This issues is related to Issue (22). If we say that
  74.  *     recursion (or some other piece of functionality) is not supported, is
  75.  *     it an error for an implementation to support it? Perhaps the
  76.  *     specification should remain silent on these kind of things so that they
  77.  *     could be gracefully added later as an extension or as part of the
  78.  *     standard.
  79.  *
  80.  *     RESOLUTION: Languages, in general, have programs that are not
  81.  *     well-formed in ways a compiler cannot detect. Portability is only
  82.  *     ensured for well-formed programs. Detecting recursion is an example of
  83.  *     this. The language will say a well-formed program may not recurse, but
  84.  *     compilers are not forced to detect that recursion may happen.
  85.  *
  86.  *     CLOSED: November 29, 2002."
  87.  *
  88.  * In GLSL 1.10 the behavior of recursion is undefined.  Compilers don't have
  89.  * to reject shaders (at compile-time or link-time) that contain recursion.
  90.  * Instead they could work, or crash, or kill a kitten.
  91.  *
  92.  * From page 44 (page 50 of the PDF) of the GLSL 1.20 spec:
  93.  *
  94.  *     "Recursion is not allowed, not even statically. Static recursion is
  95.  *     present if the static function call graph of the program contains
  96.  *     cycles."
  97.  *
  98.  * This langauge clears things up a bit, but it still leaves a lot of
  99.  * questions unanswered.
  100.  *
  101.  *     - Is the error generated at compile-time or link-time?
  102.  *
  103.  *     - Is it an error to have a recursive function that is never statically
  104.  *       called by main or any function called directly or indirectly by main?
  105.  *       Technically speaking, such a function is not in the "static function
  106.  *       call graph of the program" at all.
  107.  *
  108.  * \bug
  109.  * If a shader has multiple cycles, this algorithm may erroneously complain
  110.  * about functions that aren't in any cycle, but are in the part of the call
  111.  * tree that connects them.  For example, if the call graph consists of a
  112.  * cycle between A and B, and a cycle between D and E, and B also calls C
  113.  * which calls D, then this algorithm will report C as a function which "has
  114.  * static recursion" even though it is not part of any cycle.
  115.  *
  116.  * A better algorithm for cycle detection that doesn't have this drawback can
  117.  * be found here:
  118.  *
  119.  * http://en.wikipedia.org/wiki/Tarjan%E2%80%99s_strongly_connected_components_algorithm
  120.  *
  121.  * \author Ian Romanick <ian.d.romanick@intel.com>
  122.  */
  123. #include "main/core.h"
  124. #include "ir.h"
  125. #include "glsl_parser_extras.h"
  126. #include "linker.h"
  127. #include "program/hash_table.h"
  128. #include "program.h"
  129.  
  130. struct call_node : public exec_node {
  131.    class function *func;
  132. };
  133.  
  134. class function {
  135. public:
  136.    function(ir_function_signature *sig)
  137.       : sig(sig)
  138.    {
  139.       /* empty */
  140.    }
  141.  
  142.  
  143.    /* Callers of this ralloc-based new need not call delete. It's
  144.     * easier to just ralloc_free 'ctx' (or any of its ancestors). */
  145.    static void* operator new(size_t size, void *ctx)
  146.    {
  147.       void *node;
  148.  
  149.       node = ralloc_size(ctx, size);
  150.       assert(node != NULL);
  151.  
  152.       return node;
  153.    }
  154.  
  155.    /* If the user *does* call delete, that's OK, we will just
  156.     * ralloc_free in that case. */
  157.    static void operator delete(void *node)
  158.    {
  159.       ralloc_free(node);
  160.    }
  161.  
  162.    ir_function_signature *sig;
  163.  
  164.    /** List of functions called by this function. */
  165.    exec_list callees;
  166.  
  167.    /** List of functions that call this function. */
  168.    exec_list callers;
  169. };
  170.  
  171. class has_recursion_visitor : public ir_hierarchical_visitor {
  172. public:
  173.    has_recursion_visitor()
  174.       : current(NULL)
  175.    {
  176.       progress = false;
  177.       this->mem_ctx = ralloc_context(NULL);
  178.       this->function_hash = hash_table_ctor(0, hash_table_pointer_hash,
  179.                                             hash_table_pointer_compare);
  180.    }
  181.  
  182.    ~has_recursion_visitor()
  183.    {
  184.       hash_table_dtor(this->function_hash);
  185.       ralloc_free(this->mem_ctx);
  186.    }
  187.  
  188.    function *get_function(ir_function_signature *sig)
  189.    {
  190.       function *f = (function *) hash_table_find(this->function_hash, sig);
  191.       if (f == NULL) {
  192.          f = new(mem_ctx) function(sig);
  193.          hash_table_insert(this->function_hash, f, sig);
  194.       }
  195.  
  196.       return f;
  197.    }
  198.  
  199.    virtual ir_visitor_status visit_enter(ir_function_signature *sig)
  200.    {
  201.       this->current = this->get_function(sig);
  202.       return visit_continue;
  203.    }
  204.  
  205.    virtual ir_visitor_status visit_leave(ir_function_signature *sig)
  206.    {
  207.       (void) sig;
  208.       this->current = NULL;
  209.       return visit_continue;
  210.    }
  211.  
  212.    virtual ir_visitor_status visit_enter(ir_call *call)
  213.    {
  214.       /* At global scope this->current will be NULL.  Since there is no way to
  215.        * call global scope, it can never be part of a cycle.  Don't bother
  216.        * adding calls from global scope to the graph.
  217.        */
  218.       if (this->current == NULL)
  219.          return visit_continue;
  220.  
  221.       function *const target = this->get_function(call->callee);
  222.  
  223.       /* Create a link from the caller to the callee.
  224.        */
  225.       call_node *node = new(mem_ctx) call_node;
  226.       node->func = target;
  227.       this->current->callees.push_tail(node);
  228.  
  229.       /* Create a link from the callee to the caller.
  230.        */
  231.       node = new(mem_ctx) call_node;
  232.       node->func = this->current;
  233.       target->callers.push_tail(node);
  234.       return visit_continue;
  235.    }
  236.  
  237.    function *current;
  238.    struct hash_table *function_hash;
  239.    void *mem_ctx;
  240.    bool progress;
  241. };
  242.  
  243. static void
  244. destroy_links(exec_list *list, function *f)
  245. {
  246.    foreach_list_safe(node, list) {
  247.       struct call_node *n = (struct call_node *) node;
  248.  
  249.       /* If this is the right function, remove it.  Note that the loop cannot
  250.        * terminate now.  There can be multiple links to a function if it is
  251.        * either called multiple times or calls multiple times.
  252.        */
  253.       if (n->func == f)
  254.          n->remove();
  255.    }
  256. }
  257.  
  258.  
  259. /**
  260.  * Remove a function if it has either no in or no out links
  261.  */
  262. static void
  263. remove_unlinked_functions(const void *key, void *data, void *closure)
  264. {
  265.    has_recursion_visitor *visitor = (has_recursion_visitor *) closure;
  266.    function *f = (function *) data;
  267.  
  268.    if (f->callers.is_empty() || f->callees.is_empty()) {
  269.       while (!f->callers.is_empty()) {
  270.          struct call_node *n = (struct call_node *) f->callers.pop_head();
  271.          destroy_links(& n->func->callees, f);
  272.       }
  273.  
  274.       while (!f->callees.is_empty()) {
  275.          struct call_node *n = (struct call_node *) f->callees.pop_head();
  276.          destroy_links(& n->func->callers, f);
  277.       }
  278.  
  279.       hash_table_remove(visitor->function_hash, key);
  280.       visitor->progress = true;
  281.    }
  282. }
  283.  
  284.  
  285. static void
  286. emit_errors_unlinked(const void *key, void *data, void *closure)
  287. {
  288.    struct _mesa_glsl_parse_state *state =
  289.       (struct _mesa_glsl_parse_state *) closure;
  290.    function *f = (function *) data;
  291.    YYLTYPE loc;
  292.  
  293.    (void) key;
  294.  
  295.    char *proto = prototype_string(f->sig->return_type,
  296.                                   f->sig->function_name(),
  297.                                   &f->sig->parameters);
  298.  
  299.    memset(&loc, 0, sizeof(loc));
  300.    _mesa_glsl_error(&loc, state,
  301.                     "function `%s' has static recursion.",
  302.                     proto);
  303.    ralloc_free(proto);
  304. }
  305.  
  306.  
  307. static void
  308. emit_errors_linked(const void *key, void *data, void *closure)
  309. {
  310.    struct gl_shader_program *prog =
  311.       (struct gl_shader_program *) closure;
  312.    function *f = (function *) data;
  313.  
  314.    (void) key;
  315.  
  316.    char *proto = prototype_string(f->sig->return_type,
  317.                                   f->sig->function_name(),
  318.                                   &f->sig->parameters);
  319.  
  320.    linker_error(prog, "function `%s' has static recursion.\n", proto);
  321.    ralloc_free(proto);
  322.    prog->LinkStatus = false;
  323. }
  324.  
  325.  
  326. void
  327. detect_recursion_unlinked(struct _mesa_glsl_parse_state *state,
  328.                           exec_list *instructions)
  329. {
  330.    has_recursion_visitor v;
  331.  
  332.    /* Collect all of the information about which functions call which other
  333.     * functions.
  334.     */
  335.    v.run(instructions);
  336.  
  337.    /* Remove from the set all of the functions that either have no caller or
  338.     * call no other functions.  Repeat until no functions are removed.
  339.     */
  340.    do {
  341.       v.progress = false;
  342.       hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
  343.    } while (v.progress);
  344.  
  345.  
  346.    /* At this point any functions still in the hash must be part of a cycle.
  347.     */
  348.    hash_table_call_foreach(v.function_hash, emit_errors_unlinked, state);
  349. }
  350.  
  351.  
  352. void
  353. detect_recursion_linked(struct gl_shader_program *prog,
  354.                         exec_list *instructions)
  355. {
  356.    has_recursion_visitor v;
  357.  
  358.    /* Collect all of the information about which functions call which other
  359.     * functions.
  360.     */
  361.    v.run(instructions);
  362.  
  363.    /* Remove from the set all of the functions that either have no caller or
  364.     * call no other functions.  Repeat until no functions are removed.
  365.     */
  366.    do {
  367.       v.progress = false;
  368.       hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
  369.    } while (v.progress);
  370.  
  371.  
  372.    /* At this point any functions still in the hash must be part of a cycle.
  373.     */
  374.    hash_table_call_foreach(v.function_hash, emit_errors_linked, prog);
  375. }
  376.