blob: e6bfd1cdbae027317318197b51a7bcc8106f17ac [file] [log] [blame]
//
// Copyright (c) 2002-2013 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.
//
#ifndef COMPILER_TRANSLATOR_TYPES_H_
#define COMPILER_TRANSLATOR_TYPES_H_
#include "common/angleutils.h"
#include "common/debug.h"
#include "compiler/translator/BaseTypes.h"
#include "compiler/translator/Common.h"
#include "compiler/translator/ImmutableString.h"
#include "compiler/translator/SymbolUniqueId.h"
namespace sh
{
struct TPublicType;
class TType;
class TInterfaceBlock;
class TStructure;
class TSymbol;
class TVariable;
class TIntermSymbol;
class TSymbolTable;
class TField : angle::NonCopyable
{
public:
POOL_ALLOCATOR_NEW_DELETE
TField(TType *type, const ImmutableString &name, const TSourceLoc &line, SymbolType symbolType)
: mType(type), mName(name), mLine(line), mSymbolType(symbolType)
{
ASSERT(mSymbolType != SymbolType::Empty);
}
// TODO(alokp): We should only return const type.
// Fix it by tweaking grammar.
TType *type() { return mType; }
const TType *type() const { return mType; }
const ImmutableString &name() const { return mName; }
const TSourceLoc &line() const { return mLine; }
SymbolType symbolType() const { return mSymbolType; }
private:
TType *mType;
const ImmutableString mName;
const TSourceLoc mLine;
const SymbolType mSymbolType;
};
typedef TVector<TField *> TFieldList;
class TFieldListCollection : angle::NonCopyable
{
public:
const TFieldList &fields() const { return *mFields; }
bool containsArrays() const;
bool containsMatrices() const;
bool containsType(TBasicType t) const;
bool containsSamplers() const;
size_t objectSize() const;
// How many locations the field list consumes as a uniform.
int getLocationCount() const;
int deepestNesting() const;
const TString &mangledFieldList() const;
protected:
TFieldListCollection(const TFieldList *fields);
const TFieldList *mFields;
private:
size_t calculateObjectSize() const;
int calculateDeepestNesting() const;
TString buildMangledFieldList() const;
mutable size_t mObjectSize;
mutable int mDeepestNesting;
mutable TString mMangledFieldList;
};
//
// Base class for things that have a type.
//
class TType
{
public:
POOL_ALLOCATOR_NEW_DELETE
TType();
explicit TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1);
TType(TBasicType t,
TPrecision p,
TQualifier q = EvqTemporary,
unsigned char ps = 1,
unsigned char ss = 1);
explicit TType(const TPublicType &p);
TType(const TStructure *userDef, bool isStructSpecifier);
TType(const TInterfaceBlock *interfaceBlockIn,
TQualifier qualifierIn,
TLayoutQualifier layoutQualifierIn);
TType(const TType &t);
TType &operator=(const TType &t);
constexpr TType(TBasicType t,
TPrecision p,
TQualifier q,
unsigned char ps,
unsigned char ss,
const char *mangledName)
: type(t),
precision(p),
qualifier(q),
invariant(false),
memoryQualifier(TMemoryQualifier::Create()),
layoutQualifier(TLayoutQualifier::Create()),
primarySize(ps),
secondarySize(ss),
mArraySizes(nullptr),
mInterfaceBlock(nullptr),
mStructure(nullptr),
mIsStructSpecifier(false),
mMangledName(mangledName)
{}
constexpr TType(TType &&t)
: type(t.type),
precision(t.precision),
qualifier(t.qualifier),
invariant(t.invariant),
memoryQualifier(t.memoryQualifier),
layoutQualifier(t.layoutQualifier),
primarySize(t.primarySize),
secondarySize(t.secondarySize),
mArraySizes(t.mArraySizes),
mInterfaceBlock(t.mInterfaceBlock),
mStructure(t.mStructure),
mIsStructSpecifier(t.mIsStructSpecifier),
mMangledName(t.mMangledName)
{}
constexpr TBasicType getBasicType() const { return type; }
void setBasicType(TBasicType t);
TPrecision getPrecision() const { return precision; }
void setPrecision(TPrecision p) { precision = p; }
constexpr TQualifier getQualifier() const { return qualifier; }
void setQualifier(TQualifier q) { qualifier = q; }
bool isInvariant() const { return invariant; }
void setInvariant(bool i) { invariant = i; }
TMemoryQualifier getMemoryQualifier() const { return memoryQualifier; }
void setMemoryQualifier(const TMemoryQualifier &mq) { memoryQualifier = mq; }
TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; }
void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; }
int getNominalSize() const { return primarySize; }
int getSecondarySize() const { return secondarySize; }
int getCols() const
{
ASSERT(isMatrix());
return primarySize;
}
int getRows() const
{
ASSERT(isMatrix());
return secondarySize;
}
void setPrimarySize(unsigned char ps);
void setSecondarySize(unsigned char ss);
// Full size of single instance of type
size_t getObjectSize() const;
// Get how many locations this type consumes as a uniform.
int getLocationCount() const;
bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; }
bool isArray() const { return mArraySizes != nullptr && !mArraySizes->empty(); }
bool isArrayOfArrays() const { return isArray() && mArraySizes->size() > 1u; }
size_t getNumArraySizes() const { return isArray() ? mArraySizes->size() : 0; }
const TVector<unsigned int> *getArraySizes() const { return mArraySizes; }
unsigned int getArraySizeProduct() const;
bool isUnsizedArray() const;
unsigned int getOutermostArraySize() const
{
ASSERT(isArray());
return mArraySizes->back();
}
void makeArray(unsigned int s);
// sizes contain new outermost array sizes.
void makeArrays(const TVector<unsigned int> &sizes);
// Here, the array dimension value 0 corresponds to the innermost array.
void setArraySize(size_t arrayDimension, unsigned int s);
// 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
// remaining array sizes to 1.
void sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes);
// Will size the outermost array according to arraySize.
void sizeOutermostUnsizedArray(unsigned int arraySize);
// Note that the array element type might still be an array type in GLSL ES version >= 3.10.
void toArrayElementType();
const TInterfaceBlock *getInterfaceBlock() const { return mInterfaceBlock; }
void setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn);
bool isInterfaceBlock() const { return type == EbtInterfaceBlock; }
bool isVector() const { return primarySize > 1 && secondarySize == 1; }
bool isScalar() const
{
return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray();
}
bool isScalarFloat() const { return isScalar() && type == EbtFloat; }
bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); }
bool canBeConstructed() const;
const TStructure *getStruct() const { return mStructure; }
static constexpr char GetSizeMangledName(unsigned char primarySize, unsigned char secondarySize)
{
unsigned int sizeKey = (secondarySize - 1u) * 4u + primarySize - 1u;
if (sizeKey < 10u)
{
return static_cast<char>('0' + sizeKey);
}
return static_cast<char>('A' + sizeKey - 10);
}
const char *getMangledName() const;
bool sameNonArrayType(const TType &right) const;
// Returns true if arrayType is an array made of this type.
bool isElementTypeOf(const TType &arrayType) const;
bool operator==(const TType &right) const
{
size_t numArraySizesL = getNumArraySizes();
size_t numArraySizesR = right.getNumArraySizes();
bool arraySizesEqual = numArraySizesL == numArraySizesR &&
(numArraySizesL == 0 || *mArraySizes == *right.mArraySizes);
return type == right.type && primarySize == right.primarySize &&
secondarySize == right.secondarySize && arraySizesEqual &&
mStructure == right.mStructure;
// don't check the qualifier, it's not ever what's being sought after
}
bool operator!=(const TType &right) const { return !operator==(right); }
bool operator<(const TType &right) const
{
if (type != right.type)
return type < right.type;
if (primarySize != right.primarySize)
return primarySize < right.primarySize;
if (secondarySize != right.secondarySize)
return secondarySize < right.secondarySize;
size_t numArraySizesL = getNumArraySizes();
size_t numArraySizesR = right.getNumArraySizes();
if (numArraySizesL != numArraySizesR)
return numArraySizesL < numArraySizesR;
for (size_t i = 0; i < numArraySizesL; ++i)
{
if ((*mArraySizes)[i] != (*right.mArraySizes)[i])
return (*mArraySizes)[i] < (*right.mArraySizes)[i];
}
if (mStructure != right.mStructure)
return mStructure < right.mStructure;
return false;
}
const char *getBasicString() const { return sh::getBasicString(type); }
const char *getPrecisionString() const { return sh::getPrecisionString(precision); }
const char *getQualifierString() const { return sh::getQualifierString(qualifier); }
const char *getBuiltInTypeNameString() const;
// If this type is a struct, returns the deepest struct nesting of
// any field in the struct. For example:
// struct nesting1 {
// vec4 position;
// };
// struct nesting2 {
// nesting1 field1;
// vec4 field2;
// };
// For type "nesting2", this method would return 2 -- the number
// of structures through which indirection must occur to reach the
// deepest field (nesting2.field1.position).
int getDeepestStructNesting() const;
bool isNamelessStruct() const;
bool isStructureContainingArrays() const;
bool isStructureContainingMatrices() const;
bool isStructureContainingType(TBasicType t) const;
bool isStructureContainingSamplers() const;
bool isStructSpecifier() const { return mIsStructSpecifier; }
// Return true if variables of this type should be replaced with an inline constant value if
// such is available. False will be returned in cases where output doesn't support
// TIntermConstantUnion nodes of the type, or if the type contains a lot of fields and creating
// several copies of it in the output code is undesirable for performance.
bool canReplaceWithConstantUnion() const;
// The char arrays passed in must be pool allocated or static.
void createSamplerSymbols(const ImmutableString &namePrefix,
const TString &apiNamePrefix,
TVector<const TVariable *> *outputSymbols,
TMap<const TVariable *, TString> *outputSymbolsToAPINames,
TSymbolTable *symbolTable) const;
// Initializes all lazily-initialized members.
void realize();
bool isSampler() const { return IsSampler(type); }
private:
void invalidateMangledName();
const char *buildMangledName() const;
TBasicType type;
TPrecision precision;
TQualifier qualifier;
bool invariant;
TMemoryQualifier memoryQualifier;
TLayoutQualifier layoutQualifier;
unsigned char primarySize; // size of vector or cols matrix
unsigned char secondarySize; // rows of a matrix
// 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.
TVector<unsigned int> *mArraySizes;
// This is set only in the following two cases:
// 1) Represents an interface block.
// 2) Represents the member variable of an unnamed interface block.
// It's nullptr also for members of named interface blocks.
const TInterfaceBlock *mInterfaceBlock;
// nullptr unless this is a struct
const TStructure *mStructure;
bool mIsStructSpecifier;
mutable const char *mMangledName;
};
// TTypeSpecifierNonArray stores all of the necessary fields for type_specifier_nonarray from the
// grammar
struct TTypeSpecifierNonArray
{
TBasicType type;
unsigned char primarySize; // size of vector or cols of matrix
unsigned char secondarySize; // rows of matrix
const TStructure *userDef;
TSourceLoc line;
// true if the type was defined by a struct specifier rather than a reference to a type name.
bool isStructSpecifier;
void initialize(TBasicType aType, const TSourceLoc &aLine)
{
ASSERT(aType != EbtStruct);
type = aType;
primarySize = 1;
secondarySize = 1;
userDef = nullptr;
line = aLine;
isStructSpecifier = false;
}
void initializeStruct(const TStructure *aUserDef,
bool aIsStructSpecifier,
const TSourceLoc &aLine)
{
type = EbtStruct;
primarySize = 1;
secondarySize = 1;
userDef = aUserDef;
line = aLine;
isStructSpecifier = aIsStructSpecifier;
}
void setAggregate(unsigned char size) { primarySize = size; }
void setMatrix(unsigned char columns, unsigned char rows)
{
ASSERT(columns > 1 && rows > 1 && columns <= 4 && rows <= 4);
primarySize = columns;
secondarySize = rows;
}
bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
bool isVector() const { return primarySize > 1 && secondarySize == 1; }
};
//
// This is a workaround for a problem with the yacc stack, It can't have
// types that it thinks have non-trivial constructors. It should
// just be used while recognizing the grammar, not anything else. Pointers
// could be used, but also trying to avoid lots of memory management overhead.
//
// Not as bad as it looks, there is no actual assumption that the fields
// match up or are name the same or anything like that.
//
struct TPublicType
{
// Must have a trivial default constructor since it is used in YYSTYPE.
TPublicType() = default;
void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q);
void initializeBasicType(TBasicType basicType);
TBasicType getBasicType() const { return typeSpecifierNonArray.type; }
void setBasicType(TBasicType basicType) { typeSpecifierNonArray.type = basicType; }
unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; }
unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; }
const TStructure *getUserDef() const { return typeSpecifierNonArray.userDef; }
const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; }
bool isStructureContainingArrays() const;
bool isStructureContainingType(TBasicType t) const;
void setArraySizes(TVector<unsigned int> *sizes);
bool isArray() const;
void clearArrayness();
bool isAggregate() const;
TTypeSpecifierNonArray typeSpecifierNonArray;
TLayoutQualifier layoutQualifier;
TMemoryQualifier memoryQualifier;
TQualifier qualifier;
bool invariant;
TPrecision precision;
// Either nullptr or empty in case the type is not an array. The last element is the outermost
// array size. Note that due to bison restrictions, copies of the public type created by the
// copy constructor share the same arraySizes pointer.
const TVector<unsigned int> *arraySizes;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_TYPES_H_