blob: 2015b56f449bc0cde1d0a918672997dd96ef7fec [file] [log] [blame]
//
// Copyright (c) 2002-2014 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.
//
#if defined(_MSC_VER)
#pragma warning(disable : 4718)
#endif
#include "compiler/translator/Types.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
#include <algorithm>
#include <climits>
namespace sh
{
const char *getBasicString(TBasicType t)
{
switch (t)
{
case EbtVoid:
return "void";
case EbtFloat:
return "float";
case EbtInt:
return "int";
case EbtUInt:
return "uint";
case EbtBool:
return "bool";
case EbtYuvCscStandardEXT:
return "yuvCscStandardEXT";
case EbtSampler2D:
return "sampler2D";
case EbtSampler3D:
return "sampler3D";
case EbtSamplerCube:
return "samplerCube";
case EbtSamplerExternalOES:
return "samplerExternalOES";
case EbtSamplerExternal2DY2YEXT:
return "__samplerExternal2DY2YEXT";
case EbtSampler2DRect:
return "sampler2DRect";
case EbtSampler2DArray:
return "sampler2DArray";
case EbtSampler2DMS:
return "sampler2DMS";
case EbtISampler2D:
return "isampler2D";
case EbtISampler3D:
return "isampler3D";
case EbtISamplerCube:
return "isamplerCube";
case EbtISampler2DArray:
return "isampler2DArray";
case EbtISampler2DMS:
return "isampler2DMS";
case EbtUSampler2D:
return "usampler2D";
case EbtUSampler3D:
return "usampler3D";
case EbtUSamplerCube:
return "usamplerCube";
case EbtUSampler2DArray:
return "usampler2DArray";
case EbtUSampler2DMS:
return "usampler2DMS";
case EbtSampler2DShadow:
return "sampler2DShadow";
case EbtSamplerCubeShadow:
return "samplerCubeShadow";
case EbtSampler2DArrayShadow:
return "sampler2DArrayShadow";
case EbtStruct:
return "structure";
case EbtInterfaceBlock:
return "interface block";
case EbtImage2D:
return "image2D";
case EbtIImage2D:
return "iimage2D";
case EbtUImage2D:
return "uimage2D";
case EbtImage3D:
return "image3D";
case EbtIImage3D:
return "iimage3D";
case EbtUImage3D:
return "uimage3D";
case EbtImage2DArray:
return "image2DArray";
case EbtIImage2DArray:
return "iimage2DArray";
case EbtUImage2DArray:
return "uimage2DArray";
case EbtImageCube:
return "imageCube";
case EbtIImageCube:
return "iimageCube";
case EbtUImageCube:
return "uimageCube";
default:
UNREACHABLE();
return "unknown type";
}
}
TType::TType(const TPublicType &p)
: type(p.getBasicType()),
precision(p.precision),
qualifier(p.qualifier),
invariant(p.invariant),
memoryQualifier(p.memoryQualifier),
layoutQualifier(p.layoutQualifier),
primarySize(p.getPrimarySize()),
secondarySize(p.getSecondarySize()),
array(p.array),
arraySize(p.arraySize),
interfaceBlock(0),
structure(0)
{
ASSERT(primarySize <= 4);
ASSERT(secondarySize <= 4);
if (p.getUserDef())
structure = p.getUserDef()->getStruct();
}
bool TStructure::equals(const TStructure &other) const
{
return (uniqueId() == other.uniqueId());
}
bool TType::canBeConstructed() const
{
switch (type)
{
case EbtFloat:
case EbtInt:
case EbtUInt:
case EbtBool:
case EbtStruct:
return true;
default:
return false;
}
}
const char *TType::getBuiltInTypeNameString() const
{
if (isMatrix())
{
switch (getCols())
{
case 2:
switch (getRows())
{
case 2:
return "mat2";
case 3:
return "mat2x3";
case 4:
return "mat2x4";
default:
UNREACHABLE();
return nullptr;
}
case 3:
switch (getRows())
{
case 2:
return "mat3x2";
case 3:
return "mat3";
case 4:
return "mat3x4";
default:
UNREACHABLE();
return nullptr;
}
case 4:
switch (getRows())
{
case 2:
return "mat4x2";
case 3:
return "mat4x3";
case 4:
return "mat4";
default:
UNREACHABLE();
return nullptr;
}
default:
UNREACHABLE();
return nullptr;
}
}
if (isVector())
{
switch (getBasicType())
{
case EbtFloat:
switch (getNominalSize())
{
case 2:
return "vec2";
case 3:
return "vec3";
case 4:
return "vec4";
default:
UNREACHABLE();
return nullptr;
}
case EbtInt:
switch (getNominalSize())
{
case 2:
return "ivec2";
case 3:
return "ivec3";
case 4:
return "ivec4";
default:
UNREACHABLE();
return nullptr;
}
case EbtBool:
switch (getNominalSize())
{
case 2:
return "bvec2";
case 3:
return "bvec3";
case 4:
return "bvec4";
default:
UNREACHABLE();
return nullptr;
}
case EbtUInt:
switch (getNominalSize())
{
case 2:
return "uvec2";
case 3:
return "uvec3";
case 4:
return "uvec4";
default:
UNREACHABLE();
return nullptr;
}
default:
UNREACHABLE();
return nullptr;
}
}
ASSERT(getBasicType() != EbtStruct);
ASSERT(getBasicType() != EbtInterfaceBlock);
return getBasicString();
}
TString TType::getCompleteString() const
{
TStringStream stream;
if (invariant)
stream << "invariant ";
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
stream << getQualifierString() << " ";
if (precision != EbpUndefined)
stream << getPrecisionString() << " ";
if (array)
stream << "array[" << getArraySize() << "] of ";
if (isMatrix())
stream << getCols() << "X" << getRows() << " matrix of ";
else if (isVector())
stream << getNominalSize() << "-component vector of ";
stream << getBasicString();
return stream.str();
}
//
// Recursively generate mangled names.
//
TString TType::buildMangledName() const
{
TString mangledName;
if (isMatrix())
mangledName += 'm';
else if (isVector())
mangledName += 'v';
switch (type)
{
case EbtFloat:
mangledName += 'f';
break;
case EbtInt:
mangledName += 'i';
break;
case EbtUInt:
mangledName += 'u';
break;
case EbtBool:
mangledName += 'b';
break;
case EbtYuvCscStandardEXT:
mangledName += "ycs";
break;
case EbtSampler2D:
mangledName += "s2";
break;
case EbtSampler3D:
mangledName += "s3";
break;
case EbtSamplerCube:
mangledName += "sC";
break;
case EbtSampler2DArray:
mangledName += "s2a";
break;
case EbtSamplerExternalOES:
mangledName += "sext";
break;
case EbtSamplerExternal2DY2YEXT:
mangledName += "sext2y2y";
break;
case EbtSampler2DRect:
mangledName += "s2r";
break;
case EbtSampler2DMS:
mangledName += "s2ms";
break;
case EbtISampler2D:
mangledName += "is2";
break;
case EbtISampler3D:
mangledName += "is3";
break;
case EbtISamplerCube:
mangledName += "isC";
break;
case EbtISampler2DArray:
mangledName += "is2a";
break;
case EbtISampler2DMS:
mangledName += "is2ms";
break;
case EbtUSampler2D:
mangledName += "us2";
break;
case EbtUSampler3D:
mangledName += "us3";
break;
case EbtUSamplerCube:
mangledName += "usC";
break;
case EbtUSampler2DArray:
mangledName += "us2a";
break;
case EbtUSampler2DMS:
mangledName += "us2ms";
break;
case EbtSampler2DShadow:
mangledName += "s2s";
break;
case EbtSamplerCubeShadow:
mangledName += "sCs";
break;
case EbtSampler2DArrayShadow:
mangledName += "s2as";
break;
case EbtImage2D:
mangledName += "im2";
break;
case EbtIImage2D:
mangledName += "iim2";
break;
case EbtUImage2D:
mangledName += "uim2";
break;
case EbtImage3D:
mangledName += "im3";
break;
case EbtIImage3D:
mangledName += "iim3";
break;
case EbtUImage3D:
mangledName += "uim3";
break;
case EbtImage2DArray:
mangledName += "im2a";
break;
case EbtIImage2DArray:
mangledName += "iim2a";
break;
case EbtUImage2DArray:
mangledName += "uim2a";
break;
case EbtImageCube:
mangledName += "imc";
break;
case EbtIImageCube:
mangledName += "iimc";
break;
case EbtUImageCube:
mangledName += "uimc";
break;
case EbtStruct:
mangledName += structure->mangledName();
break;
case EbtInterfaceBlock:
mangledName += interfaceBlock->mangledName();
break;
default:
// EbtVoid, EbtAddress and non types
break;
}
if (isMatrix())
{
mangledName += static_cast<char>('0' + getCols());
mangledName += static_cast<char>('x');
mangledName += static_cast<char>('0' + getRows());
}
else
{
mangledName += static_cast<char>('0' + getNominalSize());
}
if (isArray())
{
char buf[20];
snprintf(buf, sizeof(buf), "%d", arraySize);
mangledName += '[';
mangledName += buf;
mangledName += ']';
}
return mangledName;
}
size_t TType::getObjectSize() const
{
size_t totalSize;
if (getBasicType() == EbtStruct)
totalSize = structure->objectSize();
else
totalSize = primarySize * secondarySize;
if (isArray())
{
if (totalSize == 0)
return 0;
size_t currentArraySize = getArraySize();
if (currentArraySize > INT_MAX / totalSize)
totalSize = INT_MAX;
else
totalSize *= currentArraySize;
}
return totalSize;
}
int TType::getLocationCount() const
{
int count = 1;
if (getBasicType() == EbtStruct)
{
count = structure->getLocationCount();
}
if (isArray())
{
if (count == 0)
{
return 0;
}
unsigned int currentArraySize = getArraySize();
if (currentArraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count))
{
count = std::numeric_limits<int>::max();
}
else
{
count *= static_cast<int>(currentArraySize);
}
}
return count;
}
TStructure::TStructure(const TString *name, TFieldList *fields)
: TFieldListCollection(name, fields),
mDeepestNesting(0),
mUniqueId(TSymbolTable::nextUniqueId()),
mAtGlobalScope(false)
{
}
bool TStructure::containsArrays() const
{
for (size_t i = 0; i < mFields->size(); ++i)
{
const TType *fieldType = (*mFields)[i]->type();
if (fieldType->isArray() || fieldType->isStructureContainingArrays())
return true;
}
return false;
}
bool TStructure::containsType(TBasicType type) const
{
for (size_t i = 0; i < mFields->size(); ++i)
{
const TType *fieldType = (*mFields)[i]->type();
if (fieldType->getBasicType() == type || fieldType->isStructureContainingType(type))
return true;
}
return false;
}
bool TStructure::containsSamplers() const
{
for (size_t i = 0; i < mFields->size(); ++i)
{
const TType *fieldType = (*mFields)[i]->type();
if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers())
return true;
}
return false;
}
void TStructure::createSamplerSymbols(const TString &structName,
const TString &structAPIName,
const unsigned int arrayOfStructsSize,
TVector<TIntermSymbol *> *outputSymbols,
TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const
{
for (auto &field : *mFields)
{
const TType *fieldType = field->type();
if (IsSampler(fieldType->getBasicType()))
{
if (arrayOfStructsSize > 0u)
{
for (unsigned int arrayIndex = 0u; arrayIndex < arrayOfStructsSize; ++arrayIndex)
{
TStringStream name;
name << structName << "_" << arrayIndex << "_" << field->name();
TIntermSymbol *symbol = new TIntermSymbol(0, name.str(), *fieldType);
outputSymbols->push_back(symbol);
if (outputSymbolsToAPINames)
{
TStringStream apiName;
apiName << structAPIName << "[" << arrayIndex << "]." << field->name();
(*outputSymbolsToAPINames)[symbol] = apiName.str();
}
}
}
else
{
TString symbolName = structName + "_" + field->name();
TIntermSymbol *symbol = new TIntermSymbol(0, symbolName, *fieldType);
outputSymbols->push_back(symbol);
if (outputSymbolsToAPINames)
{
TString apiName = structAPIName + "." + field->name();
(*outputSymbolsToAPINames)[symbol] = apiName;
}
}
}
else if (fieldType->isStructureContainingSamplers())
{
unsigned int nestedArrayOfStructsSize =
fieldType->isArray() ? fieldType->getArraySize() : 0u;
if (arrayOfStructsSize > 0)
{
for (unsigned int arrayIndex = 0u; arrayIndex < arrayOfStructsSize; ++arrayIndex)
{
TStringStream fieldName;
fieldName << structName << "_" << arrayIndex << "_" << field->name();
TStringStream fieldAPIName;
if (outputSymbolsToAPINames)
{
fieldAPIName << structAPIName << "[" << arrayIndex << "]." << field->name();
}
fieldType->createSamplerSymbols(fieldName.str(), fieldAPIName.str(),
nestedArrayOfStructsSize, outputSymbols,
outputSymbolsToAPINames);
}
}
else
{
fieldType->createSamplerSymbols(
structName + "_" + field->name(), structAPIName + "." + field->name(),
nestedArrayOfStructsSize, outputSymbols, outputSymbolsToAPINames);
}
}
}
}
TString TFieldListCollection::buildMangledName(const TString &mangledNamePrefix) const
{
TString mangledName(mangledNamePrefix);
mangledName += *mName;
for (size_t i = 0; i < mFields->size(); ++i)
{
mangledName += '-';
mangledName += (*mFields)[i]->type()->getMangledName();
}
return mangledName;
}
size_t TFieldListCollection::calculateObjectSize() const
{
size_t size = 0;
for (const TField *field : *mFields)
{
size_t fieldSize = field->type()->getObjectSize();
if (fieldSize > INT_MAX - size)
size = INT_MAX;
else
size += fieldSize;
}
return size;
}
int TFieldListCollection::getLocationCount() const
{
int count = 0;
for (const TField *field : *mFields)
{
int fieldCount = field->type()->getLocationCount();
if (fieldCount > std::numeric_limits<int>::max() - count)
{
count = std::numeric_limits<int>::max();
}
else
{
count += fieldCount;
}
}
return count;
}
int TStructure::calculateDeepestNesting() const
{
int maxNesting = 0;
for (size_t i = 0; i < mFields->size(); ++i)
maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting());
return 1 + maxNesting;
}
} // namespace sh