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