1 // 2 // Copyright (c) 2002-2013 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 7 #ifndef _SYMBOL_TABLE_INCLUDED_ 8 #define _SYMBOL_TABLE_INCLUDED_ 9 10 // 11 // Symbol table for parsing. Has these design characteristics: 12 // 13 // * Same symbol table can be used to compile many shaders, to preserve 14 // effort of creating and loading with the large numbers of built-in 15 // symbols. 16 // 17 // * Name mangling will be used to give each function a unique name 18 // so that symbol table lookups are never ambiguous. This allows 19 // a simpler symbol table structure. 20 // 21 // * Pushing and popping of scope, so symbol table will really be a stack 22 // of symbol tables. Searched from the top, with new inserts going into 23 // the top. 24 // 25 // * Constants: Compile time constant symbols will keep their values 26 // in the symbol table. The parser can substitute constants at parse 27 // time, including doing constant folding and constant propagation. 28 // 29 // * No temporaries: Temporaries made from operations (+, --, .xy, etc.) 30 // are tracked in the intermediate representation, not the symbol table. 31 // 32 33 #include <assert.h> 34 35 #include "common/angleutils.h" 36 #include "compiler/InfoSink.h" 37 #include "compiler/intermediate.h" 38 39 // 40 // Symbol base class. (Can build functions or variables out of these...) 41 // 42 class TSymbol { 43 public: 44 POOL_ALLOCATOR_NEW_DELETE(); 45 TSymbol(const TString *n) : name(n) { } 46 virtual ~TSymbol() { /* don't delete name, it's from the pool */ } 47 48 const TString& getName() const { return *name; } 49 virtual const TString& getMangledName() const { return getName(); } 50 virtual bool isFunction() const { return false; } 51 virtual bool isVariable() const { return false; } 52 void setUniqueId(int id) { uniqueId = id; } 53 int getUniqueId() const { return uniqueId; } 54 virtual void dump(TInfoSink &infoSink) const = 0; 55 void relateToExtension(const TString& ext) { extension = ext; } 56 const TString& getExtension() const { return extension; } 57 58 private: 59 DISALLOW_COPY_AND_ASSIGN(TSymbol); 60 61 const TString *name; 62 unsigned int uniqueId; // For real comparing during code generation 63 TString extension; 64 }; 65 66 // 67 // Variable class, meaning a symbol that's not a function. 68 // 69 // There could be a separate class heirarchy for Constant variables; 70 // Only one of int, bool, or float, (or none) is correct for 71 // any particular use, but it's easy to do this way, and doesn't 72 // seem worth having separate classes, and "getConst" can't simply return 73 // different values for different types polymorphically, so this is 74 // just simple and pragmatic. 75 // 76 class TVariable : public TSymbol { 77 public: 78 TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0) { } 79 virtual ~TVariable() { } 80 virtual bool isVariable() const { return true; } 81 TType& getType() { return type; } 82 const TType& getType() const { return type; } 83 bool isUserType() const { return userType; } 84 void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); } 85 86 virtual void dump(TInfoSink &infoSink) const; 87 88 ConstantUnion* getConstPointer() 89 { 90 if (!unionArray) 91 unionArray = new ConstantUnion[type.getObjectSize()]; 92 93 return unionArray; 94 } 95 96 ConstantUnion* getConstPointer() const { return unionArray; } 97 98 void shareConstPointer( ConstantUnion *constArray) 99 { 100 if (unionArray == constArray) 101 return; 102 103 delete[] unionArray; 104 unionArray = constArray; 105 } 106 107 private: 108 DISALLOW_COPY_AND_ASSIGN(TVariable); 109 110 TType type; 111 bool userType; 112 // we are assuming that Pool Allocator will free the memory allocated to unionArray 113 // when this object is destroyed 114 ConstantUnion *unionArray; 115 }; 116 117 // 118 // The function sub-class of symbols and the parser will need to 119 // share this definition of a function parameter. 120 // 121 struct TParameter { 122 TString *name; 123 TType* type; 124 }; 125 126 // 127 // The function sub-class of a symbol. 128 // 129 class TFunction : public TSymbol { 130 public: 131 TFunction(TOperator o) : 132 TSymbol(0), 133 returnType(TType(EbtVoid, EbpUndefined)), 134 op(o), 135 defined(false) { } 136 TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : 137 TSymbol(name), 138 returnType(retType), 139 mangledName(TFunction::mangleName(*name)), 140 op(tOp), 141 defined(false) { } 142 virtual ~TFunction(); 143 virtual bool isFunction() const { return true; } 144 145 static TString mangleName(const TString& name) { return name + '('; } 146 static TString unmangleName(const TString& mangledName) 147 { 148 return TString(mangledName.c_str(), mangledName.find_first_of('(')); 149 } 150 151 void addParameter(TParameter& p) 152 { 153 parameters.push_back(p); 154 mangledName = mangledName + p.type->getMangledName(); 155 } 156 157 const TString& getMangledName() const { return mangledName; } 158 const TType& getReturnType() const { return returnType; } 159 160 void relateToOperator(TOperator o) { op = o; } 161 TOperator getBuiltInOp() const { return op; } 162 163 void setDefined() { defined = true; } 164 bool isDefined() { return defined; } 165 166 size_t getParamCount() const { return parameters.size(); } 167 const TParameter& getParam(size_t i) const { return parameters[i]; } 168 169 virtual void dump(TInfoSink &infoSink) const; 170 171 private: 172 DISALLOW_COPY_AND_ASSIGN(TFunction); 173 174 typedef TVector<TParameter> TParamList; 175 TParamList parameters; 176 TType returnType; 177 TString mangledName; 178 TOperator op; 179 bool defined; 180 }; 181 182 183 class TSymbolTableLevel { 184 public: 185 typedef TMap<TString, TSymbol*> tLevel; 186 typedef tLevel::const_iterator const_iterator; 187 typedef const tLevel::value_type tLevelPair; 188 typedef std::pair<tLevel::iterator, bool> tInsertResult; 189 190 POOL_ALLOCATOR_NEW_DELETE(); 191 TSymbolTableLevel() { } 192 ~TSymbolTableLevel(); 193 194 bool insert(const TString &name, TSymbol &symbol) 195 { 196 // 197 // returning true means symbol was added to the table 198 // 199 tInsertResult result; 200 result = level.insert(tLevelPair(name, &symbol)); 201 202 return result.second; 203 } 204 205 bool insert(TSymbol &symbol) 206 { 207 return insert(symbol.getMangledName(), symbol); 208 } 209 210 TSymbol* find(const TString& name) const 211 { 212 tLevel::const_iterator it = level.find(name); 213 if (it == level.end()) 214 return 0; 215 else 216 return (*it).second; 217 } 218 219 const_iterator begin() const 220 { 221 return level.begin(); 222 } 223 224 const_iterator end() const 225 { 226 return level.end(); 227 } 228 229 void relateToOperator(const char* name, TOperator op); 230 void relateToExtension(const char* name, const TString& ext); 231 void dump(TInfoSink &infoSink) const; 232 233 protected: 234 tLevel level; 235 }; 236 237 class TSymbolTable { 238 public: 239 TSymbolTable() : uniqueId(0) 240 { 241 // 242 // The symbol table cannot be used until push() is called, but 243 // the lack of an initial call to push() can be used to detect 244 // that the symbol table has not been preloaded with built-ins. 245 // 246 } 247 248 ~TSymbolTable() 249 { 250 // level 0 is always built In symbols, so we never pop that out 251 while (table.size() > 1) 252 pop(); 253 } 254 255 // 256 // When the symbol table is initialized with the built-ins, there should 257 // 'push' calls, so that built-ins are at level 0 and the shader 258 // globals are at level 1. 259 // 260 bool isEmpty() { return table.size() == 0; } 261 bool atBuiltInLevel() { return table.size() == 1; } 262 bool atGlobalLevel() { return table.size() <= 2; } 263 void push() 264 { 265 table.push_back(new TSymbolTableLevel); 266 precisionStack.push_back( PrecisionStackLevel() ); 267 } 268 269 void pop() 270 { 271 delete table[currentLevel()]; 272 table.pop_back(); 273 precisionStack.pop_back(); 274 } 275 276 bool insert(TSymbol& symbol) 277 { 278 symbol.setUniqueId(++uniqueId); 279 return table[currentLevel()]->insert(symbol); 280 } 281 282 bool insertConstInt(const char *name, int value) 283 { 284 TVariable *constant = new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); 285 constant->getConstPointer()->setIConst(value); 286 return insert(*constant); 287 } 288 289 bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0) 290 { 291 TFunction *function = new TFunction(NewPoolTString(name), *rvalue); 292 293 TParameter param1 = {NULL, ptype1}; 294 function->addParameter(param1); 295 296 if(ptype2) 297 { 298 TParameter param2 = {NULL, ptype2}; 299 function->addParameter(param2); 300 } 301 302 if(ptype3) 303 { 304 TParameter param3 = {NULL, ptype3}; 305 function->addParameter(param3); 306 } 307 308 return insert(*function); 309 } 310 311 TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0) 312 { 313 int level = currentLevel(); 314 TSymbol* symbol; 315 do { 316 symbol = table[level]->find(name); 317 --level; 318 } while (symbol == 0 && level >= 0); 319 level++; 320 if (builtIn) 321 *builtIn = level == 0; 322 if (sameScope) 323 *sameScope = level == currentLevel(); 324 return symbol; 325 } 326 327 TSymbol *findBuiltIn(const TString &name) 328 { 329 return table[0]->find(name); 330 } 331 332 TSymbolTableLevel* getGlobalLevel() { 333 assert(table.size() >= 2); 334 return table[1]; 335 } 336 337 TSymbolTableLevel* getOuterLevel() { 338 assert(table.size() >= 2); 339 return table[currentLevel() - 1]; 340 } 341 342 void relateToOperator(const char* name, TOperator op) { 343 table[0]->relateToOperator(name, op); 344 } 345 void relateToExtension(const char* name, const TString& ext) { 346 table[0]->relateToExtension(name, ext); 347 } 348 int getMaxSymbolId() { return uniqueId; } 349 void dump(TInfoSink &infoSink) const; 350 351 bool setDefaultPrecision( const TPublicType& type, TPrecision prec ){ 352 if (IsSampler(type.type)) 353 return true; // Skip sampler types for the time being 354 if (type.type != EbtFloat && type.type != EbtInt) 355 return false; // Only set default precision for int/float 356 if (type.size != 1 || type.matrix || type.array) 357 return false; // Not allowed to set for aggregate types 358 int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1; 359 precisionStack[indexOfLastElement][type.type] = prec; // Uses map operator [], overwrites the current value 360 return true; 361 } 362 363 // Searches down the precisionStack for a precision qualifier for the specified TBasicType 364 TPrecision getDefaultPrecision( TBasicType type){ 365 if( type != EbtFloat && type != EbtInt ) return EbpUndefined; 366 int level = static_cast<int>(precisionStack.size()) - 1; 367 assert( level >= 0); // Just to be safe. Should not happen. 368 PrecisionStackLevel::iterator it; 369 TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this? 370 while( level >= 0 ){ 371 it = precisionStack[level].find( type ); 372 if( it != precisionStack[level].end() ){ 373 prec = (*it).second; 374 break; 375 } 376 level--; 377 } 378 return prec; 379 } 380 381 protected: 382 int currentLevel() const { return static_cast<int>(table.size()) - 1; } 383 384 std::vector<TSymbolTableLevel*> table; 385 typedef std::map< TBasicType, TPrecision > PrecisionStackLevel; 386 std::vector< PrecisionStackLevel > precisionStack; 387 int uniqueId; // for unique identification in code generation 388 }; 389 390 #endif // _SYMBOL_TABLE_INCLUDED_ 391