1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 12:28:12 +00:00

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.
This commit is contained in:
Dan Klishch 2023-10-01 22:32:10 -04:00 committed by Andrew Kaster
parent 23164bc570
commit 0aeb7a26e9
11 changed files with 173 additions and 13 deletions

View file

@ -4,6 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/String.h>
#include "AST/AST.h" #include "AST/AST.h"
namespace JSSpecCompiler { namespace JSSpecCompiler {
@ -17,6 +19,9 @@ Tree NodeSubtreePointer::get(Badge<RecursiveASTVisitor>)
}, },
[&](Tree* tree) -> Tree { [&](Tree* tree) -> Tree {
return *tree; return *tree;
},
[&](VariableRef* tree) -> Tree {
return *tree;
}); });
} }
@ -28,6 +33,9 @@ void NodeSubtreePointer::replace_subtree(Badge<RecursiveASTVisitor>, NullableTre
}, },
[&](Tree* tree) { [&](Tree* tree) {
*tree = replacement.release_nonnull(); *tree = replacement.release_nonnull();
},
[&](VariableRef*) {
VERIFY_NOT_REACHED();
}); });
} }
@ -131,4 +139,11 @@ Vector<NodeSubtreePointer> FunctionCall::subtrees()
return result; 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));
}
} }

View file

@ -33,16 +33,26 @@ public:
{ {
} }
NodeSubtreePointer(VariableRef* tree_ptr)
: m_tree_ptr(tree_ptr)
{
}
Tree get(Badge<RecursiveASTVisitor>); Tree get(Badge<RecursiveASTVisitor>);
void replace_subtree(Badge<RecursiveASTVisitor>, NullableTree replacement); void replace_subtree(Badge<RecursiveASTVisitor>, NullableTree replacement);
private: private:
Variant<Tree*, NullableTree*> m_tree_ptr; Variant<Tree*, NullableTree*, VariableRef*> m_tree_ptr;
}; };
class VariableDeclaration : public RefCounted<VariableDeclaration> { class VariableDeclaration : public RefCounted<VariableDeclaration> {
public: public:
VariableDeclaration(StringView name) virtual ~VariableDeclaration() = default;
};
class NamedVariableDeclaration : public VariableDeclaration {
public:
NamedVariableDeclaration(StringView name)
: m_name(name) : m_name(name)
{ {
} }
@ -50,6 +60,17 @@ public:
StringView m_name; 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<Node> { class Node : public RefCounted<Node> {
public: public:
virtual ~Node() = default; virtual ~Node() = default;
@ -60,6 +81,7 @@ public:
virtual Vector<NodeSubtreePointer> subtrees() { return {}; } virtual Vector<NodeSubtreePointer> subtrees() { return {}; }
virtual bool is_list() const { return false; } virtual bool is_list() const { return false; }
virtual bool is_statement() { VERIFY_NOT_REACHED(); }
protected: protected:
template<typename... Parameters> template<typename... Parameters>
@ -78,11 +100,20 @@ protected:
// auto tmp3 = d; // auto tmp3 = d;
// a = tmp1 + tmp2; // a = tmp1 + tmp2;
// ```. // ```.
class Statement : public Node { }; class Statement : public Node {
class Expression : public Node { }; public:
bool is_statement() override { return true; }
};
class Expression : public Node {
public:
bool is_statement() override { return false; }
};
class ControlFlowOperator : public Statement { class ControlFlowOperator : public Statement {
public: public:
bool is_statement() override { return false; }
virtual Vector<BasicBlockRef*> references() = 0; virtual Vector<BasicBlockRef*> references() = 0;
}; };
@ -110,6 +141,7 @@ public:
VariableRef m_return_value; VariableRef m_return_value;
Vector<NodeSubtreePointer> subtrees() override { return { { &m_return_value } }; }
Vector<BasicBlockRef*> references() override { return {}; } Vector<BasicBlockRef*> references() override { return {}; }
protected: protected:
@ -143,6 +175,7 @@ public:
{ {
} }
Vector<NodeSubtreePointer> subtrees() override { return { { &m_condition } }; }
Vector<BasicBlockRef*> references() override; Vector<BasicBlockRef*> references() override;
Tree m_condition; Tree m_condition;
@ -448,12 +481,15 @@ protected:
class Variable : public Expression { class Variable : public Expression {
public: public:
Variable(VariableDeclarationRef variable_declaration) Variable(NamedVariableDeclarationRef name)
: m_variable_declaration(move(variable_declaration)) : m_name(move(name))
{ {
} }
VariableDeclarationRef m_variable_declaration; NamedVariableDeclarationRef m_name;
SSAVariableDeclarationRef m_ssa;
String name() const;
protected: protected:
void dump_tree(StringBuilder& builder) override; void dump_tree(StringBuilder& builder) override;

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <AK/TemporaryChange.h> #include <AK/TemporaryChange.h>
@ -156,7 +157,7 @@ void SlotName::dump_tree(StringBuilder& builder)
void Variable::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) void FunctionPointer::dump_tree(StringBuilder& builder)

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include "AST/AST.h" #include "AST/AST.h"
@ -17,6 +18,15 @@ ErrorOr<void> AK::Formatter<ControlFlowGraph>::format(FormatBuilder& format_buil
for (auto const& block : control_flow_graph.blocks) { for (auto const& block : control_flow_graph.blocks) {
builder.appendff("{}:\n", block->m_index); 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) for (auto const& expression : block->m_expressions)
builder.appendff("{}", expression); builder.appendff("{}", expression);
builder.appendff("{}\n", Tree(block->m_continuation)); builder.appendff("{}\n", Tree(block->m_continuation));

View file

@ -16,15 +16,28 @@ namespace JSSpecCompiler {
class BasicBlock : public RefCounted<BasicBlock> { class BasicBlock : public RefCounted<BasicBlock> {
public: public:
struct PhiNode {
struct Branch {
BasicBlockRef block;
VariableRef value;
};
VariableRef var;
Vector<Branch> branches;
};
BasicBlock(size_t index, NonnullRefPtr<ControlFlowOperator> continuation) BasicBlock(size_t index, NonnullRefPtr<ControlFlowOperator> continuation)
: m_index(index) : m_index(index)
, m_continuation(move(continuation)) , m_continuation(move(continuation))
, m_immediate_dominator(nullptr)
{ {
} }
size_t m_index; size_t m_index;
Vector<PhiNode> m_phi_nodes;
Vector<Tree> m_expressions; Vector<Tree> m_expressions;
NonnullRefPtr<ControlFlowOperator> m_continuation; NonnullRefPtr<ControlFlowOperator> m_continuation;
BasicBlockRef m_immediate_dominator;
}; };
class ControlFlowGraph : public RefCounted<ControlFlowGraph> { class ControlFlowGraph : public RefCounted<ControlFlowGraph> {

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/NumericLimits.h>
#include <AK/Vector.h>
namespace JSSpecCompiler {
struct VoidRef { };
template<typename T, typename NativeNodeRef = VoidRef>
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<NativeNodeRef, VoidRef>)
: 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<size_t>::max();
template<typename Func>
void with_graph(Func func)
{
m_instance = static_cast<T*>(this);
func();
m_instance = nullptr;
}
template<typename Func>
void with_graph(size_t n, Func func)
{
m_instance = static_cast<T*>(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;
};
}

View file

@ -23,7 +23,7 @@ RecursionDecision ReferenceResolvingPass::on_entry(Tree tree)
if (auto variable_name = as<UnresolvedReference>(binary_operation->m_left); variable_name) { if (auto variable_name = as<UnresolvedReference>(binary_operation->m_left); variable_name) {
auto name = variable_name->m_name; auto name = variable_name->m_name;
if (!m_function->m_local_variables.contains(name)) if (!m_function->m_local_variables.contains(name))
m_function->m_local_variables.set(name, make_ref_counted<VariableDeclaration>(name)); m_function->m_local_variables.set(name, make_ref_counted<NamedVariableDeclaration>(name));
} }
} }
return RecursionDecision::Recurse; return RecursionDecision::Recurse;

View file

@ -14,6 +14,10 @@ namespace JSSpecCompiler {
class NodeSubtreePointer; class NodeSubtreePointer;
class VariableDeclaration; class VariableDeclaration;
using VariableDeclarationRef = NonnullRefPtr<VariableDeclaration>; using VariableDeclarationRef = NonnullRefPtr<VariableDeclaration>;
class NamedVariableDeclaration;
using NamedVariableDeclarationRef = NonnullRefPtr<NamedVariableDeclaration>;
class SSAVariableDeclaration;
using SSAVariableDeclarationRef = RefPtr<SSAVariableDeclaration>;
class Node; class Node;
using NullableTree = RefPtr<Node>; using NullableTree = RefPtr<Node>;

View file

@ -28,8 +28,15 @@ FunctionDeclaration::FunctionDeclaration(StringView name)
FunctionDefinition::FunctionDefinition(StringView name, Tree ast) FunctionDefinition::FunctionDefinition(StringView name, Tree ast)
: FunctionDeclaration(name) : FunctionDeclaration(name)
, m_ast(move(ast)) , m_ast(move(ast))
, m_return_value(make_ref_counted<VariableDeclaration>("$return"sv)) , m_return_value(make_ref_counted<NamedVariableDeclaration>("$return"sv))
{ {
} }
void FunctionDefinition::reindex_ssa_variables()
{
size_t index = 0;
for (auto const& var : m_local_ssa_variables)
var->m_index = index++;
}
} }

View file

@ -37,9 +37,14 @@ class FunctionDefinition : public FunctionDeclaration {
public: public:
FunctionDefinition(StringView name, Tree ast); FunctionDefinition(StringView name, Tree ast);
void reindex_ssa_variables();
Tree m_ast; Tree m_ast;
VariableDeclarationRef m_return_value; NamedVariableDeclarationRef m_return_value;
HashMap<StringView, VariableDeclarationRef> m_local_variables; // 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<StringView, NamedVariableDeclarationRef> m_local_variables;
Vector<SSAVariableDeclarationRef> m_local_ssa_variables;
RefPtr<ControlFlowGraph> m_cfg; RefPtr<ControlFlowGraph> m_cfg;
}; };

View file

@ -200,7 +200,7 @@ void SpecParsingStep::run(TranslationUnitRef translation_unit)
make_ref_counted<FunctionDefinition>(spec_function.m_name, spec_function.m_algorithm.m_tree)); make_ref_counted<FunctionDefinition>(spec_function.m_name, spec_function.m_algorithm.m_tree));
for (auto const& argument : spec_function.m_arguments) for (auto const& argument : spec_function.m_arguments)
function->m_local_variables.set(argument.name, make_ref_counted<VariableDeclaration>(argument.name)); function->m_local_variables.set(argument.name, make_ref_counted<NamedVariableDeclaration>(argument.name));
} }
} }