• 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 #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, long long>& operator[](long long i) { return maps[i]; }
231     const TMap<TString, long long>& operator[](long long i) const { return maps[i]; }
232 private:
233     TMap<TString, long long> 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         profile(p), version(v),
287         treeRoot(nullptr),
288         resources(TBuiltInResource{}),
289         numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false),
290         invertY(false),
291         dxPositionW(false),
292         enhancedMsgs(false),
293         debugInfo(false),
294         useStorageBuffer(false),
295         invariantAll(false),
296         nanMinMaxClamp(false),
297         depthReplacing(false),
298         stencilReplacing(false),
299         uniqueId(0),
300         globalUniformBlockName(""),
301         atomicCounterBlockName(""),
302         globalUniformBlockSet(TQualifier::layoutSetEnd),
303         globalUniformBlockBinding(TQualifier::layoutBindingEnd),
304         atomicCounterBlockSet(TQualifier::layoutSetEnd)
305 #ifndef GLSLANG_WEB
306         ,
307         implicitThisName("@this"), implicitCounterName("@count"),
308         source(EShSourceNone),
309         useVulkanMemoryModel(false),
310         invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet),
311         inputPrimitive(ElgNone), outputPrimitive(ElgNone),
312         pixelCenterInteger(false), originUpperLeft(false),texCoordBuiltinRedeclared(false),
313         vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false),
314         postDepthCoverage(false), earlyAndLateFragmentTestsAMD(false), depthLayout(EldNone), stencilLayout(ElsNone),
315         hlslFunctionality1(false),
316         blendEquations(0), xfbMode(false), multiStream(false),
317         layoutOverrideCoverage(false),
318         geoPassthroughEXT(false),
319         numShaderRecordBlocks(0),
320         computeDerivativeMode(LayoutDerivativeNone),
321         primitives(TQualifier::layoutNotSet),
322         numTaskNVBlocks(0),
323         layoutPrimitiveCulling(false),
324         numTaskEXTPayloads(0),
325         autoMapBindings(false),
326         autoMapLocations(false),
327         flattenUniformArrays(false),
328         useUnknownFormat(false),
329         hlslOffsets(false),
330         hlslIoMapping(false),
331         useVariablePointers(false),
332         textureSamplerTransformMode(EShTexSampTransKeep),
333         needToLegalize(false),
334         binaryDoubleOutput(false),
335         subgroupUniformControlFlow(false),
336         usePhysicalStorageBuffer(false),
337         spirvRequirement(nullptr),
338         spirvExecutionMode(nullptr),
339         uniformLocationBase(0)
340 #endif
341     {
342         localSize[0] = 1;
343         localSize[1] = 1;
344         localSize[2] = 1;
345         localSizeNotDefault[0] = false;
346         localSizeNotDefault[1] = false;
347         localSizeNotDefault[2] = false;
348         localSizeSpecId[0] = TQualifier::layoutNotSet;
349         localSizeSpecId[1] = TQualifier::layoutNotSet;
350         localSizeSpecId[2] = TQualifier::layoutNotSet;
351 #ifndef GLSLANG_WEB
352         xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
353         shiftBinding.fill(0);
354 #endif
355     }
356 
setVersion(int v)357     void setVersion(int v)
358     {
359         version = v;
360     }
setProfile(EProfile p)361     void setProfile(EProfile p)
362     {
363         profile = p;
364     }
365 
getVersion()366     int getVersion() const { return version; }
getProfile()367     EProfile getProfile() const { return profile; }
setSpv(const SpvVersion & s)368     void setSpv(const SpvVersion& s)
369     {
370         spvVersion = s;
371 
372         // client processes
373         if (spvVersion.vulkan > 0)
374             processes.addProcess("client vulkan100");
375         if (spvVersion.openGl > 0)
376             processes.addProcess("client opengl100");
377 
378         // target SPV
379         switch (spvVersion.spv) {
380         case 0:
381             break;
382         case EShTargetSpv_1_0:
383             break;
384         case EShTargetSpv_1_1:
385             processes.addProcess("target-env spirv1.1");
386             break;
387         case EShTargetSpv_1_2:
388             processes.addProcess("target-env spirv1.2");
389             break;
390         case EShTargetSpv_1_3:
391             processes.addProcess("target-env spirv1.3");
392             break;
393         case EShTargetSpv_1_4:
394             processes.addProcess("target-env spirv1.4");
395             break;
396         case EShTargetSpv_1_5:
397             processes.addProcess("target-env spirv1.5");
398             break;
399         case EShTargetSpv_1_6:
400             processes.addProcess("target-env spirv1.6");
401             break;
402         default:
403             processes.addProcess("target-env spirvUnknown");
404             break;
405         }
406 
407         // target-environment processes
408         switch (spvVersion.vulkan) {
409         case 0:
410             break;
411         case EShTargetVulkan_1_0:
412             processes.addProcess("target-env vulkan1.0");
413             break;
414         case EShTargetVulkan_1_1:
415             processes.addProcess("target-env vulkan1.1");
416             break;
417         case EShTargetVulkan_1_2:
418             processes.addProcess("target-env vulkan1.2");
419             break;
420         case EShTargetVulkan_1_3:
421             processes.addProcess("target-env vulkan1.3");
422             break;
423         default:
424             processes.addProcess("target-env vulkanUnknown");
425             break;
426         }
427         if (spvVersion.openGl > 0)
428             processes.addProcess("target-env opengl");
429     }
getSpv()430     const SpvVersion& getSpv() const { return spvVersion; }
getStage()431     EShLanguage getStage() const { return language; }
addRequestedExtension(const char * extension)432     void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
getRequestedExtensions()433     const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
isRayTracingStage()434     bool isRayTracingStage() const {
435         return language >= EShLangRayGen && language <= EShLangCallableNV;
436     }
437 
setTreeRoot(TIntermNode * r)438     void setTreeRoot(TIntermNode* r) { treeRoot = r; }
getTreeRoot()439     TIntermNode* getTreeRoot() const { return treeRoot; }
incrementEntryPointCount()440     void incrementEntryPointCount() { ++numEntryPoints; }
getNumEntryPoints()441     int getNumEntryPoints() const { return numEntryPoints; }
getNumErrors()442     int getNumErrors() const { return numErrors; }
addPushConstantCount()443     void addPushConstantCount() { ++numPushConstants; }
setLimits(const TBuiltInResource & r)444     void setLimits(const TBuiltInResource& r) { resources = r; }
getLimits()445     const TBuiltInResource& getLimits() const { return resources; }
446 
447     bool postProcess(TIntermNode*, EShLanguage);
448     void removeTree();
449 
setEntryPointName(const char * ep)450     void setEntryPointName(const char* ep)
451     {
452         entryPointName = ep;
453         processes.addProcess("entry-point");
454         processes.addArgument(entryPointName);
455     }
setEntryPointMangledName(const char * ep)456     void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
getEntryPointName()457     const std::string& getEntryPointName() const { return entryPointName; }
getEntryPointMangledName()458     const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
459 
setDebugInfo(bool debuginfo)460     void setDebugInfo(bool debuginfo)
461     {
462         debugInfo = debuginfo;
463     }
getDebugInfo()464     bool getDebugInfo() const { return debugInfo; }
465 
setInvertY(bool invert)466     void setInvertY(bool invert)
467     {
468         invertY = invert;
469         if (invertY)
470             processes.addProcess("invert-y");
471     }
getInvertY()472     bool getInvertY() const { return invertY; }
473 
setDxPositionW(bool dxPosW)474     void setDxPositionW(bool dxPosW)
475     {
476         dxPositionW = dxPosW;
477         if (dxPositionW)
478             processes.addProcess("dx-position-w");
479     }
getDxPositionW()480     bool getDxPositionW() const { return dxPositionW; }
481 
setEnhancedMsgs()482     void setEnhancedMsgs()
483     {
484         enhancedMsgs = true;
485     }
getEnhancedMsgs()486     bool getEnhancedMsgs() const { return enhancedMsgs && getSource() == EShSourceGlsl; }
487 
488 #ifdef ENABLE_HLSL
setSource(EShSource s)489     void setSource(EShSource s) { source = s; }
getSource()490     EShSource getSource() const { return source; }
491 #else
setSource(EShSource s)492     void setSource(EShSource s) { assert(s == EShSourceGlsl); (void)s; }
getSource()493     EShSource getSource() const { return EShSourceGlsl; }
494 #endif
495 
isRecursive()496     bool isRecursive() const { return recursive; }
497 
498     TIntermSymbol* addSymbol(const TVariable&);
499     TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
500     TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
501     TIntermSymbol* addSymbol(const TIntermSymbol&);
502     TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
503     std::tuple<TIntermTyped*, TIntermTyped*> addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1);
504     TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
505     TIntermTyped* addConversion(TBasicType convertTo, TIntermTyped* node) const;
506     void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
507     TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
508     TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
509     TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
510     TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&);
511     TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, const TSourceLoc&);
512     TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
513     bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const;
514     bool isIntegralPromotion(TBasicType from, TBasicType to) const;
515     bool isFPPromotion(TBasicType from, TBasicType to) const;
516     bool isIntegralConversion(TBasicType from, TBasicType to) const;
517     bool isFPConversion(TBasicType from, TBasicType to) const;
518     bool isFPIntegralConversion(TBasicType from, TBasicType to) const;
519     TOperator mapTypeToConstructorOp(const TType&) const;
520     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
521     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
522     TIntermAggregate* makeAggregate(TIntermNode* node);
523     TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
524     TIntermAggregate* makeAggregate(const TSourceLoc&);
525     TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, const TSourceLoc&);
526     bool areAllChildConst(TIntermAggregate* aggrNode);
527     TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
528     TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
529     TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
530     TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
531     TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
532     TIntermConstantUnion* addConstantUnion(signed char, const TSourceLoc&, bool literal = false) const;
533     TIntermConstantUnion* addConstantUnion(unsigned char, const TSourceLoc&, bool literal = false) const;
534     TIntermConstantUnion* addConstantUnion(signed short, const TSourceLoc&, bool literal = false) const;
535     TIntermConstantUnion* addConstantUnion(unsigned short, const TSourceLoc&, bool literal = false) const;
536     TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
537     TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
538     TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
539     TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
540     TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
541     TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
542     TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
543     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
544     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
545     TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
546     TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
547         const TSourceLoc&, TIntermLoop*&);
548     TIntermBranch* addBranch(TOperator, const TSourceLoc&);
549     TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
550     template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
551 
552     // Low level functions to add nodes (no conversions or other higher level transformations)
553     // If a type is provided, the node's type will be set to it.
554     TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&) const;
555     TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&,
556         const TType&) const;
557     TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&) const;
558     TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&, const TType&) const;
559 
560     // Constant folding (in Constant.cpp)
561     TIntermTyped* fold(TIntermAggregate* aggrNode);
562     TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
563     TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
564     TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& fields, const TSourceLoc&);
565 
566     // Tree ops
567     static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay , bool BufferReferenceOk = false);
568 
569     // Linkage related
570     void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
571     void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
572     TIntermAggregate* findLinkerObjects() const;
573 
setGlobalUniformBlockName(const char * name)574     void setGlobalUniformBlockName(const char* name) { globalUniformBlockName = std::string(name); }
getGlobalUniformBlockName()575     const char* getGlobalUniformBlockName() const { return globalUniformBlockName.c_str(); }
setGlobalUniformSet(unsigned int set)576     void setGlobalUniformSet(unsigned int set) { globalUniformBlockSet = set; }
getGlobalUniformSet()577     unsigned int getGlobalUniformSet() const { return globalUniformBlockSet; }
setGlobalUniformBinding(unsigned int binding)578     void setGlobalUniformBinding(unsigned int binding) { globalUniformBlockBinding = binding; }
getGlobalUniformBinding()579     unsigned int getGlobalUniformBinding() const { return globalUniformBlockBinding; }
580 
setAtomicCounterBlockName(const char * name)581     void setAtomicCounterBlockName(const char* name) { atomicCounterBlockName = std::string(name); }
getAtomicCounterBlockName()582     const char* getAtomicCounterBlockName() const { return atomicCounterBlockName.c_str(); }
setAtomicCounterBlockSet(unsigned int set)583     void setAtomicCounterBlockSet(unsigned int set) { atomicCounterBlockSet = set; }
getAtomicCounterBlockSet()584     unsigned int getAtomicCounterBlockSet() const { return atomicCounterBlockSet; }
585 
586 
setUseStorageBuffer()587     void setUseStorageBuffer() { useStorageBuffer = true; }
usingStorageBuffer()588     bool usingStorageBuffer() const { return useStorageBuffer; }
setInvariantAll()589     void setInvariantAll() { invariantAll = true; }
isInvariantAll()590     bool isInvariantAll() const { return invariantAll; }
setDepthReplacing()591     void setDepthReplacing() { depthReplacing = true; }
isDepthReplacing()592     bool isDepthReplacing() const { return depthReplacing; }
setStencilReplacing()593     void setStencilReplacing() { stencilReplacing = true; }
isStencilReplacing()594     bool isStencilReplacing() const { return stencilReplacing; }
setLocalSize(int dim,int size)595     bool setLocalSize(int dim, int size)
596     {
597         if (localSizeNotDefault[dim])
598             return size == localSize[dim];
599         localSizeNotDefault[dim] = true;
600         localSize[dim] = size;
601         return true;
602     }
getLocalSize(int dim)603     unsigned int getLocalSize(int dim) const { return localSize[dim]; }
isLocalSizeSet()604     bool isLocalSizeSet() const
605     {
606         // Return true if any component has been set (i.e. any component is not default).
607         return localSizeNotDefault[0] || localSizeNotDefault[1] || localSizeNotDefault[2];
608     }
setLocalSizeSpecId(int dim,int id)609     bool setLocalSizeSpecId(int dim, int id)
610     {
611         if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
612             return id == localSizeSpecId[dim];
613         localSizeSpecId[dim] = id;
614         return true;
615     }
getLocalSizeSpecId(int dim)616     int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
isLocalSizeSpecialized()617     bool isLocalSizeSpecialized() const
618     {
619         // Return true if any component has been specialized.
620         return localSizeSpecId[0] != TQualifier::layoutNotSet ||
621                localSizeSpecId[1] != TQualifier::layoutNotSet ||
622                localSizeSpecId[2] != TQualifier::layoutNotSet;
623     }
624 #ifdef GLSLANG_WEB
output(TInfoSink &,bool tree)625     void output(TInfoSink&, bool tree) { }
626 
isEsProfile()627     bool isEsProfile() const { return false; }
getXfbMode()628     bool getXfbMode() const { return false; }
isMultiStream()629     bool isMultiStream() const { return false; }
getOutputPrimitive()630     TLayoutGeometry getOutputPrimitive() const { return ElgNone; }
getPostDepthCoverage()631     bool getPostDepthCoverage() const { return false; }
getEarlyFragmentTests()632     bool getEarlyFragmentTests() const { return false; }
getDepth()633     TLayoutDepth getDepth() const { return EldNone; }
getPixelCenterInteger()634     bool getPixelCenterInteger() const { return false; }
setOriginUpperLeft()635     void setOriginUpperLeft() { }
getOriginUpperLeft()636     bool getOriginUpperLeft() const { return true; }
getInterlockOrdering()637     TInterlockOrdering getInterlockOrdering() const { return EioNone; }
638 
getAutoMapBindings()639     bool getAutoMapBindings() const { return false; }
getAutoMapLocations()640     bool getAutoMapLocations() const { return false; }
getNumPushConstants()641     int getNumPushConstants() const { return 0; }
addShaderRecordCount()642     void addShaderRecordCount() { }
addTaskNVCount()643     void addTaskNVCount() { }
addTaskPayloadEXTCount()644     void addTaskPayloadEXTCount() { }
setUseVulkanMemoryModel()645     void setUseVulkanMemoryModel() { }
usingVulkanMemoryModel()646     bool usingVulkanMemoryModel() const { return false; }
usingPhysicalStorageBuffer()647     bool usingPhysicalStorageBuffer() const { return false; }
usingVariablePointers()648     bool usingVariablePointers() const { return false; }
getXfbStride(int buffer)649     unsigned getXfbStride(int buffer) const { return 0; }
hasLayoutDerivativeModeNone()650     bool hasLayoutDerivativeModeNone() const { return false; }
getLayoutDerivativeModeNone()651     ComputeDerivativeMode getLayoutDerivativeModeNone() const { return LayoutDerivativeNone; }
652 #else
653     void output(TInfoSink&, bool tree);
654 
isEsProfile()655     bool isEsProfile() const { return profile == EEsProfile; }
656 
setShiftBinding(TResourceType res,unsigned int shift)657     void setShiftBinding(TResourceType res, unsigned int shift)
658     {
659         shiftBinding[res] = shift;
660 
661         const char* name = getResourceName(res);
662         if (name != nullptr)
663             processes.addIfNonZero(name, shift);
664     }
665 
getShiftBinding(TResourceType res)666     unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; }
667 
setShiftBindingForSet(TResourceType res,unsigned int shift,unsigned int set)668     void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set)
669     {
670         if (shift == 0) // ignore if there's no shift: it's a no-op.
671             return;
672 
673         shiftBindingForSet[res][set] = shift;
674 
675         const char* name = getResourceName(res);
676         if (name != nullptr) {
677             processes.addProcess(name);
678             processes.addArgument(shift);
679             processes.addArgument(set);
680         }
681     }
682 
getShiftBindingForSet(TResourceType res,unsigned int set)683     int getShiftBindingForSet(TResourceType res, unsigned int set) const
684     {
685         const auto shift = shiftBindingForSet[res].find(set);
686         return shift == shiftBindingForSet[res].end() ? -1 : shift->second;
687     }
hasShiftBindingForSet(TResourceType res)688     bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); }
689 
setResourceSetBinding(const std::vector<std::string> & shift)690     void setResourceSetBinding(const std::vector<std::string>& shift)
691     {
692         resourceSetBinding = shift;
693         if (shift.size() > 0) {
694             processes.addProcess("resource-set-binding");
695             for (int s = 0; s < (int)shift.size(); ++s)
696                 processes.addArgument(shift[s]);
697         }
698     }
getResourceSetBinding()699     const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
setAutoMapBindings(bool map)700     void setAutoMapBindings(bool map)
701     {
702         autoMapBindings = map;
703         if (autoMapBindings)
704             processes.addProcess("auto-map-bindings");
705     }
getAutoMapBindings()706     bool getAutoMapBindings() const { return autoMapBindings; }
setAutoMapLocations(bool map)707     void setAutoMapLocations(bool map)
708     {
709         autoMapLocations = map;
710         if (autoMapLocations)
711             processes.addProcess("auto-map-locations");
712     }
getAutoMapLocations()713     bool getAutoMapLocations() const { return autoMapLocations; }
714 
715 #ifdef ENABLE_HLSL
setFlattenUniformArrays(bool flatten)716     void setFlattenUniformArrays(bool flatten)
717     {
718         flattenUniformArrays = flatten;
719         if (flattenUniformArrays)
720             processes.addProcess("flatten-uniform-arrays");
721     }
getFlattenUniformArrays()722     bool getFlattenUniformArrays() const { return flattenUniformArrays; }
723 #endif
setNoStorageFormat(bool b)724     void setNoStorageFormat(bool b)
725     {
726         useUnknownFormat = b;
727         if (useUnknownFormat)
728             processes.addProcess("no-storage-format");
729     }
getNoStorageFormat()730     bool getNoStorageFormat() const { return useUnknownFormat; }
setUseVulkanMemoryModel()731     void setUseVulkanMemoryModel()
732     {
733         useVulkanMemoryModel = true;
734         processes.addProcess("use-vulkan-memory-model");
735     }
usingVulkanMemoryModel()736     bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
setUsePhysicalStorageBuffer()737     void setUsePhysicalStorageBuffer()
738     {
739         usePhysicalStorageBuffer = true;
740     }
usingPhysicalStorageBuffer()741     bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
setUseVariablePointers()742     void setUseVariablePointers()
743     {
744         useVariablePointers = true;
745         processes.addProcess("use-variable-pointers");
746     }
usingVariablePointers()747     bool usingVariablePointers() const { return useVariablePointers; }
748 
749 #ifdef ENABLE_HLSL
addCounterBufferName(const T & name)750     template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
hasCounterBufferName(const TString & name)751     bool hasCounterBufferName(const TString& name) const {
752         size_t len = strlen(implicitCounterName);
753         return name.size() > len &&
754                name.compare(name.size() - len, len, implicitCounterName) == 0;
755     }
756 #endif
757 
setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode)758     void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
getNumPushConstants()759     int getNumPushConstants() const { return numPushConstants; }
addShaderRecordCount()760     void addShaderRecordCount() { ++numShaderRecordBlocks; }
addTaskNVCount()761     void addTaskNVCount() { ++numTaskNVBlocks; }
addTaskPayloadEXTCount()762     void addTaskPayloadEXTCount() { ++numTaskEXTPayloads; }
763 
setInvocations(int i)764     bool setInvocations(int i)
765     {
766         if (invocations != TQualifier::layoutNotSet)
767             return invocations == i;
768         invocations = i;
769         return true;
770     }
getInvocations()771     int getInvocations() const { return invocations; }
setVertices(int m)772     bool setVertices(int m)
773     {
774         if (vertices != TQualifier::layoutNotSet)
775             return vertices == m;
776         vertices = m;
777         return true;
778     }
getVertices()779     int getVertices() const { return vertices; }
setInputPrimitive(TLayoutGeometry p)780     bool setInputPrimitive(TLayoutGeometry p)
781     {
782         if (inputPrimitive != ElgNone)
783             return inputPrimitive == p;
784         inputPrimitive = p;
785         return true;
786     }
getInputPrimitive()787     TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
setVertexSpacing(TVertexSpacing s)788     bool setVertexSpacing(TVertexSpacing s)
789     {
790         if (vertexSpacing != EvsNone)
791             return vertexSpacing == s;
792         vertexSpacing = s;
793         return true;
794     }
getVertexSpacing()795     TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
setVertexOrder(TVertexOrder o)796     bool setVertexOrder(TVertexOrder o)
797     {
798         if (vertexOrder != EvoNone)
799             return vertexOrder == o;
800         vertexOrder = o;
801         return true;
802     }
getVertexOrder()803     TVertexOrder getVertexOrder() const { return vertexOrder; }
setPointMode()804     void setPointMode() { pointMode = true; }
getPointMode()805     bool getPointMode() const { return pointMode; }
806 
setInterlockOrdering(TInterlockOrdering o)807     bool setInterlockOrdering(TInterlockOrdering o)
808     {
809         if (interlockOrdering != EioNone)
810             return interlockOrdering == o;
811         interlockOrdering = o;
812         return true;
813     }
getInterlockOrdering()814     TInterlockOrdering getInterlockOrdering() const { return interlockOrdering; }
815 
setXfbMode()816     void setXfbMode() { xfbMode = true; }
getXfbMode()817     bool getXfbMode() const { return xfbMode; }
setMultiStream()818     void setMultiStream() { multiStream = true; }
isMultiStream()819     bool isMultiStream() const { return multiStream; }
setOutputPrimitive(TLayoutGeometry p)820     bool setOutputPrimitive(TLayoutGeometry p)
821     {
822         if (outputPrimitive != ElgNone)
823             return outputPrimitive == p;
824         outputPrimitive = p;
825         return true;
826     }
getOutputPrimitive()827     TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
setPostDepthCoverage()828     void setPostDepthCoverage() { postDepthCoverage = true; }
getPostDepthCoverage()829     bool getPostDepthCoverage() const { return postDepthCoverage; }
setEarlyFragmentTests()830     void setEarlyFragmentTests() { earlyFragmentTests = true; }
setEarlyAndLateFragmentTestsAMD()831     void setEarlyAndLateFragmentTestsAMD() { earlyAndLateFragmentTestsAMD = true; }
getEarlyFragmentTests()832     bool getEarlyFragmentTests() const { return earlyFragmentTests; }
getEarlyAndLateFragmentTestsAMD()833     bool getEarlyAndLateFragmentTestsAMD() const { return earlyAndLateFragmentTestsAMD; }
setDepth(TLayoutDepth d)834     bool setDepth(TLayoutDepth d)
835     {
836         if (depthLayout != EldNone)
837             return depthLayout == d;
838         depthLayout = d;
839         return true;
840     }
setStencil(TLayoutStencil s)841     bool setStencil(TLayoutStencil s)
842     {
843         if (stencilLayout != ElsNone)
844             return stencilLayout == s;
845         stencilLayout = s;
846         return true;
847     }
getDepth()848     TLayoutDepth getDepth() const { return depthLayout; }
getStencil()849     TLayoutStencil getStencil() const { return stencilLayout; }
setOriginUpperLeft()850     void setOriginUpperLeft() { originUpperLeft = true; }
getOriginUpperLeft()851     bool getOriginUpperLeft() const { return originUpperLeft; }
setPixelCenterInteger()852     void setPixelCenterInteger() { pixelCenterInteger = true; }
getPixelCenterInteger()853     bool getPixelCenterInteger() const { return pixelCenterInteger; }
setTexCoordRedeclared()854     void setTexCoordRedeclared() { texCoordBuiltinRedeclared = true; }
getTexCoordRedeclared()855     bool getTexCoordRedeclared() const { return texCoordBuiltinRedeclared; }
addBlendEquation(TBlendEquationShift b)856     void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
getBlendEquations()857     unsigned int getBlendEquations() const { return blendEquations; }
setXfbBufferStride(int buffer,unsigned stride)858     bool setXfbBufferStride(int buffer, unsigned stride)
859     {
860         if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
861             return xfbBuffers[buffer].stride == stride;
862         xfbBuffers[buffer].stride = stride;
863         return true;
864     }
getXfbStride(int buffer)865     unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
866     int addXfbBufferOffset(const TType&);
867     unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const;
868     unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType) const;
setLayoutOverrideCoverage()869     void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
getLayoutOverrideCoverage()870     bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
setGeoPassthroughEXT()871     void setGeoPassthroughEXT() { geoPassthroughEXT = true; }
getGeoPassthroughEXT()872     bool getGeoPassthroughEXT() const { return geoPassthroughEXT; }
setLayoutDerivativeMode(ComputeDerivativeMode mode)873     void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; }
hasLayoutDerivativeModeNone()874     bool hasLayoutDerivativeModeNone() const { return computeDerivativeMode != LayoutDerivativeNone; }
getLayoutDerivativeModeNone()875     ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; }
setLayoutPrimitiveCulling()876     void setLayoutPrimitiveCulling() { layoutPrimitiveCulling = true; }
getLayoutPrimitiveCulling()877     bool getLayoutPrimitiveCulling() const { return layoutPrimitiveCulling; }
setPrimitives(int m)878     bool setPrimitives(int m)
879     {
880         if (primitives != TQualifier::layoutNotSet)
881             return primitives == m;
882         primitives = m;
883         return true;
884     }
getPrimitives()885     int getPrimitives() const { return primitives; }
addSemanticName(const TString & name)886     const char* addSemanticName(const TString& name)
887     {
888         return semanticNameSet.insert(name).first->c_str();
889     }
addUniformLocationOverride(const char * nameStr,int location)890     void addUniformLocationOverride(const char* nameStr, int location)
891     {
892         std::string name = nameStr;
893         uniformLocationOverrides[name] = location;
894     }
895 
getUniformLocationOverride(const char * nameStr)896     int getUniformLocationOverride(const char* nameStr) const
897     {
898         std::string name = nameStr;
899         auto pos = uniformLocationOverrides.find(name);
900         if (pos == uniformLocationOverrides.end())
901             return -1;
902         else
903             return pos->second;
904     }
905 
setUniformLocationBase(int base)906     void setUniformLocationBase(int base) { uniformLocationBase = base; }
getUniformLocationBase()907     int getUniformLocationBase() const { return uniformLocationBase; }
908 
setNeedsLegalization()909     void setNeedsLegalization() { needToLegalize = true; }
needsLegalization()910     bool needsLegalization() const { return needToLegalize; }
911 
setBinaryDoubleOutput()912     void setBinaryDoubleOutput() { binaryDoubleOutput = true; }
getBinaryDoubleOutput()913     bool getBinaryDoubleOutput() { return binaryDoubleOutput; }
914 
setSubgroupUniformControlFlow()915     void setSubgroupUniformControlFlow() { subgroupUniformControlFlow = true; }
getSubgroupUniformControlFlow()916     bool getSubgroupUniformControlFlow() const { return subgroupUniformControlFlow; }
917 
918     // GL_EXT_spirv_intrinsics
919     void insertSpirvRequirement(const TSpirvRequirement* spirvReq);
hasSpirvRequirement()920     bool hasSpirvRequirement() const { return spirvRequirement != nullptr; }
getSpirvRequirement()921     const TSpirvRequirement& getSpirvRequirement() const { return *spirvRequirement; }
922     void insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args = nullptr);
923     void insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args);
hasSpirvExecutionMode()924     bool hasSpirvExecutionMode() const { return spirvExecutionMode != nullptr; }
getSpirvExecutionMode()925     const TSpirvExecutionMode& getSpirvExecutionMode() const { return *spirvExecutionMode; }
926 #endif // GLSLANG_WEB
927 
addBlockStorageOverride(const char * nameStr,TBlockStorageClass backing)928     void addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing)
929     {
930         std::string name(nameStr);
931         blockBackingOverrides[name] = backing;
932     }
getBlockStorageOverride(const char * nameStr)933     TBlockStorageClass getBlockStorageOverride(const char* nameStr) const
934     {
935         std::string name = nameStr;
936         auto pos = blockBackingOverrides.find(name);
937         if (pos == blockBackingOverrides.end())
938             return EbsNone;
939         else
940             return pos->second;
941     }
942 #ifdef ENABLE_HLSL
setHlslFunctionality1()943     void setHlslFunctionality1() { hlslFunctionality1 = true; }
getHlslFunctionality1()944     bool getHlslFunctionality1() const { return hlslFunctionality1; }
setHlslOffsets()945     void setHlslOffsets()
946     {
947         hlslOffsets = true;
948         if (hlslOffsets)
949             processes.addProcess("hlsl-offsets");
950     }
usingHlslOffsets()951     bool usingHlslOffsets() const { return hlslOffsets; }
setHlslIoMapping(bool b)952     void setHlslIoMapping(bool b)
953     {
954         hlslIoMapping = b;
955         if (hlslIoMapping)
956             processes.addProcess("hlsl-iomap");
957     }
usingHlslIoMapping()958     bool usingHlslIoMapping() { return hlslIoMapping; }
959 #else
getHlslFunctionality1()960     bool getHlslFunctionality1() const { return false; }
usingHlslOffsets()961     bool usingHlslOffsets() const { return false; }
usingHlslIoMapping()962     bool usingHlslIoMapping() { return false; }
963 #endif
964 
usingScalarBlockLayout()965     bool usingScalarBlockLayout() const {
966         for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt) {
967             if (*extIt == E_GL_EXT_scalar_block_layout)
968                 return true;
969         }
970         return false;
971     }
972 
IsRequestedExtension(const char * extension)973     bool IsRequestedExtension(const char* extension) const
974     {
975         return (requestedExtensions.find(extension) != requestedExtensions.end());
976     }
977 
978     void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
979     void merge(TInfoSink&, TIntermediate&);
980     void finalCheck(TInfoSink&, bool keepUncalled);
981 
982     void mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& unit, bool mergeExistingOnly);
983     void mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit);
984     void checkStageIO(TInfoSink&, TIntermediate&);
985 
986     bool buildConvertOp(TBasicType dst, TBasicType src, TOperator& convertOp) const;
987     TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const;
988 
addIoAccessed(const TString & name)989     void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
inIoAccessed(const TString & name)990     bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
991 
992     int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
993     int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision);
994     int checkLocationRT(int set, int location);
995     int addUsedOffsets(int binding, int offset, int numOffsets);
996     bool addUsedConstantId(int id);
997     static int computeTypeLocationSize(const TType&, EShLanguage);
998     static int computeTypeUniformLocationSize(const TType&);
999 
1000     static int getBaseAlignmentScalar(const TType&, int& size);
1001     static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
1002     static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
1003     static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
1004     static bool improperStraddle(const TType& type, int size, int offset);
1005     static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize);
1006     static int getOffset(const TType& type, int index);
1007     static int getBlockSize(const TType& blockType);
1008     static int computeBufferReferenceTypeSize(const TType&);
1009     static bool isIoResizeArray(const TType& type, EShLanguage language);
1010 
1011     bool promote(TIntermOperator*);
setNanMinMaxClamp(bool setting)1012     void setNanMinMaxClamp(bool setting) { nanMinMaxClamp = setting; }
getNanMinMaxClamp()1013     bool getNanMinMaxClamp() const { return nanMinMaxClamp; }
1014 
setSourceFile(const char * file)1015     void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
getSourceFile()1016     const std::string& getSourceFile() const { return sourceFile; }
addSourceText(const char * text,size_t len)1017     void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
getSourceText()1018     const std::string& getSourceText() const { return sourceText; }
getIncludeText()1019     const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
addIncludeText(const char * name,const char * text,size_t len)1020     void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
addProcesses(const std::vector<std::string> & p)1021     void addProcesses(const std::vector<std::string>& p)
1022     {
1023         for (int i = 0; i < (int)p.size(); ++i)
1024             processes.addProcess(p[i]);
1025     }
addProcess(const std::string & process)1026     void addProcess(const std::string& process) { processes.addProcess(process); }
addProcessArgument(const std::string & arg)1027     void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
getProcesses()1028     const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
getUniqueId()1029     unsigned long long getUniqueId() const { return uniqueId; }
setUniqueId(unsigned long long id)1030     void setUniqueId(unsigned long long id) { uniqueId = id; }
1031 
1032     // Certain explicit conversions are allowed conditionally
1033 #ifdef GLSLANG_WEB
getArithemeticInt8Enabled()1034     bool getArithemeticInt8Enabled() const { return false; }
getArithemeticInt16Enabled()1035     bool getArithemeticInt16Enabled() const { return false; }
getArithemeticFloat16Enabled()1036     bool getArithemeticFloat16Enabled() const { return false; }
updateNumericFeature(TNumericFeatures::feature f,bool on)1037     void updateNumericFeature(TNumericFeatures::feature f, bool on) { }
1038 #else
getArithemeticInt8Enabled()1039     bool getArithemeticInt8Enabled() const {
1040         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1041                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8);
1042     }
getArithemeticInt16Enabled()1043     bool getArithemeticInt16Enabled() const {
1044         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1045                numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
1046                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16);
1047     }
1048 
getArithemeticFloat16Enabled()1049     bool getArithemeticFloat16Enabled() const {
1050         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1051                numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
1052                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
1053     }
updateNumericFeature(TNumericFeatures::feature f,bool on)1054     void updateNumericFeature(TNumericFeatures::feature f, bool on)
1055         { on ? numericFeatures.insert(f) : numericFeatures.erase(f); }
1056 #endif
1057 
1058 protected:
1059     TIntermSymbol* addSymbol(long long Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
1060     void error(TInfoSink& infoSink, const char*, EShLanguage unitStage = EShLangCount);
1061     void warn(TInfoSink& infoSink, const char*, EShLanguage unitStage = EShLangCount);
1062     void mergeCallGraphs(TInfoSink&, TIntermediate&);
1063     void mergeModes(TInfoSink&, TIntermediate&);
1064     void mergeTrees(TInfoSink&, TIntermediate&);
1065     void seedIdMap(TIdMaps& idMaps, long long& IdShift);
1066     void remapIds(const TIdMaps& idMaps, long long idShift, TIntermediate&);
1067     void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
1068     void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects, EShLanguage);
1069     void mergeBlockDefinitions(TInfoSink&, TIntermSymbol* block, TIntermSymbol* unitBlock, TIntermediate* unitRoot);
1070     void mergeImplicitArraySizes(TType&, const TType&);
1071     void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, EShLanguage);
1072     void checkCallGraphCycles(TInfoSink&);
1073     void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
1074     void inOutLocationCheck(TInfoSink&);
1075     void sharedBlockCheck(TInfoSink&);
1076     bool userOutputUsed() const;
1077     bool isSpecializationOperation(const TIntermOperator&) const;
1078     bool isNonuniformPropagating(TOperator) const;
1079     bool promoteUnary(TIntermUnary&);
1080     bool promoteBinary(TIntermBinary&);
1081     void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
1082     bool promoteAggregate(TIntermAggregate&);
1083     void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&);
1084     void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
1085     bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&);
1086     void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root);
1087     bool isConversionAllowed(TOperator op, TIntermTyped* node) const;
1088     std::tuple<TBasicType, TBasicType> getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const;
1089 
1090     static const char* getResourceName(TResourceType);
1091 
1092     const EShLanguage language;  // stage, known at construction time
1093     std::string entryPointName;
1094     std::string entryPointMangledName;
1095     typedef std::list<TCall> TGraph;
1096     TGraph callGraph;
1097 
1098     EProfile profile;                           // source profile
1099     int version;                                // source version
1100     SpvVersion spvVersion;
1101     TIntermNode* treeRoot;
1102     std::set<std::string> requestedExtensions;  // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
1103     MustBeAssigned<TBuiltInResource> resources;
1104     int numEntryPoints;
1105     int numErrors;
1106     int numPushConstants;
1107     bool recursive;
1108     bool invertY;
1109     bool dxPositionW;
1110     bool enhancedMsgs;
1111     bool debugInfo;
1112     bool useStorageBuffer;
1113     bool invariantAll;
1114     bool nanMinMaxClamp;            // true if desiring min/max/clamp to favor non-NaN over NaN
1115     bool depthReplacing;
1116     bool stencilReplacing;
1117     int localSize[3];
1118     bool localSizeNotDefault[3];
1119     int localSizeSpecId[3];
1120     unsigned long long uniqueId;
1121 
1122     std::string globalUniformBlockName;
1123     std::string atomicCounterBlockName;
1124     unsigned int globalUniformBlockSet;
1125     unsigned int globalUniformBlockBinding;
1126     unsigned int atomicCounterBlockSet;
1127 
1128 #ifndef GLSLANG_WEB
1129 public:
1130     const char* const implicitThisName;
1131     const char* const implicitCounterName;
1132 protected:
1133     EShSource source;            // source language, known a bit later
1134     bool useVulkanMemoryModel;
1135     int invocations;
1136     int vertices;
1137     TLayoutGeometry inputPrimitive;
1138     TLayoutGeometry outputPrimitive;
1139     bool pixelCenterInteger;
1140     bool originUpperLeft;
1141     bool texCoordBuiltinRedeclared;
1142     TVertexSpacing vertexSpacing;
1143     TVertexOrder vertexOrder;
1144     TInterlockOrdering interlockOrdering;
1145     bool pointMode;
1146     bool earlyFragmentTests;
1147     bool postDepthCoverage;
1148     bool earlyAndLateFragmentTestsAMD;
1149     TLayoutDepth depthLayout;
1150     TLayoutStencil stencilLayout;
1151     bool hlslFunctionality1;
1152     int blendEquations;        // an 'or'ing of masks of shifts of TBlendEquationShift
1153     bool xfbMode;
1154     std::vector<TXfbBuffer> xfbBuffers;     // all the data we need to track per xfb buffer
1155     bool multiStream;
1156     bool layoutOverrideCoverage;
1157     bool geoPassthroughEXT;
1158     int numShaderRecordBlocks;
1159     ComputeDerivativeMode computeDerivativeMode;
1160     int primitives;
1161     int numTaskNVBlocks;
1162     bool layoutPrimitiveCulling;
1163     int numTaskEXTPayloads;
1164 
1165     // Base shift values
1166     std::array<unsigned int, EResCount> shiftBinding;
1167 
1168     // Per-descriptor-set shift values
1169     std::array<std::map<int, int>, EResCount> shiftBindingForSet;
1170 
1171     std::vector<std::string> resourceSetBinding;
1172     bool autoMapBindings;
1173     bool autoMapLocations;
1174     bool flattenUniformArrays;
1175     bool useUnknownFormat;
1176     bool hlslOffsets;
1177     bool hlslIoMapping;
1178     bool useVariablePointers;
1179 
1180     std::set<TString> semanticNameSet;
1181 
1182     EShTextureSamplerTransformMode textureSamplerTransformMode;
1183 
1184     bool needToLegalize;
1185     bool binaryDoubleOutput;
1186     bool subgroupUniformControlFlow;
1187     bool usePhysicalStorageBuffer;
1188 
1189     TSpirvRequirement* spirvRequirement;
1190     TSpirvExecutionMode* spirvExecutionMode;
1191 
1192     std::unordered_map<std::string, int> uniformLocationOverrides;
1193     int uniformLocationBase;
1194     TNumericFeatures numericFeatures;
1195 #endif
1196     std::unordered_map<std::string, TBlockStorageClass> blockBackingOverrides;
1197 
1198     std::unordered_set<int> usedConstantId; // specialization constant ids used
1199     std::vector<TOffsetRange> usedAtomics;  // sets of bindings used by atomic counters
1200     std::vector<TIoRange> usedIo[4];        // sets of used locations, one for each of in, out, uniform, and buffers
1201     std::vector<TRange> usedIoRT[2];        // sets of used location, one for rayPayload/rayPayloadIN and other
1202                                             // for callableData/callableDataIn
1203     // set of names of statically read/written I/O that might need extra checking
1204     std::set<TString> ioAccessed;
1205 
1206     // source code of shader, useful as part of debug information
1207     std::string sourceFile;
1208     std::string sourceText;
1209 
1210     // Included text. First string is a name, second is the included text
1211     std::map<std::string, std::string> includeText;
1212 
1213     // for OpModuleProcessed, or equivalent
1214     TProcesses processes;
1215 
1216 private:
1217     void operator=(TIntermediate&); // prevent assignments
1218 };
1219 
1220 } // end namespace glslang
1221 
1222 #endif // _LOCAL_INTERMEDIATE_INCLUDED_
1223