1 // 2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. 3 // Copyright (C) 2016 LunarG, Inc. 4 // Copyright (C) 2017 ARM Limited. 5 // Copyright (C) 2015-2018 Google, Inc. 6 // 7 // All rights reserved. 8 // 9 // Redistribution and use in source and binary forms, with or without 10 // modification, are permitted provided that the following conditions 11 // are met: 12 // 13 // Redistributions of source code must retain the above copyright 14 // notice, this list of conditions and the following disclaimer. 15 // 16 // Redistributions in binary form must reproduce the above 17 // copyright notice, this list of conditions and the following 18 // disclaimer in the documentation and/or other materials provided 19 // with the distribution. 20 // 21 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 22 // contributors may be used to endorse or promote products derived 23 // from this software without specific prior written permission. 24 // 25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 35 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 // POSSIBILITY OF SUCH DAMAGE. 37 // 38 39 #ifndef _LOCAL_INTERMEDIATE_INCLUDED_ 40 #define _LOCAL_INTERMEDIATE_INCLUDED_ 41 42 #include "../Include/intermediate.h" 43 #include "../Public/ShaderLang.h" 44 #include "Versions.h" 45 46 #include <string> 47 #include <vector> 48 #include <algorithm> 49 #include <set> 50 #include <array> 51 52 class TInfoSink; 53 54 namespace glslang { 55 56 struct TMatrixSelector { 57 int coord1; // stay agnostic about column/row; this is parse order 58 int coord2; 59 }; 60 61 typedef int TVectorSelector; 62 63 const int MaxSwizzleSelectors = 4; 64 65 template<typename selectorType> 66 class TSwizzleSelectors { 67 public: TSwizzleSelectors()68 TSwizzleSelectors() : size_(0) { } 69 push_back(selectorType comp)70 void push_back(selectorType comp) 71 { 72 if (size_ < MaxSwizzleSelectors) 73 components[size_++] = comp; 74 } resize(int s)75 void resize(int s) 76 { 77 assert(s <= size_); 78 size_ = s; 79 } size()80 int size() const { return size_; } 81 selectorType operator[](int i) const 82 { 83 assert(i < MaxSwizzleSelectors); 84 return components[i]; 85 } 86 87 private: 88 int size_; 89 selectorType components[MaxSwizzleSelectors]; 90 }; 91 92 // 93 // Some helper structures for TIntermediate. Their contents are encapsulated 94 // by TIntermediate. 95 // 96 97 // Used for call-graph algorithms for detecting recursion, missing bodies, and dead bodies. 98 // A "call" is a pair: <caller, callee>. 99 // There can be duplicates. General assumption is the list is small. 100 struct TCall { TCallTCall101 TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { } 102 TString caller; 103 TString callee; 104 bool visited; 105 bool currentPath; 106 bool errorGiven; 107 int calleeBodyPosition; 108 }; 109 110 // A generic 1-D range. 111 struct TRange { TRangeTRange112 TRange(int start, int last) : start(start), last(last) { } overlapTRange113 bool overlap(const TRange& rhs) const 114 { 115 return last >= rhs.start && start <= rhs.last; 116 } 117 int start; 118 int last; 119 }; 120 121 // An IO range is a 3-D rectangle; the set of (location, component, index) triples all lying 122 // within the same location range, component range, and index value. Locations don't alias unless 123 // all other dimensions of their range overlap. 124 struct TIoRange { TIoRangeTIoRange125 TIoRange(TRange location, TRange component, TBasicType basicType, int index) 126 : location(location), component(component), basicType(basicType), index(index) { } overlapTIoRange127 bool overlap(const TIoRange& rhs) const 128 { 129 return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index; 130 } 131 TRange location; 132 TRange component; 133 TBasicType basicType; 134 int index; 135 }; 136 137 // An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying 138 // within the same binding and offset range. 139 struct TOffsetRange { TOffsetRangeTOffsetRange140 TOffsetRange(TRange binding, TRange offset) 141 : binding(binding), offset(offset) { } overlapTOffsetRange142 bool overlap(const TOffsetRange& rhs) const 143 { 144 return binding.overlap(rhs.binding) && offset.overlap(rhs.offset); 145 } 146 TRange binding; 147 TRange offset; 148 }; 149 150 // Things that need to be tracked per xfb buffer. 151 struct TXfbBuffer { TXfbBufferTXfbBuffer152 TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { } 153 std::vector<TRange> ranges; // byte offsets that have already been assigned 154 unsigned int stride; 155 unsigned int implicitStride; 156 bool containsDouble; 157 }; 158 159 // Track a set of strings describing how the module was processed. 160 // Using the form: 161 // process arg0 arg1 arg2 ... 162 // process arg0 arg1 arg2 ... 163 // where everything is textual, and there can be zero or more arguments 164 class TProcesses { 165 public: TProcesses()166 TProcesses() {} ~TProcesses()167 ~TProcesses() {} 168 addProcess(const char * process)169 void addProcess(const char* process) 170 { 171 processes.push_back(process); 172 } addProcess(const std::string & process)173 void addProcess(const std::string& process) 174 { 175 processes.push_back(process); 176 } addArgument(int arg)177 void addArgument(int arg) 178 { 179 processes.back().append(" "); 180 std::string argString = std::to_string(arg); 181 processes.back().append(argString); 182 } addArgument(const char * arg)183 void addArgument(const char* arg) 184 { 185 processes.back().append(" "); 186 processes.back().append(arg); 187 } addArgument(const std::string & arg)188 void addArgument(const std::string& arg) 189 { 190 processes.back().append(" "); 191 processes.back().append(arg); 192 } addIfNonZero(const char * process,int value)193 void addIfNonZero(const char* process, int value) 194 { 195 if (value != 0) { 196 addProcess(process); 197 addArgument(value); 198 } 199 } 200 getProcesses()201 const std::vector<std::string>& getProcesses() const { return processes; } 202 203 private: 204 std::vector<std::string> processes; 205 }; 206 207 class TSymbolTable; 208 class TSymbol; 209 class TVariable; 210 211 #ifdef NV_EXTENSIONS 212 // 213 // Texture and Sampler transformation mode. 214 // 215 enum ComputeDerivativeMode { 216 LayoutDerivativeNone, // default layout as SPV_NV_compute_shader_derivatives not enabled 217 LayoutDerivativeGroupQuads, // derivative_group_quadsNV 218 LayoutDerivativeGroupLinear, // derivative_group_linearNV 219 }; 220 #endif 221 222 // 223 // Set of helper functions to help parse and build the tree. 224 // 225 class TIntermediate { 226 public: 227 explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : 228 implicitThisName("@this"), implicitCounterName("@count"), 229 language(l), source(EShSourceNone), profile(p), version(v), treeRoot(0), 230 numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false), 231 invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), 232 inputPrimitive(ElgNone), outputPrimitive(ElgNone), 233 pixelCenterInteger(false), originUpperLeft(false), 234 vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), 235 postDepthCoverage(false), depthLayout(EldNone), depthReplacing(false), 236 hlslFunctionality1(false), 237 blendEquations(0), xfbMode(false), multiStream(false), 238 #ifdef NV_EXTENSIONS 239 layoutOverrideCoverage(false), 240 geoPassthroughEXT(false), 241 numShaderRecordNVBlocks(0), 242 computeDerivativeMode(LayoutDerivativeNone), 243 primitives(TQualifier::layoutNotSet), 244 numTaskNVBlocks(0), 245 #endif 246 autoMapBindings(false), 247 autoMapLocations(false), 248 invertY(false), 249 flattenUniformArrays(false), 250 useUnknownFormat(false), 251 hlslOffsets(false), 252 useStorageBuffer(false), 253 useVulkanMemoryModel(false), 254 hlslIoMapping(false), 255 textureSamplerTransformMode(EShTexSampTransKeep), 256 needToLegalize(false), 257 binaryDoubleOutput(false), 258 usePhysicalStorageBuffer(false), 259 uniformLocationBase(0) 260 { 261 localSize[0] = 1; 262 localSize[1] = 1; 263 localSize[2] = 1; 264 localSizeSpecId[0] = TQualifier::layoutNotSet; 265 localSizeSpecId[1] = TQualifier::layoutNotSet; 266 localSizeSpecId[2] = TQualifier::layoutNotSet; 267 xfbBuffers.resize(TQualifier::layoutXfbBufferEnd); 268 269 shiftBinding.fill(0); 270 } setLimits(const TBuiltInResource & r)271 void setLimits(const TBuiltInResource& r) { resources = r; } 272 273 bool postProcess(TIntermNode*, EShLanguage); 274 void output(TInfoSink&, bool tree); 275 void removeTree(); 276 setSource(EShSource s)277 void setSource(EShSource s) { source = s; } getSource()278 EShSource getSource() const { return source; } setEntryPointName(const char * ep)279 void setEntryPointName(const char* ep) 280 { 281 entryPointName = ep; 282 processes.addProcess("entry-point"); 283 processes.addArgument(entryPointName); 284 } setEntryPointMangledName(const char * ep)285 void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; } getEntryPointName()286 const std::string& getEntryPointName() const { return entryPointName; } getEntryPointMangledName()287 const std::string& getEntryPointMangledName() const { return entryPointMangledName; } 288 setShiftBinding(TResourceType res,unsigned int shift)289 void setShiftBinding(TResourceType res, unsigned int shift) 290 { 291 shiftBinding[res] = shift; 292 293 const char* name = getResourceName(res); 294 if (name != nullptr) 295 processes.addIfNonZero(name, shift); 296 } 297 getShiftBinding(TResourceType res)298 unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; } 299 setShiftBindingForSet(TResourceType res,unsigned int shift,unsigned int set)300 void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set) 301 { 302 if (shift == 0) // ignore if there's no shift: it's a no-op. 303 return; 304 305 shiftBindingForSet[res][set] = shift; 306 307 const char* name = getResourceName(res); 308 if (name != nullptr) { 309 processes.addProcess(name); 310 processes.addArgument(shift); 311 processes.addArgument(set); 312 } 313 } 314 getShiftBindingForSet(TResourceType res,unsigned int set)315 int getShiftBindingForSet(TResourceType res, unsigned int set) const 316 { 317 const auto shift = shiftBindingForSet[res].find(set); 318 return shift == shiftBindingForSet[res].end() ? -1 : shift->second; 319 } hasShiftBindingForSet(TResourceType res)320 bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); } 321 setResourceSetBinding(const std::vector<std::string> & shift)322 void setResourceSetBinding(const std::vector<std::string>& shift) 323 { 324 resourceSetBinding = shift; 325 if (shift.size() > 0) { 326 processes.addProcess("resource-set-binding"); 327 for (int s = 0; s < (int)shift.size(); ++s) 328 processes.addArgument(shift[s]); 329 } 330 } getResourceSetBinding()331 const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; } setAutoMapBindings(bool map)332 void setAutoMapBindings(bool map) 333 { 334 autoMapBindings = map; 335 if (autoMapBindings) 336 processes.addProcess("auto-map-bindings"); 337 } getAutoMapBindings()338 bool getAutoMapBindings() const { return autoMapBindings; } setAutoMapLocations(bool map)339 void setAutoMapLocations(bool map) 340 { 341 autoMapLocations = map; 342 if (autoMapLocations) 343 processes.addProcess("auto-map-locations"); 344 } getAutoMapLocations()345 bool getAutoMapLocations() const { return autoMapLocations; } setInvertY(bool invert)346 void setInvertY(bool invert) 347 { 348 invertY = invert; 349 if (invertY) 350 processes.addProcess("invert-y"); 351 } getInvertY()352 bool getInvertY() const { return invertY; } 353 setFlattenUniformArrays(bool flatten)354 void setFlattenUniformArrays(bool flatten) 355 { 356 flattenUniformArrays = flatten; 357 if (flattenUniformArrays) 358 processes.addProcess("flatten-uniform-arrays"); 359 } getFlattenUniformArrays()360 bool getFlattenUniformArrays() const { return flattenUniformArrays; } setNoStorageFormat(bool b)361 void setNoStorageFormat(bool b) 362 { 363 useUnknownFormat = b; 364 if (useUnknownFormat) 365 processes.addProcess("no-storage-format"); 366 } getNoStorageFormat()367 bool getNoStorageFormat() const { return useUnknownFormat; } setHlslOffsets()368 void setHlslOffsets() 369 { 370 hlslOffsets = true; 371 if (hlslOffsets) 372 processes.addProcess("hlsl-offsets"); 373 } usingHlslOffsets()374 bool usingHlslOffsets() const { return hlslOffsets; } setUseStorageBuffer()375 void setUseStorageBuffer() 376 { 377 useStorageBuffer = true; 378 processes.addProcess("use-storage-buffer"); 379 } usingStorageBuffer()380 bool usingStorageBuffer() const { return useStorageBuffer; } setHlslIoMapping(bool b)381 void setHlslIoMapping(bool b) 382 { 383 hlslIoMapping = b; 384 if (hlslIoMapping) 385 processes.addProcess("hlsl-iomap"); 386 } usingHlslIoMapping()387 bool usingHlslIoMapping() { return hlslIoMapping; } setUseVulkanMemoryModel()388 void setUseVulkanMemoryModel() 389 { 390 useVulkanMemoryModel = true; 391 processes.addProcess("use-vulkan-memory-model"); 392 } usingVulkanMemoryModel()393 bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; } setUsePhysicalStorageBuffer()394 void setUsePhysicalStorageBuffer() 395 { 396 usePhysicalStorageBuffer = true; 397 } usingPhysicalStorageBuffer()398 bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; } 399 addCounterBufferName(const T & name)400 template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; } hasCounterBufferName(const TString & name)401 bool hasCounterBufferName(const TString& name) const { 402 size_t len = strlen(implicitCounterName); 403 return name.size() > len && 404 name.compare(name.size() - len, len, implicitCounterName) == 0; 405 } 406 setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode)407 void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; } 408 setVersion(int v)409 void setVersion(int v) { version = v; } getVersion()410 int getVersion() const { return version; } setProfile(EProfile p)411 void setProfile(EProfile p) { profile = p; } getProfile()412 EProfile getProfile() const { return profile; } setSpv(const SpvVersion & s)413 void setSpv(const SpvVersion& s) 414 { 415 spvVersion = s; 416 417 // client processes 418 if (spvVersion.vulkan > 0) 419 processes.addProcess("client vulkan100"); 420 if (spvVersion.openGl > 0) 421 processes.addProcess("client opengl100"); 422 423 // target-environment processes 424 if (spvVersion.vulkan > 0) 425 processes.addProcess("target-env vulkan1.0"); 426 else if (spvVersion.vulkan > 0) 427 processes.addProcess("target-env vulkanUnknown"); 428 if (spvVersion.openGl > 0) 429 processes.addProcess("target-env opengl"); 430 } getSpv()431 const SpvVersion& getSpv() const { return spvVersion; } getStage()432 EShLanguage getStage() const { return language; } addRequestedExtension(const char * extension)433 void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); } getRequestedExtensions()434 const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; } 435 setTreeRoot(TIntermNode * r)436 void setTreeRoot(TIntermNode* r) { treeRoot = r; } getTreeRoot()437 TIntermNode* getTreeRoot() const { return treeRoot; } incrementEntryPointCount()438 void incrementEntryPointCount() { ++numEntryPoints; } getNumEntryPoints()439 int getNumEntryPoints() const { return numEntryPoints; } getNumErrors()440 int getNumErrors() const { return numErrors; } addPushConstantCount()441 void addPushConstantCount() { ++numPushConstants; } 442 #ifdef NV_EXTENSIONS addShaderRecordNVCount()443 void addShaderRecordNVCount() { ++numShaderRecordNVBlocks; } addTaskNVCount()444 void addTaskNVCount() { ++numTaskNVBlocks; } 445 #endif 446 isRecursive()447 bool isRecursive() const { return recursive; } 448 449 TIntermSymbol* addSymbol(const TVariable&); 450 TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&); 451 TIntermSymbol* addSymbol(const TType&, const TSourceLoc&); 452 TIntermSymbol* addSymbol(const TIntermSymbol&); 453 TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const; 454 std::tuple<TIntermTyped*, TIntermTyped*> addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) const; 455 TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*); 456 void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode); 457 TIntermTyped* addShapeConversion(const TType&, TIntermTyped*); 458 TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc); 459 TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc); 460 TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc); 461 TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc); 462 TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType); 463 bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const; 464 bool isIntegralPromotion(TBasicType from, TBasicType to) const; 465 bool isFPPromotion(TBasicType from, TBasicType to) const; 466 bool isIntegralConversion(TBasicType from, TBasicType to) const; 467 bool isFPConversion(TBasicType from, TBasicType to) const; 468 bool isFPIntegralConversion(TBasicType from, TBasicType to) const; 469 TOperator mapTypeToConstructorOp(const TType&) const; 470 TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right); 471 TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&); 472 TIntermAggregate* makeAggregate(TIntermNode* node); 473 TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&); 474 TIntermAggregate* makeAggregate(const TSourceLoc&); 475 TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc); 476 bool areAllChildConst(TIntermAggregate* aggrNode); 477 TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&); 478 TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&); 479 TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); 480 TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&); 481 TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const; 482 TIntermConstantUnion* addConstantUnion(signed char, const TSourceLoc&, bool literal = false) const; 483 TIntermConstantUnion* addConstantUnion(unsigned char, const TSourceLoc&, bool literal = false) const; 484 TIntermConstantUnion* addConstantUnion(signed short, const TSourceLoc&, bool literal = false) const; 485 TIntermConstantUnion* addConstantUnion(unsigned short, const TSourceLoc&, bool literal = false) const; 486 TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const; 487 TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const; 488 TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const; 489 TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const; 490 TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const; 491 TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const; 492 TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const; 493 TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const; 494 bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false); 495 TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&); 496 TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, 497 const TSourceLoc&, TIntermLoop*&); 498 TIntermBranch* addBranch(TOperator, const TSourceLoc&); 499 TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&); 500 template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&); 501 502 // Low level functions to add nodes (no conversions or other higher level transformations) 503 // If a type is provided, the node's type will be set to it. 504 TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc) const; 505 TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, const TType&) const; 506 TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc) const; 507 TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc, const TType&) const; 508 509 // Constant folding (in Constant.cpp) 510 TIntermTyped* fold(TIntermAggregate* aggrNode); 511 TIntermTyped* foldConstructor(TIntermAggregate* aggrNode); 512 TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&); 513 TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& fields, const TSourceLoc&); 514 515 // Tree ops 516 static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay); 517 518 // Linkage related 519 void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); 520 void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&); 521 setInvocations(int i)522 bool setInvocations(int i) 523 { 524 if (invocations != TQualifier::layoutNotSet) 525 return invocations == i; 526 invocations = i; 527 return true; 528 } getInvocations()529 int getInvocations() const { return invocations; } setVertices(int m)530 bool setVertices(int m) 531 { 532 if (vertices != TQualifier::layoutNotSet) 533 return vertices == m; 534 vertices = m; 535 return true; 536 } getVertices()537 int getVertices() const { return vertices; } setInputPrimitive(TLayoutGeometry p)538 bool setInputPrimitive(TLayoutGeometry p) 539 { 540 if (inputPrimitive != ElgNone) 541 return inputPrimitive == p; 542 inputPrimitive = p; 543 return true; 544 } getInputPrimitive()545 TLayoutGeometry getInputPrimitive() const { return inputPrimitive; } setVertexSpacing(TVertexSpacing s)546 bool setVertexSpacing(TVertexSpacing s) 547 { 548 if (vertexSpacing != EvsNone) 549 return vertexSpacing == s; 550 vertexSpacing = s; 551 return true; 552 } getVertexSpacing()553 TVertexSpacing getVertexSpacing() const { return vertexSpacing; } setVertexOrder(TVertexOrder o)554 bool setVertexOrder(TVertexOrder o) 555 { 556 if (vertexOrder != EvoNone) 557 return vertexOrder == o; 558 vertexOrder = o; 559 return true; 560 } getVertexOrder()561 TVertexOrder getVertexOrder() const { return vertexOrder; } setPointMode()562 void setPointMode() { pointMode = true; } getPointMode()563 bool getPointMode() const { return pointMode; } 564 setLocalSize(int dim,int size)565 bool setLocalSize(int dim, int size) 566 { 567 if (localSize[dim] > 1) 568 return size == localSize[dim]; 569 localSize[dim] = size; 570 return true; 571 } getLocalSize(int dim)572 unsigned int getLocalSize(int dim) const { return localSize[dim]; } 573 setLocalSizeSpecId(int dim,int id)574 bool setLocalSizeSpecId(int dim, int id) 575 { 576 if (localSizeSpecId[dim] != TQualifier::layoutNotSet) 577 return id == localSizeSpecId[dim]; 578 localSizeSpecId[dim] = id; 579 return true; 580 } getLocalSizeSpecId(int dim)581 int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; } 582 setXfbMode()583 void setXfbMode() { xfbMode = true; } getXfbMode()584 bool getXfbMode() const { return xfbMode; } setMultiStream()585 void setMultiStream() { multiStream = true; } isMultiStream()586 bool isMultiStream() const { return multiStream; } setOutputPrimitive(TLayoutGeometry p)587 bool setOutputPrimitive(TLayoutGeometry p) 588 { 589 if (outputPrimitive != ElgNone) 590 return outputPrimitive == p; 591 outputPrimitive = p; 592 return true; 593 } getOutputPrimitive()594 TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; } setOriginUpperLeft()595 void setOriginUpperLeft() { originUpperLeft = true; } getOriginUpperLeft()596 bool getOriginUpperLeft() const { return originUpperLeft; } setPixelCenterInteger()597 void setPixelCenterInteger() { pixelCenterInteger = true; } getPixelCenterInteger()598 bool getPixelCenterInteger() const { return pixelCenterInteger; } setEarlyFragmentTests()599 void setEarlyFragmentTests() { earlyFragmentTests = true; } getEarlyFragmentTests()600 bool getEarlyFragmentTests() const { return earlyFragmentTests; } setPostDepthCoverage()601 void setPostDepthCoverage() { postDepthCoverage = true; } getPostDepthCoverage()602 bool getPostDepthCoverage() const { return postDepthCoverage; } setDepth(TLayoutDepth d)603 bool setDepth(TLayoutDepth d) 604 { 605 if (depthLayout != EldNone) 606 return depthLayout == d; 607 depthLayout = d; 608 return true; 609 } getDepth()610 TLayoutDepth getDepth() const { return depthLayout; } setDepthReplacing()611 void setDepthReplacing() { depthReplacing = true; } isDepthReplacing()612 bool isDepthReplacing() const { return depthReplacing; } 613 setHlslFunctionality1()614 void setHlslFunctionality1() { hlslFunctionality1 = true; } getHlslFunctionality1()615 bool getHlslFunctionality1() const { return hlslFunctionality1; } 616 addBlendEquation(TBlendEquationShift b)617 void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); } getBlendEquations()618 unsigned int getBlendEquations() const { return blendEquations; } 619 620 void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee); 621 void merge(TInfoSink&, TIntermediate&); 622 void finalCheck(TInfoSink&, bool keepUncalled); 623 addIoAccessed(const TString & name)624 void addIoAccessed(const TString& name) { ioAccessed.insert(name); } inIoAccessed(const TString & name)625 bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); } 626 627 int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision); 628 int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision); 629 int addUsedOffsets(int binding, int offset, int numOffsets); 630 bool addUsedConstantId(int id); 631 static int computeTypeLocationSize(const TType&, EShLanguage); 632 static int computeTypeUniformLocationSize(const TType&); 633 setXfbBufferStride(int buffer,unsigned stride)634 bool setXfbBufferStride(int buffer, unsigned stride) 635 { 636 if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd) 637 return xfbBuffers[buffer].stride == stride; 638 xfbBuffers[buffer].stride = stride; 639 return true; 640 } getXfbStride(int buffer)641 unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; } 642 int addXfbBufferOffset(const TType&); 643 unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const; 644 static int getBaseAlignmentScalar(const TType&, int& size); 645 static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor); 646 static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor); 647 static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor); 648 static bool improperStraddle(const TType& type, int size, int offset); 649 bool promote(TIntermOperator*); 650 651 #ifdef NV_EXTENSIONS setLayoutOverrideCoverage()652 void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; } getLayoutOverrideCoverage()653 bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; } setGeoPassthroughEXT()654 void setGeoPassthroughEXT() { geoPassthroughEXT = true; } getGeoPassthroughEXT()655 bool getGeoPassthroughEXT() const { return geoPassthroughEXT; } setLayoutDerivativeMode(ComputeDerivativeMode mode)656 void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; } getLayoutDerivativeModeNone()657 ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; } setPrimitives(int m)658 bool setPrimitives(int m) 659 { 660 if (primitives != TQualifier::layoutNotSet) 661 return primitives == m; 662 primitives = m; 663 return true; 664 } getPrimitives()665 int getPrimitives() const { return primitives; } 666 #endif 667 addSemanticName(const TString & name)668 const char* addSemanticName(const TString& name) 669 { 670 return semanticNameSet.insert(name).first->c_str(); 671 } 672 setSourceFile(const char * file)673 void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; } getSourceFile()674 const std::string& getSourceFile() const { return sourceFile; } addSourceText(const char * text,size_t len)675 void addSourceText(const char* text, size_t len) { sourceText.append(text, len); } getSourceText()676 const std::string& getSourceText() const { return sourceText; } getIncludeText()677 const std::map<std::string, std::string>& getIncludeText() const { return includeText; } addIncludeText(const char * name,const char * text,size_t len)678 void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); } addProcesses(const std::vector<std::string> & p)679 void addProcesses(const std::vector<std::string>& p) 680 { 681 for (int i = 0; i < (int)p.size(); ++i) 682 processes.addProcess(p[i]); 683 } addProcess(const std::string & process)684 void addProcess(const std::string& process) { processes.addProcess(process); } addProcessArgument(const std::string & arg)685 void addProcessArgument(const std::string& arg) { processes.addArgument(arg); } getProcesses()686 const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); } 687 addUniformLocationOverride(const char * nameStr,int location)688 void addUniformLocationOverride(const char* nameStr, int location) 689 { 690 std::string name = nameStr; 691 uniformLocationOverrides[name] = location; 692 } 693 getUniformLocationOverride(const char * nameStr)694 int getUniformLocationOverride(const char* nameStr) const 695 { 696 std::string name = nameStr; 697 auto pos = uniformLocationOverrides.find(name); 698 if (pos == uniformLocationOverrides.end()) 699 return -1; 700 else 701 return pos->second; 702 } 703 setUniformLocationBase(int base)704 void setUniformLocationBase(int base) { uniformLocationBase = base; } getUniformLocationBase()705 int getUniformLocationBase() const { return uniformLocationBase; } 706 setNeedsLegalization()707 void setNeedsLegalization() { needToLegalize = true; } needsLegalization()708 bool needsLegalization() const { return needToLegalize; } 709 setBinaryDoubleOutput()710 void setBinaryDoubleOutput() { binaryDoubleOutput = true; } getBinaryDoubleOutput()711 bool getBinaryDoubleOutput() { return binaryDoubleOutput; } 712 713 const char* const implicitThisName; 714 const char* const implicitCounterName; 715 716 protected: 717 TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); 718 void error(TInfoSink& infoSink, const char*); 719 void warn(TInfoSink& infoSink, const char*); 720 void mergeCallGraphs(TInfoSink&, TIntermediate&); 721 void mergeModes(TInfoSink&, TIntermediate&); 722 void mergeTrees(TInfoSink&, TIntermediate&); 723 void seedIdMap(TMap<TString, int>& idMap, int& maxId); 724 void remapIds(const TMap<TString, int>& idMap, int idShift, TIntermediate&); 725 void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals); 726 void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects); 727 void mergeImplicitArraySizes(TType&, const TType&); 728 void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage); 729 void checkCallGraphCycles(TInfoSink&); 730 void checkCallGraphBodies(TInfoSink&, bool keepUncalled); 731 void inOutLocationCheck(TInfoSink&); 732 TIntermAggregate* findLinkerObjects() const; 733 bool userOutputUsed() const; 734 bool isSpecializationOperation(const TIntermOperator&) const; 735 bool isNonuniformPropagating(TOperator) const; 736 bool promoteUnary(TIntermUnary&); 737 bool promoteBinary(TIntermBinary&); 738 void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&); 739 bool promoteAggregate(TIntermAggregate&); 740 void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&); 741 void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&); 742 bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&); 743 void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root); 744 bool isConversionAllowed(TOperator op, TIntermTyped* node) const; 745 TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const; 746 std::tuple<TBasicType, TBasicType> getConversionDestinatonType(TBasicType type0, TBasicType type1, TOperator op) const; extensionRequested(const char * extension)747 bool extensionRequested(const char *extension) const {return requestedExtensions.find(extension) != requestedExtensions.end();} 748 static const char* getResourceName(TResourceType); 749 750 const EShLanguage language; // stage, known at construction time 751 EShSource source; // source language, known a bit later 752 std::string entryPointName; 753 std::string entryPointMangledName; 754 typedef std::list<TCall> TGraph; 755 TGraph callGraph; 756 757 EProfile profile; // source profile 758 int version; // source version 759 SpvVersion spvVersion; 760 TIntermNode* treeRoot; 761 std::set<std::string> requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them 762 TBuiltInResource resources; 763 int numEntryPoints; 764 int numErrors; 765 int numPushConstants; 766 bool recursive; 767 int invocations; 768 int vertices; 769 TLayoutGeometry inputPrimitive; 770 TLayoutGeometry outputPrimitive; 771 bool pixelCenterInteger; 772 bool originUpperLeft; 773 TVertexSpacing vertexSpacing; 774 TVertexOrder vertexOrder; 775 bool pointMode; 776 int localSize[3]; 777 int localSizeSpecId[3]; 778 bool earlyFragmentTests; 779 bool postDepthCoverage; 780 TLayoutDepth depthLayout; 781 bool depthReplacing; 782 bool hlslFunctionality1; 783 int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift 784 bool xfbMode; 785 std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer 786 bool multiStream; 787 788 #ifdef NV_EXTENSIONS 789 bool layoutOverrideCoverage; 790 bool geoPassthroughEXT; 791 int numShaderRecordNVBlocks; 792 ComputeDerivativeMode computeDerivativeMode; 793 int primitives; 794 int numTaskNVBlocks; 795 #endif 796 797 // Base shift values 798 std::array<unsigned int, EResCount> shiftBinding; 799 800 // Per-descriptor-set shift values 801 std::array<std::map<int, int>, EResCount> shiftBindingForSet; 802 803 std::vector<std::string> resourceSetBinding; 804 bool autoMapBindings; 805 bool autoMapLocations; 806 bool invertY; 807 bool flattenUniformArrays; 808 bool useUnknownFormat; 809 bool hlslOffsets; 810 bool useStorageBuffer; 811 bool useVulkanMemoryModel; 812 bool hlslIoMapping; 813 814 std::set<TString> ioAccessed; // set of names of statically read/written I/O that might need extra checking 815 std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers 816 std::vector<TOffsetRange> usedAtomics; // sets of bindings used by atomic counters 817 std::unordered_set<int> usedConstantId; // specialization constant ids used 818 std::set<TString> semanticNameSet; 819 820 EShTextureSamplerTransformMode textureSamplerTransformMode; 821 822 // source code of shader, useful as part of debug information 823 std::string sourceFile; 824 std::string sourceText; 825 826 // Included text. First string is a name, second is the included text 827 std::map<std::string, std::string> includeText; 828 829 // for OpModuleProcessed, or equivalent 830 TProcesses processes; 831 832 bool needToLegalize; 833 bool binaryDoubleOutput; 834 bool usePhysicalStorageBuffer; 835 836 std::unordered_map<std::string, int> uniformLocationOverrides; 837 int uniformLocationBase; 838 839 private: 840 void operator=(TIntermediate&); // prevent assignments 841 }; 842 843 } // end namespace glslang 844 845 #endif // _LOCAL_INTERMEDIATE_INCLUDED_ 846