Home | History | Annotate | Download | only in glsl
      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 (at) 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