Commit 27b72e42 by John Kessenich

Implement ES 2.0 (version 100) limitations for non-inductive loop detection and…

Implement ES 2.0 (version 100) limitations for non-inductive loop detection and array indexes needing "constant-index-expressions" (inductive variables and constant expressions). git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23478 e7fa87d3-cd2b-0410-9028-fcbf551c1848
parent a4ea1313
......@@ -14,32 +14,46 @@ const vec3 v3 = vec3(2.0);
void foo(inout float a) {}
int bar()
{
return 1;
}
void main()
{
while (ga < gb) { }
do { } while (false);
for ( ga = 0; ; );
for ( bool a = false; ; );
for (float a = 0.0; a == sin(f); );
for ( int a = 0; a < 10; a *= 2);
for ( int a = 0; a <= 20; ++a) --a;
for ( ; ; ); // ERROR
for ( ; ga==gb; ); // ERROR
for ( ; ; f++); // ERROR
for ( ga = 0; ; ); // ERROR
for ( bool a = false; ; ); // ERROR
for (float a = 0.0; a == sin(f); ); // ERROR
for ( int a = 0; a < 10; a *= 2); // ERROR
for ( int a = 0; a <= 20; a++) --a; // ERROR
for ( int a = 0; a <= 20; a++) { if (ga==0) a = 4; } // ERROR
for (float a = 0.0; a <= 20.0; a += 2.0);
for (float a = 0.0; a <= 20.0; a += 2.0) foo(a);
for (float a = 0.0; a != 20.0; a -= 2.0) { if (ga==0) ga = 4; }
for (float a = 0.0; a == 20.0; a--) for (float a = 0.0; a == 20.0; a--); // two different 'a's, everything okay
for (float a = 0.0; a <= 20.0; a += 2.0);
for (float a = 0.0; a <= 20.0; a += 2.0);
for (float a = 0.0; a > 2.0 * 20.0; a += v3.y);
for (float a = 0.0; a >= 20.0; a += 2.0) foo(a); // ERROR
int ia[9];
fsa[ga];
fsa[ga]; // ERROR
fua[ga];
am3[ga];
av2[ga];
va[ga];
m2[ga];
v3[ga];
ia[ga];
for ( int a = 3; a >= 0; --a) {
am3[ga]; // ERROR
av2[ga]; // ERROR
va[2+ga]; // ERROR
m2[ga]; // ERROR
v3[ga/2]; // ERROR
ia[ga]; // ERROR
for (int a = 3; a >= 0; a--) {
fsa[a];
fua[a+2];
am3[3*a];
......@@ -48,6 +62,15 @@ void main()
m2[a/2];
v3[a];
ia[a];
ia[bar()]; // ERROR
}
fsa[2];
fua[3];
am3[2];
av2[1];
va[1];
m2[1];
v3[1];
ia[3];
}
ERROR: 0:19: 'limitation' : while loops not available
ERROR: 0:21: 'limitation' : do-while loops not available
ERROR: 2 compilation errors. No code generated.
ERROR: 0:24: 'limitation' : while loops not available
ERROR: 0:26: 'limitation' : do-while loops not available
ERROR: 0:28: 'limitations' : inductive-loop init-declaration requires the form "type-specifier loop-index = constant-expression"
ERROR: 0:29: 'limitations' : inductive-loop init-declaration requires the form "type-specifier loop-index = constant-expression"
ERROR: 0:30: 'limitations' : inductive-loop init-declaration requires the form "type-specifier loop-index = constant-expression"
ERROR: 0:31: 'limitations' : inductive-loop init-declaration requires the form "type-specifier loop-index = constant-expression"
ERROR: 0:32: 'limitations' : inductive loop requires a scalar 'int' or 'float' loop index
ERROR: 0:33: 'limitations' : inductive-loop condition requires the form "loop-index <comparison-op> constant-expression"
ERROR: 0:34: 'limitations' : inductive-loop termination requires the form "loop-index++, loop-index--, loop-index += constant-expression, or loop-index -= constant-expression"
ERROR: 0:35: 'limitations' : inductive loop index modified
ERROR: 0:36: 'limitations' : inductive loop index modified
ERROR: 0:43: 'limitations' : inductive loop index modified
ERROR: 0:47: 'limitations' : Non-constant-index-expression
ERROR: 0:49: 'limitations' : Non-constant-index-expression
ERROR: 0:50: 'limitations' : Non-constant-index-expression
ERROR: 0:51: 'limitations' : Non-constant-index-expression
ERROR: 0:52: 'limitations' : Non-constant-index-expression
ERROR: 0:53: 'limitations' : Non-constant-index-expression
ERROR: 0:54: 'limitations' : Non-constant-index-expression
ERROR: 0:65: 'limitations' : Non-constant-index-expression
ERROR: 20 compilation errors. No code generated.
......@@ -156,6 +156,7 @@ xcopy /y $(IntDir)$(TargetName)$(TargetExt) Test</Command>
</ClCompile>
<ClCompile Include="glslang\MachineIndependent\InfoSink.cpp" />
<ClCompile Include="glslang\MachineIndependent\Initialize.cpp" />
<ClCompile Include="glslang\MachineIndependent\limits.cpp" />
<ClCompile Include="glslang\MachineIndependent\preprocessor\Pp.cpp" />
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpAtom.cpp" />
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpMemory.cpp" />
......
......@@ -109,6 +109,9 @@
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpContext.cpp">
<Filter>Machine Independent\Preprocessor</Filter>
</ClCompile>
<ClCompile Include="glslang\MachineIndependent\limits.cpp">
<Filter>Machine Independent</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="glslang\MachineIndependent\Initialize.h">
......
......@@ -316,6 +316,7 @@ enum TOperator {
};
class TIntermTraverser;
class TIntermOperator;
class TIntermAggregate;
class TIntermUnary;
class TIntermBinary;
......@@ -342,16 +343,17 @@ public:
virtual glslang::TSourceLoc getLoc() const { return loc; }
virtual void setLoc(glslang::TSourceLoc l) { loc = l; }
virtual void traverse(glslang::TIntermTraverser*) = 0;
virtual glslang::TIntermTyped* getAsTyped() { return 0; }
virtual glslang::TIntermConstantUnion* getAsConstantUnion() { return 0; }
virtual glslang::TIntermAggregate* getAsAggregate() { return 0; }
virtual glslang::TIntermUnary* getAsUnaryNode() { return 0; }
virtual glslang::TIntermBinary* getAsBinaryNode() { return 0; }
virtual glslang::TIntermSelection* getAsSelectionNode() { return 0; }
virtual glslang::TIntermSwitch* getAsSwitchNode() { return 0; }
virtual glslang::TIntermMethod* getAsMethodNode() { return 0; }
virtual glslang::TIntermSymbol* getAsSymbolNode() { return 0; }
virtual glslang::TIntermBranch* getAsBranchNode() { return 0; }
virtual glslang::TIntermTyped* getAsTyped() { return 0; }
virtual glslang::TIntermOperator* getAsOperator() { return 0; }
virtual glslang::TIntermConstantUnion* getAsConstantUnion() { return 0; }
virtual glslang::TIntermAggregate* getAsAggregate() { return 0; }
virtual glslang::TIntermUnary* getAsUnaryNode() { return 0; }
virtual glslang::TIntermBinary* getAsBinaryNode() { return 0; }
virtual glslang::TIntermSelection* getAsSelectionNode() { return 0; }
virtual glslang::TIntermSwitch* getAsSwitchNode() { return 0; }
virtual glslang::TIntermMethod* getAsMethodNode() { return 0; }
virtual glslang::TIntermSymbol* getAsSymbolNode() { return 0; }
virtual glslang::TIntermBranch* getAsBranchNode() { return 0; }
virtual ~TIntermNode() { }
protected:
glslang::TSourceLoc loc;
......@@ -478,7 +480,7 @@ public:
TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), unionArray(ua) { }
const TConstUnionArray& getConstArray() const { return unionArray; }
virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
virtual void traverse(TIntermTraverser* );
virtual void traverse(TIntermTraverser*);
virtual TIntermTyped* fold(TOperator, TIntermTyped*);
virtual TIntermTyped* fold(TOperator, const TType&);
protected:
......@@ -490,6 +492,7 @@ protected:
//
class TIntermOperator : public TIntermTyped {
public:
TIntermOperator* getAsOperator() { return this; }
TOperator getOp() { return op; }
bool modifiesState() const;
bool isConstructor() const;
......
......@@ -713,9 +713,9 @@ TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
TConstUnionArray unionArray(aggrNode->getType().getObjectSize());
if (aggrNode->getSequence().size() == 1)
error = parseConstTree(aggrNode->getLoc(), aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
else
error = parseConstTree(aggrNode->getLoc(), aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
if (error)
return aggrNode;
......
......@@ -809,11 +809,11 @@ TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc loc)
//
// Create loop nodes.
//
TIntermNode* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, TSourceLoc loc)
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, TSourceLoc loc)
{
TIntermNode* node = new TIntermLoop(body, test, terminal, testFirst);
TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
node->setLoc(loc);
return node;
}
......
......@@ -11,7 +11,7 @@ LIBCODEGEN=./../GenericCodeGen/libCodeGen.a
OBJECTS= Initialize.o IntermTraverse.o \
Intermediate.o ParseHelper.o PoolAlloc.o QualifierAlive.o \
RemoveTree.o ShaderLang.o intermOut.o parseConst.o SymbolTable.o \
InfoSink.o Versions.o Constant.o Scan.o
InfoSink.o Versions.o Constant.o Scan.o limits.o
SRCS= gen_glslang_tab.cpp Initialize.cpp IntermTraverse.cpp \
Intermediate.cpp ParseHelper.cpp PoolAlloc.cp QualifierAlive.cpp \
......@@ -146,3 +146,4 @@ parseConst.o: ../Public/ShaderLang.h
InfoSink.o: ../Include/InfoSink.h
Versions.o: ParseHelper.h Versions.h ../Include/ShHandle.h SymbolTable.h localintermediate.h
Constant.o: localintermediate.h ../Include/intermediate.h ../Public/ShaderLang.h SymbolTable.h Versions.h
limits.o: ParseHelper.h
......@@ -154,8 +154,17 @@ bool TParseContext::parseShaderStrings(TPpContext& ppContext, char* strings[], s
return true;
}
anyIndexLimits = ! limits.generalAttributeMatrixVectorIndexing ||
! limits.generalConstantMatrixVectorIndexing ||
! limits.generalSamplerIndexing ||
! limits.generalUniformIndexing ||
! limits.generalVariableIndexing ||
! limits.generalVaryingIndexing;
yyparse((void*)this);
finalize();
return numErrors == 0;
}
......@@ -510,6 +519,23 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
newType.getQualifier().storage = EvqConst;
newType.dereference();
result->setType(newType);
if (anyIndexLimits) {
// for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms
if ((! limits.generalSamplerIndexing && base->getBasicType() == EbtSampler) ||
(! limits.generalUniformIndexing && base->getQualifier().isUniform() && language != EShLangVertex) ||
(! limits.generalAttributeMatrixVectorIndexing && base->getQualifier().isPipeInput() && language == EShLangVertex && (base->getType().isMatrix() || base->getType().isVector())) ||
(! limits.generalConstantMatrixVectorIndexing && base->getAsConstantUnion()) ||
(! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniform() &&
! base->getType().getQualifier().isPipeInput() &&
! base->getType().getQualifier().isPipeOutput() &&
base->getType().getQualifier().storage != EvqConst) ||
(! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() ||
base->getType().getQualifier().isPipeOutput()))) {
// it's too early to know what the inductive variables are, save it for post processing
needsIndexLimitationChecking.push_back(index);
}
}
}
return result;
......@@ -1915,6 +1941,133 @@ void TParseContext::arrayObjectCheck(TSourceLoc loc, const TType& type, const ch
}
//
// See if this loop satisfies the limitations for ES 2.0 (version 100) for loops in Appendex A:
//
// "The loop index has type int or float.
//
// "The for statement has the form:
// for ( init-declaration ; condition ; expression )
// init-declaration has the form: type-specifier identifier = constant-expression
// condition has the form: loop-index relational_operator constant-expression
// where relational_operator is one of: > >= < <= == or !=
// expression [sic] has one of the following forms:
// loop-index++
// loop-index--
// loop-index += constant-expression
// loop-index -= constant-expression
//
// The body is handled in an AST traversal.
//
void TParseContext::inductiveLoopCheck(TSourceLoc loc, TIntermNode* init, TIntermLoop* loop)
{
// loop index init must exist and be a declaration, which shows up in the AST as an aggregate of size 1 of the declaration
bool badInit = false;
if (! init || ! init->getAsAggregate() || ! init->getAsAggregate()->getSequence().size() == 1)
badInit = true;
TIntermBinary* binaryInit;
if (! badInit) {
// get the declaration assignment
binaryInit = init->getAsAggregate()->getSequence()[0]->getAsBinaryNode();
if (! binaryInit)
badInit = true;
}
if (badInit) {
error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
return;
}
// loop index must be type int or float
if (! binaryInit->getType().isScalar() || (binaryInit->getBasicType() != EbtInt && binaryInit->getBasicType() != EbtFloat)) {
error(loc, "inductive loop requires a scalar 'int' or 'float' loop index", "limitations", "");
return;
}
// init is the form "loop-index = constant"
if (binaryInit->getOp() != EOpAssign || ! binaryInit->getLeft()->getAsSymbolNode() || ! binaryInit->getRight()->getAsConstantUnion()) {
error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
return;
}
// get the unique id of the loop index
int loopIndex = binaryInit->getLeft()->getAsSymbolNode()->getId();
inductiveLoopIds.insert(loopIndex);
// condition's form must be "loop-index relational-operator constant-expression"
bool badCond = ! loop->getTest();
if (! badCond) {
TIntermBinary* binaryCond = loop->getTest()->getAsBinaryNode();
badCond = ! binaryCond;
if (! badCond) {
switch (binaryCond->getOp()) {
case EOpGreaterThan:
case EOpGreaterThanEqual:
case EOpLessThan:
case EOpLessThanEqual:
case EOpEqual:
case EOpNotEqual:
break;
default:
badCond = true;
}
}
if (binaryCond && (! binaryCond->getLeft()->getAsSymbolNode() ||
binaryCond->getLeft()->getAsSymbolNode()->getId() != loopIndex ||
! binaryCond->getRight()->getAsConstantUnion()))
badCond = true;
}
if (badCond) {
error(loc, "inductive-loop condition requires the form \"loop-index <comparison-op> constant-expression\"", "limitations", "");
return;
}
// loop-index++
// loop-index--
// loop-index += constant-expression
// loop-index -= constant-expression
bool badTerminal = ! loop->getTerminal();
if (! badTerminal) {
TIntermUnary* unaryTerminal = loop->getTerminal()->getAsUnaryNode();
TIntermBinary* binaryTerminal = loop->getTerminal()->getAsBinaryNode();
if (unaryTerminal || binaryTerminal) {
switch(loop->getTerminal()->getAsOperator()->getOp()) {
case EOpPostDecrement:
case EOpPostIncrement:
case EOpAddAssign:
case EOpSubAssign:
break;
default:
badTerminal = true;
}
} else
badTerminal = true;
if (binaryTerminal && (! binaryTerminal->getLeft()->getAsSymbolNode() ||
binaryTerminal->getLeft()->getAsSymbolNode()->getId() != loopIndex ||
! binaryTerminal->getRight()->getAsConstantUnion()))
badTerminal = true;
if (unaryTerminal && (! unaryTerminal->getOperand()->getAsSymbolNode() ||
unaryTerminal->getOperand()->getAsSymbolNode()->getId() != loopIndex))
badTerminal = true;
}
if (badTerminal) {
error(loc, "inductive-loop termination requires the form \"loop-index++, loop-index--, loop-index += constant-expression, or loop-index -= constant-expression\"", "limitations", "");
return;
}
// the body
inductiveLoopBodyCheck(loop->getBody(), loopIndex, symbolTable);
}
//
// Do any additional error checking, etc., once we know the parsing is done.
//
void TParseContext::finalize()
{
// Check on array indexes for ES 2.0 (version 100) limitations.
for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i)
constantIndexExpressionCheck(needsIndexLimitationChecking[i]);
}
//
// Layout qualifier stuff.
//
......
......@@ -53,6 +53,8 @@ struct TPragma {
class TScanContext;
class TPpContext;
typedef std::set<int> TIdSetType;
//
// The following are extra variables needed during parsing, grouped together so
// they can be passed to the parser without needing a global.
......@@ -116,6 +118,9 @@ public:
void nestedBlockCheck(TSourceLoc);
void nestedStructCheck(TSourceLoc);
void arrayObjectCheck(TSourceLoc, const TType&, const char* op);
void inductiveLoopCheck(TSourceLoc, TIntermNode* init, TIntermLoop* loop);
void inductiveLoopBodyCheck(TIntermNode*, int loopIndexId, TSymbolTable&);
void constantIndexExpressionCheck(TIntermNode*);
void setLayoutQualifier(TSourceLoc, TPublicType&, TString&);
void setLayoutQualifier(TSourceLoc, TPublicType&, TString&, int);
......@@ -167,6 +172,7 @@ protected:
void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable);
TOperator mapTypeToConstructorOp(const TType&);
void finalize();
public:
//
......@@ -213,6 +219,9 @@ protected:
TQualifier globalInputDefaults;
TQualifier globalOutputDefaults;
TString currentCaller;
TIdSetType inductiveLoopIds;
bool anyIndexLimits;
TVector<TIntermTyped*> needsIndexLimitationChecking;
// TODO: desktop functionality: track use of gl_FragDepth before redeclaration
};
......
......@@ -2278,10 +2278,10 @@ iteration_statement
for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
$$ = parseContext.intermediate.makeAggregate($4, $2.loc);
$$ = parseContext.intermediate.growAggregate(
$$,
parseContext.intermediate.addLoop($7, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), true, $1.loc),
$1.loc);
TIntermLoop* forLoop = parseContext.intermediate.addLoop($7, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), true, $1.loc);
if (! parseContext.limits.nonInductiveForLoops)
parseContext.inductiveLoopCheck($1.loc, $4, forLoop);
$$ = parseContext.intermediate.growAggregate($$, forLoop, $1.loc);
$$->getAsAggregate()->setOperator(EOpSequence);
--parseContext.loopNestingLevel;
}
......
//
//Copyright (C) 2013 LunarG, Inc.
//
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions
//are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE.
//
//
// Do sub tree walks for
// 1) inductive loop bodies to see if the inductive variable is modified
// 2) array-index expressions to see if they are "constant-index-expression"
//
// These are per Appendix A of ES 2.0:
//
// "Within the body of the loop, the loop index is not statically assigned to nor is it used as the
// argument to a function out or inout parameter."
//
// "The following are constant-index-expressions:
// - Constant expressions
// - Loop indices as defined in section 4
// - Expressions composed of both of the above"
//
// N.B.: assuming the last rule excludes function calls
//
#include "ParseHelper.h"
namespace glslang {
//
// The inductive loop-body traverser.
//
// Just look at things that might modify the loop index.
//
class TInductiveTraverser : public TIntermTraverser {
public:
TInductiveTraverser(int id, TSymbolTable& st) : loopId(id), symbolTable(st), bad(false) { }
int loopId; // unique ID of the symbol that's the loop inductive variable
TSymbolTable& symbolTable;
bool bad;
TSourceLoc badLoc;
};
// check binary operations for those modifying the loop index
bool InductiveBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
{
TInductiveTraverser* oit = static_cast<TInductiveTraverser*>(it);
if (node->modifiesState() && node->getLeft()->getAsSymbolNode() &&
node->getLeft()->getAsSymbolNode()->getId() == oit->loopId) {
oit->bad = true;
oit->badLoc = node->getLoc();
}
return true;
}
// check unary operations for those modifying the loop index
bool InductiveUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it)
{
TInductiveTraverser* oit = static_cast<TInductiveTraverser*>(it);
if (node->modifiesState() && node->getOperand()->getAsSymbolNode() &&
node->getOperand()->getAsSymbolNode()->getId() == oit->loopId) {
oit->bad = true;
oit->badLoc = node->getLoc();
}
return true;
}
// check function calls for arguments modifying the loop index
bool InductiveAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it)
{
TInductiveTraverser* oit = static_cast<TInductiveTraverser*>(it);
if (node->getOp() == EOpFunctionCall) {
// see if an out or inout argument is the loop index
const TIntermSequence& args = node->getSequence();
for (size_t i = 0; i < args.size(); ++i) {
if (args[i]->getAsSymbolNode() && args[i]->getAsSymbolNode()->getId() == oit->loopId) {
TSymbol* function = oit->symbolTable.find(node->getName());
const TType* type = (*function->getAsFunction())[i].type;
if (type->getQualifier().storage == EvqOut ||
type->getQualifier().storage == EvqInOut) {
oit->bad = true;
oit->badLoc = node->getLoc();
}
}
}
}
return true;
}
//
// External function to call for loop check.
//
void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbolTable& symbolTable)
{
TInductiveTraverser it(loopId, symbolTable);
if (! body)
return;
it.visitAggregate = InductiveAggregate;
it.visitBinary = InductiveBinary;
it.visitUnary = InductiveUnary;
body->traverse(&it);
if (it.bad)
error(it.badLoc, "inductive loop index modified", "limitations", "");
}
//
// The "constant-index-expression" tranverser.
//
// Just look at things that can form an index.
//
class TIndexTraverser : public TIntermTraverser {
public:
TIndexTraverser(const TIdSetType& ids) : inductiveLoopIds(ids), bad(false) { }
const TIdSetType& inductiveLoopIds;
bool bad;
TSourceLoc badLoc;
};
// make sure symbols are inductive-loop indexes
void IndexSymbol(TIntermSymbol* symbol, TIntermTraverser* it)
{
TIndexTraverser* oit = static_cast<TIndexTraverser*>(it);
if (oit->inductiveLoopIds.find(symbol->getId()) == oit->inductiveLoopIds.end()) {
oit->bad = true;
oit->badLoc = symbol->getLoc();
}
}
// check for function calls, assuming they are bad; spec. doesn't really say
bool IndexAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it)
{
TIndexTraverser* oit = static_cast<TIndexTraverser*>(it);
if (node->getOp() == EOpFunctionCall) {
oit->bad = true;
oit->badLoc = node->getLoc();
}
return true;
}
//
// External function to call for loop check.
//
void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
{
TIndexTraverser it(inductiveLoopIds);
it.visitSymbol = IndexSymbol;
it.visitAggregate = IndexAggregate;
index->traverse(&it);
if (it.bad)
error(it.badLoc, "Non-constant-index-expression", "limitations", "");
}
} // end namespace glslang
......@@ -89,8 +89,8 @@ public:
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, TSourceLoc);
TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, TSourceLoc);
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
bool parseConstTree(TSourceLoc, TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
TIntermNode* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc);
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc);
TIntermBranch* addBranch(TOperator, TSourceLoc);
TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc);
TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc);
......
......@@ -45,7 +45,7 @@ class TConstTraverser : public TIntermTraverser {
public:
TConstTraverser(const TConstUnionArray& cUnion, bool singleConstParam, TOperator constructType, const TType& t) : unionArray(cUnion), type(t),
constructorType(constructType), singleConstantParam(singleConstParam), error(false), isMatrix(false),
matrixCols(0), matrixRows(0) { index = 0; tOp = EOpNull;}
matrixCols(0), matrixRows(0) { index = 0; tOp = EOpNull; }
int index;
TConstUnionArray unionArray;
TOperator tOp;
......@@ -170,7 +170,7 @@ void ParseConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
}
}
bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
bool TIntermediate::parseConstTree(TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
{
if (root == 0)
return false;
......
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