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 
add_interface(const glsl_type * i,enum ir_variable_mode mode)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 
get_interface(enum ir_variable_mode mode)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 
symbol_table_entry(ir_variable * v)79    symbol_table_entry(ir_variable *v)               :
80       v(v), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) {}
symbol_table_entry(ir_function * f)81    symbol_table_entry(ir_function *f)               :
82       v(0), f(f), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) {}
symbol_table_entry(const glsl_type * t)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) {}
symbol_table_entry(const glsl_type * t,enum ir_variable_mode mode)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    }
symbol_table_entry(const class ast_type_specifier * a)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 
glsl_symbol_table()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 
~glsl_symbol_table()112 glsl_symbol_table::~glsl_symbol_table()
113 {
114    _mesa_symbol_table_dtor(table);
115    ralloc_free(mem_ctx);
116 }
117 
push_scope()118 void glsl_symbol_table::push_scope()
119 {
120    _mesa_symbol_table_push_scope(table);
121 }
122 
pop_scope()123 void glsl_symbol_table::pop_scope()
124 {
125    _mesa_symbol_table_pop_scope(table);
126 }
127 
name_declared_this_scope(const char * name)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 
add_variable(ir_variable * v)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 
add_type(const char * name,const glsl_type * t)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 
add_interface(const char * name,const glsl_type * i,enum ir_variable_mode mode)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 
add_function(ir_function * f)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 
add_default_precision_qualifier(const char * type_name,int precision)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 
add_global_function(ir_function * f)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 
get_variable(const char * name)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 
get_type(const char * name)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 
get_interface(const char * name,enum ir_variable_mode mode)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 
get_function(const char * name)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 
get_default_precision_qualifier(const char * type_name)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 
get_entry(const char * name)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
disable_variable(const char * name)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
replace_variable(const char * name,ir_variable * v)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