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(glsl_type_is_interface(t));
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_context(this->mem_ctx);
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(glsl_type_is_interface(i));
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
get_variable(const char * name)223 ir_variable *glsl_symbol_table::get_variable(const char *name)
224 {
225 symbol_table_entry *entry = get_entry(name);
226 return entry != NULL ? entry->v : NULL;
227 }
228
get_type(const char * name)229 const glsl_type *glsl_symbol_table::get_type(const char *name)
230 {
231 symbol_table_entry *entry = get_entry(name);
232 return entry != NULL ? entry->t : NULL;
233 }
234
get_interface(const char * name,enum ir_variable_mode mode)235 const glsl_type *glsl_symbol_table::get_interface(const char *name,
236 enum ir_variable_mode mode)
237 {
238 symbol_table_entry *entry = get_entry(name);
239 return entry != NULL ? entry->get_interface(mode) : NULL;
240 }
241
get_function(const char * name)242 ir_function *glsl_symbol_table::get_function(const char *name)
243 {
244 symbol_table_entry *entry = get_entry(name);
245 return entry != NULL ? entry->f : NULL;
246 }
247
get_default_precision_qualifier(const char * type_name)248 int glsl_symbol_table::get_default_precision_qualifier(const char *type_name)
249 {
250 char *name = ralloc_asprintf(mem_ctx, "#default_precision_%s", type_name);
251 symbol_table_entry *entry = get_entry(name);
252 if (!entry)
253 return ast_precision_none;
254 return entry->a->default_precision;
255 }
256
get_entry(const char * name)257 symbol_table_entry *glsl_symbol_table::get_entry(const char *name)
258 {
259 return (symbol_table_entry *)
260 _mesa_symbol_table_find_symbol(table, name);
261 }
262
263 void
disable_variable(const char * name)264 glsl_symbol_table::disable_variable(const char *name)
265 {
266 /* Ideally we would remove the variable's entry from the symbol table, but
267 * that would be difficult. Fortunately, since this is only used for
268 * built-in variables, it won't be possible for the shader to re-introduce
269 * the variable later, so all we really need to do is to make sure that
270 * further attempts to access it using get_variable() will return NULL.
271 */
272 symbol_table_entry *entry = get_entry(name);
273 if (entry != NULL) {
274 entry->v = NULL;
275 }
276 }
277
278 void
replace_variable(const char * name,ir_variable * v)279 glsl_symbol_table::replace_variable(const char *name,
280 ir_variable *v)
281 {
282 symbol_table_entry *entry = get_entry(name);
283 if (entry != NULL) {
284 entry->v = v;
285 }
286 }
287