Imported a few ES3 fixes from Angle
Imported some of the more trivial bug fixes:
- Added a few missing interface block cases
- Added checks for varying structs
- Added checks for unsized arrays
- Added first-class array check for pre ES3 compilation
- Added check that ES3 functions do not use builtin names (ES3 only)
- Added more binary operator checks
Change-Id: I3d75453f17e1123478ef7da0998e869970a7fb7d
Reviewed-on: https://swiftshader-review.googlesource.com/8289
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/Intermediate.cpp b/src/OpenGL/compiler/Intermediate.cpp
index dbbfb19..a6b1b82 100644
--- a/src/OpenGL/compiler/Intermediate.cpp
+++ b/src/OpenGL/compiler/Intermediate.cpp
@@ -62,6 +62,134 @@
}
}
+TOperator TypeToConstructorOperator(const TType &type)
+{
+ switch(type.getBasicType())
+ {
+ case EbtFloat:
+ if(type.isMatrix())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2:
+ switch(type.getSecondarySize())
+ {
+ case 2:
+ return EOpConstructMat2;
+ case 3:
+ return EOpConstructMat2x3;
+ case 4:
+ return EOpConstructMat2x4;
+ default:
+ break;
+ }
+ break;
+
+ case 3:
+ switch(type.getSecondarySize())
+ {
+ case 2:
+ return EOpConstructMat3x2;
+ case 3:
+ return EOpConstructMat3;
+ case 4:
+ return EOpConstructMat3x4;
+ default:
+ break;
+ }
+ break;
+
+ case 4:
+ switch(type.getSecondarySize())
+ {
+ case 2:
+ return EOpConstructMat4x2;
+ case 3:
+ return EOpConstructMat4x3;
+ case 4:
+ return EOpConstructMat4;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch(type.getNominalSize())
+ {
+ case 1:
+ return EOpConstructFloat;
+ case 2:
+ return EOpConstructVec2;
+ case 3:
+ return EOpConstructVec3;
+ case 4:
+ return EOpConstructVec4;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case EbtInt:
+ switch(type.getNominalSize())
+ {
+ case 1:
+ return EOpConstructInt;
+ case 2:
+ return EOpConstructIVec2;
+ case 3:
+ return EOpConstructIVec3;
+ case 4:
+ return EOpConstructIVec4;
+ default:
+ break;
+ }
+ break;
+
+ case EbtUInt:
+ switch(type.getNominalSize())
+ {
+ case 1:
+ return EOpConstructUInt;
+ case 2:
+ return EOpConstructUVec2;
+ case 3:
+ return EOpConstructUVec3;
+ case 4:
+ return EOpConstructUVec4;
+ default:
+ break;
+ }
+ break;
+
+ case EbtBool:
+ switch(type.getNominalSize())
+ {
+ case 1:
+ return EOpConstructBool;
+ case 2:
+ return EOpConstructBVec2;
+ case 3:
+ return EOpConstructBVec3;
+ case 4:
+ return EOpConstructBVec4;
+ default:
+ break;
+ }
+ break;
+
+ case EbtStruct:
+ return EOpConstructStruct;
+
+ default:
+ break;
+ }
+
+ return EOpNull;
+}
+
const char* getOperatorString(TOperator op) {
switch (op) {
case EOpInitialize: return "=";
@@ -657,6 +785,17 @@
//
////////////////////////////////////////////////////////////////
+// static
+TIntermTyped *TIntermTyped::CreateIndexNode(int index)
+{
+ ConstantUnion *u = new ConstantUnion[1];
+ u[0].setIConst(index);
+
+ TType type(EbtInt, EbpUndefined, EvqConstExpr, 1);
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
+ return node;
+}
+
//
// Say whether or not an operation node changes the value of a variable.
//
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index 7bd7e64..83f58ce 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -28,6 +28,77 @@
//
////////////////////////////////////////////////////////////////////////
+namespace
+{
+ bool IsVaryingOut(TQualifier qualifier)
+ {
+ switch(qualifier)
+ {
+ case EvqVaryingOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqCentroidOut:
+ case EvqVertexOut:
+ return true;
+
+ default: break;
+ }
+
+ return false;
+ }
+
+ bool IsVaryingIn(TQualifier qualifier)
+ {
+ switch(qualifier)
+ {
+ case EvqVaryingIn:
+ case EvqSmoothIn:
+ case EvqFlatIn:
+ case EvqCentroidIn:
+ case EvqFragmentIn:
+ return true;
+
+ default: break;
+ }
+
+ return false;
+ }
+
+ bool IsVarying(TQualifier qualifier)
+ {
+ return IsVaryingIn(qualifier) || IsVaryingOut(qualifier);
+ }
+
+ bool IsAssignment(TOperator op)
+ {
+ switch(op)
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ case EOpAssign:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ case EOpDivAssign:
+ case EOpIModAssign:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
+
//
// Look at a '.' field selector string and change it into offsets
// for a vector.
@@ -282,6 +353,7 @@
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
return lValueErrorCheck(line, op, binaryNode->getLeft());
case EOpVectorSwizzle:
errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
@@ -756,7 +828,7 @@
if (IsSampler(type.getBasicType()))
return true;
- if (type.getBasicType() == EbtStruct) {
+ if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
const TFieldList& fields = type.getStruct()->fields();
for(unsigned int i = 0; i < fields.size(); ++i) {
if (containsSampler(*fields[i]->type()))
@@ -776,7 +848,7 @@
{
TIntermConstantUnion* constant = expr->getAsConstantUnion();
- if (constant == 0 || !constant->isScalarInt())
+ if (expr->getQualifier() != EvqConstExpr || constant == 0 || !constant->isScalarInt())
{
error(line, "array size must be a constant integer expression", "");
return true;
@@ -798,14 +870,20 @@
{
size = constant->getIConst(0);
- if (size <= 0)
+ if (size < 0)
{
- error(line, "array size must be a positive integer", "");
+ error(line, "array size must be non-negative", "");
size = 1;
return true;
}
}
+ if(size == 0)
+ {
+ error(line, "array size must be greater than zero", "");
+ return true;
+ }
+
return false;
}
@@ -839,6 +917,15 @@
return true;
}
+ // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
+ // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section 4.3.4).
+ if(mShaderVersion >= 300 && type.type == EbtStruct && IsVarying(type.qualifier))
+ {
+ error(line, "cannot declare arrays of structs of this qualifier",
+ TType(type).getCompleteString().c_str());
+ return true;
+ }
+
return false;
}
@@ -1191,9 +1278,19 @@
ASSERT(intermNode != nullptr);
TType type = TType(pType);
- if(type.isArray() && (type.getArraySize() == 0))
+ if(type.isUnsizedArray())
{
- type.setArraySize(initializer->getArraySize());
+ // We have not checked yet whether the initializer actually is an array or not.
+ if(initializer->isArray())
+ {
+ type.setArraySize(initializer->getArraySize());
+ }
+ else
+ {
+ // Having a non-array initializer for an unsized array will result in an error later,
+ // so we don't generate an error message here.
+ type.setArraySize(1u);
+ }
}
TVariable *variable = nullptr;
@@ -1285,6 +1382,12 @@
if(mShaderVersion < 300)
{
+ if(typeSpecifier.array)
+ {
+ error(typeSpecifier.line, "not supported", "first-class array");
+ returnType.clearArrayness();
+ }
+
if(qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
{
error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
@@ -1300,44 +1403,87 @@
}
else
{
- switch(qualifier)
+ if(!returnType.layoutQualifier.isEmpty())
{
- case EvqSmoothIn:
- case EvqSmoothOut:
- case EvqVertexOut:
- case EvqFragmentIn:
- case EvqCentroidOut:
- case EvqCentroidIn:
- if(typeSpecifier.type == EbtBool)
- {
- error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
- recover();
- }
- if(typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
- {
- error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier));
- recover();
- }
- break;
+ globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout");
+ }
- case EvqVertexIn:
- case EvqFragmentOut:
- case EvqFlatIn:
- case EvqFlatOut:
- if(typeSpecifier.type == EbtBool)
- {
- error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
- recover();
- }
- break;
-
- default: break;
+ if(IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || returnType.qualifier == EvqFragmentOut)
+ {
+ checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, typeSpecifier.line);
}
}
return returnType;
}
+void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
+ const TPublicType &type,
+ const TSourceLoc &qualifierLocation)
+{
+ // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
+ if(type.type == EbtBool)
+ {
+ error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
+ }
+
+ // Specific restrictions apply for vertex shader inputs and fragment shader outputs.
+ switch(qualifier)
+ {
+ case EvqVertexIn:
+ // ESSL 3.00 section 4.3.4
+ if(type.array)
+ {
+ error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
+ }
+ // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck
+ return;
+ case EvqFragmentOut:
+ // ESSL 3.00 section 4.3.6
+ if(type.isMatrix())
+ {
+ error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
+ }
+ // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck
+ return;
+ default:
+ break;
+ }
+
+ // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
+ // restrictions.
+ bool typeContainsIntegers = (type.type == EbtInt || type.type == EbtUInt ||
+ type.isStructureContainingType(EbtInt) ||
+ type.isStructureContainingType(EbtUInt));
+ if(typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
+ {
+ error(qualifierLocation, "must use 'flat' interpolation here", getQualifierString(qualifier));
+ }
+
+ if(type.type == EbtStruct)
+ {
+ // ESSL 3.00 sections 4.3.4 and 4.3.6.
+ // These restrictions are only implied by the ESSL 3.00 spec, but
+ // the ESSL 3.10 spec lists these restrictions explicitly.
+ if(type.array)
+ {
+ error(qualifierLocation, "cannot be an array of structures", getQualifierString(qualifier));
+ }
+ if(type.isStructureContainingArrays())
+ {
+ error(qualifierLocation, "cannot be a structure containing an array", getQualifierString(qualifier));
+ }
+ if(type.isStructureContainingType(EbtStruct))
+ {
+ error(qualifierLocation, "cannot be a structure containing a structure", getQualifierString(qualifier));
+ }
+ if(type.isStructureContainingType(EbtBool))
+ {
+ error(qualifierLocation, "cannot be a structure containing a bool", getQualifierString(qualifier));
+ }
+ }
+}
+
TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
const TSourceLoc &identifierOrTypeLocation,
const TString &identifier)
@@ -1915,7 +2061,13 @@
// here.
//
TFunction *prevDec = static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
- if(prevDec)
+ if(getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltIn(function->getName().c_str()))
+ {
+ // With ESSL 3.00, names of built-in functions cannot be redeclared as functions.
+ // Therefore overloading or redefining builtin functions is an error.
+ error(location, "Name of a built-in function cannot be redeclared as function", function->getName().c_str());
+ }
+ else if(prevDec)
{
if(prevDec->getReturnType() != function->getReturnType())
{
@@ -1969,84 +2121,7 @@
}
else
{
- switch(publicType.type)
- {
- case EbtFloat:
- if(publicType.isMatrix())
- {
- switch(publicType.getCols())
- {
- case 2:
- switch(publicType.getRows())
- {
- case 2: op = EOpConstructMat2; break;
- case 3: op = EOpConstructMat2x3; break;
- case 4: op = EOpConstructMat2x4; break;
- }
- break;
- case 3:
- switch(publicType.getRows())
- {
- case 2: op = EOpConstructMat3x2; break;
- case 3: op = EOpConstructMat3; break;
- case 4: op = EOpConstructMat3x4; break;
- }
- break;
- case 4:
- switch(publicType.getRows())
- {
- case 2: op = EOpConstructMat4x2; break;
- case 3: op = EOpConstructMat4x3; break;
- case 4: op = EOpConstructMat4; break;
- }
- break;
- }
- }
- else
- {
- switch(publicType.getNominalSize())
- {
- case 1: op = EOpConstructFloat; break;
- case 2: op = EOpConstructVec2; break;
- case 3: op = EOpConstructVec3; break;
- case 4: op = EOpConstructVec4; break;
- }
- }
- break;
-
- case EbtInt:
- switch(publicType.getNominalSize())
- {
- case 1: op = EOpConstructInt; break;
- case 2: op = EOpConstructIVec2; break;
- case 3: op = EOpConstructIVec3; break;
- case 4: op = EOpConstructIVec4; break;
- }
- break;
-
- case EbtUInt:
- switch(publicType.getNominalSize())
- {
- case 1: op = EOpConstructUInt; break;
- case 2: op = EOpConstructUVec2; break;
- case 3: op = EOpConstructUVec3; break;
- case 4: op = EOpConstructUVec4; break;
- }
- break;
-
- case EbtBool:
- switch(publicType.getNominalSize())
- {
- case 1: op = EOpConstructBool; break;
- case 2: op = EOpConstructBVec2; break;
- case 3: op = EOpConstructBVec3; break;
- case 4: op = EOpConstructBVec4; break;
- }
- break;
-
- default: break;
- }
-
+ op = TypeToConstructorOperator(TType(publicType));
if(op == EOpNull)
{
error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
@@ -2717,9 +2792,8 @@
}
else
{
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setIConst(i);
- TIntermTyped *index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
+ TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
+ index->setLine(fieldLocation);
indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation);
indexedExpression->setType(*fields[i]->type());
}
@@ -3237,6 +3311,46 @@
{
return false;
}
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpIMod:
+ case EOpBitShiftLeft:
+ case EOpBitShiftRight:
+ case EOpBitwiseAnd:
+ case EOpBitwiseXor:
+ case EOpBitwiseOr:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpDivAssign:
+ case EOpIModAssign:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ if((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()))
+ {
+ return false;
+ }
+
+ // Are the sizes compatible?
+ if(left->getNominalSize() != right->getNominalSize() || left->getSecondarySize() != right->getSecondarySize())
+ {
+ // If the nominal sizes of operands do not match:
+ // One of them must be a scalar.
+ if(!left->isScalar() && !right->isScalar())
+ return false;
+
+ // In the case of compound assignment other than multiply-assign,
+ // the right side needs to be a scalar. Otherwise a vector/matrix
+ // would be assigned to a scalar. A scalar can't be shifted by a
+ // vector either.
+ if(!right->isScalar() && (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight))
+ return false;
+ }
+ break;
default:
break;
}
diff --git a/src/OpenGL/compiler/ParseHelper.h b/src/OpenGL/compiler/ParseHelper.h
index 8733ef5..ea613eb 100644
--- a/src/OpenGL/compiler/ParseHelper.h
+++ b/src/OpenGL/compiler/ParseHelper.h
@@ -142,6 +142,7 @@
bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier);
bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *);
void es3InvariantErrorCheck(const TQualifier qualifier, const TSourceLoc &invariantLocation);
+ void checkInputOutputTypeIsValidES3(const TQualifier qualifier, const TPublicType &type, const TSourceLoc &qualifierLocation);
const TExtensionBehavior& extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); }
bool supportsExtension(const char* extension);
diff --git a/src/OpenGL/compiler/SymbolTable.cpp b/src/OpenGL/compiler/SymbolTable.cpp
index 39023ae..004a1d7 100644
--- a/src/OpenGL/compiler/SymbolTable.cpp
+++ b/src/OpenGL/compiler/SymbolTable.cpp
@@ -121,6 +121,17 @@
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)
diff --git a/src/OpenGL/compiler/SymbolTable.h b/src/OpenGL/compiler/SymbolTable.h
index d8c6029..c4fdbfe 100644
--- a/src/OpenGL/compiler/SymbolTable.h
+++ b/src/OpenGL/compiler/SymbolTable.h
@@ -369,6 +369,7 @@
{
if(ptype1->getBasicType() == EbtGSampler2D)
{
+ insertUnmangledBuiltIn(name);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5);
@@ -376,6 +377,7 @@
}
else if(ptype1->getBasicType() == EbtGSampler3D)
{
+ insertUnmangledBuiltIn(name);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5);
@@ -383,6 +385,7 @@
}
else if(ptype1->getBasicType() == EbtGSamplerCube)
{
+ insertUnmangledBuiltIn(name);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5);
@@ -390,6 +393,7 @@
}
else if(ptype1->getBasicType() == EbtGSampler2DArray)
{
+ insertUnmangledBuiltIn(name);
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5);
insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
@@ -398,6 +402,7 @@
else if(IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3))
{
ASSERT(!ptype4);
+ insertUnmangledBuiltIn(name);
insertBuiltIn(level, op, ext, GenType(rvalue, 1), name, GenType(ptype1, 1), GenType(ptype2, 1), GenType(ptype3, 1));
insertBuiltIn(level, op, ext, GenType(rvalue, 2), name, GenType(ptype1, 2), GenType(ptype2, 2), GenType(ptype3, 2));
insertBuiltIn(level, op, ext, GenType(rvalue, 3), name, GenType(ptype1, 3), GenType(ptype2, 3), GenType(ptype3, 3));
@@ -406,6 +411,7 @@
else if(IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3))
{
ASSERT(!ptype4);
+ insertUnmangledBuiltIn(name);
insertBuiltIn(level, op, ext, VecType(rvalue, 2), name, VecType(ptype1, 2), VecType(ptype2, 2), VecType(ptype3, 2));
insertBuiltIn(level, op, ext, VecType(rvalue, 3), name, VecType(ptype1, 3), VecType(ptype2, 3), VecType(ptype3, 3));
insertBuiltIn(level, op, ext, VecType(rvalue, 4), name, VecType(ptype1, 4), VecType(ptype2, 4), VecType(ptype3, 4));
@@ -441,17 +447,20 @@
function->addParameter(param5);
}
+ ASSERT(hasUnmangledBuiltIn(name));
insert(level, *function);
}
}
void insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
{
+ insertUnmangledBuiltIn(name);
insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
{
+ insertUnmangledBuiltIn(name);
insertBuiltIn(level, EOpNull, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
@@ -518,6 +527,12 @@
void setGlobalInvariant() { mGlobalInvariant = true; }
bool getGlobalInvariant() const { return mGlobalInvariant; }
+ bool hasUnmangledBuiltIn(const char *name) { return mUnmangledBuiltinNames.count(std::string(name)) > 0; }
+
+private:
+ // Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00.
+ void insertUnmangledBuiltIn(const char *name) { mUnmangledBuiltinNames.insert(std::string(name)); }
+
protected:
ESymbolLevel currentLevel() const { return static_cast<ESymbolLevel>(table.size() - 1); }
@@ -525,6 +540,8 @@
typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
std::vector< PrecisionStackLevel > precisionStack;
+ std::set<std::string> mUnmangledBuiltinNames;
+
std::set<std::string> mInvariantVaryings;
bool mGlobalInvariant;
};
diff --git a/src/OpenGL/compiler/Types.h b/src/OpenGL/compiler/Types.h
index f24f9e6..d4d98d0 100644
--- a/src/OpenGL/compiler/Types.h
+++ b/src/OpenGL/compiler/Types.h
@@ -132,6 +132,7 @@
return mDeepestNesting;
}
bool containsArrays() const;
+ bool containsType(TBasicType type) const;
bool containsSamplers() const;
bool equals(const TStructure &other) const;
@@ -381,6 +382,7 @@
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; }
@@ -468,6 +470,11 @@
return structure ? structure->containsArrays() : false;
}
+ bool isStructureContainingType(TBasicType t) const
+ {
+ return structure ? structure->containsType(t) : false;
+ }
+
bool isStructureContainingSamplers() const
{
return structure ? structure->containsSamplers() : false;
@@ -576,6 +583,16 @@
return userDef->isStructureContainingArrays();
}
+ bool isStructureContainingType(TBasicType t) const
+ {
+ if(!userDef)
+ {
+ return false;
+ }
+
+ return userDef->isStructureContainingType(t);
+ }
+
bool isMatrix() const
{
return primarySize > 1 && secondarySize > 1;
diff --git a/src/OpenGL/compiler/intermediate.h b/src/OpenGL/compiler/intermediate.h
index 740fb71..7757d89 100644
--- a/src/OpenGL/compiler/intermediate.h
+++ b/src/OpenGL/compiler/intermediate.h
@@ -238,6 +238,7 @@
EOpBitwiseOrAssign
};
+extern TOperator TypeToConstructorOperator(const TType &type);
extern const char* getOperatorString(TOperator op);
class TIntermTraverser;
@@ -334,6 +335,7 @@
int registerSize() const { return type.registerSize(); }
int getArraySize() const { return type.getArraySize(); }
+ static TIntermTyped *CreateIndexNode(int index);
protected:
TType type;
};