diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 9b03b9a7..b837a25d 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -1629,7 +1629,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* // First, steer off constants, which are not SPIR-V variables, but // can still have a mapping to a SPIR-V Id. // This includes specialization constants. - if (node->getQualifier().storage == glslang::EvqConst) { + if (node->getQualifier().isConstant()) { return createSpvSpecConstant(*node); } @@ -3732,7 +3732,7 @@ void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::De // - when running into a non-spec-constant, switch to createSpvConstant() spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node) { - assert(node.getQualifier().storage == glslang::EvqConst); + assert(node.getQualifier().isConstant()); if (! node.getQualifier().specConstant) { // hand off to the non-spec-constant path diff --git a/Test/baseResults/310.comp.out b/Test/baseResults/310.comp.out index ff438e3a..d6b03322 100644 --- a/Test/baseResults/310.comp.out +++ b/Test/baseResults/310.comp.out @@ -337,7 +337,7 @@ ERROR: node is still EOpNull! 0:201 1 (const int) 0:201 Constant: 0:201 2 (const int) -0:202 Test condition and select (layout(column_major shared ) temp highp float) +0:202 Test condition and select (temp highp float) 0:202 Condition 0:202 'b' (temp bool) 0:202 true case @@ -764,7 +764,7 @@ ERROR: node is still EOpNull! 0:201 1 (const int) 0:201 Constant: 0:201 2 (const int) -0:202 Test condition and select (layout(column_major shared ) temp highp float) +0:202 Test condition and select (temp highp float) 0:202 Condition 0:202 'b' (temp bool) 0:202 true case diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index c88bca67..1d126569 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -411,6 +411,19 @@ public: clearLayout(); } + // Drop just the storage qualification, which perhaps should + // never be done, as it is fundamentally inconsistent, but need to + // explore what downstream consumers need. + // E.g., in a deference, it is an inconsistency between: + // A) partially dereferenced resource is still in the storage class it started in + // B) partially dereferenced resource is a new temporary object + // If A, then nothing should change, if B, then everything should change, but this is half way. + void makePartialTemporary() + { + storage = EvqTemporary; + specConstant = false; + } + TStorageQualifier storage : 6; TBuiltInVariable builtIn : 8; TPrecisionQualifier precision : 3; diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 66c3680c..5f474911 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -822,7 +822,7 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true // Make a selection node. // TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); - node->getQualifier().storage = EvqTemporary; + node->getQualifier().makeTemporary(); node->setLoc(loc); node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision); diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 28af0d40..9057b345 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().storage == EvqConst) { + if (index->getQualifier().isConstant()) { indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst(); checkIndex(loc, base->getType(), indexValue); } @@ -495,7 +495,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), ""); else error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", ""); - } else if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst) + } else if (base->getType().getQualifier().isFrontEndConstant() && index->getQualifier().isFrontEndConstant()) return intermediate.foldDereference(base, indexValue, loc); else { // at least one of base and index is variable... @@ -503,7 +503,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn if (base->getAsSymbolNode() && isIoResizeArray(base->getType())) handleIoResizeArrayAccess(loc, base); - if (index->getQualifier().storage == EvqConst) { + if (index->getQualifier().isConstant()) { if (base->getType().isImplicitlySizedArray()) updateImplicitArraySize(loc, base, indexValue); result = intermediate.addIndex(EOpIndexDirect, base, index, loc); @@ -541,10 +541,10 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn } else { // Insert valid dereferenced result TType newType(base->getType(), 0); // dereferenced type - if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst) + if (base->getType().getQualifier().isFrontEndConstant() && index->getQualifier().isFrontEndConstant()) newType.getQualifier().storage = EvqConst; else - newType.getQualifier().storage = EvqTemporary; + newType.getQualifier().makePartialTemporary(); result->setType(newType); if (anyIndexLimits) @@ -587,7 +587,7 @@ void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* b (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() && ! base->getType().getQualifier().isPipeInput() && ! base->getType().getQualifier().isPipeOutput() && - base->getType().getQualifier().storage != EvqConst) || + ! base->getType().getQualifier().isConstant()) || (! 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 @@ -849,7 +849,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm } } if (fieldFound) { - if (base->getType().getQualifier().storage == EvqConst) + if (base->getType().getQualifier().isFrontEndConstant()) result = intermediate.foldDereference(base, member, loc); else { blockMemberExtensionCheck(loc, base, field); @@ -2039,7 +2039,7 @@ void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TInt // void TParseContext::constantValueCheck(TIntermTyped* node, const char* token) { - if (node->getQualifier().storage != EvqConst) + if (! node->getQualifier().isConstant()) error(node->getLoc(), "constant expression required", token, ""); } @@ -2204,6 +2204,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T int size = 0; bool constType = true; + bool specConstType = true; bool full = false; bool overFull = false; bool matrixInMatrix = false; @@ -2232,12 +2233,17 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T if (op != EOpConstructStruct && ! type.isArray() && size >= type.computeNumComponents()) full = true; - if (function[arg].type->getQualifier().storage != EvqConst) + if (! function[arg].type->getQualifier().isConstant()) constType = false; + if (! function[arg].type->getQualifier().isSpecConstant()) + specConstType = false; } - if (constType) + if (constType) { type.getQualifier().storage = EvqConst; + if (specConstType) + type.getQualifier().specConstant = true; + } if (type.isArray()) { if (function.getParamCount() == 0) { @@ -3147,7 +3153,7 @@ void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier // if (type.getQualifier().storage == EvqConst || type.getQualifier().storage == EvqConstReadOnly) { - type.getQualifier().storage = EvqTemporary; + type.getQualifier().makeTemporary(); error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), ""); } } @@ -4848,7 +4854,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp if (! initializer) { // error recovery; don't leave const without constant values if (qualifier == EvqConst) - variable->getWritableType().getQualifier().storage = EvqTemporary; + variable->getWritableType().getQualifier().makeTemporary(); return nullptr; } @@ -4868,21 +4874,22 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp } } - // Uniform and global consts require a constant initializer - if (qualifier == EvqUniform && initializer->getType().getQualifier().storage != EvqConst) { + // Uniforms require a compile-time constant initializer + if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) { error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str()); - variable->getWritableType().getQualifier().storage = EvqTemporary; + variable->getWritableType().getQualifier().makeTemporary(); return nullptr; } - if (qualifier == EvqConst && symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) { + // Global consts require a constant initializer (specialization constant is okay) + if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) { error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str()); - variable->getWritableType().getQualifier().storage = EvqTemporary; + variable->getWritableType().getQualifier().makeTemporary(); return nullptr; } // Const variables require a constant initializer, depending on version if (qualifier == EvqConst) { - if (initializer->getType().getQualifier().storage != EvqConst) { + if (! initializer->getType().getQualifier().isConstant()) { const char* initFeature = "non-constant initializer"; requireProfile(loc, ~EEsProfile, initFeature); profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); @@ -4894,7 +4901,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp // // "In declarations of global variables with no storage qualifier or with a const // qualifier any initializer must be a constant expression." - if (symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) { + if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) { const char* initFeature = "non-constant global initializer"; if (relaxedErrors()) warn(loc, "not allowed in this version", initFeature, ""); @@ -4910,7 +4917,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp if (! initializer || ! initializer->getAsConstantUnion() || variable->getType() != initializer->getType()) { error(loc, "non-matching or non-convertible constant type for const initializer", variable->getType().getStorageQualifierString(), ""); - variable->getWritableType().getQualifier().storage = EvqTemporary; + variable->getWritableType().getQualifier().makeTemporary(); return nullptr; }