feat: implement proper IR with value handles with dynamic and transferable types

This commit is contained in:
2026-01-01 15:50:26 +01:00
parent 3b8dfc4dae
commit 6f4ab269e2
8 changed files with 621 additions and 375 deletions

View File

@@ -8,176 +8,234 @@
namespace IR
{
class ExternOp : public Op
{
public:
ExternOp(StringView symbol)
: m_symbol(symbol) {}
~ExternOp() {}
OP_TYPE(EXTERN)
public:
StringView Format(int indent) const override
class ExternOp : public Op
{
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;
};
public:
ExternOp(StringView symbol)
: m_symbol(symbol) {}
~ExternOp() {}
// TODO: Make function return value (i.e. inhreit the OpValued class instead)
class FnOp : public Op
{
public:
FnOp(StringView name, const View<StringView>& params, Block&& block)
: m_name(name), m_params(params), m_body(block) {}
~FnOp() {}
OP_TYPE(FN)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << "LABEL " << m_name.c_str() << ':' << '\n';
sb << m_body.Format(indent);
return sb.view();
}
public:
const StringView& name() const { return m_name; }
const Block& body() const { return m_body; }
const View<StringView>& params() const { return m_params; }
private:
StringView m_name;
ValueView m_slots;
View<StringView> m_params;
Block m_body;
};
class LoadConstOp : public OpValued
{
public:
LoadConstOp(Value dest, long value)
: OpValued(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 OpValued
{
public:
LoadOp(Value dest, StringView addr)
: OpValued(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 OpValued
{
public:
AddOp(Value dest, Value lhs, Value rhs)
: OpValued(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 OpValued
{
public:
CallOp(Value dest, StringView callee, ValueView args)
: OpValued(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)
OP_TYPE(EXTERN)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << "PARAM " << m_args.data[i].Format() << '\n';
sb << "EXTRN " << m_symbol.c_str();
return sb.view();
}
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;
};
public:
const StringView &symbol() const { return m_symbol; }
private:
StringView m_symbol;
};
// TODO: Make function return value (i.e. inhreit the OpValued class instead)
class FnOp : public Op
{
public:
FnOp(StringView name, const View<StringView> &params, Block &&block)
: m_name(name), m_params(params), m_body(block) {}
~FnOp() {}
OP_TYPE(FN)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << "LABEL " << m_name.c_str() << ':' << '\n';
sb << m_body.Format(indent);
return sb.view();
}
public:
const StringView &name() const { return m_name; }
const Block &body() const { return m_body; }
const View<StringView> &params() const { return m_params; }
private:
StringView m_name;
View<StringView> m_params;
Block m_body;
};
// Allocate slot on the stack for variable
// with the size of destination value,
// aka (dest.GetSize() will be used)
class AllocateOp : public OpValued
{
public:
AllocateOp(ValueHandle *dest, const ValueHandle::Type *typ)
: OpValued(dest), m_typ(new ValueHandle::Type(typ)) {}
~AllocateOp() {}
OP_TYPE(ALLOCATE)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << result()->Format() << " = ALLOCATE " << m_typ->Format();
return sb.view();
}
private:
ValueHandle::Type *m_typ;
};
// class LoadConstOp : public OpValued
// {
// public:
// LoadConstOp(ValueHandle *dest, long value)
// : OpValued(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 OpValued
{
public:
LoadOp(ValueHandle *dest, StringView addr)
: OpValued(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(ValueHandle *src, Pointer *dst)
: m_dst(dst), m_src(src) {}
~StoreOp() {}
OP_TYPE(STORE)
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << "STORE " << src()->Format() << ", " << dst()->Format();
return sb.view();
}
public:
const Pointer *dst() const { return m_dst; }
const ValueHandle *src() const { return m_src; }
private:
Pointer *m_dst;
ValueHandle *m_src;
};
class MathOp : public OpValued
{
public:
MathOp(ValueHandle *dest, ValueHandle *lhs, ValueHandle *rhs, OpType typ)
: OpValued(dest), m_lhs(lhs), m_rhs(rhs), m_typ(typ) {}
~MathOp() {}
OpType GetType() const override { return m_typ; }
private:
StringView FormatOperation() const
{
switch (m_typ)
{
case OpType::ADD:
return StringView("ADD");
case OpType::MUL:
return StringView("MUL");
case OpType::SUB:
return StringView("SUB");
case OpType::DIV:
return StringView("DIV");
}
assert(false && "unreachable");
}
public:
StringView Format(int indent) const override
{
StringBuilder sb;
sb.AppendIndent(indent);
sb << result()->Format() << " = " << FormatOperation() << " " << m_lhs->Format() << ", " << m_rhs->Format();
return sb.view();
}
public:
ValueHandle *lhs() const { return m_lhs; }
ValueHandle *rhs() const { return m_rhs; }
private:
ValueHandle *m_lhs;
ValueHandle *m_rhs;
OpType m_typ;
};
class CallOp : public OpValued
{
public:
CallOp(ValueHandle *dest, StringView callee, ValueView args)
: OpValued(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;
};
} // namespace IR