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 #ifndef GLSLANG_WEB
151 // Things that need to be tracked per xfb buffer.
152 struct TXfbBuffer {
TXfbBufferTXfbBuffer153     TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), contains64BitType(false),
154                    contains32BitType(false), contains16BitType(false) { }
155     std::vector<TRange> ranges;  // byte offsets that have already been assigned
156     unsigned int stride;
157     unsigned int implicitStride;
158     bool contains64BitType;
159     bool contains32BitType;
160     bool contains16BitType;
161 };
162 #endif
163 
164 // Track a set of strings describing how the module was processed.
165 // This includes command line options, transforms, etc., ideally inclusive enough
166 // to reproduce the steps used to transform the input source to the output.
167 // E.g., see SPIR-V OpModuleProcessed.
168 // Each "process" or "transform" uses is expressed in the form:
169 //   process arg0 arg1 arg2 ...
170 //   process arg0 arg1 arg2 ...
171 // where everything is textual, and there can be zero or more arguments
172 class TProcesses {
173 public:
TProcesses()174     TProcesses() {}
~TProcesses()175     ~TProcesses() {}
176 
addProcess(const char * process)177     void addProcess(const char* process)
178     {
179         processes.push_back(process);
180     }
addProcess(const std::string & process)181     void addProcess(const std::string& process)
182     {
183         processes.push_back(process);
184     }
addArgument(int arg)185     void addArgument(int arg)
186     {
187         processes.back().append(" ");
188         std::string argString = std::to_string(arg);
189         processes.back().append(argString);
190     }
addArgument(const char * arg)191     void addArgument(const char* arg)
192     {
193         processes.back().append(" ");
194         processes.back().append(arg);
195     }
addArgument(const std::string & arg)196     void addArgument(const std::string& arg)
197     {
198         processes.back().append(" ");
199         processes.back().append(arg);
200     }
addIfNonZero(const char * process,int value)201     void addIfNonZero(const char* process, int value)
202     {
203         if (value != 0) {
204             addProcess(process);
205             addArgument(value);
206         }
207     }
208 
getProcesses()209     const std::vector<std::string>& getProcesses() const { return processes; }
210 
211 private:
212     std::vector<std::string> processes;
213 };
214 
215 class TSymbolTable;
216 class TSymbol;
217 class TVariable;
218 
219 //
220 // Texture and Sampler transformation mode.
221 //
222 enum ComputeDerivativeMode {
223     LayoutDerivativeNone,         // default layout as SPV_NV_compute_shader_derivatives not enabled
224     LayoutDerivativeGroupQuads,   // derivative_group_quadsNV
225     LayoutDerivativeGroupLinear,  // derivative_group_linearNV
226 };
227 
228 class TIdMaps {
229 public:
230     TMap<TString, int>& operator[](int i) { return maps[i]; }
231     const TMap<TString, int>& operator[](int i) const { return maps[i]; }
232 private:
233     TMap<TString, int> maps[EsiCount];
234 };
235 
236 class TNumericFeatures {
237 public:
TNumericFeatures()238     TNumericFeatures() : features(0) { }
239     TNumericFeatures(const TNumericFeatures&) = delete;
240     TNumericFeatures& operator=(const TNumericFeatures&) = delete;
241     typedef enum : unsigned int {
242         shader_explicit_arithmetic_types          = 1 << 0,
243         shader_explicit_arithmetic_types_int8     = 1 << 1,
244         shader_explicit_arithmetic_types_int16    = 1 << 2,
245         shader_explicit_arithmetic_types_int32    = 1 << 3,
246         shader_explicit_arithmetic_types_int64    = 1 << 4,
247         shader_explicit_arithmetic_types_float16  = 1 << 5,
248         shader_explicit_arithmetic_types_float32  = 1 << 6,
249         shader_explicit_arithmetic_types_float64  = 1 << 7,
250         shader_implicit_conversions               = 1 << 8,
251         gpu_shader_fp64                           = 1 << 9,
252         gpu_shader_int16                          = 1 << 10,
253         gpu_shader_half_float                     = 1 << 11,
254     } feature;
insert(feature f)255     void insert(feature f) { features |= f; }
erase(feature f)256     void erase(feature f) { features &= ~f; }
contains(feature f)257     bool contains(feature f) const { return (features & f) != 0; }
258 private:
259     unsigned int features;
260 };
261 
262 // MustBeAssigned wraps a T, asserting that it has been assigned with
263 // operator =() before attempting to read with operator T() or operator ->().
264 // Used to catch cases where fields are read before they have been assigned.
265 template<typename T>
266 class MustBeAssigned
267 {
268 public:
269     MustBeAssigned() = default;
MustBeAssigned(const T & v)270     MustBeAssigned(const T& v) : value(v) {}
271     operator const T&() const { assert(isSet); return value; }
272     const T* operator ->() const { assert(isSet); return &value; }
273     MustBeAssigned& operator = (const T& v) { value = v; isSet = true; return *this; }
274 private:
275     T value;
276     bool isSet = false;
277 };
278 
279 //
280 // Set of helper functions to help parse and build the tree.
281 //
282 class TIntermediate {
283 public:
284     explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
language(l)285         language(l),
286 #ifndef GLSLANG_ANGLE
287         profile(p), version(v),
288 #endif
289         treeRoot(0),
290         resources(TBuiltInResource{}),
291         numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false),
292         invertY(false),
293         useStorageBuffer(false),
294         nanMinMaxClamp(false),
295         depthReplacing(false)
296 #ifndef GLSLANG_WEB
297         ,
298         implicitThisName("@this"), implicitCounterName("@count"),
299         source(EShSourceNone),
300         useVulkanMemoryModel(false),
301         invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet),
302         inputPrimitive(ElgNone), outputPrimitive(ElgNone),
303         pixelCenterInteger(false), originUpperLeft(false),
304         vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false),
305         postDepthCoverage(false), depthLayout(EldNone),
306         hlslFunctionality1(false),
307         blendEquations(0), xfbMode(false), multiStream(false),
308         layoutOverrideCoverage(false),
309         geoPassthroughEXT(false),
310         numShaderRecordBlocks(0),
311         computeDerivativeMode(LayoutDerivativeNone),
312         primitives(TQualifier::layoutNotSet),
313         numTaskNVBlocks(0),
314         layoutPrimitiveCulling(false),
315         autoMapBindings(false),
316         autoMapLocations(false),
317         flattenUniformArrays(false),
318         useUnknownFormat(false),
319         hlslOffsets(false),
320         hlslIoMapping(false),
321         useVariablePointers(false),
322         textureSamplerTransformMode(EShTexSampTransKeep),
323         needToLegalize(false),
324         binaryDoubleOutput(false),
325         usePhysicalStorageBuffer(false),
326         uniformLocationBase(0)
327 #endif
328     {
329         localSize[0] = 1;
330         localSize[1] = 1;
331         localSize[2] = 1;
332         localSizeNotDefault[0] = false;
333         localSizeNotDefault[1] = false;
334         localSizeNotDefault[2] = false;
335         localSizeSpecId[0] = TQualifier::layoutNotSet;
336         localSizeSpecId[1] = TQualifier::layoutNotSet;
337         localSizeSpecId[2] = TQualifier::layoutNotSet;
338 #ifndef GLSLANG_WEB
339         xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
340         shiftBinding.fill(0);
341 #endif
342     }
343 
setVersion(int v)344     void setVersion(int v)
345     {
346 #ifndef GLSLANG_ANGLE
347         version = v;
348 #endif
349     }
setProfile(EProfile p)350     void setProfile(EProfile p)
351     {
352 #ifndef GLSLANG_ANGLE
353         profile = p;
354 #endif
355     }
356 
getVersion()357     int getVersion() const { return version; }
getProfile()358     EProfile getProfile() const { return profile; }
setSpv(const SpvVersion & s)359     void setSpv(const SpvVersion& s)
360     {
361         spvVersion = s;
362 
363         // client processes
364         if (spvVersion.vulkan > 0)
365             processes.addProcess("client vulkan100");
366         if (spvVersion.openGl > 0)
367             processes.addProcess("client opengl100");
368 
369         // target SPV
370         switch (spvVersion.spv) {
371         case 0:
372             break;
373         case EShTargetSpv_1_0:
374             break;
375         case EShTargetSpv_1_1:
376             processes.addProcess("target-env spirv1.1");
377             break;
378         case EShTargetSpv_1_2:
379             processes.addProcess("target-env spirv1.2");
380             break;
381         case EShTargetSpv_1_3:
382             processes.addProcess("target-env spirv1.3");
383             break;
384         case EShTargetSpv_1_4:
385             processes.addProcess("target-env spirv1.4");
386             break;
387         case EShTargetSpv_1_5:
388             processes.addProcess("target-env spirv1.5");
389             break;
390         default:
391             processes.addProcess("target-env spirvUnknown");
392             break;
393         }
394 
395         // target-environment processes
396         switch (spvVersion.vulkan) {
397         case 0:
398             break;
399         case EShTargetVulkan_1_0:
400             processes.addProcess("target-env vulkan1.0");
401             break;
402         case EShTargetVulkan_1_1:
403             processes.addProcess("target-env vulkan1.1");
404             break;
405         case EShTargetVulkan_1_2:
406             processes.addProcess("target-env vulkan1.2");
407             break;
408         default:
409             processes.addProcess("target-env vulkanUnknown");
410             break;
411         }
412         if (spvVersion.openGl > 0)
413             processes.addProcess("target-env opengl");
414     }
getSpv()415     const SpvVersion& getSpv() const { return spvVersion; }
getStage()416     EShLanguage getStage() const { return language; }
addRequestedExtension(const char * extension)417     void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
getRequestedExtensions()418     const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
419 
setTreeRoot(TIntermNode * r)420     void setTreeRoot(TIntermNode* r) { treeRoot = r; }
getTreeRoot()421     TIntermNode* getTreeRoot() const { return treeRoot; }
incrementEntryPointCount()422     void incrementEntryPointCount() { ++numEntryPoints; }
getNumEntryPoints()423     int getNumEntryPoints() const { return numEntryPoints; }
getNumErrors()424     int getNumErrors() const { return numErrors; }
addPushConstantCount()425     void addPushConstantCount() { ++numPushConstants; }
setLimits(const TBuiltInResource & r)426     void setLimits(const TBuiltInResource& r) { resources = r; }
getLimits()427     const TBuiltInResource& getLimits() const { return resources; }
428 
429     bool postProcess(TIntermNode*, EShLanguage);
430     void removeTree();
431 
setEntryPointName(const char * ep)432     void setEntryPointName(const char* ep)
433     {
434         entryPointName = ep;
435         processes.addProcess("entry-point");
436         processes.addArgument(entryPointName);
437     }
setEntryPointMangledName(const char * ep)438     void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
getEntryPointName()439     const std::string& getEntryPointName() const { return entryPointName; }
getEntryPointMangledName()440     const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
441 
setInvertY(bool invert)442     void setInvertY(bool invert)
443     {
444         invertY = invert;
445         if (invertY)
446             processes.addProcess("invert-y");
447     }
getInvertY()448     bool getInvertY() const { return invertY; }
449 
450 #ifdef ENABLE_HLSL
setSource(EShSource s)451     void setSource(EShSource s) { source = s; }
getSource()452     EShSource getSource() const { return source; }
453 #else
setSource(EShSource s)454     void setSource(EShSource s) { assert(s == EShSourceGlsl); (void)s; }
getSource()455     EShSource getSource() const { return EShSourceGlsl; }
456 #endif
457 
isRecursive()458     bool isRecursive() const { return recursive; }
459 
460     TIntermSymbol* addSymbol(const TVariable&);
461     TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
462     TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
463     TIntermSymbol* addSymbol(const TIntermSymbol&);
464     TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
465     std::tuple<TIntermTyped*, TIntermTyped*> addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1);
466     TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
467     TIntermTyped* addConversion(TBasicType convertTo, TIntermTyped* node) const;
468     void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
469     TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
470     TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
471     TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
472     TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&);
473     TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, const TSourceLoc&);
474     TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
475     bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const;
476     bool isIntegralPromotion(TBasicType from, TBasicType to) const;
477     bool isFPPromotion(TBasicType from, TBasicType to) const;
478     bool isIntegralConversion(TBasicType from, TBasicType to) const;
479     bool isFPConversion(TBasicType from, TBasicType to) const;
480     bool isFPIntegralConversion(TBasicType from, TBasicType to) const;
481     TOperator mapTypeToConstructorOp(const TType&) const;
482     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
483     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
484     TIntermAggregate* makeAggregate(TIntermNode* node);
485     TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
486     TIntermAggregate* makeAggregate(const TSourceLoc&);
487     TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, const TSourceLoc&);
488     bool areAllChildConst(TIntermAggregate* aggrNode);
489     TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
490     TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
491     TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
492     TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
493     TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
494     TIntermConstantUnion* addConstantUnion(signed char, const TSourceLoc&, bool literal = false) const;
495     TIntermConstantUnion* addConstantUnion(unsigned char, const TSourceLoc&, bool literal = false) const;
496     TIntermConstantUnion* addConstantUnion(signed short, const TSourceLoc&, bool literal = false) const;
497     TIntermConstantUnion* addConstantUnion(unsigned short, const TSourceLoc&, bool literal = false) const;
498     TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
499     TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
500     TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
501     TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
502     TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
503     TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
504     TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
505     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
506     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
507     TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
508     TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
509         const TSourceLoc&, TIntermLoop*&);
510     TIntermBranch* addBranch(TOperator, const TSourceLoc&);
511     TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
512     template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
513 
514     // Low level functions to add nodes (no conversions or other higher level transformations)
515     // If a type is provided, the node's type will be set to it.
516     TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&) const;
517     TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&,
518         const TType&) const;
519     TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&) const;
520     TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&, const TType&) const;
521 
522     // Constant folding (in Constant.cpp)
523     TIntermTyped* fold(TIntermAggregate* aggrNode);
524     TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
525     TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
526     TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& fields, const TSourceLoc&);
527 
528     // Tree ops
529     static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay);
530 
531     // Linkage related
532     void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
533     void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
534 
setUseStorageBuffer()535     void setUseStorageBuffer() { useStorageBuffer = true; }
usingStorageBuffer()536     bool usingStorageBuffer() const { return useStorageBuffer; }
setDepthReplacing()537     void setDepthReplacing() { depthReplacing = true; }
isDepthReplacing()538     bool isDepthReplacing() const { return depthReplacing; }
setLocalSize(int dim,int size)539     bool setLocalSize(int dim, int size)
540     {
541         if (localSizeNotDefault[dim])
542             return size == localSize[dim];
543         localSizeNotDefault[dim] = true;
544         localSize[dim] = size;
545         return true;
546     }
getLocalSize(int dim)547     unsigned int getLocalSize(int dim) const { return localSize[dim]; }
setLocalSizeSpecId(int dim,int id)548     bool setLocalSizeSpecId(int dim, int id)
549     {
550         if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
551             return id == localSizeSpecId[dim];
552         localSizeSpecId[dim] = id;
553         return true;
554     }
getLocalSizeSpecId(int dim)555     int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
556 #ifdef GLSLANG_WEB
output(TInfoSink &,bool tree)557     void output(TInfoSink&, bool tree) { }
558 
isEsProfile()559     bool isEsProfile() const { return false; }
getXfbMode()560     bool getXfbMode() const { return false; }
isMultiStream()561     bool isMultiStream() const { return false; }
getOutputPrimitive()562     TLayoutGeometry getOutputPrimitive() const { return ElgNone; }
getPostDepthCoverage()563     bool getPostDepthCoverage() const { return false; }
getEarlyFragmentTests()564     bool getEarlyFragmentTests() const { return false; }
getDepth()565     TLayoutDepth getDepth() const { return EldNone; }
getPixelCenterInteger()566     bool getPixelCenterInteger() const { return false; }
setOriginUpperLeft()567     void setOriginUpperLeft() { }
getOriginUpperLeft()568     bool getOriginUpperLeft() const { return true; }
getInterlockOrdering()569     TInterlockOrdering getInterlockOrdering() const { return EioNone; }
570 
getAutoMapBindings()571     bool getAutoMapBindings() const { return false; }
getAutoMapLocations()572     bool getAutoMapLocations() const { return false; }
getNumPushConstants()573     int getNumPushConstants() const { return 0; }
addShaderRecordCount()574     void addShaderRecordCount() { }
addTaskNVCount()575     void addTaskNVCount() { }
setUseVulkanMemoryModel()576     void setUseVulkanMemoryModel() { }
usingVulkanMemoryModel()577     bool usingVulkanMemoryModel() const { return false; }
usingPhysicalStorageBuffer()578     bool usingPhysicalStorageBuffer() const { return false; }
usingVariablePointers()579     bool usingVariablePointers() const { return false; }
getXfbStride(int buffer)580     unsigned getXfbStride(int buffer) const { return 0; }
hasLayoutDerivativeModeNone()581     bool hasLayoutDerivativeModeNone() const { return false; }
getLayoutDerivativeModeNone()582     ComputeDerivativeMode getLayoutDerivativeModeNone() const { return LayoutDerivativeNone; }
583 #else
584     void output(TInfoSink&, bool tree);
585 
isEsProfile()586     bool isEsProfile() const { return profile == EEsProfile; }
587 
setShiftBinding(TResourceType res,unsigned int shift)588     void setShiftBinding(TResourceType res, unsigned int shift)
589     {
590         shiftBinding[res] = shift;
591 
592         const char* name = getResourceName(res);
593         if (name != nullptr)
594             processes.addIfNonZero(name, shift);
595     }
596 
getShiftBinding(TResourceType res)597     unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; }
598 
setShiftBindingForSet(TResourceType res,unsigned int shift,unsigned int set)599     void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set)
600     {
601         if (shift == 0) // ignore if there's no shift: it's a no-op.
602             return;
603 
604         shiftBindingForSet[res][set] = shift;
605 
606         const char* name = getResourceName(res);
607         if (name != nullptr) {
608             processes.addProcess(name);
609             processes.addArgument(shift);
610             processes.addArgument(set);
611         }
612     }
613 
getShiftBindingForSet(TResourceType res,unsigned int set)614     int getShiftBindingForSet(TResourceType res, unsigned int set) const
615     {
616         const auto shift = shiftBindingForSet[res].find(set);
617         return shift == shiftBindingForSet[res].end() ? -1 : shift->second;
618     }
hasShiftBindingForSet(TResourceType res)619     bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); }
620 
setResourceSetBinding(const std::vector<std::string> & shift)621     void setResourceSetBinding(const std::vector<std::string>& shift)
622     {
623         resourceSetBinding = shift;
624         if (shift.size() > 0) {
625             processes.addProcess("resource-set-binding");
626             for (int s = 0; s < (int)shift.size(); ++s)
627                 processes.addArgument(shift[s]);
628         }
629     }
getResourceSetBinding()630     const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
setAutoMapBindings(bool map)631     void setAutoMapBindings(bool map)
632     {
633         autoMapBindings = map;
634         if (autoMapBindings)
635             processes.addProcess("auto-map-bindings");
636     }
getAutoMapBindings()637     bool getAutoMapBindings() const { return autoMapBindings; }
setAutoMapLocations(bool map)638     void setAutoMapLocations(bool map)
639     {
640         autoMapLocations = map;
641         if (autoMapLocations)
642             processes.addProcess("auto-map-locations");
643     }
getAutoMapLocations()644     bool getAutoMapLocations() const { return autoMapLocations; }
645 
646 #ifdef ENABLE_HLSL
setFlattenUniformArrays(bool flatten)647     void setFlattenUniformArrays(bool flatten)
648     {
649         flattenUniformArrays = flatten;
650         if (flattenUniformArrays)
651             processes.addProcess("flatten-uniform-arrays");
652     }
getFlattenUniformArrays()653     bool getFlattenUniformArrays() const { return flattenUniformArrays; }
654 #endif
setNoStorageFormat(bool b)655     void setNoStorageFormat(bool b)
656     {
657         useUnknownFormat = b;
658         if (useUnknownFormat)
659             processes.addProcess("no-storage-format");
660     }
getNoStorageFormat()661     bool getNoStorageFormat() const { return useUnknownFormat; }
setUseVulkanMemoryModel()662     void setUseVulkanMemoryModel()
663     {
664         useVulkanMemoryModel = true;
665         processes.addProcess("use-vulkan-memory-model");
666     }
usingVulkanMemoryModel()667     bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
setUsePhysicalStorageBuffer()668     void setUsePhysicalStorageBuffer()
669     {
670         usePhysicalStorageBuffer = true;
671     }
usingPhysicalStorageBuffer()672     bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
setUseVariablePointers()673     void setUseVariablePointers()
674     {
675         useVariablePointers = true;
676         processes.addProcess("use-variable-pointers");
677     }
usingVariablePointers()678     bool usingVariablePointers() const { return useVariablePointers; }
679 
680 #ifdef ENABLE_HLSL
addCounterBufferName(const T & name)681     template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
hasCounterBufferName(const TString & name)682     bool hasCounterBufferName(const TString& name) const {
683         size_t len = strlen(implicitCounterName);
684         return name.size() > len &&
685                name.compare(name.size() - len, len, implicitCounterName) == 0;
686     }
687 #endif
688 
setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode)689     void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
getNumPushConstants()690     int getNumPushConstants() const { return numPushConstants; }
addShaderRecordCount()691     void addShaderRecordCount() { ++numShaderRecordBlocks; }
addTaskNVCount()692     void addTaskNVCount() { ++numTaskNVBlocks; }
693 
setInvocations(int i)694     bool setInvocations(int i)
695     {
696         if (invocations != TQualifier::layoutNotSet)
697             return invocations == i;
698         invocations = i;
699         return true;
700     }
getInvocations()701     int getInvocations() const { return invocations; }
setVertices(int m)702     bool setVertices(int m)
703     {
704         if (vertices != TQualifier::layoutNotSet)
705             return vertices == m;
706         vertices = m;
707         return true;
708     }
getVertices()709     int getVertices() const { return vertices; }
setInputPrimitive(TLayoutGeometry p)710     bool setInputPrimitive(TLayoutGeometry p)
711     {
712         if (inputPrimitive != ElgNone)
713             return inputPrimitive == p;
714         inputPrimitive = p;
715         return true;
716     }
getInputPrimitive()717     TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
setVertexSpacing(TVertexSpacing s)718     bool setVertexSpacing(TVertexSpacing s)
719     {
720         if (vertexSpacing != EvsNone)
721             return vertexSpacing == s;
722         vertexSpacing = s;
723         return true;
724     }
getVertexSpacing()725     TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
setVertexOrder(TVertexOrder o)726     bool setVertexOrder(TVertexOrder o)
727     {
728         if (vertexOrder != EvoNone)
729             return vertexOrder == o;
730         vertexOrder = o;
731         return true;
732     }
getVertexOrder()733     TVertexOrder getVertexOrder() const { return vertexOrder; }
setPointMode()734     void setPointMode() { pointMode = true; }
getPointMode()735     bool getPointMode() const { return pointMode; }
736 
setInterlockOrdering(TInterlockOrdering o)737     bool setInterlockOrdering(TInterlockOrdering o)
738     {
739         if (interlockOrdering != EioNone)
740             return interlockOrdering == o;
741         interlockOrdering = o;
742         return true;
743     }
getInterlockOrdering()744     TInterlockOrdering getInterlockOrdering() const { return interlockOrdering; }
745 
setXfbMode()746     void setXfbMode() { xfbMode = true; }
getXfbMode()747     bool getXfbMode() const { return xfbMode; }
setMultiStream()748     void setMultiStream() { multiStream = true; }
isMultiStream()749     bool isMultiStream() const { return multiStream; }
setOutputPrimitive(TLayoutGeometry p)750     bool setOutputPrimitive(TLayoutGeometry p)
751     {
752         if (outputPrimitive != ElgNone)
753             return outputPrimitive == p;
754         outputPrimitive = p;
755         return true;
756     }
getOutputPrimitive()757     TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
setPostDepthCoverage()758     void setPostDepthCoverage() { postDepthCoverage = true; }
getPostDepthCoverage()759     bool getPostDepthCoverage() const { return postDepthCoverage; }
setEarlyFragmentTests()760     void setEarlyFragmentTests() { earlyFragmentTests = true; }
getEarlyFragmentTests()761     bool getEarlyFragmentTests() const { return earlyFragmentTests; }
setDepth(TLayoutDepth d)762     bool setDepth(TLayoutDepth d)
763     {
764         if (depthLayout != EldNone)
765             return depthLayout == d;
766         depthLayout = d;
767         return true;
768     }
getDepth()769     TLayoutDepth getDepth() const { return depthLayout; }
setOriginUpperLeft()770     void setOriginUpperLeft() { originUpperLeft = true; }
getOriginUpperLeft()771     bool getOriginUpperLeft() const { return originUpperLeft; }
setPixelCenterInteger()772     void setPixelCenterInteger() { pixelCenterInteger = true; }
getPixelCenterInteger()773     bool getPixelCenterInteger() const { return pixelCenterInteger; }
addBlendEquation(TBlendEquationShift b)774     void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
getBlendEquations()775     unsigned int getBlendEquations() const { return blendEquations; }
setXfbBufferStride(int buffer,unsigned stride)776     bool setXfbBufferStride(int buffer, unsigned stride)
777     {
778         if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
779             return xfbBuffers[buffer].stride == stride;
780         xfbBuffers[buffer].stride = stride;
781         return true;
782     }
getXfbStride(int buffer)783     unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
784     int addXfbBufferOffset(const TType&);
785     unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const;
786     unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType) const;
setLayoutOverrideCoverage()787     void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
getLayoutOverrideCoverage()788     bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
setGeoPassthroughEXT()789     void setGeoPassthroughEXT() { geoPassthroughEXT = true; }
getGeoPassthroughEXT()790     bool getGeoPassthroughEXT() const { return geoPassthroughEXT; }
setLayoutDerivativeMode(ComputeDerivativeMode mode)791     void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; }
hasLayoutDerivativeModeNone()792     bool hasLayoutDerivativeModeNone() const { return computeDerivativeMode != LayoutDerivativeNone; }
getLayoutDerivativeModeNone()793     ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; }
setLayoutPrimitiveCulling()794     void setLayoutPrimitiveCulling() { layoutPrimitiveCulling = true; }
getLayoutPrimitiveCulling()795     bool getLayoutPrimitiveCulling() const { return layoutPrimitiveCulling; }
setPrimitives(int m)796     bool setPrimitives(int m)
797     {
798         if (primitives != TQualifier::layoutNotSet)
799             return primitives == m;
800         primitives = m;
801         return true;
802     }
getPrimitives()803     int getPrimitives() const { return primitives; }
addSemanticName(const TString & name)804     const char* addSemanticName(const TString& name)
805     {
806         return semanticNameSet.insert(name).first->c_str();
807     }
addUniformLocationOverride(const char * nameStr,int location)808     void addUniformLocationOverride(const char* nameStr, int location)
809     {
810         std::string name = nameStr;
811         uniformLocationOverrides[name] = location;
812     }
813 
getUniformLocationOverride(const char * nameStr)814     int getUniformLocationOverride(const char* nameStr) const
815     {
816         std::string name = nameStr;
817         auto pos = uniformLocationOverrides.find(name);
818         if (pos == uniformLocationOverrides.end())
819             return -1;
820         else
821             return pos->second;
822     }
823 
setUniformLocationBase(int base)824     void setUniformLocationBase(int base) { uniformLocationBase = base; }
getUniformLocationBase()825     int getUniformLocationBase() const { return uniformLocationBase; }
826 
setNeedsLegalization()827     void setNeedsLegalization() { needToLegalize = true; }
needsLegalization()828     bool needsLegalization() const { return needToLegalize; }
829 
setBinaryDoubleOutput()830     void setBinaryDoubleOutput() { binaryDoubleOutput = true; }
getBinaryDoubleOutput()831     bool getBinaryDoubleOutput() { return binaryDoubleOutput; }
832 #endif // GLSLANG_WEB
833 
834 #ifdef ENABLE_HLSL
setHlslFunctionality1()835     void setHlslFunctionality1() { hlslFunctionality1 = true; }
getHlslFunctionality1()836     bool getHlslFunctionality1() const { return hlslFunctionality1; }
setHlslOffsets()837     void setHlslOffsets()
838     {
839         hlslOffsets = true;
840         if (hlslOffsets)
841             processes.addProcess("hlsl-offsets");
842     }
usingHlslOffsets()843     bool usingHlslOffsets() const { return hlslOffsets; }
setHlslIoMapping(bool b)844     void setHlslIoMapping(bool b)
845     {
846         hlslIoMapping = b;
847         if (hlslIoMapping)
848             processes.addProcess("hlsl-iomap");
849     }
usingHlslIoMapping()850     bool usingHlslIoMapping() { return hlslIoMapping; }
851 #else
getHlslFunctionality1()852     bool getHlslFunctionality1() const { return false; }
usingHlslOffsets()853     bool usingHlslOffsets() const { return false; }
usingHlslIoMapping()854     bool usingHlslIoMapping() { return false; }
855 #endif
856 
857     void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
858     void merge(TInfoSink&, TIntermediate&);
859     void finalCheck(TInfoSink&, bool keepUncalled);
860 
861     bool buildConvertOp(TBasicType dst, TBasicType src, TOperator& convertOp) const;
862     TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const;
863 
addIoAccessed(const TString & name)864     void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
inIoAccessed(const TString & name)865     bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
866 
867     int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
868     int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision);
869     int addUsedOffsets(int binding, int offset, int numOffsets);
870     bool addUsedConstantId(int id);
871     static int computeTypeLocationSize(const TType&, EShLanguage);
872     static int computeTypeUniformLocationSize(const TType&);
873 
874     static int getBaseAlignmentScalar(const TType&, int& size);
875     static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
876     static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
877     static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
878     static bool improperStraddle(const TType& type, int size, int offset);
879     static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize);
880     static int getOffset(const TType& type, int index);
881     static int getBlockSize(const TType& blockType);
882     static int computeBufferReferenceTypeSize(const TType&);
883     bool promote(TIntermOperator*);
setNanMinMaxClamp(bool setting)884     void setNanMinMaxClamp(bool setting) { nanMinMaxClamp = setting; }
getNanMinMaxClamp()885     bool getNanMinMaxClamp() const { return nanMinMaxClamp; }
886 
setSourceFile(const char * file)887     void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
getSourceFile()888     const std::string& getSourceFile() const { return sourceFile; }
addSourceText(const char * text,size_t len)889     void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
getSourceText()890     const std::string& getSourceText() const { return sourceText; }
getIncludeText()891     const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
addIncludeText(const char * name,const char * text,size_t len)892     void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
addProcesses(const std::vector<std::string> & p)893     void addProcesses(const std::vector<std::string>& p)
894     {
895         for (int i = 0; i < (int)p.size(); ++i)
896             processes.addProcess(p[i]);
897     }
addProcess(const std::string & process)898     void addProcess(const std::string& process) { processes.addProcess(process); }
addProcessArgument(const std::string & arg)899     void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
getProcesses()900     const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
901 
902     // Certain explicit conversions are allowed conditionally
903 #ifdef GLSLANG_WEB
getArithemeticInt8Enabled()904     bool getArithemeticInt8Enabled() const { return false; }
getArithemeticInt16Enabled()905     bool getArithemeticInt16Enabled() const { return false; }
getArithemeticFloat16Enabled()906     bool getArithemeticFloat16Enabled() const { return false; }
updateNumericFeature(TNumericFeatures::feature f,bool on)907     void updateNumericFeature(TNumericFeatures::feature f, bool on) { }
908 #else
getArithemeticInt8Enabled()909     bool getArithemeticInt8Enabled() const {
910         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
911                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8);
912     }
getArithemeticInt16Enabled()913     bool getArithemeticInt16Enabled() const {
914         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
915                numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
916                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16);
917     }
918 
getArithemeticFloat16Enabled()919     bool getArithemeticFloat16Enabled() const {
920         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
921                numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
922                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
923     }
updateNumericFeature(TNumericFeatures::feature f,bool on)924     void updateNumericFeature(TNumericFeatures::feature f, bool on)
925         { on ? numericFeatures.insert(f) : numericFeatures.erase(f); }
926 #endif
927 
928 protected:
929     TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
930     void error(TInfoSink& infoSink, const char*);
931     void warn(TInfoSink& infoSink, const char*);
932     void mergeCallGraphs(TInfoSink&, TIntermediate&);
933     void mergeModes(TInfoSink&, TIntermediate&);
934     void mergeTrees(TInfoSink&, TIntermediate&);
935     void seedIdMap(TIdMaps& idMaps, int& maxId);
936     void remapIds(const TIdMaps& idMaps, int idShift, TIntermediate&);
937     void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
938     void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
939     void mergeImplicitArraySizes(TType&, const TType&);
940     void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
941     void checkCallGraphCycles(TInfoSink&);
942     void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
943     void inOutLocationCheck(TInfoSink&);
944     TIntermAggregate* findLinkerObjects() const;
945     bool userOutputUsed() const;
946     bool isSpecializationOperation(const TIntermOperator&) const;
947     bool isNonuniformPropagating(TOperator) const;
948     bool promoteUnary(TIntermUnary&);
949     bool promoteBinary(TIntermBinary&);
950     void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
951     bool promoteAggregate(TIntermAggregate&);
952     void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&);
953     void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
954     bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&);
955     void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root);
956     bool isConversionAllowed(TOperator op, TIntermTyped* node) const;
957     std::tuple<TBasicType, TBasicType> getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const;
958 
959     static const char* getResourceName(TResourceType);
960 
961     const EShLanguage language;  // stage, known at construction time
962     std::string entryPointName;
963     std::string entryPointMangledName;
964     typedef std::list<TCall> TGraph;
965     TGraph callGraph;
966 
967 #ifdef GLSLANG_ANGLE
968     const EProfile profile = ECoreProfile;
969     const int version = 450;
970 #else
971     EProfile profile;                           // source profile
972     int version;                                // source version
973 #endif
974     SpvVersion spvVersion;
975     TIntermNode* treeRoot;
976     std::set<std::string> requestedExtensions;  // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
977     MustBeAssigned<TBuiltInResource> resources;
978     int numEntryPoints;
979     int numErrors;
980     int numPushConstants;
981     bool recursive;
982     bool invertY;
983     bool useStorageBuffer;
984     bool nanMinMaxClamp;            // true if desiring min/max/clamp to favor non-NaN over NaN
985     bool depthReplacing;
986     int localSize[3];
987     bool localSizeNotDefault[3];
988     int localSizeSpecId[3];
989 #ifndef GLSLANG_WEB
990 public:
991     const char* const implicitThisName;
992     const char* const implicitCounterName;
993 protected:
994     EShSource source;            // source language, known a bit later
995     bool useVulkanMemoryModel;
996     int invocations;
997     int vertices;
998     TLayoutGeometry inputPrimitive;
999     TLayoutGeometry outputPrimitive;
1000     bool pixelCenterInteger;
1001     bool originUpperLeft;
1002     TVertexSpacing vertexSpacing;
1003     TVertexOrder vertexOrder;
1004     TInterlockOrdering interlockOrdering;
1005     bool pointMode;
1006     bool earlyFragmentTests;
1007     bool postDepthCoverage;
1008     TLayoutDepth depthLayout;
1009     bool hlslFunctionality1;
1010     int blendEquations;        // an 'or'ing of masks of shifts of TBlendEquationShift
1011     bool xfbMode;
1012     std::vector<TXfbBuffer> xfbBuffers;     // all the data we need to track per xfb buffer
1013     bool multiStream;
1014     bool layoutOverrideCoverage;
1015     bool geoPassthroughEXT;
1016     int numShaderRecordBlocks;
1017     ComputeDerivativeMode computeDerivativeMode;
1018     int primitives;
1019     int numTaskNVBlocks;
1020     bool layoutPrimitiveCulling;
1021 
1022     // Base shift values
1023     std::array<unsigned int, EResCount> shiftBinding;
1024 
1025     // Per-descriptor-set shift values
1026     std::array<std::map<int, int>, EResCount> shiftBindingForSet;
1027 
1028     std::vector<std::string> resourceSetBinding;
1029     bool autoMapBindings;
1030     bool autoMapLocations;
1031     bool flattenUniformArrays;
1032     bool useUnknownFormat;
1033     bool hlslOffsets;
1034     bool hlslIoMapping;
1035     bool useVariablePointers;
1036 
1037     std::set<TString> semanticNameSet;
1038 
1039     EShTextureSamplerTransformMode textureSamplerTransformMode;
1040 
1041     bool needToLegalize;
1042     bool binaryDoubleOutput;
1043     bool usePhysicalStorageBuffer;
1044 
1045     std::unordered_map<std::string, int> uniformLocationOverrides;
1046     int uniformLocationBase;
1047     TNumericFeatures numericFeatures;
1048 #endif
1049 
1050     std::unordered_set<int> usedConstantId; // specialization constant ids used
1051     std::vector<TOffsetRange> usedAtomics;  // sets of bindings used by atomic counters
1052     std::vector<TIoRange> usedIo[4];        // sets of used locations, one for each of in, out, uniform, and buffers
1053     // set of names of statically read/written I/O that might need extra checking
1054     std::set<TString> ioAccessed;
1055     // source code of shader, useful as part of debug information
1056     std::string sourceFile;
1057     std::string sourceText;
1058 
1059     // Included text. First string is a name, second is the included text
1060     std::map<std::string, std::string> includeText;
1061 
1062     // for OpModuleProcessed, or equivalent
1063     TProcesses processes;
1064 
1065 private:
1066     void operator=(TIntermediate&); // prevent assignments
1067 };
1068 
1069 } // end namespace glslang
1070 
1071 #endif // _LOCAL_INTERMEDIATE_INCLUDED_
1072