• 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 <algorithm>
47 #include <array>
48 #include <functional>
49 #include <set>
50 #include <string>
51 #include <vector>
52 
53 class TInfoSink;
54 
55 namespace glslang {
56 
57 struct TMatrixSelector {
58     int coord1;  // stay agnostic about column/row; this is parse order
59     int coord2;
60 };
61 
62 typedef int TVectorSelector;
63 
64 const int MaxSwizzleSelectors = 4;
65 
66 template<typename selectorType>
67 class TSwizzleSelectors {
68 public:
TSwizzleSelectors()69     TSwizzleSelectors() : size_(0) { }
70 
push_back(selectorType comp)71     void push_back(selectorType comp)
72     {
73         if (size_ < MaxSwizzleSelectors)
74             components[size_++] = comp;
75     }
resize(int s)76     void resize(int s)
77     {
78         assert(s <= size_);
79         size_ = s;
80     }
size()81     int size() const { return size_; }
82     selectorType operator[](int i) const
83     {
84         assert(i < MaxSwizzleSelectors);
85         return components[i];
86     }
87 
88 private:
89     int size_;
90     selectorType components[MaxSwizzleSelectors];
91 };
92 
93 //
94 // Some helper structures for TIntermediate.  Their contents are encapsulated
95 // by TIntermediate.
96 //
97 
98 // Used for call-graph algorithms for detecting recursion, missing bodies, and dead bodies.
99 // A "call" is a pair: <caller, callee>.
100 // There can be duplicates. General assumption is the list is small.
101 struct TCall {
TCallTCall102     TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { }
103     TString caller;
104     TString callee;
105     bool visited;
106     bool currentPath;
107     bool errorGiven;
108     int calleeBodyPosition;
109 };
110 
111 // A generic 1-D range.
112 struct TRange {
TRangeTRange113     TRange(int start, int last) : start(start), last(last) { }
overlapTRange114     bool overlap(const TRange& rhs) const
115     {
116         return last >= rhs.start && start <= rhs.last;
117     }
118     int start;
119     int last;
120 };
121 
122 // An IO range is a 3-D rectangle; the set of (location, component, index) triples all lying
123 // within the same location range, component range, and index value.  Locations don't alias unless
124 // all other dimensions of their range overlap.
125 struct TIoRange {
TIoRangeTIoRange126     TIoRange(TRange location, TRange component, TBasicType basicType, int index)
127         : location(location), component(component), basicType(basicType), index(index) { }
overlapTIoRange128     bool overlap(const TIoRange& rhs) const
129     {
130         return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index;
131     }
132     TRange location;
133     TRange component;
134     TBasicType basicType;
135     int index;
136 };
137 
138 // An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying
139 // within the same binding and offset range.
140 struct TOffsetRange {
TOffsetRangeTOffsetRange141     TOffsetRange(TRange binding, TRange offset)
142         : binding(binding), offset(offset) { }
overlapTOffsetRange143     bool overlap(const TOffsetRange& rhs) const
144     {
145         return binding.overlap(rhs.binding) && offset.overlap(rhs.offset);
146     }
147     TRange binding;
148     TRange offset;
149 };
150 
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 
163 // Track a set of strings describing how the module was processed.
164 // This includes command line options, transforms, etc., ideally inclusive enough
165 // to reproduce the steps used to transform the input source to the output.
166 // E.g., see SPIR-V OpModuleProcessed.
167 // Each "process" or "transform" uses is expressed in the form:
168 //   process arg0 arg1 arg2 ...
169 //   process arg0 arg1 arg2 ...
170 // where everything is textual, and there can be zero or more arguments
171 class TProcesses {
172 public:
TProcesses()173     TProcesses() {}
~TProcesses()174     ~TProcesses() {}
175 
addProcess(const char * process)176     void addProcess(const char* process)
177     {
178         processes.push_back(process);
179     }
addProcess(const std::string & process)180     void addProcess(const std::string& process)
181     {
182         processes.push_back(process);
183     }
addArgument(int arg)184     void addArgument(int arg)
185     {
186         processes.back().append(" ");
187         std::string argString = std::to_string(arg);
188         processes.back().append(argString);
189     }
addArgument(const char * arg)190     void addArgument(const char* arg)
191     {
192         processes.back().append(" ");
193         processes.back().append(arg);
194     }
addArgument(const std::string & arg)195     void addArgument(const std::string& arg)
196     {
197         processes.back().append(" ");
198         processes.back().append(arg);
199     }
addIfNonZero(const char * process,int value)200     void addIfNonZero(const char* process, int value)
201     {
202         if (value != 0) {
203             addProcess(process);
204             addArgument(value);
205         }
206     }
207 
getProcesses()208     const std::vector<std::string>& getProcesses() const { return processes; }
209 
210 private:
211     std::vector<std::string> processes;
212 };
213 
214 class TSymbolTable;
215 class TSymbol;
216 class TVariable;
217 
218 //
219 // Texture and Sampler transformation mode.
220 //
221 enum ComputeDerivativeMode {
222     LayoutDerivativeNone,         // default layout as SPV_NV_compute_shader_derivatives not enabled
223     LayoutDerivativeGroupQuads,   // derivative_group_quadsNV
224     LayoutDerivativeGroupLinear,  // derivative_group_linearNV
225 };
226 
227 //
228 // Status type on AST level. Some uncalled status or functions would be reset in call graph.
229 // Currently we will keep status set by explicitly declared layout or variable decl.
230 //
231 enum AstRefType {
232     AstRefTypeVar,         // Status set by variable decl
233     AstRefTypeFunc,        // Status set by function decl
234     AstRefTypeLayout,      // Status set by layout decl
235 };
236 
237 class TIdMaps {
238 public:
239     TMap<TString, long long>& operator[](long long i) { return maps[i]; }
240     const TMap<TString, long long>& operator[](long long i) const { return maps[i]; }
241 private:
242     TMap<TString, long long> maps[EsiCount];
243 };
244 
245 class TNumericFeatures {
246 public:
TNumericFeatures()247     TNumericFeatures() : features(0) { }
248     TNumericFeatures(const TNumericFeatures&) = delete;
249     TNumericFeatures& operator=(const TNumericFeatures&) = delete;
250     typedef enum : unsigned int {
251         shader_explicit_arithmetic_types          = 1 << 0,
252         shader_explicit_arithmetic_types_int8     = 1 << 1,
253         shader_explicit_arithmetic_types_int16    = 1 << 2,
254         shader_explicit_arithmetic_types_int32    = 1 << 3,
255         shader_explicit_arithmetic_types_int64    = 1 << 4,
256         shader_explicit_arithmetic_types_float16  = 1 << 5,
257         shader_explicit_arithmetic_types_float32  = 1 << 6,
258         shader_explicit_arithmetic_types_float64  = 1 << 7,
259         shader_implicit_conversions               = 1 << 8,
260         gpu_shader_fp64                           = 1 << 9,
261         gpu_shader_int16                          = 1 << 10,
262         gpu_shader_half_float                     = 1 << 11,
263     } feature;
insert(feature f)264     void insert(feature f) { features |= f; }
erase(feature f)265     void erase(feature f) { features &= ~f; }
contains(feature f)266     bool contains(feature f) const { return (features & f) != 0; }
267 private:
268     unsigned int features;
269 };
270 
271 // MustBeAssigned wraps a T, asserting that it has been assigned with
272 // operator =() before attempting to read with operator T() or operator ->().
273 // Used to catch cases where fields are read before they have been assigned.
274 template<typename T>
275 class MustBeAssigned
276 {
277 public:
278     MustBeAssigned() = default;
MustBeAssigned(const T & v)279     MustBeAssigned(const T& v) : value(v) {}
280     operator const T&() const { assert(isSet); return value; }
281     const T* operator ->() const { assert(isSet); return &value; }
282     MustBeAssigned& operator = (const T& v) { value = v; isSet = true; return *this; }
283 private:
284     T value;
285     bool isSet = false;
286 };
287 
288 //
289 // Set of helper functions to help parse and build the tree.
290 //
291 class TIntermediate {
292 public:
293     explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
language(l)294         language(l),
295         profile(p), version(v),
296         treeRoot(nullptr),
297         resources(TBuiltInResource{}),
298         numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false),
299         invertY(false),
300         dxPositionW(false),
301         enhancedMsgs(false),
302         debugInfo(false),
303         useStorageBuffer(false),
304         invariantAll(false),
305         nanMinMaxClamp(false),
306         depthReplacing(false),
307         stencilReplacing(false),
308         uniqueId(0),
309         globalUniformBlockName(""),
310         atomicCounterBlockName(""),
311         globalUniformBlockSet(TQualifier::layoutSetEnd),
312         globalUniformBlockBinding(TQualifier::layoutBindingEnd),
313         atomicCounterBlockSet(TQualifier::layoutSetEnd),
314         implicitThisName("@this"), implicitCounterName("@count"),
315         source(EShSourceNone),
316         useVulkanMemoryModel(false),
317         invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet),
318         inputPrimitive(ElgNone), outputPrimitive(ElgNone),
319         pixelCenterInteger(false), originUpperLeft(false),texCoordBuiltinRedeclared(false),
320         vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false),
321         postDepthCoverage(false), earlyAndLateFragmentTestsAMD(false),
322         nonCoherentColorAttachmentReadEXT(false),
323         nonCoherentDepthAttachmentReadEXT(false),
324         nonCoherentStencilAttachmentReadEXT(false),
325         depthLayout(EldNone),
326         stencilLayout(ElsNone),
327         hlslFunctionality1(false),
328         blendEquations(0), xfbMode(false), multiStream(false),
329         layoutOverrideCoverage(false),
330         geoPassthroughEXT(false),
331         numShaderRecordBlocks(0),
332         computeDerivativeMode(LayoutDerivativeNone),
333         primitives(TQualifier::layoutNotSet),
334         numTaskNVBlocks(0),
335         layoutPrimitiveCulling(false),
336         numTaskEXTPayloads(0),
337         autoMapBindings(false),
338         autoMapLocations(false),
339         flattenUniformArrays(false),
340         useUnknownFormat(false),
341         hlslOffsets(false),
342         hlslIoMapping(false),
343         useVariablePointers(false),
344         textureSamplerTransformMode(EShTexSampTransKeep),
345         needToLegalize(false),
346         binaryDoubleOutput(false),
347         subgroupUniformControlFlow(false),
348         usePhysicalStorageBuffer(false),
349         spirvRequirement(nullptr),
350         spirvExecutionMode(nullptr),
351         uniformLocationBase(0)
352     {
353         localSize[0] = 1;
354         localSize[1] = 1;
355         localSize[2] = 1;
356         localSizeNotDefault[0] = false;
357         localSizeNotDefault[1] = false;
358         localSizeNotDefault[2] = false;
359         localSizeSpecId[0] = TQualifier::layoutNotSet;
360         localSizeSpecId[1] = TQualifier::layoutNotSet;
361         localSizeSpecId[2] = TQualifier::layoutNotSet;
362         xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
363         shiftBinding.fill(0);
364     }
365 
setVersion(int v)366     void setVersion(int v)
367     {
368         version = v;
369     }
setProfile(EProfile p)370     void setProfile(EProfile p)
371     {
372         profile = p;
373     }
374 
getVersion()375     int getVersion() const { return version; }
getProfile()376     EProfile getProfile() const { return profile; }
setSpv(const SpvVersion & s)377     void setSpv(const SpvVersion& s)
378     {
379         spvVersion = s;
380 
381         // client processes
382         if (spvVersion.vulkan > 0)
383             processes.addProcess("client vulkan100");
384         if (spvVersion.openGl > 0)
385             processes.addProcess("client opengl100");
386 
387         // target SPV
388         switch (spvVersion.spv) {
389         case 0:
390             break;
391         case EShTargetSpv_1_0:
392             break;
393         case EShTargetSpv_1_1:
394             processes.addProcess("target-env spirv1.1");
395             break;
396         case EShTargetSpv_1_2:
397             processes.addProcess("target-env spirv1.2");
398             break;
399         case EShTargetSpv_1_3:
400             processes.addProcess("target-env spirv1.3");
401             break;
402         case EShTargetSpv_1_4:
403             processes.addProcess("target-env spirv1.4");
404             break;
405         case EShTargetSpv_1_5:
406             processes.addProcess("target-env spirv1.5");
407             break;
408         case EShTargetSpv_1_6:
409             processes.addProcess("target-env spirv1.6");
410             break;
411         default:
412             processes.addProcess("target-env spirvUnknown");
413             break;
414         }
415 
416         // target-environment processes
417         switch (spvVersion.vulkan) {
418         case 0:
419             break;
420         case EShTargetVulkan_1_0:
421             processes.addProcess("target-env vulkan1.0");
422             break;
423         case EShTargetVulkan_1_1:
424             processes.addProcess("target-env vulkan1.1");
425             break;
426         case EShTargetVulkan_1_2:
427             processes.addProcess("target-env vulkan1.2");
428             break;
429         case EShTargetVulkan_1_3:
430             processes.addProcess("target-env vulkan1.3");
431             break;
432         default:
433             processes.addProcess("target-env vulkanUnknown");
434             break;
435         }
436         if (spvVersion.openGl > 0)
437             processes.addProcess("target-env opengl");
438     }
getSpv()439     const SpvVersion& getSpv() const { return spvVersion; }
getStage()440     EShLanguage getStage() const { return language; }
addRequestedExtension(const char * extension)441     void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
getRequestedExtensions()442     const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
isRayTracingStage()443     bool isRayTracingStage() const {
444         return language >= EShLangRayGen && language <= EShLangCallableNV;
445     }
446 
setTreeRoot(TIntermNode * r)447     void setTreeRoot(TIntermNode* r) { treeRoot = r; }
getTreeRoot()448     TIntermNode* getTreeRoot() const { return treeRoot; }
incrementEntryPointCount()449     void incrementEntryPointCount() { ++numEntryPoints; }
getNumEntryPoints()450     int getNumEntryPoints() const { return numEntryPoints; }
getNumErrors()451     int getNumErrors() const { return numErrors; }
addPushConstantCount()452     void addPushConstantCount() { ++numPushConstants; }
setLimits(const TBuiltInResource & r)453     void setLimits(const TBuiltInResource& r) { resources = r; }
getLimits()454     const TBuiltInResource& getLimits() const { return resources; }
455 
456     bool postProcess(TIntermNode*, EShLanguage);
457     void removeTree();
458 
setEntryPointName(const char * ep)459     void setEntryPointName(const char* ep)
460     {
461         entryPointName = ep;
462         processes.addProcess("entry-point");
463         processes.addArgument(entryPointName);
464     }
setEntryPointMangledName(const char * ep)465     void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
getEntryPointName()466     const std::string& getEntryPointName() const { return entryPointName; }
getEntryPointMangledName()467     const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
468 
setDebugInfo(bool debuginfo)469     void setDebugInfo(bool debuginfo)
470     {
471         debugInfo = debuginfo;
472     }
getDebugInfo()473     bool getDebugInfo() const { return debugInfo; }
474 
setInvertY(bool invert)475     void setInvertY(bool invert)
476     {
477         invertY = invert;
478         if (invertY)
479             processes.addProcess("invert-y");
480     }
getInvertY()481     bool getInvertY() const { return invertY; }
482 
setDxPositionW(bool dxPosW)483     void setDxPositionW(bool dxPosW)
484     {
485         dxPositionW = dxPosW;
486         if (dxPositionW)
487             processes.addProcess("dx-position-w");
488     }
getDxPositionW()489     bool getDxPositionW() const { return dxPositionW; }
490 
setEnhancedMsgs()491     void setEnhancedMsgs()
492     {
493         enhancedMsgs = true;
494     }
getEnhancedMsgs()495     bool getEnhancedMsgs() const { return enhancedMsgs && getSource() == EShSourceGlsl; }
496 
497 #ifdef ENABLE_HLSL
setSource(EShSource s)498     void setSource(EShSource s) { source = s; }
getSource()499     EShSource getSource() const { return source; }
500 #else
setSource(EShSource s)501     void setSource(EShSource s) { assert(s == EShSourceGlsl); (void)s; }
getSource()502     EShSource getSource() const { return EShSourceGlsl; }
503 #endif
504 
isRecursive()505     bool isRecursive() const { return recursive; }
506 
507     TIntermSymbol* addSymbol(const TVariable&);
508     TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
509     TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
510     TIntermSymbol* addSymbol(const TIntermSymbol&);
511     TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
512     std::tuple<TIntermTyped*, TIntermTyped*> addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1);
513     TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
514     TIntermTyped* addConversion(TBasicType convertTo, TIntermTyped* node) const;
515     void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
516     TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
517     TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
518     TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
519     TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&);
520     TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, const TSourceLoc&);
521     TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
522     bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const;
523     bool isIntegralPromotion(TBasicType from, TBasicType to) const;
524     bool isFPPromotion(TBasicType from, TBasicType to) const;
525     bool isIntegralConversion(TBasicType from, TBasicType to) const;
526     bool isFPConversion(TBasicType from, TBasicType to) const;
527     bool isFPIntegralConversion(TBasicType from, TBasicType to) const;
528     TOperator mapTypeToConstructorOp(const TType&) const;
529     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
530     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
531     TIntermAggregate* mergeAggregate(TIntermNode* left, TIntermNode* right);
532     TIntermAggregate* mergeAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
533     TIntermAggregate* makeAggregate(TIntermNode* node);
534     TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
535     TIntermAggregate* makeAggregate(const TSourceLoc&);
536     TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, const TSourceLoc&);
537     bool areAllChildConst(TIntermAggregate* aggrNode);
538     TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
539     TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
540     TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
541     TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
542     TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
543     TIntermConstantUnion* addConstantUnion(signed char, const TSourceLoc&, bool literal = false) const;
544     TIntermConstantUnion* addConstantUnion(unsigned char, const TSourceLoc&, bool literal = false) const;
545     TIntermConstantUnion* addConstantUnion(signed short, const TSourceLoc&, bool literal = false) const;
546     TIntermConstantUnion* addConstantUnion(unsigned short, const TSourceLoc&, bool literal = false) const;
547     TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
548     TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
549     TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
550     TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
551     TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
552     TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
553     TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
554     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
555     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
556     TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
557     TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
558         const TSourceLoc&, TIntermLoop*&);
559     TIntermBranch* addBranch(TOperator, const TSourceLoc&);
560     TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
561     template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
562 
563     // Low level functions to add nodes (no conversions or other higher level transformations)
564     // If a type is provided, the node's type will be set to it.
565     TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&) const;
566     TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&,
567         const TType&) const;
568     TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&) const;
569     TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&, const TType&) const;
570 
571     // Constant folding (in Constant.cpp)
572     TIntermTyped* fold(TIntermAggregate* aggrNode);
573     TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
574     TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
575     TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& fields, const TSourceLoc&);
576 
577     // Tree ops
578     static const TIntermTyped* traverseLValueBase(const TIntermTyped*, bool swizzleOkay, bool bufferReferenceOk = false,
579                                                   std::function<bool(const TIntermNode&)> proc = {});
580 
581     // Linkage related
582     void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
583     void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
584     TIntermAggregate* findLinkerObjects() const;
585 
setGlobalUniformBlockName(const char * name)586     void setGlobalUniformBlockName(const char* name) { globalUniformBlockName = std::string(name); }
getGlobalUniformBlockName()587     const char* getGlobalUniformBlockName() const { return globalUniformBlockName.c_str(); }
setGlobalUniformSet(unsigned int set)588     void setGlobalUniformSet(unsigned int set) { globalUniformBlockSet = set; }
getGlobalUniformSet()589     unsigned int getGlobalUniformSet() const { return globalUniformBlockSet; }
setGlobalUniformBinding(unsigned int binding)590     void setGlobalUniformBinding(unsigned int binding) { globalUniformBlockBinding = binding; }
getGlobalUniformBinding()591     unsigned int getGlobalUniformBinding() const { return globalUniformBlockBinding; }
592 
setAtomicCounterBlockName(const char * name)593     void setAtomicCounterBlockName(const char* name) { atomicCounterBlockName = std::string(name); }
getAtomicCounterBlockName()594     const char* getAtomicCounterBlockName() const { return atomicCounterBlockName.c_str(); }
setAtomicCounterBlockSet(unsigned int set)595     void setAtomicCounterBlockSet(unsigned int set) { atomicCounterBlockSet = set; }
getAtomicCounterBlockSet()596     unsigned int getAtomicCounterBlockSet() const { return atomicCounterBlockSet; }
597 
598 
setUseStorageBuffer()599     void setUseStorageBuffer() { useStorageBuffer = true; }
usingStorageBuffer()600     bool usingStorageBuffer() const { return useStorageBuffer; }
setInvariantAll()601     void setInvariantAll() { invariantAll = true; }
isInvariantAll()602     bool isInvariantAll() const { return invariantAll; }
setDepthReplacing()603     void setDepthReplacing() { depthReplacing = true; }
isDepthReplacing()604     bool isDepthReplacing() const { return depthReplacing; }
setStencilReplacing()605     void setStencilReplacing() { stencilReplacing = true; }
isStencilReplacing()606     bool isStencilReplacing() const { return stencilReplacing; }
setLocalSize(int dim,int size)607     bool setLocalSize(int dim, int size)
608     {
609         if (localSizeNotDefault[dim])
610             return size == localSize[dim];
611         localSizeNotDefault[dim] = true;
612         localSize[dim] = size;
613         return true;
614     }
getLocalSize(int dim)615     unsigned int getLocalSize(int dim) const { return localSize[dim]; }
isLocalSizeSet()616     bool isLocalSizeSet() const
617     {
618         // Return true if any component has been set (i.e. any component is not default).
619         return localSizeNotDefault[0] || localSizeNotDefault[1] || localSizeNotDefault[2];
620     }
setLocalSizeSpecId(int dim,int id)621     bool setLocalSizeSpecId(int dim, int id)
622     {
623         if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
624             return id == localSizeSpecId[dim];
625         localSizeSpecId[dim] = id;
626         return true;
627     }
getLocalSizeSpecId(int dim)628     int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
isLocalSizeSpecialized()629     bool isLocalSizeSpecialized() const
630     {
631         // Return true if any component has been specialized.
632         return localSizeSpecId[0] != TQualifier::layoutNotSet ||
633                localSizeSpecId[1] != TQualifier::layoutNotSet ||
634                localSizeSpecId[2] != TQualifier::layoutNotSet;
635     }
636     void output(TInfoSink&, bool tree);
637 
isEsProfile()638     bool isEsProfile() const { return profile == EEsProfile; }
639 
setShiftBinding(TResourceType res,unsigned int shift)640     void setShiftBinding(TResourceType res, unsigned int shift)
641     {
642         shiftBinding[res] = shift;
643 
644         const char* name = getResourceName(res);
645         if (name != nullptr)
646             processes.addIfNonZero(name, shift);
647     }
648 
getShiftBinding(TResourceType res)649     unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; }
650 
setShiftBindingForSet(TResourceType res,unsigned int shift,unsigned int set)651     void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set)
652     {
653         if (shift == 0) // ignore if there's no shift: it's a no-op.
654             return;
655 
656         shiftBindingForSet[res][set] = shift;
657 
658         const char* name = getResourceName(res);
659         if (name != nullptr) {
660             processes.addProcess(name);
661             processes.addArgument(shift);
662             processes.addArgument(set);
663         }
664     }
665 
getShiftBindingForSet(TResourceType res,unsigned int set)666     int getShiftBindingForSet(TResourceType res, unsigned int set) const
667     {
668         const auto shift = shiftBindingForSet[res].find(set);
669         return shift == shiftBindingForSet[res].end() ? -1 : shift->second;
670     }
hasShiftBindingForSet(TResourceType res)671     bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); }
672 
setResourceSetBinding(const std::vector<std::string> & shift)673     void setResourceSetBinding(const std::vector<std::string>& shift)
674     {
675         resourceSetBinding = shift;
676         if (shift.size() > 0) {
677             processes.addProcess("resource-set-binding");
678             for (int s = 0; s < (int)shift.size(); ++s)
679                 processes.addArgument(shift[s]);
680         }
681     }
getResourceSetBinding()682     const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
setAutoMapBindings(bool map)683     void setAutoMapBindings(bool map)
684     {
685         autoMapBindings = map;
686         if (autoMapBindings)
687             processes.addProcess("auto-map-bindings");
688     }
getAutoMapBindings()689     bool getAutoMapBindings() const { return autoMapBindings; }
setAutoMapLocations(bool map)690     void setAutoMapLocations(bool map)
691     {
692         autoMapLocations = map;
693         if (autoMapLocations)
694             processes.addProcess("auto-map-locations");
695     }
getAutoMapLocations()696     bool getAutoMapLocations() const { return autoMapLocations; }
697 
698 #ifdef ENABLE_HLSL
setFlattenUniformArrays(bool flatten)699     void setFlattenUniformArrays(bool flatten)
700     {
701         flattenUniformArrays = flatten;
702         if (flattenUniformArrays)
703             processes.addProcess("flatten-uniform-arrays");
704     }
getFlattenUniformArrays()705     bool getFlattenUniformArrays() const { return flattenUniformArrays; }
706 #endif
setNoStorageFormat(bool b)707     void setNoStorageFormat(bool b)
708     {
709         useUnknownFormat = b;
710         if (useUnknownFormat)
711             processes.addProcess("no-storage-format");
712     }
getNoStorageFormat()713     bool getNoStorageFormat() const { return useUnknownFormat; }
setUseVulkanMemoryModel()714     void setUseVulkanMemoryModel()
715     {
716         useVulkanMemoryModel = true;
717         processes.addProcess("use-vulkan-memory-model");
718     }
usingVulkanMemoryModel()719     bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
setUsePhysicalStorageBuffer()720     void setUsePhysicalStorageBuffer()
721     {
722         usePhysicalStorageBuffer = true;
723     }
usingPhysicalStorageBuffer()724     bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
setUseVariablePointers()725     void setUseVariablePointers()
726     {
727         useVariablePointers = true;
728         processes.addProcess("use-variable-pointers");
729     }
730     // Set the global flag for bindless texture
setBindlessTextureMode(const TString & currentCaller,AstRefType type)731     void setBindlessTextureMode(const TString& currentCaller, AstRefType type)
732     {
733         // When type is not func, currentCaller should be "" (empty string)
734         bindlessTextureModeCaller[currentCaller] = type;
735     }
736 
737     // Get the global flag for bindless texture
getBindlessTextureMode()738     bool getBindlessTextureMode() const
739     {
740         return (bindlessTextureModeCaller.size() > 0);
741     }
742 
743     // Set the global flag for bindless image
setBindlessImageMode(const TString & currentCaller,AstRefType type)744     void setBindlessImageMode(const TString& currentCaller, AstRefType type)
745     {
746         // When type is not func, currentCaller should be "" (empty string)
747         bindlessImageModeCaller[currentCaller] = type;
748     }
749 
750     // Get the global flag for bindless image
getBindlessImageMode()751     bool getBindlessImageMode() const
752     {
753         return (bindlessImageModeCaller.size() > 0);
754     }
755 
756     // Get the global flag for bindless texture
resetTopLevelUncalledStatus(const TString & deadCaller)757     bool resetTopLevelUncalledStatus(const TString& deadCaller)
758     {
759         // For reflection collection purpose, currently uniform layout setting and some
760         // flags introduced by variables (IO, global, etc,.) won't be reset here.
761         // Remove each global status (AST top level) introduced by uncalled functions.
762         // If a status is set by several functions, keep those which in call graph.
763         bool result = false;
764 
765         // For two types of bindless mode flag, we would only reset which is set by an uncalled function.
766         // If one status flag's key in caller vec is empty, it should be come from a non-function setting.
767         if (!bindlessTextureModeCaller.empty()) {
768             auto caller = bindlessTextureModeCaller.find(deadCaller);
769             if (caller != bindlessTextureModeCaller.end() && bindlessTextureModeCaller[deadCaller] == AstRefTypeFunc) {
770                 bindlessTextureModeCaller.erase(caller);
771                 result = true;
772             }
773         }
774         if (!bindlessImageModeCaller.empty()) {
775             auto caller = bindlessImageModeCaller.find(deadCaller);
776             if (caller != bindlessImageModeCaller.end() && bindlessImageModeCaller[deadCaller] == AstRefTypeFunc) {
777                 bindlessImageModeCaller.erase(caller);
778                 result = true;
779             }
780         }
781         return result;
782     }
783 
getBindlessMode()784     bool getBindlessMode() const
785     {
786         return getBindlessTextureMode() || getBindlessImageMode();
787     }
788 
usingVariablePointers()789     bool usingVariablePointers() const { return useVariablePointers; }
790 
791 #ifdef ENABLE_HLSL
addCounterBufferName(const T & name)792     template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
hasCounterBufferName(const TString & name)793     bool hasCounterBufferName(const TString& name) const {
794         size_t len = strlen(implicitCounterName);
795         return name.size() > len &&
796                name.compare(name.size() - len, len, implicitCounterName) == 0;
797     }
798 #endif
799 
setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode)800     void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
getNumPushConstants()801     int getNumPushConstants() const { return numPushConstants; }
addShaderRecordCount()802     void addShaderRecordCount() { ++numShaderRecordBlocks; }
addTaskNVCount()803     void addTaskNVCount() { ++numTaskNVBlocks; }
addTaskPayloadEXTCount()804     void addTaskPayloadEXTCount() { ++numTaskEXTPayloads; }
805 
setInvocations(int i)806     bool setInvocations(int i)
807     {
808         if (invocations != TQualifier::layoutNotSet)
809             return invocations == i;
810         invocations = i;
811         return true;
812     }
getInvocations()813     int getInvocations() const { return invocations; }
setVertices(int m)814     bool setVertices(int m)
815     {
816         if (vertices != TQualifier::layoutNotSet)
817             return vertices == m;
818         vertices = m;
819         return true;
820     }
getVertices()821     int getVertices() const { return vertices; }
setInputPrimitive(TLayoutGeometry p)822     bool setInputPrimitive(TLayoutGeometry p)
823     {
824         if (inputPrimitive != ElgNone)
825             return inputPrimitive == p;
826         inputPrimitive = p;
827         return true;
828     }
getInputPrimitive()829     TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
setVertexSpacing(TVertexSpacing s)830     bool setVertexSpacing(TVertexSpacing s)
831     {
832         if (vertexSpacing != EvsNone)
833             return vertexSpacing == s;
834         vertexSpacing = s;
835         return true;
836     }
getVertexSpacing()837     TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
setVertexOrder(TVertexOrder o)838     bool setVertexOrder(TVertexOrder o)
839     {
840         if (vertexOrder != EvoNone)
841             return vertexOrder == o;
842         vertexOrder = o;
843         return true;
844     }
getVertexOrder()845     TVertexOrder getVertexOrder() const { return vertexOrder; }
setPointMode()846     void setPointMode() { pointMode = true; }
getPointMode()847     bool getPointMode() const { return pointMode; }
848 
setInterlockOrdering(TInterlockOrdering o)849     bool setInterlockOrdering(TInterlockOrdering o)
850     {
851         if (interlockOrdering != EioNone)
852             return interlockOrdering == o;
853         interlockOrdering = o;
854         return true;
855     }
getInterlockOrdering()856     TInterlockOrdering getInterlockOrdering() const { return interlockOrdering; }
857 
setXfbMode()858     void setXfbMode() { xfbMode = true; }
getXfbMode()859     bool getXfbMode() const { return xfbMode; }
setMultiStream()860     void setMultiStream() { multiStream = true; }
isMultiStream()861     bool isMultiStream() const { return multiStream; }
setOutputPrimitive(TLayoutGeometry p)862     bool setOutputPrimitive(TLayoutGeometry p)
863     {
864         if (outputPrimitive != ElgNone)
865             return outputPrimitive == p;
866         outputPrimitive = p;
867         return true;
868     }
getOutputPrimitive()869     TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
setNonCoherentColorAttachmentReadEXT()870     void setNonCoherentColorAttachmentReadEXT() { nonCoherentColorAttachmentReadEXT = true; }
getNonCoherentColorAttachmentReadEXT()871     bool getNonCoherentColorAttachmentReadEXT() const { return nonCoherentColorAttachmentReadEXT; }
setNonCoherentDepthAttachmentReadEXT()872     void setNonCoherentDepthAttachmentReadEXT() { nonCoherentDepthAttachmentReadEXT = true; }
getNonCoherentDepthAttachmentReadEXT()873     bool getNonCoherentDepthAttachmentReadEXT() const { return nonCoherentDepthAttachmentReadEXT; }
setNonCoherentStencilAttachmentReadEXT()874     void setNonCoherentStencilAttachmentReadEXT() { nonCoherentStencilAttachmentReadEXT = true; }
getNonCoherentStencilAttachmentReadEXT()875     bool getNonCoherentStencilAttachmentReadEXT() const { return nonCoherentStencilAttachmentReadEXT; }
setPostDepthCoverage()876     void setPostDepthCoverage() { postDepthCoverage = true; }
getPostDepthCoverage()877     bool getPostDepthCoverage() const { return postDepthCoverage; }
setEarlyFragmentTests()878     void setEarlyFragmentTests() { earlyFragmentTests = true; }
setEarlyAndLateFragmentTestsAMD()879     void setEarlyAndLateFragmentTestsAMD() { earlyAndLateFragmentTestsAMD = true; }
getEarlyFragmentTests()880     bool getEarlyFragmentTests() const { return earlyFragmentTests; }
getEarlyAndLateFragmentTestsAMD()881     bool getEarlyAndLateFragmentTestsAMD() const { return earlyAndLateFragmentTestsAMD; }
setDepth(TLayoutDepth d)882     bool setDepth(TLayoutDepth d)
883     {
884         if (depthLayout != EldNone)
885             return depthLayout == d;
886         depthLayout = d;
887         return true;
888     }
setStencil(TLayoutStencil s)889     bool setStencil(TLayoutStencil s)
890     {
891         if (stencilLayout != ElsNone)
892             return stencilLayout == s;
893         stencilLayout = s;
894         return true;
895     }
getDepth()896     TLayoutDepth getDepth() const { return depthLayout; }
getStencil()897     TLayoutStencil getStencil() const { return stencilLayout; }
setOriginUpperLeft()898     void setOriginUpperLeft() { originUpperLeft = true; }
getOriginUpperLeft()899     bool getOriginUpperLeft() const { return originUpperLeft; }
setPixelCenterInteger()900     void setPixelCenterInteger() { pixelCenterInteger = true; }
getPixelCenterInteger()901     bool getPixelCenterInteger() const { return pixelCenterInteger; }
setTexCoordRedeclared()902     void setTexCoordRedeclared() { texCoordBuiltinRedeclared = true; }
getTexCoordRedeclared()903     bool getTexCoordRedeclared() const { return texCoordBuiltinRedeclared; }
addBlendEquation(TBlendEquationShift b)904     void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
getBlendEquations()905     unsigned int getBlendEquations() const { return blendEquations; }
setXfbBufferStride(int buffer,unsigned stride)906     bool setXfbBufferStride(int buffer, unsigned stride)
907     {
908         if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
909             return xfbBuffers[buffer].stride == stride;
910         xfbBuffers[buffer].stride = stride;
911         return true;
912     }
getXfbStride(int buffer)913     unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
914     int addXfbBufferOffset(const TType&);
915     unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const;
916     unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType) const;
setLayoutOverrideCoverage()917     void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
getLayoutOverrideCoverage()918     bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
setGeoPassthroughEXT()919     void setGeoPassthroughEXT() { geoPassthroughEXT = true; }
getGeoPassthroughEXT()920     bool getGeoPassthroughEXT() const { return geoPassthroughEXT; }
setLayoutDerivativeMode(ComputeDerivativeMode mode)921     void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; }
hasLayoutDerivativeModeNone()922     bool hasLayoutDerivativeModeNone() const { return computeDerivativeMode != LayoutDerivativeNone; }
getLayoutDerivativeModeNone()923     ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; }
setLayoutPrimitiveCulling()924     void setLayoutPrimitiveCulling() { layoutPrimitiveCulling = true; }
getLayoutPrimitiveCulling()925     bool getLayoutPrimitiveCulling() const { return layoutPrimitiveCulling; }
setPrimitives(int m)926     bool setPrimitives(int m)
927     {
928         if (primitives != TQualifier::layoutNotSet)
929             return primitives == m;
930         primitives = m;
931         return true;
932     }
getPrimitives()933     int getPrimitives() const { return primitives; }
addSemanticName(const TString & name)934     const char* addSemanticName(const TString& name)
935     {
936         return semanticNameSet.insert(name).first->c_str();
937     }
addUniformLocationOverride(const char * nameStr,int location)938     void addUniformLocationOverride(const char* nameStr, int location)
939     {
940         std::string name = nameStr;
941         uniformLocationOverrides[name] = location;
942     }
943 
getUniformLocationOverride(const char * nameStr)944     int getUniformLocationOverride(const char* nameStr) const
945     {
946         std::string name = nameStr;
947         auto pos = uniformLocationOverrides.find(name);
948         if (pos == uniformLocationOverrides.end())
949             return -1;
950         else
951             return pos->second;
952     }
953 
setUniformLocationBase(int base)954     void setUniformLocationBase(int base) { uniformLocationBase = base; }
getUniformLocationBase()955     int getUniformLocationBase() const { return uniformLocationBase; }
956 
setNeedsLegalization()957     void setNeedsLegalization() { needToLegalize = true; }
needsLegalization()958     bool needsLegalization() const { return needToLegalize; }
959 
setBinaryDoubleOutput()960     void setBinaryDoubleOutput() { binaryDoubleOutput = true; }
getBinaryDoubleOutput()961     bool getBinaryDoubleOutput() { return binaryDoubleOutput; }
962 
setSubgroupUniformControlFlow()963     void setSubgroupUniformControlFlow() { subgroupUniformControlFlow = true; }
getSubgroupUniformControlFlow()964     bool getSubgroupUniformControlFlow() const { return subgroupUniformControlFlow; }
965 
966     // GL_EXT_spirv_intrinsics
967     void insertSpirvRequirement(const TSpirvRequirement* spirvReq);
hasSpirvRequirement()968     bool hasSpirvRequirement() const { return spirvRequirement != nullptr; }
getSpirvRequirement()969     const TSpirvRequirement& getSpirvRequirement() const { return *spirvRequirement; }
970     void insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args = nullptr);
971     void insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args);
hasSpirvExecutionMode()972     bool hasSpirvExecutionMode() const { return spirvExecutionMode != nullptr; }
getSpirvExecutionMode()973     const TSpirvExecutionMode& getSpirvExecutionMode() const { return *spirvExecutionMode; }
974 
addBlockStorageOverride(const char * nameStr,TBlockStorageClass backing)975     void addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing)
976     {
977         std::string name(nameStr);
978         blockBackingOverrides[name] = backing;
979     }
getBlockStorageOverride(const char * nameStr)980     TBlockStorageClass getBlockStorageOverride(const char* nameStr) const
981     {
982         std::string name = nameStr;
983         auto pos = blockBackingOverrides.find(name);
984         if (pos == blockBackingOverrides.end())
985             return EbsNone;
986         else
987             return pos->second;
988     }
989 #ifdef ENABLE_HLSL
setHlslFunctionality1()990     void setHlslFunctionality1() { hlslFunctionality1 = true; }
getHlslFunctionality1()991     bool getHlslFunctionality1() const { return hlslFunctionality1; }
setHlslOffsets()992     void setHlslOffsets()
993     {
994         hlslOffsets = true;
995         if (hlslOffsets)
996             processes.addProcess("hlsl-offsets");
997     }
usingHlslOffsets()998     bool usingHlslOffsets() const { return hlslOffsets; }
setHlslIoMapping(bool b)999     void setHlslIoMapping(bool b)
1000     {
1001         hlslIoMapping = b;
1002         if (hlslIoMapping)
1003             processes.addProcess("hlsl-iomap");
1004     }
usingHlslIoMapping()1005     bool usingHlslIoMapping() { return hlslIoMapping; }
1006 #else
getHlslFunctionality1()1007     bool getHlslFunctionality1() const { return false; }
usingHlslOffsets()1008     bool usingHlslOffsets() const { return false; }
usingHlslIoMapping()1009     bool usingHlslIoMapping() { return false; }
1010 #endif
1011 
usingScalarBlockLayout()1012     bool usingScalarBlockLayout() const {
1013         for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt) {
1014             if (*extIt == E_GL_EXT_scalar_block_layout)
1015                 return true;
1016         }
1017         return false;
1018     }
1019 
IsRequestedExtension(const char * extension)1020     bool IsRequestedExtension(const char* extension) const
1021     {
1022         return (requestedExtensions.find(extension) != requestedExtensions.end());
1023     }
1024 
1025     void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
1026     void merge(TInfoSink&, TIntermediate&);
1027     void finalCheck(TInfoSink&, bool keepUncalled);
1028 
1029     void mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& unit, bool mergeExistingOnly);
1030     void mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit);
1031     void checkStageIO(TInfoSink&, TIntermediate&);
1032 
1033     bool buildConvertOp(TBasicType dst, TBasicType src, TOperator& convertOp) const;
1034     TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const;
1035 
addIoAccessed(const TString & name)1036     void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
inIoAccessed(const TString & name)1037     bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
1038 
1039     int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
1040     int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision);
1041     int checkLocationRT(int set, int location);
1042     int addUsedOffsets(int binding, int offset, int numOffsets);
1043     bool addUsedConstantId(int id);
1044     static int computeTypeLocationSize(const TType&, EShLanguage);
1045     static int computeTypeUniformLocationSize(const TType&);
1046 
1047     static int getBaseAlignmentScalar(const TType&, int& size);
1048     static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
1049     static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
1050     static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
1051     static bool improperStraddle(const TType& type, int size, int offset);
1052     static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize);
1053     static int getOffset(const TType& type, int index);
1054     static int getBlockSize(const TType& blockType);
1055     static int computeBufferReferenceTypeSize(const TType&);
1056     static bool isIoResizeArray(const TType& type, EShLanguage language);
1057 
1058     bool promote(TIntermOperator*);
setNanMinMaxClamp(bool setting)1059     void setNanMinMaxClamp(bool setting) { nanMinMaxClamp = setting; }
getNanMinMaxClamp()1060     bool getNanMinMaxClamp() const { return nanMinMaxClamp; }
1061 
setSourceFile(const char * file)1062     void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
getSourceFile()1063     const std::string& getSourceFile() const { return sourceFile; }
addSourceText(const char * text,size_t len)1064     void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
getSourceText()1065     const std::string& getSourceText() const { return sourceText; }
getIncludeText()1066     const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
addIncludeText(const char * name,const char * text,size_t len)1067     void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
addProcesses(const std::vector<std::string> & p)1068     void addProcesses(const std::vector<std::string>& p)
1069     {
1070         for (int i = 0; i < (int)p.size(); ++i)
1071             processes.addProcess(p[i]);
1072     }
addProcess(const std::string & process)1073     void addProcess(const std::string& process) { processes.addProcess(process); }
addProcessArgument(const std::string & arg)1074     void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
getProcesses()1075     const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
getUniqueId()1076     unsigned long long getUniqueId() const { return uniqueId; }
setUniqueId(unsigned long long id)1077     void setUniqueId(unsigned long long id) { uniqueId = id; }
1078 
1079     // Certain explicit conversions are allowed conditionally
getArithemeticInt8Enabled()1080     bool getArithemeticInt8Enabled() const {
1081         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1082                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8);
1083     }
getArithemeticInt16Enabled()1084     bool getArithemeticInt16Enabled() const {
1085         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1086                numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
1087                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16);
1088     }
1089 
getArithemeticFloat16Enabled()1090     bool getArithemeticFloat16Enabled() const {
1091         return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1092                numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
1093                numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
1094     }
updateNumericFeature(TNumericFeatures::feature f,bool on)1095     void updateNumericFeature(TNumericFeatures::feature f, bool on)
1096         { on ? numericFeatures.insert(f) : numericFeatures.erase(f); }
1097 
1098 protected:
1099     TIntermSymbol* addSymbol(long long Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
1100     void error(TInfoSink& infoSink, const char*, EShLanguage unitStage = EShLangCount);
1101     void warn(TInfoSink& infoSink, const char*, EShLanguage unitStage = EShLangCount);
1102     void mergeCallGraphs(TInfoSink&, TIntermediate&);
1103     void mergeModes(TInfoSink&, TIntermediate&);
1104     void mergeTrees(TInfoSink&, TIntermediate&);
1105     void seedIdMap(TIdMaps& idMaps, long long& IdShift);
1106     void remapIds(const TIdMaps& idMaps, long long idShift, TIntermediate&);
1107     void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
1108     void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects, EShLanguage);
1109     void mergeBlockDefinitions(TInfoSink&, TIntermSymbol* block, TIntermSymbol* unitBlock, TIntermediate* unitRoot);
1110     void mergeImplicitArraySizes(TType&, const TType&);
1111     void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, EShLanguage);
1112     void checkCallGraphCycles(TInfoSink&);
1113     void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
1114     void inOutLocationCheck(TInfoSink&);
1115     void sharedBlockCheck(TInfoSink&);
1116     bool userOutputUsed() const;
1117     bool isSpecializationOperation(const TIntermOperator&) const;
1118     bool isNonuniformPropagating(TOperator) const;
1119     bool promoteUnary(TIntermUnary&);
1120     bool promoteBinary(TIntermBinary&);
1121     void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
1122     bool promoteAggregate(TIntermAggregate&);
1123     void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&);
1124     void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
1125     bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&);
1126     void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root);
1127     bool isConversionAllowed(TOperator op, TIntermTyped* node) const;
1128     std::tuple<TBasicType, TBasicType> getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const;
1129 
1130     static const char* getResourceName(TResourceType);
1131 
1132     const EShLanguage language;  // stage, known at construction time
1133     std::string entryPointName;
1134     std::string entryPointMangledName;
1135     typedef std::list<TCall> TGraph;
1136     TGraph callGraph;
1137 
1138     EProfile profile;                           // source profile
1139     int version;                                // source version
1140     SpvVersion spvVersion;
1141     TIntermNode* treeRoot;
1142     std::set<std::string> requestedExtensions;  // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
1143     MustBeAssigned<TBuiltInResource> resources;
1144     int numEntryPoints;
1145     int numErrors;
1146     int numPushConstants;
1147     bool recursive;
1148     bool invertY;
1149     bool dxPositionW;
1150     bool enhancedMsgs;
1151     bool debugInfo;
1152     bool useStorageBuffer;
1153     bool invariantAll;
1154     bool nanMinMaxClamp;            // true if desiring min/max/clamp to favor non-NaN over NaN
1155     bool depthReplacing;
1156     bool stencilReplacing;
1157     int localSize[3];
1158     bool localSizeNotDefault[3];
1159     int localSizeSpecId[3];
1160     unsigned long long uniqueId;
1161 
1162     std::string globalUniformBlockName;
1163     std::string atomicCounterBlockName;
1164     unsigned int globalUniformBlockSet;
1165     unsigned int globalUniformBlockBinding;
1166     unsigned int atomicCounterBlockSet;
1167 
1168 public:
1169     const char* const implicitThisName;
1170     const char* const implicitCounterName;
1171 protected:
1172     EShSource source;            // source language, known a bit later
1173     bool useVulkanMemoryModel;
1174     int invocations;
1175     int vertices;
1176     TLayoutGeometry inputPrimitive;
1177     TLayoutGeometry outputPrimitive;
1178     bool pixelCenterInteger;
1179     bool originUpperLeft;
1180     bool texCoordBuiltinRedeclared;
1181     TVertexSpacing vertexSpacing;
1182     TVertexOrder vertexOrder;
1183     TInterlockOrdering interlockOrdering;
1184     bool pointMode;
1185     bool earlyFragmentTests;
1186     bool postDepthCoverage;
1187     bool earlyAndLateFragmentTestsAMD;
1188     bool nonCoherentColorAttachmentReadEXT;
1189     bool nonCoherentDepthAttachmentReadEXT;
1190     bool nonCoherentStencilAttachmentReadEXT;
1191     TLayoutDepth depthLayout;
1192     TLayoutStencil stencilLayout;
1193     bool hlslFunctionality1;
1194     int blendEquations;        // an 'or'ing of masks of shifts of TBlendEquationShift
1195     bool xfbMode;
1196     std::vector<TXfbBuffer> xfbBuffers;     // all the data we need to track per xfb buffer
1197     bool multiStream;
1198     bool layoutOverrideCoverage;
1199     bool geoPassthroughEXT;
1200     int numShaderRecordBlocks;
1201     ComputeDerivativeMode computeDerivativeMode;
1202     int primitives;
1203     int numTaskNVBlocks;
1204     bool layoutPrimitiveCulling;
1205     int numTaskEXTPayloads;
1206 
1207     // Base shift values
1208     std::array<unsigned int, EResCount> shiftBinding;
1209 
1210     // Per-descriptor-set shift values
1211     std::array<std::map<int, int>, EResCount> shiftBindingForSet;
1212 
1213     std::vector<std::string> resourceSetBinding;
1214     bool autoMapBindings;
1215     bool autoMapLocations;
1216     bool flattenUniformArrays;
1217     bool useUnknownFormat;
1218     bool hlslOffsets;
1219     bool hlslIoMapping;
1220     bool useVariablePointers;
1221 
1222     std::set<TString> semanticNameSet;
1223 
1224     EShTextureSamplerTransformMode textureSamplerTransformMode;
1225 
1226     bool needToLegalize;
1227     bool binaryDoubleOutput;
1228     bool subgroupUniformControlFlow;
1229     bool usePhysicalStorageBuffer;
1230 
1231     TSpirvRequirement* spirvRequirement;
1232     TSpirvExecutionMode* spirvExecutionMode;
1233     std::map<TString, AstRefType> bindlessTextureModeCaller;
1234     std::map<TString, AstRefType> bindlessImageModeCaller;
1235     std::unordered_map<std::string, int> uniformLocationOverrides;
1236     int uniformLocationBase;
1237     TNumericFeatures numericFeatures;
1238     std::unordered_map<std::string, TBlockStorageClass> blockBackingOverrides;
1239 
1240     std::unordered_set<int> usedConstantId; // specialization constant ids used
1241     std::vector<TOffsetRange> usedAtomics;  // sets of bindings used by atomic counters
1242     std::vector<TIoRange> usedIo[4];        // sets of used locations, one for each of in, out, uniform, and buffers
1243     std::vector<TRange> usedIoRT[4];        // sets of used location, one for rayPayload/rayPayloadIN,
1244                                             // one for callableData/callableDataIn, one for hitObjectAttributeNV and
1245                                             // one for shaderrecordhitobjectNV
1246     // set of names of statically read/written I/O that might need extra checking
1247     std::set<TString> ioAccessed;
1248 
1249     // source code of shader, useful as part of debug information
1250     std::string sourceFile;
1251     std::string sourceText;
1252 
1253     // Included text. First string is a name, second is the included text
1254     std::map<std::string, std::string> includeText;
1255 
1256     // for OpModuleProcessed, or equivalent
1257     TProcesses processes;
1258 
1259 private:
1260     void operator=(TIntermediate&); // prevent assignments
1261 };
1262 
1263 } // end namespace glslang
1264 
1265 #endif // _LOCAL_INTERMEDIATE_INCLUDED_
1266