1 // 2 // Copyright 2017 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.h: Symbols representing variables, functions, structures and interface blocks. 7 // 8 9 #ifndef COMPILER_TRANSLATOR_SYMBOL_H_ 10 #define COMPILER_TRANSLATOR_SYMBOL_H_ 11 12 #include "common/angleutils.h" 13 #include "compiler/translator/ExtensionBehavior.h" 14 #include "compiler/translator/ImmutableString.h" 15 #include "compiler/translator/IntermNode.h" 16 #include "compiler/translator/SymbolUniqueId.h" 17 18 namespace sh 19 { 20 21 class TSymbolTable; 22 23 // Symbol base class. (Can build functions or variables out of these...) 24 class TSymbol : angle::NonCopyable 25 { 26 public: 27 POOL_ALLOCATOR_NEW_DELETE 28 TSymbol(TSymbolTable *symbolTable, 29 const ImmutableString &name, 30 SymbolType symbolType, 31 SymbolClass symbolClass, 32 TExtension extension = TExtension::UNDEFINED); 33 34 TSymbol(TSymbolTable *symbolTable, 35 const ImmutableString &name, 36 SymbolType symbolType, 37 SymbolClass symbolClass, 38 const std::array<TExtension, 3u> &extensions); 39 40 // Note that we can't have a virtual destructor in order to support constexpr symbols. Data is 41 // either statically allocated or pool allocated. 42 ~TSymbol() = default; 43 44 // Calling name() for empty symbols (symbolType == SymbolType::Empty) generates a similar name 45 // as for internal variables. 46 ImmutableString name() const; 47 // Don't call getMangledName() for empty symbols (symbolType == SymbolType::Empty). 48 ImmutableString getMangledName() const; 49 isFunction()50 bool isFunction() const { return mSymbolClass == SymbolClass::Function; } isVariable()51 bool isVariable() const { return mSymbolClass == SymbolClass::Variable; } isStruct()52 bool isStruct() const { return mSymbolClass == SymbolClass::Struct; } isInterfaceBlock()53 bool isInterfaceBlock() const { return mSymbolClass == SymbolClass::InterfaceBlock; } 54 uniqueId()55 const TSymbolUniqueId &uniqueId() const { return mUniqueId; } symbolType()56 SymbolType symbolType() const { return mSymbolType; } extensions()57 const std::array<TExtension, 3u> extensions() const { return mExtensions; } 58 59 template <size_t ExtensionCount> CreateExtensionList(const std::array<TExtension,ExtensionCount> & extensions)60 constexpr const std::array<TExtension, 3u> CreateExtensionList( 61 const std::array<TExtension, ExtensionCount> &extensions) 62 { 63 switch (extensions.size()) 64 { 65 case 1: 66 return std::array<TExtension, 3u>{ 67 {extensions[0], TExtension::UNDEFINED, TExtension::UNDEFINED}}; 68 case 2: 69 return std::array<TExtension, 3u>{ 70 {extensions[0], extensions[1], TExtension::UNDEFINED}}; 71 case 3: 72 return std::array<TExtension, 3u>{{extensions[0], extensions[1], extensions[2]}}; 73 default: 74 UNREACHABLE(); 75 return std::array<TExtension, 3u>{ 76 {TExtension::UNDEFINED, TExtension::UNDEFINED, TExtension::UNDEFINED}}; 77 } 78 } 79 80 protected: 81 template <size_t ExtensionCount> TSymbol(const TSymbolUniqueId & id,const ImmutableString & name,SymbolType symbolType,const std::array<TExtension,ExtensionCount> & extensions,SymbolClass symbolClass)82 constexpr TSymbol(const TSymbolUniqueId &id, 83 const ImmutableString &name, 84 SymbolType symbolType, 85 const std::array<TExtension, ExtensionCount> &extensions, 86 SymbolClass symbolClass) 87 : mName(name), 88 mUniqueId(id), 89 mExtensions(CreateExtensionList(extensions)), 90 mSymbolType(symbolType), 91 mSymbolClass(symbolClass) 92 {} 93 94 const ImmutableString mName; 95 96 private: 97 const TSymbolUniqueId mUniqueId; 98 const std::array<TExtension, 3u> mExtensions; 99 const SymbolType mSymbolType : 4; 100 101 // We use this instead of having virtual functions for querying the class in order to support 102 // constexpr symbols. 103 const SymbolClass mSymbolClass : 4; 104 }; 105 106 static_assert(sizeof(TSymbol) <= 24, "Size check failed"); 107 108 // Variable. 109 // May store the value of a constant variable of any type (float, int, bool or struct). 110 class TVariable : public TSymbol 111 { 112 public: 113 TVariable(TSymbolTable *symbolTable, 114 const ImmutableString &name, 115 const TType *type, 116 SymbolType symbolType, 117 TExtension ext = TExtension::UNDEFINED); 118 119 TVariable(TSymbolTable *symbolTable, 120 const ImmutableString &name, 121 const TType *type, 122 SymbolType symbolType, 123 const std::array<TExtension, 3u> &extensions); 124 getType()125 const TType &getType() const { return *mType; } 126 getConstPointer()127 const TConstantUnion *getConstPointer() const { return unionArray; } 128 shareConstPointer(const TConstantUnion * constArray)129 void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; } 130 131 // Note: only to be used for built-in variables with autogenerated ids! TVariable(const TSymbolUniqueId & id,const ImmutableString & name,SymbolType symbolType,TExtension extension,const TType * type)132 constexpr TVariable(const TSymbolUniqueId &id, 133 const ImmutableString &name, 134 SymbolType symbolType, 135 TExtension extension, 136 const TType *type) 137 : TSymbol(id, 138 name, 139 symbolType, 140 std::array<TExtension, 1u>{{extension}}, 141 SymbolClass::Variable), 142 mType(type), 143 unionArray(nullptr) 144 {} 145 146 template <size_t ExtensionCount> TVariable(const TSymbolUniqueId & id,const ImmutableString & name,SymbolType symbolType,const std::array<TExtension,ExtensionCount> & extensions,const TType * type)147 constexpr TVariable(const TSymbolUniqueId &id, 148 const ImmutableString &name, 149 SymbolType symbolType, 150 const std::array<TExtension, ExtensionCount> &extensions, 151 const TType *type) 152 : TSymbol(id, name, symbolType, extensions, SymbolClass::Variable), 153 mType(type), 154 unionArray(nullptr) 155 {} 156 157 private: 158 const TType *mType; 159 const TConstantUnion *unionArray; 160 }; 161 162 // Struct type. 163 class TStructure : public TSymbol, public TFieldListCollection 164 { 165 public: 166 TStructure(TSymbolTable *symbolTable, 167 const ImmutableString &name, 168 const TFieldList *fields, 169 SymbolType symbolType); 170 171 // The char arrays passed in must be pool allocated or static. 172 void createSamplerSymbols(const char *namePrefix, 173 const TString &apiNamePrefix, 174 TVector<const TVariable *> *outputSymbols, 175 TMap<const TVariable *, TString> *outputSymbolsToAPINames, 176 TSymbolTable *symbolTable) const; 177 setAtGlobalScope(bool atGlobalScope)178 void setAtGlobalScope(bool atGlobalScope) { mAtGlobalScope = atGlobalScope; } atGlobalScope()179 bool atGlobalScope() const { return mAtGlobalScope; } 180 181 private: 182 friend class TSymbolTable; 183 // For creating built-in structs. TStructure(const TSymbolUniqueId & id,const ImmutableString & name,TExtension extension,const TFieldList * fields)184 TStructure(const TSymbolUniqueId &id, 185 const ImmutableString &name, 186 TExtension extension, 187 const TFieldList *fields) 188 : TSymbol(id, 189 name, 190 SymbolType::BuiltIn, 191 std::array<TExtension, 1u>{{extension}}, 192 SymbolClass::Struct), 193 TFieldListCollection(fields) 194 {} 195 196 template <size_t ExtensionCount> TStructure(const TSymbolUniqueId & id,const ImmutableString & name,const std::array<TExtension,ExtensionCount> & extensions,const TFieldList * fields)197 TStructure(const TSymbolUniqueId &id, 198 const ImmutableString &name, 199 const std::array<TExtension, ExtensionCount> &extensions, 200 const TFieldList *fields) 201 : TSymbol(id, name, SymbolType::BuiltIn, extensions, SymbolClass::Struct), 202 TFieldListCollection(fields) 203 {} 204 205 // TODO(zmo): Find a way to get rid of the const_cast in function 206 // setName(). At the moment keep this function private so only 207 // friend class RegenerateStructNames may call it. 208 friend class RegenerateStructNamesTraverser; 209 void setName(const ImmutableString &name); 210 211 bool mAtGlobalScope; 212 }; 213 214 // Interface block. Note that this contains the block name, not the instance name. Interface block 215 // instances are stored as TVariable. 216 class TInterfaceBlock : public TSymbol, public TFieldListCollection 217 { 218 public: 219 TInterfaceBlock(TSymbolTable *symbolTable, 220 const ImmutableString &name, 221 const TFieldList *fields, 222 const TLayoutQualifier &layoutQualifier, 223 SymbolType symbolType, 224 TExtension extension = TExtension::UNDEFINED); 225 226 TInterfaceBlock(TSymbolTable *symbolTable, 227 const ImmutableString &name, 228 const TFieldList *fields, 229 const TLayoutQualifier &layoutQualifier, 230 SymbolType symbolType, 231 const std::array<TExtension, 3u> &extensions); 232 blockStorage()233 TLayoutBlockStorage blockStorage() const { return mBlockStorage; } blockBinding()234 int blockBinding() const { return mBinding; } 235 236 private: 237 friend class TSymbolTable; 238 // For creating built-in interface blocks. TInterfaceBlock(const TSymbolUniqueId & id,const ImmutableString & name,TExtension extension,const TFieldList * fields)239 TInterfaceBlock(const TSymbolUniqueId &id, 240 const ImmutableString &name, 241 TExtension extension, 242 const TFieldList *fields) 243 : TSymbol(id, 244 name, 245 SymbolType::BuiltIn, 246 std::array<TExtension, 1u>{{extension}}, 247 SymbolClass::InterfaceBlock), 248 TFieldListCollection(fields), 249 mBlockStorage(EbsUnspecified), 250 mBinding(0) 251 {} 252 253 template <size_t ExtensionCount> TInterfaceBlock(const TSymbolUniqueId & id,const ImmutableString & name,const std::array<TExtension,ExtensionCount> & extensions,const TFieldList * fields)254 TInterfaceBlock(const TSymbolUniqueId &id, 255 const ImmutableString &name, 256 const std::array<TExtension, ExtensionCount> &extensions, 257 const TFieldList *fields) 258 : TSymbol(id, name, SymbolType::BuiltIn, extensions, SymbolClass::InterfaceBlock), 259 TFieldListCollection(fields), 260 mBlockStorage(EbsUnspecified), 261 mBinding(0) 262 {} 263 264 TLayoutBlockStorage mBlockStorage; 265 int mBinding; 266 267 // Note that we only record matrix packing on a per-field granularity. 268 }; 269 270 // Parameter class used for parsing user-defined function parameters. 271 struct TParameter 272 { 273 // Destructively converts to TVariable. 274 // This method resets name and type to nullptrs to make sure 275 // their content cannot be modified after the call. createVariableTParameter276 const TVariable *createVariable(TSymbolTable *symbolTable) 277 { 278 const ImmutableString constName(name); 279 const TType *constType = new TType(type); 280 name = nullptr; 281 return new TVariable(symbolTable, constName, constType, 282 constName.empty() ? SymbolType::Empty : SymbolType::UserDefined); 283 } 284 285 const char *name; // either pool allocated or static. 286 TPublicType type; 287 }; 288 289 // The function sub-class of a symbol. 290 class TFunction : public TSymbol 291 { 292 public: 293 // User-defined function 294 TFunction(TSymbolTable *symbolTable, 295 const ImmutableString &name, 296 SymbolType symbolType, 297 const TType *retType, 298 bool knownToNotHaveSideEffects); 299 300 void addParameter(const TVariable *p); 301 void shareParameters(const TFunction ¶metersSource); 302 getFunctionMangledName()303 ImmutableString getFunctionMangledName() const 304 { 305 ASSERT(symbolType() != SymbolType::BuiltIn); 306 if (mMangledName.empty()) 307 { 308 mMangledName = buildMangledName(); 309 } 310 return mMangledName; 311 } 312 getReturnType()313 const TType &getReturnType() const { return *returnType; } 314 getBuiltInOp()315 TOperator getBuiltInOp() const { return mOp; } 316 setDefined()317 void setDefined() { defined = true; } isDefined()318 bool isDefined() const { return defined; } setHasPrototypeDeclaration()319 void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; } hasPrototypeDeclaration()320 bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; } setHasVoidParameter()321 void setHasVoidParameter() { mHasVoidParameter = true; } hasVoidParameter()322 bool hasVoidParameter() const { return mHasVoidParameter; } 323 getParamCount()324 size_t getParamCount() const { return mParamCount; } getParam(size_t i)325 const TVariable *getParam(size_t i) const { return mParameters[i]; } 326 isKnownToNotHaveSideEffects()327 bool isKnownToNotHaveSideEffects() const { return mKnownToNotHaveSideEffects; } 328 329 bool isMain() const; 330 bool isImageFunction() const; 331 bool isAtomicCounterFunction() const; 332 333 // Note: Only to be used for static built-in functions! TFunction(const TSymbolUniqueId & id,const ImmutableString & name,TExtension extension,const TVariable * const * parameters,size_t paramCount,const TType * retType,TOperator op,bool knownToNotHaveSideEffects)334 constexpr TFunction(const TSymbolUniqueId &id, 335 const ImmutableString &name, 336 TExtension extension, 337 const TVariable *const *parameters, 338 size_t paramCount, 339 const TType *retType, 340 TOperator op, 341 bool knownToNotHaveSideEffects) 342 : TSymbol(id, 343 name, 344 SymbolType::BuiltIn, 345 std::array<TExtension, 1u>{{extension}}, 346 SymbolClass::Function), 347 mParametersVector(nullptr), 348 mParameters(parameters), 349 returnType(retType), 350 mMangledName(nullptr), 351 mParamCount(paramCount), 352 mOp(op), 353 defined(false), 354 mHasPrototypeDeclaration(false), 355 mKnownToNotHaveSideEffects(knownToNotHaveSideEffects), 356 mHasVoidParameter(false) 357 {} 358 359 template <size_t ExtensionCount> TFunction(const TSymbolUniqueId & id,const ImmutableString & name,const std::array<TExtension,ExtensionCount> & extensions,const TVariable * const * parameters,size_t paramCount,const TType * retType,TOperator op,bool knownToNotHaveSideEffects)360 constexpr TFunction(const TSymbolUniqueId &id, 361 const ImmutableString &name, 362 const std::array<TExtension, ExtensionCount> &extensions, 363 const TVariable *const *parameters, 364 size_t paramCount, 365 const TType *retType, 366 TOperator op, 367 bool knownToNotHaveSideEffects) 368 : TSymbol(id, name, SymbolType::BuiltIn, extensions, SymbolClass::Function), 369 mParametersVector(nullptr), 370 mParameters(parameters), 371 returnType(retType), 372 mMangledName(nullptr), 373 mParamCount(paramCount), 374 mOp(op), 375 defined(false), 376 mHasPrototypeDeclaration(false), 377 mKnownToNotHaveSideEffects(knownToNotHaveSideEffects), 378 mHasVoidParameter(false) 379 {} 380 381 private: 382 ImmutableString buildMangledName() const; 383 384 typedef TVector<const TVariable *> TParamVector; 385 TParamVector *mParametersVector; 386 const TVariable *const *mParameters; 387 const TType *const returnType; 388 mutable ImmutableString mMangledName; 389 size_t mParamCount : 32; 390 const TOperator mOp; // Only set for built-ins 391 bool defined : 1; 392 bool mHasPrototypeDeclaration : 1; 393 bool mKnownToNotHaveSideEffects : 1; 394 // Whether the parameter list of the function starts with void. This is used to generate an 395 // error if any other parameter follows. 396 bool mHasVoidParameter : 1; 397 }; 398 399 } // namespace sh 400 401 #endif // COMPILER_TRANSLATOR_SYMBOL_H_ 402