1 // 2 //Copyright (C) 2002-2005 3Dlabs Inc. Ltd. 3 //All rights reserved. 4 // 5 //Redistribution and use in source and binary forms, with or without 6 //modification, are permitted provided that the following conditions 7 //are met: 8 // 9 // Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // 12 // Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following 14 // disclaimer in the documentation and/or other materials provided 15 // with the distribution. 16 // 17 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 18 // contributors may be used to endorse or promote products derived 19 // from this software without specific prior written permission. 20 // 21 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 //POSSIBILITY OF SUCH DAMAGE. 33 // 34 35 #ifndef _LOCAL_INTERMEDIATE_INCLUDED_ 36 #define _LOCAL_INTERMEDIATE_INCLUDED_ 37 38 #include "../Include/intermediate.h" 39 #include "../Public/ShaderLang.h" 40 #include "Versions.h" 41 42 #include <algorithm> 43 #include <set> 44 45 class TInfoSink; 46 47 namespace glslang { 48 49 struct TVectorFields { 50 int offsets[4]; 51 int num; 52 }; 53 54 // 55 // Some helper structures for TIntermediate. Their contents are encapsulated 56 // by TIntermediate. 57 // 58 59 // Used for detecting recursion: A "call" is a pair: <caller, callee>. 60 struct TCall { 61 TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { } 62 TString caller; 63 TString callee; 64 bool visited; 65 bool currentPath; 66 bool errorGiven; 67 }; 68 69 // A generic 1-D range. 70 struct TRange { 71 TRange(int start, int last) : start(start), last(last) { } 72 bool overlap(const TRange& rhs) const 73 { 74 return last >= rhs.start && start <= rhs.last; 75 } 76 int start; 77 int last; 78 }; 79 80 // An IO range is a 3-D rectangle; the set of (location, component, index) triples all lying 81 // within the same location range, component range, and index value. Locations don't alias unless 82 // all other dimensions of their range overlap. 83 struct TIoRange { 84 TIoRange(TRange location, TRange component, TBasicType basicType, int index) 85 : location(location), component(component), basicType(basicType), index(index) { } 86 bool overlap(const TIoRange& rhs) const 87 { 88 return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index; 89 } 90 TRange location; 91 TRange component; 92 TBasicType basicType; 93 int index; 94 }; 95 96 // An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying 97 // within the same binding and offset range. 98 struct TOffsetRange { 99 TOffsetRange(TRange binding, TRange offset) 100 : binding(binding), offset(offset) { } 101 bool overlap(const TOffsetRange& rhs) const 102 { 103 return binding.overlap(rhs.binding) && offset.overlap(rhs.offset); 104 } 105 TRange binding; 106 TRange offset; 107 }; 108 109 // Things that need to be tracked per xfb buffer. 110 struct TXfbBuffer { 111 TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { } 112 std::vector<TRange> ranges; // byte offsets that have already been assigned 113 unsigned int stride; 114 unsigned int implicitStride; 115 bool containsDouble; 116 }; 117 118 class TSymbolTable; 119 class TSymbol; 120 class TVariable; 121 122 // 123 // Set of helper functions to help parse and build the tree. 124 // 125 class TIntermediate { 126 public: 127 explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : 128 source(EShSourceNone), language(l), profile(p), version(v), treeRoot(0), 129 numMains(0), numErrors(0), numPushConstants(0), recursive(false), 130 invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone), 131 pixelCenterInteger(false), originUpperLeft(false), 132 vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), depthReplacing(false), blendEquations(0), 133 multiStream(false), xfbMode(false) 134 { 135 localSize[0] = 1; 136 localSize[1] = 1; 137 localSize[2] = 1; 138 localSizeSpecId[0] = TQualifier::layoutNotSet; 139 localSizeSpecId[1] = TQualifier::layoutNotSet; 140 localSizeSpecId[2] = TQualifier::layoutNotSet; 141 xfbBuffers.resize(TQualifier::layoutXfbBufferEnd); 142 } 143 void setLimits(const TBuiltInResource& r) { resources = r; } 144 145 bool postProcess(TIntermNode*, EShLanguage); 146 void output(TInfoSink&, bool tree); 147 void removeTree(); 148 149 void setSource(EShSource s) { source = s; } 150 EShSource getSource() const { return source; } 151 void setEntryPoint(const char* ep) { entryPoint = ep; } 152 const std::string& getEntryPoint() const { return entryPoint; } 153 void setVersion(int v) { version = v; } 154 int getVersion() const { return version; } 155 void setProfile(EProfile p) { profile = p; } 156 EProfile getProfile() const { return profile; } 157 void setSpv(const SpvVersion& s) { spvVersion = s; } 158 const SpvVersion& getSpv() const { return spvVersion; } 159 EShLanguage getStage() const { return language; } 160 void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); } 161 const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; } 162 163 void setTreeRoot(TIntermNode* r) { treeRoot = r; } 164 TIntermNode* getTreeRoot() const { return treeRoot; } 165 void addMainCount() { ++numMains; } 166 int getNumMains() const { return numMains; } 167 int getNumErrors() const { return numErrors; } 168 void addPushConstantCount() { ++numPushConstants; } 169 bool isRecursive() const { return recursive; } 170 171 TIntermSymbol* addSymbol(const TVariable&); 172 TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&); 173 TIntermSymbol* addSymbol(const TType&, const TSourceLoc&); 174 TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const; 175 TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc); 176 TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc); 177 TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc); 178 TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc); 179 TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType); 180 bool canImplicitlyPromote(TBasicType from, TBasicType to) const; 181 TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right); 182 TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&); 183 TIntermAggregate* makeAggregate(TIntermNode* node); 184 TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&); 185 TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc); 186 bool areAllChildConst(TIntermAggregate* aggrNode); 187 TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&); 188 TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&); 189 TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); 190 TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&); 191 TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const; 192 TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const; 193 TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const; 194 TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const; 195 TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const; 196 TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const; 197 TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const; 198 TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const; 199 bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false); 200 TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&); 201 TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&); 202 TIntermBranch* addBranch(TOperator, const TSourceLoc&); 203 TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&); 204 TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&); 205 206 // Constant folding (in Constant.cpp) 207 TIntermTyped* fold(TIntermAggregate* aggrNode); 208 TIntermTyped* foldConstructor(TIntermAggregate* aggrNode); 209 TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&); 210 TIntermTyped* foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc&); 211 212 // Tree ops 213 static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay); 214 215 // Linkage related 216 void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); 217 void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&); 218 void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&); 219 220 bool setInvocations(int i) 221 { 222 if (invocations != TQualifier::layoutNotSet) 223 return invocations == i; 224 invocations = i; 225 return true; 226 } 227 int getInvocations() const { return invocations; } 228 bool setVertices(int m) 229 { 230 if (vertices != TQualifier::layoutNotSet) 231 return vertices == m; 232 vertices = m; 233 return true; 234 } 235 int getVertices() const { return vertices; } 236 bool setInputPrimitive(TLayoutGeometry p) 237 { 238 if (inputPrimitive != ElgNone) 239 return inputPrimitive == p; 240 inputPrimitive = p; 241 return true; 242 } 243 TLayoutGeometry getInputPrimitive() const { return inputPrimitive; } 244 bool setVertexSpacing(TVertexSpacing s) 245 { 246 if (vertexSpacing != EvsNone) 247 return vertexSpacing == s; 248 vertexSpacing = s; 249 return true; 250 } 251 TVertexSpacing getVertexSpacing() const { return vertexSpacing; } 252 bool setVertexOrder(TVertexOrder o) 253 { 254 if (vertexOrder != EvoNone) 255 return vertexOrder == o; 256 vertexOrder = o; 257 return true; 258 } 259 TVertexOrder getVertexOrder() const { return vertexOrder; } 260 void setPointMode() { pointMode = true; } 261 bool getPointMode() const { return pointMode; } 262 263 bool setLocalSize(int dim, int size) 264 { 265 if (localSize[dim] > 1) 266 return size == localSize[dim]; 267 localSize[dim] = size; 268 return true; 269 } 270 unsigned int getLocalSize(int dim) const { return localSize[dim]; } 271 272 bool setLocalSizeSpecId(int dim, int id) 273 { 274 if (localSizeSpecId[dim] != TQualifier::layoutNotSet) 275 return id == localSizeSpecId[dim]; 276 localSizeSpecId[dim] = id; 277 return true; 278 } 279 int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; } 280 281 void setXfbMode() { xfbMode = true; } 282 bool getXfbMode() const { return xfbMode; } 283 void setMultiStream() { multiStream = true; } 284 bool isMultiStream() const { return multiStream; } 285 bool setOutputPrimitive(TLayoutGeometry p) 286 { 287 if (outputPrimitive != ElgNone) 288 return outputPrimitive == p; 289 outputPrimitive = p; 290 return true; 291 } 292 TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; } 293 void setOriginUpperLeft() { originUpperLeft = true; } 294 bool getOriginUpperLeft() const { return originUpperLeft; } 295 void setPixelCenterInteger() { pixelCenterInteger = true; } 296 bool getPixelCenterInteger() const { return pixelCenterInteger; } 297 void setEarlyFragmentTests() { earlyFragmentTests = true; } 298 bool getEarlyFragmentTests() const { return earlyFragmentTests; } 299 bool setDepth(TLayoutDepth d) 300 { 301 if (depthLayout != EldNone) 302 return depthLayout == d; 303 depthLayout = d; 304 return true; 305 } 306 TLayoutDepth getDepth() const { return depthLayout; } 307 void setDepthReplacing() { depthReplacing = true; } 308 bool isDepthReplacing() const { return depthReplacing; } 309 310 void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); } 311 unsigned int getBlendEquations() const { return blendEquations; } 312 313 void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee); 314 void merge(TInfoSink&, TIntermediate&); 315 void finalCheck(TInfoSink&); 316 317 void addIoAccessed(const TString& name) { ioAccessed.insert(name); } 318 bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); } 319 320 int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision); 321 int addUsedOffsets(int binding, int offset, int numOffsets); 322 bool addUsedConstantId(int id); 323 int computeTypeLocationSize(const TType&) const; 324 325 bool setXfbBufferStride(int buffer, unsigned stride) 326 { 327 if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd) 328 return xfbBuffers[buffer].stride == stride; 329 xfbBuffers[buffer].stride = stride; 330 return true; 331 } 332 int addXfbBufferOffset(const TType&); 333 unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const; 334 static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor); 335 336 protected: 337 TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); 338 void error(TInfoSink& infoSink, const char*); 339 void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals); 340 void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects); 341 void mergeImplicitArraySizes(TType&, const TType&); 342 void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage); 343 void checkCallGraphCycles(TInfoSink&); 344 void inOutLocationCheck(TInfoSink&); 345 TIntermSequence& findLinkerObjects() const; 346 bool userOutputUsed() const; 347 static int getBaseAlignmentScalar(const TType&, int& size); 348 bool isSpecializationOperation(const TIntermOperator&) const; 349 350 const EShLanguage language; // stage, known at construction time 351 EShSource source; // source language, known a bit later 352 std::string entryPoint; 353 EProfile profile; 354 int version; 355 SpvVersion spvVersion; 356 TIntermNode* treeRoot; 357 std::set<std::string> requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them 358 TBuiltInResource resources; 359 int numMains; 360 int numErrors; 361 int numPushConstants; 362 bool recursive; 363 int invocations; 364 int vertices; 365 TLayoutGeometry inputPrimitive; 366 TLayoutGeometry outputPrimitive; 367 bool pixelCenterInteger; 368 bool originUpperLeft; 369 TVertexSpacing vertexSpacing; 370 TVertexOrder vertexOrder; 371 bool pointMode; 372 int localSize[3]; 373 int localSizeSpecId[3]; 374 bool earlyFragmentTests; 375 TLayoutDepth depthLayout; 376 bool depthReplacing; 377 int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift 378 bool xfbMode; 379 bool multiStream; 380 381 typedef std::list<TCall> TGraph; 382 TGraph callGraph; 383 384 std::set<TString> ioAccessed; // set of names of statically read/written I/O that might need extra checking 385 std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers 386 std::vector<TOffsetRange> usedAtomics; // sets of bindings used by atomic counters 387 std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer 388 std::unordered_set<int> usedConstantId; // specialization constant ids used 389 390 private: 391 void operator=(TIntermediate&); // prevent assignments 392 }; 393 394 } // end namespace glslang 395 396 #endif // _LOCAL_INTERMEDIATE_INCLUDED_ 397