1 // 2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. 3 // Copyright (C) 2012-2013 LunarG, Inc. 4 // 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions 9 // are met: 10 // 11 // Redistributions of source code must retain the above copyright 12 // notice, this list of conditions and the following disclaimer. 13 // 14 // Redistributions in binary form must reproduce the above 15 // copyright notice, this list of conditions and the following 16 // disclaimer in the documentation and/or other materials provided 17 // with the distribution. 18 // 19 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 20 // contributors may be used to endorse or promote products derived 21 // from this software without specific prior written permission. 22 // 23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 // POSSIBILITY OF SUCH DAMAGE. 35 // 36 37 // 38 // Implement types for tracking GLSL arrays, arrays of arrays, etc. 39 // 40 41 #ifndef _ARRAYS_INCLUDED 42 #define _ARRAYS_INCLUDED 43 44 #include <algorithm> 45 46 namespace glslang { 47 48 // This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else. 49 const int UnsizedArraySize = 0; 50 51 class TIntermTyped; 52 extern bool SameSpecializationConstants(TIntermTyped*, TIntermTyped*); 53 54 // Specialization constants need both a nominal size and a node that defines 55 // the specialization constant being used. Array types are the same when their 56 // size and specialization constant nodes are the same. 57 struct TArraySize { 58 unsigned int size; 59 TIntermTyped* node; // nullptr means no specialization constant node 60 bool operator==(const TArraySize& rhs) const 61 { 62 if (size != rhs.size) 63 return false; 64 if (node == nullptr || rhs.node == nullptr) 65 return node == rhs.node; 66 67 return SameSpecializationConstants(node, rhs.node); 68 } 69 }; 70 71 // 72 // TSmallArrayVector is used as the container for the set of sizes in TArraySizes. 73 // It has generic-container semantics, while TArraySizes has array-of-array semantics. 74 // That is, TSmallArrayVector should be more focused on mechanism and TArraySizes on policy. 75 // 76 struct TSmallArrayVector { 77 // 78 // TODO: memory: TSmallArrayVector is intended to be smaller. 79 // Almost all arrays could be handled by two sizes each fitting 80 // in 16 bits, needing a real vector only in the cases where there 81 // are more than 3 sizes or a size needing more than 16 bits. 82 // 83 POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) 84 TSmallArrayVectorTSmallArrayVector85 TSmallArrayVector() : sizes(nullptr) { } ~TSmallArrayVectorTSmallArrayVector86 virtual ~TSmallArrayVector() { dealloc(); } 87 88 // For breaking into two non-shared copies, independently modifiable. 89 TSmallArrayVector& operator=(const TSmallArrayVector& from) 90 { 91 if (from.sizes == nullptr) 92 sizes = nullptr; 93 else { 94 alloc(); 95 *sizes = *from.sizes; 96 } 97 98 return *this; 99 } 100 sizeTSmallArrayVector101 int size() const 102 { 103 if (sizes == nullptr) 104 return 0; 105 return (int)sizes->size(); 106 } 107 frontSizeTSmallArrayVector108 unsigned int frontSize() const 109 { 110 assert(sizes != nullptr && sizes->size() > 0); 111 return sizes->front().size; 112 } 113 frontNodeTSmallArrayVector114 TIntermTyped* frontNode() const 115 { 116 assert(sizes != nullptr && sizes->size() > 0); 117 return sizes->front().node; 118 } 119 changeFrontTSmallArrayVector120 void changeFront(unsigned int s) 121 { 122 assert(sizes != nullptr); 123 // this should only happen for implicitly sized arrays, not specialization constants 124 assert(sizes->front().node == nullptr); 125 sizes->front().size = s; 126 } 127 push_backTSmallArrayVector128 void push_back(unsigned int e, TIntermTyped* n) 129 { 130 alloc(); 131 TArraySize pair = { e, n }; 132 sizes->push_back(pair); 133 } 134 push_backTSmallArrayVector135 void push_back(const TSmallArrayVector& newDims) 136 { 137 alloc(); 138 sizes->insert(sizes->end(), newDims.sizes->begin(), newDims.sizes->end()); 139 } 140 pop_frontTSmallArrayVector141 void pop_front() 142 { 143 assert(sizes != nullptr && sizes->size() > 0); 144 if (sizes->size() == 1) 145 dealloc(); 146 else 147 sizes->erase(sizes->begin()); 148 } 149 pop_backTSmallArrayVector150 void pop_back() 151 { 152 assert(sizes != nullptr && sizes->size() > 0); 153 if (sizes->size() == 1) 154 dealloc(); 155 else 156 sizes->resize(sizes->size() - 1); 157 } 158 159 // 'this' should currently not be holding anything, and copyNonFront 160 // will make it hold a copy of all but the first element of rhs. 161 // (This would be useful for making a type that is dereferenced by 162 // one dimension.) copyNonFrontTSmallArrayVector163 void copyNonFront(const TSmallArrayVector& rhs) 164 { 165 assert(sizes == nullptr); 166 if (rhs.size() > 1) { 167 alloc(); 168 sizes->insert(sizes->begin(), rhs.sizes->begin() + 1, rhs.sizes->end()); 169 } 170 } 171 getDimSizeTSmallArrayVector172 unsigned int getDimSize(int i) const 173 { 174 assert(sizes != nullptr && (int)sizes->size() > i); 175 return (*sizes)[i].size; 176 } 177 setDimSizeTSmallArrayVector178 void setDimSize(int i, unsigned int size) const 179 { 180 assert(sizes != nullptr && (int)sizes->size() > i); 181 assert((*sizes)[i].node == nullptr); 182 (*sizes)[i].size = size; 183 } 184 getDimNodeTSmallArrayVector185 TIntermTyped* getDimNode(int i) const 186 { 187 assert(sizes != nullptr && (int)sizes->size() > i); 188 return (*sizes)[i].node; 189 } 190 191 bool operator==(const TSmallArrayVector& rhs) const 192 { 193 if (sizes == nullptr && rhs.sizes == nullptr) 194 return true; 195 if (sizes == nullptr || rhs.sizes == nullptr) 196 return false; 197 return *sizes == *rhs.sizes; 198 } 199 bool operator!=(const TSmallArrayVector& rhs) const { return ! operator==(rhs); } 200 201 protected: 202 TSmallArrayVector(const TSmallArrayVector&); 203 allocTSmallArrayVector204 void alloc() 205 { 206 if (sizes == nullptr) 207 sizes = new TVector<TArraySize>; 208 } deallocTSmallArrayVector209 void dealloc() 210 { 211 delete sizes; 212 sizes = nullptr; 213 } 214 215 TVector<TArraySize>* sizes; // will either hold such a pointer, or in the future, hold the two array sizes 216 }; 217 218 // 219 // Represent an array, or array of arrays, to arbitrary depth. This is not 220 // done through a hierarchy of types in a type tree, rather all contiguous arrayness 221 // in the type hierarchy is localized into this single cumulative object. 222 // 223 // The arrayness in TTtype is a pointer, so that it can be non-allocated and zero 224 // for the vast majority of types that are non-array types. 225 // 226 // Order Policy: these are all identical: 227 // - left to right order within a contiguous set of ...[..][..][..]... in the source language 228 // - index order 0, 1, 2, ... within the 'sizes' member below 229 // - outer-most to inner-most 230 // 231 struct TArraySizes { 232 POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) 233 TArraySizesTArraySizes234 TArraySizes() : implicitArraySize(0), implicitlySized(true), variablyIndexed(false){ } 235 236 // For breaking into two non-shared copies, independently modifiable. 237 TArraySizes& operator=(const TArraySizes& from) 238 { 239 implicitArraySize = from.implicitArraySize; 240 variablyIndexed = from.variablyIndexed; 241 sizes = from.sizes; 242 implicitlySized = from.implicitlySized; 243 244 return *this; 245 } 246 247 // translate from array-of-array semantics to container semantics getNumDimsTArraySizes248 int getNumDims() const { return sizes.size(); } getDimSizeTArraySizes249 int getDimSize(int dim) const { return sizes.getDimSize(dim); } getDimNodeTArraySizes250 TIntermTyped* getDimNode(int dim) const { return sizes.getDimNode(dim); } setDimSizeTArraySizes251 void setDimSize(int dim, int size) { sizes.setDimSize(dim, size); } getOuterSizeTArraySizes252 int getOuterSize() const { return sizes.frontSize(); } getOuterNodeTArraySizes253 TIntermTyped* getOuterNode() const { return sizes.frontNode(); } getCumulativeSizeTArraySizes254 int getCumulativeSize() const 255 { 256 int size = 1; 257 for (int d = 0; d < sizes.size(); ++d) { 258 // this only makes sense in paths that have a known array size 259 assert(sizes.getDimSize(d) != UnsizedArraySize); 260 size *= sizes.getDimSize(d); 261 } 262 return size; 263 } addInnerSizeTArraySizes264 void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); } addInnerSizeTArraySizes265 void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); } addInnerSizeTArraySizes266 void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); } addInnerSizeTArraySizes267 void addInnerSize(TArraySize pair) { 268 sizes.push_back(pair.size, pair.node); 269 implicitlySized = false; 270 } addInnerSizesTArraySizes271 void addInnerSizes(const TArraySizes& s) { sizes.push_back(s.sizes); } changeOuterSizeTArraySizes272 void changeOuterSize(int s) { 273 sizes.changeFront((unsigned)s); 274 implicitlySized = false; 275 } getImplicitSizeTArraySizes276 int getImplicitSize() const { return implicitArraySize > 0 ? implicitArraySize : 1; } updateImplicitSizeTArraySizes277 void updateImplicitSize(int s) { 278 implicitArraySize = (std::max)(implicitArraySize, s); 279 } isInnerUnsizedTArraySizes280 bool isInnerUnsized() const 281 { 282 for (int d = 1; d < sizes.size(); ++d) { 283 if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize) 284 return true; 285 } 286 287 return false; 288 } clearInnerUnsizedTArraySizes289 bool clearInnerUnsized() 290 { 291 for (int d = 1; d < sizes.size(); ++d) { 292 if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize) 293 setDimSize(d, 1); 294 } 295 296 return false; 297 } isInnerSpecializationTArraySizes298 bool isInnerSpecialization() const 299 { 300 for (int d = 1; d < sizes.size(); ++d) { 301 if (sizes.getDimNode(d) != nullptr) 302 return true; 303 } 304 305 return false; 306 } isOuterSpecializationTArraySizes307 bool isOuterSpecialization() 308 { 309 return sizes.getDimNode(0) != nullptr; 310 } 311 hasUnsizedTArraySizes312 bool hasUnsized() const { return getOuterSize() == UnsizedArraySize || isInnerUnsized(); } isSizedTArraySizes313 bool isSized() const { return getOuterSize() != UnsizedArraySize; } isImplicitlySizedTArraySizes314 bool isImplicitlySized() const { return implicitlySized; } isDefaultImplicitlySizedTArraySizes315 bool isDefaultImplicitlySized() const { return implicitlySized && implicitArraySize == 0; } setImplicitlySizedTArraySizes316 void setImplicitlySized(bool isImplicitSizing) { implicitlySized = isImplicitSizing; } dereferenceTArraySizes317 void dereference() { sizes.pop_front(); } removeLastSizeTArraySizes318 void removeLastSize() { sizes.pop_back(); } copyDereferencedTArraySizes319 void copyDereferenced(const TArraySizes& rhs) 320 { 321 assert(sizes.size() == 0); 322 if (rhs.sizes.size() > 1) 323 sizes.copyNonFront(rhs.sizes); 324 } 325 sameInnerArraynessTArraySizes326 bool sameInnerArrayness(const TArraySizes& rhs) const 327 { 328 if (sizes.size() != rhs.sizes.size()) 329 return false; 330 331 for (int d = 1; d < sizes.size(); ++d) { 332 if (sizes.getDimSize(d) != rhs.sizes.getDimSize(d) || 333 sizes.getDimNode(d) != rhs.sizes.getDimNode(d)) 334 return false; 335 } 336 337 return true; 338 } 339 setVariablyIndexedTArraySizes340 void setVariablyIndexed() { variablyIndexed = true; } isVariablyIndexedTArraySizes341 bool isVariablyIndexed() const { return variablyIndexed; } 342 343 bool operator==(const TArraySizes& rhs) const { return sizes == rhs.sizes; } 344 bool operator!=(const TArraySizes& rhs) const { return sizes != rhs.sizes; } 345 346 protected: 347 TSmallArrayVector sizes; 348 349 TArraySizes(const TArraySizes&); 350 351 // For tracking maximum referenced compile-time constant index. 352 // Applies only to the outer-most dimension. Potentially becomes 353 // the implicit size of the array, if not variably indexed and 354 // otherwise legal. 355 int implicitArraySize; 356 bool implicitlySized; 357 bool variablyIndexed; // true if array is indexed with a non compile-time constant 358 }; 359 360 } // end namespace glslang 361 362 #endif // _ARRAYS_INCLUDED_ 363