diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.cpp index dbaa66a04c..1442ca8b52 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 0c17446c3c..068ba905e7 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 b22d0e80e7..00e48ce26c 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 405e382974..ae1526f9af 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 28e0fa3723..1c6c064e5a 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 0000000000..fb827d1c0e --- /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 ca94f32961..cc2561b1b9 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 a285af898f..21962911fc 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 cda60310f3..720437c159 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 64e7b6131a..57d3fcd97a 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 357e230537..95aa1f6dd2 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)); } }