feat: introduced blocks and better project structure

This commit is contained in:
2025-12-24 20:13:13 +01:00
parent e8a496d070
commit 7f73b742c2
9 changed files with 525 additions and 453 deletions

View File

@@ -5,240 +5,29 @@
#include "ir/slot.hpp"
#include "ir/allocator.hpp"
#include "ir/value.hpp"
#include "ir/ops.hpp"
namespace IR
{
enum class OpType
{
EXTERN = 0,
FN,
LOAD_CONST,
LOAD,
STORE,
ADD,
CALL,
COUNT_OPS,
};
#define OP_TYPE(x) \
OpType GetType() const override { return OpType::x; }
class Op
{
public:
virtual OpType GetType() const = 0;
virtual ~Op() {}
virtual StringView Format(int indent) const = 0;
};
using OpView = View<Op*>;
using OpBuilder = Builder<Op*>;
class Valued
{
public:
Valued(Value dest)
: m_dest(dest) {}
~Valued() = default;
public:
Value result() const { return m_dest; }
private:
Value m_dest;
};
class ExternOp : public Op
{
public:
ExternOp(StringView symbol)
: m_symbol(symbol) {}
~ExternOp() {}
OP_TYPE(EXTERN)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << "EXTRN " << m_symbol.c_str();
return sb.view();
}
public:
const StringView& symbol() const { return m_symbol; }
private:
StringView m_symbol;
};
class FnOp : public Op
{
public:
FnOp(StringView name, const CompoundNode* body, const View<StringView>& params);
~FnOp() {}
OP_TYPE(FN)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << "LABEL " << m_name.c_str() << ':' << '\n';
for (size_t i = 0; i < m_ops.size; ++i)
{
sb << m_ops.data[i]->Format(indent + 2) << '\n';
}
return sb.view();
}
public:
const StringView& name() const { return m_name; }
const OpView& ops() const { return m_ops; }
const View<StringView>& params() const { return m_params; }
private:
StringView m_name;
OpView m_ops;
ValueView m_slots;
View<StringView> m_params;
};
class LoadConstOp : public Op, public Valued
{
public:
LoadConstOp(Value dest, long value)
: Valued(dest), m_value(value) {}
~LoadConstOp() {}
OP_TYPE(LOAD_CONST)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << result().Format() << " = LOAD_CONST " << m_value;
return sb.view();
}
public:
long value() const { return m_value; }
private:
long m_value;
};
class LoadOp : public Op, public Valued
{
public:
LoadOp(Value dest, StringView addr)
: Valued(dest), m_addr(addr) {}
~LoadOp() {}
OP_TYPE(LOAD)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << result().Format() << " = LOAD \"" << m_addr.c_str() << "\"";
return sb.view();
}
public:
const StringView& addr() const { return m_addr; }
private:
StringView m_addr;
};
class StoreOp : public Op
{
public:
StoreOp(StringView addr, Value src)
: m_addr(addr), m_src(src) {}
~StoreOp() {}
OP_TYPE(STORE)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << "STORE \"" << m_addr.c_str() << "\", " << m_src.Format();
return sb.view();
}
public:
const StringView& addr() const { return m_addr; }
Value src() const { return m_src; }
private:
StringView m_addr;
Value m_src;
};
class AddOp : public Op, public Valued
{
public:
AddOp(Value dest, Value lhs, Value rhs)
: Valued(dest), m_lhs(lhs), m_rhs(rhs) {}
~AddOp() {}
OP_TYPE(ADD)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << result().Format() << " = ADD " << m_lhs.Format() << ", " << m_rhs.Format();
return sb.view();
}
public:
Value lhs() const { return m_lhs; }
Value rhs() const { return m_rhs; }
private:
Value m_lhs;
Value m_rhs;
};
class CallOp : public Op, public Valued
{
public:
CallOp(Value dest, StringView callee, ValueView args)
: Valued(dest), m_callee(callee), m_args(args) {}
~CallOp() {}
OP_TYPE(CALL)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
for (size_t i = 0; i < m_args.size; ++i)
{
sb.AppendIndent(indent);
sb << "PARAM " << m_args.data[i].Format() << '\n';
}
sb.AppendIndent(indent);
sb << result().Format() << " = CALL " << m_callee.c_str();
return sb.view();
}
public:
const StringView& callee() const { return m_callee; }
const ValueView& args() const { return m_args; }
private:
StringView m_callee;
ValueView m_args;
};
class IRBuilder
{
public:
IRBuilder(const Node* root)
: m_root(root) {}
: m_root(root), m_ops(new OpBuilder()) {}
public:
// TODO: support other literals
Value ParseIntLiteral(const IntLiteralNode* literal)
{
auto dst = AllocateRegister();
m_ops.Push(new LoadConstOp(dst, literal->integer()));
m_ops->Push(new LoadConstOp(dst, literal->integer()));
return dst;
}
Value ParseVariable(const VariableNode* var)
{
// auto dst = AllocateRegister();
// m_ops.Push(new LoadOp(dst, var->name()));
// m_ops->Push(new LoadOp(dst, var->name()));
if (m_locals.find(var->name()) == m_locals.end())
{
// TODO: throw proper error
@@ -257,7 +46,7 @@ public:
argRegs.Push(arg);
}
auto dst = AllocateRegister();
m_ops.Push(new CallOp(dst, fn->name(), argRegs.view()));
m_ops->Push(new CallOp(dst, fn->name(), argRegs.view()));
return dst;
}
@@ -287,7 +76,7 @@ public:
assert(4 == static_cast<int>(ExpressionNode::Operator::COUNT_OPERATORS) && "some operators may not be handled");
switch (expr->op())
{
case ExpressionNode::Operator::Plus: m_ops.Push(new AddOp(dst, lhs, rhs)); break;
case ExpressionNode::Operator::Plus: m_ops->Push(new AddOp(dst, lhs, rhs)); break;
default: assert(0 && "TODO: implement other operations"); break;
}
@@ -300,12 +89,13 @@ public:
void ParseVarDecl(const VarDeclNode* varDecl)
{
auto value = ParseExpression(varDecl->value());
// m_ops.Push(new StoreOp(varDecl->name(), value));
// m_ops->Push(new StoreOp(varDecl->name(), value));
m_locals.insert(std::make_pair(varDecl->name(), value));
}
void ParseBlock(const CompoundNode* compound)
Block ParseBlock(const CompoundNode* compound)
{
StartBlock();
for (auto &statement : *compound)
{
switch(statement->GetType())
@@ -314,6 +104,10 @@ public:
default: ParseExpression(statement); continue;
}
}
auto ops = EndBlock();
auto block = Block(m_block_counter++, std::move(ops->view()));
operator delete(ops);
return block;
}
OpView Build()
@@ -324,32 +118,50 @@ public:
// Externs
for (auto &extrn : program->externs())
{
m_ops.Push(new ExternOp(extrn->symbol()));
m_ops->Push(new ExternOp(extrn->symbol()));
}
// Functions
for (auto &fn : program->funcs())
{
m_ops.Push(new FnOp(fn->name(), fn->body(), fn->params()));
auto block = ParseBlock(fn->body());
m_ops->Push(new FnOp(fn->name(), fn->params(), std::move(block)));
}
return OpView(m_ops.data, m_ops.size);
return OpView(m_ops->data, m_ops->size);
}
public:
// TODO: think about safety (copying m_ops.data before giving)
OpView ops() const { return OpView(m_ops.data, m_ops.size); }
// TODO: think about safety (copying m_ops->data before giving)
OpView ops() const { return OpView(m_ops->data, m_ops->size); }
private:
void StartBlock()
{
m_containers.Push(m_ops);
m_ops = new OpBuilder();
}
OpBuilder* EndBlock()
{
assert(m_containers.size > 0 && "containers stack is empty");
auto current = m_ops;
m_ops = m_containers.data[m_containers.size - 1];
m_containers.size--;
return current;
}
private:
Value AllocateRegister()
{
return Value(m_value_counter++);
}
private:
OpBuilder m_ops;
const Node* m_root = nullptr;
OpBuilder* m_ops = nullptr;
unsigned int m_value_counter = 0;
unsigned int m_block_counter = 0;
std::unordered_map<StringView, Value> m_locals;
Builder<OpBuilder*> m_containers;
};
} // namespace IR