342 lines
11 KiB
C++
342 lines
11 KiB
C++
//
|
|
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
|
// Copyright (C) 2012-2013 LunarG, Inc.
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
//
|
|
// Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following
|
|
// disclaimer in the documentation and/or other materials provided
|
|
// with the distribution.
|
|
//
|
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
|
// contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
|
|
//
|
|
// Implement types for tracking GLSL arrays, arrays of arrays, etc.
|
|
//
|
|
|
|
#ifndef _ARRAYS_INCLUDED
|
|
#define _ARRAYS_INCLUDED
|
|
|
|
#include <algorithm>
|
|
|
|
namespace glslang {
|
|
|
|
// This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else.
|
|
const int UnsizedArraySize = 0;
|
|
|
|
class TIntermTyped;
|
|
extern bool SameSpecializationConstants(TIntermTyped*, TIntermTyped*);
|
|
|
|
// Specialization constants need both a nominal size and a node that defines
|
|
// the specialization constant being used. Array types are the same when their
|
|
// size and specialization constant nodes are the same.
|
|
struct TArraySize {
|
|
unsigned int size;
|
|
TIntermTyped* node; // nullptr means no specialization constant node
|
|
bool operator==(const TArraySize& rhs) const
|
|
{
|
|
if (size != rhs.size)
|
|
return false;
|
|
if (node == nullptr || rhs.node == nullptr)
|
|
return node == rhs.node;
|
|
|
|
return SameSpecializationConstants(node, rhs.node);
|
|
}
|
|
};
|
|
|
|
//
|
|
// TSmallArrayVector is used as the container for the set of sizes in TArraySizes.
|
|
// It has generic-container semantics, while TArraySizes has array-of-array semantics.
|
|
// That is, TSmallArrayVector should be more focused on mechanism and TArraySizes on policy.
|
|
//
|
|
struct TSmallArrayVector {
|
|
//
|
|
// TODO: memory: TSmallArrayVector is intended to be smaller.
|
|
// Almost all arrays could be handled by two sizes each fitting
|
|
// in 16 bits, needing a real vector only in the cases where there
|
|
// are more than 3 sizes or a size needing more than 16 bits.
|
|
//
|
|
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
|
|
|
TSmallArrayVector() : sizes(nullptr) { }
|
|
virtual ~TSmallArrayVector() { dealloc(); }
|
|
|
|
// For breaking into two non-shared copies, independently modifiable.
|
|
TSmallArrayVector& operator=(const TSmallArrayVector& from)
|
|
{
|
|
if (from.sizes == nullptr)
|
|
sizes = nullptr;
|
|
else {
|
|
alloc();
|
|
*sizes = *from.sizes;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
int size() const
|
|
{
|
|
if (sizes == nullptr)
|
|
return 0;
|
|
return (int)sizes->size();
|
|
}
|
|
|
|
unsigned int frontSize() const
|
|
{
|
|
assert(sizes != nullptr && sizes->size() > 0);
|
|
return sizes->front().size;
|
|
}
|
|
|
|
TIntermTyped* frontNode() const
|
|
{
|
|
assert(sizes != nullptr && sizes->size() > 0);
|
|
return sizes->front().node;
|
|
}
|
|
|
|
void changeFront(unsigned int s)
|
|
{
|
|
assert(sizes != nullptr);
|
|
// this should only happen for implicitly sized arrays, not specialization constants
|
|
assert(sizes->front().node == nullptr);
|
|
sizes->front().size = s;
|
|
}
|
|
|
|
void push_back(unsigned int e, TIntermTyped* n)
|
|
{
|
|
alloc();
|
|
TArraySize pair = { e, n };
|
|
sizes->push_back(pair);
|
|
}
|
|
|
|
void push_back(const TSmallArrayVector& newDims)
|
|
{
|
|
alloc();
|
|
sizes->insert(sizes->end(), newDims.sizes->begin(), newDims.sizes->end());
|
|
}
|
|
|
|
void pop_front()
|
|
{
|
|
assert(sizes != nullptr && sizes->size() > 0);
|
|
if (sizes->size() == 1)
|
|
dealloc();
|
|
else
|
|
sizes->erase(sizes->begin());
|
|
}
|
|
|
|
// 'this' should currently not be holding anything, and copyNonFront
|
|
// will make it hold a copy of all but the first element of rhs.
|
|
// (This would be useful for making a type that is dereferenced by
|
|
// one dimension.)
|
|
void copyNonFront(const TSmallArrayVector& rhs)
|
|
{
|
|
assert(sizes == nullptr);
|
|
if (rhs.size() > 1) {
|
|
alloc();
|
|
sizes->insert(sizes->begin(), rhs.sizes->begin() + 1, rhs.sizes->end());
|
|
}
|
|
}
|
|
|
|
unsigned int getDimSize(int i) const
|
|
{
|
|
assert(sizes != nullptr && (int)sizes->size() > i);
|
|
return (*sizes)[i].size;
|
|
}
|
|
|
|
void setDimSize(int i, unsigned int size) const
|
|
{
|
|
assert(sizes != nullptr && (int)sizes->size() > i);
|
|
assert((*sizes)[i].node == nullptr);
|
|
(*sizes)[i].size = size;
|
|
}
|
|
|
|
TIntermTyped* getDimNode(int i) const
|
|
{
|
|
assert(sizes != nullptr && (int)sizes->size() > i);
|
|
return (*sizes)[i].node;
|
|
}
|
|
|
|
bool operator==(const TSmallArrayVector& rhs) const
|
|
{
|
|
if (sizes == nullptr && rhs.sizes == nullptr)
|
|
return true;
|
|
if (sizes == nullptr || rhs.sizes == nullptr)
|
|
return false;
|
|
return *sizes == *rhs.sizes;
|
|
}
|
|
bool operator!=(const TSmallArrayVector& rhs) const { return ! operator==(rhs); }
|
|
|
|
protected:
|
|
TSmallArrayVector(const TSmallArrayVector&);
|
|
|
|
void alloc()
|
|
{
|
|
if (sizes == nullptr)
|
|
sizes = new TVector<TArraySize>;
|
|
}
|
|
void dealloc()
|
|
{
|
|
delete sizes;
|
|
sizes = nullptr;
|
|
}
|
|
|
|
TVector<TArraySize>* sizes; // will either hold such a pointer, or in the future, hold the two array sizes
|
|
};
|
|
|
|
//
|
|
// Represent an array, or array of arrays, to arbitrary depth. This is not
|
|
// done through a hierarchy of types in a type tree, rather all contiguous arrayness
|
|
// in the type hierarchy is localized into this single cumulative object.
|
|
//
|
|
// The arrayness in TTtype is a pointer, so that it can be non-allocated and zero
|
|
// for the vast majority of types that are non-array types.
|
|
//
|
|
// Order Policy: these are all identical:
|
|
// - left to right order within a contiguous set of ...[..][..][..]... in the source language
|
|
// - index order 0, 1, 2, ... within the 'sizes' member below
|
|
// - outer-most to inner-most
|
|
//
|
|
struct TArraySizes {
|
|
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
|
|
|
TArraySizes() : implicitArraySize(1), variablyIndexed(false) { }
|
|
|
|
// For breaking into two non-shared copies, independently modifiable.
|
|
TArraySizes& operator=(const TArraySizes& from)
|
|
{
|
|
implicitArraySize = from.implicitArraySize;
|
|
variablyIndexed = from.variablyIndexed;
|
|
sizes = from.sizes;
|
|
|
|
return *this;
|
|
}
|
|
|
|
// translate from array-of-array semantics to container semantics
|
|
int getNumDims() const { return sizes.size(); }
|
|
int getDimSize(int dim) const { return sizes.getDimSize(dim); }
|
|
TIntermTyped* getDimNode(int dim) const { return sizes.getDimNode(dim); }
|
|
void setDimSize(int dim, int size) { sizes.setDimSize(dim, size); }
|
|
int getOuterSize() const { return sizes.frontSize(); }
|
|
TIntermTyped* getOuterNode() const { return sizes.frontNode(); }
|
|
int getCumulativeSize() const
|
|
{
|
|
int size = 1;
|
|
for (int d = 0; d < sizes.size(); ++d) {
|
|
// this only makes sense in paths that have a known array size
|
|
assert(sizes.getDimSize(d) != UnsizedArraySize);
|
|
size *= sizes.getDimSize(d);
|
|
}
|
|
return size;
|
|
}
|
|
void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); }
|
|
void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); }
|
|
void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); }
|
|
void addInnerSize(TArraySize pair) {
|
|
sizes.push_back(pair.size, pair.node);
|
|
}
|
|
void addInnerSizes(const TArraySizes& s) { sizes.push_back(s.sizes); }
|
|
void changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
|
|
int getImplicitSize() const { return implicitArraySize; }
|
|
void updateImplicitSize(int s) { implicitArraySize = std::max(implicitArraySize, s); }
|
|
bool isInnerUnsized() const
|
|
{
|
|
for (int d = 1; d < sizes.size(); ++d) {
|
|
if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
bool clearInnerUnsized()
|
|
{
|
|
for (int d = 1; d < sizes.size(); ++d) {
|
|
if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize)
|
|
setDimSize(d, 1);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
bool isInnerSpecialization() const
|
|
{
|
|
for (int d = 1; d < sizes.size(); ++d) {
|
|
if (sizes.getDimNode(d) != nullptr)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
bool isOuterSpecialization()
|
|
{
|
|
return sizes.getDimNode(0) != nullptr;
|
|
}
|
|
|
|
bool hasUnsized() const { return getOuterSize() == UnsizedArraySize || isInnerUnsized(); }
|
|
bool isSized() const { return getOuterSize() != UnsizedArraySize; }
|
|
void dereference() { sizes.pop_front(); }
|
|
void copyDereferenced(const TArraySizes& rhs)
|
|
{
|
|
assert(sizes.size() == 0);
|
|
if (rhs.sizes.size() > 1)
|
|
sizes.copyNonFront(rhs.sizes);
|
|
}
|
|
|
|
bool sameInnerArrayness(const TArraySizes& rhs) const
|
|
{
|
|
if (sizes.size() != rhs.sizes.size())
|
|
return false;
|
|
|
|
for (int d = 1; d < sizes.size(); ++d) {
|
|
if (sizes.getDimSize(d) != rhs.sizes.getDimSize(d) ||
|
|
sizes.getDimNode(d) != rhs.sizes.getDimNode(d))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void setVariablyIndexed() { variablyIndexed = true; }
|
|
bool isVariablyIndexed() const { return variablyIndexed; }
|
|
|
|
bool operator==(const TArraySizes& rhs) const { return sizes == rhs.sizes; }
|
|
bool operator!=(const TArraySizes& rhs) const { return sizes != rhs.sizes; }
|
|
|
|
protected:
|
|
TSmallArrayVector sizes;
|
|
|
|
TArraySizes(const TArraySizes&);
|
|
|
|
// For tracking maximum referenced compile-time constant index.
|
|
// Applies only to the outer-most dimension. Potentially becomes
|
|
// the implicit size of the array, if not variably indexed and
|
|
// otherwise legal.
|
|
int implicitArraySize;
|
|
bool variablyIndexed; // true if array is indexed with a non compile-time constant
|
|
};
|
|
|
|
} // end namespace glslang
|
|
|
|
#endif // _ARRAYS_INCLUDED_
|