From 0aeb7a26e912a7d4bc1a17e688647f54be3b3f09 Mon Sep 17 00:00:00 2001 From: Dan Klishch Date: Sun, 1 Oct 2023 22:32:10 -0400 Subject: [PATCH] JSSpecCompiler: Prepare for building SSA This commit introduces NamedVariableDeclaration and SSAVariableDeclaration and allows storing both of them in Variable node. Also, it adds additional structures in FunctionDefinition and BasicBlock, which will be used to store SSA form related information. --- .../CodeGenerators/JSSpecCompiler/AST/AST.cpp | 15 ++++ .../CodeGenerators/JSSpecCompiler/AST/AST.h | 50 ++++++++++++-- .../JSSpecCompiler/AST/ASTPrinting.cpp | 3 +- .../Compiler/ControlFlowGraph.cpp | 10 +++ .../Compiler/ControlFlowGraph.h | 13 ++++ .../Compiler/EnableGraphPointers.h | 69 +++++++++++++++++++ .../Passes/ReferenceResolvingPass.cpp | 2 +- .../CodeGenerators/JSSpecCompiler/Forward.h | 4 ++ .../JSSpecCompiler/Function.cpp | 9 ++- .../CodeGenerators/JSSpecCompiler/Function.h | 9 ++- .../JSSpecCompiler/Parser/SpecParser.cpp | 2 +- 11 files changed, 173 insertions(+), 13 deletions(-) create mode 100644 Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/EnableGraphPointers.h diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp index dbaa66a04ce..1442ca8b529 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp @@ -4,6 +4,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include "AST/AST.h" namespace JSSpecCompiler { @@ -17,6 +19,9 @@ Tree NodeSubtreePointer::get(Badge) }, [&](Tree* tree) -> Tree { return *tree; + }, + [&](VariableRef* tree) -> Tree { + return *tree; }); } @@ -28,6 +33,9 @@ void NodeSubtreePointer::replace_subtree(Badge, NullableTre }, [&](Tree* tree) { *tree = replacement.release_nonnull(); + }, + [&](VariableRef*) { + VERIFY_NOT_REACHED(); }); } @@ -131,4 +139,11 @@ Vector FunctionCall::subtrees() return result; } +String Variable::name() const +{ + if (m_ssa) + return MUST(String::formatted("{}@{}", m_name->m_name, m_ssa->m_version)); + return MUST(String::from_utf8(m_name->m_name)); +} + } diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h index 0c17446c3c4..068ba905e73 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h @@ -33,16 +33,26 @@ public: { } + NodeSubtreePointer(VariableRef* tree_ptr) + : m_tree_ptr(tree_ptr) + { + } + Tree get(Badge); void replace_subtree(Badge, NullableTree replacement); private: - Variant m_tree_ptr; + Variant m_tree_ptr; }; class VariableDeclaration : public RefCounted { public: - VariableDeclaration(StringView name) + virtual ~VariableDeclaration() = default; +}; + +class NamedVariableDeclaration : public VariableDeclaration { +public: + NamedVariableDeclaration(StringView name) : m_name(name) { } @@ -50,6 +60,17 @@ public: StringView m_name; }; +class SSAVariableDeclaration : public VariableDeclaration { +public: + SSAVariableDeclaration(u64 version) + : m_version(version) + { + } + + size_t m_index = 0; + u64 m_version; +}; + class Node : public RefCounted { public: virtual ~Node() = default; @@ -60,6 +81,7 @@ public: virtual Vector subtrees() { return {}; } virtual bool is_list() const { return false; } + virtual bool is_statement() { VERIFY_NOT_REACHED(); } protected: template @@ -78,11 +100,20 @@ protected: // auto tmp3 = d; // a = tmp1 + tmp2; // ```. -class Statement : public Node { }; -class Expression : public Node { }; +class Statement : public Node { +public: + bool is_statement() override { return true; } +}; + +class Expression : public Node { +public: + bool is_statement() override { return false; } +}; class ControlFlowOperator : public Statement { public: + bool is_statement() override { return false; } + virtual Vector references() = 0; }; @@ -110,6 +141,7 @@ public: VariableRef m_return_value; + Vector subtrees() override { return { { &m_return_value } }; } Vector references() override { return {}; } protected: @@ -143,6 +175,7 @@ public: { } + Vector subtrees() override { return { { &m_condition } }; } Vector references() override; Tree m_condition; @@ -448,12 +481,15 @@ protected: class Variable : public Expression { public: - Variable(VariableDeclarationRef variable_declaration) - : m_variable_declaration(move(variable_declaration)) + Variable(NamedVariableDeclarationRef name) + : m_name(move(name)) { } - VariableDeclarationRef m_variable_declaration; + NamedVariableDeclarationRef m_name; + SSAVariableDeclarationRef m_ssa; + + String name() const; protected: void dump_tree(StringBuilder& builder) override; diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp index b22d0e80e74..00e48ce26cc 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include @@ -156,7 +157,7 @@ void SlotName::dump_tree(StringBuilder& builder) void Variable::dump_tree(StringBuilder& builder) { - dump_node(builder, "Var {}", m_variable_declaration->m_name); + dump_node(builder, "Var {}", name()); } void FunctionPointer::dump_tree(StringBuilder& builder) diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.cpp index 405e3829747..ae1526f9af8 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include "AST/AST.h" @@ -17,6 +18,15 @@ ErrorOr AK::Formatter::format(FormatBuilder& format_buil for (auto const& block : control_flow_graph.blocks) { builder.appendff("{}:\n", block->m_index); + for (auto const& phi_node : block->m_phi_nodes) { + builder.appendff("{} = phi(", phi_node.var->name()); + for (auto const& branches : phi_node.branches) { + builder.appendff("{}: {}", branches.block->m_index, branches.value->name()); + if (&branches != &phi_node.branches.last()) + builder.appendff(", "); + } + builder.appendff(")\n"); + } for (auto const& expression : block->m_expressions) builder.appendff("{}", expression); builder.appendff("{}\n", Tree(block->m_continuation)); diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.h index 28e0fa3723c..1c6c064e5a0 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.h +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/ControlFlowGraph.h @@ -16,15 +16,28 @@ namespace JSSpecCompiler { class BasicBlock : public RefCounted { public: + struct PhiNode { + struct Branch { + BasicBlockRef block; + VariableRef value; + }; + + VariableRef var; + Vector branches; + }; + BasicBlock(size_t index, NonnullRefPtr continuation) : m_index(index) , m_continuation(move(continuation)) + , m_immediate_dominator(nullptr) { } size_t m_index; + Vector m_phi_nodes; Vector m_expressions; NonnullRefPtr m_continuation; + BasicBlockRef m_immediate_dominator; }; class ControlFlowGraph : public RefCounted { diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/EnableGraphPointers.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/EnableGraphPointers.h new file mode 100644 index 00000000000..fb827d1c0ef --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/EnableGraphPointers.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023, Dan Klishch + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace JSSpecCompiler { + +struct VoidRef { }; + +template +class EnableGraphPointers { +public: + class VertexBase { + public: + VertexBase() = default; + VertexBase(size_t index) + : m_index(index) + { + } + + bool is_invalid() const { return m_index == invalid_node; } + operator size_t() const { return m_index; } + + explicit VertexBase(NativeNodeRef const& node) + requires(!IsSame) + : VertexBase(node->m_index) + { + } + + auto& operator*() const { return m_instance->m_nodes[m_index]; } + auto* operator->() const { return &m_instance->m_nodes[m_index]; } + + protected: + size_t m_index = invalid_node; + }; + + using Vertex = VertexBase; + + inline static constexpr size_t invalid_node = NumericLimits::max(); + + template + void with_graph(Func func) + { + m_instance = static_cast(this); + func(); + m_instance = nullptr; + } + + template + void with_graph(size_t n, Func func) + { + m_instance = static_cast(this); + m_instance->m_nodes.resize(n); + func(); + m_instance->m_nodes.clear(); + m_instance = nullptr; + } + +protected: + inline static thread_local T* m_instance = nullptr; +}; + +} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.cpp index ca94f32961f..cc2561b1b97 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Compiler/Passes/ReferenceResolvingPass.cpp @@ -23,7 +23,7 @@ RecursionDecision ReferenceResolvingPass::on_entry(Tree tree) if (auto variable_name = as(binary_operation->m_left); variable_name) { auto name = variable_name->m_name; if (!m_function->m_local_variables.contains(name)) - m_function->m_local_variables.set(name, make_ref_counted(name)); + m_function->m_local_variables.set(name, make_ref_counted(name)); } } return RecursionDecision::Recurse; diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h index a285af898f3..21962911fcd 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h @@ -14,6 +14,10 @@ namespace JSSpecCompiler { class NodeSubtreePointer; class VariableDeclaration; using VariableDeclarationRef = NonnullRefPtr; +class NamedVariableDeclaration; +using NamedVariableDeclarationRef = NonnullRefPtr; +class SSAVariableDeclaration; +using SSAVariableDeclarationRef = RefPtr; class Node; using NullableTree = RefPtr; diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.cpp index cda60310f3b..720437c1593 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.cpp @@ -28,8 +28,15 @@ FunctionDeclaration::FunctionDeclaration(StringView name) FunctionDefinition::FunctionDefinition(StringView name, Tree ast) : FunctionDeclaration(name) , m_ast(move(ast)) - , m_return_value(make_ref_counted("$return"sv)) + , m_return_value(make_ref_counted("$return"sv)) { } +void FunctionDefinition::reindex_ssa_variables() +{ + size_t index = 0; + for (auto const& var : m_local_ssa_variables) + var->m_index = index++; +} + } diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.h index 64e7b6131a2..57d3fcd97a9 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.h +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Function.h @@ -37,9 +37,14 @@ class FunctionDefinition : public FunctionDeclaration { public: FunctionDefinition(StringView name, Tree ast); + void reindex_ssa_variables(); + Tree m_ast; - VariableDeclarationRef m_return_value; - HashMap m_local_variables; + NamedVariableDeclarationRef m_return_value; + // NOTE: The hash map here is ordered since we do not want random hash changes to break our test + // expectations (looking at you, SipHash). + OrderedHashMap m_local_variables; + Vector m_local_ssa_variables; RefPtr m_cfg; }; diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp index 357e230537d..95aa1f6dd20 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp @@ -200,7 +200,7 @@ void SpecParsingStep::run(TranslationUnitRef translation_unit) make_ref_counted(spec_function.m_name, spec_function.m_algorithm.m_tree)); for (auto const& argument : spec_function.m_arguments) - function->m_local_variables.set(argument.name, make_ref_counted(argument.name)); + function->m_local_variables.set(argument.name, make_ref_counted(argument.name)); } }