• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TSwizzleSelectors()68     TSwizzleSelectors() : size_(0) { }
69 
push_back(selectorType comp)70     void push_back(selectorType comp)
71     {
72         if (size_ < MaxSwizzleSelectors)
73             components[size_++] = comp;
74     }
resize(int s)75     void resize(int s)
76     {
77         assert(s <= size_);
78         size_ = s;
79     }
size()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 {
TCallTCall101     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 {
TRangeTRange112     TRange(int start, int last) : start(start), last(last) { }
overlapTRange113     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 {
TIoRangeTIoRange125     TIoRange(TRange location, TRange component, TBasicType basicType, int index)
126         : location(location), component(component), basicType(basicType), index(index) { }
overlapTIoRange127     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 {
TOffsetRangeTOffsetRange140     TOffsetRange(TRange binding, TRange offset)
141         : binding(binding), offset(offset) { }
overlapTOffsetRange142     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 {
TXfbBufferTXfbBuffer152     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:
TProcesses()166     TProcesses() {}
~TProcesses()167     ~TProcesses() {}
168 
addProcess(const char * process)169     void addProcess(const char* process)
170     {
171         processes.push_back(process);
172     }
addProcess(const std::string & process)173     void addProcess(const std::string& process)
174     {
175         processes.push_back(process);
176     }
addArgument(int arg)177     void addArgument(int arg)
178     {
179         processes.back().append(" ");
180         std::string argString = std::to_string(arg);
181         processes.back().append(argString);
182     }
addArgument(const char * arg)183     void addArgument(const char* arg)
184     {
185         processes.back().append(" ");
186         processes.back().append(arg);
187     }
addArgument(const std::string & arg)188     void addArgument(const std::string& arg)
189     {
190         processes.back().append(" ");
191         processes.back().append(arg);
192     }
addIfNonZero(const char * process,int value)193     void addIfNonZero(const char* process, int value)
194     {
195         if (value != 0) {
196             addProcess(process);
197             addArgument(value);
198         }
199     }
200 
getProcesses()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     }
setLimits(const TBuiltInResource & r)271     void setLimits(const TBuiltInResource& r) { resources = r; }
272 
273     bool postProcess(TIntermNode*, EShLanguage);
274     void output(TInfoSink&, bool tree);
275     void removeTree();
276 
setSource(EShSource s)277     void setSource(EShSource s) { source = s; }
getSource()278     EShSource getSource() const { return source; }
setEntryPointName(const char * ep)279     void setEntryPointName(const char* ep)
280     {
281         entryPointName = ep;
282         processes.addProcess("entry-point");
283         processes.addArgument(entryPointName);
284     }
setEntryPointMangledName(const char * ep)285     void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
getEntryPointName()286     const std::string& getEntryPointName() const { return entryPointName; }
getEntryPointMangledName()287     const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
288 
setShiftBinding(TResourceType res,unsigned int shift)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 
getShiftBinding(TResourceType res)298     unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; }
299 
setShiftBindingForSet(TResourceType res,unsigned int shift,unsigned int set)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 
getShiftBindingForSet(TResourceType res,unsigned int set)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     }
hasShiftBindingForSet(TResourceType res)320     bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); }
321 
setResourceSetBinding(const std::vector<std::string> & shift)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     }
getResourceSetBinding()331     const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
setAutoMapBindings(bool map)332     void setAutoMapBindings(bool map)
333     {
334         autoMapBindings = map;
335         if (autoMapBindings)
336             processes.addProcess("auto-map-bindings");
337     }
getAutoMapBindings()338     bool getAutoMapBindings() const { return autoMapBindings; }
setAutoMapLocations(bool map)339     void setAutoMapLocations(bool map)
340     {
341         autoMapLocations = map;
342         if (autoMapLocations)
343             processes.addProcess("auto-map-locations");
344     }
getAutoMapLocations()345     bool getAutoMapLocations() const { return autoMapLocations; }
setInvertY(bool invert)346     void setInvertY(bool invert)
347     {
348         invertY = invert;
349         if (invertY)
350             processes.addProcess("invert-y");
351     }
getInvertY()352     bool getInvertY() const { return invertY; }
353 
setFlattenUniformArrays(bool flatten)354     void setFlattenUniformArrays(bool flatten)
355     {
356         flattenUniformArrays = flatten;
357         if (flattenUniformArrays)
358             processes.addProcess("flatten-uniform-arrays");
359     }
getFlattenUniformArrays()360     bool getFlattenUniformArrays() const { return flattenUniformArrays; }
setNoStorageFormat(bool b)361     void setNoStorageFormat(bool b)
362     {
363         useUnknownFormat = b;
364         if (useUnknownFormat)
365             processes.addProcess("no-storage-format");
366     }
getNoStorageFormat()367     bool getNoStorageFormat() const { return useUnknownFormat; }
setHlslOffsets()368     void setHlslOffsets()
369     {
370         hlslOffsets = true;
371         if (hlslOffsets)
372             processes.addProcess("hlsl-offsets");
373     }
usingHlslOffsets()374     bool usingHlslOffsets() const { return hlslOffsets; }
setUseStorageBuffer()375     void setUseStorageBuffer()
376     {
377         useStorageBuffer = true;
378         processes.addProcess("use-storage-buffer");
379     }
usingStorageBuffer()380     bool usingStorageBuffer() const { return useStorageBuffer; }
setHlslIoMapping(bool b)381     void setHlslIoMapping(bool b)
382     {
383         hlslIoMapping = b;
384         if (hlslIoMapping)
385             processes.addProcess("hlsl-iomap");
386     }
usingHlslIoMapping()387     bool usingHlslIoMapping() { return hlslIoMapping; }
setUseVulkanMemoryModel()388     void setUseVulkanMemoryModel()
389     {
390         useVulkanMemoryModel = true;
391         processes.addProcess("use-vulkan-memory-model");
392     }
usingVulkanMemoryModel()393     bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
setUsePhysicalStorageBuffer()394     void setUsePhysicalStorageBuffer()
395     {
396         usePhysicalStorageBuffer = true;
397     }
usingPhysicalStorageBuffer()398     bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
399 
addCounterBufferName(const T & name)400     template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
hasCounterBufferName(const TString & name)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 
setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode)407     void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
408 
setVersion(int v)409     void setVersion(int v) { version = v; }
getVersion()410     int getVersion() const { return version; }
setProfile(EProfile p)411     void setProfile(EProfile p) { profile = p; }
getProfile()412     EProfile getProfile() const { return profile; }
setSpv(const SpvVersion & s)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     }
getSpv()431     const SpvVersion& getSpv() const { return spvVersion; }
getStage()432     EShLanguage getStage() const { return language; }
addRequestedExtension(const char * extension)433     void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
getRequestedExtensions()434     const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
435 
setTreeRoot(TIntermNode * r)436     void setTreeRoot(TIntermNode* r) { treeRoot = r; }
getTreeRoot()437     TIntermNode* getTreeRoot() const { return treeRoot; }
incrementEntryPointCount()438     void incrementEntryPointCount() { ++numEntryPoints; }
getNumEntryPoints()439     int getNumEntryPoints() const { return numEntryPoints; }
getNumErrors()440     int getNumErrors() const { return numErrors; }
addPushConstantCount()441     void addPushConstantCount() { ++numPushConstants; }
442 #ifdef NV_EXTENSIONS
addShaderRecordNVCount()443     void addShaderRecordNVCount() { ++numShaderRecordNVBlocks; }
addTaskNVCount()444     void addTaskNVCount() { ++numTaskNVBlocks; }
445 #endif
446 
isRecursive()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 
setInvocations(int i)522     bool setInvocations(int i)
523     {
524         if (invocations != TQualifier::layoutNotSet)
525             return invocations == i;
526         invocations = i;
527         return true;
528     }
getInvocations()529     int getInvocations() const { return invocations; }
setVertices(int m)530     bool setVertices(int m)
531     {
532         if (vertices != TQualifier::layoutNotSet)
533             return vertices == m;
534         vertices = m;
535         return true;
536     }
getVertices()537     int getVertices() const { return vertices; }
setInputPrimitive(TLayoutGeometry p)538     bool setInputPrimitive(TLayoutGeometry p)
539     {
540         if (inputPrimitive != ElgNone)
541             return inputPrimitive == p;
542         inputPrimitive = p;
543         return true;
544     }
getInputPrimitive()545     TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
setVertexSpacing(TVertexSpacing s)546     bool setVertexSpacing(TVertexSpacing s)
547     {
548         if (vertexSpacing != EvsNone)
549             return vertexSpacing == s;
550         vertexSpacing = s;
551         return true;
552     }
getVertexSpacing()553     TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
setVertexOrder(TVertexOrder o)554     bool setVertexOrder(TVertexOrder o)
555     {
556         if (vertexOrder != EvoNone)
557             return vertexOrder == o;
558         vertexOrder = o;
559         return true;
560     }
getVertexOrder()561     TVertexOrder getVertexOrder() const { return vertexOrder; }
setPointMode()562     void setPointMode() { pointMode = true; }
getPointMode()563     bool getPointMode() const { return pointMode; }
564 
setLocalSize(int dim,int size)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     }
getLocalSize(int dim)572     unsigned int getLocalSize(int dim) const { return localSize[dim]; }
573 
setLocalSizeSpecId(int dim,int id)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     }
getLocalSizeSpecId(int dim)581     int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
582 
setXfbMode()583     void setXfbMode() { xfbMode = true; }
getXfbMode()584     bool getXfbMode() const { return xfbMode; }
setMultiStream()585     void setMultiStream() { multiStream = true; }
isMultiStream()586     bool isMultiStream() const { return multiStream; }
setOutputPrimitive(TLayoutGeometry p)587     bool setOutputPrimitive(TLayoutGeometry p)
588     {
589         if (outputPrimitive != ElgNone)
590             return outputPrimitive == p;
591         outputPrimitive = p;
592         return true;
593     }
getOutputPrimitive()594     TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
setOriginUpperLeft()595     void setOriginUpperLeft() { originUpperLeft = true; }
getOriginUpperLeft()596     bool getOriginUpperLeft() const { return originUpperLeft; }
setPixelCenterInteger()597     void setPixelCenterInteger() { pixelCenterInteger = true; }
getPixelCenterInteger()598     bool getPixelCenterInteger() const { return pixelCenterInteger; }
setEarlyFragmentTests()599     void setEarlyFragmentTests() { earlyFragmentTests = true; }
getEarlyFragmentTests()600     bool getEarlyFragmentTests() const { return earlyFragmentTests; }
setPostDepthCoverage()601     void setPostDepthCoverage() { postDepthCoverage = true; }
getPostDepthCoverage()602     bool getPostDepthCoverage() const { return postDepthCoverage; }
setDepth(TLayoutDepth d)603     bool setDepth(TLayoutDepth d)
604     {
605         if (depthLayout != EldNone)
606             return depthLayout == d;
607         depthLayout = d;
608         return true;
609     }
getDepth()610     TLayoutDepth getDepth() const { return depthLayout; }
setDepthReplacing()611     void setDepthReplacing() { depthReplacing = true; }
isDepthReplacing()612     bool isDepthReplacing() const { return depthReplacing; }
613 
setHlslFunctionality1()614     void setHlslFunctionality1() { hlslFunctionality1 = true; }
getHlslFunctionality1()615     bool getHlslFunctionality1() const { return hlslFunctionality1; }
616 
addBlendEquation(TBlendEquationShift b)617     void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
getBlendEquations()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 
addIoAccessed(const TString & name)624     void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
inIoAccessed(const TString & 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 
setXfbBufferStride(int buffer,unsigned stride)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     }
getXfbStride(int buffer)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
setLayoutOverrideCoverage()652     void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
getLayoutOverrideCoverage()653     bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
setGeoPassthroughEXT()654     void setGeoPassthroughEXT() { geoPassthroughEXT = true; }
getGeoPassthroughEXT()655     bool getGeoPassthroughEXT() const { return geoPassthroughEXT; }
setLayoutDerivativeMode(ComputeDerivativeMode mode)656     void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; }
getLayoutDerivativeModeNone()657     ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; }
setPrimitives(int m)658     bool setPrimitives(int m)
659     {
660         if (primitives != TQualifier::layoutNotSet)
661             return primitives == m;
662         primitives = m;
663         return true;
664     }
getPrimitives()665     int getPrimitives() const { return primitives; }
666 #endif
667 
addSemanticName(const TString & name)668     const char* addSemanticName(const TString& name)
669     {
670         return semanticNameSet.insert(name).first->c_str();
671     }
672 
setSourceFile(const char * file)673     void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
getSourceFile()674     const std::string& getSourceFile() const { return sourceFile; }
addSourceText(const char * text,size_t len)675     void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
getSourceText()676     const std::string& getSourceText() const { return sourceText; }
getIncludeText()677     const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
addIncludeText(const char * name,const char * text,size_t len)678     void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
addProcesses(const std::vector<std::string> & p)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     }
addProcess(const std::string & process)684     void addProcess(const std::string& process) { processes.addProcess(process); }
addProcessArgument(const std::string & arg)685     void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
getProcesses()686     const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
687 
addUniformLocationOverride(const char * nameStr,int location)688     void addUniformLocationOverride(const char* nameStr, int location)
689     {
690         std::string name = nameStr;
691         uniformLocationOverrides[name] = location;
692     }
693 
getUniformLocationOverride(const char * nameStr)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 
setUniformLocationBase(int base)704     void setUniformLocationBase(int base) { uniformLocationBase = base; }
getUniformLocationBase()705     int getUniformLocationBase() const { return uniformLocationBase; }
706 
setNeedsLegalization()707     void setNeedsLegalization() { needToLegalize = true; }
needsLegalization()708     bool needsLegalization() const { return needToLegalize; }
709 
setBinaryDoubleOutput()710     void setBinaryDoubleOutput() { binaryDoubleOutput = true; }
getBinaryDoubleOutput()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;
extensionRequested(const char * extension)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