From 806e20d9b1d49de683a66e88d088cc344937ad0d Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 5 Jan 2026 19:36:48 +0100 Subject: [PATCH] feat: fasm stack codegen beta --- include/codegen/targets/fasm_x86_64_linux.hpp | 137 ++++++++++++++++++ include/ir/ir.hpp | 2 +- include/ir/ops.hpp | 6 + src/main.cpp | 6 + 4 files changed, 150 insertions(+), 1 deletion(-) diff --git a/include/codegen/targets/fasm_x86_64_linux.hpp b/include/codegen/targets/fasm_x86_64_linux.hpp index 7df7402..e957d92 100644 --- a/include/codegen/targets/fasm_x86_64_linux.hpp +++ b/include/codegen/targets/fasm_x86_64_linux.hpp @@ -2,7 +2,10 @@ #include "codegen/codegen.hpp" #include "ir/op.hpp" #include "ir/ops.hpp" +#include "ir/value.hpp" #include "prelude/linkedlist.hpp" +#include "prelude/string.hpp" +#include class FasmX86_64Generator : public CodeGenerator { @@ -34,6 +37,9 @@ private: void GenerateFunction(IR::FnOp* fn) { + m_slots.clear(); + m_stackCounter = 0; + output().AppendFormat("public %s\n", fn->name().c_str()); output().AppendFormat("%s:\n", fn->name().c_str()); output().Extend(" push rbp\n"); @@ -50,7 +56,105 @@ private: void GenerateCall(IR::CallOp* call) { + // 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"}; + for (size_t i = 0; i < call->args().size; ++i) + { + auto arg = call->args().data[i]; + if (arg->HasId()) { + auto sp = EnsureSlot(arg); + // TODO: + auto size = "dword"; + output().AppendFormat(" mov %s, %s [rbp-%d]\n", regs[i], size, sp); + } else { + output().AppendFormat(" mov %s, %d\n", regs[i], reinterpret_cast(arg)->GetValue()); + } + } output().AppendFormat(" call %s\n", call->callee().c_str()); + auto sp = EnsureSlot(call->result()); + auto size = "dword"; + output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp); + } + + void GenerateAllocate(IR::AllocateOp* alloc) + { + // TODO: support other types + assert(alloc->Type()->kind == IR::ValueHandle::Type::Kind::Int); + + EnsureSlot(alloc->result()); + } + + void GenerateStore(IR::StoreOp* store) + { + auto sp = EnsureSlot(store->dst()); + + // TODO: support other types + assert(store->src()->GetType()->kind == IR::ValueHandle::Type::Kind::Int); + if (!store->src()->HasId()) { + auto value = reinterpret_cast(store->src()); + auto size = "dword"; + output().AppendFormat(" mov %s [rbp-%d], %d\n", size, sp, value->GetValue()); + } else { + auto ssp = EnsureSlot(store->src()); + auto size = "dword"; + output().AppendFormat(" mov eax, %s [rbp-%d]\n", size, ssp); + output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp); + } + } + + void GenerateLoad(IR::LoadOp* load) + { + auto sp = EnsureSlot(load->Ptr()); + + // TODO: support other types + auto size = "dword"; + output().AppendFormat(" mov eax, %s [rbp-%d]\n", size, sp); + + sp = EnsureSlot(load->result()); + output().AppendFormat(" mov dword [rbp-%d], eax\n", sp); + } + + void GenerateMath(IR::MathOp* math) + { + StringBuilder sb; + + switch(math->GetType()) + { + case IR::OpType::ADD: + sb << "add"; + break; + case IR::OpType::SUB: + sb << "sub"; + break; + case IR::OpType::MUL: + sb << "imul"; + break; + case IR::OpType::DIV: + sb << "div"; + break; + default: assert(false && "unreachable or not implemented"); + } + + auto op = sb.view(); + + // TODO: + auto size = "dword"; + if (!math->lhs()->HasId()) { + output().AppendFormat(" mov eax, %d\n", reinterpret_cast(math->lhs())->GetValue()); + } else { + auto lsp = EnsureSlot(math->lhs()); + output().AppendFormat(" mov eax, %s [rbp-%d]\n", size, lsp); + } + if (!math->rhs()->HasId()) { + output().AppendFormat(" %s eax, %d\n", op.c_str(), reinterpret_cast(math->rhs())->GetValue()); + } else { + auto lsp = EnsureSlot(math->rhs()); + output().AppendFormat(" %s eax, %s [rbp-%d]\n", op.c_str(), size, lsp); + } + + auto sp = EnsureSlot(math->result()); + output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp); } void GenerateStatement(IR::Op* op) @@ -63,8 +167,41 @@ private: return GenerateFunction(reinterpret_cast(op)); case IR::OpType::CALL: return GenerateCall(reinterpret_cast(op)); + case IR::OpType::ALLOCATE: + return GenerateAllocate(reinterpret_cast(op)); + case IR::OpType::STORE: + return GenerateStore(reinterpret_cast(op)); + case IR::OpType::LOAD: + return GenerateLoad(reinterpret_cast(op)); + case IR::OpType::ADD: + case IR::OpType::SUB: + case IR::OpType::MUL: + case IR::OpType::DIV: + return GenerateMath(reinterpret_cast(op)); // TODO: default: output().AppendFormat(" ; %d not implemented\n", op->GetType()); } } + +private: + uint32_t EnsureSlot(const IR::ValueHandle* value) + { + assert(value->HasId()); + auto stackPointer = m_slots.find(value->GetId()); + if (stackPointer != m_slots.end()) + { + return stackPointer->second; + } + + // TODO: dynamic size based on type + auto allocSize = 4; + output().AppendFormat(" sub rsp, %d\n", allocSize); + m_stackCounter += allocSize; + m_slots.insert(std::make_pair(value->GetId(), m_stackCounter)); + return m_stackCounter; + } + +private: + std::unordered_map m_slots; + uint32_t m_stackCounter = 0; }; diff --git a/include/ir/ir.hpp b/include/ir/ir.hpp index d6dab8a..249386c 100644 --- a/include/ir/ir.hpp +++ b/include/ir/ir.hpp @@ -56,7 +56,7 @@ namespace IR argRegs.Push(arg); } // TODO: gather return type of the function - auto dst = AllocateNamed(new ValueHandle::Type {ValueHandle::Type::Kind::Void}); + auto dst = AllocateNamed(new ValueHandle::Type {ValueHandle::Type::Kind::Int}); m_ops->Push(new CallOp(dst, fn->name(), argRegs.view())); return dst; } diff --git a/include/ir/ops.hpp b/include/ir/ops.hpp index fab2e72..5dcd498 100644 --- a/include/ir/ops.hpp +++ b/include/ir/ops.hpp @@ -82,6 +82,9 @@ namespace IR return sb.view(); } + public: + const ValueHandle::Type *Type() const { return m_typ; } + private: ValueHandle::Type *m_typ; }; @@ -103,6 +106,9 @@ namespace IR return sb.view(); } + public: + const Pointer* Ptr() const { return m_ptr; } + private: Pointer* m_ptr; }; diff --git a/src/main.cpp b/src/main.cpp index dfcd7ae..2745816 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -73,6 +73,12 @@ int main(int argc, char **argv) } } + for (size_t i = 0; i < ops.size; ++i) + { + auto op = ops.data[i]; + printf("%s\n", op->Format(0).c_str()); + } + FasmX86_64Generator gen; gen.Generate(&ops);