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.
7 // All rights reserved.
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions
13 // Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
39 #ifndef _LOCAL_INTERMEDIATE_INCLUDED_
40 #define _LOCAL_INTERMEDIATE_INCLUDED_
42 #include "../Include/intermediate.h"
43 #include "../Public/ShaderLang.h"
56 struct TMatrixSelector {
57 int coord1; // stay agnostic about column/row; this is parse order
61 typedef int TVectorSelector;
63 const int MaxSwizzleSelectors = 4;
65 template<typename selectorType>
66 class TSwizzleSelectors {
68 TSwizzleSelectors() : size_(0) { }
70 void push_back(selectorType comp)
72 if (size_ < MaxSwizzleSelectors)
73 components[size_++] = comp;
80 int size() const { return size_; }
81 selectorType operator[](int i) const
83 assert(i < MaxSwizzleSelectors);
89 selectorType components[MaxSwizzleSelectors];
93 // Some helper structures for TIntermediate. Their contents are encapsulated
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.
101 TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { }
107 int calleeBodyPosition;
110 // A generic 1-D range.
112 TRange(int start, int last) : start(start), last(last) { }
113 bool overlap(const TRange& rhs) const
115 return last >= rhs.start && start <= rhs.last;
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.
125 TIoRange(TRange location, TRange component, TBasicType basicType, int index)
126 : location(location), component(component), basicType(basicType), index(index) { }
127 bool overlap(const TIoRange& rhs) const
129 return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index;
133 TBasicType basicType;
137 // An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying
138 // within the same binding and offset range.
139 struct TOffsetRange {
140 TOffsetRange(TRange binding, TRange offset)
141 : binding(binding), offset(offset) { }
142 bool overlap(const TOffsetRange& rhs) const
144 return binding.overlap(rhs.binding) && offset.overlap(rhs.offset);
151 // Things that need to be tracked per xfb buffer.
153 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
157 unsigned int implicitStride;
158 bool contains64BitType;
159 bool contains32BitType;
160 bool contains16BitType;
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
177 void addProcess(const char* process)
179 processes.push_back(process);
181 void addProcess(const std::string& process)
183 processes.push_back(process);
185 void addArgument(int arg)
187 processes.back().append(" ");
188 std::string argString = std::to_string(arg);
189 processes.back().append(argString);
191 void addArgument(const char* arg)
193 processes.back().append(" ");
194 processes.back().append(arg);
196 void addArgument(const std::string& arg)
198 processes.back().append(" ");
199 processes.back().append(arg);
201 void addIfNonZero(const char* process, int value)
209 const std::vector<std::string>& getProcesses() const { return processes; }
212 std::vector<std::string> processes;
220 // Texture and Sampler transformation mode.
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
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]; }
233 TMap<TString, long long> maps[EsiCount];
236 class 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,
255 void insert(feature f) { features |= f; }
256 void erase(feature f) { features &= ~f; }
257 bool contains(feature f) const { return (features & f) != 0; }
259 unsigned int features;
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.
269 MustBeAssigned() = default;
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; }
280 // Set of helper functions to help parse and build the tree.
282 class TIntermediate {
284 explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
286 #ifndef GLSLANG_ANGLE
287 profile(p), version(v),
290 resources(TBuiltInResource{}),
291 numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false),
293 useStorageBuffer(false),
295 nanMinMaxClamp(false),
296 depthReplacing(false),
298 globalUniformBlockName(""),
299 atomicCounterBlockName(""),
300 globalUniformBlockSet(TQualifier::layoutSetEnd),
301 globalUniformBlockBinding(TQualifier::layoutBindingEnd),
302 atomicCounterBlockSet(TQualifier::layoutSetEnd)
305 implicitThisName("@this"), implicitCounterName("@count"),
306 source(EShSourceNone),
307 useVulkanMemoryModel(false),
308 invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet),
309 inputPrimitive(ElgNone), outputPrimitive(ElgNone),
310 pixelCenterInteger(false), originUpperLeft(false),
311 vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false),
312 postDepthCoverage(false), depthLayout(EldNone),
313 hlslFunctionality1(false),
314 blendEquations(0), xfbMode(false), multiStream(false),
315 layoutOverrideCoverage(false),
316 geoPassthroughEXT(false),
317 numShaderRecordBlocks(0),
318 computeDerivativeMode(LayoutDerivativeNone),
319 primitives(TQualifier::layoutNotSet),
321 layoutPrimitiveCulling(false),
322 autoMapBindings(false),
323 autoMapLocations(false),
324 flattenUniformArrays(false),
325 useUnknownFormat(false),
327 hlslIoMapping(false),
328 useVariablePointers(false),
329 textureSamplerTransformMode(EShTexSampTransKeep),
330 needToLegalize(false),
331 binaryDoubleOutput(false),
332 subgroupUniformControlFlow(false),
333 usePhysicalStorageBuffer(false),
334 spirvRequirement(nullptr),
335 spirvExecutionMode(nullptr),
336 uniformLocationBase(0)
342 localSizeNotDefault[0] = false;
343 localSizeNotDefault[1] = false;
344 localSizeNotDefault[2] = false;
345 localSizeSpecId[0] = TQualifier::layoutNotSet;
346 localSizeSpecId[1] = TQualifier::layoutNotSet;
347 localSizeSpecId[2] = TQualifier::layoutNotSet;
349 xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
350 shiftBinding.fill(0);
354 void setVersion(int v)
356 #ifndef GLSLANG_ANGLE
360 void setProfile(EProfile p)
362 #ifndef GLSLANG_ANGLE
367 int getVersion() const { return version; }
368 EProfile getProfile() const { return profile; }
369 void setSpv(const SpvVersion& s)
374 if (spvVersion.vulkan > 0)
375 processes.addProcess("client vulkan100");
376 if (spvVersion.openGl > 0)
377 processes.addProcess("client opengl100");
380 switch (spvVersion.spv) {
383 case EShTargetSpv_1_0:
385 case EShTargetSpv_1_1:
386 processes.addProcess("target-env spirv1.1");
388 case EShTargetSpv_1_2:
389 processes.addProcess("target-env spirv1.2");
391 case EShTargetSpv_1_3:
392 processes.addProcess("target-env spirv1.3");
394 case EShTargetSpv_1_4:
395 processes.addProcess("target-env spirv1.4");
397 case EShTargetSpv_1_5:
398 processes.addProcess("target-env spirv1.5");
401 processes.addProcess("target-env spirvUnknown");
405 // target-environment processes
406 switch (spvVersion.vulkan) {
409 case EShTargetVulkan_1_0:
410 processes.addProcess("target-env vulkan1.0");
412 case EShTargetVulkan_1_1:
413 processes.addProcess("target-env vulkan1.1");
415 case EShTargetVulkan_1_2:
416 processes.addProcess("target-env vulkan1.2");
419 processes.addProcess("target-env vulkanUnknown");
422 if (spvVersion.openGl > 0)
423 processes.addProcess("target-env opengl");
425 const SpvVersion& getSpv() const { return spvVersion; }
426 EShLanguage getStage() const { return language; }
427 void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
428 const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
429 bool isRayTracingStage() const {
430 return language >= EShLangRayGen && language <= EShLangCallableNV;
433 void setTreeRoot(TIntermNode* r) { treeRoot = r; }
434 TIntermNode* getTreeRoot() const { return treeRoot; }
435 void incrementEntryPointCount() { ++numEntryPoints; }
436 int getNumEntryPoints() const { return numEntryPoints; }
437 int getNumErrors() const { return numErrors; }
438 void addPushConstantCount() { ++numPushConstants; }
439 void setLimits(const TBuiltInResource& r) { resources = r; }
440 const TBuiltInResource& getLimits() const { return resources; }
442 bool postProcess(TIntermNode*, EShLanguage);
445 void setEntryPointName(const char* ep)
448 processes.addProcess("entry-point");
449 processes.addArgument(entryPointName);
451 void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
452 const std::string& getEntryPointName() const { return entryPointName; }
453 const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
455 void setInvertY(bool invert)
459 processes.addProcess("invert-y");
461 bool getInvertY() const { return invertY; }
464 void setSource(EShSource s) { source = s; }
465 EShSource getSource() const { return source; }
467 void setSource(EShSource s) { assert(s == EShSourceGlsl); (void)s; }
468 EShSource getSource() const { return EShSourceGlsl; }
471 bool isRecursive() const { return recursive; }
473 TIntermSymbol* addSymbol(const TVariable&);
474 TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
475 TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
476 TIntermSymbol* addSymbol(const TIntermSymbol&);
477 TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
478 std::tuple<TIntermTyped*, TIntermTyped*> addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1);
479 TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
480 TIntermTyped* addConversion(TBasicType convertTo, TIntermTyped* node) const;
481 void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
482 TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
483 TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
484 TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
485 TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&);
486 TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, const TSourceLoc&);
487 TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
488 bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const;
489 bool isIntegralPromotion(TBasicType from, TBasicType to) const;
490 bool isFPPromotion(TBasicType from, TBasicType to) const;
491 bool isIntegralConversion(TBasicType from, TBasicType to) const;
492 bool isFPConversion(TBasicType from, TBasicType to) const;
493 bool isFPIntegralConversion(TBasicType from, TBasicType to) const;
494 TOperator mapTypeToConstructorOp(const TType&) const;
495 TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
496 TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
497 TIntermAggregate* makeAggregate(TIntermNode* node);
498 TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
499 TIntermAggregate* makeAggregate(const TSourceLoc&);
500 TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, const TSourceLoc&);
501 bool areAllChildConst(TIntermAggregate* aggrNode);
502 TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
503 TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
504 TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
505 TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
506 TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
507 TIntermConstantUnion* addConstantUnion(signed char, const TSourceLoc&, bool literal = false) const;
508 TIntermConstantUnion* addConstantUnion(unsigned char, const TSourceLoc&, bool literal = false) const;
509 TIntermConstantUnion* addConstantUnion(signed short, const TSourceLoc&, bool literal = false) const;
510 TIntermConstantUnion* addConstantUnion(unsigned short, const TSourceLoc&, bool literal = false) const;
511 TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
512 TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
513 TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
514 TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
515 TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
516 TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
517 TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
518 TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
519 bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
520 TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
521 TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
522 const TSourceLoc&, TIntermLoop*&);
523 TIntermBranch* addBranch(TOperator, const TSourceLoc&);
524 TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
525 template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
527 // Low level functions to add nodes (no conversions or other higher level transformations)
528 // If a type is provided, the node's type will be set to it.
529 TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&) const;
530 TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&,
532 TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&) const;
533 TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&, const TType&) const;
535 // Constant folding (in Constant.cpp)
536 TIntermTyped* fold(TIntermAggregate* aggrNode);
537 TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
538 TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
539 TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& fields, const TSourceLoc&);
542 static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay , bool BufferReferenceOk = false);
545 void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
546 void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
547 TIntermAggregate* findLinkerObjects() const;
549 void setGlobalUniformBlockName(const char* name) { globalUniformBlockName = std::string(name); }
550 const char* getGlobalUniformBlockName() const { return globalUniformBlockName.c_str(); }
551 void setGlobalUniformSet(unsigned int set) { globalUniformBlockSet = set; }
552 unsigned int getGlobalUniformSet() const { return globalUniformBlockSet; }
553 void setGlobalUniformBinding(unsigned int binding) { globalUniformBlockBinding = binding; }
554 unsigned int getGlobalUniformBinding() const { return globalUniformBlockBinding; }
556 void setAtomicCounterBlockName(const char* name) { atomicCounterBlockName = std::string(name); }
557 const char* getAtomicCounterBlockName() const { return atomicCounterBlockName.c_str(); }
558 void setAtomicCounterBlockSet(unsigned int set) { atomicCounterBlockSet = set; }
559 unsigned int getAtomicCounterBlockSet() const { return atomicCounterBlockSet; }
562 void setUseStorageBuffer() { useStorageBuffer = true; }
563 bool usingStorageBuffer() const { return useStorageBuffer; }
564 void setInvariantAll() { invariantAll = true; }
565 bool isInvariantAll() const { return invariantAll; }
566 void setDepthReplacing() { depthReplacing = true; }
567 bool isDepthReplacing() const { return depthReplacing; }
568 bool setLocalSize(int dim, int size)
570 if (localSizeNotDefault[dim])
571 return size == localSize[dim];
572 localSizeNotDefault[dim] = true;
573 localSize[dim] = size;
576 unsigned int getLocalSize(int dim) const { return localSize[dim]; }
577 bool isLocalSizeSet() const
579 // Return true if any component has been set (i.e. any component is not default).
580 return localSizeNotDefault[0] || localSizeNotDefault[1] || localSizeNotDefault[2];
582 bool setLocalSizeSpecId(int dim, int id)
584 if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
585 return id == localSizeSpecId[dim];
586 localSizeSpecId[dim] = id;
589 int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
590 bool isLocalSizeSpecialized() const
592 // Return true if any component has been specialized.
593 return localSizeSpecId[0] != TQualifier::layoutNotSet ||
594 localSizeSpecId[1] != TQualifier::layoutNotSet ||
595 localSizeSpecId[2] != TQualifier::layoutNotSet;
598 void output(TInfoSink&, bool tree) { }
600 bool isEsProfile() const { return false; }
601 bool getXfbMode() const { return false; }
602 bool isMultiStream() const { return false; }
603 TLayoutGeometry getOutputPrimitive() const { return ElgNone; }
604 bool getPostDepthCoverage() const { return false; }
605 bool getEarlyFragmentTests() const { return false; }
606 TLayoutDepth getDepth() const { return EldNone; }
607 bool getPixelCenterInteger() const { return false; }
608 void setOriginUpperLeft() { }
609 bool getOriginUpperLeft() const { return true; }
610 TInterlockOrdering getInterlockOrdering() const { return EioNone; }
612 bool getAutoMapBindings() const { return false; }
613 bool getAutoMapLocations() const { return false; }
614 int getNumPushConstants() const { return 0; }
615 void addShaderRecordCount() { }
616 void addTaskNVCount() { }
617 void setUseVulkanMemoryModel() { }
618 bool usingVulkanMemoryModel() const { return false; }
619 bool usingPhysicalStorageBuffer() const { return false; }
620 bool usingVariablePointers() const { return false; }
621 unsigned getXfbStride(int buffer) const { return 0; }
622 bool hasLayoutDerivativeModeNone() const { return false; }
623 ComputeDerivativeMode getLayoutDerivativeModeNone() const { return LayoutDerivativeNone; }
625 void output(TInfoSink&, bool tree);
627 bool isEsProfile() const { return profile == EEsProfile; }
629 void setShiftBinding(TResourceType res, unsigned int shift)
631 shiftBinding[res] = shift;
633 const char* name = getResourceName(res);
635 processes.addIfNonZero(name, shift);
638 unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; }
640 void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set)
642 if (shift == 0) // ignore if there's no shift: it's a no-op.
645 shiftBindingForSet[res][set] = shift;
647 const char* name = getResourceName(res);
648 if (name != nullptr) {
649 processes.addProcess(name);
650 processes.addArgument(shift);
651 processes.addArgument(set);
655 int getShiftBindingForSet(TResourceType res, unsigned int set) const
657 const auto shift = shiftBindingForSet[res].find(set);
658 return shift == shiftBindingForSet[res].end() ? -1 : shift->second;
660 bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); }
662 void setResourceSetBinding(const std::vector<std::string>& shift)
664 resourceSetBinding = shift;
665 if (shift.size() > 0) {
666 processes.addProcess("resource-set-binding");
667 for (int s = 0; s < (int)shift.size(); ++s)
668 processes.addArgument(shift[s]);
671 const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
672 void setAutoMapBindings(bool map)
674 autoMapBindings = map;
676 processes.addProcess("auto-map-bindings");
678 bool getAutoMapBindings() const { return autoMapBindings; }
679 void setAutoMapLocations(bool map)
681 autoMapLocations = map;
682 if (autoMapLocations)
683 processes.addProcess("auto-map-locations");
685 bool getAutoMapLocations() const { return autoMapLocations; }
688 void setFlattenUniformArrays(bool flatten)
690 flattenUniformArrays = flatten;
691 if (flattenUniformArrays)
692 processes.addProcess("flatten-uniform-arrays");
694 bool getFlattenUniformArrays() const { return flattenUniformArrays; }
696 void setNoStorageFormat(bool b)
698 useUnknownFormat = b;
699 if (useUnknownFormat)
700 processes.addProcess("no-storage-format");
702 bool getNoStorageFormat() const { return useUnknownFormat; }
703 void setUseVulkanMemoryModel()
705 useVulkanMemoryModel = true;
706 processes.addProcess("use-vulkan-memory-model");
708 bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
709 void setUsePhysicalStorageBuffer()
711 usePhysicalStorageBuffer = true;
713 bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
714 void setUseVariablePointers()
716 useVariablePointers = true;
717 processes.addProcess("use-variable-pointers");
719 bool usingVariablePointers() const { return useVariablePointers; }
722 template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
723 bool hasCounterBufferName(const TString& name) const {
724 size_t len = strlen(implicitCounterName);
725 return name.size() > len &&
726 name.compare(name.size() - len, len, implicitCounterName) == 0;
730 void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
731 int getNumPushConstants() const { return numPushConstants; }
732 void addShaderRecordCount() { ++numShaderRecordBlocks; }
733 void addTaskNVCount() { ++numTaskNVBlocks; }
735 bool setInvocations(int i)
737 if (invocations != TQualifier::layoutNotSet)
738 return invocations == i;
742 int getInvocations() const { return invocations; }
743 bool setVertices(int m)
745 if (vertices != TQualifier::layoutNotSet)
746 return vertices == m;
750 int getVertices() const { return vertices; }
751 bool setInputPrimitive(TLayoutGeometry p)
753 if (inputPrimitive != ElgNone)
754 return inputPrimitive == p;
758 TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
759 bool setVertexSpacing(TVertexSpacing s)
761 if (vertexSpacing != EvsNone)
762 return vertexSpacing == s;
766 TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
767 bool setVertexOrder(TVertexOrder o)
769 if (vertexOrder != EvoNone)
770 return vertexOrder == o;
774 TVertexOrder getVertexOrder() const { return vertexOrder; }
775 void setPointMode() { pointMode = true; }
776 bool getPointMode() const { return pointMode; }
778 bool setInterlockOrdering(TInterlockOrdering o)
780 if (interlockOrdering != EioNone)
781 return interlockOrdering == o;
782 interlockOrdering = o;
785 TInterlockOrdering getInterlockOrdering() const { return interlockOrdering; }
787 void setXfbMode() { xfbMode = true; }
788 bool getXfbMode() const { return xfbMode; }
789 void setMultiStream() { multiStream = true; }
790 bool isMultiStream() const { return multiStream; }
791 bool setOutputPrimitive(TLayoutGeometry p)
793 if (outputPrimitive != ElgNone)
794 return outputPrimitive == p;
798 TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
799 void setPostDepthCoverage() { postDepthCoverage = true; }
800 bool getPostDepthCoverage() const { return postDepthCoverage; }
801 void setEarlyFragmentTests() { earlyFragmentTests = true; }
802 bool getEarlyFragmentTests() const { return earlyFragmentTests; }
803 bool setDepth(TLayoutDepth d)
805 if (depthLayout != EldNone)
806 return depthLayout == d;
810 TLayoutDepth getDepth() const { return depthLayout; }
811 void setOriginUpperLeft() { originUpperLeft = true; }
812 bool getOriginUpperLeft() const { return originUpperLeft; }
813 void setPixelCenterInteger() { pixelCenterInteger = true; }
814 bool getPixelCenterInteger() const { return pixelCenterInteger; }
815 void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
816 unsigned int getBlendEquations() const { return blendEquations; }
817 bool setXfbBufferStride(int buffer, unsigned stride)
819 if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
820 return xfbBuffers[buffer].stride == stride;
821 xfbBuffers[buffer].stride = stride;
824 unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
825 int addXfbBufferOffset(const TType&);
826 unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const;
827 unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType) const;
828 void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
829 bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
830 void setGeoPassthroughEXT() { geoPassthroughEXT = true; }
831 bool getGeoPassthroughEXT() const { return geoPassthroughEXT; }
832 void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; }
833 bool hasLayoutDerivativeModeNone() const { return computeDerivativeMode != LayoutDerivativeNone; }
834 ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; }
835 void setLayoutPrimitiveCulling() { layoutPrimitiveCulling = true; }
836 bool getLayoutPrimitiveCulling() const { return layoutPrimitiveCulling; }
837 bool setPrimitives(int m)
839 if (primitives != TQualifier::layoutNotSet)
840 return primitives == m;
844 int getPrimitives() const { return primitives; }
845 const char* addSemanticName(const TString& name)
847 return semanticNameSet.insert(name).first->c_str();
849 void addUniformLocationOverride(const char* nameStr, int location)
851 std::string name = nameStr;
852 uniformLocationOverrides[name] = location;
855 int getUniformLocationOverride(const char* nameStr) const
857 std::string name = nameStr;
858 auto pos = uniformLocationOverrides.find(name);
859 if (pos == uniformLocationOverrides.end())
865 void setUniformLocationBase(int base) { uniformLocationBase = base; }
866 int getUniformLocationBase() const { return uniformLocationBase; }
868 void setNeedsLegalization() { needToLegalize = true; }
869 bool needsLegalization() const { return needToLegalize; }
871 void setBinaryDoubleOutput() { binaryDoubleOutput = true; }
872 bool getBinaryDoubleOutput() { return binaryDoubleOutput; }
874 void setSubgroupUniformControlFlow() { subgroupUniformControlFlow = true; }
875 bool getSubgroupUniformControlFlow() const { return subgroupUniformControlFlow; }
877 // GL_EXT_spirv_intrinsics
878 void insertSpirvRequirement(const TSpirvRequirement* spirvReq);
879 bool hasSpirvRequirement() const { return spirvRequirement != nullptr; }
880 const TSpirvRequirement& getSpirvRequirement() const { return *spirvRequirement; }
881 void insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args = nullptr);
882 void insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args);
883 bool hasSpirvExecutionMode() const { return spirvExecutionMode != nullptr; }
884 const TSpirvExecutionMode& getSpirvExecutionMode() const { return *spirvExecutionMode; }
885 #endif // GLSLANG_WEB
887 void addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing)
889 std::string name(nameStr);
890 blockBackingOverrides[name] = backing;
892 TBlockStorageClass getBlockStorageOverride(const char* nameStr) const
894 std::string name = nameStr;
895 auto pos = blockBackingOverrides.find(name);
896 if (pos == blockBackingOverrides.end())
902 void setHlslFunctionality1() { hlslFunctionality1 = true; }
903 bool getHlslFunctionality1() const { return hlslFunctionality1; }
904 void setHlslOffsets()
908 processes.addProcess("hlsl-offsets");
910 bool usingHlslOffsets() const { return hlslOffsets; }
911 void setHlslIoMapping(bool b)
915 processes.addProcess("hlsl-iomap");
917 bool usingHlslIoMapping() { return hlslIoMapping; }
919 bool getHlslFunctionality1() const { return false; }
920 bool usingHlslOffsets() const { return false; }
921 bool usingHlslIoMapping() { return false; }
924 bool usingScalarBlockLayout() const {
925 for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt) {
926 if (*extIt == E_GL_EXT_scalar_block_layout)
932 bool IsRequestedExtension(const char* extension) const
934 return (requestedExtensions.find(extension) != requestedExtensions.end());
937 void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
938 void merge(TInfoSink&, TIntermediate&);
939 void finalCheck(TInfoSink&, bool keepUncalled);
941 void mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& unit, bool mergeExistingOnly);
942 void mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit);
943 void checkStageIO(TInfoSink&, TIntermediate&);
945 bool buildConvertOp(TBasicType dst, TBasicType src, TOperator& convertOp) const;
946 TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const;
948 void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
949 bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
951 int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
952 int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision);
953 int checkLocationRT(int set, int location);
954 int addUsedOffsets(int binding, int offset, int numOffsets);
955 bool addUsedConstantId(int id);
956 static int computeTypeLocationSize(const TType&, EShLanguage);
957 static int computeTypeUniformLocationSize(const TType&);
959 static int getBaseAlignmentScalar(const TType&, int& size);
960 static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
961 static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
962 static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
963 static bool improperStraddle(const TType& type, int size, int offset);
964 static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize);
965 static int getOffset(const TType& type, int index);
966 static int getBlockSize(const TType& blockType);
967 static int computeBufferReferenceTypeSize(const TType&);
968 static bool isIoResizeArray(const TType& type, EShLanguage language);
970 bool promote(TIntermOperator*);
971 void setNanMinMaxClamp(bool setting) { nanMinMaxClamp = setting; }
972 bool getNanMinMaxClamp() const { return nanMinMaxClamp; }
974 void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
975 const std::string& getSourceFile() const { return sourceFile; }
976 void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
977 const std::string& getSourceText() const { return sourceText; }
978 const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
979 void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
980 void addProcesses(const std::vector<std::string>& p)
982 for (int i = 0; i < (int)p.size(); ++i)
983 processes.addProcess(p[i]);
985 void addProcess(const std::string& process) { processes.addProcess(process); }
986 void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
987 const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
988 unsigned long long getUniqueId() const { return uniqueId; }
989 void setUniqueId(unsigned long long id) { uniqueId = id; }
991 // Certain explicit conversions are allowed conditionally
993 bool getArithemeticInt8Enabled() const { return false; }
994 bool getArithemeticInt16Enabled() const { return false; }
995 bool getArithemeticFloat16Enabled() const { return false; }
996 void updateNumericFeature(TNumericFeatures::feature f, bool on) { }
998 bool getArithemeticInt8Enabled() const {
999 return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1000 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8);
1002 bool getArithemeticInt16Enabled() const {
1003 return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1004 numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
1005 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16);
1008 bool getArithemeticFloat16Enabled() const {
1009 return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1010 numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
1011 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
1013 void updateNumericFeature(TNumericFeatures::feature f, bool on)
1014 { on ? numericFeatures.insert(f) : numericFeatures.erase(f); }
1018 TIntermSymbol* addSymbol(long long Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
1019 void error(TInfoSink& infoSink, const char*);
1020 void warn(TInfoSink& infoSink, const char*);
1021 void mergeCallGraphs(TInfoSink&, TIntermediate&);
1022 void mergeModes(TInfoSink&, TIntermediate&);
1023 void mergeTrees(TInfoSink&, TIntermediate&);
1024 void seedIdMap(TIdMaps& idMaps, long long& IdShift);
1025 void remapIds(const TIdMaps& idMaps, long long idShift, TIntermediate&);
1026 void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
1027 void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects, EShLanguage);
1028 void mergeBlockDefinitions(TInfoSink&, TIntermSymbol* block, TIntermSymbol* unitBlock, TIntermediate* unitRoot);
1029 void mergeImplicitArraySizes(TType&, const TType&);
1030 void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, EShLanguage);
1031 void checkCallGraphCycles(TInfoSink&);
1032 void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
1033 void inOutLocationCheck(TInfoSink&);
1034 void sharedBlockCheck(TInfoSink&);
1035 bool userOutputUsed() const;
1036 bool isSpecializationOperation(const TIntermOperator&) const;
1037 bool isNonuniformPropagating(TOperator) const;
1038 bool promoteUnary(TIntermUnary&);
1039 bool promoteBinary(TIntermBinary&);
1040 void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
1041 bool promoteAggregate(TIntermAggregate&);
1042 void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&);
1043 void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
1044 bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&);
1045 void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root);
1046 bool isConversionAllowed(TOperator op, TIntermTyped* node) const;
1047 std::tuple<TBasicType, TBasicType> getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const;
1049 static const char* getResourceName(TResourceType);
1051 const EShLanguage language; // stage, known at construction time
1052 std::string entryPointName;
1053 std::string entryPointMangledName;
1054 typedef std::list<TCall> TGraph;
1057 #ifdef GLSLANG_ANGLE
1058 const EProfile profile = ECoreProfile;
1059 const int version = 450;
1061 EProfile profile; // source profile
1062 int version; // source version
1064 SpvVersion spvVersion;
1065 TIntermNode* treeRoot;
1066 std::set<std::string> requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
1067 MustBeAssigned<TBuiltInResource> resources;
1070 int numPushConstants;
1073 bool useStorageBuffer;
1075 bool nanMinMaxClamp; // true if desiring min/max/clamp to favor non-NaN over NaN
1076 bool depthReplacing;
1078 bool localSizeNotDefault[3];
1079 int localSizeSpecId[3];
1080 unsigned long long uniqueId;
1082 std::string globalUniformBlockName;
1083 std::string atomicCounterBlockName;
1084 unsigned int globalUniformBlockSet;
1085 unsigned int globalUniformBlockBinding;
1086 unsigned int atomicCounterBlockSet;
1090 const char* const implicitThisName;
1091 const char* const implicitCounterName;
1093 EShSource source; // source language, known a bit later
1094 bool useVulkanMemoryModel;
1097 TLayoutGeometry inputPrimitive;
1098 TLayoutGeometry outputPrimitive;
1099 bool pixelCenterInteger;
1100 bool originUpperLeft;
1101 TVertexSpacing vertexSpacing;
1102 TVertexOrder vertexOrder;
1103 TInterlockOrdering interlockOrdering;
1105 bool earlyFragmentTests;
1106 bool postDepthCoverage;
1107 TLayoutDepth depthLayout;
1108 bool hlslFunctionality1;
1109 int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift
1111 std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer
1113 bool layoutOverrideCoverage;
1114 bool geoPassthroughEXT;
1115 int numShaderRecordBlocks;
1116 ComputeDerivativeMode computeDerivativeMode;
1118 int numTaskNVBlocks;
1119 bool layoutPrimitiveCulling;
1121 // Base shift values
1122 std::array<unsigned int, EResCount> shiftBinding;
1124 // Per-descriptor-set shift values
1125 std::array<std::map<int, int>, EResCount> shiftBindingForSet;
1127 std::vector<std::string> resourceSetBinding;
1128 bool autoMapBindings;
1129 bool autoMapLocations;
1130 bool flattenUniformArrays;
1131 bool useUnknownFormat;
1134 bool useVariablePointers;
1136 std::set<TString> semanticNameSet;
1138 EShTextureSamplerTransformMode textureSamplerTransformMode;
1140 bool needToLegalize;
1141 bool binaryDoubleOutput;
1142 bool subgroupUniformControlFlow;
1143 bool usePhysicalStorageBuffer;
1145 TSpirvRequirement* spirvRequirement;
1146 TSpirvExecutionMode* spirvExecutionMode;
1148 std::unordered_map<std::string, int> uniformLocationOverrides;
1149 int uniformLocationBase;
1150 TNumericFeatures numericFeatures;
1152 std::unordered_map<std::string, TBlockStorageClass> blockBackingOverrides;
1154 std::unordered_set<int> usedConstantId; // specialization constant ids used
1155 std::vector<TOffsetRange> usedAtomics; // sets of bindings used by atomic counters
1156 std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers
1157 std::vector<TRange> usedIoRT[2]; // sets of used location, one for rayPayload/rayPayloadIN and other
1158 // for callableData/callableDataIn
1159 // set of names of statically read/written I/O that might need extra checking
1160 std::set<TString> ioAccessed;
1161 // source code of shader, useful as part of debug information
1162 std::string sourceFile;
1163 std::string sourceText;
1165 // Included text. First string is a name, second is the included text
1166 std::map<std::string, std::string> includeText;
1168 // for OpModuleProcessed, or equivalent
1169 TProcesses processes;
1172 void operator=(TIntermediate&); // prevent assignments
1175 } // end namespace glslang
1177 #endif // _LOCAL_INTERMEDIATE_INCLUDED_