| /* |
| * Copyright (c) 2023 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "MangleNames.h" |
| |
| #include "AST.h" |
| #include "ASTVisitor.h" |
| #include "CallGraph.h" |
| #include "ContextProviderInlines.h" |
| #include "WGSL.h" |
| #include "WGSLShaderModule.h" |
| #include <wtf/HashSet.h> |
| |
| namespace WGSL { |
| |
| struct MangledName { |
| enum Kind : uint8_t { |
| Type, |
| Local, |
| Global, |
| Parameter, |
| Function, |
| Field, |
| }; |
| static constexpr unsigned numberOfKinds = 6; |
| |
| Kind kind; |
| uint32_t index; |
| String originalName; |
| |
| String toString() const |
| { |
| static const ASCIILiteral prefixes[] = { |
| "type"_s, |
| "local"_s, |
| "global"_s, |
| "parameter"_s, |
| "function"_s, |
| "field"_s, |
| }; |
| return makeString(prefixes[WTF::enumToUnderlyingType(kind)], String::number(index)); |
| } |
| }; |
| |
| class NameManglerVisitor : public AST::Visitor, public ContextProvider<MangledName> { |
| using ContextProvider = ContextProvider<MangledName>; |
| |
| public: |
| NameManglerVisitor(const CallGraph& callGraph, PrepareResult& result) |
| : m_callGraph(callGraph) |
| , m_result(result) |
| { |
| } |
| |
| void run(); |
| |
| void visit(AST::Function&) override; |
| void visit(AST::VariableStatement&) override; |
| void visit(AST::Structure&) override; |
| void visit(AST::Variable&) override; |
| void visit(AST::IdentifierExpression&) override; |
| void visit(AST::FieldAccessExpression&) override; |
| void visit(AST::NamedTypeName&) override; |
| |
| private: |
| using NameMap = ContextProvider::ContextMap; |
| |
| void introduceVariable(AST::Identifier&, MangledName::Kind); |
| void readVariable(AST::Identifier&) const; |
| |
| MangledName makeMangledName(const String&, MangledName::Kind); |
| |
| void visitVariableDeclaration(AST::Variable&, MangledName::Kind); |
| void visitFunctionBody(AST::Function&); |
| |
| const CallGraph& m_callGraph; |
| PrepareResult& m_result; |
| HashMap<AST::Structure*, NameMap> m_structFieldMapping; |
| uint32_t m_indexPerType[MangledName::numberOfKinds] { 0 }; |
| }; |
| |
| void NameManglerVisitor::run() |
| { |
| for (const auto& entrypoint : m_callGraph.entrypoints()) { |
| String originalName = entrypoint.m_function.name(); |
| introduceVariable(entrypoint.m_function.name(), MangledName::Function); |
| auto it = m_result.entryPoints.find(originalName); |
| RELEASE_ASSERT(it != m_result.entryPoints.end()); |
| it->value.mangledName = entrypoint.m_function.name(); |
| } |
| |
| auto& module = m_callGraph.ast(); |
| for (auto& structure : module.structures()) |
| visit(structure); |
| |
| for (auto& variable : module.variables()) |
| visit(variable); |
| |
| for (auto& function : module.functions()) |
| visitFunctionBody(function); |
| } |
| |
| void NameManglerVisitor::visit(AST::Function& function) |
| { |
| introduceVariable(function.name(), MangledName::Function); |
| } |
| |
| void NameManglerVisitor::visitFunctionBody(AST::Function& function) |
| { |
| ContextScope functionScope(this); |
| |
| for (auto& parameter : function.parameters()) { |
| AST::Visitor::visit(parameter.typeName()); |
| introduceVariable(parameter.name(), MangledName::Parameter); |
| } |
| |
| AST::Visitor::visit(function.body()); |
| if (function.maybeReturnType()) |
| AST::Visitor::visit(*function.maybeReturnType()); |
| } |
| |
| void NameManglerVisitor::visit(AST::Structure& structure) |
| { |
| introduceVariable(structure.name(), MangledName::Type); |
| |
| NameMap fieldMap; |
| for (auto& member : structure.members()) { |
| AST::Visitor::visit(member.type()); |
| auto mangledName = makeMangledName(member.name(), MangledName::Field); |
| fieldMap.add(member.name(), mangledName); |
| // FIXME: need to resolve type of expressions in order to be able to replace struct fields |
| } |
| auto result = m_structFieldMapping.add(&structure, WTFMove(fieldMap)); |
| ASSERT_UNUSED(result, result.isNewEntry); |
| } |
| |
| void NameManglerVisitor::visit(AST::Variable& variable) |
| { |
| visitVariableDeclaration(variable, MangledName::Global); |
| } |
| |
| void NameManglerVisitor::visit(AST::VariableStatement& variable) |
| { |
| visitVariableDeclaration(variable.variable(), MangledName::Local); |
| } |
| |
| void NameManglerVisitor::visitVariableDeclaration(AST::Variable& variable, MangledName::Kind kind) |
| { |
| introduceVariable(variable.name(), kind); |
| AST::Visitor::visit(variable); |
| } |
| |
| void NameManglerVisitor::visit(AST::IdentifierExpression& identifier) |
| { |
| readVariable(identifier.identifier()); |
| } |
| |
| void NameManglerVisitor::visit(AST::FieldAccessExpression& access) |
| { |
| // FIXME: need to resolve type of expressions in order to be able to replace struct fields |
| AST::Visitor::visit(access.base()); |
| } |
| |
| void NameManglerVisitor::visit(AST::NamedTypeName& type) |
| { |
| readVariable(type.name()); |
| } |
| |
| void NameManglerVisitor::introduceVariable(AST::Identifier& name, MangledName::Kind kind) |
| { |
| const auto& mangledName = ContextProvider::introduceVariable(name, makeMangledName(name, kind)); |
| name = AST::Identifier::makeWithSpan(name.span(), mangledName.toString()); |
| } |
| |
| MangledName NameManglerVisitor::makeMangledName(const String& name, MangledName::Kind kind) |
| { |
| return MangledName { |
| kind, |
| m_indexPerType[WTF::enumToUnderlyingType(kind)]++, |
| name |
| }; |
| } |
| |
| void NameManglerVisitor::readVariable(AST::Identifier& name) const |
| { |
| // FIXME: this should be unconditional |
| if (const auto* mangledName = ContextProvider::readVariable(name)) |
| name = AST::Identifier::makeWithSpan(name.span(), mangledName->toString()); |
| } |
| |
| void mangleNames(CallGraph& callGraph, PrepareResult& result) |
| { |
| NameManglerVisitor(callGraph, result).run(); |
| } |
| |
| } // namespace WGSL |