Compare commits
4 Commits
16cc06b788
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 952df07ce3 | |||
| b3498135aa | |||
| c506c2159c | |||
| 2a34d0094c |
@ -1,15 +1,18 @@
|
|||||||
extern putchar
|
extern putchar
|
||||||
|
|
||||||
fn main() {
|
fn hello() {
|
||||||
local h = 72
|
local h = 72
|
||||||
local e = 69
|
local e = 69
|
||||||
local l = 76
|
local l = 76
|
||||||
local o = 79
|
local o = 79
|
||||||
local nl = 10
|
|
||||||
putchar(h)
|
putchar(h)
|
||||||
putchar(e)
|
putchar(e)
|
||||||
putchar(l)
|
putchar(l)
|
||||||
putchar(l)
|
putchar(l)
|
||||||
putchar(o)
|
putchar(o)
|
||||||
putchar(nl)
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
hello()
|
||||||
|
putchar(10)
|
||||||
}
|
}
|
||||||
@ -126,8 +126,8 @@ class FnDeclNode : public Node
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// TODO: support parameters
|
// TODO: support parameters
|
||||||
FnDeclNode(const StringView& name, CompoundNode* body)
|
FnDeclNode(const StringView& name, CompoundNode* body, View<StringView> params)
|
||||||
: m_name(name), m_body(body) {}
|
: m_name(name), m_body(body), m_params(params) {}
|
||||||
~FnDeclNode() override {
|
~FnDeclNode() override {
|
||||||
delete m_body;
|
delete m_body;
|
||||||
}
|
}
|
||||||
@ -136,9 +136,11 @@ public:
|
|||||||
public:
|
public:
|
||||||
const StringView& name() const { return m_name; }
|
const StringView& name() const { return m_name; }
|
||||||
const CompoundNode* body() const { return m_body; }
|
const CompoundNode* body() const { return m_body; }
|
||||||
|
const View<StringView>& params() const { return m_params; }
|
||||||
private:
|
private:
|
||||||
StringView m_name;
|
StringView m_name;
|
||||||
CompoundNode* m_body;
|
CompoundNode* m_body;
|
||||||
|
View<StringView> m_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FnCallNode : public Node
|
class FnCallNode : public Node
|
||||||
@ -236,7 +238,13 @@ public:
|
|||||||
m_lexer->NextExpect(TokenType::Id);
|
m_lexer->NextExpect(TokenType::Id);
|
||||||
StringView name = m_lexer->token().string;
|
StringView name = m_lexer->token().string;
|
||||||
m_lexer->NextExpect('(');
|
m_lexer->NextExpect('(');
|
||||||
// TODO: parse parameters
|
Builder<StringView> params;
|
||||||
|
// TODO: support multiple params
|
||||||
|
if (m_lexer->seek_token()->token != ')')
|
||||||
|
{
|
||||||
|
m_lexer->NextExpect(TokenType::Id);
|
||||||
|
params.Push(m_lexer->token().string);
|
||||||
|
}
|
||||||
m_lexer->NextExpect(')');
|
m_lexer->NextExpect(')');
|
||||||
m_lexer->NextExpect('{');
|
m_lexer->NextExpect('{');
|
||||||
auto compound = new CompoundNode();
|
auto compound = new CompoundNode();
|
||||||
@ -245,7 +253,7 @@ public:
|
|||||||
compound->addNode(ParseStatement());
|
compound->addNode(ParseStatement());
|
||||||
}
|
}
|
||||||
m_lexer->NextExpect('}');
|
m_lexer->NextExpect('}');
|
||||||
return new FnDeclNode(name, compound);
|
return new FnDeclNode(name, compound, params.view());
|
||||||
}
|
}
|
||||||
|
|
||||||
FnCallNode* ParseFnCall(const StringView& name)
|
FnCallNode* ParseFnCall(const StringView& name)
|
||||||
@ -253,7 +261,12 @@ public:
|
|||||||
// m_lexer->NextExpect(TokenType::Id);
|
// m_lexer->NextExpect(TokenType::Id);
|
||||||
// char* name = strdup(m_lexer->token().string);
|
// char* name = strdup(m_lexer->token().string);
|
||||||
m_lexer->NextExpect('(');
|
m_lexer->NextExpect('(');
|
||||||
Node* arg = ParseExpression();
|
Node* arg = nullptr;
|
||||||
|
// TODO: support multiple arguments
|
||||||
|
if (m_lexer->seek_token()->token != ')')
|
||||||
|
{
|
||||||
|
arg = ParseExpression();
|
||||||
|
}
|
||||||
m_lexer->NextExpect(')');
|
m_lexer->NextExpect(')');
|
||||||
return new FnCallNode(name, arg);
|
return new FnCallNode(name, arg);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
|
||||||
|
// TODO: store all of values, allocated registers, stack offsets in single allocator
|
||||||
|
// to be able to find out which kind a specific temp register represent
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
@ -49,98 +53,98 @@ private:
|
|||||||
Builder<StackSlot> m_slots;
|
Builder<StackSlot> m_slots;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConstSlot
|
// struct ConstSlot
|
||||||
{
|
// {
|
||||||
long value;
|
// long value;
|
||||||
StringView addr;
|
// StringView addr;
|
||||||
};
|
// };
|
||||||
|
|
||||||
class ConstAllocator : public Allocator<ConstSlot>
|
// class ConstAllocator : public Allocator<ConstSlot>
|
||||||
{
|
// {
|
||||||
public:
|
// public:
|
||||||
ConstAllocator() = default;
|
// ConstAllocator() = default;
|
||||||
~ConstAllocator() override = default;
|
// ~ConstAllocator() override = default;
|
||||||
public:
|
// public:
|
||||||
const ConstSlot& Allocate(const StringView& addr)
|
// const ConstSlot& Allocate(const StringView& addr)
|
||||||
{
|
// {
|
||||||
m_slots.Push(ConstSlot { 0, addr });
|
// m_slots.Push(ConstSlot { 0, addr });
|
||||||
return m_slots.data[m_slots.size - 1];
|
// return m_slots.data[m_slots.size - 1];
|
||||||
}
|
// }
|
||||||
|
|
||||||
const ConstSlot& StoreValue(const StringView& addr, long value)
|
// const ConstSlot& StoreValue(const StringView& addr, long value)
|
||||||
{
|
// {
|
||||||
for (size_t i = 0; i < m_slots.size; ++i)
|
// for (size_t i = 0; i < m_slots.size; ++i)
|
||||||
{
|
// {
|
||||||
if (strcmp(m_slots.data[i].addr.c_str(), addr.c_str()) == 0)
|
// if (strcmp(m_slots.data[i].addr.c_str(), addr.c_str()) == 0)
|
||||||
{
|
// {
|
||||||
m_slots.data[i].value = value;
|
// m_slots.data[i].value = value;
|
||||||
return m_slots.data[i];
|
// return m_slots.data[i];
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
assert(0 && "could not resolve const under specified address");
|
// assert(0 && "could not resolve const under specified address");
|
||||||
}
|
// }
|
||||||
|
|
||||||
const ConstSlot& Resolve(const StringView& addr)
|
// const ConstSlot& Resolve(const StringView& addr)
|
||||||
{
|
// {
|
||||||
for (size_t i = 0; i < m_slots.size; ++i)
|
// for (size_t i = 0; i < m_slots.size; ++i)
|
||||||
{
|
// {
|
||||||
if (strcmp(m_slots.data[i].addr.c_str(), addr.c_str()) == 0)
|
// if (strcmp(m_slots.data[i].addr.c_str(), addr.c_str()) == 0)
|
||||||
{
|
// {
|
||||||
return m_slots.data[i];
|
// return m_slots.data[i];
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
assert(0 && "could not resolve const under specified address");
|
// assert(0 && "could not resolve const under specified address");
|
||||||
}
|
// }
|
||||||
private:
|
// private:
|
||||||
Builder<ConstSlot> m_slots;
|
// Builder<ConstSlot> m_slots;
|
||||||
};
|
// };
|
||||||
|
|
||||||
struct RegisterSlot
|
// struct RegisterSlot
|
||||||
{
|
// {
|
||||||
const StringView& reg;
|
// const StringView& reg;
|
||||||
StringView addr;
|
// StringView addr;
|
||||||
};
|
// };
|
||||||
|
|
||||||
class RegisterAllocator : public Allocator<RegisterSlot>
|
// class RegisterAllocator : public Allocator<RegisterSlot>
|
||||||
{
|
// {
|
||||||
public:
|
// public:
|
||||||
RegisterAllocator()
|
// RegisterAllocator()
|
||||||
{
|
// {
|
||||||
m_regs.Push(std::move(StringView("eax")));
|
// m_regs.Push(std::move(StringView("eax")));
|
||||||
m_regs.Push(std::move(StringView("ecx")));
|
// m_regs.Push(std::move(StringView("ecx")));
|
||||||
}
|
// }
|
||||||
~RegisterAllocator() override = default;
|
// ~RegisterAllocator() override = default;
|
||||||
public:
|
// public:
|
||||||
const RegisterSlot& Allocate(const StringView& addr)
|
// const RegisterSlot& Allocate(const StringView& addr)
|
||||||
{
|
// {
|
||||||
assert(m_slots.size < m_regs.size && "no space available for allocating to register");
|
// assert(m_slots.size < m_regs.size && "no space available for allocating to register");
|
||||||
m_slots.Push(RegisterSlot { m_regs.data[m_slots.size], addr });
|
// m_slots.Push(RegisterSlot { m_regs.data[m_slots.size], addr });
|
||||||
return m_slots.data[m_slots.size - 1];
|
// return m_slots.data[m_slots.size - 1];
|
||||||
}
|
// }
|
||||||
|
|
||||||
const RegisterSlot& Resolve(const StringView& addr)
|
// const RegisterSlot& Resolve(const StringView& addr)
|
||||||
{
|
// {
|
||||||
for (size_t i = 0; i < m_slots.size; ++i)
|
// for (size_t i = 0; i < m_slots.size; ++i)
|
||||||
{
|
// {
|
||||||
if (strcmp(m_slots.data[i].addr.c_str(), addr.c_str()) == 0)
|
// if (strcmp(m_slots.data[i].addr.c_str(), addr.c_str()) == 0)
|
||||||
{
|
// {
|
||||||
return m_slots.data[i];
|
// return m_slots.data[i];
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
assert(0 && "could not resolve const under specified address");
|
// assert(0 && "could not resolve register for specified address");
|
||||||
}
|
// }
|
||||||
|
|
||||||
void Clear()
|
// void Clear()
|
||||||
{
|
// {
|
||||||
m_slots.size = 0;
|
// m_slots.size = 0;
|
||||||
}
|
// }
|
||||||
private:
|
// private:
|
||||||
Builder<RegisterSlot> m_slots;
|
// Builder<RegisterSlot> m_slots;
|
||||||
Builder<StringView> m_regs;
|
// Builder<StringView> m_regs;
|
||||||
};
|
// };
|
||||||
|
|
||||||
class CodeGenerator
|
class CodeGenerator
|
||||||
{
|
{
|
||||||
@ -160,7 +164,15 @@ private:
|
|||||||
int stackSize = 0;
|
int stackSize = 0;
|
||||||
for (auto &op : ops)
|
for (auto &op : ops)
|
||||||
{
|
{
|
||||||
if (op->GetType() == IR::OpType::STORE) stackSize += 4;
|
switch (op->GetType())
|
||||||
|
{
|
||||||
|
case IR::OpType::STORE:
|
||||||
|
case IR::OpType::LOAD:
|
||||||
|
case IR::OpType::LOAD_CONST:
|
||||||
|
case IR::OpType::ADD:
|
||||||
|
case IR::OpType::CALL:
|
||||||
|
stackSize += 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stackSize;
|
return stackSize;
|
||||||
}
|
}
|
||||||
@ -190,12 +202,19 @@ private:
|
|||||||
printf("%s:\n", name.c_str());
|
printf("%s:\n", name.c_str());
|
||||||
printf("push rbp\n");
|
printf("push rbp\n");
|
||||||
printf("mov rbp, rsp\n");
|
printf("mov rbp, rsp\n");
|
||||||
|
m_stack = new StackAllocator();
|
||||||
int stackSize = GetStackSize(fn->ops());
|
int stackSize = GetStackSize(fn->ops());
|
||||||
printf("sub rsp, %d\n", stackSize);
|
printf("sub rsp, %d\n", stackSize);
|
||||||
|
if (fn->params().size > 0)
|
||||||
|
{
|
||||||
|
auto param_slot = m_stack->Allocate(fn->params().data[0]);
|
||||||
|
printf("mov [rbp-%d], edi\n", param_slot.offset);
|
||||||
|
}
|
||||||
for(auto &fOp : fn->ops())
|
for(auto &fOp : fn->ops())
|
||||||
{
|
{
|
||||||
GenerateOp(fOp);
|
GenerateOp(fOp);
|
||||||
}
|
}
|
||||||
|
m_stack = nullptr;
|
||||||
printf("leave\nret\n");
|
printf("leave\nret\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -205,46 +224,50 @@ private:
|
|||||||
// TODO: support several arguments
|
// TODO: support several arguments
|
||||||
if (call->args().size == 1)
|
if (call->args().size == 1)
|
||||||
{
|
{
|
||||||
auto reg_slot = m_registers.Resolve(GetTempAddr(call->args().data[0]));
|
auto slot = m_stack->Resolve(GetTempAddr(call->args().data[0]));
|
||||||
printf("mov edi, %s\n", reg_slot.reg.c_str());
|
printf("mov edi, [rbp-%d]\n", slot.offset);
|
||||||
}
|
}
|
||||||
printf("call %s\n", call->callee().c_str());
|
printf("call %s\n", call->callee().c_str());
|
||||||
m_registers.Clear();
|
auto result_slot = m_stack->Allocate(GetTempAddr(call->result()));
|
||||||
|
printf("mov dword [rbp-%d], eax\n", result_slot.offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IR::OpType::LOAD_CONST:
|
case IR::OpType::LOAD_CONST:
|
||||||
{
|
{
|
||||||
auto lc = reinterpret_cast<const IR::LoadConstOp *>(op);
|
auto lc = reinterpret_cast<const IR::LoadConstOp *>(op);
|
||||||
auto addr = GetTempAddr(lc->result());
|
auto addr = GetTempAddr(lc->result());
|
||||||
m_consts.Allocate(addr);
|
auto slot = m_stack->Allocate(addr);
|
||||||
m_consts.StoreValue(addr, lc->value());
|
printf("mov dword [rbp-%d], %ld\n", slot.offset, lc->value());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IR::OpType::STORE:
|
case IR::OpType::STORE:
|
||||||
{
|
{
|
||||||
auto s = reinterpret_cast<const IR::StoreOp *>(op);
|
auto s = reinterpret_cast<const IR::StoreOp *>(op);
|
||||||
printf("; DEBUG: resolving stack slot at %s\n", s->addr().c_str());
|
printf("; DEBUG: resolving stack slot at %s\n", s->addr().c_str());
|
||||||
auto slot = m_stack.Allocate(s->addr());
|
auto slot = m_stack->Allocate(s->addr());
|
||||||
auto value = m_consts.Resolve(GetTempAddr(s->src()));
|
auto value_slot = m_stack->Resolve(GetTempAddr(s->src()));
|
||||||
printf("mov dword [rbp-%d], %ld\n", slot.offset, value.value);
|
printf("mov eax, [rbp-%d]\n", value_slot.offset);
|
||||||
|
printf("mov dword [rbp-%d], eax\n", slot.offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IR::OpType::LOAD:
|
case IR::OpType::LOAD:
|
||||||
{
|
{
|
||||||
auto l = reinterpret_cast<const IR::LoadOp *>(op);
|
auto l = reinterpret_cast<const IR::LoadOp *>(op);
|
||||||
auto reg_slot = m_registers.Allocate(GetTempAddr(l->result()));
|
auto value_slot = m_stack->Allocate(GetTempAddr(l->result()));
|
||||||
auto stack_slot = m_stack.Resolve(l->addr());
|
auto variable_slot = m_stack->Resolve(l->addr());
|
||||||
printf("mov %s, [rbp-%d]\n", reg_slot.reg.c_str(), stack_slot.offset);
|
printf("mov eax, [rbp-%d]\n", variable_slot.offset);
|
||||||
|
printf("mov dword [rbp-%d], eax\n", value_slot.offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IR::OpType::ADD:
|
case IR::OpType::ADD:
|
||||||
{
|
{
|
||||||
auto expr = reinterpret_cast<const IR::AddOp *>(op);
|
auto expr = reinterpret_cast<const IR::AddOp *>(op);
|
||||||
auto lhs_slot = m_registers.Resolve(GetTempAddr(expr->lhs()));
|
auto lhs_slot = m_stack->Resolve(GetTempAddr(expr->lhs()));
|
||||||
auto rhs_slot = m_registers.Resolve(GetTempAddr(expr->rhs()));
|
printf("mov eax, [rbp-%d]\n", lhs_slot.offset);
|
||||||
printf("add %s, %s\n", lhs_slot.reg.c_str(), rhs_slot.reg.c_str());
|
auto rhs_slot = m_stack->Resolve(GetTempAddr(expr->rhs()));
|
||||||
m_registers.Clear();
|
printf("add eax, [rbp-%d]\n", rhs_slot.offset);
|
||||||
m_registers.Allocate(GetTempAddr(expr->result()));
|
auto result_slot = m_stack->Allocate(GetTempAddr(expr->result()));
|
||||||
|
printf("mov dword [rbp-%d], eax\n", result_slot.offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: printf("; NOT HANDLED\n; %s\n", op->Format(0).c_str()); break;
|
default: printf("; NOT HANDLED\n; %s\n", op->Format(0).c_str()); break;
|
||||||
@ -264,7 +287,5 @@ public:
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// TODO: handle sub-blocks
|
// TODO: handle sub-blocks
|
||||||
StackAllocator m_stack;
|
StackAllocator* m_stack = nullptr;
|
||||||
ConstAllocator m_consts;
|
|
||||||
RegisterAllocator m_registers;
|
|
||||||
};
|
};
|
||||||
@ -74,7 +74,7 @@ private:
|
|||||||
class FnOp : public Op
|
class FnOp : public Op
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FnOp(StringView name, const CompoundNode* body);
|
FnOp(StringView name, const CompoundNode* body, const View<StringView>& params);
|
||||||
~FnOp() {}
|
~FnOp() {}
|
||||||
|
|
||||||
OP_TYPE(FN)
|
OP_TYPE(FN)
|
||||||
@ -93,9 +93,11 @@ public:
|
|||||||
public:
|
public:
|
||||||
const StringView& name() const { return m_name; }
|
const StringView& name() const { return m_name; }
|
||||||
const OpView& ops() const { return m_ops; }
|
const OpView& ops() const { return m_ops; }
|
||||||
|
const View<StringView>& params() const { return m_params; }
|
||||||
private:
|
private:
|
||||||
StringView m_name;
|
StringView m_name;
|
||||||
OpView m_ops;
|
OpView m_ops;
|
||||||
|
View<StringView> m_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LoadConstOp : public Op, public Valued
|
class LoadConstOp : public Op, public Valued
|
||||||
@ -243,11 +245,14 @@ public:
|
|||||||
Reg ParseFnCall(const FnCallNode* fn)
|
Reg ParseFnCall(const FnCallNode* fn)
|
||||||
{
|
{
|
||||||
// TODO: support multiple args
|
// TODO: support multiple args
|
||||||
auto arg = ParseExpression(fn->arg());
|
|
||||||
auto argRegs = RegBuilder();
|
auto argRegs = RegBuilder();
|
||||||
|
if (fn->arg() != nullptr)
|
||||||
|
{
|
||||||
|
auto arg = ParseExpression(fn->arg());
|
||||||
argRegs.Push(arg);
|
argRegs.Push(arg);
|
||||||
|
}
|
||||||
auto dst = AllocateRegister();
|
auto dst = AllocateRegister();
|
||||||
m_ops.Push(new CallOp(dst, fn->name(), RegView(argRegs.data, argRegs.size)));
|
m_ops.Push(new CallOp(dst, fn->name(), argRegs.view()));
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +324,7 @@ public:
|
|||||||
// Functions
|
// Functions
|
||||||
for (auto &fn : program->funcs())
|
for (auto &fn : program->funcs())
|
||||||
{
|
{
|
||||||
m_ops.Push(new FnOp(fn->name(), fn->body()));
|
m_ops.Push(new FnOp(fn->name(), fn->body(), fn->params()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpView(m_ops.data, m_ops.size);
|
return OpView(m_ops.data, m_ops.size);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "ir.hpp"
|
#include "ir.hpp"
|
||||||
|
|
||||||
IR::FnOp::FnOp(StringView name, const CompoundNode* body)
|
IR::FnOp::FnOp(StringView name, const CompoundNode* body, const View<StringView>& params)
|
||||||
: m_name(name)
|
: m_name(name), m_params(params)
|
||||||
{
|
{
|
||||||
IRBuilder ir(body); // Now IRBuilder is complete → OK
|
IRBuilder ir(body); // Now IRBuilder is complete → OK
|
||||||
ir.ParseBlock(body);
|
ir.ParseBlock(body);
|
||||||
|
|||||||
@ -49,11 +49,12 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
auto ops = irBuilder.Build();
|
auto ops = irBuilder.Build();
|
||||||
|
|
||||||
// printf("\n");
|
// printf("; ------ IR ------\n");
|
||||||
// for (size_t i = 0; i < ops.size; ++i)
|
// for (size_t i = 0; i < ops.size; ++i)
|
||||||
// {
|
// {
|
||||||
// printf("%s\n", ops.data[i]->Format(0).c_str());
|
// printf("; %s\n", ops.data[i]->Format(0).c_str());
|
||||||
// }
|
// }
|
||||||
|
// printf("; ------ IR ------\n");
|
||||||
|
|
||||||
StackFasmX86_64Generator gen;
|
StackFasmX86_64Generator gen;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user