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 = type; 280 name = nullptr; 281 type = nullptr; 282 return new TVariable(symbolTable, constName, constType, 283 constName.empty() ? SymbolType::Empty : SymbolType::UserDefined); 284 } 285 286 const char *name; // either pool allocated or static. 287 TType *type; 288 }; 289 290 // The function sub-class of a symbol. 291 class TFunction : public TSymbol 292 { 293 public: 294 // User-defined function 295 TFunction(TSymbolTable *symbolTable, 296 const ImmutableString &name, 297 SymbolType symbolType, 298 const TType *retType, 299 bool knownToNotHaveSideEffects); 300 301 void addParameter(const TVariable *p); 302 void shareParameters(const TFunction ¶metersSource); 303 getFunctionMangledName()304 ImmutableString getFunctionMangledName() const 305 { 306 ASSERT(symbolType() != SymbolType::BuiltIn); 307 if (mMangledName.empty()) 308 { 309 mMangledName = buildMangledName(); 310 } 311 return mMangledName; 312 } 313 getReturnType()314 const TType &getReturnType() const { return *returnType; } 315 getBuiltInOp()316 TOperator getBuiltInOp() const { return mOp; } 317 setDefined()318 void setDefined() { defined = true; } isDefined()319 bool isDefined() const { return defined; } setHasPrototypeDeclaration()320 void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; } hasPrototypeDeclaration()321 bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; } setHasVoidParameter()322 void setHasVoidParameter() { mHasVoidParameter = true; } hasVoidParameter()323 bool hasVoidParameter() const { return mHasVoidParameter; } 324 getParamCount()325 size_t getParamCount() const { return mParamCount; } getParam(size_t i)326 const TVariable *getParam(size_t i) const { return mParameters[i]; } 327 isKnownToNotHaveSideEffects()328 bool isKnownToNotHaveSideEffects() const { return mKnownToNotHaveSideEffects; } 329 330 bool isMain() const; 331 bool isImageFunction() const; 332 bool isAtomicCounterFunction() const; 333 334 // 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)335 constexpr TFunction(const TSymbolUniqueId &id, 336 const ImmutableString &name, 337 TExtension extension, 338 const TVariable *const *parameters, 339 size_t paramCount, 340 const TType *retType, 341 TOperator op, 342 bool knownToNotHaveSideEffects) 343 : TSymbol(id, 344 name, 345 SymbolType::BuiltIn, 346 std::array<TExtension, 1u>{{extension}}, 347 SymbolClass::Function), 348 mParametersVector(nullptr), 349 mParameters(parameters), 350 returnType(retType), 351 mMangledName(nullptr), 352 mParamCount(paramCount), 353 mOp(op), 354 defined(false), 355 mHasPrototypeDeclaration(false), 356 mKnownToNotHaveSideEffects(knownToNotHaveSideEffects), 357 mHasVoidParameter(false) 358 {} 359 360 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)361 constexpr TFunction(const TSymbolUniqueId &id, 362 const ImmutableString &name, 363 const std::array<TExtension, ExtensionCount> &extensions, 364 const TVariable *const *parameters, 365 size_t paramCount, 366 const TType *retType, 367 TOperator op, 368 bool knownToNotHaveSideEffects) 369 : TSymbol(id, name, SymbolType::BuiltIn, extensions, SymbolClass::Function), 370 mParametersVector(nullptr), 371 mParameters(parameters), 372 returnType(retType), 373 mMangledName(nullptr), 374 mParamCount(paramCount), 375 mOp(op), 376 defined(false), 377 mHasPrototypeDeclaration(false), 378 mKnownToNotHaveSideEffects(knownToNotHaveSideEffects), 379 mHasVoidParameter(false) 380 {} 381 382 private: 383 ImmutableString buildMangledName() const; 384 385 typedef TVector<const TVariable *> TParamVector; 386 TParamVector *mParametersVector; 387 const TVariable *const *mParameters; 388 const TType *const returnType; 389 mutable ImmutableString mMangledName; 390 size_t mParamCount : 32; 391 const TOperator mOp; // Only set for built-ins 392 bool defined : 1; 393 bool mHasPrototypeDeclaration : 1; 394 bool mKnownToNotHaveSideEffects : 1; 395 // Whether the parameter list of the function starts with void. This is used to generate an 396 // error if any other parameter follows. 397 bool mHasVoidParameter : 1; 398 }; 399 400 } // namespace sh 401 402 #endif // COMPILER_TRANSLATOR_SYMBOL_H_ 403