Home | History | Annotate | Download | only in MachineIndependent
      1 //
      2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
      3 // Copyright (C) 2016 LunarG, Inc.
      4 // Copyright (C) 2017 ARM Limited.
      5 // Copyright (C) 2015-2018 Google, Inc.
      6 //
      7 // All rights reserved.
      8 //
      9 // Redistribution and use in source and binary forms, with or without
     10 // modification, are permitted provided that the following conditions
     11 // are met:
     12 //
     13 //    Redistributions of source code must retain the above copyright
     14 //    notice, this list of conditions and the following disclaimer.
     15 //
     16 //    Redistributions in binary form must reproduce the above
     17 //    copyright notice, this list of conditions and the following
     18 //    disclaimer in the documentation and/or other materials provided
     19 //    with the distribution.
     20 //
     21 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
     22 //    contributors may be used to endorse or promote products derived
     23 //    from this software without specific prior written permission.
     24 //
     25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     26 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     27 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     28 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     29 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     30 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     31 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     32 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     33 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     35 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36 // POSSIBILITY OF SUCH DAMAGE.
     37 //
     38 
     39 #ifndef _LOCAL_INTERMEDIATE_INCLUDED_
     40 #define _LOCAL_INTERMEDIATE_INCLUDED_
     41 
     42 #include "../Include/intermediate.h"
     43 #include "../Public/ShaderLang.h"
     44 #include "Versions.h"
     45 
     46 #include <string>
     47 #include <vector>
     48 #include <algorithm>
     49 #include <set>
     50 #include <array>
     51 
     52 class TInfoSink;
     53 
     54 namespace glslang {
     55 
     56 struct TMatrixSelector {
     57     int coord1;  // stay agnostic about column/row; this is parse order
     58     int coord2;
     59 };
     60 
     61 typedef int TVectorSelector;
     62 
     63 const int MaxSwizzleSelectors = 4;
     64 
     65 template<typename selectorType>
     66 class TSwizzleSelectors {
     67 public:
     68     TSwizzleSelectors() : size_(0) { }
     69 
     70     void push_back(selectorType comp)
     71     {
     72         if (size_ < MaxSwizzleSelectors)
     73             components[size_++] = comp;
     74     }
     75     void resize(int s)
     76     {
     77         assert(s <= size_);
     78         size_ = s;
     79     }
     80     int size() const { return size_; }
     81     selectorType operator[](int i) const
     82     {
     83         assert(i < MaxSwizzleSelectors);
     84         return components[i];
     85     }
     86 
     87 private:
     88     int size_;
     89     selectorType components[MaxSwizzleSelectors];
     90 };
     91 
     92 //
     93 // Some helper structures for TIntermediate.  Their contents are encapsulated
     94 // by TIntermediate.
     95 //
     96 
     97 // Used for call-graph algorithms for detecting recursion, missing bodies, and dead bodies.
     98 // A "call" is a pair: <caller, callee>.
     99 // There can be duplicates. General assumption is the list is small.
    100 struct TCall {
    101     TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { }
    102     TString caller;
    103     TString callee;
    104     bool visited;
    105     bool currentPath;
    106     bool errorGiven;
    107     int calleeBodyPosition;
    108 };
    109 
    110 // A generic 1-D range.
    111 struct TRange {
    112     TRange(int start, int last) : start(start), last(last) { }
    113     bool overlap(const TRange& rhs) const
    114     {
    115         return last >= rhs.start && start <= rhs.last;
    116     }
    117     int start;
    118     int last;
    119 };
    120 
    121 // An IO range is a 3-D rectangle; the set of (location, component, index) triples all lying
    122 // within the same location range, component range, and index value.  Locations don't alias unless
    123 // all other dimensions of their range overlap.
    124 struct TIoRange {
    125     TIoRange(TRange location, TRange component, TBasicType basicType, int index)
    126         : location(location), component(component), basicType(basicType), index(index) { }
    127     bool overlap(const TIoRange& rhs) const
    128     {
    129         return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index;
    130     }
    131     TRange location;
    132     TRange component;
    133     TBasicType basicType;
    134     int index;
    135 };
    136 
    137 // An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying
    138 // within the same binding and offset range.
    139 struct TOffsetRange {
    140     TOffsetRange(TRange binding, TRange offset)
    141         : binding(binding), offset(offset) { }
    142     bool overlap(const TOffsetRange& rhs) const
    143     {
    144         return binding.overlap(rhs.binding) && offset.overlap(rhs.offset);
    145     }
    146     TRange binding;
    147     TRange offset;
    148 };
    149 
    150 // Things that need to be tracked per xfb buffer.
    151 struct TXfbBuffer {
    152     TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { }
    153     std::vector<TRange> ranges;  // byte offsets that have already been assigned
    154     unsigned int stride;
    155     unsigned int implicitStride;
    156     bool containsDouble;
    157 };
    158 
    159 // Track a set of strings describing how the module was processed.
    160 // Using the form:
    161 //   process arg0 arg1 arg2 ...
    162 //   process arg0 arg1 arg2 ...
    163 // where everything is textual, and there can be zero or more arguments
    164 class TProcesses {
    165 public:
    166     TProcesses() {}
    167     ~TProcesses() {}
    168 
    169     void addProcess(const char* process)
    170     {
    171         processes.push_back(process);
    172     }
    173     void addProcess(const std::string& process)
    174     {
    175         processes.push_back(process);
    176     }
    177     void addArgument(int arg)
    178     {
    179         processes.back().append(" ");
    180         std::string argString = std::to_string(arg);
    181         processes.back().append(argString);
    182     }
    183     void addArgument(const char* arg)
    184     {
    185         processes.back().append(" ");
    186         processes.back().append(arg);
    187     }
    188     void addArgument(const std::string& arg)
    189     {
    190         processes.back().append(" ");
    191         processes.back().append(arg);
    192     }
    193     void addIfNonZero(const char* process, int value)
    194     {
    195         if (value != 0) {
    196             addProcess(process);
    197             addArgument(value);
    198         }
    199     }
    200 
    201     const std::vector<std::string>& getProcesses() const { return processes; }
    202 
    203 private:
    204     std::vector<std::string> processes;
    205 };
    206 
    207 class TSymbolTable;
    208 class TSymbol;
    209 class TVariable;
    210 
    211 #ifdef NV_EXTENSIONS
    212 //
    213 // Texture and Sampler transformation mode.
    214 //
    215 enum ComputeDerivativeMode {
    216     LayoutDerivativeNone,         // default layout as SPV_NV_compute_shader_derivatives not enabled
    217     LayoutDerivativeGroupQuads,   // derivative_group_quadsNV
    218     LayoutDerivativeGroupLinear,  // derivative_group_linearNV
    219 };
    220 #endif
    221 
    222 //
    223 // Set of helper functions to help parse and build the tree.
    224 //
    225 class TIntermediate {
    226 public:
    227     explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
    228         implicitThisName("@this"), implicitCounterName("@count"),
    229         language(l), source(EShSourceNone), profile(p), version(v), treeRoot(0),
    230         numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false),
    231         invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet),
    232         inputPrimitive(ElgNone), outputPrimitive(ElgNone),
    233         pixelCenterInteger(false), originUpperLeft(false),
    234         vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false),
    235         postDepthCoverage(false), depthLayout(EldNone), depthReplacing(false),
    236         hlslFunctionality1(false),
    237         blendEquations(0), xfbMode(false), multiStream(false),
    238 #ifdef NV_EXTENSIONS
    239         layoutOverrideCoverage(false),
    240         geoPassthroughEXT(false),
    241         numShaderRecordNVBlocks(0),
    242         computeDerivativeMode(LayoutDerivativeNone),
    243         primitives(TQualifier::layoutNotSet),
    244         numTaskNVBlocks(0),
    245 #endif
    246         autoMapBindings(false),
    247         autoMapLocations(false),
    248         invertY(false),
    249         flattenUniformArrays(false),
    250         useUnknownFormat(false),
    251         hlslOffsets(false),
    252         useStorageBuffer(false),
    253         useVulkanMemoryModel(false),
    254         hlslIoMapping(false),
    255         textureSamplerTransformMode(EShTexSampTransKeep),
    256         needToLegalize(false),
    257         binaryDoubleOutput(false),
    258         usePhysicalStorageBuffer(false),
    259         uniformLocationBase(0)
    260     {
    261         localSize[0] = 1;
    262         localSize[1] = 1;
    263         localSize[2] = 1;
    264         localSizeSpecId[0] = TQualifier::layoutNotSet;
    265         localSizeSpecId[1] = TQualifier::layoutNotSet;
    266         localSizeSpecId[2] = TQualifier::layoutNotSet;
    267         xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
    268 
    269         shiftBinding.fill(0);
    270     }
    271     void setLimits(const TBuiltInResource& r) { resources = r; }
    272 
    273     bool postProcess(TIntermNode*, EShLanguage);
    274     void output(TInfoSink&, bool tree);
    275     void removeTree();
    276 
    277     void setSource(EShSource s) { source = s; }
    278     EShSource getSource() const { return source; }
    279     void setEntryPointName(const char* ep)
    280     {
    281         entryPointName = ep;
    282         processes.addProcess("entry-point");
    283         processes.addArgument(entryPointName);
    284     }
    285     void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
    286     const std::string& getEntryPointName() const { return entryPointName; }
    287     const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
    288 
    289     void setShiftBinding(TResourceType res, unsigned int shift)
    290     {
    291         shiftBinding[res] = shift;
    292 
    293         const char* name = getResourceName(res);
    294         if (name != nullptr)
    295             processes.addIfNonZero(name, shift);
    296     }
    297 
    298     unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; }
    299 
    300     void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set)
    301     {
    302         if (shift == 0) // ignore if there's no shift: it's a no-op.
    303             return;
    304 
    305         shiftBindingForSet[res][set] = shift;
    306 
    307         const char* name = getResourceName(res);
    308         if (name != nullptr) {
    309             processes.addProcess(name);
    310             processes.addArgument(shift);
    311             processes.addArgument(set);
    312         }
    313     }
    314 
    315     int getShiftBindingForSet(TResourceType res, unsigned int set) const
    316     {
    317         const auto shift = shiftBindingForSet[res].find(set);
    318         return shift == shiftBindingForSet[res].end() ? -1 : shift->second;
    319     }
    320     bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); }
    321 
    322     void setResourceSetBinding(const std::vector<std::string>& shift)
    323     {
    324         resourceSetBinding = shift;
    325         if (shift.size() > 0) {
    326             processes.addProcess("resource-set-binding");
    327             for (int s = 0; s < (int)shift.size(); ++s)
    328                 processes.addArgument(shift[s]);
    329         }
    330     }
    331     const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
    332     void setAutoMapBindings(bool map)
    333     {
    334         autoMapBindings = map;
    335         if (autoMapBindings)
    336             processes.addProcess("auto-map-bindings");
    337     }
    338     bool getAutoMapBindings() const { return autoMapBindings; }
    339     void setAutoMapLocations(bool map)
    340     {
    341         autoMapLocations = map;
    342         if (autoMapLocations)
    343             processes.addProcess("auto-map-locations");
    344     }
    345     bool getAutoMapLocations() const { return autoMapLocations; }
    346     void setInvertY(bool invert)
    347     {
    348         invertY = invert;
    349         if (invertY)
    350             processes.addProcess("invert-y");
    351     }
    352     bool getInvertY() const { return invertY; }
    353 
    354     void setFlattenUniformArrays(bool flatten)
    355     {
    356         flattenUniformArrays = flatten;
    357         if (flattenUniformArrays)
    358             processes.addProcess("flatten-uniform-arrays");
    359     }
    360     bool getFlattenUniformArrays() const { return flattenUniformArrays; }
    361     void setNoStorageFormat(bool b)
    362     {
    363         useUnknownFormat = b;
    364         if (useUnknownFormat)
    365             processes.addProcess("no-storage-format");
    366     }
    367     bool getNoStorageFormat() const { return useUnknownFormat; }
    368     void setHlslOffsets()
    369     {
    370         hlslOffsets = true;
    371         if (hlslOffsets)
    372             processes.addProcess("hlsl-offsets");
    373     }
    374     bool usingHlslOffsets() const { return hlslOffsets; }
    375     void setUseStorageBuffer()
    376     {
    377         useStorageBuffer = true;
    378         processes.addProcess("use-storage-buffer");
    379     }
    380     bool usingStorageBuffer() const { return useStorageBuffer; }
    381     void setHlslIoMapping(bool b)
    382     {
    383         hlslIoMapping = b;
    384         if (hlslIoMapping)
    385             processes.addProcess("hlsl-iomap");
    386     }
    387     bool usingHlslIoMapping() { return hlslIoMapping; }
    388     void setUseVulkanMemoryModel()
    389     {
    390         useVulkanMemoryModel = true;
    391         processes.addProcess("use-vulkan-memory-model");
    392     }
    393     bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
    394     void setUsePhysicalStorageBuffer()
    395     {
    396         usePhysicalStorageBuffer = true;
    397     }
    398     bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
    399 
    400     template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
    401     bool hasCounterBufferName(const TString& name) const {
    402         size_t len = strlen(implicitCounterName);
    403         return name.size() > len &&
    404                name.compare(name.size() - len, len, implicitCounterName) == 0;
    405     }
    406 
    407     void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
    408 
    409     void setVersion(int v) { version = v; }
    410     int getVersion() const { return version; }
    411     void setProfile(EProfile p) { profile = p; }
    412     EProfile getProfile() const { return profile; }
    413     void setSpv(const SpvVersion& s)
    414     {
    415         spvVersion = s;
    416 
    417         // client processes
    418         if (spvVersion.vulkan > 0)
    419             processes.addProcess("client vulkan100");
    420         if (spvVersion.openGl > 0)
    421             processes.addProcess("client opengl100");
    422 
    423         // target-environment processes
    424         if (spvVersion.vulkan > 0)
    425             processes.addProcess("target-env vulkan1.0");
    426         else if (spvVersion.vulkan > 0)
    427             processes.addProcess("target-env vulkanUnknown");
    428         if (spvVersion.openGl > 0)
    429             processes.addProcess("target-env opengl");
    430     }
    431     const SpvVersion& getSpv() const { return spvVersion; }
    432     EShLanguage getStage() const { return language; }
    433     void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
    434     const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
    435 
    436     void setTreeRoot(TIntermNode* r) { treeRoot = r; }
    437     TIntermNode* getTreeRoot() const { return treeRoot; }
    438     void incrementEntryPointCount() { ++numEntryPoints; }
    439     int getNumEntryPoints() const { return numEntryPoints; }
    440     int getNumErrors() const { return numErrors; }
    441     void addPushConstantCount() { ++numPushConstants; }
    442 #ifdef NV_EXTENSIONS
    443     void addShaderRecordNVCount() { ++numShaderRecordNVBlocks; }
    444     void addTaskNVCount() { ++numTaskNVBlocks; }
    445 #endif
    446 
    447     bool isRecursive() const { return recursive; }
    448 
    449     TIntermSymbol* addSymbol(const TVariable&);
    450     TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
    451     TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
    452     TIntermSymbol* addSymbol(const TIntermSymbol&);
    453     TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
    454     std::tuple<TIntermTyped*, TIntermTyped*> addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) const;
    455     TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
    456     void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
    457     TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
    458     TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
    459     TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
    460     TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
    461     TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc);
    462     TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
    463     bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const;
    464     bool isIntegralPromotion(TBasicType from, TBasicType to) const;
    465     bool isFPPromotion(TBasicType from, TBasicType to) const;
    466     bool isIntegralConversion(TBasicType from, TBasicType to) const;
    467     bool isFPConversion(TBasicType from, TBasicType to) const;
    468     bool isFPIntegralConversion(TBasicType from, TBasicType to) const;
    469     TOperator mapTypeToConstructorOp(const TType&) const;
    470     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
    471     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
    472     TIntermAggregate* makeAggregate(TIntermNode* node);
    473     TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
    474     TIntermAggregate* makeAggregate(const TSourceLoc&);
    475     TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
    476     bool areAllChildConst(TIntermAggregate* aggrNode);
    477     TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
    478     TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
    479     TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
    480     TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
    481     TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
    482     TIntermConstantUnion* addConstantUnion(signed char, const TSourceLoc&, bool literal = false) const;
    483     TIntermConstantUnion* addConstantUnion(unsigned char, const TSourceLoc&, bool literal = false) const;
    484     TIntermConstantUnion* addConstantUnion(signed short, const TSourceLoc&, bool literal = false) const;
    485     TIntermConstantUnion* addConstantUnion(unsigned short, const TSourceLoc&, bool literal = false) const;
    486     TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
    487     TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
    488     TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
    489     TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
    490     TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
    491     TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
    492     TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
    493     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
    494     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
    495     TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
    496     TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
    497         const TSourceLoc&, TIntermLoop*&);
    498     TIntermBranch* addBranch(TOperator, const TSourceLoc&);
    499     TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
    500     template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
    501 
    502     // Low level functions to add nodes (no conversions or other higher level transformations)
    503     // If a type is provided, the node's type will be set to it.
    504     TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc) const;
    505     TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, const TType&) const;
    506     TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc) const;
    507     TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc, const TType&) const;
    508 
    509     // Constant folding (in Constant.cpp)
    510     TIntermTyped* fold(TIntermAggregate* aggrNode);
    511     TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
    512     TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
    513     TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& fields, const TSourceLoc&);
    514 
    515     // Tree ops
    516     static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay);
    517 
    518     // Linkage related
    519     void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
    520     void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
    521 
    522     bool setInvocations(int i)
    523     {
    524         if (invocations != TQualifier::layoutNotSet)
    525             return invocations == i;
    526         invocations = i;
    527         return true;
    528     }
    529     int getInvocations() const { return invocations; }
    530     bool setVertices(int m)
    531     {
    532         if (vertices != TQualifier::layoutNotSet)
    533             return vertices == m;
    534         vertices = m;
    535         return true;
    536     }
    537     int getVertices() const { return vertices; }
    538     bool setInputPrimitive(TLayoutGeometry p)
    539     {
    540         if (inputPrimitive != ElgNone)
    541             return inputPrimitive == p;
    542         inputPrimitive = p;
    543         return true;
    544     }
    545     TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
    546     bool setVertexSpacing(TVertexSpacing s)
    547     {
    548         if (vertexSpacing != EvsNone)
    549             return vertexSpacing == s;
    550         vertexSpacing = s;
    551         return true;
    552     }
    553     TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
    554     bool setVertexOrder(TVertexOrder o)
    555     {
    556         if (vertexOrder != EvoNone)
    557             return vertexOrder == o;
    558         vertexOrder = o;
    559         return true;
    560     }
    561     TVertexOrder getVertexOrder() const { return vertexOrder; }
    562     void setPointMode() { pointMode = true; }
    563     bool getPointMode() const { return pointMode; }
    564 
    565     bool setLocalSize(int dim, int size)
    566     {
    567         if (localSize[dim] > 1)
    568             return size == localSize[dim];
    569         localSize[dim] = size;
    570         return true;
    571     }
    572     unsigned int getLocalSize(int dim) const { return localSize[dim]; }
    573 
    574     bool setLocalSizeSpecId(int dim, int id)
    575     {
    576         if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
    577             return id == localSizeSpecId[dim];
    578         localSizeSpecId[dim] = id;
    579         return true;
    580     }
    581     int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
    582 
    583     void setXfbMode() { xfbMode = true; }
    584     bool getXfbMode() const { return xfbMode; }
    585     void setMultiStream() { multiStream = true; }
    586     bool isMultiStream() const { return multiStream; }
    587     bool setOutputPrimitive(TLayoutGeometry p)
    588     {
    589         if (outputPrimitive != ElgNone)
    590             return outputPrimitive == p;
    591         outputPrimitive = p;
    592         return true;
    593     }
    594     TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
    595     void setOriginUpperLeft() { originUpperLeft = true; }
    596     bool getOriginUpperLeft() const { return originUpperLeft; }
    597     void setPixelCenterInteger() { pixelCenterInteger = true; }
    598     bool getPixelCenterInteger() const { return pixelCenterInteger; }
    599     void setEarlyFragmentTests() { earlyFragmentTests = true; }
    600     bool getEarlyFragmentTests() const { return earlyFragmentTests; }
    601     void setPostDepthCoverage() { postDepthCoverage = true; }
    602     bool getPostDepthCoverage() const { return postDepthCoverage; }
    603     bool setDepth(TLayoutDepth d)
    604     {
    605         if (depthLayout != EldNone)
    606             return depthLayout == d;
    607         depthLayout = d;
    608         return true;
    609     }
    610     TLayoutDepth getDepth() const { return depthLayout; }
    611     void setDepthReplacing() { depthReplacing = true; }
    612     bool isDepthReplacing() const { return depthReplacing; }
    613 
    614     void setHlslFunctionality1() { hlslFunctionality1 = true; }
    615     bool getHlslFunctionality1() const { return hlslFunctionality1; }
    616 
    617     void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
    618     unsigned int getBlendEquations() const { return blendEquations; }
    619 
    620     void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
    621     void merge(TInfoSink&, TIntermediate&);
    622     void finalCheck(TInfoSink&, bool keepUncalled);
    623 
    624     void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
    625     bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
    626 
    627     int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
    628     int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision);
    629     int addUsedOffsets(int binding, int offset, int numOffsets);
    630     bool addUsedConstantId(int id);
    631     static int computeTypeLocationSize(const TType&, EShLanguage);
    632     static int computeTypeUniformLocationSize(const TType&);
    633 
    634     bool setXfbBufferStride(int buffer, unsigned stride)
    635     {
    636         if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
    637             return xfbBuffers[buffer].stride == stride;
    638         xfbBuffers[buffer].stride = stride;
    639         return true;
    640     }
    641     unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
    642     int addXfbBufferOffset(const TType&);
    643     unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
    644     static int getBaseAlignmentScalar(const TType&, int& size);
    645     static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
    646     static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
    647     static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
    648     static bool improperStraddle(const TType& type, int size, int offset);
    649     bool promote(TIntermOperator*);
    650 
    651 #ifdef NV_EXTENSIONS
    652     void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
    653     bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
    654     void setGeoPassthroughEXT() { geoPassthroughEXT = true; }
    655     bool getGeoPassthroughEXT() const { return geoPassthroughEXT; }
    656     void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; }
    657     ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; }
    658     bool setPrimitives(int m)
    659     {
    660         if (primitives != TQualifier::layoutNotSet)
    661             return primitives == m;
    662         primitives = m;
    663         return true;
    664     }
    665     int getPrimitives() const { return primitives; }
    666 #endif
    667 
    668     const char* addSemanticName(const TString& name)
    669     {
    670         return semanticNameSet.insert(name).first->c_str();
    671     }
    672 
    673     void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
    674     const std::string& getSourceFile() const { return sourceFile; }
    675     void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
    676     const std::string& getSourceText() const { return sourceText; }
    677     const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
    678     void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
    679     void addProcesses(const std::vector<std::string>& p)
    680     {
    681         for (int i = 0; i < (int)p.size(); ++i)
    682             processes.addProcess(p[i]);
    683     }
    684     void addProcess(const std::string& process) { processes.addProcess(process); }
    685     void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
    686     const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
    687 
    688     void addUniformLocationOverride(const char* nameStr, int location)
    689     {
    690         std::string name = nameStr;
    691         uniformLocationOverrides[name] = location;
    692     }
    693 
    694     int getUniformLocationOverride(const char* nameStr) const
    695     {
    696         std::string name = nameStr;
    697         auto pos = uniformLocationOverrides.find(name);
    698         if (pos == uniformLocationOverrides.end())
    699             return -1;
    700         else
    701             return pos->second;
    702     }
    703 
    704     void setUniformLocationBase(int base) { uniformLocationBase = base; }
    705     int getUniformLocationBase() const { return uniformLocationBase; }
    706 
    707     void setNeedsLegalization() { needToLegalize = true; }
    708     bool needsLegalization() const { return needToLegalize; }
    709 
    710     void setBinaryDoubleOutput() { binaryDoubleOutput = true; }
    711     bool getBinaryDoubleOutput() { return binaryDoubleOutput; }
    712 
    713     const char* const implicitThisName;
    714     const char* const implicitCounterName;
    715 
    716 protected:
    717     TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
    718     void error(TInfoSink& infoSink, const char*);
    719     void warn(TInfoSink& infoSink, const char*);
    720     void mergeCallGraphs(TInfoSink&, TIntermediate&);
    721     void mergeModes(TInfoSink&, TIntermediate&);
    722     void mergeTrees(TInfoSink&, TIntermediate&);
    723     void seedIdMap(TMap<TString, int>& idMap, int& maxId);
    724     void remapIds(const TMap<TString, int>& idMap, int idShift, TIntermediate&);
    725     void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
    726     void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
    727     void mergeImplicitArraySizes(TType&, const TType&);
    728     void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
    729     void checkCallGraphCycles(TInfoSink&);
    730     void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
    731     void inOutLocationCheck(TInfoSink&);
    732     TIntermAggregate* findLinkerObjects() const;
    733     bool userOutputUsed() const;
    734     bool isSpecializationOperation(const TIntermOperator&) const;
    735     bool isNonuniformPropagating(TOperator) const;
    736     bool promoteUnary(TIntermUnary&);
    737     bool promoteBinary(TIntermBinary&);
    738     void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
    739     bool promoteAggregate(TIntermAggregate&);
    740     void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&);
    741     void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
    742     bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&);
    743     void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root);
    744     bool isConversionAllowed(TOperator op, TIntermTyped* node) const;
    745     TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const;
    746     std::tuple<TBasicType, TBasicType> getConversionDestinatonType(TBasicType type0, TBasicType type1, TOperator op) const;
    747     bool extensionRequested(const char *extension) const {return requestedExtensions.find(extension) != requestedExtensions.end();}
    748     static const char* getResourceName(TResourceType);
    749 
    750     const EShLanguage language;  // stage, known at construction time
    751     EShSource source;            // source language, known a bit later
    752     std::string entryPointName;
    753     std::string entryPointMangledName;
    754     typedef std::list<TCall> TGraph;
    755     TGraph callGraph;
    756 
    757     EProfile profile;                           // source profile
    758     int version;                                // source version
    759     SpvVersion spvVersion;
    760     TIntermNode* treeRoot;
    761     std::set<std::string> requestedExtensions;  // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
    762     TBuiltInResource resources;
    763     int numEntryPoints;
    764     int numErrors;
    765     int numPushConstants;
    766     bool recursive;
    767     int invocations;
    768     int vertices;
    769     TLayoutGeometry inputPrimitive;
    770     TLayoutGeometry outputPrimitive;
    771     bool pixelCenterInteger;
    772     bool originUpperLeft;
    773     TVertexSpacing vertexSpacing;
    774     TVertexOrder vertexOrder;
    775     bool pointMode;
    776     int localSize[3];
    777     int localSizeSpecId[3];
    778     bool earlyFragmentTests;
    779     bool postDepthCoverage;
    780     TLayoutDepth depthLayout;
    781     bool depthReplacing;
    782     bool hlslFunctionality1;
    783     int blendEquations;        // an 'or'ing of masks of shifts of TBlendEquationShift
    784     bool xfbMode;
    785     std::vector<TXfbBuffer> xfbBuffers;     // all the data we need to track per xfb buffer
    786     bool multiStream;
    787 
    788 #ifdef NV_EXTENSIONS
    789     bool layoutOverrideCoverage;
    790     bool geoPassthroughEXT;
    791     int numShaderRecordNVBlocks;
    792     ComputeDerivativeMode computeDerivativeMode;
    793     int primitives;
    794     int numTaskNVBlocks;
    795 #endif
    796 
    797     // Base shift values
    798     std::array<unsigned int, EResCount> shiftBinding;
    799 
    800     // Per-descriptor-set shift values
    801     std::array<std::map<int, int>, EResCount> shiftBindingForSet;
    802 
    803     std::vector<std::string> resourceSetBinding;
    804     bool autoMapBindings;
    805     bool autoMapLocations;
    806     bool invertY;
    807     bool flattenUniformArrays;
    808     bool useUnknownFormat;
    809     bool hlslOffsets;
    810     bool useStorageBuffer;
    811     bool useVulkanMemoryModel;
    812     bool hlslIoMapping;
    813 
    814     std::set<TString> ioAccessed;           // set of names of statically read/written I/O that might need extra checking
    815     std::vector<TIoRange> usedIo[4];        // sets of used locations, one for each of in, out, uniform, and buffers
    816     std::vector<TOffsetRange> usedAtomics;  // sets of bindings used by atomic counters
    817     std::unordered_set<int> usedConstantId; // specialization constant ids used
    818     std::set<TString> semanticNameSet;
    819 
    820     EShTextureSamplerTransformMode textureSamplerTransformMode;
    821 
    822     // source code of shader, useful as part of debug information
    823     std::string sourceFile;
    824     std::string sourceText;
    825 
    826     // Included text. First string is a name, second is the included text
    827     std::map<std::string, std::string> includeText;
    828 
    829     // for OpModuleProcessed, or equivalent
    830     TProcesses processes;
    831 
    832     bool needToLegalize;
    833     bool binaryDoubleOutput;
    834     bool usePhysicalStorageBuffer;
    835 
    836     std::unordered_map<std::string, int> uniformLocationOverrides;
    837     int uniformLocationBase;
    838 
    839 private:
    840     void operator=(TIntermediate&); // prevent assignments
    841 };
    842 
    843 } // end namespace glslang
    844 
    845 #endif // _LOCAL_INTERMEDIATE_INCLUDED_
    846