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.
......
...@@ -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