From 0840838d1739f2d5ebfe2037f4c6f09478710689 Mon Sep 17 00:00:00 2001 From: qining <qining@google.com> Date: Mon, 21 Mar 2016 09:51:37 -0400 Subject: [PATCH] Support specialization composite constants Fix issue #163, support creation and reference of composite type specialization constants. e.g.: ``` layout(constant_id = 200) const float myfloat = 1.25; layout(constant_id = 201) const int myint = 14; struct structtype { float f; int i; }; const structtype outer_struct_var = {myfloat, myint}; void main(){} ``` generated code (use glslangValidator): ``` // Module Version 10000 // Generated by (magic number): 80001 // Id's are bound by 12 Capability Shader 1: ExtInstImport "GLSL.std.450" MemoryModel Logical GLSL450 EntryPoint Vertex 4 "main" Source GLSL 450 Name 4 "main" Name 10 "structtype" MemberName 10(structtype) 0 "f" MemberName 10(structtype) 1 "i" Decorate 7 SpecId 200 Decorate 9 SpecId 201 2: TypeVoid 3: TypeFunction 2 6: TypeFloat 32 7: 6(float) SpecConstant 1067450368 8: TypeInt 32 1 9: 8(int) SpecConstant 14 10(structtype): TypeStruct 6(float) 8(int) 11:10(structtype) SpecConstantComposite 7 9 4(main): 2 Function None 3 5: Label Return FunctionEnd ``` Rname two function names to match their functionalities. 1) Rename `GlslangToSpvTraverser::createSpvSpecConstant()` to `createSpvConstant()`; 2) Rename `GlslangToSpvTraverser::createSpvConstant()` to `createSpvConstantFromConstUnionArray()` Add function `GlslangToSpvTraverser::createSpvConstantFromSubTree()` to handle constant creation from sub trees (e.g.: specialization constants). Related PR: #208 --- SPIRV/GlslangToSpv.cpp | 87 +++++++-- .../spv.specConstantComposite.vert.out | 172 ++++++++++++++++++ Test/spv.specConstantComposite.vert | 93 ++++++++++ Test/test-spirv-list | 1 + glslang/Include/Types.h | 1 + glslang/MachineIndependent/ParseHelper.cpp | 27 ++- 6 files changed, 362 insertions(+), 19 deletions(-) create mode 100644 Test/baseResults/spv.specConstantComposite.vert.out create mode 100644 Test/spv.specConstantComposite.vert diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 6f5697e3db..dd5afd4b66 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -128,8 +128,9 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { void addDecoration(spv::Id id, spv::Decoration dec, unsigned value); void addMemberDecoration(spv::Id id, int member, spv::Decoration dec); void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value); - spv::Id createSpvSpecConstant(const glslang::TIntermTyped&); - spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant); + spv::Id createSpvConstant(const glslang::TIntermTyped&); + spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant); + spv::Id createSpvConstantFromConstSubTree(const glslang::TIntermTyped* subTree); bool isTrivialLeaf(const glslang::TIntermTyped* node); bool isTrivial(const glslang::TIntermTyped* node); spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right); @@ -1520,7 +1521,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node) { int nextConst = 0; - spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst, false); + spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false); builder.clearAccessChain(); builder.setAccessChainRValue(constant); @@ -1630,7 +1631,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* // can still have a mapping to a SPIR-V Id. // This includes specialization constants. if (node->getQualifier().isConstant()) { - return createSpvSpecConstant(*node); + return createSpvConstant(*node); } // Now, handle actual variables @@ -3730,7 +3731,7 @@ void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::De // recursively walks. So, this function walks the "top" of the tree: // - emit specialization constant-building instructions for specConstant // - when running into a non-spec-constant, switch to createSpvConstant() -spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node) +spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node) { assert(node.getQualifier().isConstant()); @@ -3738,7 +3739,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType // hand off to the non-spec-constant path assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr); int nextConst = 0; - return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), + return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), nextConst, false); } @@ -3747,7 +3748,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType if (node.getAsSymbolNode() && node.getQualifier().hasSpecConstantId()) { // this is a direct literal assigned to a layout(constant_id=) declaration int nextConst = 0; - return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), + return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), nextConst, true); } else { // gl_WorkgroupSize is a special case until the front-end handles hierarchical specialization constants, @@ -3761,8 +3762,10 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType addDecoration(dimConstId.back(), spv::DecorationSpecId, glslangIntermediate->getLocalSizeSpecId(dim)); } return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true); + } else if (auto* sn = node.getAsSymbolNode()){ + return createSpvConstantFromConstSubTree(sn->getConstSubtree()); } else { - spv::MissingFunctionality("specialization-constant expression trees"); + spv::MissingFunctionality("Neither a front-end constant nor a spec constant."); exit(1); return spv::NoResult; } @@ -3775,7 +3778,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType // If there are not enough elements present in 'consts', 0 will be substituted; // an empty 'consts' can be used to create a fully zeroed SPIR-V constant. // -spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant) +spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant) { // vector of constants for SPIR-V std::vector<spv::Id> spvConsts; @@ -3786,15 +3789,15 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT if (glslangType.isArray()) { glslang::TType elementType(glslangType, 0); for (int i = 0; i < glslangType.getOuterArraySize(); ++i) - spvConsts.push_back(createSpvConstant(elementType, consts, nextConst, false)); + spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false)); } else if (glslangType.isMatrix()) { glslang::TType vectorType(glslangType, 0); for (int col = 0; col < glslangType.getMatrixCols(); ++col) - spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst, false)); + spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false)); } else if (glslangType.getStruct()) { glslang::TVector<glslang::TTypeLoc>::const_iterator iter; for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter) - spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst, false)); + spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false)); } else if (glslangType.isVector()) { for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) { bool zero = nextConst >= consts.size(); @@ -3851,6 +3854,66 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT return builder.makeCompositeConstant(typeId, spvConsts); } +// Create constant ID from const initializer sub tree. +spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstSubTree( + const glslang::TIntermTyped* subTree) { + const glslang::TType& glslangType = subTree->getType(); + spv::Id typeId = convertGlslangToSpvType(glslangType); + bool is_spec_const = subTree->getType().getQualifier().isSpecConstant(); + if (const glslang::TIntermAggregate* an = subTree->getAsAggregate()) { + // Aggregate node, we should generate OpConstantComposite or + // OpSpecConstantComposite instruction. + std::vector<spv::Id> const_constituents; + for (auto NI = an->getSequence().begin(); NI != an->getSequence().end(); + NI++) { + const_constituents.push_back( + createSpvConstantFromConstSubTree((*NI)->getAsTyped())); + } + // Note that constructors are aggregate nodes, so expressions like: + // float x = float(y) will become an aggregate node. If 'x' is declared + // as a constant, the aggregate node representing 'float(y)' will be + // processed here. + if (builder.isVectorType(typeId) || builder.isMatrixType(typeId) || + builder.isAggregateType(typeId)) { + return builder.makeCompositeConstant(typeId, const_constituents, is_spec_const); + } else { + assert(builder.isScalarType(typeId) && const_constituents.size() == 1); + return const_constituents.front(); + } + + } else if (const glslang::TIntermBinary* bn = subTree->getAsBinaryNode()) { + // Binary operation node, we should generate OpSpecConstantOp <binary op> + // This case should only happen when Specialization Constants are involved. + spv::MissingFunctionality("OpSpecConstantOp <binary op> not implemented"); + return spv::NoResult; + + } else if (const glslang::TIntermUnary* un = subTree->getAsUnaryNode()) { + // Unary operation node, similar to binary operation node, should only + // happen when specialization constants are involved. + spv::MissingFunctionality("OpSpecConstantOp <unary op> not implemented"); + return spv::NoResult; + + } else if (const glslang::TIntermConstantUnion* cn = subTree->getAsConstantUnion()) { + // ConstantUnion node, should redirect to + // createSpvConstantFromConstUnionArray + int nextConst = 0; + return createSpvConstantFromConstUnionArray( + glslangType, cn->getConstArray(), nextConst, is_spec_const); + + } else if (const glslang::TIntermSymbol* sn = subTree->getAsSymbolNode()) { + // Symbol node. Call getSymbolId(). This should cover both cases 1) the + // symbol has already been assigned an ID, 2) need a new ID for this + // symbol. + return getSymbolId(sn); + + } else { + spv::MissingFunctionality( + "createSpvConstantFromConstSubTree() not covered TIntermTyped* const " + "initializer subtree."); + return spv::NoResult; + } +} + // Return true if the node is a constant or symbol whose reading has no // non-trivial observable cost or effect. bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node) diff --git a/Test/baseResults/spv.specConstantComposite.vert.out b/Test/baseResults/spv.specConstantComposite.vert.out new file mode 100644 index 0000000000..5e2dfa4a76 --- /dev/null +++ b/Test/baseResults/spv.specConstantComposite.vert.out @@ -0,0 +1,172 @@ +spv.specConstantComposite.vert +Warning, version 450 is not yet complete; most version-specific features are present, but some are missing. + + +Linked vertex stage: + + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 106 + + Capability Shader + Capability Float64 + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" 27 105 + Source GLSL 450 + Name 4 "main" + Name 6 "refer_primary_spec_const(" + Name 8 "refer_composite_spec_const(" + Name 10 "refer_copmosite_dot_dereference(" + Name 12 "refer_composite_bracket_dereference(" + Name 16 "refer_spec_const_array_length(" + Name 18 "declare_spec_const_in_func(" + Name 27 "color" + Name 41 "flat_struct" + MemberName 41(flat_struct) 0 "i" + MemberName 41(flat_struct) 1 "f" + MemberName 41(flat_struct) 2 "d" + MemberName 41(flat_struct) 3 "b" + Name 42 "nesting_struct" + MemberName 42(nesting_struct) 0 "nested" + MemberName 42(nesting_struct) 1 "v" + MemberName 42(nesting_struct) 2 "i" + Name 72 "indexable" + Name 76 "indexable" + Name 83 "len" + Name 105 "global_vec4_array_with_spec_length" + Decorate 21 SpecId 203 + Decorate 28 SpecId 200 + Decorate 32 SpecId 201 + Decorate 43 SpecId 202 + 2: TypeVoid + 3: TypeFunction 2 + 14: TypeInt 32 1 + 15: TypeFunction 14(int) + 20: TypeBool + 21: 20(bool) SpecConstantTrue + 24: TypeFloat 32 + 25: TypeVector 24(float) 4 + 26: TypePointer Output 25(fvec4) + 27(color): 26(ptr) Variable Output + 28: 14(int) SpecConstant 3 + 32: 24(float) SpecConstant 1078523331 + 33: 25(fvec4) SpecConstantComposite 32 32 32 32 + 36: 24(float) Constant 1133908460 + 37: 25(fvec4) SpecConstantComposite 32 32 36 36 + 40: TypeFloat 64 + 41(flat_struct): TypeStruct 14(int) 24(float) 40(float) 20(bool) +42(nesting_struct): TypeStruct 41(flat_struct) 25(fvec4) 14(int) + 43: 40(float) SpecConstant 1413754136 1074340347 + 44:41(flat_struct) SpecConstantComposite 28 32 43 21 + 45:42(nesting_struct) SpecConstantComposite 44 33 28 + 46: 14(int) Constant 2 + 51: TypeInt 32 0 + 52: 51(int) Constant 0 + 57: 51(int) Constant 5 + 58: TypeArray 24(float) 57 + 59: 24(float) Constant 1065353216 + 60: 24(float) Constant 1073741824 + 61: 24(float) Constant 1077936128 + 62: 58 SpecConstantComposite 32 32 59 60 61 + 63: 14(int) Constant 1 + 68: TypeArray 14(int) 57 + 69: 14(int) Constant 30 + 70: 68 SpecConstantComposite 28 28 63 46 69 + 71: TypePointer Function 68 + 73: TypePointer Function 14(int) + 87: 24(float) Constant 1106321080 + 88:41(flat_struct) SpecConstantComposite 69 87 43 21 + 89: 14(int) Constant 10 + 90:42(nesting_struct) SpecConstantComposite 88 37 89 + 96: 20(bool) ConstantFalse + 97:41(flat_struct) SpecConstantComposite 28 32 43 96 + 98: 24(float) Constant 1036831949 + 99: 25(fvec4) ConstantComposite 98 98 98 98 + 100:42(nesting_struct) SpecConstantComposite 97 99 28 + 101: 14(int) Constant 3000 + 102:42(nesting_struct) SpecConstantComposite 88 37 101 + 103: TypeArray 25(fvec4) 28 + 104: TypePointer Input 103 +105(global_vec4_array_with_spec_length): 104(ptr) Variable Input + 4(main): 2 Function None 3 + 5: Label + Return + FunctionEnd +6(refer_primary_spec_const(): 2 Function None 3 + 7: Label + SelectionMerge 23 None + BranchConditional 21 22 23 + 22: Label + 29: 24(float) ConvertSToF 28 + 30: 25(fvec4) Load 27(color) + 31: 25(fvec4) VectorTimesScalar 30 29 + Store 27(color) 31 + Branch 23 + 23: Label + Return + FunctionEnd +8(refer_composite_spec_const(): 2 Function None 3 + 9: Label + 34: 25(fvec4) Load 27(color) + 35: 25(fvec4) FAdd 34 33 + Store 27(color) 35 + 38: 25(fvec4) Load 27(color) + 39: 25(fvec4) FSub 38 37 + Store 27(color) 39 + Return + FunctionEnd +10(refer_copmosite_dot_dereference(): 2 Function None 3 + 11: Label + 47: 14(int) CompositeExtract 45 2 + 48: 24(float) ConvertSToF 47 + 49: 25(fvec4) Load 27(color) + 50: 25(fvec4) VectorTimesScalar 49 48 + Store 27(color) 50 + 53: 24(float) CompositeExtract 33 0 + 54: 25(fvec4) Load 27(color) + 55: 25(fvec4) CompositeConstruct 53 53 53 53 + 56: 25(fvec4) FAdd 54 55 + Store 27(color) 56 + Return + FunctionEnd +12(refer_composite_bracket_dereference(): 2 Function None 3 + 13: Label + 72(indexable): 71(ptr) Variable Function + 76(indexable): 71(ptr) Variable Function + 64: 24(float) CompositeExtract 62 1 + 65: 25(fvec4) Load 27(color) + 66: 25(fvec4) CompositeConstruct 64 64 64 64 + 67: 25(fvec4) FSub 65 66 + Store 27(color) 67 + Store 72(indexable) 70 + 74: 73(ptr) AccessChain 72(indexable) 28 + 75: 14(int) Load 74 + Store 76(indexable) 70 + 77: 73(ptr) AccessChain 76(indexable) 75 + 78: 14(int) Load 77 + 79: 24(float) ConvertSToF 78 + 80: 25(fvec4) Load 27(color) + 81: 25(fvec4) CompositeConstruct 79 79 79 79 + 82: 25(fvec4) FDiv 80 81 + Store 27(color) 82 + Return + FunctionEnd +16(refer_spec_const_array_length(): 14(int) Function None 15 + 17: Label + 83(len): 73(ptr) Variable Function + Store 83(len) 28 + 84: 14(int) Load 83(len) + ReturnValue 84 + FunctionEnd +18(declare_spec_const_in_func(): 2 Function None 3 + 19: Label + 91: 14(int) CompositeExtract 90 2 + 92: 24(float) ConvertSToF 91 + 93: 25(fvec4) Load 27(color) + 94: 25(fvec4) CompositeConstruct 92 92 92 92 + 95: 25(fvec4) FDiv 93 94 + Store 27(color) 95 + Return + FunctionEnd diff --git a/Test/spv.specConstantComposite.vert b/Test/spv.specConstantComposite.vert new file mode 100644 index 0000000000..4450ddd668 --- /dev/null +++ b/Test/spv.specConstantComposite.vert @@ -0,0 +1,93 @@ +#version 450 + +// constant_id specified scalar spec constants +layout(constant_id = 200) const int spec_int = 3; +layout(constant_id = 201) const float spec_float = 3.14; +layout(constant_id = 202) const + double spec_double = 3.1415926535897932384626433832795; +layout(constant_id = 203) const bool spec_bool = true; + +const float cast_spec_float = float(spec_float); + +// Flat struct +struct flat_struct { + int i; + float f; + double d; + bool b; +}; + +// Nesting struct +struct nesting_struct { + flat_struct nested; + vec4 v; + int i; +}; + +// Expect OpSpecConstantComposite +// Flat struct initializer +const flat_struct spec_flat_struct_all_spec = {spec_int, spec_float, + spec_double, spec_bool}; +const flat_struct spec_flat_struct_partial_spec = {30, 30.14, spec_double, + spec_bool}; + +// Nesting struct initializer +const nesting_struct nesting_struct_ctor = { + {spec_int, spec_float, spec_double, false}, + vec4(0.1, 0.1, 0.1, 0.1), + spec_int}; + +// Vector constructor +const vec4 spec_vec4_all_spec = + vec4(spec_float, spec_float, spec_float, spec_float); +const vec4 spec_vec4_partial_spec = + vec4(spec_float, spec_float, 300.14, 300.14); + +// Struct nesting constructor +const nesting_struct spec_nesting_struct_all_spec = { + spec_flat_struct_all_spec, spec_vec4_all_spec, spec_int}; +const nesting_struct spec_nesting_struct_partial_spec = { + spec_flat_struct_partial_spec, spec_vec4_partial_spec, 3000}; + +const float spec_float_array[5] = {spec_float, spec_float, 1.0, 2.0, 3.0}; +const int spec_int_array[5] = {spec_int, spec_int, 1, 2, 30}; + +// global_vec4_array_with_spec_length is not a spec constant, but its array +// size is. When calling global_vec4_array_with_spec_length.length(), A +// TIntermSymbol Node shoule be returned, instead of a TIntermConstantUnion +// node which represents a known constant value. +in vec4 global_vec4_array_with_spec_length[spec_int]; + +out vec4 color; + +void refer_primary_spec_const() { + if (spec_bool) color *= spec_int; +} + +void refer_composite_spec_const() { + color += spec_vec4_all_spec; + color -= spec_vec4_partial_spec; +} + +void refer_copmosite_dot_dereference() { + color *= spec_nesting_struct_all_spec.i; + color += spec_vec4_all_spec.x; +} + +void refer_composite_bracket_dereference() { + color -= spec_float_array[1]; + color /= spec_int_array[spec_int_array[spec_int]]; +} + +int refer_spec_const_array_length() { + int len = global_vec4_array_with_spec_length.length(); + return len; +} + +void declare_spec_const_in_func() { + const nesting_struct spec_const_declared_in_func = { + spec_flat_struct_partial_spec, spec_vec4_partial_spec, 10}; + color /= spec_const_declared_in_func.i; +} + +void main() {} diff --git a/Test/test-spirv-list b/Test/test-spirv-list index 0e22367402..4534132f2b 100644 --- a/Test/test-spirv-list +++ b/Test/test-spirv-list @@ -102,6 +102,7 @@ spv.pushConstant.vert spv.subpass.frag spv.specConstant.vert spv.specConstant.comp +spv.specConstantComposite.vert # GLSL-level semantics vulkan.frag vulkan.vert diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 05681c9a41..bff7e9a95f 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -1223,6 +1223,7 @@ class TType { virtual int getMatrixCols() const { return matrixCols; } virtual int getMatrixRows() const { return matrixRows; } virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); } + virtual TIntermTyped* getOuterArrayNode() const { return arraySizes->getOuterNode(); } virtual int getCumulativeArraySize() const { return arraySizes->getCumulativeSize(); } virtual bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; } virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); } diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 132963183b..5de89e1b32 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -484,7 +484,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn TIntermTyped* result = nullptr; int indexValue = 0; - if (index->getQualifier().isConstant()) { + if (index->getQualifier().isFrontEndConstant()) { indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst(); checkIndex(loc, base->getType(), indexValue); } @@ -503,7 +503,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn if (base->getAsSymbolNode() && isIoResizeArray(base->getType())) handleIoResizeArrayAccess(loc, base); - if (index->getQualifier().isConstant()) { + if (index->getQualifier().isFrontEndConstant()) { if (base->getType().isImplicitlySizedArray()) updateImplicitArraySize(loc, base, indexValue); result = intermediate.addIndex(EOpIndexDirect, base, index, loc); @@ -541,10 +541,15 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn } else { // Insert valid dereferenced result TType newType(base->getType(), 0); // dereferenced type - if (base->getType().getQualifier().isFrontEndConstant() && index->getQualifier().isFrontEndConstant()) + if (base->getType().getQualifier().isConstant() && index->getQualifier().isConstant()) { newType.getQualifier().storage = EvqConst; - else + // If base or index is a specialization constant, the result should also be a specialization constant. + if (base->getType().getQualifier().isSpecConstant() || index->getQualifier().isSpecConstant()) { + newType.getQualifier().makeSpecConstant(); + } + } else { newType.getQualifier().makePartialTemporary(); + } result->setType(newType); if (anyIndexLimits) @@ -1226,6 +1231,11 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction else error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method"); } + } else if (type.getOuterArrayNode()) { + // If the array's outer size is specified by an intermediate node, it means the array's length + // was specified by a specialization constant. In such a case, we should return the node of the + // specialization constants to represent the length. + return type.getOuterArrayNode(); } else length = type.getOuterArraySize(); } else if (type.isMatrix()) @@ -5110,7 +5120,8 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* // We don't know "top down" whether type is a specialization constant, // but a const becomes a specialization constant if any of its children are. - bool specConst = false; + bool hasSpecConst = false; + bool isConstConstrutor = true; for (TIntermSequence::iterator p = sequenceVector.begin(); p != sequenceVector.end(); p++, paramCount++) { @@ -5123,14 +5134,16 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* if (newNode) { *p = newNode; + if (! newNode->getType().getQualifier().isConstant()) + isConstConstrutor = false; if (newNode->getType().getQualifier().isSpecConstant()) - specConst = true; + hasSpecConst = true; } else return nullptr; } TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, type, loc); - if (constructor->getType().getQualifier().isConstant() && specConst) + if (isConstConstrutor && hasSpecConst) constructor->getWritableType().getQualifier().makeSpecConstant(); return constructor;