Commit e5246698 by Alexis Hetu Committed by Alexis Hétu

Adding unsized arrays to the glsl parser

Unsized arrays declare with an empty [] without a specified size are now supported properly in the glsl parser. Also moved the construction code from the parser into TParseContext. Change-Id: Ic7b3efeee51da1a264e26af4d7908e7d2fccebd9 Reviewed-on: https://swiftshader-review.googlesource.com/3520Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <capn@google.com>
parent 3713cd4b
...@@ -39,6 +39,7 @@ LOCAL_SRC_FILES += \ ...@@ -39,6 +39,7 @@ LOCAL_SRC_FILES += \
SymbolTable.cpp \ SymbolTable.cpp \
TranslatorASM.cpp \ TranslatorASM.cpp \
util.cpp \ util.cpp \
ValidateGlobalInitializer.cpp \
ValidateLimitations.cpp \ ValidateLimitations.cpp \
ValidateSwitch.cpp \ ValidateSwitch.cpp \
......
...@@ -213,6 +213,7 @@ ...@@ -213,6 +213,7 @@
<ClCompile Include="SymbolTable.cpp" /> <ClCompile Include="SymbolTable.cpp" />
<ClCompile Include="TranslatorASM.cpp" /> <ClCompile Include="TranslatorASM.cpp" />
<ClCompile Include="util.cpp" /> <ClCompile Include="util.cpp" />
<ClCompile Include="ValidateGlobalInitializer.cpp" />
<ClCompile Include="ValidateLimitations.cpp" /> <ClCompile Include="ValidateLimitations.cpp" />
<ClCompile Include="glslang_lex.cpp" /> <ClCompile Include="glslang_lex.cpp" />
<ClCompile Include="glslang_tab.cpp" /> <ClCompile Include="glslang_tab.cpp" />
...@@ -317,6 +318,7 @@ ...@@ -317,6 +318,7 @@
<ClInclude Include="TranslatorASM.h" /> <ClInclude Include="TranslatorASM.h" />
<ClInclude Include="Types.h" /> <ClInclude Include="Types.h" />
<ClInclude Include="util.h" /> <ClInclude Include="util.h" />
<ClInclude Include="ValidateGlobalInitializer.h" />
<ClInclude Include="ValidateLimitations.h" /> <ClInclude Include="ValidateLimitations.h" />
<ClInclude Include="glslang_tab.h" /> <ClInclude Include="glslang_tab.h" />
<ClInclude Include="ValidateSwitch.h" /> <ClInclude Include="ValidateSwitch.h" />
......
...@@ -86,6 +86,9 @@ ...@@ -86,6 +86,9 @@
<ClCompile Include="ValidateSwitch.cpp"> <ClCompile Include="ValidateSwitch.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="ValidateGlobalInitializer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="BaseTypes.h"> <ClInclude Include="BaseTypes.h">
...@@ -175,6 +178,9 @@ ...@@ -175,6 +178,9 @@
<ClInclude Include="ValidateSwitch.h"> <ClInclude Include="ValidateSwitch.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ValidateGlobalInitializer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="glslang.l"> <CustomBuild Include="glslang.l">
......
...@@ -780,11 +780,7 @@ bool TIntermUnary::promote(TInfoSink&) ...@@ -780,11 +780,7 @@ bool TIntermUnary::promote(TInfoSink&)
// //
bool TIntermBinary::promote(TInfoSink& infoSink) bool TIntermBinary::promote(TInfoSink& infoSink)
{ {
// This function only handles scalars, vectors, and matrices. ASSERT(left->isArray() == right->isArray());
if (left->isArray() || right->isArray()) {
infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine());
return false;
}
// GLSL ES 2.0 does not support implicit type casting. // GLSL ES 2.0 does not support implicit type casting.
// So the basic type should always match. // So the basic type should always match.
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "glslang.h" #include "glslang.h"
#include "preprocessor/SourceLocation.h" #include "preprocessor/SourceLocation.h"
#include "ValidateGlobalInitializer.h"
#include "ValidateSwitch.h" #include "ValidateSwitch.h"
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
...@@ -462,7 +463,13 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, TIntermNode* n ...@@ -462,7 +463,13 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, TIntermNode* n
bool constructingMatrix = false; bool constructingMatrix = false;
switch(op) { switch(op) {
case EOpConstructMat2: case EOpConstructMat2:
case EOpConstructMat2x3:
case EOpConstructMat2x4:
case EOpConstructMat3x2:
case EOpConstructMat3: case EOpConstructMat3:
case EOpConstructMat3x4:
case EOpConstructMat4x2:
case EOpConstructMat4x3:
case EOpConstructMat4: case EOpConstructMat4:
constructingMatrix = true; constructingMatrix = true;
break; break;
...@@ -501,10 +508,14 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, TIntermNode* n ...@@ -501,10 +508,14 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, TIntermNode* n
if (constType) if (constType)
type->setQualifier(EvqConstExpr); type->setQualifier(EvqConstExpr);
if (type->isArray() && type->getArraySize() != function.getParamCount()) { if(type->isArray()) {
if(type->getArraySize() == 0) {
type->setArraySize(function.getParamCount());
} else if(type->getArraySize() != function.getParamCount()) {
error(line, "array constructor needs one argument per array element", "constructor"); error(line, "array constructor needs one argument per array element", "constructor");
return true; return true;
} }
}
if (arrayArg && op != EOpConstructStruct) { if (arrayArg && op != EOpConstructStruct) {
error(line, "constructing from a non-dereferenced array", "constructor"); error(line, "constructing from a non-dereferenced array", "constructor");
...@@ -833,79 +844,6 @@ bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, TPublicType type ...@@ -833,79 +844,6 @@ bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, TPublicType type
return false; return false;
} }
//
// Do all the semantic checking for declaring an array, with and
// without a size, and make the right changes to the symbol table.
//
// size == 0 means no specified size.
//
// Returns true if there was an error.
//
bool TParseContext::arrayErrorCheck(const TSourceLoc &line, TString& identifier, TPublicType type, TVariable*& variable)
{
//
// Don't check for reserved word use until after we know it's not in the symbol table,
// because reserved arrays can be redeclared.
//
bool builtIn = false;
bool sameScope = false;
TSymbol* symbol = symbolTable.find(identifier, shaderVersion, &builtIn, &sameScope);
if (symbol == 0 || !sameScope) {
if (reservedErrorCheck(line, identifier))
return true;
variable = new TVariable(&identifier, TType(type));
if (type.arraySize)
variable->getType().setArraySize(type.arraySize);
if (! symbolTable.declare(*variable)) {
delete variable;
error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str());
return true;
}
} else {
if (! symbol->isVariable()) {
error(line, "variable expected", identifier.c_str());
return true;
}
variable = static_cast<TVariable*>(symbol);
if (! variable->getType().isArray()) {
error(line, "redeclaring non-array as array", identifier.c_str());
return true;
}
if (variable->getType().getArraySize() > 0) {
error(line, "redeclaration of array with size", identifier.c_str());
return true;
}
if (! variable->getType().sameElementType(TType(type))) {
error(line, "redeclaration of array with a different type", identifier.c_str());
return true;
}
TType* t = variable->getArrayInformationType();
while (t != 0) {
if (t->getMaxArraySize() > type.arraySize) {
error(line, "higher index value already used for the array", identifier.c_str());
return true;
}
t->setArraySize(type.arraySize);
t = t->getArrayInformationType();
}
if (type.arraySize)
variable->getType().setArraySize(type.arraySize);
}
if (voidErrorCheck(line, identifier, type.type))
return true;
return false;
}
bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, const TSourceLoc &line) bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, const TSourceLoc &line)
{ {
bool builtIn = false; bool builtIn = false;
...@@ -1234,27 +1172,33 @@ const TFunction* TParseContext::findFunction(const TSourceLoc &line, TFunction* ...@@ -1234,27 +1172,33 @@ const TFunction* TParseContext::findFunction(const TSourceLoc &line, TFunction*
// code to handle them here. // code to handle them here.
// //
bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, const TPublicType& pType, bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, const TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable) TIntermTyped *initializer, TIntermNode **intermNode)
{ {
ASSERT(intermNode != nullptr);
TType type = TType(pType); TType type = TType(pType);
if (variable == 0) { TVariable *variable = nullptr;
if (reservedErrorCheck(line, identifier)) if(type.isArray() && (type.getArraySize() == 0))
return true; {
type.setArraySize(initializer->getArraySize());
if (voidErrorCheck(line, identifier, pType.type)) }
if(!declareVariable(line, identifier, type, &variable))
{
return true; return true;
}
// bool globalInitWarning = false;
// add variable to symbol table if(symbolTable.atGlobalLevel() && !ValidateGlobalInitializer(initializer, this, &globalInitWarning))
// {
variable = new TVariable(&identifier, type); // Error message does not completely match behavior with ESSL 1.00, but
if (! symbolTable.declare(*variable)) { // we want to steer developers towards only using constant expressions.
error(line, "redefinition", variable->getName().c_str()); error(line, "global variable initializers must be constant expressions", "=");
return true; return true;
// don't delete variable, it's used by error recovery, and the pool
// pop will take care of the memory
} }
if(globalInitWarning)
{
warning(line, "global variable initializers should be constant expressions "
"(uniforms and globals are allowed in global initializers for legacy compatibility)", "=");
} }
// //
...@@ -1285,15 +1229,9 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id ...@@ -1285,15 +1229,9 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
return true; return true;
} }
if (initializer->getAsConstantUnion()) { if (initializer->getAsConstantUnion()) {
ConstantUnion* unionArray = variable->getConstPointer();
if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) {
*unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0];
} else {
variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
}
} else if (initializer->getAsSymbolNode()) { } else if (initializer->getAsSymbolNode()) {
const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), shaderVersion); const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
const TVariable* tVar = static_cast<const TVariable*>(symbol); const TVariable* tVar = static_cast<const TVariable*>(symbol);
ConstantUnion* constArray = tVar->getConstPointer(); ConstantUnion* constArray = tVar->getConstPointer();
...@@ -1310,13 +1248,13 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id ...@@ -1310,13 +1248,13 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
if (qualifier != EvqConstExpr) { if (qualifier != EvqConstExpr) {
TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
if (intermNode == 0) { if(*intermNode == nullptr) {
assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
return true; return true;
} }
} else } else
intermNode = 0; *intermNode = nullptr;
return false; return false;
} }
...@@ -1500,7 +1438,7 @@ TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &p ...@@ -1500,7 +1438,7 @@ TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &p
recover(); recover();
TIntermNode *intermNode = nullptr; TIntermNode *intermNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode)) if(!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
{ {
// //
// Build intermediate representation // Build intermediate representation
...@@ -1546,7 +1484,7 @@ TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(TPublicType &pu ...@@ -1546,7 +1484,7 @@ TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(TPublicType &pu
// initNode will correspond to the whole of "type b[n] = initializer". // initNode will correspond to the whole of "type b[n] = initializer".
TIntermNode *initNode = nullptr; TIntermNode *initNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, initNode)) if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
{ {
return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr; return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
} }
...@@ -1686,7 +1624,7 @@ TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicTy ...@@ -1686,7 +1624,7 @@ TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicTy
recover(); recover();
TIntermNode *intermNode = nullptr; TIntermNode *intermNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode)) if(!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
{ {
// //
// build the intermediate representation // build the intermediate representation
...@@ -1745,7 +1683,7 @@ TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &pub ...@@ -1745,7 +1683,7 @@ TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &pub
// initNode will correspond to the whole of "b[n] = initializer". // initNode will correspond to the whole of "b[n] = initializer".
TIntermNode *initNode = nullptr; TIntermNode *initNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, initNode)) if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
{ {
if(initNode) if(initNode)
{ {
...@@ -1799,6 +1737,108 @@ void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier) ...@@ -1799,6 +1737,108 @@ void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
} }
} }
TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
{
TPublicType publicType = publicTypeIn;
TOperator op = EOpNull;
if(publicType.userDef)
{
op = EOpConstructStruct;
}
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;
}
if(op == EOpNull)
{
error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
recover();
publicType.type = EbtFloat;
op = EOpConstructFloat;
}
}
TString tempString;
TType type(publicType);
return new TFunction(&tempString, type, op);
}
// This function is used to test for the correctness of the parameters passed to various constructor functions // This function is used to test for the correctness of the parameters passed to various constructor functions
// and also convert them to the right datatype if it is allowed and required. // and also convert them to the right datatype if it is allowed and required.
// //
...@@ -3054,6 +3094,26 @@ TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) ...@@ -3054,6 +3094,26 @@ TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
} }
return node; return node;
} }
TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc)
{
if(binaryOpCommonCheck(op, left, right, loc))
{
return intermediate.addAssign(op, left, right, loc);
}
return nullptr;
}
TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc)
{
TIntermTyped *node = createAssign(op, left, right, loc);
if(node == nullptr)
{
assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
recover();
return left;
}
return node;
}
TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &loc) const TSourceLoc &loc)
......
...@@ -106,7 +106,6 @@ struct TParseContext { ...@@ -106,7 +106,6 @@ struct TParseContext {
bool arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped* expr, int& size); bool arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped* expr, int& size);
bool arrayQualifierErrorCheck(const TSourceLoc &line, TPublicType type); bool arrayQualifierErrorCheck(const TSourceLoc &line, TPublicType type);
bool arrayTypeErrorCheck(const TSourceLoc &line, TPublicType type); bool arrayTypeErrorCheck(const TSourceLoc &line, TPublicType type);
bool arrayErrorCheck(const TSourceLoc &line, TString& identifier, TPublicType type, TVariable*& variable);
bool voidErrorCheck(const TSourceLoc&, const TString&, const TBasicType&); bool voidErrorCheck(const TSourceLoc&, const TString&, const TBasicType&);
bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*); bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*);
bool boolErrorCheck(const TSourceLoc&, const TPublicType&); bool boolErrorCheck(const TSourceLoc&, const TPublicType&);
...@@ -132,8 +131,8 @@ struct TParseContext { ...@@ -132,8 +131,8 @@ struct TParseContext {
bool containsSampler(TType& type); bool containsSampler(TType& type);
bool areAllChildConst(TIntermAggregate* aggrNode); bool areAllChildConst(TIntermAggregate* aggrNode);
const TFunction* findFunction(const TSourceLoc &line, TFunction* pfnCall, bool *builtIn = 0); const TFunction* findFunction(const TSourceLoc &line, TFunction* pfnCall, bool *builtIn = 0);
bool executeInitializer(const TSourceLoc &line, const TString& identifier, const TPublicType& pType, bool executeInitializer(const TSourceLoc &line, const TString &identifier, const TPublicType &pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0); TIntermTyped *initializer, TIntermNode **intermNode);
TPublicType addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier); TPublicType addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier);
bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, const TSourceLoc&); bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, const TSourceLoc&);
...@@ -166,6 +165,7 @@ struct TParseContext { ...@@ -166,6 +165,7 @@ struct TParseContext {
const TSourceLoc &initLocation, TIntermTyped *initializer); const TSourceLoc &initLocation, TIntermTyped *initializer);
void parseGlobalLayoutQualifier(const TPublicType &typeQualifier); void parseGlobalLayoutQualifier(const TPublicType &typeQualifier);
TFunction *addConstructorFunc(const TPublicType &publicType);
TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&); TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&);
TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type); TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&); TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&);
...@@ -203,6 +203,8 @@ struct TParseContext { ...@@ -203,6 +203,8 @@ struct TParseContext {
TIntermTyped *addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc); TIntermTyped *addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc); TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermTyped *addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc); TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc); TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
...@@ -210,6 +212,7 @@ private: ...@@ -210,6 +212,7 @@ private:
bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable); bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
TIntermTyped *addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc); TIntermTyped *addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermTyped *createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
// The funcReturnType parameter is expected to be non-null when the operation is a built-in function. // The funcReturnType parameter is expected to be non-null when the operation is a built-in function.
// It is expected to be null for other unary operators. // It is expected to be null for other unary operators.
......
//
// Copyright (c) 2002-2015 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.
//
#include "ValidateGlobalInitializer.h"
#include "ParseHelper.h"
namespace
{
class ValidateGlobalInitializerTraverser : public TIntermTraverser
{
public:
ValidateGlobalInitializerTraverser(const TParseContext *context);
void visitSymbol(TIntermSymbol *node) override;
bool isValid() const { return mIsValid; }
bool issueWarning() const { return mIssueWarning; }
private:
const TParseContext *mContext;
bool mIsValid;
bool mIssueWarning;
};
void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
{
const TSymbol *sym = mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion());
if (sym->isVariable())
{
// ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
// Global initializers must be constant expressions.
const TVariable *var = static_cast<const TVariable *>(sym);
switch (var->getType().getQualifier())
{
case EvqConstExpr:
break;
case EvqGlobal:
case EvqTemporary:
case EvqUniform:
// We allow these cases to be compatible with legacy ESSL 1.00 content.
// Implement stricter rules for ESSL 3.00 since there's no legacy content to deal with.
if (mContext->getShaderVersion() >= 300)
{
mIsValid = false;
}
else
{
mIssueWarning = true;
}
break;
default:
mIsValid = false;
}
}
}
ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
: TIntermTraverser(true, false, false),
mContext(context),
mIsValid(true),
mIssueWarning(false)
{
}
} // namespace
bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
{
ValidateGlobalInitializerTraverser validate(context);
initializer->traverse(&validate);
ASSERT(warning != nullptr);
*warning = validate.issueWarning();
return validate.isValid();
}
//
// Copyright (c) 2002-2015 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_VALIDATEGLOBALINITIALIZER_H_
#define COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
class TIntermTyped;
struct TParseContext;
// Returns true if the initializer is valid.
bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning);
#endif // COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
...@@ -448,82 +448,11 @@ function_call_header ...@@ -448,82 +448,11 @@ function_call_header
// Grammar Note: Constructors look like functions, but are recognized as types. // Grammar Note: Constructors look like functions, but are recognized as types.
function_identifier function_identifier
: type_specifier_nonarray { : type_specifier_no_prec {
// if ($1.array) {
// Constructor ES3_ONLY("[]", @1);
//
TOperator op = EOpNull;
if ($1.userDef) {
op = EOpConstructStruct;
} else {
switch ($1.type) {
case EbtFloat:
switch($1.primarySize) {
case 1:
op = EOpConstructFloat; break;
case 2:
switch($1.secondarySize) {
case 1: op = EOpConstructVec2; break;
case 2: op = EOpConstructMat2; break;
case 3: op = EOpConstructMat2x3; break;
case 4: op = EOpConstructMat2x4; break;
}
break;
case 3:
switch($1.secondarySize) {
case 1: op = EOpConstructVec3; break;
case 2: op = EOpConstructMat3x2; break;
case 3: op = EOpConstructMat3; break;
case 4: op = EOpConstructMat3x4; break;
}
break;
case 4:
switch($1.secondarySize) {
case 1: op = EOpConstructVec4; break;
case 2: op = EOpConstructMat4x2; break;
case 3: op = EOpConstructMat4x3; break;
case 4: op = EOpConstructMat4; break;
}
break;
}
break;
case EbtInt:
switch($1.primarySize) {
case 1: op = EOpConstructInt; break;
case 2: FRAG_VERT_ONLY("ivec2", @1); op = EOpConstructIVec2; break;
case 3: FRAG_VERT_ONLY("ivec3", @1); op = EOpConstructIVec3; break;
case 4: FRAG_VERT_ONLY("ivec4", @1); op = EOpConstructIVec4; break;
}
break;
case EbtUInt:
switch($1.primarySize) {
case 1: op = EOpConstructUInt; break;
case 2: FRAG_VERT_ONLY("uvec2", @1); op = EOpConstructUVec2; break;
case 3: FRAG_VERT_ONLY("uvec3", @1); op = EOpConstructUVec3; break;
case 4: FRAG_VERT_ONLY("uvec4", @1); op = EOpConstructUVec4; break;
}
break;
case EbtBool:
switch($1.primarySize) {
case 1: op = EOpConstructBool; break;
case 2: FRAG_VERT_ONLY("bvec2", @1); op = EOpConstructBVec2; break;
case 3: FRAG_VERT_ONLY("bvec3", @1); op = EOpConstructBVec3; break;
case 4: FRAG_VERT_ONLY("bvec4", @1); op = EOpConstructBVec4; break;
}
break;
default: break;
}
if (op == EOpNull) {
context->error(@1, "cannot construct this type", getBasicString($1.type));
context->recover();
$1.type = EbtFloat;
op = EOpConstructFloat;
}
} }
TString tempString; $$ = context->addConstructorFunc($1);
TType type($1);
TFunction *function = new TFunction(&tempString, type, op);
$$ = function;
} }
| IDENTIFIER { | IDENTIFIER {
if (context->reservedErrorCheck(@1, *$1.string)) if (context->reservedErrorCheck(@1, *$1.string))
...@@ -730,12 +659,7 @@ assignment_expression ...@@ -730,12 +659,7 @@ assignment_expression
| unary_expression assignment_operator assignment_expression { | unary_expression assignment_operator assignment_expression {
if (context->lValueErrorCheck(@2, "assign", $1)) if (context->lValueErrorCheck(@2, "assign", $1))
context->recover(); context->recover();
$$ = context->intermediate.addAssign($2.op, $1, $3, @2); $$ = context->addAssign($2.op, $1, $3, @2);
if ($$ == 0) {
context->assignError(@2, "assign", $1->getCompleteString(), $3->getCompleteString());
context->recover();
$$ = $1;
}
} }
; ;
...@@ -783,7 +707,7 @@ constant_expression ...@@ -783,7 +707,7 @@ constant_expression
enter_struct enter_struct
: IDENTIFIER LEFT_BRACE { : IDENTIFIER LEFT_BRACE {
if (context->enterStructDeclaration($1.line, *$1.string)) if (context->enterStructDeclaration(@1, *$1.string))
context->recover(); context->recover();
$$ = $1; $$ = $1;
} }
...@@ -831,16 +755,16 @@ declaration ...@@ -831,16 +755,16 @@ declaration
$$ = 0; $$ = 0;
} }
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON { | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line); ES3_ONLY(getQualifierString($1.qualifier), @1);
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, NULL, $1.line, NULL, $1.line); $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @1, NULL, @1);
} }
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON { | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line); ES3_ONLY(getQualifierString($1.qualifier), @1);
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, $5.string, $5.line, NULL, $1.line); $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @1);
} }
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON { | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line); ES3_ONLY(getQualifierString($1.qualifier), @1);
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, $5.string, $5.line, $7, $6.line); $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6);
} }
| type_qualifier SEMICOLON { | type_qualifier SEMICOLON {
context->parseGlobalLayoutQualifier($1); context->parseGlobalLayoutQualifier($1);
...@@ -1352,6 +1276,11 @@ type_specifier_no_prec ...@@ -1352,6 +1276,11 @@ type_specifier_no_prec
: type_specifier_nonarray { : type_specifier_nonarray {
$$ = $1; $$ = $1;
} }
| type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
ES3_ONLY("[]", @2);
$$ = $1;
$$.setArray(true, 0);
}
| type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$ = $1; $$ = $1;
...@@ -1769,17 +1698,17 @@ selection_rest_statement ...@@ -1769,17 +1698,17 @@ selection_rest_statement
switch_statement switch_statement
: SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement { : SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement {
$$ = context->addSwitch($3, $6, $1.line); $$ = context->addSwitch($3, $6, @1);
context->decrSwitchNestingLevel(); context->decrSwitchNestingLevel();
} }
; ;
case_label case_label
: CASE constant_expression COLON { : CASE constant_expression COLON {
$$ = context->addCase($2, $1.line); $$ = context->addCase($2, @1);
} }
| DEFAULT COLON { | DEFAULT COLON {
$$ = context->addDefault($1.line); $$ = context->addDefault(@1);
} }
; ;
...@@ -1799,7 +1728,7 @@ condition ...@@ -1799,7 +1728,7 @@ condition
if (context->boolErrorCheck(@2, $1)) if (context->boolErrorCheck(@2, $1))
context->recover(); context->recover();
if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode)) if (!context->executeInitializer(@2, *$2.string, $1, $4, &intermNode))
$$ = $4; $$ = $4;
else { else {
context->recover(); context->recover();
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -295,6 +295,8 @@ ...@@ -295,6 +295,8 @@
<Unit filename="../compiler/TranslatorASM.cpp" /> <Unit filename="../compiler/TranslatorASM.cpp" />
<Unit filename="../compiler/TranslatorASM.h" /> <Unit filename="../compiler/TranslatorASM.h" />
<Unit filename="../compiler/Types.h" /> <Unit filename="../compiler/Types.h" />
<Unit filename="../compiler/ValidateGlobalInitializer.cpp" />
<Unit filename="../compiler/ValidateGlobalInitializer.h" />
<Unit filename="../compiler/ValidateLimitations.cpp" /> <Unit filename="../compiler/ValidateLimitations.cpp" />
<Unit filename="../compiler/ValidateLimitations.h" /> <Unit filename="../compiler/ValidateLimitations.h" />
<Unit filename="../compiler/ValidateSwitch.cpp" /> <Unit filename="../compiler/ValidateSwitch.cpp" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment