blob: 4bc29a45c63389a06cc4bf82b13efb0a43ca5359 [file] [log] [blame]
//
// Copyright (c) 2002-2013 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 "compiler/translator/ImmutableString.h"
#include "compiler/translator/IntermNode.h"
#include <stdio.h>
#include <algorithm>
namespace sh
{
class TSymbolTable::TSymbolTableLevel
{
public:
TSymbolTableLevel() : mGlobalInvariant(false) {}
bool insert(TSymbol *symbol);
// Insert a function using its unmangled name as the key.
bool insertUnmangled(TFunction *function);
TSymbol *find(const TString &name) const;
void addInvariantVarying(const std::string &name) { mInvariantVaryings.insert(name); }
bool isVaryingInvariant(const std::string &name)
{
return (mGlobalInvariant || mInvariantVaryings.count(name) > 0);
}
void setGlobalInvariant(bool invariant) { mGlobalInvariant = invariant; }
void insertUnmangledBuiltInName(const char *name);
bool hasUnmangledBuiltIn(const char *name) const;
private:
using tLevel = TUnorderedMap<TString, TSymbol *>;
using tLevelPair = const tLevel::value_type;
using tInsertResult = std::pair<tLevel::iterator, bool>;
tLevel level;
std::set<std::string> mInvariantVaryings;
bool mGlobalInvariant;
std::set<ImmutableString> mUnmangledBuiltInNames;
};
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;
}
bool TSymbolTable::TSymbolTableLevel::insertUnmangled(TFunction *function)
{
// returning true means symbol was added to the table
tInsertResult result = level.insert(tLevelPair(function->name(), function));
return result.second;
}
TSymbol *TSymbolTable::TSymbolTableLevel::find(const TString &name) const
{
tLevel::const_iterator it = level.find(name);
if (it == level.end())
return 0;
else
return (*it).second;
}
void TSymbolTable::TSymbolTableLevel::insertUnmangledBuiltInName(const char *name)
{
mUnmangledBuiltInNames.insert(ImmutableString(name));
}
bool TSymbolTable::TSymbolTableLevel::hasUnmangledBuiltIn(const char *name) const
{
return mUnmangledBuiltInNames.count(ImmutableString(name)) > 0;
}
void TSymbolTable::push()
{
table.push_back(new TSymbolTableLevel);
precisionStack.push_back(new PrecisionStackLevel);
}
void TSymbolTable::pop()
{
delete table.back();
table.pop_back();
delete precisionStack.back();
precisionStack.pop_back();
}
const TFunction *TSymbolTable::markUserDefinedFunctionHasPrototypeDeclaration(
const TString &mangledName,
bool *hadPrototypeDeclarationOut)
{
TFunction *function = findUserDefinedFunction(mangledName);
*hadPrototypeDeclarationOut = function->hasPrototypeDeclaration();
function->setHasPrototypeDeclaration();
return function;
}
const TFunction *TSymbolTable::setUserDefinedFunctionParameterNamesFromDefinition(
const TFunction *function,
bool *wasDefinedOut)
{
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)
{
// Swap the parameters of the previous declaration to the parameters of the function
// definition (parameter names may differ).
firstDeclaration->swapParameters(*function);
}
*wasDefinedOut = firstDeclaration->isDefined();
firstDeclaration->setDefined();
return firstDeclaration;
}
const TSymbol *TSymbolTable::find(const TString &name, int shaderVersion) const
{
int level = currentLevel();
TSymbol *symbol = nullptr;
do
{
if (level == GLSL_BUILTINS)
level--;
if (level == ESSL3_1_BUILTINS && shaderVersion != 310)
level--;
if (level == ESSL3_BUILTINS && shaderVersion < 300)
level--;
if (level == ESSL1_BUILTINS && shaderVersion != 100)
level--;
symbol = table[level]->find(name);
level--;
} while (symbol == nullptr && level >= 0);
return symbol;
}
TFunction *TSymbolTable::findUserDefinedFunction(const TString &name) const
{
// User-defined functions are always declared at the global level.
ASSERT(currentLevel() >= GLOBAL_LEVEL);
return static_cast<TFunction *>(table[GLOBAL_LEVEL]->find(name));
}
const TSymbol *TSymbolTable::findGlobal(const TString &name) const
{
ASSERT(table.size() > GLOBAL_LEVEL);
return table[GLOBAL_LEVEL]->find(name);
}
const TSymbol *TSymbolTable::findBuiltIn(const TString &name, int shaderVersion) const
{
return findBuiltIn(name, shaderVersion, false);
}
const TSymbol *TSymbolTable::findBuiltIn(const TString &name,
int shaderVersion,
bool includeGLSLBuiltins) const
{
for (int level = LAST_BUILTIN_LEVEL; level >= 0; level--)
{
if (level == GLSL_BUILTINS && !includeGLSLBuiltins)
level--;
if (level == ESSL3_1_BUILTINS && shaderVersion != 310)
level--;
if (level == ESSL3_BUILTINS && shaderVersion < 300)
level--;
if (level == ESSL1_BUILTINS && shaderVersion != 100)
level--;
TSymbol *symbol = table[level]->find(name);
if (symbol)
return symbol;
}
return nullptr;
}
TSymbolTable::~TSymbolTable()
{
while (table.size() > 0)
pop();
}
constexpr bool IsGenType(const TType *type)
{
if (type)
{
TBasicType basicType = type->getBasicType();
return basicType == EbtGenType || basicType == EbtGenIType || basicType == EbtGenUType ||
basicType == EbtGenBType;
}
return false;
}
constexpr bool IsVecType(const TType *type)
{
if (type)
{
TBasicType basicType = type->getBasicType();
return basicType == EbtVec || basicType == EbtIVec || basicType == EbtUVec ||
basicType == EbtBVec;
}
return false;
}
constexpr const TType *SpecificType(const TType *type, int size)
{
ASSERT(size >= 1 && size <= 4);
if (!type)
{
return nullptr;
}
ASSERT(!IsVecType(type));
switch (type->getBasicType())
{
case EbtGenType:
return StaticType::GetForVec<EbtFloat>(type->getQualifier(),
static_cast<unsigned char>(size));
case EbtGenIType:
return StaticType::GetForVec<EbtInt>(type->getQualifier(),
static_cast<unsigned char>(size));
case EbtGenUType:
return StaticType::GetForVec<EbtUInt>(type->getQualifier(),
static_cast<unsigned char>(size));
case EbtGenBType:
return StaticType::GetForVec<EbtBool>(type->getQualifier(),
static_cast<unsigned char>(size));
default:
return type;
}
}
constexpr const TType *VectorType(const TType *type, int size)
{
ASSERT(size >= 2 && size <= 4);
if (!type)
{
return nullptr;
}
ASSERT(!IsGenType(type));
switch (type->getBasicType())
{
case EbtVec:
return StaticType::GetForVecMat<EbtFloat>(static_cast<unsigned char>(size));
case EbtIVec:
return StaticType::GetForVecMat<EbtInt>(static_cast<unsigned char>(size));
case EbtUVec:
return StaticType::GetForVecMat<EbtUInt>(static_cast<unsigned char>(size));
case EbtBVec:
return StaticType::GetForVecMat<EbtBool>(static_cast<unsigned char>(size));
default:
return type;
}
}
bool TSymbolTable::declareVariable(TVariable *variable)
{
ASSERT(variable->symbolType() == SymbolType::UserDefined);
return insertVariable(currentLevel(), variable);
}
bool TSymbolTable::declareStructType(TStructure *str)
{
return insertStructType(currentLevel(), str);
}
bool TSymbolTable::declareInterfaceBlock(TInterfaceBlock *interfaceBlock)
{
return insert(currentLevel(), interfaceBlock);
}
void TSymbolTable::declareUserDefinedFunction(TFunction *function, bool insertUnmangledName)
{
ASSERT(currentLevel() >= GLOBAL_LEVEL);
if (insertUnmangledName)
{
// Insert the unmangled name to detect potential future redefinition as a variable.
table[GLOBAL_LEVEL]->insertUnmangled(function);
}
table[GLOBAL_LEVEL]->insert(function);
}
TVariable *TSymbolTable::insertVariable(ESymbolLevel level, const char *name, const TType *type)
{
ASSERT(level <= LAST_BUILTIN_LEVEL);
ASSERT(type->isRealized());
return insertVariable(level, NewPoolTString(name), type, SymbolType::BuiltIn);
}
TVariable *TSymbolTable::insertVariable(ESymbolLevel level,
const TString *name,
const TType *type,
SymbolType symbolType)
{
ASSERT(level > LAST_BUILTIN_LEVEL || type->isRealized());
TVariable *var = new TVariable(this, name, type, symbolType);
if (insert(level, var))
{
return var;
}
return nullptr;
}
TVariable *TSymbolTable::insertVariableExt(ESymbolLevel level,
TExtension ext,
const char *name,
const TType *type)
{
ASSERT(level <= LAST_BUILTIN_LEVEL);
ASSERT(type->isRealized());
TVariable *var = new TVariable(this, NewPoolTString(name), type, SymbolType::BuiltIn, ext);
if (insert(level, var))
{
return var;
}
return nullptr;
}
bool TSymbolTable::insertVariable(ESymbolLevel level, TVariable *variable)
{
ASSERT(variable);
ASSERT(level > LAST_BUILTIN_LEVEL || variable->getType().isRealized());
return insert(level, variable);
}
bool TSymbolTable::insert(ESymbolLevel level, TSymbol *symbol)
{
ASSERT(level > LAST_BUILTIN_LEVEL || mUserDefinedUniqueIdsStart == -1);
return table[level]->insert(symbol);
}
bool TSymbolTable::insertStructType(ESymbolLevel level, TStructure *str)
{
ASSERT(str);
return insert(level, str);
}
bool TSymbolTable::insertInterfaceBlock(ESymbolLevel level, TInterfaceBlock *interfaceBlock)
{
ASSERT(interfaceBlock);
return insert(level, interfaceBlock);
}
void TSymbolTable::insertBuiltIn(ESymbolLevel level,
TOperator op,
TExtension ext,
const TType *rvalue,
const char *name,
const TType *ptype1,
const TType *ptype2,
const TType *ptype3,
const TType *ptype4,
const TType *ptype5)
{
if (ptype1->getBasicType() == EbtGSampler2D)
{
insertUnmangledBuiltInName(name, level);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
StaticType::GetBasic<EbtSampler2D>(), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtISampler2D>(), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtUSampler2D>(), ptype2, ptype3, ptype4, ptype5);
}
else if (ptype1->getBasicType() == EbtGSampler3D)
{
insertUnmangledBuiltInName(name, level);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
StaticType::GetBasic<EbtSampler3D>(), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtISampler3D>(), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtUSampler3D>(), ptype2, ptype3, ptype4, ptype5);
}
else if (ptype1->getBasicType() == EbtGSamplerCube)
{
insertUnmangledBuiltInName(name, level);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
StaticType::GetBasic<EbtSamplerCube>(), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtISamplerCube>(), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtUSamplerCube>(), ptype2, ptype3, ptype4, ptype5);
}
else if (ptype1->getBasicType() == EbtGSampler2DArray)
{
insertUnmangledBuiltInName(name, level);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
StaticType::GetBasic<EbtSampler2DArray>(), ptype2, ptype3, ptype4,
ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtISampler2DArray>(), ptype2, ptype3, ptype4,
ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtUSampler2DArray>(), ptype2, ptype3, ptype4,
ptype5);
}
else if (ptype1->getBasicType() == EbtGSampler2DMS)
{
insertUnmangledBuiltInName(name, level);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
StaticType::GetBasic<EbtSampler2DMS>(), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtISampler2DMS>(), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
StaticType::GetBasic<EbtUSampler2DMS>(), ptype2, ptype3, ptype4, ptype5);
}
else if (IsGImage(ptype1->getBasicType()))
{
insertUnmangledBuiltInName(name, level);
const TType *floatType = StaticType::GetBasic<EbtFloat, 4>();
const TType *intType = StaticType::GetBasic<EbtInt, 4>();
const TType *unsignedType = StaticType::GetBasic<EbtUInt, 4>();
const TType *floatImage = StaticType::GetForFloatImage(ptype1->getBasicType());
const TType *intImage = StaticType::GetForIntImage(ptype1->getBasicType());
const TType *unsignedImage = StaticType::GetForUintImage(ptype1->getBasicType());
// GLSL ES 3.10, Revision 4, 8.12 Image Functions
if (rvalue->getBasicType() == EbtGVec4)
{
// imageLoad
insertBuiltIn(level, floatType, name, floatImage, ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, intType, name, intImage, ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, unsignedType, name, unsignedImage, ptype2, ptype3, ptype4, ptype5);
}
else if (rvalue->getBasicType() == EbtVoid)
{
// imageStore
insertBuiltIn(level, rvalue, name, floatImage, ptype2, floatType, ptype4, ptype5);
insertBuiltIn(level, rvalue, name, intImage, ptype2, intType, ptype4, ptype5);
insertBuiltIn(level, rvalue, name, unsignedImage, ptype2, unsignedType, ptype4, ptype5);
}
else
{
// imageSize
insertBuiltIn(level, rvalue, name, floatImage, ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, rvalue, name, intImage, ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, rvalue, name, unsignedImage, ptype2, ptype3, ptype4, ptype5);
}
}
else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3) ||
IsGenType(ptype4))
{
ASSERT(!ptype5);
insertUnmangledBuiltInName(name, level);
insertBuiltIn(level, op, ext, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1),
SpecificType(ptype2, 1), SpecificType(ptype3, 1), SpecificType(ptype4, 1));
insertBuiltIn(level, op, ext, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2),
SpecificType(ptype2, 2), SpecificType(ptype3, 2), SpecificType(ptype4, 2));
insertBuiltIn(level, op, ext, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3),
SpecificType(ptype2, 3), SpecificType(ptype3, 3), SpecificType(ptype4, 3));
insertBuiltIn(level, op, ext, SpecificType(rvalue, 4), name, SpecificType(ptype1, 4),
SpecificType(ptype2, 4), SpecificType(ptype3, 4), SpecificType(ptype4, 4));
}
else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3))
{
ASSERT(!ptype4 && !ptype5);
insertUnmangledBuiltInName(name, level);
insertBuiltIn(level, op, ext, VectorType(rvalue, 2), name, VectorType(ptype1, 2),
VectorType(ptype2, 2), VectorType(ptype3, 2));
insertBuiltIn(level, op, ext, VectorType(rvalue, 3), name, VectorType(ptype1, 3),
VectorType(ptype2, 3), VectorType(ptype3, 3));
insertBuiltIn(level, op, ext, VectorType(rvalue, 4), name, VectorType(ptype1, 4),
VectorType(ptype2, 4), VectorType(ptype3, 4));
}
else
{
TFunction *function =
new TFunction(this, NewPoolTString(name), rvalue, SymbolType::BuiltIn, false, op, ext);
function->addParameter(TConstParameter(ptype1));
if (ptype2)
{
function->addParameter(TConstParameter(ptype2));
}
if (ptype3)
{
function->addParameter(TConstParameter(ptype3));
}
if (ptype4)
{
function->addParameter(TConstParameter(ptype4));
}
if (ptype5)
{
function->addParameter(TConstParameter(ptype5));
}
ASSERT(hasUnmangledBuiltInAtLevel(name, level));
insert(level, function);
}
}
void TSymbolTable::insertBuiltInOp(ESymbolLevel level,
TOperator op,
const TType *rvalue,
const TType *ptype1,
const TType *ptype2,
const TType *ptype3,
const TType *ptype4,
const TType *ptype5)
{
const char *name = GetOperatorString(op);
ASSERT(strlen(name) > 0);
insertUnmangledBuiltInName(name, level);
insertBuiltIn(level, op, TExtension::UNDEFINED, rvalue, name, ptype1, ptype2, ptype3, ptype4,
ptype5);
}
void TSymbolTable::insertBuiltInOp(ESymbolLevel level,
TOperator op,
TExtension ext,
const TType *rvalue,
const TType *ptype1,
const TType *ptype2,
const TType *ptype3,
const TType *ptype4,
const TType *ptype5)
{
const char *name = GetOperatorString(op);
insertUnmangledBuiltInName(name, level);
insertBuiltIn(level, op, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
void TSymbolTable::insertBuiltInFunctionNoParameters(ESymbolLevel level,
TOperator op,
const TType *rvalue,
const char *name)
{
insertUnmangledBuiltInName(name, level);
insert(level,
new TFunction(this, NewPoolTString(name), rvalue, SymbolType::BuiltIn, false, op));
}
void TSymbolTable::insertBuiltInFunctionNoParametersExt(ESymbolLevel level,
TExtension ext,
TOperator op,
const TType *rvalue,
const char *name)
{
insertUnmangledBuiltInName(name, level);
insert(level,
new TFunction(this, NewPoolTString(name), rvalue, SymbolType::BuiltIn, false, op, ext));
}
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>(precisionStack.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 = precisionStack[level]->find(baseType);
if (it != precisionStack[level]->end())
{
prec = (*it).second;
break;
}
level--;
}
return prec;
}
void TSymbolTable::addInvariantVarying(const std::string &originalName)
{
ASSERT(atGlobalLevel());
table[currentLevel()]->addInvariantVarying(originalName);
}
bool TSymbolTable::isVaryingInvariant(const std::string &originalName) const
{
ASSERT(atGlobalLevel());
return table[currentLevel()]->isVaryingInvariant(originalName);
}
void TSymbolTable::setGlobalInvariant(bool invariant)
{
ASSERT(atGlobalLevel());
table[currentLevel()]->setGlobalInvariant(invariant);
}
void TSymbolTable::insertUnmangledBuiltInName(const char *name, ESymbolLevel level)
{
ASSERT(level >= 0 && level < static_cast<ESymbolLevel>(table.size()));
ASSERT(mUserDefinedUniqueIdsStart == -1);
table[level]->insertUnmangledBuiltInName(name);
}
bool TSymbolTable::hasUnmangledBuiltInAtLevel(const char *name, ESymbolLevel level)
{
ASSERT(level >= 0 && level < static_cast<ESymbolLevel>(table.size()));
return table[level]->hasUnmangledBuiltIn(name);
}
bool TSymbolTable::hasUnmangledBuiltInForShaderVersion(const char *name, int shaderVersion)
{
ASSERT(static_cast<ESymbolLevel>(table.size()) > LAST_BUILTIN_LEVEL);
for (int level = LAST_BUILTIN_LEVEL; level >= 0; --level)
{
if (level == ESSL3_1_BUILTINS && shaderVersion != 310)
{
--level;
}
if (level == ESSL3_BUILTINS && shaderVersion < 300)
{
--level;
}
if (level == ESSL1_BUILTINS && shaderVersion != 100)
{
--level;
}
if (table[level]->hasUnmangledBuiltIn(name))
{
return true;
}
}
return false;
}
void TSymbolTable::markBuiltInInitializationFinished()
{
mUserDefinedUniqueIdsStart = mUniqueIdCounter;
}
void TSymbolTable::clearCompilationResults()
{
mUniqueIdCounter = mUserDefinedUniqueIdsStart;
// User-defined scopes should have already been cleared when the compilation finished.
ASSERT(table.size() == LAST_BUILTIN_LEVEL + 1u);
}
int TSymbolTable::nextUniqueIdValue()
{
ASSERT(mUniqueIdCounter < std::numeric_limits<int>::max());
return ++mUniqueIdCounter;
}
} // namespace sh