Home | History | Annotate | Download | only in glsl
      1 /* -*- c++ -*- */
      2 /*
      3  * Copyright  2010 Intel Corporation
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22  * DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 #include "glsl_symbol_table.h"
     26 #include "ast.h"
     27 
     28 class symbol_table_entry {
     29 public:
     30    DECLARE_LINEAR_ALLOC_CXX_OPERATORS(symbol_table_entry);
     31 
     32    bool add_interface(const glsl_type *i, enum ir_variable_mode mode)
     33    {
     34       const glsl_type **dest;
     35 
     36       switch (mode) {
     37       case ir_var_uniform:
     38          dest = &ibu;
     39          break;
     40       case ir_var_shader_storage:
     41          dest = &iss;
     42          break;
     43       case ir_var_shader_in:
     44          dest = &ibi;
     45          break;
     46       case ir_var_shader_out:
     47          dest = &ibo;
     48          break;
     49       default:
     50          assert(!"Unsupported interface variable mode!");
     51          return false;
     52       }
     53 
     54       if (*dest != NULL) {
     55          return false;
     56       } else {
     57          *dest = i;
     58          return true;
     59       }
     60    }
     61 
     62    const glsl_type *get_interface(enum ir_variable_mode mode)
     63    {
     64       switch (mode) {
     65       case ir_var_uniform:
     66          return ibu;
     67       case ir_var_shader_storage:
     68          return iss;
     69       case ir_var_shader_in:
     70          return ibi;
     71       case ir_var_shader_out:
     72          return ibo;
     73       default:
     74          assert(!"Unsupported interface variable mode!");
     75          return NULL;
     76       }
     77    }
     78 
     79    symbol_table_entry(ir_variable *v)               :
     80       v(v), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) {}
     81    symbol_table_entry(ir_function *f)               :
     82       v(0), f(f), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) {}
     83    symbol_table_entry(const glsl_type *t)           :
     84       v(0), f(0), t(t), ibu(0), iss(0), ibi(0), ibo(0), a(0) {}
     85    symbol_table_entry(const glsl_type *t, enum ir_variable_mode mode) :
     86       v(0), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0)
     87    {
     88       assert(t->is_interface());
     89       add_interface(t, mode);
     90    }
     91    symbol_table_entry(const class ast_type_specifier *a):
     92       v(0), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(a) {}
     93 
     94    ir_variable *v;
     95    ir_function *f;
     96    const glsl_type *t;
     97    const glsl_type *ibu;
     98    const glsl_type *iss;
     99    const glsl_type *ibi;
    100    const glsl_type *ibo;
    101    const class ast_type_specifier *a;
    102 };
    103 
    104 glsl_symbol_table::glsl_symbol_table()
    105 {
    106    this->separate_function_namespace = false;
    107    this->table = _mesa_symbol_table_ctor();
    108    this->mem_ctx = ralloc_context(NULL);
    109    this->linalloc = linear_alloc_parent(this->mem_ctx, 0);
    110 }
    111 
    112 glsl_symbol_table::~glsl_symbol_table()
    113 {
    114    _mesa_symbol_table_dtor(table);
    115    ralloc_free(mem_ctx);
    116 }
    117 
    118 void glsl_symbol_table::push_scope()
    119 {
    120    _mesa_symbol_table_push_scope(table);
    121 }
    122 
    123 void glsl_symbol_table::pop_scope()
    124 {
    125    _mesa_symbol_table_pop_scope(table);
    126 }
    127 
    128 bool glsl_symbol_table::name_declared_this_scope(const char *name)
    129 {
    130    return _mesa_symbol_table_symbol_scope(table, name) == 0;
    131 }
    132 
    133 bool glsl_symbol_table::add_variable(ir_variable *v)
    134 {
    135    assert(v->data.mode != ir_var_temporary);
    136 
    137    if (this->separate_function_namespace) {
    138       /* In 1.10, functions and variables have separate namespaces. */
    139       symbol_table_entry *existing = get_entry(v->name);
    140       if (name_declared_this_scope(v->name)) {
    141 	 /* If there's already an existing function (not a constructor!) in
    142 	  * the current scope, just update the existing entry to include 'v'.
    143 	  */
    144 	 if (existing->v == NULL && existing->t == NULL) {
    145 	    existing->v = v;
    146 	    return true;
    147 	 }
    148       } else {
    149 	 /* If not declared at this scope, add a new entry.  But if an existing
    150 	  * entry includes a function, propagate that to this block - otherwise
    151 	  * the new variable declaration would shadow the function.
    152 	  */
    153 	 symbol_table_entry *entry = new(linalloc) symbol_table_entry(v);
    154 	 if (existing != NULL)
    155 	    entry->f = existing->f;
    156 	 int added = _mesa_symbol_table_add_symbol(table, v->name, entry);
    157 	 assert(added == 0);
    158 	 (void)added;
    159 	 return true;
    160       }
    161       return false;
    162    }
    163 
    164    /* 1.20+ rules: */
    165    symbol_table_entry *entry = new(linalloc) symbol_table_entry(v);
    166    return _mesa_symbol_table_add_symbol(table, v->name, entry) == 0;
    167 }
    168 
    169 bool glsl_symbol_table::add_type(const char *name, const glsl_type *t)
    170 {
    171    symbol_table_entry *entry = new(linalloc) symbol_table_entry(t);
    172    return _mesa_symbol_table_add_symbol(table, name, entry) == 0;
    173 }
    174 
    175 bool glsl_symbol_table::add_interface(const char *name, const glsl_type *i,
    176                                       enum ir_variable_mode mode)
    177 {
    178    assert(i->is_interface());
    179    symbol_table_entry *entry = get_entry(name);
    180    if (entry == NULL) {
    181       symbol_table_entry *entry =
    182          new(linalloc) symbol_table_entry(i, mode);
    183       bool add_interface_symbol_result =
    184          _mesa_symbol_table_add_symbol(table, name, entry) == 0;
    185       assert(add_interface_symbol_result);
    186       return add_interface_symbol_result;
    187    } else {
    188       return entry->add_interface(i, mode);
    189    }
    190 }
    191 
    192 bool glsl_symbol_table::add_function(ir_function *f)
    193 {
    194    if (this->separate_function_namespace && name_declared_this_scope(f->name)) {
    195       /* In 1.10, functions and variables have separate namespaces. */
    196       symbol_table_entry *existing = get_entry(f->name);
    197       if ((existing->f == NULL) && (existing->t == NULL)) {
    198 	 existing->f = f;
    199 	 return true;
    200       }
    201    }
    202    symbol_table_entry *entry = new(linalloc) symbol_table_entry(f);
    203    return _mesa_symbol_table_add_symbol(table, f->name, entry) == 0;
    204 }
    205 
    206 bool glsl_symbol_table::add_default_precision_qualifier(const char *type_name,
    207                                                         int precision)
    208 {
    209    char *name = ralloc_asprintf(mem_ctx, "#default_precision_%s", type_name);
    210 
    211    ast_type_specifier *default_specifier = new(linalloc) ast_type_specifier(name);
    212    default_specifier->default_precision = precision;
    213 
    214    symbol_table_entry *entry =
    215       new(linalloc) symbol_table_entry(default_specifier);
    216 
    217    if (!get_entry(name))
    218       return _mesa_symbol_table_add_symbol(table, name, entry) == 0;
    219 
    220    return _mesa_symbol_table_replace_symbol(table, name, entry) == 0;
    221 }
    222 
    223 void glsl_symbol_table::add_global_function(ir_function *f)
    224 {
    225    symbol_table_entry *entry = new(linalloc) symbol_table_entry(f);
    226    int added = _mesa_symbol_table_add_global_symbol(table, f->name, entry);
    227    assert(added == 0);
    228    (void)added;
    229 }
    230 
    231 ir_variable *glsl_symbol_table::get_variable(const char *name)
    232 {
    233    symbol_table_entry *entry = get_entry(name);
    234    return entry != NULL ? entry->v : NULL;
    235 }
    236 
    237 const glsl_type *glsl_symbol_table::get_type(const char *name)
    238 {
    239    symbol_table_entry *entry = get_entry(name);
    240    return entry != NULL ? entry->t : NULL;
    241 }
    242 
    243 const glsl_type *glsl_symbol_table::get_interface(const char *name,
    244                                                   enum ir_variable_mode mode)
    245 {
    246    symbol_table_entry *entry = get_entry(name);
    247    return entry != NULL ? entry->get_interface(mode) : NULL;
    248 }
    249 
    250 ir_function *glsl_symbol_table::get_function(const char *name)
    251 {
    252    symbol_table_entry *entry = get_entry(name);
    253    return entry != NULL ? entry->f : NULL;
    254 }
    255 
    256 int glsl_symbol_table::get_default_precision_qualifier(const char *type_name)
    257 {
    258    char *name = ralloc_asprintf(mem_ctx, "#default_precision_%s", type_name);
    259    symbol_table_entry *entry = get_entry(name);
    260    if (!entry)
    261       return ast_precision_none;
    262    return entry->a->default_precision;
    263 }
    264 
    265 symbol_table_entry *glsl_symbol_table::get_entry(const char *name)
    266 {
    267    return (symbol_table_entry *)
    268       _mesa_symbol_table_find_symbol(table, name);
    269 }
    270 
    271 void
    272 glsl_symbol_table::disable_variable(const char *name)
    273 {
    274    /* Ideally we would remove the variable's entry from the symbol table, but
    275     * that would be difficult.  Fortunately, since this is only used for
    276     * built-in variables, it won't be possible for the shader to re-introduce
    277     * the variable later, so all we really need to do is to make sure that
    278     * further attempts to access it using get_variable() will return NULL.
    279     */
    280    symbol_table_entry *entry = get_entry(name);
    281    if (entry != NULL) {
    282       entry->v = NULL;
    283    }
    284 }
    285 
    286 void
    287 glsl_symbol_table::replace_variable(const char *name,
    288                                     ir_variable *v)
    289 {
    290    symbol_table_entry *entry = get_entry(name);
    291    if (entry != NULL) {
    292       entry->v = v;
    293    }
    294 }
    295