diff --git a/include/NZSL/Ast/Compare.inl b/include/NZSL/Ast/Compare.inl index da30143..bce8fd1 100644 --- a/include/NZSL/Ast/Compare.inl +++ b/include/NZSL/Ast/Compare.inl @@ -524,9 +524,6 @@ namespace nzsl::Ast if (!Compare(lhs.variableId, rhs.variableId, params)) return false; - if (!Compare(lhs.prefix, rhs.prefix, params)) - return false; - return true; } diff --git a/include/NZSL/Ast/Nodes.hpp b/include/NZSL/Ast/Nodes.hpp index c328db2..b43d2dd 100644 --- a/include/NZSL/Ast/Nodes.hpp +++ b/include/NZSL/Ast/Nodes.hpp @@ -242,7 +242,6 @@ namespace nzsl::Ast void Visit(ExpressionVisitor& visitor) override; std::size_t variableId; - std::string prefix; }; struct NZSL_API UnaryExpression : Expression diff --git a/include/NZSL/Ast/SanitizeVisitor.hpp b/include/NZSL/Ast/SanitizeVisitor.hpp index 811079d..160dbd1 100644 --- a/include/NZSL/Ast/SanitizeVisitor.hpp +++ b/include/NZSL/Ast/SanitizeVisitor.hpp @@ -144,11 +144,11 @@ namespace nzsl::Ast std::size_t RegisterAlias(std::string name, std::optional aliasData, std::optional index, const SourceLocation& sourceLocation); std::size_t RegisterConstant(std::string name, std::optional value, std::optional index, const SourceLocation& sourceLocation); + std::size_t RegisterExternalBlock(std::string name, std::size_t externalBlockIndex, const SourceLocation& sourceLocation); std::size_t RegisterFunction(std::string name, std::optional funcData, std::optional index, const SourceLocation& sourceLocation); std::size_t RegisterIntrinsic(std::string name, IntrinsicType type); std::size_t RegisterModule(std::string moduleIdentifier, std::size_t moduleIndex); void RegisterReservedName(std::string name); - void RegisterExternalName(std::string name, const SourceLocation& sourceLocation); std::size_t RegisterStruct(std::string name, std::optional description, std::optional index, const SourceLocation& sourceLocation); std::size_t RegisterType(std::string name, std::optional expressionType, std::optional index, const SourceLocation& sourceLocation); std::size_t RegisterType(std::string name, std::optional partialType, std::optional index, const SourceLocation& sourceLocation); @@ -208,7 +208,7 @@ namespace nzsl::Ast { Alias, Constant, - External, + ExternalBlock, Function, Intrinsic, Module, diff --git a/src/NZSL/Ast/Cloner.cpp b/src/NZSL/Ast/Cloner.cpp index 6f6deb7..62b0f70 100644 --- a/src/NZSL/Ast/Cloner.cpp +++ b/src/NZSL/Ast/Cloner.cpp @@ -127,8 +127,8 @@ namespace nzsl::Ast auto clone = std::make_unique(); clone->autoBinding = Clone(node.autoBinding); clone->bindingSet = Clone(node.bindingSet); - clone->tag = node.tag; clone->name = node.name; + clone->tag = node.tag; clone->externalVars.reserve(node.externalVars.size()); for (const auto& var : node.externalVars) @@ -594,7 +594,6 @@ namespace nzsl::Ast { auto clone = std::make_unique(); clone->variableId = node.variableId; - clone->prefix = node.prefix; clone->cachedExpressionType = node.cachedExpressionType; clone->sourceLocation = node.sourceLocation; diff --git a/src/NZSL/Ast/ReflectVisitor.cpp b/src/NZSL/Ast/ReflectVisitor.cpp index 2254ab6..acbdab0 100644 --- a/src/NZSL/Ast/ReflectVisitor.cpp +++ b/src/NZSL/Ast/ReflectVisitor.cpp @@ -3,7 +3,6 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include namespace nzsl::Ast { @@ -57,7 +56,7 @@ namespace nzsl::Ast for (const auto& extVar : node.externalVars) { if (extVar.varIndex) - m_callbacks->onVariableIndex(node.name + extVar.name, *extVar.varIndex, extVar.sourceLocation); + m_callbacks->onVariableIndex(extVar.name, *extVar.varIndex, extVar.sourceLocation); } } diff --git a/src/NZSL/Ast/SanitizeVisitor.cpp b/src/NZSL/Ast/SanitizeVisitor.cpp index ffc2abc..9f5e729 100644 --- a/src/NZSL/Ast/SanitizeVisitor.cpp +++ b/src/NZSL/Ast/SanitizeVisitor.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -22,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -183,15 +181,21 @@ namespace nzsl::Ast std::unique_ptr dependenciesVisitor; }; + struct NamedExternalBlockData + { + std::shared_ptr environment; + }; + struct UsedExternalData { unsigned int conditionalStatementIndex; }; - static constexpr std::size_t ModuleIdSentinel = std::numeric_limits::max(); + static constexpr std::size_t ModuleIdSentinel = std::numeric_limits::max(); std::array entryFunctions = {}; std::vector modules; + std::vector namedExternalBlocks; std::vector* currentStatementList = nullptr; std::unordered_map moduleByName; std::unordered_map usedBindingIndexes; @@ -205,6 +209,7 @@ namespace nzsl::Ast IdentifierList aliases; IdentifierList intrinsics; IdentifierList moduleIndices; + IdentifierList namedExternalBlockIndices; IdentifierList structs; IdentifierList> types; IdentifierList variableTypes; @@ -318,29 +323,44 @@ namespace nzsl::Ast auto& identifierExpr = static_cast(*node.expr); const IdentifierData* identifierData = FindIdentifier(identifierExpr.identifier); - if (identifierData && identifierData->category == IdentifierCategory::Module) + if (identifierData) { - std::size_t moduleIndex = m_context->moduleIndices.Retrieve(identifierData->index, node.sourceLocation); - - const auto& env = *m_context->modules[moduleIndex].environment; - identifierData = FindIdentifier(env, node.identifiers.front().identifier); - if (identifierData) + switch (identifierData->category) { - if (m_context->options.partialSanitization && identifierData->conditionalIndex != m_context->currentConditionalIndex) - return Cloner::Clone(node); + case IdentifierCategory::ExternalBlock: + { + std::size_t namedExternalBlockIndex = m_context->namedExternalBlockIndices.Retrieve(identifierData->index, node.sourceLocation); - return HandleIdentifier(identifierData, node.identifiers.front().sourceLocation); - } - } + const auto& env = *m_context->namedExternalBlocks[namedExternalBlockIndex].environment; + identifierData = FindIdentifier(env, node.identifiers.front().identifier); + if (identifierData) + { + if (m_context->options.partialSanitization && identifierData->conditionalIndex != m_context->currentConditionalIndex) + return Cloner::Clone(node); - if (identifierData && identifierData->category == IdentifierCategory::External) - { - identifierData = FindIdentifier(identifierExpr.identifier + node.identifiers.front().identifier); - if (identifierData) - { - auto variableValuePtr = HandleIdentifier(identifierData, node.identifiers.front().sourceLocation); - static_cast(variableValuePtr.get())->prefix = identifierExpr.identifier; - return variableValuePtr; + return HandleIdentifier(identifierData, node.identifiers.front().sourceLocation); + } + break; + } + + case IdentifierCategory::Module: + { + std::size_t moduleIndex = m_context->moduleIndices.Retrieve(identifierData->index, node.sourceLocation); + + const auto& env = *m_context->modules[moduleIndex].environment; + identifierData = FindIdentifier(env, node.identifiers.front().identifier); + if (identifierData) + { + if (m_context->options.partialSanitization && identifierData->conditionalIndex != m_context->currentConditionalIndex) + return Cloner::Clone(node); + + return HandleIdentifier(identifierData, node.identifiers.front().sourceLocation); + } + break; + } + + default: + break; } } } @@ -1476,9 +1496,18 @@ namespace nzsl::Ast } }; + std::optional namedExternalBlockIndex; + std::shared_ptr previousEnv; if (!clone->name.empty()) { - RegisterExternalName(clone->name, clone->sourceLocation); + namedExternalBlockIndex = m_context->namedExternalBlocks.size(); + auto& namedExternal = m_context->namedExternalBlocks.emplace_back(); + namedExternal.environment = std::make_shared(); + + RegisterExternalBlock(clone->name, *namedExternalBlockIndex, clone->sourceLocation); + + previousEnv = std::move(m_context->currentEnv); + m_context->currentEnv = namedExternal.environment; } bool hasUnresolved = false; @@ -1487,25 +1516,30 @@ namespace nzsl::Ast { auto& extVar = clone->externalVars[i]; - SanitizeIdentifier(extVar.name, IdentifierScope::ExternalVariable); + std::string fullName; + if (!clone->name.empty()) + { + fullName = fmt::format("{}_{}", clone->name, extVar.name); + SanitizeIdentifier(fullName, IdentifierScope::ExternalVariable); + } + + std::string& internalName = (!clone->name.empty()) ? fullName : extVar.name; - std::string fullName = clone->name + extVar.name; - Context::UsedExternalData usedBindingData; usedBindingData.conditionalStatementIndex = m_context->currentConditionalIndex; - if (auto it = m_context->declaredExternalVar.find(fullName); it != m_context->declaredExternalVar.end()) + if (auto it = m_context->declaredExternalVar.find(internalName); it != m_context->declaredExternalVar.end()) { if (it->second.conditionalStatementIndex == m_context->currentConditionalIndex || usedBindingData.conditionalStatementIndex == m_context->currentConditionalIndex) throw CompilerExtAlreadyDeclaredError{ extVar.sourceLocation, extVar.name }; } - m_context->declaredExternalVar.emplace(fullName, usedBindingData); + m_context->declaredExternalVar.emplace(internalName, usedBindingData); std::optional resolvedType = ResolveTypeExpr(extVar.type, false, node.sourceLocation); if (!resolvedType.has_value()) { - RegisterUnresolved(fullName); + RegisterUnresolved(extVar.name); hasUnresolved = true; continue; } @@ -1576,9 +1610,13 @@ namespace nzsl::Ast } extVar.type = std::move(resolvedType).value(); - extVar.varIndex = RegisterVariable(fullName, std::move(varType), extVar.varIndex, extVar.sourceLocation); + extVar.varIndex = RegisterVariable(extVar.name, std::move(varType), extVar.varIndex, extVar.sourceLocation); + SanitizeIdentifier(extVar.name, IdentifierScope::ExternalVariable); } + if (previousEnv) + m_context->currentEnv = std::move(previousEnv); + // Resolve auto-binding entries when explicit binding are known if (!hasUnresolved) { @@ -2890,7 +2928,7 @@ namespace nzsl::Ast return Clone(constantExpr); //< Turn ConstantExpression into ConstantValueExpression } - case IdentifierCategory::External: + case IdentifierCategory::ExternalBlock: throw AstUnexpectedIdentifierError{ sourceLocation, "external" }; case IdentifierCategory::Function: @@ -3662,6 +3700,25 @@ namespace nzsl::Ast return constantIndex; } + std::size_t SanitizeVisitor::RegisterExternalBlock(std::string name, std::size_t externalBlockIndex, const SourceLocation& sourceLocation) + { + if (!IsIdentifierAvailable(name)) + throw CompilerIdentifierAlreadyUsedError{ sourceLocation, name }; + + std::size_t index = m_context->namedExternalBlockIndices.Register(externalBlockIndex, std::nullopt, {}); + + m_context->currentEnv->identifiersInScope.push_back({ + std::move(name), + { + index, + IdentifierCategory::ExternalBlock, + m_context->currentConditionalIndex + } + }); + + return index; + } + std::size_t SanitizeVisitor::RegisterFunction(std::string name, std::optional funcData, std::optional index, const SourceLocation& sourceLocation) { if (auto* identifier = FindIdentifier(name)) @@ -3764,20 +3821,6 @@ namespace nzsl::Ast }); } - void SanitizeVisitor::RegisterExternalName(std::string name, const SourceLocation& sourceLocation) - { - if (!IsIdentifierAvailable(name)) - throw CompilerIdentifierAlreadyUsedError{ sourceLocation, name }; - - m_context->currentEnv->identifiersInScope.push_back({ - std::move(name), - { - std::numeric_limits::max(), - IdentifierCategory::External - } - }); - } - std::size_t SanitizeVisitor::RegisterStruct(std::string name, std::optional description, std::optional index, const SourceLocation& sourceLocation) { bool unresolved = false; diff --git a/src/NZSL/GlslWriter.cpp b/src/NZSL/GlslWriter.cpp index 48f04cc..d2b61c5 100644 --- a/src/NZSL/GlslWriter.cpp +++ b/src/NZSL/GlslWriter.cpp @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include @@ -26,6 +24,7 @@ #include #include #include +#include namespace nzsl { @@ -345,6 +344,7 @@ namespace nzsl std::unordered_map variableNames; std::unordered_map explicitTextureBinding; std::unordered_map explicitUniformBlockBinding; + std::unordered_set reservedNames; Nz::Bitset<> declaredFunctions; const GlslWriter::BindingMapping& bindingMapping; GlslWriterPreVisitor previsitor; @@ -2270,7 +2270,24 @@ namespace nzsl AppendComment("struct tag: " + structInfo.desc->tag); } - std::string varName = node.name + externalVar.name + m_currentState->moduleSuffix; + std::string varName = externalVar.name + m_currentState->moduleSuffix; + if (!node.name.empty()) + varName = fmt::format("{}_{}", node.name, varName); + + if (m_currentState->reservedNames.count(varName) > 0) + { + unsigned int cloneIndex = 2; + std::string candidateName; + do + { + candidateName = fmt::format("{}_{}", varName, cloneIndex++); + } + while (m_currentState->reservedNames.count(candidateName) > 0); + + varName = std::move(candidateName); + } + + m_currentState->reservedNames.insert(varName); // Layout handling bool hasLayout = false; @@ -2522,9 +2539,23 @@ namespace nzsl void GlslWriter::Visit(Ast::DeclareVariableStatement& node) { assert(node.varIndex); - RegisterVariable(*node.varIndex, node.varName); - AppendVariableDeclaration(node.varType.GetResultingValue(), node.varName); + std::string varName = node.varName; + if (m_currentState->reservedNames.count(varName) > 0) + { + unsigned int cloneIndex = 2; + std::string candidateName; + do + { + candidateName = fmt::format("{}_{}", varName, cloneIndex++); + } while (m_currentState->reservedNames.count(candidateName) > 0); + + varName = std::move(candidateName); + } + + AppendVariableDeclaration(node.varType.GetResultingValue(), varName); + RegisterVariable(*node.varIndex, std::move(varName)); + if (node.initialExpression) { Append(" = "); diff --git a/src/NZSL/LangWriter.cpp b/src/NZSL/LangWriter.cpp index 1203ac7..57bb813 100644 --- a/src/NZSL/LangWriter.cpp +++ b/src/NZSL/LangWriter.cpp @@ -176,10 +176,12 @@ namespace nzsl { struct Identifier { + std::optional externalBlockIndex; std::size_t moduleIndex; std::string name; }; + std::optional currentExternalBlockIndex; std::size_t currentModuleIndex; std::stringstream stream; std::unordered_map aliases; @@ -187,6 +189,7 @@ namespace nzsl std::unordered_map functions; std::unordered_map structs; std::unordered_map variables; + std::vector externalBlockNames; std::vector moduleNames; const States* states = nullptr; const Ast::Module* module; @@ -804,11 +807,14 @@ namespace nzsl template void LangWriter::AppendIdentifier(const T& map, std::size_t id) { - const auto& structIdentifier = Nz::Retrieve(map, id); - if (structIdentifier.moduleIndex != m_currentState->currentModuleIndex) - Append(m_currentState->moduleNames[structIdentifier.moduleIndex], '.'); + const auto& identifier = Nz::Retrieve(map, id); + if (identifier.moduleIndex != m_currentState->currentModuleIndex) + Append(m_currentState->moduleNames[identifier.moduleIndex], '.'); - Append(structIdentifier.name); + if (identifier.externalBlockIndex != m_currentState->currentExternalBlockIndex) + Append(m_currentState->externalBlockNames[*identifier.externalBlockIndex], '.'); + + Append(identifier.name); } template @@ -922,6 +928,7 @@ namespace nzsl void LangWriter::RegisterVariable(std::size_t varIndex, std::string varName) { State::Identifier identifier; + identifier.externalBlockIndex = m_currentState->currentExternalBlockIndex; identifier.moduleIndex = m_currentState->currentModuleIndex; identifier.name = std::move(varName); @@ -1260,11 +1267,6 @@ namespace nzsl void LangWriter::Visit(Ast::VariableValueExpression& node) { - if (!node.prefix.empty()) - { - Append(node.prefix, '.'); - } - AppendIdentifier(m_currentState->variables, node.variableId); } @@ -1374,7 +1376,12 @@ namespace nzsl Append("external"); if (!node.name.empty()) + { Append(" ", node.name); + + m_currentState->currentExternalBlockIndex = m_currentState->externalBlockNames.size(); + m_currentState->externalBlockNames.push_back(node.name); + } AppendLine(); @@ -1399,6 +1406,8 @@ namespace nzsl } LeaveScope(); + + m_currentState->currentExternalBlockIndex = {}; } void LangWriter::Visit(Ast::DeclareFunctionStatement& node) diff --git a/src/NZSL/SpirvWriter.cpp b/src/NZSL/SpirvWriter.cpp index ad56241..0be83fb 100644 --- a/src/NZSL/SpirvWriter.cpp +++ b/src/NZSL/SpirvWriter.cpp @@ -192,7 +192,7 @@ namespace nzsl ExternalVar& extVarData = extVars[*extVar.varIndex]; SpirvConstantCache::Variable variable; - variable.debugName = node.name + extVar.name; + variable.debugName = (!node.name.empty()) ? fmt::format("{}_{}", node.name, extVar.name) : extVar.name; const Ast::ExpressionType& extVarType = extVar.type.GetResultingValue(); diff --git a/tests/src/Tests/ExternalTests.cpp b/tests/src/Tests/ExternalTests.cpp index f3a2888..8f65f98 100644 --- a/tests/src/Tests/ExternalTests.cpp +++ b/tests/src/Tests/ExternalTests.cpp @@ -1316,11 +1316,11 @@ precision mediump sampler2D; // header end // external var tag: Color map -uniform sampler2D Viewertex; +uniform sampler2D Viewer_tex; void main() { - vec4 value = texture(Viewertex, vec2(0.0, 0.0)); + vec4 value = texture(Viewer_tex, vec2(0.0, 0.0)); } )"); @@ -1374,8 +1374,8 @@ external Viewer [entry(frag)] fn main() { - let Viewertex = 0.0; - let value = Viewertex; + let Viewer_tex = 0.0; + let value = Viewer_tex; } )"; @@ -1397,12 +1397,12 @@ precision mediump sampler2D; // header end // external var tag: Color map -uniform sampler2D Viewertex; +uniform sampler2D Viewer_tex; void main() { - float Viewertex_2 = 0.0; - float value = Viewertex_2; + float Viewer_tex_2 = 0.0; + float value = Viewer_tex_2; } )"); @@ -1415,17 +1415,17 @@ external Viewer [entry(frag)] fn main() { - let Viewertex: f32 = 0.0; - let value: f32 = Viewertex; + let Viewer_tex: f32 = 0.0; + let value: f32 = Viewer_tex; })"); ExpectSPIRV(*shaderModule, R"( - OpCapability Capability(Shader) + OpCapability Capability(Shader) OpMemoryModel AddressingModel(Logical) MemoryModel(GLSL450) OpEntryPoint ExecutionModel(Fragment) %10 "main" OpExecutionMode %10 ExecutionMode(OriginUpperLeft) OpSource SourceLanguage(NZSL) 100 - OpName %5 "Viewertex" + OpName %5 "Viewer_tex" OpName %10 "main" OpDecorate %5 Decoration(Binding) 0 OpDecorate %5 Decoration(DescriptorSet) 0