// // 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.h: Symbols representing variables, functions, structures and interface blocks. // #ifndef COMPILER_TRANSLATOR_SYMBOL_H_ #define COMPILER_TRANSLATOR_SYMBOL_H_ #include "common/angleutils.h" #include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/ImmutableString.h" #include "compiler/translator/IntermNode.h" #include "compiler/translator/SymbolUniqueId.h" namespace sh { class TSymbolTable; // Symbol base class. (Can build functions or variables out of these...) class TSymbol : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE TSymbol(TSymbolTable *symbolTable, const ImmutableString &name, SymbolType symbolType, SymbolClass symbolClass, TExtension extension = TExtension::UNDEFINED); TSymbol(TSymbolTable *symbolTable, const ImmutableString &name, SymbolType symbolType, SymbolClass symbolClass, const std::array &extensions); // Note that we can't have a virtual destructor in order to support constexpr symbols. Data is // either statically allocated or pool allocated. ~TSymbol() = default; // Calling name() for empty symbols (symbolType == SymbolType::Empty) generates a similar name // as for internal variables. ImmutableString name() const; // Don't call getMangledName() for empty symbols (symbolType == SymbolType::Empty). ImmutableString getMangledName() const; bool isFunction() const { return mSymbolClass == SymbolClass::Function; } bool isVariable() const { return mSymbolClass == SymbolClass::Variable; } bool isStruct() const { return mSymbolClass == SymbolClass::Struct; } bool isInterfaceBlock() const { return mSymbolClass == SymbolClass::InterfaceBlock; } const TSymbolUniqueId &uniqueId() const { return mUniqueId; } SymbolType symbolType() const { return mSymbolType; } const std::array extensions() const { return mExtensions; } template constexpr const std::array CreateExtensionList( const std::array &extensions) { switch (extensions.size()) { case 1: return std::array{ {extensions[0], TExtension::UNDEFINED, TExtension::UNDEFINED}}; case 2: return std::array{ {extensions[0], extensions[1], TExtension::UNDEFINED}}; case 3: return std::array{{extensions[0], extensions[1], extensions[2]}}; default: UNREACHABLE(); return std::array{ {TExtension::UNDEFINED, TExtension::UNDEFINED, TExtension::UNDEFINED}}; } } protected: template constexpr TSymbol(const TSymbolUniqueId &id, const ImmutableString &name, SymbolType symbolType, const std::array &extensions, SymbolClass symbolClass) : mName(name), mUniqueId(id), mExtensions(CreateExtensionList(extensions)), mSymbolType(symbolType), mSymbolClass(symbolClass) {} const ImmutableString mName; private: const TSymbolUniqueId mUniqueId; const std::array mExtensions; const SymbolType mSymbolType : 4; // We use this instead of having virtual functions for querying the class in order to support // constexpr symbols. const SymbolClass mSymbolClass : 4; }; static_assert(sizeof(TSymbol) <= 24, "Size check failed"); // Variable. // May store the value of a constant variable of any type (float, int, bool or struct). class TVariable : public TSymbol { public: TVariable(TSymbolTable *symbolTable, const ImmutableString &name, const TType *type, SymbolType symbolType, TExtension ext = TExtension::UNDEFINED); TVariable(TSymbolTable *symbolTable, const ImmutableString &name, const TType *type, SymbolType symbolType, const std::array &extensions); const TType &getType() const { return *mType; } const TConstantUnion *getConstPointer() const { return unionArray; } void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; } // Note: only to be used for built-in variables with autogenerated ids! constexpr TVariable(const TSymbolUniqueId &id, const ImmutableString &name, SymbolType symbolType, TExtension extension, const TType *type) : TSymbol(id, name, symbolType, std::array{{extension}}, SymbolClass::Variable), mType(type), unionArray(nullptr) {} template constexpr TVariable(const TSymbolUniqueId &id, const ImmutableString &name, SymbolType symbolType, const std::array &extensions, const TType *type) : TSymbol(id, name, symbolType, extensions, SymbolClass::Variable), mType(type), unionArray(nullptr) {} private: const TType *mType; const TConstantUnion *unionArray; }; // Struct type. class TStructure : public TSymbol, public TFieldListCollection { public: TStructure(TSymbolTable *symbolTable, const ImmutableString &name, const TFieldList *fields, SymbolType symbolType); // The char arrays passed in must be pool allocated or static. void createSamplerSymbols(const char *namePrefix, const TString &apiNamePrefix, TVector *outputSymbols, TMap *outputSymbolsToAPINames, TSymbolTable *symbolTable) const; void setAtGlobalScope(bool atGlobalScope) { mAtGlobalScope = atGlobalScope; } bool atGlobalScope() const { return mAtGlobalScope; } private: friend class TSymbolTable; // For creating built-in structs. TStructure(const TSymbolUniqueId &id, const ImmutableString &name, TExtension extension, const TFieldList *fields) : TSymbol(id, name, SymbolType::BuiltIn, std::array{{extension}}, SymbolClass::Struct), TFieldListCollection(fields) {} template TStructure(const TSymbolUniqueId &id, const ImmutableString &name, const std::array &extensions, const TFieldList *fields) : TSymbol(id, name, SymbolType::BuiltIn, extensions, SymbolClass::Struct), TFieldListCollection(fields) {} // TODO(zmo): Find a way to get rid of the const_cast in function // setName(). At the moment keep this function private so only // friend class RegenerateStructNames may call it. friend class RegenerateStructNamesTraverser; void setName(const ImmutableString &name); bool mAtGlobalScope; }; // Interface block. Note that this contains the block name, not the instance name. Interface block // instances are stored as TVariable. class TInterfaceBlock : public TSymbol, public TFieldListCollection { public: TInterfaceBlock(TSymbolTable *symbolTable, const ImmutableString &name, const TFieldList *fields, const TLayoutQualifier &layoutQualifier, SymbolType symbolType, TExtension extension = TExtension::UNDEFINED); TInterfaceBlock(TSymbolTable *symbolTable, const ImmutableString &name, const TFieldList *fields, const TLayoutQualifier &layoutQualifier, SymbolType symbolType, const std::array &extensions); TLayoutBlockStorage blockStorage() const { return mBlockStorage; } int blockBinding() const { return mBinding; } private: friend class TSymbolTable; // For creating built-in interface blocks. TInterfaceBlock(const TSymbolUniqueId &id, const ImmutableString &name, TExtension extension, const TFieldList *fields) : TSymbol(id, name, SymbolType::BuiltIn, std::array{{extension}}, SymbolClass::InterfaceBlock), TFieldListCollection(fields), mBlockStorage(EbsUnspecified), mBinding(0) {} template TInterfaceBlock(const TSymbolUniqueId &id, const ImmutableString &name, const std::array &extensions, const TFieldList *fields) : TSymbol(id, name, SymbolType::BuiltIn, extensions, SymbolClass::InterfaceBlock), TFieldListCollection(fields), mBlockStorage(EbsUnspecified), mBinding(0) {} TLayoutBlockStorage mBlockStorage; int mBinding; // Note that we only record matrix packing on a per-field granularity. }; // Parameter class used for parsing user-defined function parameters. struct TParameter { // Destructively converts to TVariable. // This method resets name and type to nullptrs to make sure // their content cannot be modified after the call. const TVariable *createVariable(TSymbolTable *symbolTable) { const ImmutableString constName(name); const TType *constType = type; name = nullptr; type = nullptr; return new TVariable(symbolTable, constName, constType, constName.empty() ? SymbolType::Empty : SymbolType::UserDefined); } const char *name; // either pool allocated or static. TType *type; }; // The function sub-class of a symbol. class TFunction : public TSymbol { public: // User-defined function TFunction(TSymbolTable *symbolTable, const ImmutableString &name, SymbolType symbolType, const TType *retType, bool knownToNotHaveSideEffects); void addParameter(const TVariable *p); void shareParameters(const TFunction ¶metersSource); ImmutableString getFunctionMangledName() const { ASSERT(symbolType() != SymbolType::BuiltIn); if (mMangledName.empty()) { mMangledName = buildMangledName(); } return mMangledName; } const TType &getReturnType() const { return *returnType; } TOperator getBuiltInOp() const { return mOp; } void setDefined() { defined = true; } bool isDefined() const { return defined; } void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; } bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; } void setHasVoidParameter() { mHasVoidParameter = true; } bool hasVoidParameter() const { return mHasVoidParameter; } size_t getParamCount() const { return mParamCount; } const TVariable *getParam(size_t i) const { return mParameters[i]; } bool isKnownToNotHaveSideEffects() const { return mKnownToNotHaveSideEffects; } bool isMain() const; bool isImageFunction() const; bool isAtomicCounterFunction() const; // Note: Only to be used for static built-in functions! constexpr TFunction(const TSymbolUniqueId &id, const ImmutableString &name, TExtension extension, const TVariable *const *parameters, size_t paramCount, const TType *retType, TOperator op, bool knownToNotHaveSideEffects) : TSymbol(id, name, SymbolType::BuiltIn, std::array{{extension}}, SymbolClass::Function), mParametersVector(nullptr), mParameters(parameters), returnType(retType), mMangledName(nullptr), mParamCount(paramCount), mOp(op), defined(false), mHasPrototypeDeclaration(false), mKnownToNotHaveSideEffects(knownToNotHaveSideEffects), mHasVoidParameter(false) {} template constexpr TFunction(const TSymbolUniqueId &id, const ImmutableString &name, const std::array &extensions, const TVariable *const *parameters, size_t paramCount, const TType *retType, TOperator op, bool knownToNotHaveSideEffects) : TSymbol(id, name, SymbolType::BuiltIn, extensions, SymbolClass::Function), mParametersVector(nullptr), mParameters(parameters), returnType(retType), mMangledName(nullptr), mParamCount(paramCount), mOp(op), defined(false), mHasPrototypeDeclaration(false), mKnownToNotHaveSideEffects(knownToNotHaveSideEffects), mHasVoidParameter(false) {} private: ImmutableString buildMangledName() const; typedef TVector TParamVector; TParamVector *mParametersVector; const TVariable *const *mParameters; const TType *const returnType; mutable ImmutableString mMangledName; size_t mParamCount : 32; const TOperator mOp; // Only set for built-ins bool defined : 1; bool mHasPrototypeDeclaration : 1; bool mKnownToNotHaveSideEffects : 1; // Whether the parameter list of the function starts with void. This is used to generate an // error if any other parameter follows. bool mHasVoidParameter : 1; }; } // namespace sh #endif // COMPILER_TRANSLATOR_SYMBOL_H_