ERROR: 0:18: '' : array size must be a constant integer expression \r
ERROR: 0:19: '' : constant expression required \r
ERROR: 0:19: '' : array size must be a constant integer expression \r
-ERROR: 7 compilation errors. No code generated.\r
+ERROR: 0:27: '=' : assigning non-constant to 'const structure'\r
+ERROR: 0:33: '=' : assigning non-constant to 'const structure'\r
+ERROR: 9 compilation errors. No code generated.\r
\r
ERROR: node is still EOpNull!\r
0:10 Function Definition: main( (void)\r
0:69 0.028000\r
0:69 0.500000\r
0:69 1.000000\r
+0:78 Function Definition: foo( (void)\r
+0:78 Function Parameters: \r
+0:? Sequence\r
+0:81 move second child to first child (float)\r
+0:81 direct index (float)\r
+0:81 'a' (3-element array of float)\r
+0:81 0 (const int)\r
+0:81 7.000000\r
0:? Linker Objects\r
0:? 'inv' (smooth in 4-component vector of float)\r
0:? 'FragColor' (out 4-component vector of float)\r
vec4 g[int(sin(0.3)) + 1]; // okay
}
+
+const struct S {
+ vec3 v3;
+ ivec2 iv2;
+} s = S(vec3(3.0), ivec2(3, constInt + uniformInt)); // ERROR, non-const y componenent
+
+const struct S2 {
+ vec3 v3;
+ ivec2 iv2;
+ mat2x4 m;
+} s2 = S2(vec3(3.0), ivec2(3, constInt), mat2x4(1.0, 2.0, 3.0, inVar.x, 5.0, 6.0, 7.0, 8.0)); // ERROR, non-constant matrix
out2 = step(0.5, vec2(0.2, 0.6)); // 0.0, 1.0
out11 = smoothstep(50.0, 60.0, vec4(40.0, 51.0, 55.0, 70.0)); // 0.0, 0.028, 0.5, 1.0
}
+
+const struct S {
+ vec3 v3;
+ ivec2 iv2;
+ mat2x4 m;
+} s = S(vec3(3.0), ivec2(3, a + b), mat2x4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0));
+
+void foo()
+{
+ float a[s.iv2.y]; // 3 element array
+ a[0] = s.m[1].z; // 7.0
+}
glslang::TSourceLoc loc;
};
-class TInfoSink;
-
namespace glslang {
//
void setUnionArrayPointer(TConstUnion *c) { unionArrayPointer = c; }
virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
virtual void traverse(TIntermTraverser* );
- virtual TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
- virtual TIntermTyped* fold(TOperator, const TType&, TInfoSink&);
+ virtual TIntermTyped* fold(TOperator, TIntermTyped*);
+ virtual TIntermTyped* fold(TOperator, const TType&);
protected:
TConstUnion *unionArrayPointer;
};
TOperator getOp() { return op; }
bool modifiesState() const;
bool isConstructor() const;
- virtual bool promote(TInfoSink&) { return true; }
+ virtual bool promote() { return true; }
protected:
TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat)), op(o) {}
TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
virtual TIntermTyped* getLeft() const { return left; }
virtual TIntermTyped* getRight() const { return right; }
virtual TIntermBinary* getAsBinaryNode() { return this; }
- virtual bool promote(TInfoSink&);
+ virtual bool promote();
virtual void updatePrecision();
protected:
TIntermTyped* left;
virtual void setOperand(TIntermTyped* o) { operand = o; }
virtual TIntermTyped* getOperand() { return operand; }
virtual TIntermUnary* getAsUnaryNode() { return this; }
- virtual bool promote(TInfoSink&);
+ virtual bool promote();
virtual void updatePrecision();
protected:
TIntermTyped* operand;
//
// Do folding between a pair of nodes
//
-TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode)
{
TConstUnion *unionArray = getUnionArrayPointer();
int objectSize = getType().getObjectSize();
newConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst());
break;
default:
- infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLoc());
return 0;
}
}
break;
default:
- infoSink.info.message(EPrefixInternalError, "Invalid binary operator for constant folding", getLoc());
-
return 0;
}
//
// Do single unary node folding
//
-TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType, TInfoSink& infoSink)
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
{
TConstUnion *unionArray = getUnionArrayPointer();
int objectSize = getType().getObjectSize();
case EbtInt: newConstArray[i].setIConst(-unionArray[i].getIConst()); break;
case EbtUint: newConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst()))); break;
default:
- infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLoc());
return 0;
}
break;
switch (getType().getBasicType()) {
case EbtBool: newConstArray[i].setBConst(!unionArray[i].getBConst()); break;
default:
- infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLoc());
return 0;
}
break;
case EOpAll:
default:
- infoSink.info.message(EPrefixInternalError, "missing operator for unary constant folding", getLoc());
return 0;
}
}
break;
}
default:
- infoSink.info.message(EPrefixInternalError, "componentwise constant folding operation not implemented", aggrNode->getLoc());
return aggrNode;
}
}
case EOpReflect:
case EOpRefract:
case EOpOuterProduct:
- infoSink.info.message(EPrefixInternalError, "constant folding operation not implemented", aggrNode->getLoc());
return aggrNode;
default:
TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
{
- bool returnVal = false;
+ bool error = false;
TConstUnion* unionArray = new TConstUnion[aggrNode->getType().getObjectSize()];
if (aggrNode->getSequence().size() == 1)
- returnVal = parseConstTree(aggrNode->getLoc(), aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
+ error = parseConstTree(aggrNode->getLoc(), aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
else
- returnVal = parseConstTree(aggrNode->getLoc(), aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
+ error = parseConstTree(aggrNode->getLoc(), aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
- if (returnVal)
+ if (error)
return aggrNode;
return addConstantUnion(unionArray, aggrNode->getType(), aggrNode->getLoc());
node->setLeft(left);
node->setRight(right);
- if (! node->promote(infoSink))
+ if (! node->promote())
return 0;
node->updatePrecision();
TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
if (leftTempConstant && rightTempConstant) {
- TIntermTyped* folded = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
+ TIntermTyped* folded = leftTempConstant->fold(node->getOp(), rightTempConstant);
if (folded)
return folded;
- else
- infoSink.info.message(EPrefixInternalError, "Constant folding failed", loc);
}
return node;
node->setLeft(left);
node->setRight(child);
- if (! node->promote(infoSink))
+ if (! node->promote())
return 0;
node->updatePrecision();
if (child->getType().getBasicType() == EbtBlock)
return 0;
- if (child == 0) {
- infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", loc);
+ if (child == 0)
return 0;
- }
switch (op) {
case EOpLogicalNot:
node->setLoc(loc);
node->setOperand(child);
- if (! node->promote(infoSink))
+ if (! node->promote())
return 0;
node->updatePrecision();
if (child->getAsConstantUnion())
- return child->getAsConstantUnion()->fold(op, node->getType(), infoSink);
+ return child->getAsConstantUnion()->fold(op, node->getType());
return node;
}
// including constness (which would differ from the prototype).
//
TIntermTyped* child = childNode->getAsTyped();
- if (child == 0) {
- infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", child->getLoc());
-
+ if (child == 0)
return 0;
- }
if (child->getAsConstantUnion()) {
- TIntermTyped* folded = child->getAsConstantUnion()->fold(op, returnType, infoSink);
+ TIntermTyped* folded = child->getAsConstantUnion()->fold(op, returnType);
if (folded)
return folded;
}
//case EbtBool: newOp = EOpConvBoolToDouble; break;
//case EbtFloat: newOp = EOpConvFloatToDouble; break;
//default:
- infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLoc());
return 0;
//}
break;
case EbtBool: newOp = EOpConvBoolToFloat; break;
case EbtDouble: newOp = EOpConvDoubleToFloat; break;
default:
- infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLoc());
return 0;
}
break;
case EbtFloat: newOp = EOpConvFloatToBool; break;
case EbtDouble: newOp = EOpConvDoubleToBool; break;
default:
- infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLoc());
return 0;
}
break;
case EbtFloat: newOp = EOpConvFloatToInt; break;
case EbtDouble: newOp = EOpConvDoubleToInt; break;
default:
- infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLoc());
return 0;
}
break;
case EbtFloat: newOp = EOpConvFloatToUint; break;
case EbtDouble: newOp = EOpConvDoubleToUint; break;
default:
- infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLoc());
return 0;
}
break;
default:
- infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLoc());
return 0;
}
//
// Returns false in nothing makes sense.
//
-bool TIntermUnary::promote(TInfoSink&)
+bool TIntermUnary::promote()
{
switch (op) {
case EOpLogicalNot:
//
// Returns false if operator can't work on operands.
//
-bool TIntermBinary::promote(TInfoSink& infoSink)
+bool TIntermBinary::promote()
{
// Arrays and structures have to be exact matches.
if ((left->isArray() || right->isArray() || left->getBasicType() == EbtStruct || right->getBasicType() == EbtStruct)
setType(TType(basicType, EvqTemporary, right->getVectorSize()));
}
} else {
- infoSink.info.message(EPrefixInternalError, "Missing elses", getLoc());
return false;
}
break;
op = EOpVectorTimesScalarAssign;
}
} else {
- infoSink.info.message(EPrefixInternalError, "Missing elses", getLoc());
return false;
}
break;
TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
{
- if (node->getType().isArray())
- infoSink.info.message(EPrefixInternalError, "Cannot promote array", node->getLoc());
-
TConstUnion *rightUnionArray = node->getUnionArrayPointer();
int size = node->getType().getObjectSize();
case EbtDouble:
leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getBConst()));
break;
- default:
- infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLoc());
- return 0;
+ default:
+ return node;
}
break;
case EbtDouble:
leftUnionArray[i] = rightUnionArray[i];
break;
default:
- infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLoc());
- return 0;
+ return node;
}
break;
case EbtInt:
leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getDConst()));
break;
default:
- infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLoc());
- return 0;
+ return node;
}
break;
case EbtUint:
leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getDConst()));
break;
default:
- infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLoc());
- return 0;
+ return node;
}
break;
case EbtBool:
leftUnionArray[i].setBConst(rightUnionArray[i].getDConst() != 0.0);
break;
default:
- infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLoc());
- return 0;
+ return node;
}
break;
default:
- infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLoc());
- return 0;
+ return node;
}
}
bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink,
TSymbolTable& symbolTable)
{
- TIntermediate intermediate(infoSink, version, profile);
+ TIntermediate intermediate(version, profile);
TParseContext parseContext(symbolTable, intermediate, true, version, profile, language, infoSink);
TPpContext ppContext(parseContext);
}
bool goodProfile = DeduceProfile(compiler->infoSink, version, profile);
- TIntermediate intermediate(compiler->infoSink, version, profile);
+ TIntermediate intermediate(version, profile);
SetupBuiltinSymbolTable(version, profile);
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
if (success) {
if (messages & EShMsgAST)
- intermediate.outputTree(parseContext.treeRoot);
+ intermediate.outputTree(parseContext.treeRoot, parseContext.infoSink);
//
// Call the machine dependent compiler
parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n";
success = false;
if (messages & EShMsgAST)
- intermediate.outputTree(parseContext.treeRoot);
+ intermediate.outputTree(parseContext.treeRoot, parseContext.infoSink);
}
intermediate.remove(parseContext.treeRoot);
// Individual functions can be initialized to 0 to skip processing of that
// type of node. It's children will still be processed.
//
-void TIntermediate::outputTree(TIntermNode* root)
+void TIntermediate::outputTree(TIntermNode* root, TInfoSink& infoSink)
{
if (root == 0)
return;
public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
- TIntermediate(TInfoSink& i, int v, EProfile p) : infoSink(i), version(v), profile(p) { }
+ TIntermediate(int v, EProfile p) : version(v), profile(p) { }
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc);
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
void addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable&);
void remove(TIntermNode*);
- void outputTree(TIntermNode*);
+ void outputTree(TIntermNode*, TInfoSink&);
protected:
- TInfoSink& infoSink;
EProfile profile;
int version;
//POSSIBILITY OF SUCH DAMAGE.
//
+//
+// Travarse a tree of constants to create a single folded constant.
+// It should only be used when the whole tree is known to be constant.
+//
+
#include "ParseHelper.h"
namespace glslang {
-//
-// Use this class to carry along data from node to node in
-// the traversal
-//
class TConstTraverser : public TIntermTraverser {
public:
- TConstTraverser(TConstUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, const TType& t) : unionArray(cUnion), type(t),
- constructorType(constructType), singleConstantParam(singleConstParam), infoSink(sink), error(false), isMatrix(false),
+ TConstTraverser(TConstUnion* 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;}
int index ;
TConstUnion *unionArray;
const TType& type;
TOperator constructorType;
bool singleConstantParam;
- TInfoSink& infoSink;
bool error;
int size; // size of the constructor ( 4 for vec4)
bool isMatrix;
int matrixRows;
};
-//
-// The rest of the file are the traversal functions. The last one
-// is the one that starts the traversal.
-//
-// Return true from interior nodes to have the external traversal
-// continue on to children. If you process children yourself,
-// return false.
-//
-
-void ParseSymbol(TIntermSymbol* node, TIntermTraverser* it)
-{
- TConstTraverser* oit = static_cast<TConstTraverser*>(it);
- oit->infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLoc());
-
- return;
-}
-
-bool ParseBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
-{
- TConstTraverser* oit = static_cast<TConstTraverser*>(it);
-
- TStorageQualifier qualifier = node->getType().getQualifier().storage;
-
- if (qualifier != EvqConst) {
- const int maxSize = GlslangMaxTypeLength + 50;
- char buf[maxSize];
- snprintf(buf, maxSize, "'constructor' : assigning non-constant to %s", oit->type.getCompleteString().c_str());
- oit->infoSink.info.message(EPrefixError, buf, node->getLoc());
- oit->error = true;
-
- return false;
- }
-
- oit->infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLoc());
-
- return false;
-}
-
-bool ParseUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it)
-{
- TConstTraverser* oit = static_cast<TConstTraverser*>(it);
-
- const int maxSize = GlslangMaxTypeLength + 50;
- char buf[maxSize];
- snprintf(buf, maxSize, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str());
- oit->infoSink.info.message(EPrefixError, buf, node->getLoc());
- oit->error = true;
-
- return false;
-}
-
bool ParseAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it)
{
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
- if (!node->isConstructor() && node->getOp() != EOpComma) {
- const int maxSize = GlslangMaxTypeLength + 50;
- char buf[maxSize];
- snprintf(buf, maxSize, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str());
- oit->infoSink.info.message(EPrefixError, buf, node->getLoc());
+ if (! node->isConstructor() && node->getOp() != EOpComma) {
oit->error = true;
return false;
return false;
}
-bool ParseSelection(bool /* preVisit */, TIntermSelection* node, TIntermTraverser* it)
-{
- TConstTraverser* oit = static_cast<TConstTraverser*>(it);
- oit->infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLoc());
- oit->error = true;
- return false;
-}
-
void ParseConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
{
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
isMatrix = oit->isMatrix;
totalSize = oit->index + size;
TConstUnion *rightUnionArray = node->getUnionArrayPointer();
- if (!isMatrix) {
+ if (! isMatrix) {
int count = 0;
for (int i = oit->index; i < totalSize; i++) {
if (i >= instanceSize)
}
}
-bool ParseLoop(bool /* preVisit */, TIntermLoop* node, TIntermTraverser* it)
-{
- TConstTraverser* oit = static_cast<TConstTraverser*>(it);
- oit->infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLoc());
- oit->error = true;
-
- return false;
-}
-
-bool ParseBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it)
-{
- TConstTraverser* oit = static_cast<TConstTraverser*>(it);
- oit->infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLoc());
- oit->error = true;
-
- return false;
-}
-
-//
-// This function is the one to call externally to start the traversal.
-// Individual functions can be initialized to 0 to skip processing of that
-// type of node. It's children will still be processed.
-//
bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, TConstUnion* unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
{
if (root == 0)
return false;
- TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, t);
+ TConstTraverser it(unionArray, singleConstantParam, constructorType, t);
it.visitAggregate = ParseAggregate;
- it.visitBinary = ParseBinary;
it.visitConstantUnion = ParseConstantUnion;
- it.visitSelection = ParseSelection;
- it.visitSymbol = ParseSymbol;
- it.visitUnary = ParseUnary;
- it.visitLoop = ParseLoop;
- it.visitBranch = ParseBranch;
root->traverse(&it);
if (it.error)