Commit 86d9c93a by Shahbaz Youssefi Committed by Commit Bot

Use TSpan for TType's array sizes

Until C++20, std::vector doesn't have a constexpr constructor, which means TType cannot use a `TVector` for `mArraySizes` if an arrayed type needs to be created constexpr. This is needed for the upcoming textureGatherOffsets implementation. A new TSpan class is introduced, based on std::span (from C++20) that holds the pointer/size allocated from a TVector without owning it. Since TVector's allocation are made from a pool, the allocated memory will live beyond the vector's destruction. `TType::mArraySizes` is changed to this type. This change will allow a new constexpr constructor to be added to TType that takes a TSpan as array directly, a value which is constexpr initialized from a static array (instead of TVector). Bug: angleproject:3569 Change-Id: I78793b0f4c64519e0ebe30cf6e0de995ba70035d Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1968260Reviewed-by: 's avatarJiajia Qin <jiajia.qin@intel.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent c713abfd
...@@ -653,9 +653,10 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type, ...@@ -653,9 +653,10 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
variableOut->fields.push_back(fieldVariable); variableOut->fields.push_back(fieldVariable);
} }
} }
if (auto *arraySizes = type.getArraySizes()) const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
if (!arraySizes.empty())
{ {
variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end()); variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end());
} }
} }
......
...@@ -108,6 +108,105 @@ class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D>>> ...@@ -108,6 +108,105 @@ class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D>>>
{} {}
}; };
// Basic implementation of C++20's span for use with pool-allocated containers (TVector) or static
// arrays. This is used by the array sizes member of TType to allow arrayed types to be
// constexpr-constructed.
// See the reference for std::span here: https://en.cppreference.com/w/cpp/container/span
template <typename T>
class TSpan
{
public:
typedef size_t size_type;
constexpr TSpan() {}
constexpr TSpan(T *ptr, size_type size) : mData(ptr), mSize(size) {}
constexpr TSpan(const TSpan &that) : mData(that.mData), mSize(that.mSize) {}
constexpr TSpan &operator=(const TSpan &that)
{
mData = that.mData;
mSize = that.mSize;
return *this;
}
// Note: the pointer is taken out of the TVector because TVector's memory is pool allocated,
// so the memory will live on even if the TVector is destroyed.
template <typename S>
TSpan(const TVector<S> &vec) : mData(vec.data()), mSize(vec.size())
{}
template <typename S>
TSpan &operator=(const TVector<S> &vec)
{
mData = vec.data();
mSize = vec.size();
return *this;
}
constexpr bool operator==(const TSpan &that) const
{
if (mSize != that.mSize)
{
return false;
}
if (mData == that.mData)
{
return true;
}
for (size_type index = 0; index < mSize; ++index)
{
if (mData[index] != that.mData[index])
{
return false;
}
}
return true;
}
constexpr bool operator!=(const TSpan &that) const { return !(*this == that); }
constexpr T *data() const { return mData; }
constexpr size_type size() const { return mSize; }
constexpr bool empty() const { return mSize == 0; }
constexpr T &operator[](size_type index) const { return mData[index]; }
constexpr T &front() const { return mData[0]; }
constexpr T &back() const { return mData[mSize - 1]; }
constexpr T *begin() const { return mData; }
constexpr T *end() const { return mData + mSize; }
constexpr std::reverse_iterator<T *> rbegin() const
{
return std::make_reverse_iterator(end());
}
constexpr std::reverse_iterator<T *> rend() const
{
return std::make_reverse_iterator(begin());
}
constexpr TSpan first(size_type count) const
{
ASSERT(count <= mSize);
return count == 0 ? TSpan() : TSpan(mData, count);
}
constexpr TSpan last(size_type count) const
{
ASSERT(count <= mSize);
return count == 0 ? TSpan() : TSpan(mData + mSize - count, count);
}
constexpr TSpan subspan(size_type offset, size_type count) const
{
ASSERT(offset + count <= mSize);
return count == 0 ? TSpan() : TSpan(mData + offset, count);
}
private:
T *mData = nullptr;
size_t mSize = 0;
};
// Integer to TString conversion // Integer to TString conversion
template <typename T> template <typename T>
inline TString str(T i) inline TString str(T i)
......
...@@ -73,8 +73,8 @@ TInfoSinkBase &TInfoSinkBase::operator<<(const TType &type) ...@@ -73,8 +73,8 @@ TInfoSinkBase &TInfoSinkBase::operator<<(const TType &type)
if (type.isArray()) if (type.isArray())
{ {
for (auto arraySizeIter = type.getArraySizes()->rbegin(); for (auto arraySizeIter = type.getArraySizes().rbegin();
arraySizeIter != type.getArraySizes()->rend(); ++arraySizeIter) arraySizeIter != type.getArraySizes().rend(); ++arraySizeIter)
{ {
*this << "array[" << (*arraySizeIter) << "] of "; *this << "array[" << (*arraySizeIter) << "] of ";
} }
......
...@@ -43,7 +43,7 @@ TString ArrayHelperFunctionName(const char *prefix, const TType &type) ...@@ -43,7 +43,7 @@ TString ArrayHelperFunctionName(const char *prefix, const TType &type)
fnName << prefix << "_"; fnName << prefix << "_";
if (type.isArray()) if (type.isArray())
{ {
for (unsigned int arraySize : *type.getArraySizes()) for (unsigned int arraySize : type.getArraySizes())
{ {
fnName << arraySize << "_"; fnName << arraySize << "_";
} }
......
...@@ -1961,8 +1961,7 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, ...@@ -1961,8 +1961,7 @@ bool TParseContext::executeInitializer(const TSourceLoc &line,
// will default to setting array sizes to 1. We have not checked yet whether the initializer // will default to setting array sizes to 1. We have not checked yet whether the initializer
// actually is an array or not. Having a non-array initializer for an unsized array will // actually is an array or not. Having a non-array initializer for an unsized array will
// result in an error later, so we don't generate an error message here. // result in an error later, so we don't generate an error message here.
auto *arraySizes = initializer->getType().getArraySizes(); type->sizeUnsizedArrays(initializer->getType().getArraySizes());
type->sizeUnsizedArrays(arraySizes);
} }
const TQualifier qualifier = type->getQualifier(); const TQualifier qualifier = type->getQualifier();
...@@ -3531,7 +3530,7 @@ void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line, ...@@ -3531,7 +3530,7 @@ void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line,
if (arrayType->isUnsizedArray()) if (arrayType->isUnsizedArray())
{ {
error(line, errorMessage, token); error(line, errorMessage, token);
arrayType->sizeUnsizedArrays(nullptr); arrayType->sizeUnsizedArrays(TSpan<const unsigned int>());
} }
} }
...@@ -3623,7 +3622,7 @@ TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSour ...@@ -3623,7 +3622,7 @@ TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSour
{ {
if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line)) if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line))
{ {
type.sizeUnsizedArrays(nullptr); type.sizeUnsizedArrays(TSpan<const unsigned int>());
return CreateZeroNode(type); return CreateZeroNode(type);
} }
TIntermTyped *firstElement = arguments.at(0)->getAsTyped(); TIntermTyped *firstElement = arguments.at(0)->getAsTyped();
...@@ -3634,9 +3633,9 @@ TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSour ...@@ -3634,9 +3633,9 @@ TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSour
} }
for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i) for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i)
{ {
if ((*type.getArraySizes())[i] == 0u) if (type.getArraySizes()[i] == 0u)
{ {
type.setArraySize(i, (*firstElement->getType().getArraySizes())[i]); type.setArraySize(i, firstElement->getType().getArraySizes()[i]);
} }
} }
ASSERT(!type.isUnsizedArray()); ASSERT(!type.isUnsizedArray());
...@@ -5227,7 +5226,7 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, ...@@ -5227,7 +5226,7 @@ bool TParseContext::binaryOpCommonCheck(TOperator op,
return false; return false;
} }
// At this point, size of implicitly sized arrays should be resolved. // At this point, size of implicitly sized arrays should be resolved.
if (*left->getType().getArraySizes() != *right->getType().getArraySizes()) if (left->getType().getArraySizes() != right->getType().getArraySizes())
{ {
error(loc, "array size mismatch", GetOperatorString(op)); error(loc, "array size mismatch", GetOperatorString(op));
return false; return false;
......
...@@ -111,10 +111,10 @@ const BlockMemberInfo GetBlockMemberInfoByType(const TType &type, ...@@ -111,10 +111,10 @@ const BlockMemberInfo GetBlockMemberInfoByType(const TType &type,
} }
std::vector<unsigned int> arraySizes; std::vector<unsigned int> arraySizes;
auto *typeArraySizes = type.getArraySizes(); const TSpan<const unsigned int> &typeArraySizes = type.getArraySizes();
if (typeArraySizes != nullptr) if (!typeArraySizes.empty())
{ {
arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end()); arraySizes.assign(typeArraySizes.begin(), typeArraySizes.end());
} }
return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor); return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
} }
...@@ -677,7 +677,7 @@ void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSink ...@@ -677,7 +677,7 @@ void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSink
{ {
if (type.isArrayOfArrays()) if (type.isArrayOfArrays())
{ {
const TVector<unsigned int> &arraySizes = *type.getArraySizes(); const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
// Don't need to concern the tail comma which will be used to multiply the index. // Don't need to concern the tail comma which will be used to multiply the index.
for (unsigned int i = 0; i < (arraySizes.size() - 1); i++) for (unsigned int i = 0; i < (arraySizes.size() - 1); i++)
{ {
......
...@@ -143,7 +143,7 @@ TType::TType(const TPublicType &p) ...@@ -143,7 +143,7 @@ TType::TType(const TPublicType &p)
layoutQualifier(p.layoutQualifier), layoutQualifier(p.layoutQualifier),
primarySize(p.getPrimarySize()), primarySize(p.getPrimarySize()),
secondarySize(p.getSecondarySize()), secondarySize(p.getSecondarySize()),
mArraySizes(nullptr), mArraySizesStorage(nullptr),
mInterfaceBlock(nullptr), mInterfaceBlock(nullptr),
mStructure(nullptr), mStructure(nullptr),
mIsStructSpecifier(false), mIsStructSpecifier(false),
...@@ -153,7 +153,7 @@ TType::TType(const TPublicType &p) ...@@ -153,7 +153,7 @@ TType::TType(const TPublicType &p)
ASSERT(secondarySize <= 4); ASSERT(secondarySize <= 4);
if (p.isArray()) if (p.isArray())
{ {
mArraySizes = new TVector<unsigned int>(*p.arraySizes); makeArrays(*p.arraySizes);
} }
if (p.getUserDef()) if (p.getUserDef())
{ {
...@@ -194,11 +194,24 @@ TType &TType::operator=(const TType &t) ...@@ -194,11 +194,24 @@ TType &TType::operator=(const TType &t)
layoutQualifier = t.layoutQualifier; layoutQualifier = t.layoutQualifier;
primarySize = t.primarySize; primarySize = t.primarySize;
secondarySize = t.secondarySize; secondarySize = t.secondarySize;
mArraySizes = t.mArraySizes ? new TVector<unsigned int>(*t.mArraySizes) : nullptr; mArraySizesStorage = nullptr;
mInterfaceBlock = t.mInterfaceBlock; mInterfaceBlock = t.mInterfaceBlock;
mStructure = t.mStructure; mStructure = t.mStructure;
mIsStructSpecifier = t.mIsStructSpecifier; mIsStructSpecifier = t.mIsStructSpecifier;
mMangledName = t.mMangledName; mMangledName = t.mMangledName;
if (t.mArraySizesStorage)
{
// If other type has storage, duplicate the storage and set the view to our own storage.
mArraySizesStorage = new TVector<unsigned int>(*t.mArraySizesStorage);
mArraySizes = *mArraySizesStorage;
}
else
{
// Otherwise reference the same (constexpr) array sizes as the other type.
mArraySizes = t.mArraySizes;
}
return *this; return *this;
} }
...@@ -425,16 +438,13 @@ const char *TType::buildMangledName() const ...@@ -425,16 +438,13 @@ const char *TType::buildMangledName() const
} }
} }
if (mArraySizes) for (unsigned int arraySize : mArraySizes)
{ {
for (unsigned int arraySize : *mArraySizes) char buf[20];
{ snprintf(buf, sizeof(buf), "%d", arraySize);
char buf[20]; mangledName += '[';
snprintf(buf, sizeof(buf), "%d", arraySize); mangledName += buf;
mangledName += '['; mangledName += ']';
mangledName += buf;
mangledName += ']';
}
} }
// Copy string contents into a pool-allocated buffer, so we never need to call delete. // Copy string contents into a pool-allocated buffer, so we never need to call delete.
...@@ -453,15 +463,12 @@ size_t TType::getObjectSize() const ...@@ -453,15 +463,12 @@ size_t TType::getObjectSize() const
if (totalSize == 0) if (totalSize == 0)
return 0; return 0;
if (mArraySizes) for (size_t arraySize : mArraySizes)
{ {
for (size_t arraySize : *mArraySizes) if (arraySize > INT_MAX / totalSize)
{ totalSize = INT_MAX;
if (arraySize > INT_MAX / totalSize) else
totalSize = INT_MAX; totalSize *= arraySize;
else
totalSize *= arraySize;
}
} }
return totalSize; return totalSize;
...@@ -481,18 +488,15 @@ int TType::getLocationCount() const ...@@ -481,18 +488,15 @@ int TType::getLocationCount() const
return 0; return 0;
} }
if (mArraySizes) for (unsigned int arraySize : mArraySizes)
{ {
for (unsigned int arraySize : *mArraySizes) if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count))
{ {
if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count)) count = std::numeric_limits<int>::max();
{ }
count = std::numeric_limits<int>::max(); else
} {
else count *= static_cast<int>(arraySize);
{
count *= static_cast<int>(arraySize);
}
} }
} }
...@@ -501,12 +505,9 @@ int TType::getLocationCount() const ...@@ -501,12 +505,9 @@ int TType::getLocationCount() const
unsigned int TType::getArraySizeProduct() const unsigned int TType::getArraySizeProduct() const
{ {
if (!mArraySizes)
return 1u;
unsigned int product = 1u; unsigned int product = 1u;
for (unsigned int arraySize : *mArraySizes) for (unsigned int arraySize : mArraySizes)
{ {
product *= arraySize; product *= arraySize;
} }
...@@ -515,10 +516,7 @@ unsigned int TType::getArraySizeProduct() const ...@@ -515,10 +516,7 @@ unsigned int TType::getArraySizeProduct() const
bool TType::isUnsizedArray() const bool TType::isUnsizedArray() const
{ {
if (!mArraySizes) for (unsigned int arraySize : mArraySizes)
return false;
for (unsigned int arraySize : *mArraySizes)
{ {
if (arraySize == 0u) if (arraySize == 0u)
{ {
...@@ -544,34 +542,30 @@ bool TType::isElementTypeOf(const TType &arrayType) const ...@@ -544,34 +542,30 @@ bool TType::isElementTypeOf(const TType &arrayType) const
{ {
return false; return false;
} }
if (isArray()) for (size_t i = 0; i < mArraySizes.size(); ++i)
{ {
for (size_t i = 0; i < mArraySizes->size(); ++i) if (mArraySizes[i] != arrayType.mArraySizes[i])
{ {
if ((*mArraySizes)[i] != (*arrayType.mArraySizes)[i]) return false;
{
return false;
}
} }
} }
return true; return true;
} }
void TType::sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes) void TType::sizeUnsizedArrays(const TSpan<const unsigned int> &newArraySizes)
{ {
size_t newArraySizesSize = newArraySizes ? newArraySizes->size() : 0; ASSERT(!isArray() || mArraySizesStorage != nullptr);
for (size_t i = 0u; i < getNumArraySizes(); ++i) for (size_t i = 0u; i < getNumArraySizes(); ++i)
{ {
if ((*mArraySizes)[i] == 0) if (mArraySizes[i] == 0)
{ {
if (i < newArraySizesSize) if (i < newArraySizes.size())
{ {
ASSERT(newArraySizes != nullptr); (*mArraySizesStorage)[i] = newArraySizes[i];
(*mArraySizes)[i] = (*newArraySizes)[i];
} }
else else
{ {
(*mArraySizes)[i] = 1u; (*mArraySizesStorage)[i] = 1u;
} }
} }
} }
...@@ -580,9 +574,9 @@ void TType::sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes) ...@@ -580,9 +574,9 @@ void TType::sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes)
void TType::sizeOutermostUnsizedArray(unsigned int arraySize) void TType::sizeOutermostUnsizedArray(unsigned int arraySize)
{ {
ASSERT(isArray()); ASSERT(isArray() && mArraySizesStorage != nullptr);
ASSERT(mArraySizes->back() == 0u); ASSERT((*mArraySizesStorage).back() == 0u);
mArraySizes->back() = arraySize; (*mArraySizesStorage).back() = arraySize;
} }
void TType::setBasicType(TBasicType t) void TType::setBasicType(TBasicType t)
...@@ -616,54 +610,61 @@ void TType::setSecondarySize(unsigned char ss) ...@@ -616,54 +610,61 @@ void TType::setSecondarySize(unsigned char ss)
void TType::makeArray(unsigned int s) void TType::makeArray(unsigned int s)
{ {
if (!mArraySizes) if (mArraySizesStorage == nullptr)
mArraySizes = new TVector<unsigned int>(); {
mArraySizesStorage = new TVector<unsigned int>();
mArraySizes->push_back(s); }
invalidateMangledName(); // Add a dimension to the current ones.
mArraySizesStorage->push_back(s);
onArrayDimensionsChange(*mArraySizesStorage);
} }
void TType::makeArrays(const TVector<unsigned int> &sizes) void TType::makeArrays(const TSpan<const unsigned int> &sizes)
{ {
if (!mArraySizes) if (mArraySizesStorage == nullptr)
mArraySizes = new TVector<unsigned int>(); {
mArraySizesStorage = new TVector<unsigned int>();
}
// Add dimensions to the current ones.
mArraySizesStorage->insert(mArraySizesStorage->end(), sizes.begin(), sizes.end());
onArrayDimensionsChange(*mArraySizesStorage);
}
mArraySizes->insert(mArraySizes->end(), sizes.begin(), sizes.end()); void TType::onArrayDimensionsChange(const TSpan<const unsigned int> &sizes)
{
mArraySizes = sizes;
invalidateMangledName(); invalidateMangledName();
} }
void TType::setArraySize(size_t arrayDimension, unsigned int s) void TType::setArraySize(size_t arrayDimension, unsigned int s)
{ {
ASSERT(mArraySizes != nullptr); ASSERT(isArray() && mArraySizesStorage != nullptr);
ASSERT(arrayDimension < mArraySizes->size()); ASSERT(arrayDimension < mArraySizesStorage->size());
if (mArraySizes->at(arrayDimension) != s) if (mArraySizes[arrayDimension] != s)
{ {
(*mArraySizes)[arrayDimension] = s; (*mArraySizesStorage)[arrayDimension] = s;
invalidateMangledName(); invalidateMangledName();
} }
} }
void TType::toArrayElementType() void TType::toArrayElementType()
{ {
ASSERT(mArraySizes != nullptr); ASSERT(isArray() && mArraySizesStorage != nullptr);
if (mArraySizes->size() > 0) mArraySizesStorage->pop_back();
{ onArrayDimensionsChange(*mArraySizesStorage);
mArraySizes->pop_back();
invalidateMangledName();
}
} }
void TType::toArrayBaseType() void TType::toArrayBaseType()
{ {
if (mArraySizes == nullptr) if (!isArray())
{ {
return; return;
} }
if (mArraySizes->size() > 0) if (mArraySizesStorage)
{ {
mArraySizes->clear(); mArraySizesStorage->clear();
} }
invalidateMangledName(); onArrayDimensionsChange(TSpan<const unsigned int>());
} }
void TType::setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn) void TType::setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn)
......
...@@ -122,7 +122,7 @@ class TType ...@@ -122,7 +122,7 @@ class TType
layoutQualifier(TLayoutQualifier::Create()), layoutQualifier(TLayoutQualifier::Create()),
primarySize(ps), primarySize(ps),
secondarySize(ss), secondarySize(ss),
mArraySizes(nullptr), mArraySizesStorage(nullptr),
mInterfaceBlock(nullptr), mInterfaceBlock(nullptr),
mStructure(nullptr), mStructure(nullptr),
mIsStructSpecifier(false), mIsStructSpecifier(false),
...@@ -140,11 +140,14 @@ class TType ...@@ -140,11 +140,14 @@ class TType
primarySize(t.primarySize), primarySize(t.primarySize),
secondarySize(t.secondarySize), secondarySize(t.secondarySize),
mArraySizes(t.mArraySizes), mArraySizes(t.mArraySizes),
mArraySizesStorage(t.mArraySizesStorage),
mInterfaceBlock(t.mInterfaceBlock), mInterfaceBlock(t.mInterfaceBlock),
mStructure(t.mStructure), mStructure(t.mStructure),
mIsStructSpecifier(t.mIsStructSpecifier), mIsStructSpecifier(t.mIsStructSpecifier),
mMangledName(t.mMangledName) mMangledName(t.mMangledName)
{} {
t.mArraySizesStorage = nullptr;
}
constexpr TBasicType getBasicType() const { return type; } constexpr TBasicType getBasicType() const { return type; }
void setBasicType(TBasicType t); void setBasicType(TBasicType t);
...@@ -190,28 +193,28 @@ class TType ...@@ -190,28 +193,28 @@ class TType
bool isMatrix() const { return primarySize > 1 && secondarySize > 1; } bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; } bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; }
bool isArray() const { return mArraySizes != nullptr && !mArraySizes->empty(); } bool isArray() const { return !mArraySizes.empty(); }
bool isArrayOfArrays() const { return isArray() && mArraySizes->size() > 1u; } bool isArrayOfArrays() const { return mArraySizes.size() > 1u; }
size_t getNumArraySizes() const { return isArray() ? mArraySizes->size() : 0; } size_t getNumArraySizes() const { return mArraySizes.size(); }
const TVector<unsigned int> *getArraySizes() const { return mArraySizes; } const TSpan<const unsigned int> &getArraySizes() const { return mArraySizes; }
unsigned int getArraySizeProduct() const; unsigned int getArraySizeProduct() const;
bool isUnsizedArray() const; bool isUnsizedArray() const;
unsigned int getOutermostArraySize() const unsigned int getOutermostArraySize() const
{ {
ASSERT(isArray()); ASSERT(isArray());
return mArraySizes->back(); return mArraySizes.back();
} }
void makeArray(unsigned int s); void makeArray(unsigned int s);
// sizes contain new outermost array sizes. // sizes contain new outermost array sizes.
void makeArrays(const TVector<unsigned int> &sizes); void makeArrays(const TSpan<const unsigned int> &sizes);
// Here, the array dimension value 0 corresponds to the innermost array. // Here, the array dimension value 0 corresponds to the innermost array.
void setArraySize(size_t arrayDimension, unsigned int s); void setArraySize(size_t arrayDimension, unsigned int s);
// Will set unsized array sizes according to newArraySizes. In case there are more // Will set unsized array sizes according to newArraySizes. In case there are more
// unsized arrays than there are sizes in newArraySizes, defaults to setting any // unsized arrays than there are sizes in newArraySizes, defaults to setting any
// remaining array sizes to 1. // remaining array sizes to 1.
void sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes); void sizeUnsizedArrays(const TSpan<const unsigned int> &newArraySizes);
// Will size the outermost array according to arraySize. // Will size the outermost array according to arraySize.
void sizeOutermostUnsizedArray(unsigned int arraySize); void sizeOutermostUnsizedArray(unsigned int arraySize);
...@@ -258,7 +261,7 @@ class TType ...@@ -258,7 +261,7 @@ class TType
size_t numArraySizesL = getNumArraySizes(); size_t numArraySizesL = getNumArraySizes();
size_t numArraySizesR = right.getNumArraySizes(); size_t numArraySizesR = right.getNumArraySizes();
bool arraySizesEqual = numArraySizesL == numArraySizesR && bool arraySizesEqual = numArraySizesL == numArraySizesR &&
(numArraySizesL == 0 || *mArraySizes == *right.mArraySizes); (numArraySizesL == 0 || mArraySizes == right.mArraySizes);
return type == right.type && primarySize == right.primarySize && return type == right.type && primarySize == right.primarySize &&
secondarySize == right.secondarySize && arraySizesEqual && secondarySize == right.secondarySize && arraySizesEqual &&
mStructure == right.mStructure; mStructure == right.mStructure;
...@@ -279,8 +282,8 @@ class TType ...@@ -279,8 +282,8 @@ class TType
return numArraySizesL < numArraySizesR; return numArraySizesL < numArraySizesR;
for (size_t i = 0; i < numArraySizesL; ++i) for (size_t i = 0; i < numArraySizesL; ++i)
{ {
if ((*mArraySizes)[i] != (*right.mArraySizes)[i]) if (mArraySizes[i] != right.mArraySizes[i])
return (*mArraySizes)[i] < (*right.mArraySizes)[i]; return mArraySizes[i] < right.mArraySizes[i];
} }
if (mStructure != right.mStructure) if (mStructure != right.mStructure)
return mStructure < right.mStructure; return mStructure < right.mStructure;
...@@ -342,12 +345,14 @@ class TType ...@@ -342,12 +345,14 @@ class TType
private: private:
void invalidateMangledName(); void invalidateMangledName();
const char *buildMangledName() const; const char *buildMangledName() const;
void onArrayDimensionsChange(const TSpan<const unsigned int> &sizes);
TBasicType type; TBasicType type;
TPrecision precision; TPrecision precision;
TQualifier qualifier; TQualifier qualifier;
bool invariant; bool invariant;
bool precise; bool precise;
TMemoryQualifier memoryQualifier; TMemoryQualifier memoryQualifier;
TLayoutQualifier layoutQualifier; TLayoutQualifier layoutQualifier;
unsigned char primarySize; // size of vector or cols matrix unsigned char primarySize; // size of vector or cols matrix
...@@ -355,7 +360,12 @@ class TType ...@@ -355,7 +360,12 @@ class TType
// Used to make an array type. Outermost array size is stored at the end of the vector. Having 0 // Used to make an array type. Outermost array size is stored at the end of the vector. Having 0
// in this vector means an unsized array. // in this vector means an unsized array.
TVector<unsigned int> *mArraySizes; TSpan<const unsigned int> mArraySizes;
// Storage for mArraySizes, if any. This is usually the case, except for constexpr TTypes which
// only have a valid mArraySizes (with mArraySizesStorage being nullptr). Therefore, all
// modifications to array sizes happen on the storage (and if dimensions change, mArraySizes is
// also updated) and all reads are from mArraySizes.
TVector<unsigned int> *mArraySizesStorage;
// This is set only in the following two cases: // This is set only in the following two cases:
// 1) Represents an interface block. // 1) Represents an interface block.
......
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// span_unittests.cpp: Unit tests for the TSpan class.
//
#include "Common.h"
#include <gtest/gtest.h>
using namespace angle;
namespace
{
using Span = sh::TSpan<const unsigned int>;
constexpr size_t kSpanDataSize = 16;
constexpr unsigned int kSpanData[kSpanDataSize] = {0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15};
// Test that comparing spans work
TEST(SpanTest, Comparison)
{
// Duplicate data to make sure comparison is being done on values (and not addresses).
constexpr unsigned int kSpanDataDup[kSpanDataSize] = {0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15};
// Don't use ASSERT_EQ at first because the == is more hidden
ASSERT_TRUE(Span() == Span(kSpanData, 0));
ASSERT_TRUE(Span(kSpanData + 3, 4) != Span(kSpanDataDup + 5, 4));
// Check ASSERT_EQ and ASSERT_NE work correctly
ASSERT_EQ(Span(kSpanData, kSpanDataSize), Span(kSpanDataDup, kSpanDataSize));
ASSERT_NE(Span(kSpanData, kSpanDataSize - 1), Span(kSpanDataDup + 1, kSpanDataSize - 1));
ASSERT_NE(Span(kSpanData, kSpanDataSize), Span(kSpanDataDup, kSpanDataSize - 1));
ASSERT_NE(Span(kSpanData, kSpanDataSize - 1), Span(kSpanDataDup, kSpanDataSize));
ASSERT_NE(Span(kSpanData, 0), Span(kSpanDataDup, 1));
ASSERT_NE(Span(kSpanData, 1), Span(kSpanDataDup, 0));
}
// Test indexing
TEST(SpanTest, Indexing)
{
constexpr Span sp(kSpanData, kSpanDataSize);
for (size_t i = 0; i < kSpanDataSize; ++i)
{
ASSERT_EQ(sp[i], i);
}
unsigned int storage[kSpanDataSize] = {};
sh::TSpan<unsigned int> writableSpan(storage, kSpanDataSize);
for (size_t i = 0; i < kSpanDataSize; ++i)
{
writableSpan[i] = i;
}
for (size_t i = 0; i < kSpanDataSize; ++i)
{
ASSERT_EQ(writableSpan[i], i);
}
for (size_t i = 0; i < kSpanDataSize; ++i)
{
ASSERT_EQ(storage[i], i);
}
}
// Test for the various constructors
TEST(SpanTest, Constructors)
{
// Default constructor
{
Span sp;
ASSERT_TRUE(sp.size() == 0);
ASSERT_TRUE(sp.empty());
}
// Constexpr construct from pointer
{
constexpr Span sp(kSpanData, kSpanDataSize);
ASSERT_EQ(sp.data(), kSpanData);
ASSERT_EQ(sp.size(), kSpanDataSize);
ASSERT_FALSE(sp.empty());
}
// Copy constructor and copy assignment
{
Span sp(kSpanData, kSpanDataSize);
Span sp2(sp);
Span sp3;
ASSERT_EQ(sp, sp2);
ASSERT_EQ(sp2.data(), kSpanData);
ASSERT_EQ(sp2.size(), kSpanDataSize);
ASSERT_FALSE(sp2.empty());
sp3 = sp;
ASSERT_EQ(sp, sp3);
ASSERT_EQ(sp3.data(), kSpanData);
ASSERT_EQ(sp3.size(), kSpanDataSize);
ASSERT_FALSE(sp3.empty());
}
}
// Test accessing the data directly
TEST(SpanTest, DataAccess)
{
constexpr Span sp(kSpanData, kSpanDataSize);
const unsigned int *data = sp.data();
for (size_t i = 0; i < kSpanDataSize; ++i)
{
ASSERT_EQ(data[i], i);
}
}
// Test front and back
TEST(SpanTest, FrontAndBack)
{
constexpr Span sp(kSpanData, kSpanDataSize);
ASSERT_TRUE(sp.front() == 0);
ASSERT_EQ(sp.back(), kSpanDataSize - 1);
}
// Test begin and end
TEST(SpanTest, BeginAndEnd)
{
constexpr Span sp(kSpanData, kSpanDataSize);
size_t currentIndex = 0;
for (unsigned int value : sp)
{
ASSERT_EQ(value, currentIndex);
++currentIndex;
}
}
// Test reverse begin and end
TEST(SpanTest, RbeginAndRend)
{
constexpr Span sp(kSpanData, kSpanDataSize);
size_t currentIndex = 0;
for (auto iter = sp.rbegin(); iter != sp.rend(); ++iter)
{
ASSERT_EQ(*iter, kSpanDataSize - 1 - currentIndex);
++currentIndex;
}
}
// Test first and last
TEST(SpanTest, FirstAndLast)
{
constexpr Span sp(kSpanData, kSpanDataSize);
constexpr size_t kSplitSize = kSpanDataSize / 4;
constexpr Span first = sp.first(kSplitSize);
constexpr Span last = sp.last(kSplitSize);
ASSERT_EQ(first, Span(kSpanData, kSplitSize));
ASSERT_EQ(first.data(), kSpanData);
ASSERT_EQ(first.size(), kSplitSize);
ASSERT_EQ(last, Span(kSpanData + kSpanDataSize - kSplitSize, kSplitSize));
ASSERT_EQ(last.data(), kSpanData + kSpanDataSize - kSplitSize);
ASSERT_EQ(last.size(), kSplitSize);
}
// Test subspan
TEST(SpanTest, Subspan)
{
constexpr Span sp(kSpanData, kSpanDataSize);
constexpr size_t kSplitOffset = kSpanDataSize / 4;
constexpr size_t kSplitSize = kSpanDataSize / 2;
constexpr Span subspan = sp.subspan(kSplitOffset, kSplitSize);
ASSERT_EQ(subspan, Span(kSpanData + kSplitOffset, kSplitSize));
ASSERT_EQ(subspan.data(), kSpanData + kSplitOffset);
ASSERT_EQ(subspan.size(), kSplitSize);
}
} // anonymous namespace
...@@ -513,18 +513,18 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser ...@@ -513,18 +513,18 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser
TIntermSymbol *argumentAsSymbol = symbol->getAsSymbolNode(); TIntermSymbol *argumentAsSymbol = symbol->getAsSymbolNode();
ASSERT(argumentAsSymbol); ASSERT(argumentAsSymbol);
const TVector<unsigned int> *arraySizes = argumentAsSymbol->getType().getArraySizes(); const TSpan<const unsigned int> &arraySizes = argumentAsSymbol->getType().getArraySizes();
// Calculate Pi // Calculate Pi
TVector<unsigned int> runningArraySizeProducts; TVector<unsigned int> runningArraySizeProducts;
if (arraySizes && arraySizes->size() > 0) if (!arraySizes.empty())
{ {
runningArraySizeProducts.resize(arraySizes->size()); runningArraySizeProducts.resize(arraySizes.size());
uint32_t runningProduct = 1; uint32_t runningProduct = 1;
for (size_t dimension = 0; dimension < arraySizes->size(); ++dimension) for (size_t dimension = 0; dimension < arraySizes.size(); ++dimension)
{ {
runningArraySizeProducts[dimension] = runningProduct; runningArraySizeProducts[dimension] = runningProduct;
runningProduct *= (*arraySizes)[dimension]; runningProduct *= arraySizes[dimension];
} }
} }
......
...@@ -78,7 +78,7 @@ void CopyArraySizes(const TType *from, TType *to) ...@@ -78,7 +78,7 @@ void CopyArraySizes(const TType *from, TType *to)
{ {
if (from->isArray()) if (from->isArray())
{ {
to->makeArrays(*from->getArraySizes()); to->makeArrays(from->getArraySizes());
} }
} }
...@@ -219,15 +219,15 @@ class TransformArrayHelper ...@@ -219,15 +219,15 @@ class TransformArrayHelper
TransformArrayHelper(TIntermTyped *baseExpression) TransformArrayHelper(TIntermTyped *baseExpression)
: mBaseExpression(baseExpression), : mBaseExpression(baseExpression),
mBaseExpressionType(baseExpression->getType()), mBaseExpressionType(baseExpression->getType()),
mArrayIndices(mBaseExpressionType.getArraySizes()->size(), 0) mArrayIndices(mBaseExpressionType.getArraySizes().size(), 0)
{} {}
TIntermTyped *getNextElement(TIntermTyped *valueExpression, TIntermTyped **valueElementOut) TIntermTyped *getNextElement(TIntermTyped *valueExpression, TIntermTyped **valueElementOut)
{ {
const TVector<unsigned int> *arraySizes = mBaseExpressionType.getArraySizes(); const TSpan<const unsigned int> &arraySizes = mBaseExpressionType.getArraySizes();
// If the last index overflows, element enumeration is done. // If the last index overflows, element enumeration is done.
if (mArrayIndices.back() >= arraySizes->back()) if (mArrayIndices.back() >= arraySizes.back())
{ {
return nullptr; return nullptr;
} }
...@@ -252,7 +252,8 @@ class TransformArrayHelper ...@@ -252,7 +252,8 @@ class TransformArrayHelper
TIntermTyped *constructReadTransformExpression() TIntermTyped *constructReadTransformExpression()
{ {
const TVector<unsigned int> &arraySizes = *mBaseExpressionType.getArraySizes(); const TSpan<const unsigned int> &baseTypeArraySizes = mBaseExpressionType.getArraySizes();
TVector<unsigned int> arraySizes(baseTypeArraySizes.begin(), baseTypeArraySizes.end());
TIntermTyped *firstElement = mReadTransformConstructorArgs.front()->getAsTyped(); TIntermTyped *firstElement = mReadTransformConstructorArgs.front()->getAsTyped();
const TType &baseType = firstElement->getType(); const TType &baseType = firstElement->getType();
...@@ -282,19 +283,19 @@ class TransformArrayHelper ...@@ -282,19 +283,19 @@ class TransformArrayHelper
return element; return element;
} }
void incrementIndices(const TVector<unsigned int> *arraySizes) void incrementIndices(const TSpan<const unsigned int> &arraySizes)
{ {
// Assume mArrayIndices is an N digit number, where digit i is in the range // Assume mArrayIndices is an N digit number, where digit i is in the range
// [0, arraySizes[i]). This function increments this number. Last digit is the most // [0, arraySizes[i]). This function increments this number. Last digit is the most
// significant digit. // significant digit.
for (size_t digitIndex = 0; digitIndex < arraySizes->size(); ++digitIndex) for (size_t digitIndex = 0; digitIndex < arraySizes.size(); ++digitIndex)
{ {
++mArrayIndices[digitIndex]; ++mArrayIndices[digitIndex];
if (mArrayIndices[digitIndex] < (*arraySizes)[digitIndex]) if (mArrayIndices[digitIndex] < arraySizes[digitIndex])
{ {
break; break;
} }
if (digitIndex + 1 != arraySizes->size()) if (digitIndex + 1 != arraySizes.size())
{ {
// This digit has now overflown and is reset to 0, carry will be added to the next // This digit has now overflown and is reset to 0, carry will be added to the next
// digit. The most significant digit will keep the overflow though, to make it // digit. The most significant digit will keep the overflow though, to make it
...@@ -305,8 +306,8 @@ class TransformArrayHelper ...@@ -305,8 +306,8 @@ class TransformArrayHelper
} }
TIntermTyped *constructReadTransformExpressionHelper( TIntermTyped *constructReadTransformExpressionHelper(
const TVector<unsigned int> arraySizes, const TVector<unsigned int> &arraySizes,
const TVector<unsigned int> accumulatedArraySizes, const TVector<unsigned int> &accumulatedArraySizes,
const TType &baseType, const TType &baseType,
size_t elementsOffset) size_t elementsOffset)
{ {
......
...@@ -29,7 +29,7 @@ TType *GetStructSamplerParameterType(TSymbolTable *symbolTable, const TVariable ...@@ -29,7 +29,7 @@ TType *GetStructSamplerParameterType(TSymbolTable *symbolTable, const TVariable
if (param.getType().isArray()) if (param.getType().isArray())
{ {
structType->makeArrays(*param.getType().getArraySizes()); structType->makeArrays(param.getType().getArraySizes());
} }
ASSERT(!structType->isStructureContainingSamplers()); ASSERT(!structType->isStructureContainingSamplers());
...@@ -210,7 +210,7 @@ TFunction *GenerateFunctionFromArguments(const TFunction *function, ...@@ -210,7 +210,7 @@ TFunction *GenerateFunctionFromArguments(const TFunction *function,
if (type.isArray() && type.isSampler()) if (type.isArray() && type.isSampler())
{ {
ASSERT(type.getNumArraySizes() == 1); ASSERT(type.getNumArraySizes() == 1);
instantiation.push_back((*type.getArraySizes())[0]); instantiation.push_back(type.getArraySizes()[0]);
} }
} }
...@@ -267,8 +267,8 @@ class ArrayTraverser ...@@ -267,8 +267,8 @@ class ArrayTraverser
{ {
if (!arrayType.isArray()) if (!arrayType.isArray())
return; return;
size_t currentArraySize = mCumulativeArraySizeStack.back(); size_t currentArraySize = mCumulativeArraySizeStack.back();
const auto &arraySizes = *arrayType.getArraySizes(); const TSpan<const unsigned int> &arraySizes = arrayType.getArraySizes();
for (auto it = arraySizes.rbegin(); it != arraySizes.rend(); ++it) for (auto it = arraySizes.rbegin(); it != arraySizes.rend(); ++it)
{ {
unsigned int arraySize = *it; unsigned int arraySize = *it;
...@@ -552,7 +552,7 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser ...@@ -552,7 +552,7 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
newType = new TType(fieldStruct, true); newType = new TType(fieldStruct, true);
if (fieldType.isArray()) if (fieldType.isArray())
{ {
newType->makeArrays(*fieldType.getArraySizes()); newType->makeArrays(fieldType.getArraySizes());
} }
} }
else else
...@@ -759,9 +759,9 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser ...@@ -759,9 +759,9 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
// Also includes samplers in arrays of arrays. // Also includes samplers in arrays of arrays.
virtual void visitSamplerInStructParam(const ImmutableString &name, virtual void visitSamplerInStructParam(const ImmutableString &name,
const TType *type, const TType *type,
size_t paramIndex) = 0; size_t paramIndex) = 0;
virtual void visitStructParam(const TFunction *function, size_t paramIndex) = 0; virtual void visitStructParam(const TFunction *function, size_t paramIndex) = 0;
virtual void visitNonStructParam(const TFunction *function, size_t paramIndex) = 0; virtual void visitNonStructParam(const TFunction *function, size_t paramIndex) = 0;
private: private:
bool traverseStructContainingSamplers(const ImmutableString &baseName, bool traverseStructContainingSamplers(const ImmutableString &baseName,
......
...@@ -27,7 +27,7 @@ TType *GetStructSamplerParameterType(TSymbolTable *symbolTable, const TVariable ...@@ -27,7 +27,7 @@ TType *GetStructSamplerParameterType(TSymbolTable *symbolTable, const TVariable
if (param.getType().isArray()) if (param.getType().isArray())
{ {
structType->makeArrays(*param.getType().getArraySizes()); structType->makeArrays(param.getType().getArraySizes());
} }
ASSERT(!structType->isStructureContainingSamplers()); ASSERT(!structType->isStructureContainingSamplers());
...@@ -290,7 +290,7 @@ class Traverser final : public TIntermTraverser ...@@ -290,7 +290,7 @@ class Traverser final : public TIntermTraverser
newType = new TType(fieldStruct, true); newType = new TType(fieldStruct, true);
if (fieldType.isArray()) if (fieldType.isArray())
{ {
newType->makeArrays(*fieldType.getArraySizes()); newType->makeArrays(fieldType.getArraySizes());
} }
} }
else else
...@@ -372,7 +372,7 @@ class Traverser final : public TIntermTraverser ...@@ -372,7 +372,7 @@ class Traverser final : public TIntermTraverser
size_t nonSamplerCount = 0; size_t nonSamplerCount = 0;
// Name the samplers internally as varName_<index>_fieldName // Name the samplers internally as varName_<index>_fieldName
const TVector<unsigned int> &arraySizes = *containingType.getArraySizes(); const TSpan<const unsigned int> &arraySizes = containingType.getArraySizes();
for (unsigned int arrayElement = 0; arrayElement < arraySizes[0]; ++arrayElement) for (unsigned int arrayElement = 0; arrayElement < arraySizes[0]; ++arrayElement)
{ {
ImmutableStringBuilder stringBuilder(prefix.length() + kHexSize + 1); ImmutableStringBuilder stringBuilder(prefix.length() + kHexSize + 1);
...@@ -530,7 +530,7 @@ class Traverser final : public TIntermTraverser ...@@ -530,7 +530,7 @@ class Traverser final : public TIntermTraverser
if (baseType.isArray()) if (baseType.isArray())
{ {
const TVector<unsigned int> &arraySizes = *baseType.getArraySizes(); const TSpan<const unsigned int> &arraySizes = baseType.getArraySizes();
ASSERT(arraySizes.size() == 1); ASSERT(arraySizes.size() == 1);
for (unsigned int arrayIndex = 0; arrayIndex < arraySizes[0]; ++arrayIndex) for (unsigned int arrayIndex = 0; arrayIndex < arraySizes[0]; ++arrayIndex)
......
...@@ -488,7 +488,7 @@ ImmutableString ArrayString(const TType &type) ...@@ -488,7 +488,7 @@ ImmutableString ArrayString(const TType &type)
if (!type.isArray()) if (!type.isArray())
return ImmutableString(""); return ImmutableString("");
const TVector<unsigned int> &arraySizes = *type.getArraySizes(); const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
constexpr const size_t kMaxDecimalDigitsPerSize = 10u; constexpr const size_t kMaxDecimalDigitsPerSize = 10u;
ImmutableStringBuilder arrayString(arraySizes.size() * (kMaxDecimalDigitsPerSize + 2u)); ImmutableStringBuilder arrayString(arraySizes.size() * (kMaxDecimalDigitsPerSize + 2u));
for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend(); for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend();
......
...@@ -45,6 +45,7 @@ angle_unittests_sources = [ ...@@ -45,6 +45,7 @@ angle_unittests_sources = [
"../libANGLE/renderer/TextureImpl_mock.h", "../libANGLE/renderer/TextureImpl_mock.h",
"../libANGLE/renderer/TransformFeedbackImpl_mock.h", "../libANGLE/renderer/TransformFeedbackImpl_mock.h",
"../libANGLE/renderer/serial_utils_unittest.cpp", "../libANGLE/renderer/serial_utils_unittest.cpp",
"../compiler/translator/span_unittest.cpp",
"angle_unittests_utils.h", "angle_unittests_utils.h",
"compiler_tests/API_test.cpp", "compiler_tests/API_test.cpp",
"compiler_tests/AppendixALimitations_test.cpp", "compiler_tests/AppendixALimitations_test.cpp",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment