diff --git a/Source/WebGPU/WGSL/AST/ASTBuilder.cpp b/Source/WebGPU/WGSL/AST/ASTBuilder.cpp new file mode 100644 index 000000000000..0dfc9295d6ef --- /dev/null +++ b/Source/WebGPU/WGSL/AST/ASTBuilder.cpp @@ -0,0 +1,62 @@ +/* + * 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 "ASTBuilder.h" + +namespace WGSL::AST { + +DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(WGSLAST); + +Builder::Builder(Builder&& other) +{ + m_arena = std::exchange(other.m_arena, nullptr); + m_arenaEnd = std::exchange(other.m_arenaEnd, nullptr); + m_arenas = WTFMove(other.m_arenas); + m_nodes = WTFMove(other.m_nodes); +} + +inline uint8_t* Builder::arena() +{ + ASSERT(m_arenaEnd); + return m_arenaEnd - arenaSize; +} + +Builder::~Builder() +{ + size_t size = m_nodes.size(); + for (size_t i = 0; i < size; ++i) + m_nodes[i]->~Node(); +} + +void Builder::allocateArena() +{ + m_arenas.append(MallocPtr::malloc(arenaSize)); + m_arena = m_arenas.last().get(); + m_arenaEnd = m_arena + arenaSize; + ASSERT(arena() == m_arena); +} + +} // namespace WGSL::AST diff --git a/Source/WebGPU/WGSL/AST/ASTBuilder.h b/Source/WebGPU/WGSL/AST/ASTBuilder.h new file mode 100644 index 000000000000..e2a22dc1ec6a --- /dev/null +++ b/Source/WebGPU/WGSL/AST/ASTBuilder.h @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#pragma once + +#include "ASTNode.h" +#include +#include +#include +#include + +#define WGSL_AST_BUILDER_NODE(Node) \ + WTF_MAKE_NONCOPYABLE(Node); \ + WTF_MAKE_NONMOVABLE(Node); \ + friend class Builder; \ + +namespace WGSL::AST { + +DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(WGSLAST); + +class Builder { + WTF_MAKE_NONCOPYABLE(Builder); + +public: + static constexpr size_t arenaSize = 0x4000; + + Builder() = default; + Builder(Builder&&); + ~Builder(); + + template>> + T& construct(Arguments&&... arguments) + { + constexpr size_t size = sizeof(T); + constexpr size_t alignedSize = alignSize(size); + static_assert(alignedSize <= arenaSize); + if (UNLIKELY(static_cast(m_arenaEnd - m_arena) < alignedSize)) + allocateArena(); + + auto* node = new (m_arena) T(std::forward(arguments)...); + m_arena += alignedSize; + m_nodes.append(node); + return *node; + } + +private: + static constexpr size_t alignSize(size_t size) + { + return (size + sizeof(WTF::AllocAlignmentInteger) - 1) & ~(sizeof(WTF::AllocAlignmentInteger) - 1); + } + + uint8_t* arena(); + void allocateArena(); + + uint8_t* m_arena { nullptr }; + uint8_t* m_arenaEnd { nullptr }; + Vector> m_arenas; + Vector m_nodes; +}; + +} // namespace WGSL::AST diff --git a/Source/WebGPU/WGSL/AST/ASTStructureMember.h b/Source/WebGPU/WGSL/AST/ASTStructureMember.h index bae25364b7bc..7e784ddd7c4d 100644 --- a/Source/WebGPU/WGSL/AST/ASTStructureMember.h +++ b/Source/WebGPU/WGSL/AST/ASTStructureMember.h @@ -26,16 +26,24 @@ #pragma once #include "ASTAttribute.h" +#include "ASTBuilder.h" #include "ASTIdentifier.h" #include "ASTTypeName.h" namespace WGSL::AST { class StructureMember final : public Node { - WTF_MAKE_FAST_ALLOCATED; + WGSL_AST_BUILDER_NODE(StructureMember); + public: - using List = UniqueRefVector; + using List = Vector>; + NodeKind kind() const final; + Identifier& name() { return m_name; } + TypeName& type() { return m_type; } + Attribute::List& attributes() { return m_attributes; } + +private: StructureMember(SourceSpan span, Identifier&& name, TypeName::Ref&& type, Attribute::List&& attributes) : Node(span) , m_name(WTFMove(name)) @@ -43,12 +51,6 @@ class StructureMember final : public Node { , m_type(WTFMove(type)) { } - NodeKind kind() const final; - Identifier& name() { return m_name; } - TypeName& type() { return m_type; } - Attribute::List& attributes() { return m_attributes; } - -private: Identifier m_name; Attribute::List m_attributes; TypeName::Ref m_type; diff --git a/Source/WebGPU/WGSL/EntryPointRewriter.cpp b/Source/WebGPU/WGSL/EntryPointRewriter.cpp index 0ddda8afa036..d9fbc6159267 100644 --- a/Source/WebGPU/WGSL/EntryPointRewriter.cpp +++ b/Source/WebGPU/WGSL/EntryPointRewriter.cpp @@ -159,7 +159,7 @@ void EntryPointRewriter::constructInputStruct() // insert `var ${parameter.name()} = ${structName}.${parameter.name()}` AST::StructureMember::List structMembers; for (auto& parameter : m_parameters) { - structMembers.append(makeUniqueRef( + structMembers.append(m_shaderModule.astBuilder().construct( SourceSpan::empty(), WTFMove(parameter.name), WTFMove(parameter.type), @@ -253,7 +253,7 @@ void EntryPointRewriter::visit(Vector& path, MemberOrParameter&& data) ) )); path.append(data.name); - for (auto& member : structType->structure.members()) + for (AST::StructureMember& member : structType->structure.members()) visit(path, MemberOrParameter { member.name(), member.type(), member.attributes() }); path.removeLast(); return; diff --git a/Source/WebGPU/WGSL/GlobalVariableRewriter.cpp b/Source/WebGPU/WGSL/GlobalVariableRewriter.cpp index 43f2a4f447ae..d1e04b3ababe 100644 --- a/Source/WebGPU/WGSL/GlobalVariableRewriter.cpp +++ b/Source/WebGPU/WGSL/GlobalVariableRewriter.cpp @@ -312,7 +312,7 @@ void RewriteGlobalVariables::insertStructs(const UsedGlobals& usedGlobals) AST::TypeName::Ref memberType = *global->declaration->maybeTypeName(); if (shouldBeReference) memberType = adoptRef(*new AST::ReferenceTypeName(span, WTFMove(memberType))); - structMembers.append(makeUniqueRef( + structMembers.append(m_callGraph.ast().astBuilder().construct( span, AST::Identifier::make(global->declaration->name()), WTFMove(memberType), diff --git a/Source/WebGPU/WGSL/MangleNames.cpp b/Source/WebGPU/WGSL/MangleNames.cpp index 40e1e34f7a2b..e6d9a569f893 100644 --- a/Source/WebGPU/WGSL/MangleNames.cpp +++ b/Source/WebGPU/WGSL/MangleNames.cpp @@ -148,7 +148,7 @@ void NameManglerVisitor::visit(AST::Structure& structure) introduceVariable(structure.name(), MangledName::Type); NameMap fieldMap; - for (auto& member : structure.members()) { + for (AST::StructureMember& member : structure.members()) { AST::Visitor::visit(member.type()); auto mangledName = makeMangledName(member.name(), MangledName::Field); fieldMap.add(member.name(), mangledName); diff --git a/Source/WebGPU/WGSL/Metal/MetalFunctionWriter.cpp b/Source/WebGPU/WGSL/Metal/MetalFunctionWriter.cpp index 13ab1dd82801..60db3dfdf06c 100644 --- a/Source/WebGPU/WGSL/Metal/MetalFunctionWriter.cpp +++ b/Source/WebGPU/WGSL/Metal/MetalFunctionWriter.cpp @@ -168,7 +168,7 @@ void FunctionDefinitionWriter::visit(AST::Structure& structDecl) m_stringBuilder.append(m_indent, "struct ", structDecl.name(), " {\n"); { IndentationScope scope(m_indent); - for (auto& member : structDecl.members()) { + for (AST::StructureMember& member : structDecl.members()) { m_stringBuilder.append(m_indent); visit(member.type()); m_stringBuilder.append(" ", member.name()); diff --git a/Source/WebGPU/WGSL/Parser.cpp b/Source/WebGPU/WGSL/Parser.cpp index 2f32aaf89e40..484354b4b5f3 100644 --- a/Source/WebGPU/WGSL/Parser.cpp +++ b/Source/WebGPU/WGSL/Parser.cpp @@ -77,6 +77,12 @@ struct TemplateTypes { return { WTFMove(astNodeResult) }; \ } while (false) +#define RETURN_ARENA_NODE(type, ...) \ + do { \ + AST::type& astNodeResult = m_builder.construct(CURRENT_SOURCE_SPAN() __VA_OPT__(,) __VA_ARGS__); /* NOLINT */ \ + return { astNodeResult }; \ + } while (false) + #define RETURN_NODE_REF(type, ...) \ return { adoptRef(*new AST::type(CURRENT_SOURCE_SPAN(), __VA_ARGS__)) }; @@ -549,7 +555,7 @@ Result Parser::parseStructure(AST::Attribute::List&& AST::StructureMember::List members; while (current().type != TokenType::BraceRight) { PARSE(member, StructureMember); - members.append(makeUniqueRef(WTFMove(member))); + members.append(member); if (current().type == TokenType::Comma) consume(); else @@ -562,7 +568,7 @@ Result Parser::parseStructure(AST::Attribute::List&& } template -Result Parser::parseStructureMember() +Result> Parser::parseStructureMember() { START_PARSE(); @@ -571,7 +577,7 @@ Result Parser::parseStructureMember() CONSUME_TYPE(Colon); PARSE(type, TypeName); - RETURN_NODE(StructureMember, WTFMove(name), WTFMove(type), WTFMove(attributes)); + RETURN_ARENA_NODE(StructureMember, WTFMove(name), WTFMove(type), WTFMove(attributes)); } template diff --git a/Source/WebGPU/WGSL/ParserPrivate.h b/Source/WebGPU/WGSL/ParserPrivate.h index fdfb86d3118a..24ab3673cd6e 100644 --- a/Source/WebGPU/WGSL/ParserPrivate.h +++ b/Source/WebGPU/WGSL/ParserPrivate.h @@ -26,6 +26,7 @@ #pragma once #include "ASTAttribute.h" +#include "ASTBuilder.h" #include "ASTExpression.h" #include "ASTForward.h" #include "ASTStatement.h" @@ -34,6 +35,7 @@ #include "ASTVariable.h" #include "CompilationMessage.h" #include "Lexer.h" +#include "WGSLShaderModule.h" #include namespace WGSL { @@ -45,6 +47,7 @@ class Parser { public: Parser(ShaderModule& shaderModule, Lexer& lexer) : m_shaderModule(shaderModule) + , m_builder(shaderModule.astBuilder()) , m_lexer(lexer) , m_current(lexer.lex()) { @@ -58,7 +61,7 @@ class Parser { Result parseAttributes(); Result parseAttribute(); Result parseStructure(AST::Attribute::List&&); - Result parseStructureMember(); + Result> parseStructureMember(); Result parseTypeName(); Result parseTypeNameAfterIdentifier(AST::Identifier&&, SourcePosition start); Result parseArrayType(); @@ -101,6 +104,7 @@ class Parser { Token& current() { return m_current; } ShaderModule& m_shaderModule; + AST::Builder& m_builder; Lexer& m_lexer; Token m_current; }; diff --git a/Source/WebGPU/WGSL/TypeCheck.cpp b/Source/WebGPU/WGSL/TypeCheck.cpp index 753f71c16be0..80b6ad5d8ba7 100644 --- a/Source/WebGPU/WGSL/TypeCheck.cpp +++ b/Source/WebGPU/WGSL/TypeCheck.cpp @@ -178,7 +178,7 @@ void TypeChecker::visitStructMembers(AST::Structure& structure) ASSERT(std::holds_alternative(**type)); auto& structType = std::get(**type); - for (auto& member : structure.members()) { + for (AST::StructureMember& member : structure.members()) { auto* memberType = resolve(member.type()); auto result = structType.fields.add(member.name().id(), memberType); ASSERT_UNUSED(result, result.isNewEntry); diff --git a/Source/WebGPU/WGSL/WGSLShaderModule.h b/Source/WebGPU/WGSL/WGSLShaderModule.h index a1bcd11976ce..74fc91bdae24 100644 --- a/Source/WebGPU/WGSL/WGSLShaderModule.h +++ b/Source/WebGPU/WGSL/WGSLShaderModule.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Apple Inc. All rights reserved. + * Copyright (c) 2021-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 @@ -25,6 +25,7 @@ #pragma once +#include "ASTBuilder.h" #include "ASTDirective.h" #include "ASTFunction.h" #include "ASTStructure.h" @@ -56,6 +57,7 @@ class ShaderModule { AST::Structure::List& structures() { return m_structures; } AST::Variable::List& variables() { return m_variables; } TypeStore& types() { return m_types; } + AST::Builder& astBuilder() { return m_astBuilder; } template std::enable_if_t, void> replace(T* current, T&& replacement) @@ -136,6 +138,7 @@ class ShaderModule { AST::Structure::List m_structures; AST::Variable::List m_variables; TypeStore m_types; + AST::Builder m_astBuilder; Vector> m_replacements; }; diff --git a/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj b/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj index bf349483f261..1c8c25afc90d 100644 --- a/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj +++ b/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj @@ -123,6 +123,8 @@ 9776BE732992A236002D6D93 /* Overload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9776BE712992A236002D6D93 /* Overload.cpp */; }; 9776BE742992A236002D6D93 /* Overload.h in Headers */ = {isa = PBXBuildFile; fileRef = 9776BE722992A236002D6D93 /* Overload.h */; }; 9776BE7629957E12002D6D93 /* WGSLShaderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 9776BE7529957E12002D6D93 /* WGSLShaderModule.h */; }; + 97835C9329F7C9C600939EBA /* ASTBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 97835C9229F7C9C600939EBA /* ASTBuilder.h */; }; + 97835C9529F7D85A00939EBA /* ASTBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97835C9429F7D85A00939EBA /* ASTBuilder.cpp */; }; 9789C31A297EA105009E9006 /* CallGraph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9789C318297EA105009E9006 /* CallGraph.cpp */; }; 978A9125298A4E8400B37E5E /* MangleNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 978A9123298A4E8400B37E5E /* MangleNames.cpp */; }; 978A9126298A4E8400B37E5E /* MangleNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 978A9124298A4E8400B37E5E /* MangleNames.h */; }; @@ -363,6 +365,8 @@ 9776BE712992A236002D6D93 /* Overload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Overload.cpp; sourceTree = ""; }; 9776BE722992A236002D6D93 /* Overload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Overload.h; sourceTree = ""; }; 9776BE7529957E12002D6D93 /* WGSLShaderModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WGSLShaderModule.h; sourceTree = ""; }; + 97835C9229F7C9C600939EBA /* ASTBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTBuilder.h; sourceTree = ""; }; + 97835C9429F7D85A00939EBA /* ASTBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTBuilder.cpp; sourceTree = ""; }; 9789C318297EA105009E9006 /* CallGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallGraph.cpp; sourceTree = ""; }; 9789C319297EA105009E9006 /* CallGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallGraph.h; sourceTree = ""; }; 978A9123298A4E8400B37E5E /* MangleNames.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MangleNames.cpp; sourceTree = ""; }; @@ -602,6 +606,8 @@ 3A12AECB28FCFA9800C1B975 /* ASTBitcastExpression.h */, 3A12AED028FCFC5500C1B975 /* ASTBoolLiteral.h */, 3A12AE9F28FCE94B00C1B975 /* ASTBreakStatement.h */, + 97835C9429F7D85A00939EBA /* ASTBuilder.cpp */, + 97835C9229F7C9C600939EBA /* ASTBuilder.h */, 3A12AE9028FCE94A00C1B975 /* ASTBuiltinAttribute.h */, 33EA188527BC26DF00A1DD52 /* ASTCallExpression.h */, 3A12AEA328FCE94C00C1B975 /* ASTCompoundAssignmentStatement.h */, @@ -707,6 +713,7 @@ 3A12AECD28FCFA9800C1B975 /* ASTBitcastExpression.h in Headers */, 3A12AED628FCFC5600C1B975 /* ASTBoolLiteral.h in Headers */, 3A12AEB928FCE94C00C1B975 /* ASTBreakStatement.h in Headers */, + 97835C9329F7C9C600939EBA /* ASTBuilder.h in Headers */, 3A12AEAA28FCE94C00C1B975 /* ASTBuiltinAttribute.h in Headers */, 33EA188627BC26DF00A1DD52 /* ASTCallExpression.h in Headers */, 3A12AEBD28FCE94C00C1B975 /* ASTCompoundAssignmentStatement.h in Headers */, @@ -951,6 +958,7 @@ buildActionMask = 2147483647; files = ( 3AD0D23E2988F3AB0080D728 /* ASTBinaryExpression.cpp in Sources */, + 97835C9529F7D85A00939EBA /* ASTBuilder.cpp in Sources */, 3A9D02A4298390CF00888A75 /* ASTStringDumper.cpp in Sources */, 3AD0D23B2988ED8F0080D728 /* ASTUnaryExpression.cpp in Sources */, 3A1337E728FBD56400F29B73 /* ASTVisitor.cpp in Sources */, diff --git a/Tools/TestWebKitAPI/Tests/WGSL/ParserTests.cpp b/Tools/TestWebKitAPI/Tests/WGSL/ParserTests.cpp index 3e76713affa3..895577d6fc00 100644 --- a/Tools/TestWebKitAPI/Tests/WGSL/ParserTests.cpp +++ b/Tools/TestWebKitAPI/Tests/WGSL/ParserTests.cpp @@ -123,7 +123,7 @@ static void testStruct(ASCIILiteral program, const Vector& fieldNames, c EXPECT_EQ(str.members().size(), fieldNames.size()); for (unsigned i = 0; i < fieldNames.size(); ++i) { - auto& attributes = str.members()[i].attributes(); + auto& attributes = str.members()[i].get().attributes(); if (!attributeTests.size()) EXPECT_TRUE(attributes.isEmpty()); else { @@ -150,9 +150,9 @@ static void testStruct(ASCIILiteral program, const Vector& fieldNames, c } } } - EXPECT_EQ(str.members()[i].name(), fieldNames[i]); - EXPECT_TRUE(is(str.members()[i].type())); - auto& memberType = downcast(str.members()[i].type()); + EXPECT_EQ(str.members()[i].get().name(), fieldNames[i]); + EXPECT_TRUE(is(str.members()[i].get().type())); + auto& memberType = downcast(str.members()[i].get().type()); EXPECT_EQ(memberType.name(), typeNames[i]); } }