Commit 9ec79391 by Olli Etuaho Committed by Commit Bot

Use TLValueTrackingTraverser in ValidateLimitations

Use TLValueTrackingTraverser to determine whether a loop index is used as an l-value. This replaces custom logic in ValidateLimitations, greatly simplifying the code. Also pass the symbol table to ValidateLimitations as a parameter, which removes the need to store a global pointer to the current ParseContext. BUG=angleproject:1960 TEST=angle_unittests, WebGL conformance tests Change-Id: I122c85c78bbea05833d7c787cd184de568c5c45f Reviewed-on: https://chromium-review.googlesource.com/465606 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent b5e884a4
...@@ -64,8 +64,6 @@ ...@@ -64,8 +64,6 @@
'compiler/translator/InitializeDll.cpp', 'compiler/translator/InitializeDll.cpp',
'compiler/translator/InitializeDll.h', 'compiler/translator/InitializeDll.h',
'compiler/translator/InitializeGlobals.h', 'compiler/translator/InitializeGlobals.h',
'compiler/translator/InitializeParseContext.cpp',
'compiler/translator/InitializeParseContext.h',
'compiler/translator/InitializeVariables.cpp', 'compiler/translator/InitializeVariables.cpp',
'compiler/translator/InitializeVariables.h', 'compiler/translator/InitializeVariables.h',
'compiler/translator/IntermNode.h', 'compiler/translator/IntermNode.h',
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "compiler/translator/EmulateGLFragColorBroadcast.h" #include "compiler/translator/EmulateGLFragColorBroadcast.h"
#include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/Initialize.h" #include "compiler/translator/Initialize.h"
#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/InitializeVariables.h" #include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/ParseContext.h" #include "compiler/translator/ParseContext.h"
#include "compiler/translator/PruneEmptyDeclarations.h" #include "compiler/translator/PruneEmptyDeclarations.h"
...@@ -293,7 +292,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -293,7 +292,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
compileOptions, true, &mDiagnostics, getResources()); compileOptions, true, &mDiagnostics, getResources());
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh); parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
SetGlobalParseContext(&parseContext);
// We preserve symbols at the built-in level from compile-to-compile. // We preserve symbols at the built-in level from compile-to-compile.
// Start pushing the user-defined symbols at global level. // Start pushing the user-defined symbols at global level.
...@@ -368,7 +366,8 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -368,7 +366,8 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
success = validateOutputs(root); success = validateOutputs(root);
if (success && shouldRunLoopAndIndexingValidation(compileOptions)) if (success && shouldRunLoopAndIndexingValidation(compileOptions))
success = validateLimitations(root); success =
ValidateLimitations(root, shaderType, symbolTable, shaderVersion, &mDiagnostics);
bool multiview2 = IsExtensionEnabled(extensionBehavior, "GL_OVR_multiview2"); bool multiview2 = IsExtensionEnabled(extensionBehavior, "GL_OVR_multiview2");
if (success && compileResources.OVR_multiview && IsWebGLBasedSpec(shaderSpec) && if (success && compileResources.OVR_multiview && IsWebGLBasedSpec(shaderSpec) &&
...@@ -477,7 +476,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -477,7 +476,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
} }
} }
SetGlobalParseContext(NULL);
if (success) if (success)
return root; return root;
...@@ -854,13 +852,6 @@ bool TCompiler::validateOutputs(TIntermNode *root) ...@@ -854,13 +852,6 @@ bool TCompiler::validateOutputs(TIntermNode *root)
return (mDiagnostics.numErrors() == 0); return (mDiagnostics.numErrors() == 0);
} }
bool TCompiler::validateLimitations(TIntermNode *root)
{
ValidateLimitations validate(shaderType, &mDiagnostics);
root->traverse(&validate);
return mDiagnostics.numErrors() == 0;
}
bool TCompiler::limitExpressionComplexity(TIntermNode *root) bool TCompiler::limitExpressionComplexity(TIntermNode *root)
{ {
TMaxDepthTraverser traverser(maxExpressionComplexity + 1); TMaxDepthTraverser traverser(maxExpressionComplexity + 1);
......
...@@ -135,9 +135,6 @@ class TCompiler : public TShHandleBase ...@@ -135,9 +135,6 @@ class TCompiler : public TShHandleBase
bool checkCallDepth(); bool checkCallDepth();
// Returns true if a program has no conflicting or missing fragment outputs // Returns true if a program has no conflicting or missing fragment outputs
bool validateOutputs(TIntermNode *root); bool validateOutputs(TIntermNode *root);
// Returns true if the given shader does not exceed the minimum
// functionality mandated in GLSL 1.0 spec Appendix A.
bool validateLimitations(TIntermNode *root);
// Add emulated functions to the built-in function emulator. // Add emulated functions to the built-in function emulator.
virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
ShCompileOptions compileOptions){}; ShCompileOptions compileOptions){};
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include "compiler/translator/Cache.h" #include "compiler/translator/Cache.h"
#include "compiler/translator/InitializeDll.h" #include "compiler/translator/InitializeDll.h"
#include "compiler/translator/InitializeGlobals.h" #include "compiler/translator/InitializeGlobals.h"
#include "compiler/translator/InitializeParseContext.h"
#include "common/platform.h" #include "common/platform.h"
...@@ -24,12 +23,6 @@ bool InitProcess() ...@@ -24,12 +23,6 @@ bool InitProcess()
return false; return false;
} }
if (!InitializeParseContextIndex())
{
assert(0 && "InitProcess(): Failed to initalize parse context");
return false;
}
TCache::initialize(); TCache::initialize();
return true; return true;
...@@ -37,7 +30,6 @@ bool InitProcess() ...@@ -37,7 +30,6 @@ bool InitProcess()
void DetachProcess() void DetachProcess()
{ {
FreeParseContextIndex();
FreePoolIndex(); FreePoolIndex();
TCache::destroy(); TCache::destroy();
} }
......
//
// Copyright (c) 2012 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 "compiler/translator/InitializeParseContext.h"
#include "common/tls.h"
#include <assert.h>
namespace sh
{
TLSIndex GlobalParseContextIndex = TLS_INVALID_INDEX;
bool InitializeParseContextIndex()
{
assert(GlobalParseContextIndex == TLS_INVALID_INDEX);
GlobalParseContextIndex = CreateTLSIndex();
return GlobalParseContextIndex != TLS_INVALID_INDEX;
}
void FreeParseContextIndex()
{
assert(GlobalParseContextIndex != TLS_INVALID_INDEX);
DestroyTLSIndex(GlobalParseContextIndex);
GlobalParseContextIndex = TLS_INVALID_INDEX;
}
void SetGlobalParseContext(TParseContext *context)
{
assert(GlobalParseContextIndex != TLS_INVALID_INDEX);
SetTLSValue(GlobalParseContextIndex, context);
}
TParseContext *GetGlobalParseContext()
{
assert(GlobalParseContextIndex != TLS_INVALID_INDEX);
return static_cast<TParseContext *>(GetTLSValue(GlobalParseContextIndex));
}
} // namespace sh
//
// Copyright (c) 2002-2010 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_INITIALIZEPARSECONTEXT_H_
#define COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_
namespace sh
{
bool InitializeParseContextIndex();
void FreeParseContextIndex();
class TParseContext;
extern void SetGlobalParseContext(TParseContext *context);
extern TParseContext *GetGlobalParseContext();
} // namespace sh
#endif // COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_
...@@ -6,10 +6,9 @@ ...@@ -6,10 +6,9 @@
#include "compiler/translator/ValidateLimitations.h" #include "compiler/translator/ValidateLimitations.h"
#include "angle_gl.h"
#include "compiler/translator/Diagnostics.h" #include "compiler/translator/Diagnostics.h"
#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/ParseContext.h" #include "compiler/translator/ParseContext.h"
#include "angle_gl.h"
namespace sh namespace sh
{ {
...@@ -65,52 +64,73 @@ class ValidateConstIndexExpr : public TIntermTraverser ...@@ -65,52 +64,73 @@ class ValidateConstIndexExpr : public TIntermTraverser
const std::vector<int> mLoopSymbolIds; const std::vector<int> mLoopSymbolIds;
}; };
} // namespace anonymous // Traverses intermediate tree to ensure that the shader does not exceed the
// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
class ValidateLimitationsTraverser : public TLValueTrackingTraverser
{
public:
ValidateLimitationsTraverser(sh::GLenum shaderType,
const TSymbolTable &symbolTable,
int shaderVersion,
TDiagnostics *diagnostics);
void visitSymbol(TIntermSymbol *node) override;
bool visitBinary(Visit, TIntermBinary *) override;
bool visitLoop(Visit, TIntermLoop *) override;
private:
void error(TSourceLoc loc, const char *reason, const char *token);
bool withinLoopBody() const;
bool isLoopIndex(TIntermSymbol *symbol);
bool validateLoopType(TIntermLoop *node);
bool validateForLoopHeader(TIntermLoop *node);
// If valid, return the index symbol id; Otherwise, return -1.
int validateForLoopInit(TIntermLoop *node);
bool validateForLoopCond(TIntermLoop *node, int indexSymbolId);
bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId);
// Returns true if indexing does not exceed the minimum functionality
// mandated in GLSL 1.0 spec, Appendix A, Section 5.
bool isConstExpr(TIntermNode *node);
bool isConstIndexExpr(TIntermNode *node);
bool validateIndexing(TIntermBinary *node);
sh::GLenum mShaderType;
TDiagnostics *mDiagnostics;
std::vector<int> mLoopSymbolIds;
};
ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TDiagnostics *diagnostics) ValidateLimitationsTraverser::ValidateLimitationsTraverser(sh::GLenum shaderType,
: TIntermTraverser(true, false, false), const TSymbolTable &symbolTable,
int shaderVersion,
TDiagnostics *diagnostics)
: TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
mShaderType(shaderType), mShaderType(shaderType),
mDiagnostics(diagnostics), mDiagnostics(diagnostics)
mValidateIndexing(true),
mValidateInnerLoops(true)
{ {
ASSERT(diagnostics); ASSERT(diagnostics);
} }
bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node) void ValidateLimitationsTraverser::visitSymbol(TIntermSymbol *node)
{ {
// Check if loop index is modified in the loop body. if (isLoopIndex(node) && isLValueRequiredHere())
validateOperation(node, node->getLeft());
// Check indexing.
switch (node->getOp())
{ {
case EOpIndexDirect: error(node->getLine(),
case EOpIndexIndirect: "Loop index cannot be statically assigned to within the body of the loop",
if (mValidateIndexing) node->getSymbol().c_str());
validateIndexing(node);
break;
default:
break;
} }
return true;
}
bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
{
// Check if loop index is modified in the loop body.
validateOperation(node, node->getOperand());
return true;
} }
bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node) bool ValidateLimitationsTraverser::visitBinary(Visit, TIntermBinary *node)
{ {
// Check indexing.
switch (node->getOp()) switch (node->getOp())
{ {
case EOpCallFunctionInAST: case EOpIndexDirect:
case EOpCallBuiltInFunction: case EOpIndexIndirect:
validateFunctionCall(node); validateIndexing(node);
break; break;
default: default:
break; break;
...@@ -118,11 +138,8 @@ bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node) ...@@ -118,11 +138,8 @@ bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
return true; return true;
} }
bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node) bool ValidateLimitationsTraverser::visitLoop(Visit, TIntermLoop *node)
{ {
if (!mValidateInnerLoops)
return true;
if (!validateLoopType(node)) if (!validateLoopType(node))
return false; return false;
...@@ -141,23 +158,23 @@ bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node) ...@@ -141,23 +158,23 @@ bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
return false; return false;
} }
void ValidateLimitations::error(TSourceLoc loc, const char *reason, const char *token) void ValidateLimitationsTraverser::error(TSourceLoc loc, const char *reason, const char *token)
{ {
mDiagnostics->error(loc, reason, token); mDiagnostics->error(loc, reason, token);
} }
bool ValidateLimitations::withinLoopBody() const bool ValidateLimitationsTraverser::withinLoopBody() const
{ {
return !mLoopSymbolIds.empty(); return !mLoopSymbolIds.empty();
} }
bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol) bool ValidateLimitationsTraverser::isLoopIndex(TIntermSymbol *symbol)
{ {
return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) != return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) !=
mLoopSymbolIds.end(); mLoopSymbolIds.end();
} }
bool ValidateLimitations::validateLoopType(TIntermLoop *node) bool ValidateLimitationsTraverser::validateLoopType(TIntermLoop *node)
{ {
TLoopType type = node->getType(); TLoopType type = node->getType();
if (type == ELoopFor) if (type == ELoopFor)
...@@ -168,7 +185,7 @@ bool ValidateLimitations::validateLoopType(TIntermLoop *node) ...@@ -168,7 +185,7 @@ bool ValidateLimitations::validateLoopType(TIntermLoop *node)
return false; return false;
} }
bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node) bool ValidateLimitationsTraverser::validateForLoopHeader(TIntermLoop *node)
{ {
ASSERT(node->getType() == ELoopFor); ASSERT(node->getType() == ELoopFor);
...@@ -187,7 +204,7 @@ bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node) ...@@ -187,7 +204,7 @@ bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
return true; return true;
} }
int ValidateLimitations::validateForLoopInit(TIntermLoop *node) int ValidateLimitationsTraverser::validateForLoopInit(TIntermLoop *node)
{ {
TIntermNode *init = node->getInit(); TIntermNode *init = node->getInit();
if (init == NULL) if (init == NULL)
...@@ -243,7 +260,7 @@ int ValidateLimitations::validateForLoopInit(TIntermLoop *node) ...@@ -243,7 +260,7 @@ int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
return symbol->getId(); return symbol->getId();
} }
bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, int indexSymbolId) bool ValidateLimitationsTraverser::validateForLoopCond(TIntermLoop *node, int indexSymbolId)
{ {
TIntermNode *cond = node->getCondition(); TIntermNode *cond = node->getCondition();
if (cond == NULL) if (cond == NULL)
...@@ -299,7 +316,7 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, int indexSymbol ...@@ -299,7 +316,7 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, int indexSymbol
return true; return true;
} }
bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, int indexSymbolId) bool ValidateLimitationsTraverser::validateForLoopExpr(TIntermLoop *node, int indexSymbolId)
{ {
TIntermNode *expr = node->getExpression(); TIntermNode *expr = node->getExpression();
if (expr == NULL) if (expr == NULL)
...@@ -377,77 +394,13 @@ bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, int indexSymbol ...@@ -377,77 +394,13 @@ bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, int indexSymbol
return true; return true;
} }
bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node) bool ValidateLimitationsTraverser::isConstExpr(TIntermNode *node)
{
ASSERT(node->getOp() == EOpCallFunctionInAST || node->getOp() == EOpCallBuiltInFunction);
// If not within loop body, there is nothing to check.
if (!withinLoopBody())
return true;
// List of param indices for which loop indices are used as argument.
typedef std::vector<size_t> ParamIndex;
ParamIndex pIndex;
TIntermSequence *params = node->getSequence();
for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
{
TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
if (symbol && isLoopIndex(symbol))
pIndex.push_back(i);
}
// If none of the loop indices are used as arguments,
// there is nothing to check.
if (pIndex.empty())
return true;
bool valid = true;
TSymbolTable &symbolTable = GetGlobalParseContext()->symbolTable;
// TODO(oetuaho@nvidia.com): It would be neater to leverage TIntermLValueTrackingTraverser to
// keep track of out parameters, rather than doing a symbol table lookup here.
TString mangledName = TFunction::GetMangledNameFromCall(
node->getFunctionSymbolInfo()->getName(), *node->getSequence());
TSymbol *symbol = symbolTable.find(mangledName, GetGlobalParseContext()->getShaderVersion());
ASSERT(symbol && symbol->isFunction());
TFunction *function = static_cast<TFunction *>(symbol);
for (ParamIndex::const_iterator i = pIndex.begin(); i != pIndex.end(); ++i)
{
const TConstParameter &param = function->getParam(*i);
TQualifier qual = param.type->getQualifier();
if ((qual == EvqOut) || (qual == EvqInOut))
{
error((*params)[*i]->getLine(),
"Loop index cannot be used as argument to a function out or inout parameter",
(*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
valid = false;
}
}
return valid;
}
bool ValidateLimitations::validateOperation(TIntermOperator *node, TIntermNode *operand)
{
// Check if loop index is modified in the loop body.
if (!withinLoopBody() || !node->isAssignment())
return true;
TIntermSymbol *symbol = operand->getAsSymbolNode();
if (symbol && isLoopIndex(symbol))
{
error(node->getLine(),
"Loop index cannot be statically assigned to within the body of the loop",
symbol->getSymbol().c_str());
}
return true;
}
bool ValidateLimitations::isConstExpr(TIntermNode *node)
{ {
ASSERT(node != nullptr); ASSERT(node != nullptr);
return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst; return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
} }
bool ValidateLimitations::isConstIndexExpr(TIntermNode *node) bool ValidateLimitationsTraverser::isConstIndexExpr(TIntermNode *node)
{ {
ASSERT(node != NULL); ASSERT(node != NULL);
...@@ -456,7 +409,7 @@ bool ValidateLimitations::isConstIndexExpr(TIntermNode *node) ...@@ -456,7 +409,7 @@ bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
return validate.isValid(); return validate.isValid();
} }
bool ValidateLimitations::validateIndexing(TIntermBinary *node) bool ValidateLimitationsTraverser::validateIndexing(TIntermBinary *node)
{ {
ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect)); ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect));
...@@ -474,4 +427,17 @@ bool ValidateLimitations::validateIndexing(TIntermBinary *node) ...@@ -474,4 +427,17 @@ bool ValidateLimitations::validateIndexing(TIntermBinary *node)
return valid; return valid;
} }
} // namespace anonymous
bool ValidateLimitations(TIntermNode *root,
GLenum shaderType,
const TSymbolTable &symbolTable,
int shaderVersion,
TDiagnostics *diagnostics)
{
ValidateLimitationsTraverser validate(shaderType, symbolTable, shaderVersion, diagnostics);
root->traverse(&validate);
return diagnostics->numErrors() == 0;
}
} // namespace sh } // namespace sh
...@@ -14,48 +14,13 @@ namespace sh ...@@ -14,48 +14,13 @@ namespace sh
class TDiagnostics; class TDiagnostics;
// Traverses intermediate tree to ensure that the shader does not exceed the // Returns true if the given shader does not exceed the minimum functionality mandated in GLSL ES
// minimum functionality mandated in GLSL 1.0 spec, Appendix A. // 1.00 spec Appendix A.
class ValidateLimitations : public TIntermTraverser bool ValidateLimitations(TIntermNode *root,
{ GLenum shaderType,
public: const TSymbolTable &symbolTable,
ValidateLimitations(sh::GLenum shaderType, TDiagnostics *diagnostics); int shaderVersion,
TDiagnostics *diagnostics);
bool visitBinary(Visit, TIntermBinary *) override;
bool visitUnary(Visit, TIntermUnary *) override;
bool visitAggregate(Visit, TIntermAggregate *) override;
bool visitLoop(Visit, TIntermLoop *) override;
private:
void error(TSourceLoc loc, const char *reason, const char *token);
bool withinLoopBody() const;
bool isLoopIndex(TIntermSymbol *symbol);
bool validateLoopType(TIntermLoop *node);
bool validateForLoopHeader(TIntermLoop *node);
// If valid, return the index symbol id; Otherwise, return -1.
int validateForLoopInit(TIntermLoop *node);
bool validateForLoopCond(TIntermLoop *node, int indexSymbolId);
bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId);
// Returns true if none of the loop indices is used as the argument to
// the given function out or inout parameter.
bool validateFunctionCall(TIntermAggregate *node);
bool validateOperation(TIntermOperator *node, TIntermNode *operand);
// Returns true if indexing does not exceed the minimum functionality
// mandated in GLSL 1.0 spec, Appendix A, Section 5.
bool isConstExpr(TIntermNode *node);
bool isConstIndexExpr(TIntermNode *node);
bool validateIndexing(TIntermBinary *node);
sh::GLenum mShaderType;
TDiagnostics *mDiagnostics;
std::vector<int> mLoopSymbolIds;
bool mValidateIndexing;
bool mValidateInnerLoops;
};
} // namespace sh } // namespace sh
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include "compiler/translator/ValidateOutputs.h" #include "compiler/translator/ValidateOutputs.h"
#include "compiler/translator/InfoSink.h" #include "compiler/translator/InfoSink.h"
#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/ParseContext.h" #include "compiler/translator/ParseContext.h"
namespace sh namespace sh
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
'<(angle_path)/src/libANGLE/validationES_unittest.cpp', '<(angle_path)/src/libANGLE/validationES_unittest.cpp',
'<(angle_path)/src/tests/angle_unittests_utils.h', '<(angle_path)/src/tests/angle_unittests_utils.h',
'<(angle_path)/src/tests/compiler_tests/API_test.cpp', '<(angle_path)/src/tests/compiler_tests/API_test.cpp',
'<(angle_path)/src/tests/compiler_tests/AppendixALimitations_test.cpp',
'<(angle_path)/src/tests/compiler_tests/CollectVariables_test.cpp', '<(angle_path)/src/tests/compiler_tests/CollectVariables_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ConstantFolding_test.cpp', '<(angle_path)/src/tests/compiler_tests/ConstantFolding_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ConstantFoldingNaN_test.cpp', '<(angle_path)/src/tests/compiler_tests/ConstantFoldingNaN_test.cpp',
......
//
// Copyright (c) 2017 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.
//
// AppendixALimitations_test.cpp:
// Tests for validating ESSL 1.00 Appendix A limitations.
//
#include "gtest/gtest.h"
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
#include "tests/test_utils/ShaderCompileTreeTest.h"
using namespace sh;
class AppendixALimitationsTest : public ShaderCompileTreeTest
{
public:
AppendixALimitationsTest() {}
protected:
::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
ShShaderSpec getShaderSpec() const override { return SH_WEBGL_SPEC; }
};
// Test an invalid shader where a for loop index is used as an out parameter.
TEST_F(AppendixALimitationsTest, IndexAsFunctionOutParameter)
{
const std::string &shaderString =
"precision mediump float;\n"
"void fun(out int a)\n"
"{\n"
" a = 2;\n"
"}\n"
"void main()\n"
"{\n"
" for (int i = 0; i < 2; ++i)\n"
" {\n"
" fun(i);\n"
" }\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test an invalid shader where a for loop index is used as an inout parameter.
TEST_F(AppendixALimitationsTest, IndexAsFunctionInOutParameter)
{
const std::string &shaderString =
"precision mediump float;\n"
"void fun(int b, inout int a)\n"
"{\n"
" a += b;\n"
"}\n"
"void main()\n"
"{\n"
" for (int i = 0; i < 2; ++i)\n"
" {\n"
" fun(2, i);\n"
" }\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test a valid shader where a for loop index is used as an in parameter in a function that also has
// an out parameter.
TEST_F(AppendixALimitationsTest, IndexAsFunctionInParameter)
{
const std::string &shaderString =
"precision mediump float;\n"
"void fun(int b, inout int a)\n"
"{\n"
" a += b;\n"
"}\n"
"void main()\n"
"{\n"
" for (int i = 0; i < 2; ++i)\n"
" {\n"
" int a = 1;"
" fun(i, a);\n"
" }\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test an invalid shader where a for loop index is used as a target of assignment.
TEST_F(AppendixALimitationsTest, IndexAsTargetOfAssignment)
{
const std::string &shaderString =
"precision mediump float;\n"
"void main()\n"
"{\n"
" for (int i = 0; i < 2; ++i)\n"
" {\n"
" i = 2;\n"
" }\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test an invalid shader where a for loop index is incremented inside the loop.
TEST_F(AppendixALimitationsTest, IndexIncrementedInLoopBody)
{
const std::string &shaderString =
"precision mediump float;\n"
"void main()\n"
"{\n"
" for (int i = 0; i < 2; ++i)\n"
" {\n"
" ++i;\n"
" }\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
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