feat: migrate from OpView to DoubleLinkedList<Op*> + multiple
funciton arguments
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "ir/op.hpp"
|
||||
#include "prelude/linkedlist.hpp"
|
||||
#include "prelude/string.hpp"
|
||||
|
||||
class CodeGenerator
|
||||
@@ -9,7 +10,7 @@ public:
|
||||
virtual ~CodeGenerator() {}
|
||||
|
||||
public:
|
||||
virtual bool Generate(const IR::OpView* ops) = 0;
|
||||
virtual bool Generate(const DoubleLinkedList<IR::Op*>* ops) = 0;
|
||||
StringView GetOutput() { return output().view(); }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -13,30 +13,35 @@ public:
|
||||
FasmX86_64Generator() = default;
|
||||
|
||||
public:
|
||||
bool Generate(const IR::OpView* ops) override
|
||||
bool Generate(const DoubleLinkedList<IR::Op*>* ops) override
|
||||
{
|
||||
m_ops = ops;
|
||||
|
||||
output().Extend("format ELF64\n");
|
||||
output().Extend("section '.text' executable\n");
|
||||
|
||||
for (size_t i = 0; i < ops->size; ++i)
|
||||
for (m_current = m_ops->Begin(); m_current != nullptr; node_next())
|
||||
{
|
||||
GenerateStatement(ops->data[i]);
|
||||
GenerateStatement();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void GenerateExtern(IR::ExternOp* extrn)
|
||||
void GenerateExtern()
|
||||
{
|
||||
auto extrn = current<IR::ExternOp>();
|
||||
// TODO: instead of __<symbol, use some random UID or hash string
|
||||
// for safety and collision considerations
|
||||
output().AppendFormat("extrn '%s' as __%s\n", extrn->symbol().c_str(), extrn->symbol().c_str());
|
||||
output().AppendFormat("%s = PLT __%s\n", extrn->symbol().c_str(), extrn->symbol().c_str());
|
||||
}
|
||||
|
||||
void GenerateFunction(IR::FnOp* fn)
|
||||
void GenerateFunction()
|
||||
{
|
||||
auto fn = current<IR::FnOp>();
|
||||
|
||||
m_slots.clear();
|
||||
m_stackCounter = 0;
|
||||
|
||||
@@ -45,17 +50,23 @@ private:
|
||||
output().Extend(" push rbp\n");
|
||||
output().Extend(" mov rbp, rsp\n");
|
||||
|
||||
for (auto cur = fn->body().ops().Begin(); cur != nullptr; cur = cur->next)
|
||||
auto fnNode = node<IR::Op>();
|
||||
auto ops = m_ops;
|
||||
m_ops = &fn->body().ops();
|
||||
for (m_current = m_ops->Begin(); m_current != nullptr; node_next())
|
||||
{
|
||||
GenerateStatement(cur->value);
|
||||
GenerateStatement();
|
||||
}
|
||||
m_ops = ops;
|
||||
m_current = fnNode;
|
||||
|
||||
output().Extend(" leave\n");
|
||||
output().Extend(" ret\n");
|
||||
}
|
||||
|
||||
void GenerateCall(IR::CallOp* call)
|
||||
void GenerateCall()
|
||||
{
|
||||
auto call = current<IR::CallOp>();
|
||||
// TODO: support stack spilled arguments
|
||||
assert(call->args().size < 7 && "stack arguments not supported yet");
|
||||
const char *regs[6] = {"edi", "esi", "edx", "ecx","e8", "e9"};
|
||||
@@ -77,16 +88,29 @@ private:
|
||||
output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp);
|
||||
}
|
||||
|
||||
void GenerateAllocate(IR::AllocateOp* alloc)
|
||||
void GenerateAllocate()
|
||||
{
|
||||
// TODO: support other types
|
||||
assert(alloc->Type()->kind == IR::ValueHandle::Type::Kind::Int);
|
||||
auto totalAllocSize = 0;
|
||||
while (current<IR::Op>()->GetType() == IR::OpType::ALLOCATE)
|
||||
{
|
||||
auto alloc = current<IR::AllocateOp>();
|
||||
// TODO: support other types
|
||||
assert(alloc->Type()->kind == IR::ValueHandle::Type::Kind::Int);
|
||||
// TODO: dynamic size + alignment
|
||||
auto allocSize = 4;
|
||||
totalAllocSize += allocSize;
|
||||
m_stackCounter += allocSize;
|
||||
m_slots.insert(std::make_pair(alloc->result()->GetId(), m_stackCounter));
|
||||
|
||||
EnsureSlot(alloc->result());
|
||||
if (seek<IR::Op>() && seek<IR::Op>()->get()->GetType() == IR::OpType::ALLOCATE) node_next();
|
||||
else break;
|
||||
};
|
||||
output().AppendFormat(" sub rsp, %d\n", totalAllocSize);
|
||||
}
|
||||
|
||||
void GenerateStore(IR::StoreOp* store)
|
||||
void GenerateStore()
|
||||
{
|
||||
auto store = current<IR::StoreOp>();
|
||||
auto sp = EnsureSlot(store->dst());
|
||||
|
||||
// TODO: support other types
|
||||
@@ -103,8 +127,9 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateLoad(IR::LoadOp* load)
|
||||
void GenerateLoad()
|
||||
{
|
||||
auto load = current<IR::LoadOp>();
|
||||
auto sp = EnsureSlot(load->Ptr());
|
||||
|
||||
// TODO: support other types
|
||||
@@ -115,8 +140,9 @@ private:
|
||||
output().AppendFormat(" mov dword [rbp-%d], eax\n", sp);
|
||||
}
|
||||
|
||||
void GenerateMath(IR::MathOp* math)
|
||||
void GenerateMath()
|
||||
{
|
||||
auto math = current<IR::MathOp>();
|
||||
StringBuilder sb;
|
||||
|
||||
switch(math->GetType())
|
||||
@@ -157,30 +183,31 @@ private:
|
||||
output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp);
|
||||
}
|
||||
|
||||
void GenerateStatement(IR::Op* op)
|
||||
void GenerateStatement()
|
||||
{
|
||||
switch(op->GetType())
|
||||
{
|
||||
case IR::OpType::EXTERN:
|
||||
return GenerateExtern(reinterpret_cast<IR::ExternOp*>(op));
|
||||
case IR::OpType::FN:
|
||||
return GenerateFunction(reinterpret_cast<IR::FnOp*>(op));
|
||||
case IR::OpType::CALL:
|
||||
return GenerateCall(reinterpret_cast<IR::CallOp*>(op));
|
||||
case IR::OpType::ALLOCATE:
|
||||
return GenerateAllocate(reinterpret_cast<IR::AllocateOp*>(op));
|
||||
case IR::OpType::STORE:
|
||||
return GenerateStore(reinterpret_cast<IR::StoreOp*>(op));
|
||||
case IR::OpType::LOAD:
|
||||
return GenerateLoad(reinterpret_cast<IR::LoadOp*>(op));
|
||||
case IR::OpType::ADD:
|
||||
case IR::OpType::SUB:
|
||||
case IR::OpType::MUL:
|
||||
case IR::OpType::DIV:
|
||||
return GenerateMath(reinterpret_cast<IR::MathOp*>(op));
|
||||
// TODO:
|
||||
default: output().AppendFormat(" ; %d not implemented\n", op->GetType());
|
||||
}
|
||||
auto op = current<IR::Op>();
|
||||
switch(op->GetType())
|
||||
{
|
||||
case IR::OpType::EXTERN:
|
||||
return GenerateExtern();
|
||||
case IR::OpType::FN:
|
||||
return GenerateFunction();
|
||||
case IR::OpType::CALL:
|
||||
return GenerateCall();
|
||||
case IR::OpType::ALLOCATE:
|
||||
return GenerateAllocate();
|
||||
case IR::OpType::STORE:
|
||||
return GenerateStore();
|
||||
case IR::OpType::LOAD:
|
||||
return GenerateLoad();
|
||||
case IR::OpType::ADD:
|
||||
case IR::OpType::SUB:
|
||||
case IR::OpType::MUL:
|
||||
case IR::OpType::DIV:
|
||||
return GenerateMath();
|
||||
// TODO:
|
||||
default: output().AppendFormat(" ; %d not implemented\n", op->GetType());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -202,6 +229,19 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
ListNode<T*>* node() { return reinterpret_cast<ListNode<T*>*>(m_current); }
|
||||
template<typename T>
|
||||
ListNode<T*>* seek() { return m_current && m_current->next ? reinterpret_cast<ListNode<T*>*>(m_current->next) : nullptr; }
|
||||
|
||||
void node_next() { assert(m_current); m_current = m_current->next; }
|
||||
|
||||
template<typename T>
|
||||
T* current() const { return reinterpret_cast<T*>(m_current->value); }
|
||||
|
||||
private:
|
||||
const DoubleLinkedList<IR::Op*>* m_ops;
|
||||
ListNode<IR::Op*>* m_current;
|
||||
std::unordered_map<uint32_t, uint32_t> m_slots;
|
||||
uint32_t m_stackCounter = 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user