diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c5d98fa --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug", + "program": "${workspaceFolder}/build/llvm_c_compiler", + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/src/codegen.cpp b/src/codegen.cpp index f2b9eb6..4ce0518 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -33,9 +33,10 @@ namespace AST { return value->second; } else { + auto loaded = value->second.ty->load(builder, value->second.value); return codegen::StackValue{ - builder.builder->CreateLoad(value->second.ty->codegen(builder), value->second.value), - value->second.ty + loaded.first, + loaded.second }; } } @@ -82,9 +83,14 @@ namespace AST { for (auto& arg : this->m_args) { args.push_back(arg->codegen(builder, scope).value); } - auto function = this->m_fn_expr->codegen(builder, scope); + auto with_lvalue = scope.with_lvalue(); + auto function = this->m_fn_expr->codegen(builder, with_lvalue); - builder.builder->CreateCall(dyn_cast(function.ty->codegen(builder)), function.value); + auto value = builder.builder->CreateCall(llvm::dyn_cast(function.ty->codegen(builder)), function.value, args, "call"); + return codegen::StackValue{ + value, + *function.ty->return_type(), + }; } void ReturnStatement::codegen(codegen::Builder& builder, codegen::Scope& scope) { @@ -158,33 +164,41 @@ namespace AST { void Function::codegen(codegen::Builder& builder, codegen::Scope& scope) { - codegen::Scope inner_scope{ scope }; auto ret_ty = this->m_return_ty->codegen(builder); - std::vector params{}; + + std::shared_ptr ret_ty_ptr{ std::move(this->m_return_ty) }; + std::vector> param_ty_ptrs{}; for (auto& param : this->m_params) { - params.push_back(param.second->codegen(builder)); + param_ty_ptrs.push_back(std::move(param.second)); } + auto fn_ty_ptr = std::shared_ptr{ new types::FunctionType{ ret_ty_ptr, param_ty_ptrs } }; - auto fn_ty = llvm::FunctionType::get(ret_ty, params, false); + auto fn_ty = fn_ty_ptr->codegen(builder); auto function = llvm::Function::Create( - fn_ty, + llvm::dyn_cast(fn_ty), llvm::GlobalValue::LinkageTypes::ExternalLinkage, this->m_name, builder.mod.get() ); + + scope.values[this->m_name] = codegen::StackValue{ function, fn_ty_ptr }; + auto BB = llvm::BasicBlock::Create(*builder.context, "entry", function, nullptr); builder.block = BB; + codegen::Scope inner_scope{ scope }; + int counter = 0; for (auto& param : this->m_params) { + auto param_ty_ptr = param_ty_ptrs[counter]; auto arg = function->getArg(counter++); arg->setName(param.first); inner_scope.values[param.first] = codegen::StackValue{ arg, - std::move(param.second), + param_ty_ptr, }; } @@ -209,4 +223,20 @@ namespace types { return builder.builder->getVoidTy(); } } + + llvm::Type* FunctionType::codegen(codegen::Builder& builder) { + std::vector params{}; + + for (auto& param : this->m_param_tys) { + params.push_back(param->codegen(builder)); + } + + auto ret_ty = this->m_ret_ty->codegen(builder); + + return llvm::FunctionType::get(ret_ty, params, false); + } + + llvm::Type* PointerType::codegen(codegen::Builder& builder) { + return llvm::PointerType::get(this->m_inner->codegen(builder), 0); + } } \ No newline at end of file diff --git a/src/types.cpp b/src/types.cpp index 2e3f9d1..793f3f7 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -46,10 +46,19 @@ namespace types { } } + std::optional> FundamentalType::return_type() { + return {}; + } + + std::pair> FundamentalType::load(codegen::Builder& builder, llvm::Value* ptr) { + auto self = std::make_shared(*this); + return std::pair(ptr, self); + } + llvm::Value* FundamentalType::add(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { switch (this->m_ty) { case FundamentalTypeKind::Int: - return builder.builder->CreateAdd(lhs, rhs); + return builder.builder->CreateAdd(lhs, rhs, "add"); default: throw std::runtime_error("Invalid type for add"); } @@ -58,7 +67,7 @@ namespace types { llvm::Value* FundamentalType::sub(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { switch (this->m_ty) { case FundamentalTypeKind::Int: - return builder.builder->CreateSub(lhs, rhs); + return builder.builder->CreateSub(lhs, rhs, "sub"); default: throw std::runtime_error("Invalid type"); } @@ -67,7 +76,7 @@ namespace types { llvm::Value* FundamentalType::lt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { switch (this->m_ty) { case FundamentalTypeKind::Int: - return builder.builder->CreateCmp(llvm::CmpInst::Predicate::ICMP_SLT, lhs, rhs); + return builder.builder->CreateCmp(llvm::CmpInst::Predicate::ICMP_SLT, lhs, rhs, "cmp"); default: throw std::runtime_error("Invalid type"); } @@ -81,4 +90,77 @@ namespace types { throw std::runtime_error("Invalid type"); } } + + std::string FunctionType::formatted() { + std::stringstream out{ "" }; + out << "("; + + int counter = 0; + for (auto& param : this->m_param_tys) { + if (counter++ > 0) + out << ", "; + out << param->formatted(); + } + + out << ") -> " << this->m_ret_ty->formatted(); + return out.str(); + } + + std::optional> FunctionType::return_type() { + return this->m_ret_ty; + } + + std::pair> FunctionType::load(codegen::Builder& builder, llvm::Value* ptr) { + auto self = std::make_shared(*this); + return std::pair(ptr, self); + } + + llvm::Value* FunctionType::add(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + throw std::runtime_error("Invalid operation for functions"); + } + + llvm::Value* FunctionType::sub(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + throw std::runtime_error("Invalid operation for functions"); + } + + llvm::Value* FunctionType::lt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + throw std::runtime_error("Invalid operation for functions"); + } + + llvm::Value* FunctionType::gt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + throw std::runtime_error("Invalid operation for functions"); + } + + std::string PointerType::formatted() { + std::stringstream out{ "" }; + out << this->m_inner << "*"; + return out.str(); + } + + std::optional> PointerType::return_type() { + return {}; + } + + std::pair> PointerType::load(codegen::Builder& builder, llvm::Value* ptr) { + return std::pair( + builder.builder->CreateLoad(this->m_inner->codegen(builder), ptr), + this->m_inner + ); + } + + llvm::Value* PointerType::add(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + throw std::runtime_error("Invalid operation for pointers"); + } + + llvm::Value* PointerType::sub(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + throw std::runtime_error("Invalid operation for pointers"); + } + + llvm::Value* PointerType::lt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + throw std::runtime_error("Invalid operation for pointers"); + } + + llvm::Value* PointerType::gt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + throw std::runtime_error("Invalid operation for pointers"); + } } \ No newline at end of file diff --git a/src/types.h b/src/types.h index f10a01d..c8fe8ab 100644 --- a/src/types.h +++ b/src/types.h @@ -28,6 +28,8 @@ namespace types { virtual ~Type() = default; virtual std::string formatted() = 0; virtual llvm::Type* codegen(codegen::Builder& builder) = 0; + virtual std::pair> load(codegen::Builder& builder, llvm::Value* ptr) = 0; + virtual std::optional> return_type() = 0; virtual llvm::Value* add(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) = 0; virtual llvm::Value* sub(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) = 0; virtual llvm::Value* lt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) = 0; @@ -42,6 +44,48 @@ namespace types { virtual ~FundamentalType() override = default; virtual std::string formatted() override; virtual llvm::Type* codegen(codegen::Builder& builder) override; + virtual std::pair> load(codegen::Builder& builder, llvm::Value* ptr) override; + virtual std::optional> return_type() override; + virtual llvm::Value* add(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; + virtual llvm::Value* sub(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; + virtual llvm::Value* lt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; + virtual llvm::Value* gt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; + }; + + + class FunctionType : public Type { + private: + std::shared_ptr m_ret_ty; + std::vector> m_param_tys; + public: + FunctionType(std::shared_ptr ret_ty, std::vector> param_tys) + : m_ret_ty{ std::move(ret_ty) }, m_param_tys{ std::move(param_tys) } { + } + virtual ~FunctionType() override = default; + virtual std::string formatted() override; + virtual llvm::Type* codegen(codegen::Builder& builder) override; + virtual std::pair> load(codegen::Builder& builder, llvm::Value* ptr) override; + virtual std::optional> return_type() override; + virtual llvm::Value* add(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; + virtual llvm::Value* sub(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; + virtual llvm::Value* lt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; + virtual llvm::Value* gt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; + }; + + + + class PointerType : public Type { + private: + std::shared_ptr m_inner; + public: + PointerType(std::shared_ptr inner) + : m_inner{ std::move(inner) } { + } + virtual ~PointerType() override = default; + virtual std::string formatted() override; + virtual llvm::Type* codegen(codegen::Builder& builder) override; + virtual std::pair> load(codegen::Builder& builder, llvm::Value* ptr) override; + virtual std::optional> return_type() override; virtual llvm::Value* add(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; virtual llvm::Value* sub(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; virtual llvm::Value* lt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) override; diff --git a/test.c b/test.c index df13984..7d5e563 100644 --- a/test.c +++ b/test.c @@ -1,11 +1,9 @@ int fibonacci(int n) { if (n < 2) - return 0; - return fibonacci(n - 1); + return 1; + return fibonacci(n - 1) + fibonacci(n - 2); } int main() { - int a = 5; - a = 15 + 20; - return a - 30; + return fibonacci(10); } \ No newline at end of file