1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/compiler/SymbolTable.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,390 @@ 1.4 +// 1.5 +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 1.6 +// Use of this source code is governed by a BSD-style license that can be 1.7 +// found in the LICENSE file. 1.8 +// 1.9 + 1.10 +#ifndef _SYMBOL_TABLE_INCLUDED_ 1.11 +#define _SYMBOL_TABLE_INCLUDED_ 1.12 + 1.13 +// 1.14 +// Symbol table for parsing. Has these design characteristics: 1.15 +// 1.16 +// * Same symbol table can be used to compile many shaders, to preserve 1.17 +// effort of creating and loading with the large numbers of built-in 1.18 +// symbols. 1.19 +// 1.20 +// * Name mangling will be used to give each function a unique name 1.21 +// so that symbol table lookups are never ambiguous. This allows 1.22 +// a simpler symbol table structure. 1.23 +// 1.24 +// * Pushing and popping of scope, so symbol table will really be a stack 1.25 +// of symbol tables. Searched from the top, with new inserts going into 1.26 +// the top. 1.27 +// 1.28 +// * Constants: Compile time constant symbols will keep their values 1.29 +// in the symbol table. The parser can substitute constants at parse 1.30 +// time, including doing constant folding and constant propagation. 1.31 +// 1.32 +// * No temporaries: Temporaries made from operations (+, --, .xy, etc.) 1.33 +// are tracked in the intermediate representation, not the symbol table. 1.34 +// 1.35 + 1.36 +#include <assert.h> 1.37 + 1.38 +#include "common/angleutils.h" 1.39 +#include "compiler/InfoSink.h" 1.40 +#include "compiler/intermediate.h" 1.41 + 1.42 +// 1.43 +// Symbol base class. (Can build functions or variables out of these...) 1.44 +// 1.45 +class TSymbol { 1.46 +public: 1.47 + POOL_ALLOCATOR_NEW_DELETE(); 1.48 + TSymbol(const TString *n) : name(n) { } 1.49 + virtual ~TSymbol() { /* don't delete name, it's from the pool */ } 1.50 + 1.51 + const TString& getName() const { return *name; } 1.52 + virtual const TString& getMangledName() const { return getName(); } 1.53 + virtual bool isFunction() const { return false; } 1.54 + virtual bool isVariable() const { return false; } 1.55 + void setUniqueId(int id) { uniqueId = id; } 1.56 + int getUniqueId() const { return uniqueId; } 1.57 + virtual void dump(TInfoSink &infoSink) const = 0; 1.58 + void relateToExtension(const TString& ext) { extension = ext; } 1.59 + const TString& getExtension() const { return extension; } 1.60 + 1.61 +private: 1.62 + DISALLOW_COPY_AND_ASSIGN(TSymbol); 1.63 + 1.64 + const TString *name; 1.65 + unsigned int uniqueId; // For real comparing during code generation 1.66 + TString extension; 1.67 +}; 1.68 + 1.69 +// 1.70 +// Variable class, meaning a symbol that's not a function. 1.71 +// 1.72 +// There could be a separate class heirarchy for Constant variables; 1.73 +// Only one of int, bool, or float, (or none) is correct for 1.74 +// any particular use, but it's easy to do this way, and doesn't 1.75 +// seem worth having separate classes, and "getConst" can't simply return 1.76 +// different values for different types polymorphically, so this is 1.77 +// just simple and pragmatic. 1.78 +// 1.79 +class TVariable : public TSymbol { 1.80 +public: 1.81 + TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0) { } 1.82 + virtual ~TVariable() { } 1.83 + virtual bool isVariable() const { return true; } 1.84 + TType& getType() { return type; } 1.85 + const TType& getType() const { return type; } 1.86 + bool isUserType() const { return userType; } 1.87 + void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); } 1.88 + 1.89 + virtual void dump(TInfoSink &infoSink) const; 1.90 + 1.91 + ConstantUnion* getConstPointer() 1.92 + { 1.93 + if (!unionArray) 1.94 + unionArray = new ConstantUnion[type.getObjectSize()]; 1.95 + 1.96 + return unionArray; 1.97 + } 1.98 + 1.99 + ConstantUnion* getConstPointer() const { return unionArray; } 1.100 + 1.101 + void shareConstPointer( ConstantUnion *constArray) 1.102 + { 1.103 + if (unionArray == constArray) 1.104 + return; 1.105 + 1.106 + delete[] unionArray; 1.107 + unionArray = constArray; 1.108 + } 1.109 + 1.110 +private: 1.111 + DISALLOW_COPY_AND_ASSIGN(TVariable); 1.112 + 1.113 + TType type; 1.114 + bool userType; 1.115 + // we are assuming that Pool Allocator will free the memory allocated to unionArray 1.116 + // when this object is destroyed 1.117 + ConstantUnion *unionArray; 1.118 +}; 1.119 + 1.120 +// 1.121 +// The function sub-class of symbols and the parser will need to 1.122 +// share this definition of a function parameter. 1.123 +// 1.124 +struct TParameter { 1.125 + TString *name; 1.126 + TType* type; 1.127 +}; 1.128 + 1.129 +// 1.130 +// The function sub-class of a symbol. 1.131 +// 1.132 +class TFunction : public TSymbol { 1.133 +public: 1.134 + TFunction(TOperator o) : 1.135 + TSymbol(0), 1.136 + returnType(TType(EbtVoid, EbpUndefined)), 1.137 + op(o), 1.138 + defined(false) { } 1.139 + TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : 1.140 + TSymbol(name), 1.141 + returnType(retType), 1.142 + mangledName(TFunction::mangleName(*name)), 1.143 + op(tOp), 1.144 + defined(false) { } 1.145 + virtual ~TFunction(); 1.146 + virtual bool isFunction() const { return true; } 1.147 + 1.148 + static TString mangleName(const TString& name) { return name + '('; } 1.149 + static TString unmangleName(const TString& mangledName) 1.150 + { 1.151 + return TString(mangledName.c_str(), mangledName.find_first_of('(')); 1.152 + } 1.153 + 1.154 + void addParameter(TParameter& p) 1.155 + { 1.156 + parameters.push_back(p); 1.157 + mangledName = mangledName + p.type->getMangledName(); 1.158 + } 1.159 + 1.160 + const TString& getMangledName() const { return mangledName; } 1.161 + const TType& getReturnType() const { return returnType; } 1.162 + 1.163 + void relateToOperator(TOperator o) { op = o; } 1.164 + TOperator getBuiltInOp() const { return op; } 1.165 + 1.166 + void setDefined() { defined = true; } 1.167 + bool isDefined() { return defined; } 1.168 + 1.169 + size_t getParamCount() const { return parameters.size(); } 1.170 + const TParameter& getParam(size_t i) const { return parameters[i]; } 1.171 + 1.172 + virtual void dump(TInfoSink &infoSink) const; 1.173 + 1.174 +private: 1.175 + DISALLOW_COPY_AND_ASSIGN(TFunction); 1.176 + 1.177 + typedef TVector<TParameter> TParamList; 1.178 + TParamList parameters; 1.179 + TType returnType; 1.180 + TString mangledName; 1.181 + TOperator op; 1.182 + bool defined; 1.183 +}; 1.184 + 1.185 + 1.186 +class TSymbolTableLevel { 1.187 +public: 1.188 + typedef TMap<TString, TSymbol*> tLevel; 1.189 + typedef tLevel::const_iterator const_iterator; 1.190 + typedef const tLevel::value_type tLevelPair; 1.191 + typedef std::pair<tLevel::iterator, bool> tInsertResult; 1.192 + 1.193 + POOL_ALLOCATOR_NEW_DELETE(); 1.194 + TSymbolTableLevel() { } 1.195 + ~TSymbolTableLevel(); 1.196 + 1.197 + bool insert(const TString &name, TSymbol &symbol) 1.198 + { 1.199 + // 1.200 + // returning true means symbol was added to the table 1.201 + // 1.202 + tInsertResult result; 1.203 + result = level.insert(tLevelPair(name, &symbol)); 1.204 + 1.205 + return result.second; 1.206 + } 1.207 + 1.208 + bool insert(TSymbol &symbol) 1.209 + { 1.210 + return insert(symbol.getMangledName(), symbol); 1.211 + } 1.212 + 1.213 + TSymbol* find(const TString& name) const 1.214 + { 1.215 + tLevel::const_iterator it = level.find(name); 1.216 + if (it == level.end()) 1.217 + return 0; 1.218 + else 1.219 + return (*it).second; 1.220 + } 1.221 + 1.222 + const_iterator begin() const 1.223 + { 1.224 + return level.begin(); 1.225 + } 1.226 + 1.227 + const_iterator end() const 1.228 + { 1.229 + return level.end(); 1.230 + } 1.231 + 1.232 + void relateToOperator(const char* name, TOperator op); 1.233 + void relateToExtension(const char* name, const TString& ext); 1.234 + void dump(TInfoSink &infoSink) const; 1.235 + 1.236 +protected: 1.237 + tLevel level; 1.238 +}; 1.239 + 1.240 +class TSymbolTable { 1.241 +public: 1.242 + TSymbolTable() : uniqueId(0) 1.243 + { 1.244 + // 1.245 + // The symbol table cannot be used until push() is called, but 1.246 + // the lack of an initial call to push() can be used to detect 1.247 + // that the symbol table has not been preloaded with built-ins. 1.248 + // 1.249 + } 1.250 + 1.251 + ~TSymbolTable() 1.252 + { 1.253 + // level 0 is always built In symbols, so we never pop that out 1.254 + while (table.size() > 1) 1.255 + pop(); 1.256 + } 1.257 + 1.258 + // 1.259 + // When the symbol table is initialized with the built-ins, there should 1.260 + // 'push' calls, so that built-ins are at level 0 and the shader 1.261 + // globals are at level 1. 1.262 + // 1.263 + bool isEmpty() { return table.size() == 0; } 1.264 + bool atBuiltInLevel() { return table.size() == 1; } 1.265 + bool atGlobalLevel() { return table.size() <= 2; } 1.266 + void push() 1.267 + { 1.268 + table.push_back(new TSymbolTableLevel); 1.269 + precisionStack.push_back( PrecisionStackLevel() ); 1.270 + } 1.271 + 1.272 + void pop() 1.273 + { 1.274 + delete table[currentLevel()]; 1.275 + table.pop_back(); 1.276 + precisionStack.pop_back(); 1.277 + } 1.278 + 1.279 + bool insert(TSymbol& symbol) 1.280 + { 1.281 + symbol.setUniqueId(++uniqueId); 1.282 + return table[currentLevel()]->insert(symbol); 1.283 + } 1.284 + 1.285 + bool insertConstInt(const char *name, int value) 1.286 + { 1.287 + TVariable *constant = new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); 1.288 + constant->getConstPointer()->setIConst(value); 1.289 + return insert(*constant); 1.290 + } 1.291 + 1.292 + bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0) 1.293 + { 1.294 + TFunction *function = new TFunction(NewPoolTString(name), *rvalue); 1.295 + 1.296 + TParameter param1 = {NULL, ptype1}; 1.297 + function->addParameter(param1); 1.298 + 1.299 + if(ptype2) 1.300 + { 1.301 + TParameter param2 = {NULL, ptype2}; 1.302 + function->addParameter(param2); 1.303 + } 1.304 + 1.305 + if(ptype3) 1.306 + { 1.307 + TParameter param3 = {NULL, ptype3}; 1.308 + function->addParameter(param3); 1.309 + } 1.310 + 1.311 + return insert(*function); 1.312 + } 1.313 + 1.314 + TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0) 1.315 + { 1.316 + int level = currentLevel(); 1.317 + TSymbol* symbol; 1.318 + do { 1.319 + symbol = table[level]->find(name); 1.320 + --level; 1.321 + } while (symbol == 0 && level >= 0); 1.322 + level++; 1.323 + if (builtIn) 1.324 + *builtIn = level == 0; 1.325 + if (sameScope) 1.326 + *sameScope = level == currentLevel(); 1.327 + return symbol; 1.328 + } 1.329 + 1.330 + TSymbol *findBuiltIn(const TString &name) 1.331 + { 1.332 + return table[0]->find(name); 1.333 + } 1.334 + 1.335 + TSymbolTableLevel* getGlobalLevel() { 1.336 + assert(table.size() >= 2); 1.337 + return table[1]; 1.338 + } 1.339 + 1.340 + TSymbolTableLevel* getOuterLevel() { 1.341 + assert(table.size() >= 2); 1.342 + return table[currentLevel() - 1]; 1.343 + } 1.344 + 1.345 + void relateToOperator(const char* name, TOperator op) { 1.346 + table[0]->relateToOperator(name, op); 1.347 + } 1.348 + void relateToExtension(const char* name, const TString& ext) { 1.349 + table[0]->relateToExtension(name, ext); 1.350 + } 1.351 + int getMaxSymbolId() { return uniqueId; } 1.352 + void dump(TInfoSink &infoSink) const; 1.353 + 1.354 + bool setDefaultPrecision( const TPublicType& type, TPrecision prec ){ 1.355 + if (IsSampler(type.type)) 1.356 + return true; // Skip sampler types for the time being 1.357 + if (type.type != EbtFloat && type.type != EbtInt) 1.358 + return false; // Only set default precision for int/float 1.359 + if (type.size != 1 || type.matrix || type.array) 1.360 + return false; // Not allowed to set for aggregate types 1.361 + int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1; 1.362 + precisionStack[indexOfLastElement][type.type] = prec; // Uses map operator [], overwrites the current value 1.363 + return true; 1.364 + } 1.365 + 1.366 + // Searches down the precisionStack for a precision qualifier for the specified TBasicType 1.367 + TPrecision getDefaultPrecision( TBasicType type){ 1.368 + if( type != EbtFloat && type != EbtInt ) return EbpUndefined; 1.369 + int level = static_cast<int>(precisionStack.size()) - 1; 1.370 + assert( level >= 0); // Just to be safe. Should not happen. 1.371 + PrecisionStackLevel::iterator it; 1.372 + TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this? 1.373 + while( level >= 0 ){ 1.374 + it = precisionStack[level].find( type ); 1.375 + if( it != precisionStack[level].end() ){ 1.376 + prec = (*it).second; 1.377 + break; 1.378 + } 1.379 + level--; 1.380 + } 1.381 + return prec; 1.382 + } 1.383 + 1.384 +protected: 1.385 + int currentLevel() const { return static_cast<int>(table.size()) - 1; } 1.386 + 1.387 + std::vector<TSymbolTableLevel*> table; 1.388 + typedef std::map< TBasicType, TPrecision > PrecisionStackLevel; 1.389 + std::vector< PrecisionStackLevel > precisionStack; 1.390 + int uniqueId; // for unique identification in code generation 1.391 +}; 1.392 + 1.393 +#endif // _SYMBOL_TABLE_INCLUDED_