Shader: Fix conditional statement handling in partial compilation mode
This commit is contained in:
parent
e62969999a
commit
973b589b08
|
|
@ -166,6 +166,7 @@ namespace Nz::ShaderAst
|
||||||
ExpressionValue<StructLayout> layout;
|
ExpressionValue<StructLayout> layout;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<StructMember> members;
|
std::vector<StructMember> members;
|
||||||
|
bool isConditional;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool IsAliasType(const ExpressionType& type);
|
inline bool IsAliasType(const ExpressionType& type);
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,7 @@ namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
std::size_t index;
|
std::size_t index;
|
||||||
IdentifierCategory category;
|
IdentifierCategory category;
|
||||||
|
bool isConditional = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Identifier
|
struct Identifier
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,11 @@ namespace Nz::ShaderAst
|
||||||
const DeclareFunctionStatement* node;
|
const DeclareFunctionStatement* node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UsedExternalData
|
||||||
|
{
|
||||||
|
bool isConditional;
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr std::size_t ModuleIdSentinel = std::numeric_limits<std::size_t>::max();
|
static constexpr std::size_t ModuleIdSentinel = std::numeric_limits<std::size_t>::max();
|
||||||
|
|
||||||
std::array<DeclareFunctionStatement*, ShaderStageTypeCount> entryFunctions = {};
|
std::array<DeclareFunctionStatement*, ShaderStageTypeCount> entryFunctions = {};
|
||||||
|
|
@ -165,8 +170,8 @@ namespace Nz::ShaderAst
|
||||||
std::vector<PendingFunction> pendingFunctions;
|
std::vector<PendingFunction> pendingFunctions;
|
||||||
std::vector<StatementPtr>* currentStatementList = nullptr;
|
std::vector<StatementPtr>* currentStatementList = nullptr;
|
||||||
std::unordered_map<Uuid, std::size_t> moduleByUuid;
|
std::unordered_map<Uuid, std::size_t> moduleByUuid;
|
||||||
std::unordered_set<std::string> declaredExternalVar;
|
std::unordered_map<UInt64, UsedExternalData> usedBindingIndexes;
|
||||||
std::unordered_set<UInt64> usedBindingIndexes;
|
std::unordered_map<std::string, UsedExternalData> declaredExternalVar;
|
||||||
std::shared_ptr<Environment> globalEnv;
|
std::shared_ptr<Environment> globalEnv;
|
||||||
std::shared_ptr<Environment> currentEnv;
|
std::shared_ptr<Environment> currentEnv;
|
||||||
std::shared_ptr<Environment> moduleEnv;
|
std::shared_ptr<Environment> moduleEnv;
|
||||||
|
|
@ -182,6 +187,7 @@ namespace Nz::ShaderAst
|
||||||
Options options;
|
Options options;
|
||||||
CurrentFunctionData* currentFunction = nullptr;
|
CurrentFunctionData* currentFunction = nullptr;
|
||||||
bool allowUnknownIdentifiers = false;
|
bool allowUnknownIdentifiers = false;
|
||||||
|
bool inConditionalStatement = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
ModulePtr SanitizeVisitor::Sanitize(const Module& module, const Options& options, std::string* error)
|
ModulePtr SanitizeVisitor::Sanitize(const Module& module, const Options& options, std::string* error)
|
||||||
|
|
@ -350,7 +356,12 @@ namespace Nz::ShaderAst
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fieldPtr)
|
if (!fieldPtr)
|
||||||
|
{
|
||||||
|
if (s->isConditional)
|
||||||
|
return AstCloner::Clone(node); //< unresolved
|
||||||
|
|
||||||
throw ShaderLang::CompilerUnknownFieldError{ indexedExpr->sourceLocation, identifierEntry.identifier };
|
throw ShaderLang::CompilerUnknownFieldError{ indexedExpr->sourceLocation, identifierEntry.identifier };
|
||||||
|
}
|
||||||
|
|
||||||
if (m_context->options.useIdentifierAccessesForStructs)
|
if (m_context->options.useIdentifierAccessesForStructs)
|
||||||
{
|
{
|
||||||
|
|
@ -953,6 +964,11 @@ namespace Nz::ShaderAst
|
||||||
ExpressionPtr cloneCondition = AstCloner::Clone(*node.condition);
|
ExpressionPtr cloneCondition = AstCloner::Clone(*node.condition);
|
||||||
|
|
||||||
std::optional<ConstantValue> conditionValue = ComputeConstantValue(*cloneCondition);
|
std::optional<ConstantValue> conditionValue = ComputeConstantValue(*cloneCondition);
|
||||||
|
|
||||||
|
bool wasInConditionalStatement = m_context->inConditionalStatement;
|
||||||
|
m_context->inConditionalStatement = true;
|
||||||
|
CallOnExit restoreCond([=] { m_context->inConditionalStatement = wasInConditionalStatement; });
|
||||||
|
|
||||||
if (!conditionValue.has_value())
|
if (!conditionValue.has_value())
|
||||||
{
|
{
|
||||||
// Unresolvable condition
|
// Unresolvable condition
|
||||||
|
|
@ -1045,22 +1061,31 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
ComputeExprValue(extVar.bindingIndex, node.sourceLocation);
|
ComputeExprValue(extVar.bindingIndex, node.sourceLocation);
|
||||||
|
|
||||||
|
Context::UsedExternalData usedBindingData;
|
||||||
|
usedBindingData.isConditional = m_context->inConditionalStatement;
|
||||||
|
|
||||||
if (extVar.bindingSet.IsResultingValue() && extVar.bindingIndex.IsResultingValue())
|
if (extVar.bindingSet.IsResultingValue() && extVar.bindingIndex.IsResultingValue())
|
||||||
{
|
{
|
||||||
UInt64 bindingSet = extVar.bindingSet.GetResultingValue();
|
UInt64 bindingSet = extVar.bindingSet.GetResultingValue();
|
||||||
UInt64 bindingIndex = extVar.bindingIndex.GetResultingValue();
|
UInt64 bindingIndex = extVar.bindingIndex.GetResultingValue();
|
||||||
|
|
||||||
UInt64 bindingKey = bindingSet << 32 | bindingIndex;
|
UInt64 bindingKey = bindingSet << 32 | bindingIndex;
|
||||||
if (m_context->usedBindingIndexes.find(bindingKey) != m_context->usedBindingIndexes.end())
|
if (auto it = m_context->usedBindingIndexes.find(bindingKey); it != m_context->usedBindingIndexes.end())
|
||||||
|
{
|
||||||
|
if (!it->second.isConditional || !usedBindingData.isConditional)
|
||||||
throw ShaderLang::CompilerExtBindingAlreadyUsedError{ extVar.sourceLocation, UInt32(bindingSet), UInt32(bindingIndex) };
|
throw ShaderLang::CompilerExtBindingAlreadyUsedError{ extVar.sourceLocation, UInt32(bindingSet), UInt32(bindingIndex) };
|
||||||
|
|
||||||
m_context->usedBindingIndexes.insert(bindingKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_context->declaredExternalVar.find(extVar.name) != m_context->declaredExternalVar.end())
|
m_context->usedBindingIndexes.emplace(bindingKey, usedBindingData);
|
||||||
throw ShaderLang::CompilerExtAlreadyDeclaredError{ extVar.sourceLocation, extVar.name };
|
}
|
||||||
|
|
||||||
m_context->declaredExternalVar.insert(extVar.name);
|
if (auto it = m_context->declaredExternalVar.find(extVar.name); it != m_context->declaredExternalVar.end())
|
||||||
|
{
|
||||||
|
if (!it->second.isConditional || !usedBindingData.isConditional)
|
||||||
|
throw ShaderLang::CompilerExtAlreadyDeclaredError{ extVar.sourceLocation, extVar.name };
|
||||||
|
}
|
||||||
|
|
||||||
|
m_context->declaredExternalVar.emplace(extVar.name, usedBindingData);
|
||||||
|
|
||||||
std::optional<ExpressionType> resolvedType = ResolveTypeExpr(extVar.type, false, node.sourceLocation);
|
std::optional<ExpressionType> resolvedType = ResolveTypeExpr(extVar.type, false, node.sourceLocation);
|
||||||
if (!resolvedType.has_value())
|
if (!resolvedType.has_value())
|
||||||
|
|
@ -1303,6 +1328,8 @@ namespace Nz::ShaderAst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clone->description.isConditional = m_context->inConditionalStatement;
|
||||||
|
|
||||||
clone->structIndex = RegisterStruct(clone->description.name, &clone->description, clone->structIndex, clone->sourceLocation);
|
clone->structIndex = RegisterStruct(clone->description.name, &clone->description, clone->structIndex, clone->sourceLocation);
|
||||||
|
|
||||||
SanitizeIdentifier(clone->description.name);
|
SanitizeIdentifier(clone->description.name);
|
||||||
|
|
@ -2420,7 +2447,8 @@ namespace Nz::ShaderAst
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
aliasIndex,
|
aliasIndex,
|
||||||
IdentifierCategory::Alias
|
IdentifierCategory::Alias,
|
||||||
|
m_context->inConditionalStatement
|
||||||
});
|
});
|
||||||
|
|
||||||
return aliasIndex;
|
return aliasIndex;
|
||||||
|
|
@ -2445,7 +2473,8 @@ namespace Nz::ShaderAst
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
constantIndex,
|
constantIndex,
|
||||||
IdentifierCategory::Constant
|
IdentifierCategory::Constant,
|
||||||
|
m_context->inConditionalStatement
|
||||||
});
|
});
|
||||||
|
|
||||||
return constantIndex;
|
return constantIndex;
|
||||||
|
|
@ -2494,7 +2523,8 @@ namespace Nz::ShaderAst
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
functionIndex,
|
functionIndex,
|
||||||
IdentifierCategory::Function
|
IdentifierCategory::Function,
|
||||||
|
m_context->inConditionalStatement
|
||||||
});
|
});
|
||||||
|
|
||||||
return functionIndex;
|
return functionIndex;
|
||||||
|
|
@ -2510,7 +2540,8 @@ namespace Nz::ShaderAst
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
intrinsicIndex,
|
intrinsicIndex,
|
||||||
IdentifierCategory::Intrinsic
|
IdentifierCategory::Intrinsic,
|
||||||
|
m_context->inConditionalStatement
|
||||||
});
|
});
|
||||||
|
|
||||||
return intrinsicIndex;
|
return intrinsicIndex;
|
||||||
|
|
@ -2526,7 +2557,8 @@ namespace Nz::ShaderAst
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(moduleIdentifier),
|
std::move(moduleIdentifier),
|
||||||
moduleIndex,
|
moduleIndex,
|
||||||
IdentifierCategory::Module
|
IdentifierCategory::Module,
|
||||||
|
m_context->inConditionalStatement
|
||||||
});
|
});
|
||||||
|
|
||||||
return moduleIndex;
|
return moduleIndex;
|
||||||
|
|
@ -2534,8 +2566,14 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
std::size_t SanitizeVisitor::RegisterStruct(std::string name, std::optional<StructDescription*> description, std::optional<std::size_t> index, const ShaderLang::SourceLocation& sourceLocation)
|
std::size_t SanitizeVisitor::RegisterStruct(std::string name, std::optional<StructDescription*> description, std::optional<std::size_t> index, const ShaderLang::SourceLocation& sourceLocation)
|
||||||
{
|
{
|
||||||
if (FindIdentifier(name))
|
bool unresolved = false;
|
||||||
|
if (const IdentifierData* identifierData = FindIdentifier(name))
|
||||||
|
{
|
||||||
|
if (!m_context->inConditionalStatement || !identifierData->isConditional)
|
||||||
throw ShaderLang::CompilerIdentifierAlreadyUsedError{ sourceLocation, name };
|
throw ShaderLang::CompilerIdentifierAlreadyUsedError{ sourceLocation, name };
|
||||||
|
else
|
||||||
|
unresolved = true;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t structIndex;
|
std::size_t structIndex;
|
||||||
if (description)
|
if (description)
|
||||||
|
|
@ -2548,11 +2586,19 @@ namespace Nz::ShaderAst
|
||||||
else
|
else
|
||||||
structIndex = m_context->structs.RegisterNewIndex(true);
|
structIndex = m_context->structs.RegisterNewIndex(true);
|
||||||
|
|
||||||
|
if (!unresolved)
|
||||||
|
{
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
|
{
|
||||||
structIndex,
|
structIndex,
|
||||||
IdentifierCategory::Struct
|
IdentifierCategory::Struct,
|
||||||
|
m_context->inConditionalStatement
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RegisterUnresolved(std::move(name));
|
||||||
|
|
||||||
return structIndex;
|
return structIndex;
|
||||||
}
|
}
|
||||||
|
|
@ -2576,7 +2622,8 @@ namespace Nz::ShaderAst
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
typeIndex,
|
typeIndex,
|
||||||
IdentifierCategory::Type
|
IdentifierCategory::Type,
|
||||||
|
m_context->inConditionalStatement
|
||||||
});
|
});
|
||||||
|
|
||||||
return typeIndex;
|
return typeIndex;
|
||||||
|
|
@ -2607,7 +2654,8 @@ namespace Nz::ShaderAst
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
typeIndex,
|
typeIndex,
|
||||||
IdentifierCategory::Type
|
IdentifierCategory::Type,
|
||||||
|
m_context->inConditionalStatement
|
||||||
});
|
});
|
||||||
|
|
||||||
return typeIndex;
|
return typeIndex;
|
||||||
|
|
@ -2618,17 +2666,21 @@ namespace Nz::ShaderAst
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
std::numeric_limits<std::size_t>::max(),
|
std::numeric_limits<std::size_t>::max(),
|
||||||
IdentifierCategory::Unresolved
|
IdentifierCategory::Unresolved,
|
||||||
|
m_context->inConditionalStatement
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SanitizeVisitor::RegisterVariable(std::string name, std::optional<ExpressionType> type, std::optional<std::size_t> index, const ShaderLang::SourceLocation& sourceLocation)
|
std::size_t SanitizeVisitor::RegisterVariable(std::string name, std::optional<ExpressionType> type, std::optional<std::size_t> index, const ShaderLang::SourceLocation& sourceLocation)
|
||||||
{
|
{
|
||||||
|
bool unresolved = false;
|
||||||
if (auto* identifier = FindIdentifier(name))
|
if (auto* identifier = FindIdentifier(name))
|
||||||
{
|
{
|
||||||
// Allow variable shadowing
|
// Allow variable shadowing
|
||||||
if (identifier->category != IdentifierCategory::Variable)
|
if (identifier->category != IdentifierCategory::Variable)
|
||||||
throw ShaderLang::CompilerIdentifierAlreadyUsedError{ sourceLocation, name };
|
throw ShaderLang::CompilerIdentifierAlreadyUsedError{ sourceLocation, name };
|
||||||
|
else if (identifier->isConditional && m_context->inConditionalStatement)
|
||||||
|
unresolved = true; //< right variable isn't know from this point
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t varIndex;
|
std::size_t varIndex;
|
||||||
|
|
@ -2642,11 +2694,19 @@ namespace Nz::ShaderAst
|
||||||
else
|
else
|
||||||
varIndex = m_context->variableTypes.RegisterNewIndex(true);
|
varIndex = m_context->variableTypes.RegisterNewIndex(true);
|
||||||
|
|
||||||
|
if (!unresolved)
|
||||||
|
{
|
||||||
m_context->currentEnv->identifiersInScope.push_back({
|
m_context->currentEnv->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
|
{
|
||||||
varIndex,
|
varIndex,
|
||||||
IdentifierCategory::Variable
|
IdentifierCategory::Variable,
|
||||||
|
m_context->inConditionalStatement
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RegisterUnresolved(std::move(name));
|
||||||
|
|
||||||
return varIndex;
|
return varIndex;
|
||||||
}
|
}
|
||||||
|
|
@ -2667,10 +2727,15 @@ namespace Nz::ShaderAst
|
||||||
PushScope();
|
PushScope();
|
||||||
|
|
||||||
for (auto& parameter : pendingFunc.cloneNode->parameters)
|
for (auto& parameter : pendingFunc.cloneNode->parameters)
|
||||||
|
{
|
||||||
|
if (!m_context->options.allowPartialSanitization || parameter.type.IsResultingValue())
|
||||||
{
|
{
|
||||||
parameter.varIndex = RegisterVariable(parameter.name, parameter.type.GetResultingValue(), parameter.varIndex, parameter.sourceLocation);
|
parameter.varIndex = RegisterVariable(parameter.name, parameter.type.GetResultingValue(), parameter.varIndex, parameter.sourceLocation);
|
||||||
SanitizeIdentifier(parameter.name);
|
SanitizeIdentifier(parameter.name);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
RegisterUnresolved(parameter.name);
|
||||||
|
}
|
||||||
|
|
||||||
CurrentFunctionData tempFuncData;
|
CurrentFunctionData tempFuncData;
|
||||||
if (pendingFunc.cloneNode->entryStage.HasValue())
|
if (pendingFunc.cloneNode->entryStage.HasValue())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue