Line data Source code
1 : //
2 : // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3 : // Use of this source code is governed by a BSD-style license that can be
4 : // found in the LICENSE file.
5 : //
6 :
7 : #ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_H_
8 : #define COMPILER_TRANSLATOR_SYMBOLTABLE_H_
9 :
10 : //
11 : // Symbol table for parsing. Has these design characteristics:
12 : //
13 : // * Same symbol table can be used to compile many shaders, to preserve
14 : // effort of creating and loading with the large numbers of built-in
15 : // symbols.
16 : //
17 : // * Name mangling will be used to give each function a unique name
18 : // so that symbol table lookups are never ambiguous. This allows
19 : // a simpler symbol table structure.
20 : //
21 : // * Pushing and popping of scope, so symbol table will really be a stack
22 : // of symbol tables. Searched from the top, with new inserts going into
23 : // the top.
24 : //
25 : // * Constants: Compile time constant symbols will keep their values
26 : // in the symbol table. The parser can substitute constants at parse
27 : // time, including doing constant folding and constant propagation.
28 : //
29 : // * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
30 : // are tracked in the intermediate representation, not the symbol table.
31 : //
32 :
33 : #include <array>
34 : #include <assert.h>
35 : #include <set>
36 :
37 : #include "common/angleutils.h"
38 : #include "compiler/translator/InfoSink.h"
39 : #include "compiler/translator/IntermNode.h"
40 :
41 : namespace sh
42 : {
43 :
44 : // Symbol base class. (Can build functions or variables out of these...)
45 : class TSymbol : angle::NonCopyable
46 : {
47 : public:
48 0 : POOL_ALLOCATOR_NEW_DELETE();
49 : TSymbol(const TString *n);
50 :
51 0 : virtual ~TSymbol()
52 0 : {
53 : // don't delete name, it's from the pool
54 0 : }
55 :
56 0 : const TString &getName() const
57 : {
58 0 : return *name;
59 : }
60 0 : virtual const TString &getMangledName() const
61 : {
62 0 : return getName();
63 : }
64 0 : virtual bool isFunction() const
65 : {
66 0 : return false;
67 : }
68 0 : virtual bool isVariable() const
69 : {
70 0 : return false;
71 : }
72 0 : int getUniqueId() const
73 : {
74 0 : return uniqueId;
75 : }
76 0 : void relateToExtension(const TString &ext)
77 : {
78 0 : extension = ext;
79 0 : }
80 0 : const TString &getExtension() const
81 : {
82 0 : return extension;
83 : }
84 :
85 : private:
86 : const int uniqueId;
87 : const TString *name;
88 : TString extension;
89 : };
90 :
91 : // Variable class, meaning a symbol that's not a function.
92 : //
93 : // There could be a separate class heirarchy for Constant variables;
94 : // Only one of int, bool, or float, (or none) is correct for
95 : // any particular use, but it's easy to do this way, and doesn't
96 : // seem worth having separate classes, and "getConst" can't simply return
97 : // different values for different types polymorphically, so this is
98 : // just simple and pragmatic.
99 : class TVariable : public TSymbol
100 : {
101 : public:
102 0 : TVariable(const TString *name, const TType &t, bool uT = false)
103 0 : : TSymbol(name),
104 : type(t),
105 : userType(uT),
106 0 : unionArray(0)
107 : {
108 0 : }
109 0 : ~TVariable() override {}
110 0 : bool isVariable() const override { return true; }
111 0 : TType &getType()
112 : {
113 0 : return type;
114 : }
115 0 : const TType &getType() const
116 : {
117 0 : return type;
118 : }
119 0 : bool isUserType() const
120 : {
121 0 : return userType;
122 : }
123 0 : void setQualifier(TQualifier qualifier)
124 : {
125 0 : type.setQualifier(qualifier);
126 0 : }
127 :
128 0 : const TConstantUnion *getConstPointer() const { return unionArray; }
129 :
130 0 : void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; }
131 :
132 : private:
133 : TType type;
134 : bool userType;
135 : // we are assuming that Pool Allocator will free the memory
136 : // allocated to unionArray when this object is destroyed.
137 : const TConstantUnion *unionArray;
138 : };
139 :
140 : // Immutable version of TParameter.
141 : struct TConstParameter
142 : {
143 : TConstParameter()
144 : : name(nullptr),
145 : type(nullptr)
146 : {
147 : }
148 : explicit TConstParameter(const TString *n)
149 : : name(n),
150 : type(nullptr)
151 : {
152 : }
153 0 : explicit TConstParameter(const TType *t)
154 0 : : name(nullptr),
155 0 : type(t)
156 : {
157 0 : }
158 0 : TConstParameter(const TString *n, const TType *t)
159 0 : : name(n),
160 0 : type(t)
161 : {
162 0 : }
163 :
164 : // Both constructor arguments must be const.
165 : TConstParameter(TString *n, TType *t) = delete;
166 : TConstParameter(const TString *n, TType *t) = delete;
167 : TConstParameter(TString *n, const TType *t) = delete;
168 :
169 : const TString *name;
170 : const TType *type;
171 : };
172 :
173 : // The function sub-class of symbols and the parser will need to
174 : // share this definition of a function parameter.
175 : struct TParameter
176 : {
177 : // Destructively converts to TConstParameter.
178 : // This method resets name and type to nullptrs to make sure
179 : // their content cannot be modified after the call.
180 0 : TConstParameter turnToConst()
181 : {
182 0 : const TString *constName = name;
183 0 : const TType *constType = type;
184 0 : name = nullptr;
185 0 : type = nullptr;
186 0 : return TConstParameter(constName, constType);
187 : }
188 :
189 : TString *name;
190 : TType *type;
191 : };
192 :
193 : // The function sub-class of a symbol.
194 : class TFunction : public TSymbol
195 : {
196 : public:
197 0 : TFunction(const TString *name,
198 : const TType *retType,
199 : TOperator tOp = EOpNull,
200 : const char *ext = "")
201 0 : : TSymbol(name),
202 : returnType(retType),
203 : mangledName(nullptr),
204 : op(tOp),
205 : defined(false),
206 0 : mHasPrototypeDeclaration(false)
207 : {
208 0 : relateToExtension(ext);
209 0 : }
210 : ~TFunction() override;
211 0 : bool isFunction() const override { return true; }
212 :
213 0 : static TString mangleName(const TString &name)
214 : {
215 0 : return name + '(';
216 : }
217 0 : static TString unmangleName(const TString &mangledName)
218 : {
219 0 : return TString(mangledName.c_str(), mangledName.find_first_of('('));
220 : }
221 :
222 0 : void addParameter(const TConstParameter &p)
223 : {
224 0 : parameters.push_back(p);
225 0 : mangledName = nullptr;
226 0 : }
227 :
228 : void swapParameters(const TFunction ¶metersSource);
229 :
230 0 : const TString &getMangledName() const override
231 : {
232 0 : if (mangledName == nullptr)
233 : {
234 0 : mangledName = buildMangledName();
235 : }
236 0 : return *mangledName;
237 : }
238 0 : const TType &getReturnType() const
239 : {
240 0 : return *returnType;
241 : }
242 :
243 0 : TOperator getBuiltInOp() const
244 : {
245 0 : return op;
246 : }
247 :
248 0 : void setDefined() { defined = true; }
249 0 : bool isDefined() { return defined; }
250 0 : void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; }
251 0 : bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; }
252 :
253 0 : size_t getParamCount() const
254 : {
255 0 : return parameters.size();
256 : }
257 0 : const TConstParameter &getParam(size_t i) const
258 : {
259 0 : return parameters[i];
260 : }
261 :
262 : private:
263 : void clearParameters();
264 :
265 : const TString *buildMangledName() const;
266 :
267 : typedef TVector<TConstParameter> TParamList;
268 : TParamList parameters;
269 : const TType *returnType;
270 : mutable const TString *mangledName;
271 : TOperator op;
272 : bool defined;
273 : bool mHasPrototypeDeclaration;
274 : };
275 :
276 : // Interface block name sub-symbol
277 : class TInterfaceBlockName : public TSymbol
278 : {
279 : public:
280 0 : TInterfaceBlockName(const TString *name)
281 0 : : TSymbol(name)
282 : {
283 0 : }
284 :
285 0 : virtual ~TInterfaceBlockName()
286 0 : {
287 0 : }
288 : };
289 :
290 : class TSymbolTableLevel
291 : {
292 : public:
293 : typedef TMap<TString, TSymbol *> tLevel;
294 : typedef tLevel::const_iterator const_iterator;
295 : typedef const tLevel::value_type tLevelPair;
296 : typedef std::pair<tLevel::iterator, bool> tInsertResult;
297 :
298 0 : TSymbolTableLevel()
299 0 : : mGlobalInvariant(false)
300 : {
301 0 : }
302 : ~TSymbolTableLevel();
303 :
304 : bool insert(TSymbol *symbol);
305 :
306 : // Insert a function using its unmangled name as the key.
307 : bool insertUnmangled(TFunction *function);
308 :
309 : TSymbol *find(const TString &name) const;
310 :
311 0 : void addInvariantVarying(const std::string &name)
312 : {
313 0 : mInvariantVaryings.insert(name);
314 0 : }
315 :
316 0 : bool isVaryingInvariant(const std::string &name)
317 : {
318 0 : return (mGlobalInvariant || mInvariantVaryings.count(name) > 0);
319 : }
320 :
321 0 : void setGlobalInvariant(bool invariant) { mGlobalInvariant = invariant; }
322 :
323 : protected:
324 : tLevel level;
325 : std::set<std::string> mInvariantVaryings;
326 : bool mGlobalInvariant;
327 : };
328 :
329 : // Define ESymbolLevel as int rather than an enum since level can go
330 : // above GLOBAL_LEVEL and cause atBuiltInLevel() to fail if the
331 : // compiler optimizes the >= of the last element to ==.
332 : typedef int ESymbolLevel;
333 : const int COMMON_BUILTINS = 0;
334 : const int ESSL1_BUILTINS = 1;
335 : const int ESSL3_BUILTINS = 2;
336 : const int ESSL3_1_BUILTINS = 3;
337 : const int LAST_BUILTIN_LEVEL = ESSL3_1_BUILTINS;
338 : const int GLOBAL_LEVEL = 4;
339 :
340 : class TSymbolTable : angle::NonCopyable
341 : {
342 : public:
343 0 : TSymbolTable()
344 0 : {
345 : // The symbol table cannot be used until push() is called, but
346 : // the lack of an initial call to push() can be used to detect
347 : // that the symbol table has not been preloaded with built-ins.
348 0 : }
349 :
350 : ~TSymbolTable();
351 :
352 : // When the symbol table is initialized with the built-ins, there should
353 : // 'push' calls, so that built-ins are at level 0 and the shader
354 : // globals are at level 1.
355 0 : bool isEmpty() const
356 : {
357 0 : return table.empty();
358 : }
359 0 : bool atBuiltInLevel() const
360 : {
361 0 : return currentLevel() <= LAST_BUILTIN_LEVEL;
362 : }
363 0 : bool atGlobalLevel() const
364 : {
365 0 : return currentLevel() == GLOBAL_LEVEL;
366 : }
367 0 : void push()
368 : {
369 0 : table.push_back(new TSymbolTableLevel);
370 0 : precisionStack.push_back(new PrecisionStackLevel);
371 0 : }
372 :
373 0 : void pop()
374 : {
375 0 : delete table.back();
376 0 : table.pop_back();
377 :
378 0 : delete precisionStack.back();
379 0 : precisionStack.pop_back();
380 0 : }
381 :
382 0 : bool declare(TSymbol *symbol)
383 : {
384 0 : return insert(currentLevel(), symbol);
385 : }
386 :
387 0 : bool insert(ESymbolLevel level, TSymbol *symbol)
388 : {
389 0 : return table[level]->insert(symbol);
390 : }
391 :
392 0 : bool insert(ESymbolLevel level, const char *ext, TSymbol *symbol)
393 : {
394 0 : symbol->relateToExtension(ext);
395 0 : return table[level]->insert(symbol);
396 : }
397 :
398 0 : bool insertConstInt(ESymbolLevel level, const char *name, int value, TPrecision precision)
399 : {
400 : TVariable *constant =
401 0 : new TVariable(NewPoolTString(name), TType(EbtInt, precision, EvqConst, 1));
402 0 : TConstantUnion *unionArray = new TConstantUnion[1];
403 0 : unionArray[0].setIConst(value);
404 0 : constant->shareConstPointer(unionArray);
405 0 : return insert(level, constant);
406 : }
407 :
408 0 : bool insertConstIntExt(ESymbolLevel level, const char *ext, const char *name, int value)
409 : {
410 : TVariable *constant =
411 0 : new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
412 0 : TConstantUnion *unionArray = new TConstantUnion[1];
413 0 : unionArray[0].setIConst(value);
414 0 : constant->shareConstPointer(unionArray);
415 0 : return insert(level, ext, constant);
416 : }
417 :
418 0 : bool insertConstIvec3(ESymbolLevel level,
419 : const char *name,
420 : const std::array<int, 3> &values,
421 : TPrecision precision)
422 : {
423 : TVariable *constantIvec3 =
424 0 : new TVariable(NewPoolTString(name), TType(EbtInt, precision, EvqConst, 3));
425 :
426 0 : TConstantUnion *unionArray = new TConstantUnion[3];
427 0 : for (size_t index = 0u; index < 3u; ++index)
428 : {
429 0 : unionArray[index].setIConst(values[index]);
430 : }
431 0 : constantIvec3->shareConstPointer(unionArray);
432 :
433 0 : return insert(level, constantIvec3);
434 : }
435 :
436 : void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, const TType *rvalue, const char *name,
437 : const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0);
438 :
439 0 : void insertBuiltIn(ESymbolLevel level, const TType *rvalue, const char *name,
440 : const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
441 : {
442 0 : insertUnmangledBuiltIn(name);
443 0 : insertBuiltIn(level, EOpNull, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
444 0 : }
445 :
446 0 : void insertBuiltIn(ESymbolLevel level, const char *ext, const TType *rvalue, const char *name,
447 : const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
448 : {
449 0 : insertUnmangledBuiltIn(name);
450 0 : insertBuiltIn(level, EOpNull, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
451 0 : }
452 :
453 0 : void insertBuiltIn(ESymbolLevel level, TOperator op, const TType *rvalue, const char *name,
454 : const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
455 : {
456 0 : insertUnmangledBuiltIn(name);
457 0 : insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
458 0 : }
459 :
460 : TSymbol *find(const TString &name, int shaderVersion,
461 : bool *builtIn = NULL, bool *sameScope = NULL) const;
462 :
463 : TSymbol *findGlobal(const TString &name) const;
464 :
465 : TSymbol *findBuiltIn(const TString &name, int shaderVersion) const;
466 :
467 0 : TSymbolTableLevel *getOuterLevel()
468 : {
469 0 : assert(currentLevel() >= 1);
470 0 : return table[currentLevel() - 1];
471 : }
472 :
473 : void dump(TInfoSink &infoSink) const;
474 :
475 0 : bool setDefaultPrecision(const TPublicType &type, TPrecision prec)
476 : {
477 0 : if (!SupportsPrecision(type.getBasicType()))
478 0 : return false;
479 0 : if (type.getBasicType() == EbtUInt)
480 0 : return false; // ESSL 3.00.4 section 4.5.4
481 0 : if (type.isAggregate())
482 0 : return false; // Not allowed to set for aggregate types
483 0 : int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
484 : // Uses map operator [], overwrites the current value
485 0 : (*precisionStack[indexOfLastElement])[type.getBasicType()] = prec;
486 0 : return true;
487 : }
488 :
489 : // Searches down the precisionStack for a precision qualifier
490 : // for the specified TBasicType
491 : TPrecision getDefaultPrecision(TBasicType type) const;
492 :
493 : // This records invariant varyings declared through
494 : // "invariant varying_name;".
495 0 : void addInvariantVarying(const std::string &originalName)
496 : {
497 0 : ASSERT(atGlobalLevel());
498 0 : table[currentLevel()]->addInvariantVarying(originalName);
499 0 : }
500 : // If this returns false, the varying could still be invariant
501 : // if it is set as invariant during the varying variable
502 : // declaration - this piece of information is stored in the
503 : // variable's type, not here.
504 0 : bool isVaryingInvariant(const std::string &originalName) const
505 : {
506 0 : ASSERT(atGlobalLevel());
507 0 : return table[currentLevel()]->isVaryingInvariant(originalName);
508 : }
509 :
510 0 : void setGlobalInvariant(bool invariant)
511 : {
512 0 : ASSERT(atGlobalLevel());
513 0 : table[currentLevel()]->setGlobalInvariant(invariant);
514 0 : }
515 :
516 0 : static int nextUniqueId()
517 : {
518 0 : return ++uniqueIdCounter;
519 : }
520 :
521 0 : bool hasUnmangledBuiltIn(const char *name)
522 : {
523 0 : return mUnmangledBuiltinNames.count(std::string(name)) > 0;
524 : }
525 :
526 : private:
527 0 : ESymbolLevel currentLevel() const
528 : {
529 0 : return static_cast<ESymbolLevel>(table.size() - 1);
530 : }
531 :
532 : // Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00.
533 0 : void insertUnmangledBuiltIn(const char *name)
534 : {
535 0 : mUnmangledBuiltinNames.insert(std::string(name));
536 0 : }
537 :
538 : std::vector<TSymbolTableLevel *> table;
539 : typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
540 : std::vector< PrecisionStackLevel *> precisionStack;
541 :
542 : std::set<std::string> mUnmangledBuiltinNames;
543 :
544 : static int uniqueIdCounter;
545 : };
546 :
547 : } // namespace sh
548 :
549 : #endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_
|