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
Notes: sideshowbarker 2024-07-17 02:29:45 +09:00
11 changed files with 173 additions and 13 deletions

View file

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

View file

@ -33,16 +33,26 @@ public:
{
}
NodeSubtreePointer(VariableRef* tree_ptr)
: m_tree_ptr(tree_ptr)
{
}
Tree get(Badge<RecursiveASTVisitor>);
void replace_subtree(Badge<RecursiveASTVisitor>, NullableTree replacement);
private:
Variant<Tree*, NullableTree*> m_tree_ptr;
Variant<Tree*, NullableTree*, VariableRef*> m_tree_ptr;
};
class VariableDeclaration : public RefCounted<VariableDeclaration> {
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<Node> {
public:
virtual ~Node() = default;
@ -60,6 +81,7 @@ public:
virtual Vector<NodeSubtreePointer> subtrees() { return {}; }
virtual bool is_list() const { return false; }
virtual bool is_statement() { VERIFY_NOT_REACHED(); }
protected:
template<typename... Parameters>
@ -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<BasicBlockRef*> references() = 0;
};
@ -110,6 +141,7 @@ public:
VariableRef m_return_value;
Vector<NodeSubtreePointer> subtrees() override { return { { &m_return_value } }; }
Vector<BasicBlockRef*> references() override { return {}; }
protected:
@ -143,6 +175,7 @@ public:
{
}
Vector<NodeSubtreePointer> subtrees() override { return { { &m_condition } }; }
Vector<BasicBlockRef*> 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;

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <AK/TemporaryChange.h>
@ -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)

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/String.h>
#include <AK/StringBuilder.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) {
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));

View file

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

View file

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

View file

@ -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<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:
FunctionDefinition(StringView name, Tree ast);
void reindex_ssa_variables();
Tree m_ast;
VariableDeclarationRef m_return_value;
HashMap<StringView, VariableDeclarationRef> 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<StringView, NamedVariableDeclarationRef> m_local_variables;
Vector<SSAVariableDeclarationRef> m_local_ssa_variables;
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));
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));
}
}