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