Home | History | Annotate | Download | only in MachineIndependent
      1 //
      2 //Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
      3 //All rights reserved.
      4 //
      5 //Redistribution and use in source and binary forms, with or without
      6 //modification, are permitted provided that the following conditions
      7 //are met:
      8 //
      9 //    Redistributions of source code must retain the above copyright
     10 //    notice, this list of conditions and the following disclaimer.
     11 //
     12 //    Redistributions in binary form must reproduce the above
     13 //    copyright notice, this list of conditions and the following
     14 //    disclaimer in the documentation and/or other materials provided
     15 //    with the distribution.
     16 //
     17 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
     18 //    contributors may be used to endorse or promote products derived
     19 //    from this software without specific prior written permission.
     20 //
     21 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     22 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     23 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     24 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     25 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     26 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     27 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     28 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     29 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     31 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     32 //POSSIBILITY OF SUCH DAMAGE.
     33 //
     34 
     35 #ifndef _LOCAL_INTERMEDIATE_INCLUDED_
     36 #define _LOCAL_INTERMEDIATE_INCLUDED_
     37 
     38 #include "../Include/intermediate.h"
     39 #include "../Public/ShaderLang.h"
     40 #include "Versions.h"
     41 
     42 #include <algorithm>
     43 #include <set>
     44 
     45 class TInfoSink;
     46 
     47 namespace glslang {
     48 
     49 struct TVectorFields {
     50     int offsets[4];
     51     int num;
     52 };
     53 
     54 //
     55 // Some helper structures for TIntermediate.  Their contents are encapsulated
     56 // by TIntermediate.
     57 //
     58 
     59 // Used for detecting recursion:  A "call" is a pair: <caller, callee>.
     60 struct TCall {
     61     TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { }
     62     TString caller;
     63     TString callee;
     64     bool visited;
     65     bool currentPath;
     66     bool errorGiven;
     67 };
     68 
     69 // A generic 1-D range.
     70 struct TRange {
     71     TRange(int start, int last) : start(start), last(last) { }
     72     bool overlap(const TRange& rhs) const
     73     {
     74         return last >= rhs.start && start <= rhs.last;
     75     }
     76     int start;
     77     int last;
     78 };
     79 
     80 // An IO range is a 3-D rectangle; the set of (location, component, index) triples all lying
     81 // within the same location range, component range, and index value.  Locations don't alias unless
     82 // all other dimensions of their range overlap.
     83 struct TIoRange {
     84     TIoRange(TRange location, TRange component, TBasicType basicType, int index)
     85         : location(location), component(component), basicType(basicType), index(index) { }
     86     bool overlap(const TIoRange& rhs) const
     87     {
     88         return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index;
     89     }
     90     TRange location;
     91     TRange component;
     92     TBasicType basicType;
     93     int index;
     94 };
     95 
     96 // An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying
     97 // within the same binding and offset range.
     98 struct TOffsetRange {
     99     TOffsetRange(TRange binding, TRange offset)
    100         : binding(binding), offset(offset) { }
    101     bool overlap(const TOffsetRange& rhs) const
    102     {
    103         return binding.overlap(rhs.binding) && offset.overlap(rhs.offset);
    104     }
    105     TRange binding;
    106     TRange offset;
    107 };
    108 
    109 // Things that need to be tracked per xfb buffer.
    110 struct TXfbBuffer {
    111     TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { }
    112     std::vector<TRange> ranges;  // byte offsets that have already been assigned
    113     unsigned int stride;
    114     unsigned int implicitStride;
    115     bool containsDouble;
    116 };
    117 
    118 class TSymbolTable;
    119 class TSymbol;
    120 class TVariable;
    121 
    122 //
    123 // Set of helper functions to help parse and build the tree.
    124 //
    125 class TIntermediate {
    126 public:
    127     explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
    128         source(EShSourceNone), language(l), profile(p), version(v), treeRoot(0),
    129         numMains(0), numErrors(0), numPushConstants(0), recursive(false),
    130         invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone),
    131         pixelCenterInteger(false), originUpperLeft(false),
    132         vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), depthReplacing(false), blendEquations(0),
    133         multiStream(false), xfbMode(false)
    134     {
    135         localSize[0] = 1;
    136         localSize[1] = 1;
    137         localSize[2] = 1;
    138         localSizeSpecId[0] = TQualifier::layoutNotSet;
    139         localSizeSpecId[1] = TQualifier::layoutNotSet;
    140         localSizeSpecId[2] = TQualifier::layoutNotSet;
    141         xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
    142     }
    143     void setLimits(const TBuiltInResource& r) { resources = r; }
    144 
    145     bool postProcess(TIntermNode*, EShLanguage);
    146     void output(TInfoSink&, bool tree);
    147     void removeTree();
    148 
    149     void setSource(EShSource s) { source = s; }
    150     EShSource getSource() const { return source; }
    151     void setEntryPoint(const char* ep) { entryPoint = ep; }
    152     const std::string& getEntryPoint() const { return entryPoint; }
    153     void setVersion(int v) { version = v; }
    154     int getVersion() const { return version; }
    155     void setProfile(EProfile p) { profile = p; }
    156     EProfile getProfile() const { return profile; }
    157     void setSpv(const SpvVersion& s) { spvVersion = s; }
    158     const SpvVersion& getSpv() const { return spvVersion; }
    159     EShLanguage getStage() const { return language; }
    160     void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
    161     const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
    162 
    163     void setTreeRoot(TIntermNode* r) { treeRoot = r; }
    164     TIntermNode* getTreeRoot() const { return treeRoot; }
    165     void addMainCount() { ++numMains; }
    166     int getNumMains() const { return numMains; }
    167     int getNumErrors() const { return numErrors; }
    168     void addPushConstantCount() { ++numPushConstants; }
    169     bool isRecursive() const { return recursive; }
    170 
    171     TIntermSymbol* addSymbol(const TVariable&);
    172     TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
    173     TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
    174     TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
    175     TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
    176     TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
    177     TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
    178     TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc);
    179     TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
    180     bool canImplicitlyPromote(TBasicType from, TBasicType to) const;
    181     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
    182     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
    183     TIntermAggregate* makeAggregate(TIntermNode* node);
    184     TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
    185     TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
    186     bool areAllChildConst(TIntermAggregate* aggrNode);
    187     TIntermNode*  addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
    188     TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
    189     TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
    190     TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
    191     TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
    192     TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
    193     TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
    194     TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
    195     TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
    196     TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
    197     TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
    198     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
    199     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
    200     TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
    201     TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
    202     TIntermBranch* addBranch(TOperator, const TSourceLoc&);
    203     TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
    204     TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&);
    205 
    206     // Constant folding (in Constant.cpp)
    207     TIntermTyped* fold(TIntermAggregate* aggrNode);
    208     TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
    209     TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
    210     TIntermTyped* foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc&);
    211 
    212     // Tree ops
    213     static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay);
    214 
    215     // Linkage related
    216     void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
    217     void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
    218     void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
    219 
    220     bool setInvocations(int i)
    221     {
    222         if (invocations != TQualifier::layoutNotSet)
    223             return invocations == i;
    224         invocations = i;
    225         return true;
    226     }
    227     int getInvocations() const { return invocations; }
    228     bool setVertices(int m)
    229     {
    230         if (vertices != TQualifier::layoutNotSet)
    231             return vertices == m;
    232         vertices = m;
    233         return true;
    234     }
    235     int getVertices() const { return vertices; }
    236     bool setInputPrimitive(TLayoutGeometry p)
    237     {
    238         if (inputPrimitive != ElgNone)
    239             return inputPrimitive == p;
    240         inputPrimitive = p;
    241         return true;
    242     }
    243     TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
    244     bool setVertexSpacing(TVertexSpacing s)
    245     {
    246         if (vertexSpacing != EvsNone)
    247             return vertexSpacing == s;
    248         vertexSpacing = s;
    249         return true;
    250     }
    251     TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
    252     bool setVertexOrder(TVertexOrder o)
    253     {
    254         if (vertexOrder != EvoNone)
    255             return vertexOrder == o;
    256         vertexOrder = o;
    257         return true;
    258     }
    259     TVertexOrder getVertexOrder() const { return vertexOrder; }
    260     void setPointMode() { pointMode = true; }
    261     bool getPointMode() const { return pointMode; }
    262 
    263     bool setLocalSize(int dim, int size)
    264     {
    265         if (localSize[dim] > 1)
    266             return size == localSize[dim];
    267         localSize[dim] = size;
    268         return true;
    269     }
    270     unsigned int getLocalSize(int dim) const { return localSize[dim]; }
    271 
    272     bool setLocalSizeSpecId(int dim, int id)
    273     {
    274         if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
    275             return id == localSizeSpecId[dim];
    276         localSizeSpecId[dim] = id;
    277         return true;
    278     }
    279     int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
    280 
    281     void setXfbMode() { xfbMode = true; }
    282     bool getXfbMode() const { return xfbMode; }
    283     void setMultiStream() { multiStream = true; }
    284     bool isMultiStream() const { return multiStream; }
    285     bool setOutputPrimitive(TLayoutGeometry p)
    286     {
    287         if (outputPrimitive != ElgNone)
    288             return outputPrimitive == p;
    289         outputPrimitive = p;
    290         return true;
    291     }
    292     TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
    293     void setOriginUpperLeft() { originUpperLeft = true; }
    294     bool getOriginUpperLeft() const { return originUpperLeft; }
    295     void setPixelCenterInteger() { pixelCenterInteger = true; }
    296     bool getPixelCenterInteger() const { return pixelCenterInteger; }
    297     void setEarlyFragmentTests() { earlyFragmentTests = true; }
    298     bool getEarlyFragmentTests() const { return earlyFragmentTests; }
    299     bool setDepth(TLayoutDepth d)
    300     {
    301         if (depthLayout != EldNone)
    302             return depthLayout == d;
    303         depthLayout = d;
    304         return true;
    305     }
    306     TLayoutDepth getDepth() const { return depthLayout; }
    307     void setDepthReplacing() { depthReplacing = true; }
    308     bool isDepthReplacing() const { return depthReplacing; }
    309 
    310     void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
    311     unsigned int getBlendEquations() const { return blendEquations; }
    312 
    313     void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
    314     void merge(TInfoSink&, TIntermediate&);
    315     void finalCheck(TInfoSink&);
    316 
    317     void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
    318     bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
    319 
    320     int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
    321     int addUsedOffsets(int binding, int offset, int numOffsets);
    322     bool addUsedConstantId(int id);
    323     int computeTypeLocationSize(const TType&) const;
    324 
    325     bool setXfbBufferStride(int buffer, unsigned stride)
    326     {
    327         if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
    328             return xfbBuffers[buffer].stride == stride;
    329         xfbBuffers[buffer].stride = stride;
    330         return true;
    331     }
    332     int addXfbBufferOffset(const TType&);
    333     unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
    334     static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
    335 
    336 protected:
    337     TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
    338     void error(TInfoSink& infoSink, const char*);
    339     void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
    340     void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
    341     void mergeImplicitArraySizes(TType&, const TType&);
    342     void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
    343     void checkCallGraphCycles(TInfoSink&);
    344     void inOutLocationCheck(TInfoSink&);
    345     TIntermSequence& findLinkerObjects() const;
    346     bool userOutputUsed() const;
    347     static int getBaseAlignmentScalar(const TType&, int& size);
    348     bool isSpecializationOperation(const TIntermOperator&) const;
    349 
    350     const EShLanguage language;  // stage, known at construction time
    351     EShSource source;            // source language, known a bit later
    352     std::string entryPoint;
    353     EProfile profile;
    354     int version;
    355     SpvVersion spvVersion;
    356     TIntermNode* treeRoot;
    357     std::set<std::string> requestedExtensions;  // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
    358     TBuiltInResource resources;
    359     int numMains;
    360     int numErrors;
    361     int numPushConstants;
    362     bool recursive;
    363     int invocations;
    364     int vertices;
    365     TLayoutGeometry inputPrimitive;
    366     TLayoutGeometry outputPrimitive;
    367     bool pixelCenterInteger;
    368     bool originUpperLeft;
    369     TVertexSpacing vertexSpacing;
    370     TVertexOrder vertexOrder;
    371     bool pointMode;
    372     int localSize[3];
    373     int localSizeSpecId[3];
    374     bool earlyFragmentTests;
    375     TLayoutDepth depthLayout;
    376     bool depthReplacing;
    377     int blendEquations;        // an 'or'ing of masks of shifts of TBlendEquationShift
    378     bool xfbMode;
    379     bool multiStream;
    380 
    381     typedef std::list<TCall> TGraph;
    382     TGraph callGraph;
    383 
    384     std::set<TString> ioAccessed;           // set of names of statically read/written I/O that might need extra checking
    385     std::vector<TIoRange> usedIo[4];        // sets of used locations, one for each of in, out, uniform, and buffers
    386     std::vector<TOffsetRange> usedAtomics;  // sets of bindings used by atomic counters
    387     std::vector<TXfbBuffer> xfbBuffers;     // all the data we need to track per xfb buffer
    388     std::unordered_set<int> usedConstantId; // specialization constant ids used
    389 
    390 private:
    391     void operator=(TIntermediate&); // prevent assignments
    392 };
    393 
    394 } // end namespace glslang
    395 
    396 #endif // _LOCAL_INTERMEDIATE_INCLUDED_
    397