gfx/angle/src/compiler/SymbolTable.h

changeset 0
6474c204b198
     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_

mercurial