blob: 846b240dc8a1aee6d642a2e2f172f074d06ff938 [file] [log] [blame]
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _TYPES_INCLUDED
#define _TYPES_INCLUDED
#include "BaseTypes.h"
#include "Common.h"
#include "debug.h"
#include <algorithm>
class TType;
struct TPublicType;
class TField
{
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
{
public:
virtual ~TFieldListCollection() { }
const TString &name() const
{
return *mName;
}
const TFieldList &fields() const
{
return *mFields;
}
const TString &mangledName() const
{
if(mMangledName.empty())
mMangledName = buildMangledName();
return mMangledName;
}
size_t objectSize() const
{
if(mObjectSize == 0)
mObjectSize = calculateObjectSize();
return mObjectSize;
}
protected:
TFieldListCollection(const TString *name, TFieldList *fields)
: mName(name),
mFields(fields),
mObjectSize(0)
{
}
TString buildMangledName() const;
size_t calculateObjectSize() const;
virtual TString mangledNamePrefix() const = 0;
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)
: TFieldListCollection(name, fields),
mDeepestNesting(0),
mUniqueId(0),
mAtGlobalScope(false)
{
}
int deepestNesting() const
{
if(mDeepestNesting == 0)
mDeepestNesting = calculateDeepestNesting();
return mDeepestNesting;
}
bool containsArrays() const;
bool containsType(TBasicType type) const;
bool containsSamplers() const;
bool equals(const TStructure &other) const;
void setMatrixPackingIfUnspecified(TLayoutMatrixPacking matrixPacking);
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;
}
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;
}
virtual TString mangledNamePrefix() const
{
return "struct-";
}
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;
}
private:
virtual TString mangledNamePrefix() const
{
return "iblock-";
}
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(TBasicType t, int s0 = 1, int s1 = 1) :
type(t), precision(EbpUndefined), qualifier(EvqGlobal),
primarySize(s0), secondarySize(s1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), layoutQualifier(TLayoutQualifier::create()),
structure(0), mangled(0)
{
}
TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s0 = 1, int s1 = 1, bool a = false) :
type(t), precision(p), qualifier(q),
primarySize(s0), secondarySize(s1), array(a), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), layoutQualifier(TLayoutQualifier::create()),
structure(0), mangled(0)
{
}
TType(TStructure* userDef, TPrecision p = EbpUndefined) :
type(EbtStruct), precision(p), qualifier(EvqTemporary),
primarySize(1), secondarySize(1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), layoutQualifier(TLayoutQualifier::create()),
structure(userDef), mangled(0)
{
}
TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn,
TLayoutQualifier layoutQualifierIn, int arraySizeIn)
: type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn),
primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn), maxArraySize(0), arrayInformationType(0),
interfaceBlock(interfaceBlockIn), layoutQualifier(layoutQualifierIn), structure(0), mangled(0)
{
}
explicit TType(const TPublicType &p);
TBasicType getBasicType() const { return type; }
void setBasicType(TBasicType t) { type = t; }
TPrecision getPrecision() const { return precision; }
void setPrecision(TPrecision p) { precision = p; }
TQualifier getQualifier() const { return qualifier; }
void setQualifier(TQualifier q) { qualifier = q; }
TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; }
void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; }
void setMatrixPackingIfUnspecified(TLayoutMatrixPacking matrixPacking)
{
if(isStruct())
{
// If the structure's matrix packing is specified, it overrules the block's matrix packing
structure->setMatrixPackingIfUnspecified((layoutQualifier.matrixPacking == EmpUnspecified) ?
matrixPacking : layoutQualifier.matrixPacking);
}
// If the member's matrix packing is specified, it overrules any higher level matrix packing
if(layoutQualifier.matrixPacking == EmpUnspecified)
{
layoutQualifier.matrixPacking = matrixPacking;
}
}
// One-dimensional size of single instance type
int getNominalSize() const { return primarySize; }
void setNominalSize(int s) { primarySize = s; }
// Full size of single instance of type
size_t getObjectSize() const
{
if(isArray())
{
return getElementSize() * std::max(getArraySize(), getMaxArraySize());
}
else
{
return getElementSize();
}
}
size_t getElementSize() const
{
if(getBasicType() == EbtStruct)
{
return getStructSize();
}
else if(isInterfaceBlock())
{
return interfaceBlock->objectSize();
}
else if(isMatrix())
{
return primarySize * secondarySize;
}
else // Vector or scalar
{
return primarySize;
}
}
int samplerRegisterCount() const
{
if(structure)
{
int registerCount = 0;
const TFieldList& fields = isInterfaceBlock() ? interfaceBlock->fields() : structure->fields();
for(size_t i = 0; i < fields.size(); i++)
{
registerCount += fields[i]->type()->totalSamplerRegisterCount();
}
return registerCount;
}
return IsSampler(getBasicType()) ? 1 : 0;
}
int elementRegisterCount() const
{
if(structure || isInterfaceBlock())
{
int registerCount = 0;
const TFieldList& fields = isInterfaceBlock() ? interfaceBlock->fields() : structure->fields();
for(size_t i = 0; i < fields.size(); i++)
{
registerCount += fields[i]->type()->totalRegisterCount();
}
return registerCount;
}
else if(isMatrix())
{
return getNominalSize();
}
else
{
return 1;
}
}
int blockRegisterCount() const
{
// If this TType object is a block member, return the register count of the parent block
// Otherwise, return the register count of the current TType object
if(interfaceBlock && !isInterfaceBlock())
{
int registerCount = 0;
const TFieldList& fieldList = interfaceBlock->fields();
for(size_t i = 0; i < fieldList.size(); i++)
{
const TType &fieldType = *(fieldList[i]->type());
registerCount += fieldType.totalRegisterCount();
}
return registerCount;
}
return totalRegisterCount();
}
int totalSamplerRegisterCount() const
{
if(array)
{
return arraySize * samplerRegisterCount();
}
else
{
return samplerRegisterCount();
}
}
int totalRegisterCount() const
{
if(array)
{
return arraySize * elementRegisterCount();
}
else
{
return elementRegisterCount();
}
}
int registerSize() const
{
return isMatrix() ? secondarySize : primarySize;
}
bool isMatrix() const { return secondarySize > 1; }
void setSecondarySize(int s1) { secondarySize = s1; }
int getSecondarySize() const { return secondarySize; }
bool isArray() const { return array ? true : false; }
bool isUnsizedArray() const { return array && arraySize == 0; }
int getArraySize() const { return arraySize; }
void setArraySize(int s) { array = true; arraySize = s; }
int getMaxArraySize () const { return maxArraySize; }
void setMaxArraySize (int s) { maxArraySize = s; }
void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; }
void setArrayInformationType(TType* t) { arrayInformationType = t; }
TType* getArrayInformationType() const { return arrayInformationType; }
TInterfaceBlock *getInterfaceBlock() const { return interfaceBlock; }
void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn) { interfaceBlock = interfaceBlockIn; }
bool isInterfaceBlock() const { return type == EbtInterfaceBlock; }
TInterfaceBlock *getAsInterfaceBlock() const { return isInterfaceBlock() ? getInterfaceBlock() : nullptr; }
bool isVector() const { return primarySize > 1 && !isMatrix(); }
bool isScalar() const { return primarySize == 1 && !isMatrix() && !structure && !isInterfaceBlock() && !IsSampler(getBasicType()); }
bool isRegister() const { return !isMatrix() && !structure && !array && !isInterfaceBlock(); } // Fits in a 4-element register
bool isStruct() const { return structure != 0; }
bool isScalarInt() const { return isScalar() && IsInteger(type); }
TStructure* getStruct() const { return structure; }
void setStruct(TStructure* s) { structure = s; }
TString& getMangledName() {
if (!mangled) {
mangled = NewPoolTString("");
buildMangledName(*mangled);
*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 * secondarySize) < (right.primarySize * right.secondarySize);
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 ::getBasicString(type); }
const char* getPrecisionString() const { return ::getPrecisionString(precision); }
const char* getQualifierString() const { return ::getQualifierString(qualifier); }
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;
}
protected:
void buildMangledName(TString&);
size_t getStructSize() const;
TBasicType type = EbtVoid;
TPrecision precision = EbpUndefined;
TQualifier qualifier = EvqTemporary;
unsigned char primarySize = 0; // size of vector or matrix, not size of array
unsigned char secondarySize = 0; // 1 for vectors, > 1 for matrices
bool array = false;
int arraySize = 0;
int maxArraySize = 0;
TType *arrayInformationType = nullptr;
// null unless this is an interface block, or interface block member variable
TInterfaceBlock *interfaceBlock = nullptr;
TLayoutQualifier layoutQualifier;
TStructure *structure = nullptr; // null unless this is a struct
TString *mangled = nullptr;
};
//
// 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
{
TBasicType type;
TLayoutQualifier layoutQualifier;
TQualifier qualifier;
bool invariant;
TPrecision precision;
int primarySize; // size of vector or matrix, not size of array
int secondarySize; // 1 for scalars/vectors, >1 for matrices
bool array;
int arraySize;
TType* userDef;
TSourceLoc line;
void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln)
{
type = bt;
layoutQualifier = TLayoutQualifier::create();
qualifier = q;
invariant = false;
precision = EbpUndefined;
primarySize = 1;
secondarySize = 1;
array = false;
arraySize = 0;
userDef = 0;
line = ln;
}
void setAggregate(int s)
{
primarySize = s;
secondarySize = 1;
}
void setMatrix(int s0, int s1)
{
primarySize = s0;
secondarySize = s1;
}
bool isUnsizedArray() const
{
return array && arraySize == 0;
}
void setArray(bool a, int s = 0)
{
array = a;
arraySize = s;
}
void clearArrayness()
{
array = false;
arraySize = 0;
}
bool isStructureContainingArrays() const
{
if (!userDef)
{
return false;
}
return userDef->isStructureContainingArrays();
}
bool isStructureContainingType(TBasicType t) const
{
if(!userDef)
{
return false;
}
return userDef->isStructureContainingType(t);
}
bool isMatrix() const
{
return primarySize > 1 && secondarySize > 1;
}
bool isVector() const
{
return primarySize > 1 && secondarySize == 1;
}
int getCols() const
{
ASSERT(isMatrix());
return primarySize;
}
int getRows() const
{
ASSERT(isMatrix());
return secondarySize;
}
int getNominalSize() const
{
return primarySize;
}
bool isAggregate() const
{
return array || isMatrix() || isVector();
}
};
#endif // _TYPES_INCLUDED_