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
This commit is contained in:
parent
a4ea1313c3
commit
27b72e42c3
15 changed files with 856 additions and 240 deletions
|
|
@ -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;
|
||||
|
|
@ -1914,6 +1940,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;
|
||||
}
|
||||
|
|
|
|||
199
glslang/MachineIndependent/limits.cpp
Normal file
199
glslang/MachineIndependent/limits.cpp
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
//
|
||||
//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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue