summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp559
1 files changed, 559 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp b/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp
new file mode 100644
index 0000000000..8424f474f7
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp
@@ -0,0 +1,559 @@
+//
+// Copyright 2002 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Symbol table for parsing. The design principles and most of the functionality are documented in
+// the header file.
+//
+
+#if defined(_MSC_VER)
+# pragma warning(disable : 4718)
+#endif
+
+#include "compiler/translator/SymbolTable.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+namespace
+{
+bool CheckShaderType(Shader expected, GLenum actual)
+{
+ switch (expected)
+ {
+ case Shader::ALL:
+ return true;
+ case Shader::FRAGMENT:
+ return actual == GL_FRAGMENT_SHADER;
+ case Shader::VERTEX:
+ return actual == GL_VERTEX_SHADER;
+ case Shader::COMPUTE:
+ return actual == GL_COMPUTE_SHADER;
+ case Shader::GEOMETRY:
+ return actual == GL_GEOMETRY_SHADER;
+ case Shader::GEOMETRY_EXT:
+ return actual == GL_GEOMETRY_SHADER_EXT;
+ case Shader::TESS_CONTROL_EXT:
+ return actual == GL_TESS_CONTROL_SHADER_EXT;
+ case Shader::TESS_EVALUATION_EXT:
+ return actual == GL_TESS_EVALUATION_SHADER_EXT;
+ case Shader::NOT_COMPUTE:
+ return actual != GL_COMPUTE_SHADER;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+bool CheckExtension(uint32_t extensionIndex, const ShBuiltInResources &resources)
+{
+ const int *resourcePtr = reinterpret_cast<const int *>(&resources);
+ return resourcePtr[extensionIndex] > 0;
+}
+} // namespace
+
+class TSymbolTable::TSymbolTableLevel
+{
+ public:
+ TSymbolTableLevel() = default;
+
+ bool insert(TSymbol *symbol);
+
+ // Insert a function using its unmangled name as the key.
+ void insertUnmangled(TFunction *function);
+
+ TSymbol *find(const ImmutableString &name) const;
+
+ private:
+ using tLevel = TUnorderedMap<ImmutableString,
+ TSymbol *,
+ ImmutableString::FowlerNollVoHash<sizeof(size_t)>>;
+ using tLevelPair = const tLevel::value_type;
+ using tInsertResult = std::pair<tLevel::iterator, bool>;
+
+ tLevel level;
+};
+
+bool TSymbolTable::TSymbolTableLevel::insert(TSymbol *symbol)
+{
+ // returning true means symbol was added to the table
+ tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol));
+ return result.second;
+}
+
+void TSymbolTable::TSymbolTableLevel::insertUnmangled(TFunction *function)
+{
+ level.insert(tLevelPair(function->name(), function));
+}
+
+TSymbol *TSymbolTable::TSymbolTableLevel::find(const ImmutableString &name) const
+{
+ tLevel::const_iterator it = level.find(name);
+ if (it == level.end())
+ return nullptr;
+ else
+ return (*it).second;
+}
+
+TSymbolTable::TSymbolTable()
+ : mGlobalInvariant(false),
+ mUniqueIdCounter(0),
+ mShaderType(GL_FRAGMENT_SHADER),
+ mShaderSpec(SH_GLES2_SPEC),
+ mGlInVariableWithArraySize(nullptr)
+{}
+
+TSymbolTable::~TSymbolTable() = default;
+
+bool TSymbolTable::isEmpty() const
+{
+ return mTable.empty();
+}
+
+bool TSymbolTable::atGlobalLevel() const
+{
+ return mTable.size() == 1u;
+}
+
+void TSymbolTable::push()
+{
+ mTable.emplace_back(new TSymbolTableLevel);
+ mPrecisionStack.emplace_back(new PrecisionStackLevel);
+}
+
+void TSymbolTable::pop()
+{
+ mTable.pop_back();
+ mPrecisionStack.pop_back();
+}
+
+const TFunction *TSymbolTable::markFunctionHasPrototypeDeclaration(
+ const ImmutableString &mangledName,
+ bool *hadPrototypeDeclarationOut) const
+{
+ TFunction *function = findUserDefinedFunction(mangledName);
+ *hadPrototypeDeclarationOut = function->hasPrototypeDeclaration();
+ function->setHasPrototypeDeclaration();
+ return function;
+}
+
+const TFunction *TSymbolTable::setFunctionParameterNamesFromDefinition(const TFunction *function,
+ bool *wasDefinedOut) const
+{
+ TFunction *firstDeclaration = findUserDefinedFunction(function->getMangledName());
+ ASSERT(firstDeclaration);
+ // Note: 'firstDeclaration' could be 'function' if this is the first time we've seen function as
+ // it would have just been put in the symbol table. Otherwise, we're looking up an earlier
+ // occurance.
+ if (function != firstDeclaration)
+ {
+ // The previous declaration should have the same parameters as the function definition
+ // (parameter names may differ).
+ firstDeclaration->shareParameters(*function);
+ }
+
+ *wasDefinedOut = firstDeclaration->isDefined();
+ firstDeclaration->setDefined();
+ return firstDeclaration;
+}
+
+bool TSymbolTable::setGlInArraySize(unsigned int inputArraySize)
+{
+ if (mGlInVariableWithArraySize)
+ {
+ return mGlInVariableWithArraySize->getType().getOutermostArraySize() == inputArraySize;
+ }
+ const TInterfaceBlock *glPerVertex = static_cast<const TInterfaceBlock *>(m_gl_PerVertex);
+ TType *glInType = new TType(glPerVertex, EvqPerVertexIn, TLayoutQualifier::Create());
+ glInType->makeArray(inputArraySize);
+ mGlInVariableWithArraySize =
+ new TVariable(this, ImmutableString("gl_in"), glInType, SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader);
+ return true;
+}
+
+TVariable *TSymbolTable::getGlInVariableWithArraySize() const
+{
+ return mGlInVariableWithArraySize;
+}
+
+const TVariable *TSymbolTable::gl_FragData() const
+{
+ return static_cast<const TVariable *>(m_gl_FragData);
+}
+
+const TVariable *TSymbolTable::gl_SecondaryFragDataEXT() const
+{
+ return static_cast<const TVariable *>(m_gl_SecondaryFragDataEXT);
+}
+
+TSymbolTable::VariableMetadata *TSymbolTable::getOrCreateVariableMetadata(const TVariable &variable)
+{
+ int id = variable.uniqueId().get();
+ auto iter = mVariableMetadata.find(id);
+ if (iter == mVariableMetadata.end())
+ {
+ iter = mVariableMetadata.insert(std::make_pair(id, VariableMetadata())).first;
+ }
+ return &iter->second;
+}
+
+void TSymbolTable::markStaticWrite(const TVariable &variable)
+{
+ auto metadata = getOrCreateVariableMetadata(variable);
+ metadata->staticWrite = true;
+}
+
+void TSymbolTable::markStaticRead(const TVariable &variable)
+{
+ auto metadata = getOrCreateVariableMetadata(variable);
+ metadata->staticRead = true;
+}
+
+bool TSymbolTable::isStaticallyUsed(const TVariable &variable) const
+{
+ ASSERT(!variable.getConstPointer());
+ int id = variable.uniqueId().get();
+ auto iter = mVariableMetadata.find(id);
+ return iter != mVariableMetadata.end() && (iter->second.staticRead || iter->second.staticWrite);
+}
+
+void TSymbolTable::addInvariantVarying(const TVariable &variable)
+{
+ ASSERT(atGlobalLevel());
+ auto metadata = getOrCreateVariableMetadata(variable);
+ metadata->invariant = true;
+}
+
+bool TSymbolTable::isVaryingInvariant(const TVariable &variable) const
+{
+ ASSERT(atGlobalLevel());
+ if (mGlobalInvariant && (IsShaderOutput(variable.getType().getQualifier())))
+ {
+ return true;
+ }
+ int id = variable.uniqueId().get();
+ auto iter = mVariableMetadata.find(id);
+ return iter != mVariableMetadata.end() && iter->second.invariant;
+}
+
+void TSymbolTable::setGlobalInvariant(bool invariant)
+{
+ ASSERT(atGlobalLevel());
+ mGlobalInvariant = invariant;
+}
+
+const TSymbol *TSymbolTable::find(const ImmutableString &name, int shaderVersion) const
+{
+ const TSymbol *userSymbol = findUserDefined(name);
+ if (userSymbol)
+ {
+ return userSymbol;
+ }
+
+ return findBuiltIn(name, shaderVersion);
+}
+
+const TSymbol *TSymbolTable::findUserDefined(const ImmutableString &name) const
+{
+ int userDefinedLevel = static_cast<int>(mTable.size()) - 1;
+ while (userDefinedLevel >= 0)
+ {
+ const TSymbol *symbol = mTable[userDefinedLevel]->find(name);
+ if (symbol)
+ {
+ return symbol;
+ }
+ userDefinedLevel--;
+ }
+
+ return nullptr;
+}
+
+TFunction *TSymbolTable::findUserDefinedFunction(const ImmutableString &name) const
+{
+ // User-defined functions are always declared at the global level.
+ ASSERT(!mTable.empty());
+ return static_cast<TFunction *>(mTable[0]->find(name));
+}
+
+const TSymbol *TSymbolTable::findGlobal(const ImmutableString &name) const
+{
+ ASSERT(!mTable.empty());
+ return mTable[0]->find(name);
+}
+
+const TSymbol *TSymbolTable::findGlobalWithConversion(
+ const std::vector<ImmutableString> &names) const
+{
+ for (const ImmutableString &name : names)
+ {
+ const TSymbol *target = findGlobal(name);
+ if (target != nullptr)
+ return target;
+ }
+ return nullptr;
+}
+
+const TSymbol *TSymbolTable::findBuiltInWithConversion(const std::vector<ImmutableString> &names,
+ int shaderVersion) const
+{
+ for (const ImmutableString &name : names)
+ {
+ const TSymbol *target = findBuiltIn(name, shaderVersion);
+ if (target != nullptr)
+ return target;
+ }
+ return nullptr;
+}
+
+bool TSymbolTable::declare(TSymbol *symbol)
+{
+ ASSERT(!mTable.empty());
+ // The following built-ins may be redeclared by the shader: gl_ClipDistance, gl_CullDistance and
+ // gl_LastFragData.
+ ASSERT(symbol->symbolType() == SymbolType::UserDefined ||
+ (symbol->symbolType() == SymbolType::BuiltIn && IsRedeclarableBuiltIn(symbol->name())));
+ ASSERT(!symbol->isFunction());
+ return mTable.back()->insert(symbol);
+}
+
+bool TSymbolTable::declareInternal(TSymbol *symbol)
+{
+ ASSERT(!mTable.empty());
+ ASSERT(symbol->symbolType() == SymbolType::AngleInternal);
+ ASSERT(!symbol->isFunction());
+ return mTable.back()->insert(symbol);
+}
+
+void TSymbolTable::declareUserDefinedFunction(TFunction *function, bool insertUnmangledName)
+{
+ ASSERT(!mTable.empty());
+ if (insertUnmangledName)
+ {
+ // Insert the unmangled name to detect potential future redefinition as a variable.
+ mTable[0]->insertUnmangled(function);
+ }
+ mTable[0]->insert(function);
+}
+
+void TSymbolTable::setDefaultPrecision(TBasicType type, TPrecision prec)
+{
+ int indexOfLastElement = static_cast<int>(mPrecisionStack.size()) - 1;
+ // Uses map operator [], overwrites the current value
+ (*mPrecisionStack[indexOfLastElement])[type] = prec;
+}
+
+TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const
+{
+ if (!SupportsPrecision(type))
+ return EbpUndefined;
+
+ // unsigned integers use the same precision as signed
+ TBasicType baseType = (type == EbtUInt) ? EbtInt : type;
+
+ int level = static_cast<int>(mPrecisionStack.size()) - 1;
+ ASSERT(level >= 0); // Just to be safe. Should not happen.
+ // If we dont find anything we return this. Some types don't have predefined default precision.
+ TPrecision prec = EbpUndefined;
+ while (level >= 0)
+ {
+ PrecisionStackLevel::iterator it = mPrecisionStack[level]->find(baseType);
+ if (it != mPrecisionStack[level]->end())
+ {
+ prec = (*it).second;
+ break;
+ }
+ level--;
+ }
+ return prec;
+}
+
+void TSymbolTable::clearCompilationResults()
+{
+ mGlobalInvariant = false;
+ mUniqueIdCounter = kLastBuiltInId + 1;
+ mVariableMetadata.clear();
+ mGlInVariableWithArraySize = nullptr;
+
+ // User-defined scopes should have already been cleared when the compilation finished.
+ ASSERT(mTable.empty());
+}
+
+int TSymbolTable::nextUniqueIdValue()
+{
+ ASSERT(mUniqueIdCounter < std::numeric_limits<int>::max());
+ return ++mUniqueIdCounter;
+}
+
+void TSymbolTable::initializeBuiltIns(sh::GLenum type,
+ ShShaderSpec spec,
+ const ShBuiltInResources &resources)
+{
+ mShaderType = type;
+ mShaderSpec = spec;
+ mResources = resources;
+
+ // We need just one precision stack level for predefined precisions.
+ mPrecisionStack.emplace_back(new PrecisionStackLevel);
+
+ if (IsDesktopGLSpec(spec))
+ {
+ setDefaultPrecision(EbtInt, EbpUndefined);
+ setDefaultPrecision(EbtFloat, EbpUndefined);
+ }
+ else
+ {
+ switch (type)
+ {
+ case GL_FRAGMENT_SHADER:
+ setDefaultPrecision(EbtInt, EbpMedium);
+ break;
+ case GL_VERTEX_SHADER:
+ case GL_COMPUTE_SHADER:
+ case GL_GEOMETRY_SHADER_EXT:
+ case GL_TESS_CONTROL_SHADER_EXT:
+ case GL_TESS_EVALUATION_SHADER_EXT:
+ setDefaultPrecision(EbtInt, EbpHigh);
+ setDefaultPrecision(EbtFloat, EbpHigh);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ // Set defaults for sampler types that have default precision, even those that are
+ // only available if an extension exists.
+ // New sampler types in ESSL3 don't have default precision. ESSL1 types do.
+ initSamplerDefaultPrecision(EbtSampler2D);
+ initSamplerDefaultPrecision(EbtSamplerCube);
+ // SamplerExternalOES is specified in the extension to have default precision.
+ initSamplerDefaultPrecision(EbtSamplerExternalOES);
+ // SamplerExternal2DY2YEXT is specified in the extension to have default precision.
+ initSamplerDefaultPrecision(EbtSamplerExternal2DY2YEXT);
+ // It isn't specified whether Sampler2DRect has default precision.
+ initSamplerDefaultPrecision(EbtSampler2DRect);
+
+ if (spec < SH_GLES3_SPEC)
+ {
+ // Only set the default precision of shadow samplers in ESLL1. They become core in ESSL3
+ // where they do not have a defalut precision.
+ initSamplerDefaultPrecision(EbtSampler2DShadow);
+ }
+
+ setDefaultPrecision(EbtAtomicCounter, EbpHigh);
+
+ initializeBuiltInVariables(type, spec, resources);
+ mUniqueIdCounter = kLastBuiltInId + 1;
+}
+
+void TSymbolTable::initSamplerDefaultPrecision(TBasicType samplerType)
+{
+ ASSERT(samplerType >= EbtGuardSamplerBegin && samplerType <= EbtGuardSamplerEnd);
+ setDefaultPrecision(samplerType, EbpLow);
+}
+
+TSymbolTable::VariableMetadata::VariableMetadata()
+ : staticRead(false), staticWrite(false), invariant(false)
+{}
+
+const TSymbol *SymbolRule::get(ShShaderSpec shaderSpec,
+ int shaderVersion,
+ sh::GLenum shaderType,
+ const ShBuiltInResources &resources,
+ const TSymbolTableBase &symbolTable) const
+{
+ if (IsDesktopGLSpec(shaderSpec) != (mIsDesktop == 1))
+ return nullptr;
+
+ if (mVersion == kESSL1Only && shaderVersion != static_cast<int>(kESSL1Only))
+ return nullptr;
+
+ if (mVersion > shaderVersion)
+ return nullptr;
+
+ if (!CheckShaderType(static_cast<Shader>(mShaders), shaderType))
+ return nullptr;
+
+ if (mExtensionIndex != 0 && !CheckExtension(mExtensionIndex, resources))
+ return nullptr;
+
+ return mIsVar > 0 ? symbolTable.*(mSymbolOrVar.var) : mSymbolOrVar.symbol;
+}
+
+const TSymbol *FindMangledBuiltIn(ShShaderSpec shaderSpec,
+ int shaderVersion,
+ sh::GLenum shaderType,
+ const ShBuiltInResources &resources,
+ const TSymbolTableBase &symbolTable,
+ const SymbolRule *rules,
+ uint16_t startIndex,
+ uint16_t endIndex)
+{
+ for (uint32_t ruleIndex = startIndex; ruleIndex < endIndex; ++ruleIndex)
+ {
+ const TSymbol *symbol =
+ rules[ruleIndex].get(shaderSpec, shaderVersion, shaderType, resources, symbolTable);
+ if (symbol)
+ {
+ return symbol;
+ }
+ }
+
+ return nullptr;
+}
+
+bool UnmangledEntry::matches(const ImmutableString &name,
+ ShShaderSpec shaderSpec,
+ int shaderVersion,
+ sh::GLenum shaderType,
+ const TExtensionBehavior &extensions) const
+{
+ if (name != mName)
+ return false;
+
+ if (!CheckShaderType(static_cast<Shader>(mShaderType), shaderType))
+ return false;
+
+ if (IsDesktopGLSpec(shaderSpec))
+ {
+ if (mGLSLVersion > shaderVersion)
+ return false;
+
+ if (mGLSLExtension == TExtension::UNDEFINED)
+ return true;
+
+ return IsExtensionEnabled(extensions, mGLSLExtension);
+ }
+ else
+ {
+ if (mESSLVersion == kESSL1Only && shaderVersion != static_cast<int>(kESSL1Only))
+ return false;
+
+ if (mESSLVersion > shaderVersion)
+ return false;
+
+ bool anyExtension = false;
+ bool anyExtensionEnabled = false;
+ for (TExtension ext : mESSLExtensions)
+ {
+ if (ext != TExtension::UNDEFINED)
+ {
+ anyExtension = true;
+ anyExtensionEnabled = anyExtensionEnabled || IsExtensionEnabled(extensions, ext);
+ }
+ }
+
+ if (!anyExtension)
+ return true;
+
+ return anyExtensionEnabled;
+ }
+}
+} // namespace sh