// // Copyright 2017 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.cpp: Symbols representing variables, functions, structures and interface blocks. // #if defined(_MSC_VER) # pragma warning(disable : 4718) #endif #include "compiler/translator/Symbol.h" #include "compiler/translator/ImmutableStringBuilder.h" #include "compiler/translator/SymbolTable.h" namespace sh { namespace { constexpr const ImmutableString kMainName("main"); constexpr const ImmutableString kImageLoadName("imageLoad"); constexpr const ImmutableString kImageStoreName("imageStore"); constexpr const ImmutableString kImageSizeName("imageSize"); constexpr const ImmutableString kAtomicCounterName("atomicCounter"); static const char kFunctionMangledNameSeparator = '('; } // anonymous namespace TSymbol::TSymbol(TSymbolTable *symbolTable, const ImmutableString &name, SymbolType symbolType, SymbolClass symbolClass, TExtension extension) : mName(name), mUniqueId(symbolTable->nextUniqueId()), mSymbolType(symbolType), mExtension(extension), mSymbolClass(symbolClass) { ASSERT(mSymbolType == SymbolType::BuiltIn || mExtension == TExtension::UNDEFINED); ASSERT(mName != "" || mSymbolType == SymbolType::AngleInternal || mSymbolType == SymbolType::Empty); } ImmutableString TSymbol::name() const { if (!mName.empty()) { return mName; } // This can be called for nameless function parameters in HLSL. ASSERT(mSymbolType == SymbolType::AngleInternal || (mSymbolType == SymbolType::Empty && isVariable())); int uniqueId = mUniqueId.get(); ImmutableStringBuilder symbolNameOut(sizeof(uniqueId) * 2u + 1u); symbolNameOut << 's'; symbolNameOut.appendHex(mUniqueId.get()); return symbolNameOut; } ImmutableString TSymbol::getMangledName() const { if (mSymbolClass == SymbolClass::Function) { // We do this instead of using proper virtual functions so that we can better support // constexpr symbols. return static_cast(this)->getFunctionMangledName(); } ASSERT(mSymbolType != SymbolType::Empty); return name(); } TVariable::TVariable(TSymbolTable *symbolTable, const ImmutableString &name, const TType *type, SymbolType symbolType, TExtension extension) : TSymbol(symbolTable, name, symbolType, SymbolClass::Variable, extension), mType(type), unionArray(nullptr) { ASSERT(mType); ASSERT(name.empty() || symbolType != SymbolType::Empty); } TStructure::TStructure(TSymbolTable *symbolTable, const ImmutableString &name, const TFieldList *fields, SymbolType symbolType) : TSymbol(symbolTable, name, symbolType, SymbolClass::Struct), TFieldListCollection(fields) {} TStructure::TStructure(const TSymbolUniqueId &id, const ImmutableString &name, TExtension extension, const TFieldList *fields) : TSymbol(id, name, SymbolType::BuiltIn, extension, SymbolClass::Struct), TFieldListCollection(fields) {} void TStructure::createSamplerSymbols(const char *namePrefix, const TString &apiNamePrefix, TVector *outputSymbols, TMap *outputSymbolsToAPINames, TSymbolTable *symbolTable) const { ASSERT(containsSamplers()); for (const auto *field : *mFields) { const TType *fieldType = field->type(); if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers()) { std::stringstream fieldName = sh::InitializeStream(); fieldName << namePrefix << "_" << field->name(); TString fieldApiName = apiNamePrefix + "."; fieldApiName += field->name().data(); fieldType->createSamplerSymbols(ImmutableString(fieldName.str()), fieldApiName, outputSymbols, outputSymbolsToAPINames, symbolTable); } } } void TStructure::setName(const ImmutableString &name) { ImmutableString *mutableName = const_cast(&mName); *mutableName = name; } TInterfaceBlock::TInterfaceBlock(TSymbolTable *symbolTable, const ImmutableString &name, const TFieldList *fields, const TLayoutQualifier &layoutQualifier, SymbolType symbolType, TExtension extension) : TSymbol(symbolTable, name, symbolType, SymbolClass::InterfaceBlock, extension), TFieldListCollection(fields), mBlockStorage(layoutQualifier.blockStorage), mBinding(layoutQualifier.binding) { ASSERT(name != nullptr); } TInterfaceBlock::TInterfaceBlock(const TSymbolUniqueId &id, const ImmutableString &name, TExtension extension, const TFieldList *fields) : TSymbol(id, name, SymbolType::BuiltIn, extension, SymbolClass::InterfaceBlock), TFieldListCollection(fields), mBlockStorage(EbsUnspecified), mBinding(0) {} TFunction::TFunction(TSymbolTable *symbolTable, const ImmutableString &name, SymbolType symbolType, const TType *retType, bool knownToNotHaveSideEffects) : TSymbol(symbolTable, name, symbolType, SymbolClass::Function, TExtension::UNDEFINED), mParametersVector(new TParamVector()), mParameters(nullptr), mParamCount(0u), returnType(retType), mMangledName(""), mOp(EOpNull), defined(false), mHasPrototypeDeclaration(false), mKnownToNotHaveSideEffects(knownToNotHaveSideEffects) { // Functions with an empty name are not allowed. ASSERT(symbolType != SymbolType::Empty); ASSERT(name != nullptr || symbolType == SymbolType::AngleInternal); } void TFunction::addParameter(const TVariable *p) { ASSERT(mParametersVector); mParametersVector->push_back(p); mParameters = mParametersVector->data(); mParamCount = mParametersVector->size(); mMangledName = kEmptyImmutableString; } void TFunction::shareParameters(const TFunction ¶metersSource) { mParametersVector = nullptr; mParameters = parametersSource.mParameters; mParamCount = parametersSource.mParamCount; ASSERT(parametersSource.name() == name()); mMangledName = parametersSource.mMangledName; } ImmutableString TFunction::buildMangledName() const { std::string newName(name().data(), name().length()); newName += kFunctionMangledNameSeparator; for (size_t i = 0u; i < mParamCount; ++i) { newName += mParameters[i]->getType().getMangledName(); } return ImmutableString(newName); } bool TFunction::isMain() const { return symbolType() == SymbolType::UserDefined && name() == kMainName; } bool TFunction::isImageFunction() const { return symbolType() == SymbolType::BuiltIn && (name() == kImageSizeName || name() == kImageLoadName || name() == kImageStoreName); } bool TFunction::isAtomicCounterFunction() const { return SymbolType() == SymbolType::BuiltIn && name().beginsWith(kAtomicCounterName); } bool TFunction::hasSamplerInStructOrArrayParams() const { for (size_t paramIndex = 0; paramIndex < mParamCount; ++paramIndex) { const TVariable *param = getParam(paramIndex); if (param->getType().isStructureContainingSamplers() || (param->getType().isArray() && param->getType().isSampler())) { return true; } } return false; } bool TFunction::hasSamplerInStructOrArrayOfArrayParams() const { for (size_t paramIndex = 0; paramIndex < mParamCount; ++paramIndex) { const TVariable *param = getParam(paramIndex); if (param->getType().isStructureContainingSamplers() || (param->getType().isArrayOfArrays() && param->getType().isSampler())) { return true; } } return false; } } // namespace sh