Files
pl/include/ir/ops.hpp

242 lines
6.1 KiB
C++

#pragma once
#include "prelude/string.hpp"
#include "parser/nodes.hpp"
#include "ir/value.hpp"
#include "ir/op.hpp"
#include "ir/block.hpp"
namespace IR
{
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;
};
// 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