536f0a3a8c23e319e1d3ef3956cc7653b4f747e0
[mesa.git] / src / glsl / glsl_symbol_table.cpp
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
27 class symbol_table_entry {
28 public:
29 DECLARE_RALLOC_CXX_OPERATORS(symbol_table_entry);
30
31 bool add_interface(const glsl_type *i, enum ir_variable_mode mode)
32 {
33 const glsl_type **dest;
34
35 switch (mode) {
36 case ir_var_uniform:
37 dest = &ibu;
38 break;
39 case ir_var_shader_storage:
40 dest = &iss;
41 break;
42 case ir_var_shader_in:
43 dest = &ibi;
44 break;
45 case ir_var_shader_out:
46 dest = &ibo;
47 break;
48 default:
49 assert(!"Unsupported interface variable mode!");
50 return false;
51 }
52
53 if (*dest != NULL) {
54 return false;
55 } else {
56 *dest = i;
57 return true;
58 }
59 }
60
61 const glsl_type *get_interface(enum ir_variable_mode mode)
62 {
63 switch (mode) {
64 case ir_var_uniform:
65 return ibu;
66 case ir_var_shader_storage:
67 return iss;
68 case ir_var_shader_in:
69 return ibi;
70 case ir_var_shader_out:
71 return ibo;
72 default:
73 assert(!"Unsupported interface variable mode!");
74 return NULL;
75 }
76 }
77
78 symbol_table_entry(ir_variable *v) :
79 v(v), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) {}
80 symbol_table_entry(ir_function *f) :
81 v(0), f(f), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) {}
82 symbol_table_entry(const glsl_type *t) :
83 v(0), f(0), t(t), ibu(0), iss(0), ibi(0), ibo(0), a(0) {}
84 symbol_table_entry(const glsl_type *t, enum ir_variable_mode mode) :
85 v(0), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0)
86 {
87 assert(t->is_interface());
88 add_interface(t, mode);
89 }
90 symbol_table_entry(const class ast_type_specifier *a):
91 v(0), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(a) {}
92
93 ir_variable *v;
94 ir_function *f;
95 const glsl_type *t;
96 const glsl_type *ibu;
97 const glsl_type *iss;
98 const glsl_type *ibi;
99 const glsl_type *ibo;
100 const class ast_type_specifier *a;
101 };
102
103 glsl_symbol_table::glsl_symbol_table()
104 {
105 this->separate_function_namespace = false;
106 this->table = _mesa_symbol_table_ctor();
107 this->mem_ctx = ralloc_context(NULL);
108 }
109
110 glsl_symbol_table::~glsl_symbol_table()
111 {
112 _mesa_symbol_table_dtor(table);
113 ralloc_free(mem_ctx);
114 }
115
116 void glsl_symbol_table::push_scope()
117 {
118 _mesa_symbol_table_push_scope(table);
119 }
120
121 void glsl_symbol_table::pop_scope()
122 {
123 _mesa_symbol_table_pop_scope(table);
124 }
125
126 bool glsl_symbol_table::name_declared_this_scope(const char *name)
127 {
128 return _mesa_symbol_table_symbol_scope(table, -1, name) == 0;
129 }
130
131 bool glsl_symbol_table::add_variable(ir_variable *v)
132 {
133 assert(v->data.mode != ir_var_temporary);
134
135 if (this->separate_function_namespace) {
136 /* In 1.10, functions and variables have separate namespaces. */
137 symbol_table_entry *existing = get_entry(v->name);
138 if (name_declared_this_scope(v->name)) {
139 /* If there's already an existing function (not a constructor!) in
140 * the current scope, just update the existing entry to include 'v'.
141 */
142 if (existing->v == NULL && existing->t == NULL) {
143 existing->v = v;
144 return true;
145 }
146 } else {
147 /* If not declared at this scope, add a new entry. But if an existing
148 * entry includes a function, propagate that to this block - otherwise
149 * the new variable declaration would shadow the function.
150 */
151 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(v);
152 if (existing != NULL)
153 entry->f = existing->f;
154 int added = _mesa_symbol_table_add_symbol(table, -1, v->name, entry);
155 assert(added == 0);
156 (void)added;
157 return true;
158 }
159 return false;
160 }
161
162 /* 1.20+ rules: */
163 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(v);
164 return _mesa_symbol_table_add_symbol(table, -1, v->name, entry) == 0;
165 }
166
167 bool glsl_symbol_table::add_type(const char *name, const glsl_type *t)
168 {
169 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(t);
170 return _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0;
171 }
172
173 bool glsl_symbol_table::add_interface(const char *name, const glsl_type *i,
174 enum ir_variable_mode mode)
175 {
176 assert(i->is_interface());
177 symbol_table_entry *entry = get_entry(name);
178 if (entry == NULL) {
179 symbol_table_entry *entry =
180 new(mem_ctx) symbol_table_entry(i, mode);
181 bool add_interface_symbol_result =
182 _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0;
183 assert(add_interface_symbol_result);
184 return add_interface_symbol_result;
185 } else {
186 return entry->add_interface(i, mode);
187 }
188 }
189
190 bool glsl_symbol_table::add_function(ir_function *f)
191 {
192 if (this->separate_function_namespace && name_declared_this_scope(f->name)) {
193 /* In 1.10, functions and variables have separate namespaces. */
194 symbol_table_entry *existing = get_entry(f->name);
195 if ((existing->f == NULL) && (existing->t == NULL)) {
196 existing->f = f;
197 return true;
198 }
199 }
200 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(f);
201 return _mesa_symbol_table_add_symbol(table, -1, f->name, entry) == 0;
202 }
203
204 void glsl_symbol_table::add_global_function(ir_function *f)
205 {
206 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(f);
207 int added = _mesa_symbol_table_add_global_symbol(table, -1, f->name, entry);
208 assert(added == 0);
209 (void)added;
210 }
211
212 ir_variable *glsl_symbol_table::get_variable(const char *name)
213 {
214 symbol_table_entry *entry = get_entry(name);
215 return entry != NULL ? entry->v : NULL;
216 }
217
218 const glsl_type *glsl_symbol_table::get_type(const char *name)
219 {
220 symbol_table_entry *entry = get_entry(name);
221 return entry != NULL ? entry->t : NULL;
222 }
223
224 const glsl_type *glsl_symbol_table::get_interface(const char *name,
225 enum ir_variable_mode mode)
226 {
227 symbol_table_entry *entry = get_entry(name);
228 return entry != NULL ? entry->get_interface(mode) : NULL;
229 }
230
231 ir_function *glsl_symbol_table::get_function(const char *name)
232 {
233 symbol_table_entry *entry = get_entry(name);
234 return entry != NULL ? entry->f : NULL;
235 }
236
237 symbol_table_entry *glsl_symbol_table::get_entry(const char *name)
238 {
239 return (symbol_table_entry *)
240 _mesa_symbol_table_find_symbol(table, -1, name);
241 }
242
243 void
244 glsl_symbol_table::disable_variable(const char *name)
245 {
246 /* Ideally we would remove the variable's entry from the symbol table, but
247 * that would be difficult. Fortunately, since this is only used for
248 * built-in variables, it won't be possible for the shader to re-introduce
249 * the variable later, so all we really need to do is to make sure that
250 * further attempts to access it using get_variable() will return NULL.
251 */
252 symbol_table_entry *entry = get_entry(name);
253 if (entry != NULL) {
254 entry->v = NULL;
255 }
256 }