From c314ca4cb741eddfa5a898341c372a24203a69de Mon Sep 17 00:00:00 2001 From: Sofia Date: Thu, 2 Apr 2026 17:20:07 +0300 Subject: [PATCH] Compile test.c using LLVM --- CMakeLists.txt | 2 +- src/ast.h | 24 +++++++++++++++++--- src/codegen.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ src/codegen.h | 17 +++++++++++++++ src/main.cpp | 40 +++++++++++++++++++++++++++++++--- 5 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 src/codegen.cpp create mode 100644 src/codegen.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 340b6b0..a3b1a08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) add_definitions(${LLVM_DEFINITIONS_LIST}) # Executable -add_executable(${PROJECT_NAME} src/main.cpp src/tokens.cpp src/parsing.cpp src/ast.cpp) +add_executable(${PROJECT_NAME} src/main.cpp src/tokens.cpp src/parsing.cpp src/ast.cpp src/codegen.cpp) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) # Find the libraries that correspond to the LLVM components diff --git a/src/ast.h b/src/ast.h index 79ec60e..1431c18 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1,6 +1,8 @@ #ifndef AST_H #define AST_H +#include "codegen.h" + #include #include #include @@ -11,12 +13,21 @@ namespace AST { virtual std::string formatted() = 0; }; - class Expression : public Node {}; + class Expression : public Node { + public: + virtual llvm::Value* codegen(codegen::Builder& builder) = 0; + }; + class Type { public: virtual std::string formatted() = 0; + virtual llvm::Type* codegen(codegen::Builder& builder) = 0; + }; + + class Statement : public Node { + public: + virtual void codegen(codegen::Builder& builder) = 0; }; - class Statement : public Node {}; class IntLiteralExpression : public Expression { private: @@ -24,6 +35,7 @@ namespace AST { public: IntLiteralExpression(int value) : m_value{ value } {} virtual std::string formatted() override; + virtual llvm::Value* codegen(codegen::Builder& builder) override; }; @@ -33,9 +45,13 @@ namespace AST { public: ReturnStatement(std::unique_ptr expr) : m_expr{ std::move(expr) } {} virtual std::string formatted() override; + virtual void codegen(codegen::Builder& builder) override; }; - class TopLevelStatement : public Node {}; + class TopLevelStatement : public Node { + public: + virtual void codegen(codegen::Builder& builder) = 0; + }; class Function : public TopLevelStatement { private: @@ -55,6 +71,7 @@ namespace AST { , m_statements{ std::move(statements) } { } virtual std::string formatted() override; + virtual void codegen(codegen::Builder& builder) override; }; enum class FundamentalTypeKind { @@ -67,6 +84,7 @@ namespace AST { public: FundamentalType(FundamentalTypeKind kind) : m_ty{ kind } {} virtual std::string formatted() override; + virtual llvm::Type* codegen(codegen::Builder& builder) override; }; } diff --git a/src/codegen.cpp b/src/codegen.cpp new file mode 100644 index 0000000..f6a9bd9 --- /dev/null +++ b/src/codegen.cpp @@ -0,0 +1,58 @@ +#include "codegen.h" +#include "ast.h" + +#include +#include +#include +#include + +namespace AST { + llvm::Value* IntLiteralExpression::codegen(codegen::Builder& builder) { + auto ty = builder.builder->getInt32Ty(); + return llvm::ConstantInt::get(ty, this->m_value); + } + + void ReturnStatement::codegen(codegen::Builder& builder) { + if (!builder.block) + return; + + builder.builder->SetInsertPoint(builder.block.get()); + + auto value = this->m_expr->codegen(builder); + builder.builder->CreateRet(value); + } + + void Function::codegen(codegen::Builder& builder) { + auto ret_ty = this->m_return_ty->codegen(builder); + std::vector params{}; + + + auto fn_ty = llvm::FunctionType::get(ret_ty, params, false); + auto function = llvm::Function::Create( + fn_ty, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + this->m_name, + builder.mod.get() + ); + auto BB = std::unique_ptr{ llvm::BasicBlock::Create(*builder.context, "entry", function, nullptr) }; + builder.block = std::move(BB); + + for (auto& statement : this->m_statements) { + statement->codegen(builder); + } + + llvm::verifyFunction(*function); + + // unique_ptr is not really supposed to free the block + builder.block.release(); + } + + llvm::Type* FundamentalType::codegen(codegen::Builder& builder) { + switch (this->m_ty) { + case FundamentalTypeKind::Int: + return builder.builder->getInt32Ty(); + default: + return builder.builder->getVoidTy(); + } + } +} \ No newline at end of file diff --git a/src/codegen.h b/src/codegen.h new file mode 100644 index 0000000..91dc884 --- /dev/null +++ b/src/codegen.h @@ -0,0 +1,17 @@ +#ifndef CODEGEN_H +#define CODEGEN_H + +#include +#include +#include + +namespace codegen { + struct Builder { + std::unique_ptr context; + std::unique_ptr mod; + std::unique_ptr> builder; + std::unique_ptr block; + }; +} + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 79615ec..751b8b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,11 +61,45 @@ int main() { } stream.expect(token::Type::Eof); - for (int i = 0; i < statements.size(); i++) { - if (statements[i]) - std::cout << statements[i]->formatted() << std::endl; + + auto LLVMContext = std::make_unique(); + auto LLVMModule = std::make_unique("test.c", *LLVMContext); + auto LLVMBuilder = std::make_unique>(*LLVMContext); + + codegen::Builder builder{ + std::move(LLVMContext), + std::move(LLVMModule), + std::move(LLVMBuilder), + {} + }; + + for (auto& tls : statements) { + std::cout << tls->formatted() << std::endl; + tls->codegen(builder); } + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllAsmPrinters(); + + auto TargetTriple = llvm::sys::getDefaultTargetTriple(); + std::string Error; + auto Target = llvm::TargetRegistry::lookupTarget(TargetTriple, Error); + + llvm::TargetOptions opt; + auto TargetMachine = Target->createTargetMachine(TargetTriple, "generic", "", opt, llvm::Reloc::PIC_); + builder.mod->setDataLayout(TargetMachine->createDataLayout()); + + std::string ir_output; + llvm::raw_string_ostream dest{ ir_output }; + + builder.mod->print(dest, nullptr); + dest.flush(); + + std::cout << ir_output << std::endl; + // LLVM Hello World // llvm_hello_world();