blob: 721c090ec8d9cfa181ebdfab693773e5ae7e4aa0 [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"
namespace sh
{
struct TPublicType;
class TType;
class TSymbol;
class TIntermSymbol;
class TField : angle::NonCopyable
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TField(TType *type, TString *name, const TSourceLoc &line)
: mType(type), mName(name), mLine(line)
{
}
// TODO(alokp): We should only return const type.
// Fix it by tweaking grammar.
TType *type() { return mType; }
const TType *type() const { return mType; }
const TString &name() const { return *mName; }
const TSourceLoc &line() const { return mLine; }
private:
TType *mType;
TString *mName;
TSourceLoc mLine;
};
typedef TVector<TField *> TFieldList;
inline TFieldList *NewPoolTFieldList()
{
void *memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList));
return new (memory) TFieldList;
}
class TFieldListCollection : angle::NonCopyable
{
public:
const TString &name() const { return *mName; }
const TFieldList &fields() const { return *mFields; }
size_t objectSize() const
{
if (mObjectSize == 0)
mObjectSize = calculateObjectSize();
return mObjectSize;
}
// How many locations the field list consumes as a uniform.
int getLocationCount() const;
protected:
TFieldListCollection(const TString *name, TFieldList *fields)
: mName(name), mFields(fields), mObjectSize(0)
{
}
TString buildMangledName(const TString &mangledNamePrefix) const;
size_t calculateObjectSize() const;
const TString *mName;
TFieldList *mFields;
mutable TString mMangledName;
mutable size_t mObjectSize;
};
// May also represent interface blocks
class TStructure : public TFieldListCollection
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TStructure(const TString *name, TFieldList *fields);
int deepestNesting() const
{
if (mDeepestNesting == 0)
mDeepestNesting = calculateDeepestNesting();
return mDeepestNesting;
}
bool containsArrays() const;
bool containsType(TBasicType t) const;
bool containsSamplers() const;
void createSamplerSymbols(const TString &structName,
const TString &structAPIName,
const unsigned int arrayOfStructsSize,
TVector<TIntermSymbol *> *outputSymbols,
TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const;
bool equals(const TStructure &other) const;
void setUniqueId(int uniqueId) { mUniqueId = uniqueId; }
int uniqueId() const
{
ASSERT(mUniqueId != 0);
return mUniqueId;
}
void setAtGlobalScope(bool atGlobalScope) { mAtGlobalScope = atGlobalScope; }
bool atGlobalScope() const { return mAtGlobalScope; }
const TString &mangledName() const
{
if (mMangledName.empty())
mMangledName = buildMangledName("struct-");
return mMangledName;
}
private:
// TODO(zmo): Find a way to get rid of the const_cast in function
// setName(). At the moment keep this function private so only
// friend class RegenerateStructNames may call it.
friend class RegenerateStructNames;
void setName(const TString &name)
{
TString *mutableName = const_cast<TString *>(mName);
*mutableName = name;
}
int calculateDeepestNesting() const;
mutable int mDeepestNesting;
int mUniqueId;
bool mAtGlobalScope;
};
class TInterfaceBlock : public TFieldListCollection
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TInterfaceBlock(const TString *name,
TFieldList *fields,
const TString *instanceName,
int arraySize,
const TLayoutQualifier &layoutQualifier)
: TFieldListCollection(name, fields),
mInstanceName(instanceName),
mArraySize(arraySize),
mBlockStorage(layoutQualifier.blockStorage),
mMatrixPacking(layoutQualifier.matrixPacking)
{
}
const TString &instanceName() const { return *mInstanceName; }
bool hasInstanceName() const { return mInstanceName != nullptr; }
bool isArray() const { return mArraySize > 0; }
int arraySize() const { return mArraySize; }
TLayoutBlockStorage blockStorage() const { return mBlockStorage; }
TLayoutMatrixPacking matrixPacking() const { return mMatrixPacking; }
const TString &mangledName() const
{
if (mMangledName.empty())
mMangledName = buildMangledName("iblock-");
return mMangledName;
}
private:
const TString *mInstanceName; // for interface block instance names
int mArraySize; // 0 if not an array
TLayoutBlockStorage mBlockStorage;
TLayoutMatrixPacking mMatrixPacking;
};
//
// Base class for things that have a type.
//
class TType
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TType()
: type(EbtVoid),
precision(EbpUndefined),
qualifier(EvqGlobal),
invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(TLayoutQualifier::create()),
primarySize(0),
secondarySize(0),
array(false),
arraySize(0),
interfaceBlock(nullptr),
structure(nullptr)
{
}
explicit TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1)
: type(t),
precision(EbpUndefined),
qualifier(EvqGlobal),
invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(TLayoutQualifier::create()),
primarySize(ps),
secondarySize(ss),
array(false),
arraySize(0),
interfaceBlock(0),
structure(0)
{
}
TType(TBasicType t,
TPrecision p,
TQualifier q = EvqTemporary,
unsigned char ps = 1,
unsigned char ss = 1,
bool a = false)
: type(t),
precision(p),
qualifier(q),
invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(TLayoutQualifier::create()),
primarySize(ps),
secondarySize(ss),
array(a),
arraySize(0),
interfaceBlock(0),
structure(0)
{
}
explicit TType(const TPublicType &p);
explicit TType(TStructure *userDef, TPrecision p = EbpUndefined)
: type(EbtStruct),
precision(p),
qualifier(EvqTemporary),
invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(TLayoutQualifier::create()),
primarySize(1),
secondarySize(1),
array(false),
arraySize(0),
interfaceBlock(0),
structure(userDef)
{
}
TType(TInterfaceBlock *interfaceBlockIn,
TQualifier qualifierIn,
TLayoutQualifier layoutQualifierIn,
int arraySizeIn)
: type(EbtInterfaceBlock),
precision(EbpUndefined),
qualifier(qualifierIn),
invariant(false),
memoryQualifier(TMemoryQualifier::create()),
layoutQualifier(layoutQualifierIn),
primarySize(1),
secondarySize(1),
array(arraySizeIn > 0),
arraySize(arraySizeIn),
interfaceBlock(interfaceBlockIn),
structure(0)
{
}
TType(const TType &) = default;
TType &operator=(const TType &) = default;
TBasicType getBasicType() const { return type; }
void setBasicType(TBasicType t)
{
if (type != t)
{
type = t;
invalidateMangledName();
}
}
TPrecision getPrecision() const { return precision; }
void setPrecision(TPrecision p) { precision = p; }
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)
{
if (primarySize != ps)
{
ASSERT(ps <= 4);
primarySize = ps;
invalidateMangledName();
}
}
void setSecondarySize(unsigned char ss)
{
if (secondarySize != ss)
{
ASSERT(ss <= 4);
secondarySize = ss;
invalidateMangledName();
}
}
// 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 array; }
bool isUnsizedArray() const { return array && arraySize == 0u; }
unsigned int getArraySize() const { return arraySize; }
void setArraySize(unsigned int s)
{
if (!array || arraySize != s)
{
array = true;
arraySize = s;
invalidateMangledName();
}
}
void clearArrayness()
{
if (array)
{
array = false;
arraySize = 0u;
invalidateMangledName();
}
}
TInterfaceBlock *getInterfaceBlock() const { return interfaceBlock; }
void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn)
{
if (interfaceBlock != interfaceBlockIn)
{
interfaceBlock = interfaceBlockIn;
invalidateMangledName();
}
}
bool isInterfaceBlock() const { return type == EbtInterfaceBlock; }
bool isVector() const { return primarySize > 1 && secondarySize == 1; }
bool isScalar() const { return primarySize == 1 && secondarySize == 1 && !structure; }
bool isScalarFloat() const { return isScalar() && type == EbtFloat; }
bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); }
bool canBeConstructed() const;
TStructure *getStruct() const { return structure; }
void setStruct(TStructure *s)
{
if (structure != s)
{
structure = s;
invalidateMangledName();
}
}
const TString &getMangledName() const
{
if (mangled.empty())
{
mangled = buildMangledName();
mangled += ';';
}
return mangled;
}
bool sameElementType(const TType &right) const
{
return type == right.type && primarySize == right.primarySize &&
secondarySize == right.secondarySize && structure == right.structure;
}
bool operator==(const TType &right) const
{
return type == right.type && primarySize == right.primarySize &&
secondarySize == right.secondarySize && array == right.array &&
(!array || arraySize == right.arraySize) && structure == right.structure;
// 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;
if (array != right.array)
return array < right.array;
if (arraySize != right.arraySize)
return arraySize < right.arraySize;
if (structure != right.structure)
return structure < right.structure;
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;
TString getCompleteString() 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 { return structure ? structure->deepestNesting() : 0; }
bool isStructureContainingArrays() const
{
return structure ? structure->containsArrays() : false;
}
bool isStructureContainingType(TBasicType t) const
{
return structure ? structure->containsType(t) : false;
}
bool isStructureContainingSamplers() const
{
return structure ? structure->containsSamplers() : false;
}
void createSamplerSymbols(const TString &structName,
const TString &structAPIName,
const unsigned int arrayOfStructsSize,
TVector<TIntermSymbol *> *outputSymbols,
TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const
{
ASSERT(structure != nullptr && structure->containsSamplers());
structure->createSamplerSymbols(structName, structAPIName, arrayOfStructsSize,
outputSymbols, outputSymbolsToAPINames);
}
// Initializes all lazily-initialized members.
void realize() { getMangledName(); }
private:
void invalidateMangledName() { mangled = ""; }
TString 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
bool array;
unsigned int arraySize;
// 0 unless this is an interface block, or interface block member variable
TInterfaceBlock *interfaceBlock;
// 0 unless this is a struct
TStructure *structure;
mutable TString mangled;
};
// 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
TType *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 bt, const TSourceLoc &ln)
{
type = bt;
primarySize = 1;
secondarySize = 1;
userDef = nullptr;
line = ln;
isStructSpecifier = false;
}
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
{
TTypeSpecifierNonArray typeSpecifierNonArray;
TLayoutQualifier layoutQualifier;
TMemoryQualifier memoryQualifier;
TQualifier qualifier;
bool invariant;
TPrecision precision;
bool array;
int arraySize;
void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q)
{
typeSpecifierNonArray = typeSpecifier;
layoutQualifier = TLayoutQualifier::create();
memoryQualifier = TMemoryQualifier::create();
qualifier = q;
invariant = false;
precision = EbpUndefined;
array = false;
arraySize = 0;
}
void initializeBasicType(TBasicType basicType)
{
typeSpecifierNonArray.type = basicType;
typeSpecifierNonArray.primarySize = 1;
typeSpecifierNonArray.secondarySize = 1;
layoutQualifier = TLayoutQualifier::create();
memoryQualifier = TMemoryQualifier::create();
qualifier = EvqTemporary;
invariant = false;
precision = EbpUndefined;
array = false;
arraySize = 0;
}
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 TType *getUserDef() const { return typeSpecifierNonArray.userDef; }
const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; }
bool isStructureContainingArrays() const
{
if (!typeSpecifierNonArray.userDef)
{
return false;
}
return typeSpecifierNonArray.userDef->isStructureContainingArrays();
}
bool isStructureContainingType(TBasicType t) const
{
if (!typeSpecifierNonArray.userDef)
{
return false;
}
return typeSpecifierNonArray.userDef->isStructureContainingType(t);
}
bool isUnsizedArray() const { return array && arraySize == 0; }
void setArraySize(int s)
{
array = true;
arraySize = s;
}
void clearArrayness()
{
array = false;
arraySize = 0;
}
bool isAggregate() const
{
return array || typeSpecifierNonArray.isMatrix() || typeSpecifierNonArray.isVector();
}
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_TYPES_H_