mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-12 21:20:06 +00:00
Front-end infrastructure: Encapsulate semantic-level questions/actions about const/temp.
Much about const or temp is mechanical, about actual declaration, while much is semantic, about something higher level. This commit checks every use everywhere, and for the high-level ones, substitutes an encapsulated version instead.
This commit is contained in:
parent
952543e757
commit
7cc0e2896e
@ -1629,7 +1629,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
|
|||||||
// First, steer off constants, which are not SPIR-V variables, but
|
// First, steer off constants, which are not SPIR-V variables, but
|
||||||
// can still have a mapping to a SPIR-V Id.
|
// can still have a mapping to a SPIR-V Id.
|
||||||
// This includes specialization constants.
|
// This includes specialization constants.
|
||||||
if (node->getQualifier().storage == glslang::EvqConst) {
|
if (node->getQualifier().isConstant()) {
|
||||||
return createSpvSpecConstant(*node);
|
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()
|
// - when running into a non-spec-constant, switch to createSpvConstant()
|
||||||
spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
|
spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
|
||||||
{
|
{
|
||||||
assert(node.getQualifier().storage == glslang::EvqConst);
|
assert(node.getQualifier().isConstant());
|
||||||
|
|
||||||
if (! node.getQualifier().specConstant) {
|
if (! node.getQualifier().specConstant) {
|
||||||
// hand off to the non-spec-constant path
|
// hand off to the non-spec-constant path
|
||||||
|
@ -337,7 +337,7 @@ ERROR: node is still EOpNull!
|
|||||||
0:201 1 (const int)
|
0:201 1 (const int)
|
||||||
0:201 Constant:
|
0:201 Constant:
|
||||||
0:201 2 (const int)
|
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 Condition
|
||||||
0:202 'b' (temp bool)
|
0:202 'b' (temp bool)
|
||||||
0:202 true case
|
0:202 true case
|
||||||
@ -764,7 +764,7 @@ ERROR: node is still EOpNull!
|
|||||||
0:201 1 (const int)
|
0:201 1 (const int)
|
||||||
0:201 Constant:
|
0:201 Constant:
|
||||||
0:201 2 (const int)
|
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 Condition
|
||||||
0:202 'b' (temp bool)
|
0:202 'b' (temp bool)
|
||||||
0:202 true case
|
0:202 true case
|
||||||
|
@ -411,6 +411,19 @@ public:
|
|||||||
clearLayout();
|
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;
|
TStorageQualifier storage : 6;
|
||||||
TBuiltInVariable builtIn : 8;
|
TBuiltInVariable builtIn : 8;
|
||||||
TPrecisionQualifier precision : 3;
|
TPrecisionQualifier precision : 3;
|
||||||
|
@ -822,7 +822,7 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
|
|||||||
// Make a selection node.
|
// Make a selection node.
|
||||||
//
|
//
|
||||||
TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
|
TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
|
||||||
node->getQualifier().storage = EvqTemporary;
|
node->getQualifier().makeTemporary();
|
||||||
node->setLoc(loc);
|
node->setLoc(loc);
|
||||||
node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
|
node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
|
||||||
|
|
||||||
|
@ -484,7 +484,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|||||||
TIntermTyped* result = nullptr;
|
TIntermTyped* result = nullptr;
|
||||||
|
|
||||||
int indexValue = 0;
|
int indexValue = 0;
|
||||||
if (index->getQualifier().storage == EvqConst) {
|
if (index->getQualifier().isConstant()) {
|
||||||
indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst();
|
indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||||
checkIndex(loc, base->getType(), indexValue);
|
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(), "");
|
error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
|
||||||
else
|
else
|
||||||
error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", "");
|
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);
|
return intermediate.foldDereference(base, indexValue, loc);
|
||||||
else {
|
else {
|
||||||
// at least one of base and index is variable...
|
// 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()))
|
if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
|
||||||
handleIoResizeArrayAccess(loc, base);
|
handleIoResizeArrayAccess(loc, base);
|
||||||
|
|
||||||
if (index->getQualifier().storage == EvqConst) {
|
if (index->getQualifier().isConstant()) {
|
||||||
if (base->getType().isImplicitlySizedArray())
|
if (base->getType().isImplicitlySizedArray())
|
||||||
updateImplicitArraySize(loc, base, indexValue);
|
updateImplicitArraySize(loc, base, indexValue);
|
||||||
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
|
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
|
||||||
@ -541,10 +541,10 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|||||||
} else {
|
} else {
|
||||||
// Insert valid dereferenced result
|
// Insert valid dereferenced result
|
||||||
TType newType(base->getType(), 0); // dereferenced type
|
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;
|
newType.getQualifier().storage = EvqConst;
|
||||||
else
|
else
|
||||||
newType.getQualifier().storage = EvqTemporary;
|
newType.getQualifier().makePartialTemporary();
|
||||||
result->setType(newType);
|
result->setType(newType);
|
||||||
|
|
||||||
if (anyIndexLimits)
|
if (anyIndexLimits)
|
||||||
@ -587,7 +587,7 @@ void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* b
|
|||||||
(! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() &&
|
(! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() &&
|
||||||
! base->getType().getQualifier().isPipeInput() &&
|
! base->getType().getQualifier().isPipeInput() &&
|
||||||
! base->getType().getQualifier().isPipeOutput() &&
|
! base->getType().getQualifier().isPipeOutput() &&
|
||||||
base->getType().getQualifier().storage != EvqConst) ||
|
! base->getType().getQualifier().isConstant()) ||
|
||||||
(! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() ||
|
(! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() ||
|
||||||
base->getType().getQualifier().isPipeOutput()))) {
|
base->getType().getQualifier().isPipeOutput()))) {
|
||||||
// it's too early to know what the inductive variables are, save it for post processing
|
// 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 (fieldFound) {
|
||||||
if (base->getType().getQualifier().storage == EvqConst)
|
if (base->getType().getQualifier().isFrontEndConstant())
|
||||||
result = intermediate.foldDereference(base, member, loc);
|
result = intermediate.foldDereference(base, member, loc);
|
||||||
else {
|
else {
|
||||||
blockMemberExtensionCheck(loc, base, field);
|
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)
|
void TParseContext::constantValueCheck(TIntermTyped* node, const char* token)
|
||||||
{
|
{
|
||||||
if (node->getQualifier().storage != EvqConst)
|
if (! node->getQualifier().isConstant())
|
||||||
error(node->getLoc(), "constant expression required", token, "");
|
error(node->getLoc(), "constant expression required", token, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2204,6 +2204,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||||||
|
|
||||||
int size = 0;
|
int size = 0;
|
||||||
bool constType = true;
|
bool constType = true;
|
||||||
|
bool specConstType = true;
|
||||||
bool full = false;
|
bool full = false;
|
||||||
bool overFull = false;
|
bool overFull = false;
|
||||||
bool matrixInMatrix = 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())
|
if (op != EOpConstructStruct && ! type.isArray() && size >= type.computeNumComponents())
|
||||||
full = true;
|
full = true;
|
||||||
|
|
||||||
if (function[arg].type->getQualifier().storage != EvqConst)
|
if (! function[arg].type->getQualifier().isConstant())
|
||||||
constType = false;
|
constType = false;
|
||||||
|
if (! function[arg].type->getQualifier().isSpecConstant())
|
||||||
|
specConstType = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constType)
|
if (constType) {
|
||||||
type.getQualifier().storage = EvqConst;
|
type.getQualifier().storage = EvqConst;
|
||||||
|
if (specConstType)
|
||||||
|
type.getQualifier().specConstant = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (type.isArray()) {
|
if (type.isArray()) {
|
||||||
if (function.getParamCount() == 0) {
|
if (function.getParamCount() == 0) {
|
||||||
@ -3147,7 +3153,7 @@ void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier
|
|||||||
//
|
//
|
||||||
if (type.getQualifier().storage == EvqConst ||
|
if (type.getQualifier().storage == EvqConst ||
|
||||||
type.getQualifier().storage == EvqConstReadOnly) {
|
type.getQualifier().storage == EvqConstReadOnly) {
|
||||||
type.getQualifier().storage = EvqTemporary;
|
type.getQualifier().makeTemporary();
|
||||||
error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
|
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) {
|
if (! initializer) {
|
||||||
// error recovery; don't leave const without constant values
|
// error recovery; don't leave const without constant values
|
||||||
if (qualifier == EvqConst)
|
if (qualifier == EvqConst)
|
||||||
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4868,21 +4874,22 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uniform and global consts require a constant initializer
|
// Uniforms require a compile-time constant initializer
|
||||||
if (qualifier == EvqUniform && initializer->getType().getQualifier().storage != EvqConst) {
|
if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) {
|
||||||
error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
||||||
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
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());
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Const variables require a constant initializer, depending on version
|
// Const variables require a constant initializer, depending on version
|
||||||
if (qualifier == EvqConst) {
|
if (qualifier == EvqConst) {
|
||||||
if (initializer->getType().getQualifier().storage != EvqConst) {
|
if (! initializer->getType().getQualifier().isConstant()) {
|
||||||
const char* initFeature = "non-constant initializer";
|
const char* initFeature = "non-constant initializer";
|
||||||
requireProfile(loc, ~EEsProfile, initFeature);
|
requireProfile(loc, ~EEsProfile, initFeature);
|
||||||
profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, 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
|
// "In declarations of global variables with no storage qualifier or with a const
|
||||||
// qualifier any initializer must be a constant expression."
|
// 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";
|
const char* initFeature = "non-constant global initializer";
|
||||||
if (relaxedErrors())
|
if (relaxedErrors())
|
||||||
warn(loc, "not allowed in this version", initFeature, "");
|
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()) {
|
if (! initializer || ! initializer->getAsConstantUnion() || variable->getType() != initializer->getType()) {
|
||||||
error(loc, "non-matching or non-convertible constant type for const initializer",
|
error(loc, "non-matching or non-convertible constant type for const initializer",
|
||||||
variable->getType().getStorageQualifierString(), "");
|
variable->getType().getStorageQualifierString(), "");
|
||||||
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user