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