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),
294 useStorageBuffer(false),
296 nanMinMaxClamp(false),
297 depthReplacing(false),
299 globalUniformBlockName(""),
300 atomicCounterBlockName(""),
301 globalUniformBlockSet(TQualifier::layoutSetEnd),
302 globalUniformBlockBinding(TQualifier::layoutBindingEnd),
303 atomicCounterBlockSet(TQualifier::layoutSetEnd)
306 implicitThisName("@this"), implicitCounterName("@count"),
307 source(EShSourceNone),
308 useVulkanMemoryModel(false),
309 invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet),
310 inputPrimitive(ElgNone), outputPrimitive(ElgNone),
311 pixelCenterInteger(false), originUpperLeft(false),
312 vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false),
313 postDepthCoverage(false), depthLayout(EldNone),
314 hlslFunctionality1(false),
315 blendEquations(0), xfbMode(false), multiStream(false),
316 layoutOverrideCoverage(false),
317 geoPassthroughEXT(false),
318 numShaderRecordBlocks(0),
319 computeDerivativeMode(LayoutDerivativeNone),
320 primitives(TQualifier::layoutNotSet),
322 layoutPrimitiveCulling(false),
323 autoMapBindings(false),
324 autoMapLocations(false),
325 flattenUniformArrays(false),
326 useUnknownFormat(false),
328 hlslIoMapping(false),
329 useVariablePointers(false),
330 textureSamplerTransformMode(EShTexSampTransKeep),
331 needToLegalize(false),
332 binaryDoubleOutput(false),
333 subgroupUniformControlFlow(false),
334 usePhysicalStorageBuffer(false),
335 spirvRequirement(nullptr),
336 spirvExecutionMode(nullptr),
337 uniformLocationBase(0)
343 localSizeNotDefault[0] = false;
344 localSizeNotDefault[1] = false;
345 localSizeNotDefault[2] = false;
346 localSizeSpecId[0] = TQualifier::layoutNotSet;
347 localSizeSpecId[1] = TQualifier::layoutNotSet;
348 localSizeSpecId[2] = TQualifier::layoutNotSet;
350 xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
351 shiftBinding.fill(0);
355 void setVersion(int v)
357 #ifndef GLSLANG_ANGLE
361 void setProfile(EProfile p)
363 #ifndef GLSLANG_ANGLE
368 int getVersion() const { return version; }
369 EProfile getProfile() const { return profile; }
370 void setSpv(const SpvVersion& s)
375 if (spvVersion.vulkan > 0)
376 processes.addProcess("client vulkan100");
377 if (spvVersion.openGl > 0)
378 processes.addProcess("client opengl100");
381 switch (spvVersion.spv) {
384 case EShTargetSpv_1_0:
386 case EShTargetSpv_1_1:
387 processes.addProcess("target-env spirv1.1");
389 case EShTargetSpv_1_2:
390 processes.addProcess("target-env spirv1.2");
392 case EShTargetSpv_1_3:
393 processes.addProcess("target-env spirv1.3");
395 case EShTargetSpv_1_4:
396 processes.addProcess("target-env spirv1.4");
398 case EShTargetSpv_1_5:
399 processes.addProcess("target-env spirv1.5");
401 case EShTargetSpv_1_6:
402 processes.addProcess("target-env spirv1.6");
405 processes.addProcess("target-env spirvUnknown");
409 // target-environment processes
410 switch (spvVersion.vulkan) {
413 case EShTargetVulkan_1_0:
414 processes.addProcess("target-env vulkan1.0");
416 case EShTargetVulkan_1_1:
417 processes.addProcess("target-env vulkan1.1");
419 case EShTargetVulkan_1_2:
420 processes.addProcess("target-env vulkan1.2");
423 processes.addProcess("target-env vulkanUnknown");
426 if (spvVersion.openGl > 0)
427 processes.addProcess("target-env opengl");
429 const SpvVersion& getSpv() const { return spvVersion; }
430 EShLanguage getStage() const { return language; }
431 void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
432 const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
433 bool isRayTracingStage() const {
434 return language >= EShLangRayGen && language <= EShLangCallableNV;
437 void setTreeRoot(TIntermNode* r) { treeRoot = r; }
438 TIntermNode* getTreeRoot() const { return treeRoot; }
439 void incrementEntryPointCount() { ++numEntryPoints; }
440 int getNumEntryPoints() const { return numEntryPoints; }
441 int getNumErrors() const { return numErrors; }
442 void addPushConstantCount() { ++numPushConstants; }
443 void setLimits(const TBuiltInResource& r) { resources = r; }
444 const TBuiltInResource& getLimits() const { return resources; }
446 bool postProcess(TIntermNode*, EShLanguage);
449 void setEntryPointName(const char* ep)
452 processes.addProcess("entry-point");
453 processes.addArgument(entryPointName);
455 void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
456 const std::string& getEntryPointName() const { return entryPointName; }
457 const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
459 void setInvertY(bool invert)
463 processes.addProcess("invert-y");
465 bool getInvertY() const { return invertY; }
467 void setDxPositionW(bool dxPosW)
469 dxPositionW = dxPosW;
471 processes.addProcess("dx-position-w");
473 bool getDxPositionW() const { return dxPositionW; }
476 void setSource(EShSource s) { source = s; }
477 EShSource getSource() const { return source; }
479 void setSource(EShSource s) { assert(s == EShSourceGlsl); (void)s; }
480 EShSource getSource() const { return EShSourceGlsl; }
483 bool isRecursive() const { return recursive; }
485 TIntermSymbol* addSymbol(const TVariable&);
486 TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
487 TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
488 TIntermSymbol* addSymbol(const TIntermSymbol&);
489 TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
490 std::tuple<TIntermTyped*, TIntermTyped*> addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1);
491 TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
492 TIntermTyped* addConversion(TBasicType convertTo, TIntermTyped* node) const;
493 void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
494 TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
495 TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
496 TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
497 TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&);
498 TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, const TSourceLoc&);
499 TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
500 bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const;
501 bool isIntegralPromotion(TBasicType from, TBasicType to) const;
502 bool isFPPromotion(TBasicType from, TBasicType to) const;
503 bool isIntegralConversion(TBasicType from, TBasicType to) const;
504 bool isFPConversion(TBasicType from, TBasicType to) const;
505 bool isFPIntegralConversion(TBasicType from, TBasicType to) const;
506 TOperator mapTypeToConstructorOp(const TType&) const;
507 TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
508 TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
509 TIntermAggregate* makeAggregate(TIntermNode* node);
510 TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
511 TIntermAggregate* makeAggregate(const TSourceLoc&);
512 TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, const TSourceLoc&);
513 bool areAllChildConst(TIntermAggregate* aggrNode);
514 TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
515 TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
516 TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
517 TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
518 TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
519 TIntermConstantUnion* addConstantUnion(signed char, const TSourceLoc&, bool literal = false) const;
520 TIntermConstantUnion* addConstantUnion(unsigned char, const TSourceLoc&, bool literal = false) const;
521 TIntermConstantUnion* addConstantUnion(signed short, const TSourceLoc&, bool literal = false) const;
522 TIntermConstantUnion* addConstantUnion(unsigned short, const TSourceLoc&, bool literal = false) const;
523 TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
524 TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
525 TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
526 TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
527 TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
528 TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
529 TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
530 TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
531 bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
532 TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
533 TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
534 const TSourceLoc&, TIntermLoop*&);
535 TIntermBranch* addBranch(TOperator, const TSourceLoc&);
536 TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
537 template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
539 // Low level functions to add nodes (no conversions or other higher level transformations)
540 // If a type is provided, the node's type will be set to it.
541 TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&) const;
542 TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&,
544 TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&) const;
545 TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&, const TType&) const;
547 // Constant folding (in Constant.cpp)
548 TIntermTyped* fold(TIntermAggregate* aggrNode);
549 TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
550 TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
551 TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& fields, const TSourceLoc&);
554 static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay , bool BufferReferenceOk = false);
557 void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
558 void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
559 TIntermAggregate* findLinkerObjects() const;
561 void setGlobalUniformBlockName(const char* name) { globalUniformBlockName = std::string(name); }
562 const char* getGlobalUniformBlockName() const { return globalUniformBlockName.c_str(); }
563 void setGlobalUniformSet(unsigned int set) { globalUniformBlockSet = set; }
564 unsigned int getGlobalUniformSet() const { return globalUniformBlockSet; }
565 void setGlobalUniformBinding(unsigned int binding) { globalUniformBlockBinding = binding; }
566 unsigned int getGlobalUniformBinding() const { return globalUniformBlockBinding; }
568 void setAtomicCounterBlockName(const char* name) { atomicCounterBlockName = std::string(name); }
569 const char* getAtomicCounterBlockName() const { return atomicCounterBlockName.c_str(); }
570 void setAtomicCounterBlockSet(unsigned int set) { atomicCounterBlockSet = set; }
571 unsigned int getAtomicCounterBlockSet() const { return atomicCounterBlockSet; }
574 void setUseStorageBuffer() { useStorageBuffer = true; }
575 bool usingStorageBuffer() const { return useStorageBuffer; }
576 void setInvariantAll() { invariantAll = true; }
577 bool isInvariantAll() const { return invariantAll; }
578 void setDepthReplacing() { depthReplacing = true; }
579 bool isDepthReplacing() const { return depthReplacing; }
580 bool setLocalSize(int dim, int size)
582 if (localSizeNotDefault[dim])
583 return size == localSize[dim];
584 localSizeNotDefault[dim] = true;
585 localSize[dim] = size;
588 unsigned int getLocalSize(int dim) const { return localSize[dim]; }
589 bool isLocalSizeSet() const
591 // Return true if any component has been set (i.e. any component is not default).
592 return localSizeNotDefault[0] || localSizeNotDefault[1] || localSizeNotDefault[2];
594 bool setLocalSizeSpecId(int dim, int id)
596 if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
597 return id == localSizeSpecId[dim];
598 localSizeSpecId[dim] = id;
601 int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
602 bool isLocalSizeSpecialized() const
604 // Return true if any component has been specialized.
605 return localSizeSpecId[0] != TQualifier::layoutNotSet ||
606 localSizeSpecId[1] != TQualifier::layoutNotSet ||
607 localSizeSpecId[2] != TQualifier::layoutNotSet;
610 void output(TInfoSink&, bool tree) { }
612 bool isEsProfile() const { return false; }
613 bool getXfbMode() const { return false; }
614 bool isMultiStream() const { return false; }
615 TLayoutGeometry getOutputPrimitive() const { return ElgNone; }
616 bool getPostDepthCoverage() const { return false; }
617 bool getEarlyFragmentTests() const { return false; }
618 TLayoutDepth getDepth() const { return EldNone; }
619 bool getPixelCenterInteger() const { return false; }
620 void setOriginUpperLeft() { }
621 bool getOriginUpperLeft() const { return true; }
622 TInterlockOrdering getInterlockOrdering() const { return EioNone; }
624 bool getAutoMapBindings() const { return false; }
625 bool getAutoMapLocations() const { return false; }
626 int getNumPushConstants() const { return 0; }
627 void addShaderRecordCount() { }
628 void addTaskNVCount() { }
629 void setUseVulkanMemoryModel() { }
630 bool usingVulkanMemoryModel() const { return false; }
631 bool usingPhysicalStorageBuffer() const { return false; }
632 bool usingVariablePointers() const { return false; }
633 unsigned getXfbStride(int buffer) const { return 0; }
634 bool hasLayoutDerivativeModeNone() const { return false; }
635 ComputeDerivativeMode getLayoutDerivativeModeNone() const { return LayoutDerivativeNone; }
637 void output(TInfoSink&, bool tree);
639 bool isEsProfile() const { return profile == EEsProfile; }
641 void setShiftBinding(TResourceType res, unsigned int shift)
643 shiftBinding[res] = shift;
645 const char* name = getResourceName(res);
647 processes.addIfNonZero(name, shift);
650 unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; }
652 void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set)
654 if (shift == 0) // ignore if there's no shift: it's a no-op.
657 shiftBindingForSet[res][set] = shift;
659 const char* name = getResourceName(res);
660 if (name != nullptr) {
661 processes.addProcess(name);
662 processes.addArgument(shift);
663 processes.addArgument(set);
667 int getShiftBindingForSet(TResourceType res, unsigned int set) const
669 const auto shift = shiftBindingForSet[res].find(set);
670 return shift == shiftBindingForSet[res].end() ? -1 : shift->second;
672 bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); }
674 void setResourceSetBinding(const std::vector<std::string>& shift)
676 resourceSetBinding = shift;
677 if (shift.size() > 0) {
678 processes.addProcess("resource-set-binding");
679 for (int s = 0; s < (int)shift.size(); ++s)
680 processes.addArgument(shift[s]);
683 const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
684 void setAutoMapBindings(bool map)
686 autoMapBindings = map;
688 processes.addProcess("auto-map-bindings");
690 bool getAutoMapBindings() const { return autoMapBindings; }
691 void setAutoMapLocations(bool map)
693 autoMapLocations = map;
694 if (autoMapLocations)
695 processes.addProcess("auto-map-locations");
697 bool getAutoMapLocations() const { return autoMapLocations; }
700 void setFlattenUniformArrays(bool flatten)
702 flattenUniformArrays = flatten;
703 if (flattenUniformArrays)
704 processes.addProcess("flatten-uniform-arrays");
706 bool getFlattenUniformArrays() const { return flattenUniformArrays; }
708 void setNoStorageFormat(bool b)
710 useUnknownFormat = b;
711 if (useUnknownFormat)
712 processes.addProcess("no-storage-format");
714 bool getNoStorageFormat() const { return useUnknownFormat; }
715 void setUseVulkanMemoryModel()
717 useVulkanMemoryModel = true;
718 processes.addProcess("use-vulkan-memory-model");
720 bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
721 void setUsePhysicalStorageBuffer()
723 usePhysicalStorageBuffer = true;
725 bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
726 void setUseVariablePointers()
728 useVariablePointers = true;
729 processes.addProcess("use-variable-pointers");
731 bool usingVariablePointers() const { return useVariablePointers; }
734 template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
735 bool hasCounterBufferName(const TString& name) const {
736 size_t len = strlen(implicitCounterName);
737 return name.size() > len &&
738 name.compare(name.size() - len, len, implicitCounterName) == 0;
742 void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
743 int getNumPushConstants() const { return numPushConstants; }
744 void addShaderRecordCount() { ++numShaderRecordBlocks; }
745 void addTaskNVCount() { ++numTaskNVBlocks; }
747 bool setInvocations(int i)
749 if (invocations != TQualifier::layoutNotSet)
750 return invocations == i;
754 int getInvocations() const { return invocations; }
755 bool setVertices(int m)
757 if (vertices != TQualifier::layoutNotSet)
758 return vertices == m;
762 int getVertices() const { return vertices; }
763 bool setInputPrimitive(TLayoutGeometry p)
765 if (inputPrimitive != ElgNone)
766 return inputPrimitive == p;
770 TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
771 bool setVertexSpacing(TVertexSpacing s)
773 if (vertexSpacing != EvsNone)
774 return vertexSpacing == s;
778 TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
779 bool setVertexOrder(TVertexOrder o)
781 if (vertexOrder != EvoNone)
782 return vertexOrder == o;
786 TVertexOrder getVertexOrder() const { return vertexOrder; }
787 void setPointMode() { pointMode = true; }
788 bool getPointMode() const { return pointMode; }
790 bool setInterlockOrdering(TInterlockOrdering o)
792 if (interlockOrdering != EioNone)
793 return interlockOrdering == o;
794 interlockOrdering = o;
797 TInterlockOrdering getInterlockOrdering() const { return interlockOrdering; }
799 void setXfbMode() { xfbMode = true; }
800 bool getXfbMode() const { return xfbMode; }
801 void setMultiStream() { multiStream = true; }
802 bool isMultiStream() const { return multiStream; }
803 bool setOutputPrimitive(TLayoutGeometry p)
805 if (outputPrimitive != ElgNone)
806 return outputPrimitive == p;
810 TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
811 void setPostDepthCoverage() { postDepthCoverage = true; }
812 bool getPostDepthCoverage() const { return postDepthCoverage; }
813 void setEarlyFragmentTests() { earlyFragmentTests = true; }
814 bool getEarlyFragmentTests() const { return earlyFragmentTests; }
815 bool setDepth(TLayoutDepth d)
817 if (depthLayout != EldNone)
818 return depthLayout == d;
822 TLayoutDepth getDepth() const { return depthLayout; }
823 void setOriginUpperLeft() { originUpperLeft = true; }
824 bool getOriginUpperLeft() const { return originUpperLeft; }
825 void setPixelCenterInteger() { pixelCenterInteger = true; }
826 bool getPixelCenterInteger() const { return pixelCenterInteger; }
827 void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
828 unsigned int getBlendEquations() const { return blendEquations; }
829 bool setXfbBufferStride(int buffer, unsigned stride)
831 if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
832 return xfbBuffers[buffer].stride == stride;
833 xfbBuffers[buffer].stride = stride;
836 unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
837 int addXfbBufferOffset(const TType&);
838 unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const;
839 unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType) const;
840 void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
841 bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
842 void setGeoPassthroughEXT() { geoPassthroughEXT = true; }
843 bool getGeoPassthroughEXT() const { return geoPassthroughEXT; }
844 void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; }
845 bool hasLayoutDerivativeModeNone() const { return computeDerivativeMode != LayoutDerivativeNone; }
846 ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; }
847 void setLayoutPrimitiveCulling() { layoutPrimitiveCulling = true; }
848 bool getLayoutPrimitiveCulling() const { return layoutPrimitiveCulling; }
849 bool setPrimitives(int m)
851 if (primitives != TQualifier::layoutNotSet)
852 return primitives == m;
856 int getPrimitives() const { return primitives; }
857 const char* addSemanticName(const TString& name)
859 return semanticNameSet.insert(name).first->c_str();
861 void addUniformLocationOverride(const char* nameStr, int location)
863 std::string name = nameStr;
864 uniformLocationOverrides[name] = location;
867 int getUniformLocationOverride(const char* nameStr) const
869 std::string name = nameStr;
870 auto pos = uniformLocationOverrides.find(name);
871 if (pos == uniformLocationOverrides.end())
877 void setUniformLocationBase(int base) { uniformLocationBase = base; }
878 int getUniformLocationBase() const { return uniformLocationBase; }
880 void setNeedsLegalization() { needToLegalize = true; }
881 bool needsLegalization() const { return needToLegalize; }
883 void setBinaryDoubleOutput() { binaryDoubleOutput = true; }
884 bool getBinaryDoubleOutput() { return binaryDoubleOutput; }
886 void setSubgroupUniformControlFlow() { subgroupUniformControlFlow = true; }
887 bool getSubgroupUniformControlFlow() const { return subgroupUniformControlFlow; }
889 // GL_EXT_spirv_intrinsics
890 void insertSpirvRequirement(const TSpirvRequirement* spirvReq);
891 bool hasSpirvRequirement() const { return spirvRequirement != nullptr; }
892 const TSpirvRequirement& getSpirvRequirement() const { return *spirvRequirement; }
893 void insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args = nullptr);
894 void insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args);
895 bool hasSpirvExecutionMode() const { return spirvExecutionMode != nullptr; }
896 const TSpirvExecutionMode& getSpirvExecutionMode() const { return *spirvExecutionMode; }
897 #endif // GLSLANG_WEB
899 void addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing)
901 std::string name(nameStr);
902 blockBackingOverrides[name] = backing;
904 TBlockStorageClass getBlockStorageOverride(const char* nameStr) const
906 std::string name = nameStr;
907 auto pos = blockBackingOverrides.find(name);
908 if (pos == blockBackingOverrides.end())
914 void setHlslFunctionality1() { hlslFunctionality1 = true; }
915 bool getHlslFunctionality1() const { return hlslFunctionality1; }
916 void setHlslOffsets()
920 processes.addProcess("hlsl-offsets");
922 bool usingHlslOffsets() const { return hlslOffsets; }
923 void setHlslIoMapping(bool b)
927 processes.addProcess("hlsl-iomap");
929 bool usingHlslIoMapping() { return hlslIoMapping; }
931 bool getHlslFunctionality1() const { return false; }
932 bool usingHlslOffsets() const { return false; }
933 bool usingHlslIoMapping() { return false; }
936 bool usingScalarBlockLayout() const {
937 for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt) {
938 if (*extIt == E_GL_EXT_scalar_block_layout)
944 bool IsRequestedExtension(const char* extension) const
946 return (requestedExtensions.find(extension) != requestedExtensions.end());
949 void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
950 void merge(TInfoSink&, TIntermediate&);
951 void finalCheck(TInfoSink&, bool keepUncalled);
953 void mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& unit, bool mergeExistingOnly);
954 void mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit);
955 void checkStageIO(TInfoSink&, TIntermediate&);
957 bool buildConvertOp(TBasicType dst, TBasicType src, TOperator& convertOp) const;
958 TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const;
960 void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
961 bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
963 int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
964 int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision);
965 int checkLocationRT(int set, int location);
966 int addUsedOffsets(int binding, int offset, int numOffsets);
967 bool addUsedConstantId(int id);
968 static int computeTypeLocationSize(const TType&, EShLanguage);
969 static int computeTypeUniformLocationSize(const TType&);
971 static int getBaseAlignmentScalar(const TType&, int& size);
972 static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
973 static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
974 static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
975 static bool improperStraddle(const TType& type, int size, int offset);
976 static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize);
977 static int getOffset(const TType& type, int index);
978 static int getBlockSize(const TType& blockType);
979 static int computeBufferReferenceTypeSize(const TType&);
980 static bool isIoResizeArray(const TType& type, EShLanguage language);
982 bool promote(TIntermOperator*);
983 void setNanMinMaxClamp(bool setting) { nanMinMaxClamp = setting; }
984 bool getNanMinMaxClamp() const { return nanMinMaxClamp; }
986 void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
987 const std::string& getSourceFile() const { return sourceFile; }
988 void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
989 const std::string& getSourceText() const { return sourceText; }
990 const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
991 void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
992 void addProcesses(const std::vector<std::string>& p)
994 for (int i = 0; i < (int)p.size(); ++i)
995 processes.addProcess(p[i]);
997 void addProcess(const std::string& process) { processes.addProcess(process); }
998 void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
999 const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
1000 unsigned long long getUniqueId() const { return uniqueId; }
1001 void setUniqueId(unsigned long long id) { uniqueId = id; }
1003 // Certain explicit conversions are allowed conditionally
1005 bool getArithemeticInt8Enabled() const { return false; }
1006 bool getArithemeticInt16Enabled() const { return false; }
1007 bool getArithemeticFloat16Enabled() const { return false; }
1008 void updateNumericFeature(TNumericFeatures::feature f, bool on) { }
1010 bool getArithemeticInt8Enabled() const {
1011 return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1012 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8);
1014 bool getArithemeticInt16Enabled() const {
1015 return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1016 numericFeatures.contains(TNumericFeatures::gpu_shader_int16) ||
1017 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16);
1020 bool getArithemeticFloat16Enabled() const {
1021 return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1022 numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
1023 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
1025 void updateNumericFeature(TNumericFeatures::feature f, bool on)
1026 { on ? numericFeatures.insert(f) : numericFeatures.erase(f); }
1030 TIntermSymbol* addSymbol(long long Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
1031 void error(TInfoSink& infoSink, const char*);
1032 void warn(TInfoSink& infoSink, const char*);
1033 void mergeCallGraphs(TInfoSink&, TIntermediate&);
1034 void mergeModes(TInfoSink&, TIntermediate&);
1035 void mergeTrees(TInfoSink&, TIntermediate&);
1036 void seedIdMap(TIdMaps& idMaps, long long& IdShift);
1037 void remapIds(const TIdMaps& idMaps, long long idShift, TIntermediate&);
1038 void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
1039 void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects, EShLanguage);
1040 void mergeBlockDefinitions(TInfoSink&, TIntermSymbol* block, TIntermSymbol* unitBlock, TIntermediate* unitRoot);
1041 void mergeImplicitArraySizes(TType&, const TType&);
1042 void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, EShLanguage);
1043 void checkCallGraphCycles(TInfoSink&);
1044 void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
1045 void inOutLocationCheck(TInfoSink&);
1046 void sharedBlockCheck(TInfoSink&);
1047 bool userOutputUsed() const;
1048 bool isSpecializationOperation(const TIntermOperator&) const;
1049 bool isNonuniformPropagating(TOperator) const;
1050 bool promoteUnary(TIntermUnary&);
1051 bool promoteBinary(TIntermBinary&);
1052 void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
1053 bool promoteAggregate(TIntermAggregate&);
1054 void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&);
1055 void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
1056 bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&);
1057 void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root);
1058 bool isConversionAllowed(TOperator op, TIntermTyped* node) const;
1059 std::tuple<TBasicType, TBasicType> getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const;
1061 static const char* getResourceName(TResourceType);
1063 const EShLanguage language; // stage, known at construction time
1064 std::string entryPointName;
1065 std::string entryPointMangledName;
1066 typedef std::list<TCall> TGraph;
1069 #ifdef GLSLANG_ANGLE
1070 const EProfile profile = ECoreProfile;
1071 const int version = 450;
1073 EProfile profile; // source profile
1074 int version; // source version
1076 SpvVersion spvVersion;
1077 TIntermNode* treeRoot;
1078 std::set<std::string> requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
1079 MustBeAssigned<TBuiltInResource> resources;
1082 int numPushConstants;
1086 bool useStorageBuffer;
1088 bool nanMinMaxClamp; // true if desiring min/max/clamp to favor non-NaN over NaN
1089 bool depthReplacing;
1091 bool localSizeNotDefault[3];
1092 int localSizeSpecId[3];
1093 unsigned long long uniqueId;
1095 std::string globalUniformBlockName;
1096 std::string atomicCounterBlockName;
1097 unsigned int globalUniformBlockSet;
1098 unsigned int globalUniformBlockBinding;
1099 unsigned int atomicCounterBlockSet;
1103 const char* const implicitThisName;
1104 const char* const implicitCounterName;
1106 EShSource source; // source language, known a bit later
1107 bool useVulkanMemoryModel;
1110 TLayoutGeometry inputPrimitive;
1111 TLayoutGeometry outputPrimitive;
1112 bool pixelCenterInteger;
1113 bool originUpperLeft;
1114 TVertexSpacing vertexSpacing;
1115 TVertexOrder vertexOrder;
1116 TInterlockOrdering interlockOrdering;
1118 bool earlyFragmentTests;
1119 bool postDepthCoverage;
1120 TLayoutDepth depthLayout;
1121 bool hlslFunctionality1;
1122 int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift
1124 std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer
1126 bool layoutOverrideCoverage;
1127 bool geoPassthroughEXT;
1128 int numShaderRecordBlocks;
1129 ComputeDerivativeMode computeDerivativeMode;
1131 int numTaskNVBlocks;
1132 bool layoutPrimitiveCulling;
1134 // Base shift values
1135 std::array<unsigned int, EResCount> shiftBinding;
1137 // Per-descriptor-set shift values
1138 std::array<std::map<int, int>, EResCount> shiftBindingForSet;
1140 std::vector<std::string> resourceSetBinding;
1141 bool autoMapBindings;
1142 bool autoMapLocations;
1143 bool flattenUniformArrays;
1144 bool useUnknownFormat;
1147 bool useVariablePointers;
1149 std::set<TString> semanticNameSet;
1151 EShTextureSamplerTransformMode textureSamplerTransformMode;
1153 bool needToLegalize;
1154 bool binaryDoubleOutput;
1155 bool subgroupUniformControlFlow;
1156 bool usePhysicalStorageBuffer;
1158 TSpirvRequirement* spirvRequirement;
1159 TSpirvExecutionMode* spirvExecutionMode;
1161 std::unordered_map<std::string, int> uniformLocationOverrides;
1162 int uniformLocationBase;
1163 TNumericFeatures numericFeatures;
1165 std::unordered_map<std::string, TBlockStorageClass> blockBackingOverrides;
1167 std::unordered_set<int> usedConstantId; // specialization constant ids used
1168 std::vector<TOffsetRange> usedAtomics; // sets of bindings used by atomic counters
1169 std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers
1170 std::vector<TRange> usedIoRT[2]; // sets of used location, one for rayPayload/rayPayloadIN and other
1171 // for callableData/callableDataIn
1172 // set of names of statically read/written I/O that might need extra checking
1173 std::set<TString> ioAccessed;
1174 // source code of shader, useful as part of debug information
1175 std::string sourceFile;
1176 std::string sourceText;
1178 // Included text. First string is a name, second is the included text
1179 std::map<std::string, std::string> includeText;
1181 // for OpModuleProcessed, or equivalent
1182 TProcesses processes;
1185 void operator=(TIntermediate&); // prevent assignments
1188 } // end namespace glslang
1190 #endif // _LOCAL_INTERMEDIATE_INCLUDED_