From 779e6b406a3962258d744986fdda944f03cbb85d Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Thu, 17 Oct 2013 19:43:43 +0000 Subject: [PATCH] Add C-style curly-brace initializers. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23565 e7fa87d3-cd2b-0410-9028-fcbf551c1848 --- Test/420.tese | 72 +++++++++ Test/baseResults/100.frag.out | 10 +- Test/baseResults/420.tese.out | 164 ++++++++++++++++++++- Test/baseResults/specExamples.frag.out | 21 ++- Test/baseResults/specExamples.vert.out | 14 +- glslang/Include/ConstantUnion.h | 3 + glslang/MachineIndependent/ParseHelper.cpp | 100 ++++++++++++- glslang/MachineIndependent/ParseHelper.h | 3 +- glslang/MachineIndependent/glslang.y | 5 +- 9 files changed, 373 insertions(+), 19 deletions(-) diff --git a/Test/420.tese b/Test/420.tese index 37a5213f..988a26d7 100644 --- a/Test/420.tese +++ b/Test/420.tese @@ -1,6 +1,78 @@ #version 420 core +const mat2x2 a = mat2( vec2( 1.0, 0.0 ), vec2( 0.0, 1.0 ) ); +mat2x2 b = { vec2( 1.0, 0.0 ), vec2( 0.0, 1.0 ) }; +const mat2x2 c = { { 1.0, 0.0, }, { 0.0, 1.0 } }; + +float a2[2] = { 3.4, 4.2, 5.0 }; // illegal +vec2 b2 = { 1.0, 2.0, 3.0 }; // illegal +mat3x3 c2 = { vec3(0.0), vec3(1.0), vec3(2.0), vec3(3.0) }; // illegal +mat2x2 d = { 1.0, 0.0, 0.0, 1.0 }; // illegal, can't flatten nesting + +struct { + float a; + int b; +} e = { 1.2, 2, }; + +struct { + float a; + int b; +} e2 = { 1, 3 }; // legal, first initializer is converted + +struct { + float a; + int b; +} e3 = { 1.2, 2, 3 }; // illegal + +int a3 = true; // illegal +vec4 b3[2] = { vec4(0.0), 1.0 }; // illegal +vec4 b4[2] = vec4[2](vec4(0.0), mat2x2(1.0)); // illegal +mat4x2 c3 = { vec3(0.0), vec3(1.0) }; // illegal + +struct S1 { + vec4 a; + vec4 b; +}; + +struct { + float s; + float t; +} d2[] = { S1(vec4(0.0), vec4(1.1)) }; // illegal + +float b5[] = { 3.4, 4.2, 5.0, 5.2, 1.1 }; + +struct S3 { + float f; + mat2x3 m23; +}; + +struct S4 { + uvec2 uv2; + S3 s[2]; +}; + +const S4 constructed = S4(uvec2(1, 2), + S3[2](S3(3.0, mat2x3(4.0)), + S3(5.0, mat2x3(6.0)))); + +const S4 curlybad1 = { {1, 2}, + { {3, {4.0, 0, 0.0}, {0.0, 4.0, 0.0 } }, // ERROR, the mat2x3 isn't isolated + {5.0, {6, 0.0, 0.0}, {0.0, 6.0, 0.0 } } } }; + +const S4 curlyInit = { {1, 2}, + { {3, { {4.0, 0, 0.0}, {0.0, 4.0, 0.0 } } }, + {5.0, { {6, 0.0, 0.0}, {0.0, 6.0, 0.0 } } } } }; + +float vc1, vc2, vc3; +vec3 av3 = vec3(vc1, vc2, vc3); +vec3 bv3 = { vc1, vc2, vc3 }; + void main() { memoryBarrier(); + + if (constructed == curlybad1) + ; + if (constructed == curlyInit) + ; } diff --git a/Test/baseResults/100.frag.out b/Test/baseResults/100.frag.out index fc1369d0..9c30310b 100644 --- a/Test/baseResults/100.frag.out +++ b/Test/baseResults/100.frag.out @@ -1,6 +1,5 @@ ERROR: 0:3: '{ } style initializers' : not supported with this profile: es ERROR: 0:3: 'initializer' : not supported for this version or the enabled extensions -ERROR: 0:3: '=' : cannot convert from 'const int' to '3-element array of mediump int' ERROR: 0:7: 'attribute' : not supported in this stage: fragment ERROR: 0:7: 'float' : type requires declaration of default precision qualifier ERROR: 0:9: '=' : cannot convert from 'const int' to 'mediump float' @@ -21,9 +20,16 @@ ERROR: 0:38: 'array comparison' : not supported for this version or the enabled ERROR: 0:40: 'switch' : Reserved word. ERROR: 0:40: 'switch statements' : not supported for this version or the enabled extensions ERROR: 0:45: '' : array size required -ERROR: 23 compilation errors. No code generated. +ERROR: 22 compilation errors. No code generated. ERROR: node is still EOpNull! +0:3 Sequence +0:3 move second child to first child (3-element array of mediump int) +0:3 'a' (3-element array of mediump int) +0:3 Constant: +0:3 2 (const int) +0:3 3 (const int) +0:3 4 (const int) 0:17 Function Definition: main( (void) 0:17 Function Parameters: 0:19 Sequence diff --git a/Test/baseResults/420.tese.out b/Test/baseResults/420.tese.out index 951bfb5b..415129bf 100644 --- a/Test/baseResults/420.tese.out +++ b/Test/baseResults/420.tese.out @@ -1,8 +1,160 @@ Warning, version 420 is not yet complete; some version-specific features are present, but many are missing. -0:? Sequence -0:3 Function Definition: main( (void) -0:3 Function Parameters: -0:5 Sequence -0:5 MemoryBarrier (void) -0:? Linker Objects +ERROR: 0:7: '=' : cannot convert from '3-element array of float' to '2-element array of float' +ERROR: 0:8: 'initializer list' : wrong vector size (or rows in a matrix column): 2-component vector of float +ERROR: 0:9: 'initializer list' : wrong number of matrix columns: 3X3 matrix of float +ERROR: 0:10: 'initializer list' : wrong number of matrix columns: 2X2 matrix of float +ERROR: 0:25: 'initializer list' : wrong number of structure members +ERROR: 0:27: '=' : cannot convert from 'const bool' to 'int' +ERROR: 0:28: 'constructor' : cannot convert parameter 2 from 'const float' to '4-component vector of float' +ERROR: 0:29: 'constructor' : cannot convert parameter 2 from 'const 2X2 matrix of float' to 'const 4-component vector of float' +ERROR: 0:29: 'const 2-element array of 4-component vector of float' : cannot construct with these arguments +ERROR: 0:30: 'initializer list' : wrong number of matrix columns: 4X2 matrix of float +ERROR: 0:40: 'constructor' : cannot convert parameter 1 from 'float' to 'structure' +ERROR: 0:58: 'initializer list' : wrong number of structure members +ERROR: 12 compilation errors. No code generated. + +ERROR: node is still EOpNull! +0:4 Sequence +0:4 move second child to first child (2X2 matrix of float) +0:4 'b' (2X2 matrix of float) +0:4 Constant: +0:4 1.000000 +0:4 0.000000 +0:4 0.000000 +0:4 1.000000 +0:15 Sequence +0:15 move second child to first child (structure) +0:15 'e' (structure) +0:15 Constant: +0:15 1.200000 +0:15 2 (const int) +0:20 Sequence +0:20 move second child to first child (structure) +0:20 'e2' (structure) +0:20 Constant: +0:20 1.000000 +0:20 3 (const int) +0:29 Sequence +0:29 move second child to first child (2-element array of 4-component vector of float) +0:29 'b4' (2-element array of 4-component vector of float) +0:29 Construct vec4 (const 2-element array of 4-component vector of float) +0:42 Sequence +0:42 move second child to first child (5-element array of float) +0:42 'b5' (5-element array of float) +0:42 Constant: +0:42 3.400000 +0:42 4.200000 +0:42 5.000000 +0:42 5.200000 +0:42 1.100000 +0:67 Sequence +0:67 move second child to first child (3-component vector of float) +0:67 'av3' (3-component vector of float) +0:67 Construct vec3 (3-component vector of float) +0:67 'vc1' (float) +0:67 'vc2' (float) +0:67 'vc3' (float) +0:68 Sequence +0:68 move second child to first child (3-component vector of float) +0:68 'bv3' (3-component vector of float) +0:68 Construct vec3 (3-component vector of float) +0:68 'vc1' (float) +0:68 'vc2' (float) +0:68 'vc3' (float) +0:70 Function Definition: main( (void) +0:70 Function Parameters: +0:72 Sequence +0:72 MemoryBarrier (void) +0:74 Test condition and select (void) +0:74 Condition +0:74 Compare Equal (bool) +0:74 Constant: +0:74 1 (const uint) +0:74 2 (const uint) +0:74 3.000000 +0:74 4.000000 +0:74 0.000000 +0:74 0.000000 +0:74 0.000000 +0:74 4.000000 +0:74 0.000000 +0:74 5.000000 +0:74 6.000000 +0:74 0.000000 +0:74 0.000000 +0:74 0.000000 +0:74 6.000000 +0:74 0.000000 +0:74 'curlybad1' (structure) +0:74 true case is null +0:76 Test condition and select (void) +0:76 Condition +0:76 Constant: +0:76 true (const bool) +0:76 true case is null +0:? Linker Objects +0:? 'a' (const 2X2 matrix of float) +0:? 1.000000 +0:? 0.000000 +0:? 0.000000 +0:? 1.000000 +0:? 'b' (2X2 matrix of float) +0:? 'c' (const 2X2 matrix of float) +0:? 1.000000 +0:? 0.000000 +0:? 0.000000 +0:? 1.000000 +0:? 'a2' (2-element array of float) +0:? 'b2' (2-component vector of float) +0:? 'c2' (3X3 matrix of float) +0:? 'd' (2X2 matrix of float) +0:? 'e' (structure) +0:? 'e2' (structure) +0:? 'e3' (structure) +0:? 'a3' (int) +0:? 'b3' (2-element array of 4-component vector of float) +0:? 'b4' (2-element array of 4-component vector of float) +0:? 'c3' (4X2 matrix of float) +0:? 'd2' (unsized array of structure) +0:? 'b5' (5-element array of float) +0:? 'constructed' (const structure) +0:? 1 (const uint) +0:? 2 (const uint) +0:? 3.000000 +0:? 4.000000 +0:? 0.000000 +0:? 0.000000 +0:? 0.000000 +0:? 4.000000 +0:? 0.000000 +0:? 5.000000 +0:? 6.000000 +0:? 0.000000 +0:? 0.000000 +0:? 0.000000 +0:? 6.000000 +0:? 0.000000 +0:? 'curlybad1' (structure) +0:? 'curlyInit' (const structure) +0:? 1 (const uint) +0:? 2 (const uint) +0:? 3.000000 +0:? 4.000000 +0:? 0.000000 +0:? 0.000000 +0:? 0.000000 +0:? 4.000000 +0:? 0.000000 +0:? 5.000000 +0:? 6.000000 +0:? 0.000000 +0:? 0.000000 +0:? 0.000000 +0:? 6.000000 +0:? 0.000000 +0:? 'vc1' (float) +0:? 'vc2' (float) +0:? 'vc3' (float) +0:? 'av3' (3-component vector of float) +0:? 'bv3' (3-component vector of float) diff --git a/Test/baseResults/specExamples.frag.out b/Test/baseResults/specExamples.frag.out index 1a5b781c..9eb9566b 100644 --- a/Test/baseResults/specExamples.frag.out +++ b/Test/baseResults/specExamples.frag.out @@ -22,7 +22,7 @@ ERROR: 0:115: 'depth_greater' : unrecognized layout identifier ERROR: 0:118: 'depth_less' : unrecognized layout identifier ERROR: 0:121: 'depth_unchanged' : unrecognized layout identifier ERROR: 0:150: 'constructor' : constructing from a non-dereferenced array -ERROR: 0:152: '=' : cannot convert from 'const 2-element array of 4-component vector of float' to '3-element array of 4-component vector of float' +ERROR: 0:152: 'constructor' : cannot convert parameter 1 from 'const 2-element array of 4-component vector of float' to '4-component vector of float' ERROR: 0:172: 'x' : undeclared identifier ERROR: 0:172: '[]' : scalar integer expression required ERROR: 0:172: 'length' : illegal vector field selection @@ -202,6 +202,12 @@ ERROR: node is still EOpNull! 0:175 0.000000 0:178 Constant: 0:178 0.000000 +0:193 Sequence +0:193 move second child to first child (structure) +0:193 'e' (structure) +0:193 Constant: +0:193 1.200000 +0:193 2 (const int) 0:216 Sequence 0:216 Sequence 0:216 move second child to first child (5-element array of float) @@ -212,10 +218,23 @@ ERROR: node is still EOpNull! 0:216 5.000000 0:216 5.200000 0:216 1.100000 +0:217 Sequence +0:217 move second child to first child (5-element array of float) +0:217 'b' (5-element array of float) +0:217 Constant: +0:217 3.400000 +0:217 4.200000 +0:217 5.000000 +0:217 5.200000 +0:217 1.100000 0:218 Sequence 0:218 move second child to first child (5-element array of float) 0:218 'c' (5-element array of float) 0:218 'a' (5-element array of float) +0:219 Sequence +0:219 move second child to first child (5-element array of float) +0:219 'd' (5-element array of float) +0:219 'b' (5-element array of float) 0:? Linker Objects 0:? 'a' (int) 0:? 'b' (int) diff --git a/Test/baseResults/specExamples.vert.out b/Test/baseResults/specExamples.vert.out index 6cff7998..5edf37f6 100644 --- a/Test/baseResults/specExamples.vert.out +++ b/Test/baseResults/specExamples.vert.out @@ -231,7 +231,19 @@ ERROR: node is still EOpNull! 0:188 'g' (float) 0:188 Constant: 0:188 2.000000 -0:? Sequence +0:191 Sequence +0:191 Sequence +0:191 move second child to first child (2-element array of 4-component vector of float) +0:191 'b' (2-element array of 4-component vector of float) +0:191 Constant: +0:191 1.000000 +0:191 1.000000 +0:191 1.000000 +0:191 1.000000 +0:191 1.000000 +0:191 1.000000 +0:191 1.000000 +0:191 1.000000 0:192 Construct vec4 (3-element array of 4-component vector of float) 0:193 Construct vec4 (3-element array of 4-component vector of float) 0:194 Construct vec4 (3-element array of 4-component vector of float) diff --git a/glslang/Include/ConstantUnion.h b/glslang/Include/ConstantUnion.h index 1e1d18a5..c19502e8 100644 --- a/glslang/Include/ConstantUnion.h +++ b/glslang/Include/ConstantUnion.h @@ -456,6 +456,9 @@ public: if (! unionArray || ! rhs.unionArray) return false; + if (! unionArray || ! rhs.unionArray) + return false; + return *unionArray == *rhs.unionArray; } bool operator!=(const TConstUnionArray& rhs) const { return ! operator==(rhs); } diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index f04b7c32..442023ab 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -805,7 +805,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal // // It's a constructor, of type 'type'. // - result = addConstructor(intermNode, type, op, fnCall, loc); + result = addConstructor(loc, intermNode, type, op); if (result == 0) error(loc, "cannot construct with these arguments", type.getCompleteString().c_str(), ""); } @@ -2256,7 +2256,20 @@ TIntermNode* TParseContext::executeInitializer(TSourceLoc loc, TString& identifi return 0; } - // Fix arrayness if variable is unsized, getting size for initializer + // + // If the initializer was from braces { ... }, we convert the whole subtree to a + // constructor-style subtree, allowing the rest of the code to operate + // identically for both kinds of initializers. + // + initializer = convertInitializerList(loc, variable->getType(), initializer); + if (! initializer) { + // error recovery; don't leave const without constant values + if (qualifier == EvqConst) + variable->getWritableType().getQualifier().storage = EvqTemporary; + return 0; + } + + // Fix arrayness if variable is unsized, getting size from the initializer if (initializer->getType().isArray() && initializer->getType().getArraySize() > 0 && variable->getType().isArray() && variable->getType().getArraySize() == 0) variable->getWritableType().changeArraySize(initializer->getType().getArraySize()); @@ -2303,12 +2316,89 @@ TIntermNode* TParseContext::executeInitializer(TSourceLoc loc, TString& identifi return 0; } +// +// Reprocess any initalizer-list { ... } parts of the initializer. +// Need to heirarchically assign correct types and implicit +// conversions. Will do this mimicking the same process used for +// creating a constructor-style initializer, ensuring we get the +// same form. +// +TIntermTyped* TParseContext::convertInitializerList(TSourceLoc loc, const TType& type, TIntermTyped* initializer) +{ + // Will operate recursively. Once a subtree is found that is constructor style, + // everything below it is already good: Only the "top part" of the initializer + // can be an initializer list, where "top part" can extend for several (or all) levels. + + // see if we have bottomed out in the tree within the initializer-list part + TIntermAggregate* initList = initializer->getAsAggregate(); + if (! initList || initList->getOp() != EOpNull) + return initializer; + + // Of the initializer-list set of nodes, need to process bottom up, + // so recurse deep, then process on the way up. + + // Go down the tree here... + if (type.isArray()) { + // The type's array might be unsized, which could be okay, so base sizes on the size of the aggregate. + // Later on, initializer execution code will deal with array size logic. + TType arrayType; + arrayType.shallowCopy(type); + arrayType.setArraySizes(type); + arrayType.changeArraySize(initList->getSequence().size()); + TType elementType; + elementType.shallowCopy(arrayType); // TODO: arrays of arrays: combine this with deref. + elementType.dereference(); + for (size_t i = 0; i < initList->getSequence().size(); ++i) { + initList->getSequence()[i] = convertInitializerList(loc, elementType, initList->getSequence()[i]->getAsTyped()); + if (initList->getSequence()[i] == 0) + return 0; + } + + return addConstructor(loc, initList, arrayType, mapTypeToConstructorOp(arrayType)); + } else if (type.getStruct()) { + if (type.getStruct()->size() != initList->getSequence().size()) { + error(loc, "wrong number of structure members", "initializer list", ""); + return 0; + } + for (size_t i = 0; i < type.getStruct()->size(); ++i) { + initList->getSequence()[i] = convertInitializerList(loc, *(*type.getStruct())[i].type, initList->getSequence()[i]->getAsTyped()); + if (initList->getSequence()[i] == 0) + return 0; + } + } else if (type.isMatrix()) { + if (type.getMatrixCols() != initList->getSequence().size()) { + error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString().c_str()); + return 0; + } + TType vectorType; + vectorType.shallowCopy(type); // TODO: arrays of arrays: combine this with deref. + vectorType.dereference(); + for (int i = 0; i < type.getMatrixCols(); ++i) { + initList->getSequence()[i] = convertInitializerList(loc, vectorType, initList->getSequence()[i]->getAsTyped()); + if (initList->getSequence()[i] == 0) + return 0; + } + } else if (type.isVector()) { + if (type.getVectorSize() != initList->getSequence().size()) { + error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str()); + return 0; + } + } else { + error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str()); + return 0; + } + + // now that the subtree is processed, process this node + return addConstructor(loc, initList, type, mapTypeToConstructorOp(type)); +} + +// // Test for the correctness of the parameters passed to various constructor functions -// and also convert them to the right datatype if it is allowed and required. +// and also convert them to the right data type, if allowed and required. // // Returns 0 for an error or the constructed node (aggregate or typed) for no error. // -TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType& type, TOperator op, TFunction* fnCall, TSourceLoc loc) +TIntermTyped* TParseContext::addConstructor(TSourceLoc loc, TIntermNode* node, const TType& type, TOperator op) { if (node == 0) return 0; @@ -2485,7 +2575,7 @@ TIntermTyped* TParseContext::constructStruct(TIntermNode* node, const TType& typ TIntermTyped* converted = intermediate.addConversion(EOpConstructStruct, type, node->getAsTyped()); if (! converted || converted->getType() != type) { error(loc, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount, - node->getAsTyped()->getType().getCompleteTypeString().c_str(), type.getCompleteTypeString().c_str()); + node->getAsTyped()->getType().getCompleteString().c_str(), type.getCompleteString().c_str()); return 0; } diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index d18e875b..208e5faa 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -129,7 +129,7 @@ public: const TFunction* findFunction(TSourceLoc, TFunction* pfnCall, bool *builtIn = 0); TIntermNode* declareVariable(TSourceLoc, TString& identifier, TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0); - TIntermTyped* addConstructor(TIntermNode*, const TType&, TOperator, TFunction*, TSourceLoc); + TIntermTyped* addConstructor(TSourceLoc, TIntermNode*, const TType&, TOperator); TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc); TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset); void addBlock(TSourceLoc, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0); @@ -172,6 +172,7 @@ protected: TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration); void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration); TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable); + TIntermTyped* convertInitializerList(TSourceLoc, const TType&, TIntermTyped* initializer); TOperator mapTypeToConstructorOp(const TType&); void finalize(); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 695b4f85..c7159257 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -2104,11 +2104,10 @@ initializer initializer_list : initializer { - $$ = $1; + $$ = parseContext.intermediate.growAggregate(0, $1, $1->getLoc()); } | initializer_list COMMA initializer { - // TODO: 4.2 functionality: implement the initializer list - $$ = $3; + $$ = parseContext.intermediate.growAggregate($1, $3); } ;