• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 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 // Symbol table for parsing. The design principles and most of the functionality are documented in
7 // the header file.
8 //
9 
10 #if defined(_MSC_VER)
11 #    pragma warning(disable : 4718)
12 #endif
13 
14 #include "compiler/translator/SymbolTable.h"
15 
16 #include "angle_gl.h"
17 #include "compiler/translator/ImmutableString.h"
18 #include "compiler/translator/IntermNode.h"
19 #include "compiler/translator/StaticType.h"
20 #include "compiler/translator/util.h"
21 
22 namespace sh
23 {
24 namespace
25 {
CheckShaderType(Shader expected,GLenum actual)26 bool CheckShaderType(Shader expected, GLenum actual)
27 {
28     switch (expected)
29     {
30         case Shader::ALL:
31             return true;
32         case Shader::FRAGMENT:
33             return actual == GL_FRAGMENT_SHADER;
34         case Shader::VERTEX:
35             return actual == GL_VERTEX_SHADER;
36         case Shader::COMPUTE:
37             return actual == GL_COMPUTE_SHADER;
38         case Shader::GEOMETRY:
39             return actual == GL_GEOMETRY_SHADER;
40         case Shader::GEOMETRY_EXT:
41             return actual == GL_GEOMETRY_SHADER_EXT;
42         case Shader::NOT_COMPUTE:
43             return actual != GL_COMPUTE_SHADER;
44         default:
45             UNREACHABLE();
46             return false;
47     }
48 }
49 
CheckExtension(uint32_t extensionIndex,const ShBuiltInResources & resources)50 bool CheckExtension(uint32_t extensionIndex, const ShBuiltInResources &resources)
51 {
52     const int *resourcePtr = reinterpret_cast<const int *>(&resources);
53     return resourcePtr[extensionIndex] > 0;
54 }
55 }  // namespace
56 
57 class TSymbolTable::TSymbolTableLevel
58 {
59   public:
60     TSymbolTableLevel() = default;
61 
62     bool insert(TSymbol *symbol);
63 
64     // Insert a function using its unmangled name as the key.
65     void insertUnmangled(TFunction *function);
66 
67     TSymbol *find(const ImmutableString &name) const;
68 
69   private:
70     using tLevel        = TUnorderedMap<ImmutableString,
71                                  TSymbol *,
72                                  ImmutableString::FowlerNollVoHash<sizeof(size_t)>>;
73     using tLevelPair    = const tLevel::value_type;
74     using tInsertResult = std::pair<tLevel::iterator, bool>;
75 
76     tLevel level;
77 };
78 
insert(TSymbol * symbol)79 bool TSymbolTable::TSymbolTableLevel::insert(TSymbol *symbol)
80 {
81     // returning true means symbol was added to the table
82     tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol));
83     return result.second;
84 }
85 
insertUnmangled(TFunction * function)86 void TSymbolTable::TSymbolTableLevel::insertUnmangled(TFunction *function)
87 {
88     level.insert(tLevelPair(function->name(), function));
89 }
90 
find(const ImmutableString & name) const91 TSymbol *TSymbolTable::TSymbolTableLevel::find(const ImmutableString &name) const
92 {
93     tLevel::const_iterator it = level.find(name);
94     if (it == level.end())
95         return nullptr;
96     else
97         return (*it).second;
98 }
99 
TSymbolTable()100 TSymbolTable::TSymbolTable()
101     : mGlobalInvariant(false),
102       mUniqueIdCounter(0),
103       mShaderType(GL_FRAGMENT_SHADER),
104       mShaderSpec(SH_GLES2_SPEC),
105       mGlInVariableWithArraySize(nullptr)
106 {}
107 
108 TSymbolTable::~TSymbolTable() = default;
109 
isEmpty() const110 bool TSymbolTable::isEmpty() const
111 {
112     return mTable.empty();
113 }
114 
atGlobalLevel() const115 bool TSymbolTable::atGlobalLevel() const
116 {
117     return mTable.size() == 1u;
118 }
119 
push()120 void TSymbolTable::push()
121 {
122     mTable.emplace_back(new TSymbolTableLevel);
123     mPrecisionStack.emplace_back(new PrecisionStackLevel);
124 }
125 
pop()126 void TSymbolTable::pop()
127 {
128     mTable.pop_back();
129     mPrecisionStack.pop_back();
130 }
131 
markFunctionHasPrototypeDeclaration(const ImmutableString & mangledName,bool * hadPrototypeDeclarationOut) const132 const TFunction *TSymbolTable::markFunctionHasPrototypeDeclaration(
133     const ImmutableString &mangledName,
134     bool *hadPrototypeDeclarationOut) const
135 {
136     TFunction *function         = findUserDefinedFunction(mangledName);
137     *hadPrototypeDeclarationOut = function->hasPrototypeDeclaration();
138     function->setHasPrototypeDeclaration();
139     return function;
140 }
141 
setFunctionParameterNamesFromDefinition(const TFunction * function,bool * wasDefinedOut) const142 const TFunction *TSymbolTable::setFunctionParameterNamesFromDefinition(const TFunction *function,
143                                                                        bool *wasDefinedOut) const
144 {
145     TFunction *firstDeclaration = findUserDefinedFunction(function->getMangledName());
146     ASSERT(firstDeclaration);
147     // Note: 'firstDeclaration' could be 'function' if this is the first time we've seen function as
148     // it would have just been put in the symbol table. Otherwise, we're looking up an earlier
149     // occurance.
150     if (function != firstDeclaration)
151     {
152         // The previous declaration should have the same parameters as the function definition
153         // (parameter names may differ).
154         firstDeclaration->shareParameters(*function);
155     }
156 
157     *wasDefinedOut = firstDeclaration->isDefined();
158     firstDeclaration->setDefined();
159     return firstDeclaration;
160 }
161 
setGlInArraySize(unsigned int inputArraySize)162 bool TSymbolTable::setGlInArraySize(unsigned int inputArraySize)
163 {
164     if (mGlInVariableWithArraySize)
165     {
166         return mGlInVariableWithArraySize->getType().getOutermostArraySize() == inputArraySize;
167     }
168     const TInterfaceBlock *glPerVertex = static_cast<const TInterfaceBlock *>(m_gl_PerVertex);
169     TType *glInType = new TType(glPerVertex, EvqPerVertexIn, TLayoutQualifier::Create());
170     glInType->makeArray(inputArraySize);
171     mGlInVariableWithArraySize =
172         new TVariable(this, ImmutableString("gl_in"), glInType, SymbolType::BuiltIn,
173                       TExtension::EXT_geometry_shader);
174     return true;
175 }
176 
getGlInVariableWithArraySize() const177 TVariable *TSymbolTable::getGlInVariableWithArraySize() const
178 {
179     return mGlInVariableWithArraySize;
180 }
181 
gl_FragData() const182 const TVariable *TSymbolTable::gl_FragData() const
183 {
184     return static_cast<const TVariable *>(m_gl_FragData);
185 }
186 
gl_SecondaryFragDataEXT() const187 const TVariable *TSymbolTable::gl_SecondaryFragDataEXT() const
188 {
189     return static_cast<const TVariable *>(m_gl_SecondaryFragDataEXT);
190 }
191 
getOrCreateVariableMetadata(const TVariable & variable)192 TSymbolTable::VariableMetadata *TSymbolTable::getOrCreateVariableMetadata(const TVariable &variable)
193 {
194     int id    = variable.uniqueId().get();
195     auto iter = mVariableMetadata.find(id);
196     if (iter == mVariableMetadata.end())
197     {
198         iter = mVariableMetadata.insert(std::make_pair(id, VariableMetadata())).first;
199     }
200     return &iter->second;
201 }
202 
markStaticWrite(const TVariable & variable)203 void TSymbolTable::markStaticWrite(const TVariable &variable)
204 {
205     auto metadata         = getOrCreateVariableMetadata(variable);
206     metadata->staticWrite = true;
207 }
208 
markStaticRead(const TVariable & variable)209 void TSymbolTable::markStaticRead(const TVariable &variable)
210 {
211     auto metadata        = getOrCreateVariableMetadata(variable);
212     metadata->staticRead = true;
213 }
214 
isStaticallyUsed(const TVariable & variable) const215 bool TSymbolTable::isStaticallyUsed(const TVariable &variable) const
216 {
217     ASSERT(!variable.getConstPointer());
218     int id    = variable.uniqueId().get();
219     auto iter = mVariableMetadata.find(id);
220     return iter != mVariableMetadata.end() && (iter->second.staticRead || iter->second.staticWrite);
221 }
222 
addInvariantVarying(const TVariable & variable)223 void TSymbolTable::addInvariantVarying(const TVariable &variable)
224 {
225     ASSERT(atGlobalLevel());
226     auto metadata       = getOrCreateVariableMetadata(variable);
227     metadata->invariant = true;
228 }
229 
isVaryingInvariant(const TVariable & variable) const230 bool TSymbolTable::isVaryingInvariant(const TVariable &variable) const
231 {
232     ASSERT(atGlobalLevel());
233     if (mGlobalInvariant && (IsShaderOutput(variable.getType().getQualifier())))
234     {
235         return true;
236     }
237     int id    = variable.uniqueId().get();
238     auto iter = mVariableMetadata.find(id);
239     return iter != mVariableMetadata.end() && iter->second.invariant;
240 }
241 
setGlobalInvariant(bool invariant)242 void TSymbolTable::setGlobalInvariant(bool invariant)
243 {
244     ASSERT(atGlobalLevel());
245     mGlobalInvariant = invariant;
246 }
247 
find(const ImmutableString & name,int shaderVersion) const248 const TSymbol *TSymbolTable::find(const ImmutableString &name, int shaderVersion) const
249 {
250     const TSymbol *userSymbol = findUserDefined(name);
251     if (userSymbol)
252     {
253         return userSymbol;
254     }
255 
256     return findBuiltIn(name, shaderVersion);
257 }
258 
findUserDefined(const ImmutableString & name) const259 const TSymbol *TSymbolTable::findUserDefined(const ImmutableString &name) const
260 {
261     int userDefinedLevel = static_cast<int>(mTable.size()) - 1;
262     while (userDefinedLevel >= 0)
263     {
264         const TSymbol *symbol = mTable[userDefinedLevel]->find(name);
265         if (symbol)
266         {
267             return symbol;
268         }
269         userDefinedLevel--;
270     }
271 
272     return nullptr;
273 }
274 
findUserDefinedFunction(const ImmutableString & name) const275 TFunction *TSymbolTable::findUserDefinedFunction(const ImmutableString &name) const
276 {
277     // User-defined functions are always declared at the global level.
278     ASSERT(!mTable.empty());
279     return static_cast<TFunction *>(mTable[0]->find(name));
280 }
281 
findGlobal(const ImmutableString & name) const282 const TSymbol *TSymbolTable::findGlobal(const ImmutableString &name) const
283 {
284     ASSERT(!mTable.empty());
285     return mTable[0]->find(name);
286 }
287 
findGlobalWithConversion(const std::vector<ImmutableString> & names) const288 const TSymbol *TSymbolTable::findGlobalWithConversion(
289     const std::vector<ImmutableString> &names) const
290 {
291     for (const ImmutableString &name : names)
292     {
293         const TSymbol *target = findGlobal(name);
294         if (target != nullptr)
295             return target;
296     }
297     return nullptr;
298 }
299 
findBuiltInWithConversion(const std::vector<ImmutableString> & names,int shaderVersion) const300 const TSymbol *TSymbolTable::findBuiltInWithConversion(const std::vector<ImmutableString> &names,
301                                                        int shaderVersion) const
302 {
303     for (const ImmutableString &name : names)
304     {
305         const TSymbol *target = findBuiltIn(name, shaderVersion);
306         if (target != nullptr)
307             return target;
308     }
309     return nullptr;
310 }
311 
declare(TSymbol * symbol)312 bool TSymbolTable::declare(TSymbol *symbol)
313 {
314     ASSERT(!mTable.empty());
315     ASSERT(symbol->symbolType() == SymbolType::UserDefined);
316     ASSERT(!symbol->isFunction());
317     return mTable.back()->insert(symbol);
318 }
319 
declareInternal(TSymbol * symbol)320 bool TSymbolTable::declareInternal(TSymbol *symbol)
321 {
322     ASSERT(!mTable.empty());
323     ASSERT(symbol->symbolType() == SymbolType::AngleInternal);
324     ASSERT(!symbol->isFunction());
325     return mTable.back()->insert(symbol);
326 }
327 
declareUserDefinedFunction(TFunction * function,bool insertUnmangledName)328 void TSymbolTable::declareUserDefinedFunction(TFunction *function, bool insertUnmangledName)
329 {
330     ASSERT(!mTable.empty());
331     if (insertUnmangledName)
332     {
333         // Insert the unmangled name to detect potential future redefinition as a variable.
334         mTable[0]->insertUnmangled(function);
335     }
336     mTable[0]->insert(function);
337 }
338 
setDefaultPrecision(TBasicType type,TPrecision prec)339 void TSymbolTable::setDefaultPrecision(TBasicType type, TPrecision prec)
340 {
341     int indexOfLastElement = static_cast<int>(mPrecisionStack.size()) - 1;
342     // Uses map operator [], overwrites the current value
343     (*mPrecisionStack[indexOfLastElement])[type] = prec;
344 }
345 
getDefaultPrecision(TBasicType type) const346 TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const
347 {
348     if (!SupportsPrecision(type))
349         return EbpUndefined;
350 
351     // unsigned integers use the same precision as signed
352     TBasicType baseType = (type == EbtUInt) ? EbtInt : type;
353 
354     int level = static_cast<int>(mPrecisionStack.size()) - 1;
355     ASSERT(level >= 0);  // Just to be safe. Should not happen.
356     // If we dont find anything we return this. Some types don't have predefined default precision.
357     TPrecision prec = EbpUndefined;
358     while (level >= 0)
359     {
360         PrecisionStackLevel::iterator it = mPrecisionStack[level]->find(baseType);
361         if (it != mPrecisionStack[level]->end())
362         {
363             prec = (*it).second;
364             break;
365         }
366         level--;
367     }
368     return prec;
369 }
370 
clearCompilationResults()371 void TSymbolTable::clearCompilationResults()
372 {
373     mGlobalInvariant = false;
374     mUniqueIdCounter = kLastBuiltInId + 1;
375     mVariableMetadata.clear();
376     mGlInVariableWithArraySize = nullptr;
377 
378     // User-defined scopes should have already been cleared when the compilation finished.
379     ASSERT(mTable.empty());
380 }
381 
nextUniqueIdValue()382 int TSymbolTable::nextUniqueIdValue()
383 {
384     ASSERT(mUniqueIdCounter < std::numeric_limits<int>::max());
385     return ++mUniqueIdCounter;
386 }
387 
initializeBuiltIns(sh::GLenum type,ShShaderSpec spec,const ShBuiltInResources & resources)388 void TSymbolTable::initializeBuiltIns(sh::GLenum type,
389                                       ShShaderSpec spec,
390                                       const ShBuiltInResources &resources)
391 {
392     mShaderType = type;
393     mShaderSpec = spec;
394     mResources  = resources;
395 
396     // We need just one precision stack level for predefined precisions.
397     mPrecisionStack.emplace_back(new PrecisionStackLevel);
398 
399     if (IsDesktopGLSpec(spec))
400     {
401         setDefaultPrecision(EbtInt, EbpUndefined);
402         setDefaultPrecision(EbtFloat, EbpUndefined);
403     }
404     else
405     {
406         switch (type)
407         {
408             case GL_FRAGMENT_SHADER:
409                 setDefaultPrecision(EbtInt, EbpMedium);
410                 break;
411             case GL_VERTEX_SHADER:
412             case GL_COMPUTE_SHADER:
413             case GL_GEOMETRY_SHADER_EXT:
414                 setDefaultPrecision(EbtInt, EbpHigh);
415                 setDefaultPrecision(EbtFloat, EbpHigh);
416                 break;
417             default:
418                 UNREACHABLE();
419         }
420     }
421 
422     // Set defaults for sampler types that have default precision, even those that are
423     // only available if an extension exists.
424     // New sampler types in ESSL3 don't have default precision. ESSL1 types do.
425     initSamplerDefaultPrecision(EbtSampler2D);
426     initSamplerDefaultPrecision(EbtSamplerCube);
427     // SamplerExternalOES is specified in the extension to have default precision.
428     initSamplerDefaultPrecision(EbtSamplerExternalOES);
429     // SamplerExternal2DY2YEXT is specified in the extension to have default precision.
430     initSamplerDefaultPrecision(EbtSamplerExternal2DY2YEXT);
431     // It isn't specified whether Sampler2DRect has default precision.
432     initSamplerDefaultPrecision(EbtSampler2DRect);
433 
434     setDefaultPrecision(EbtAtomicCounter, EbpHigh);
435 
436     initializeBuiltInVariables(type, spec, resources);
437     mUniqueIdCounter = kLastBuiltInId + 1;
438 }
439 
initSamplerDefaultPrecision(TBasicType samplerType)440 void TSymbolTable::initSamplerDefaultPrecision(TBasicType samplerType)
441 {
442     ASSERT(samplerType >= EbtGuardSamplerBegin && samplerType <= EbtGuardSamplerEnd);
443     setDefaultPrecision(samplerType, EbpLow);
444 }
445 
VariableMetadata()446 TSymbolTable::VariableMetadata::VariableMetadata()
447     : staticRead(false), staticWrite(false), invariant(false)
448 {}
449 
get(ShShaderSpec shaderSpec,int shaderVersion,sh::GLenum shaderType,const ShBuiltInResources & resources,const TSymbolTableBase & symbolTable) const450 const TSymbol *SymbolRule::get(ShShaderSpec shaderSpec,
451                                int shaderVersion,
452                                sh::GLenum shaderType,
453                                const ShBuiltInResources &resources,
454                                const TSymbolTableBase &symbolTable) const
455 {
456     if (IsDesktopGLSpec(shaderSpec) != (mIsDesktop == 1))
457         return nullptr;
458 
459     if (mVersion == kESSL1Only && shaderVersion != static_cast<int>(kESSL1Only))
460         return nullptr;
461 
462     if (mVersion > shaderVersion)
463         return nullptr;
464 
465     if (!CheckShaderType(static_cast<Shader>(mShaders), shaderType))
466         return nullptr;
467 
468     if (mExtensionIndex != 0 && !CheckExtension(mExtensionIndex, resources))
469         return nullptr;
470 
471     return mIsVar > 0 ? symbolTable.*(mSymbolOrVar.var) : mSymbolOrVar.symbol;
472 }
473 
FindMangledBuiltIn(ShShaderSpec shaderSpec,int shaderVersion,sh::GLenum shaderType,const ShBuiltInResources & resources,const TSymbolTableBase & symbolTable,const SymbolRule * rules,uint16_t startIndex,uint16_t endIndex)474 const TSymbol *FindMangledBuiltIn(ShShaderSpec shaderSpec,
475                                   int shaderVersion,
476                                   sh::GLenum shaderType,
477                                   const ShBuiltInResources &resources,
478                                   const TSymbolTableBase &symbolTable,
479                                   const SymbolRule *rules,
480                                   uint16_t startIndex,
481                                   uint16_t endIndex)
482 {
483     for (uint32_t ruleIndex = startIndex; ruleIndex < endIndex; ++ruleIndex)
484     {
485         const TSymbol *symbol =
486             rules[ruleIndex].get(shaderSpec, shaderVersion, shaderType, resources, symbolTable);
487         if (symbol)
488         {
489             return symbol;
490         }
491     }
492 
493     return nullptr;
494 }
495 
matches(const ImmutableString & name,ShShaderSpec shaderSpec,int shaderVersion,sh::GLenum shaderType,const TExtensionBehavior & extensions) const496 bool UnmangledEntry::matches(const ImmutableString &name,
497                              ShShaderSpec shaderSpec,
498                              int shaderVersion,
499                              sh::GLenum shaderType,
500                              const TExtensionBehavior &extensions) const
501 {
502     if (name != mName)
503         return false;
504 
505     if (!CheckShaderType(static_cast<Shader>(mShaderType), shaderType))
506         return false;
507 
508     if (IsDesktopGLSpec(shaderSpec))
509     {
510         if (mGLSLVersion > shaderVersion)
511             return false;
512 
513         if (static_cast<TExtension>(mGLSLExtension) == TExtension::UNDEFINED)
514             return true;
515 
516         return IsExtensionEnabled(extensions, static_cast<TExtension>(mGLSLExtension));
517     }
518     else
519     {
520         if (mESSLVersion == kESSL1Only && shaderVersion != static_cast<int>(kESSL1Only))
521             return false;
522 
523         if (mESSLVersion > shaderVersion)
524             return false;
525 
526         if (static_cast<TExtension>(mESSLExtension) == TExtension::UNDEFINED)
527             return true;
528 
529         return IsExtensionEnabled(extensions, static_cast<TExtension>(mESSLExtension));
530     }
531 }
532 }  // namespace sh
533