Compile test.c using LLVM

This commit is contained in:
Sofia 2026-04-02 17:20:07 +03:00
parent 74a3914fdf
commit c314ca4cb7
5 changed files with 134 additions and 7 deletions

View File

@ -15,7 +15,7 @@ separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST}) add_definitions(${LLVM_DEFINITIONS_LIST})
# Executable # 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) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
# Find the libraries that correspond to the LLVM components # Find the libraries that correspond to the LLVM components

View File

@ -1,6 +1,8 @@
#ifndef AST_H #ifndef AST_H
#define AST_H #define AST_H
#include "codegen.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <memory> #include <memory>
@ -11,12 +13,21 @@ namespace AST {
virtual std::string formatted() = 0; virtual std::string formatted() = 0;
}; };
class Expression : public Node {}; class Expression : public Node {
public:
virtual llvm::Value* codegen(codegen::Builder& builder) = 0;
};
class Type { class Type {
public: public:
virtual std::string formatted() = 0; 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 { class IntLiteralExpression : public Expression {
private: private:
@ -24,6 +35,7 @@ namespace AST {
public: public:
IntLiteralExpression(int value) : m_value{ value } {} IntLiteralExpression(int value) : m_value{ value } {}
virtual std::string formatted() override; virtual std::string formatted() override;
virtual llvm::Value* codegen(codegen::Builder& builder) override;
}; };
@ -33,9 +45,13 @@ namespace AST {
public: public:
ReturnStatement(std::unique_ptr<Expression> expr) : m_expr{ std::move(expr) } {} ReturnStatement(std::unique_ptr<Expression> expr) : m_expr{ std::move(expr) } {}
virtual std::string formatted() override; 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 { class Function : public TopLevelStatement {
private: private:
@ -55,6 +71,7 @@ namespace AST {
, m_statements{ std::move(statements) } { , m_statements{ std::move(statements) } {
} }
virtual std::string formatted() override; virtual std::string formatted() override;
virtual void codegen(codegen::Builder& builder) override;
}; };
enum class FundamentalTypeKind { enum class FundamentalTypeKind {
@ -67,6 +84,7 @@ namespace AST {
public: public:
FundamentalType(FundamentalTypeKind kind) : m_ty{ kind } {} FundamentalType(FundamentalTypeKind kind) : m_ty{ kind } {}
virtual std::string formatted() override; virtual std::string formatted() override;
virtual llvm::Type* codegen(codegen::Builder& builder) override;
}; };
} }

58
src/codegen.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "codegen.h"
#include "ast.h"
#include <llvm/IR/Module.h>
#include <llvm/IR/Verifier.h>
#include <memory>
#include <iostream>
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<llvm::Type*> 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>{ 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();
}
}
}

17
src/codegen.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef CODEGEN_H
#define CODEGEN_H
#include <memory>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/IRBuilder.h>
namespace codegen {
struct Builder {
std::unique_ptr<llvm::LLVMContext> context;
std::unique_ptr<llvm::Module> mod;
std::unique_ptr<llvm::IRBuilder<>> builder;
std::unique_ptr<llvm::BasicBlock> block;
};
}
#endif

View File

@ -61,11 +61,45 @@ int main() {
} }
stream.expect(token::Type::Eof); stream.expect(token::Type::Eof);
for (int i = 0; i < statements.size(); i++) {
if (statements[i]) auto LLVMContext = std::make_unique<llvm::LLVMContext>();
std::cout << statements[i]->formatted() << std::endl; auto LLVMModule = std::make_unique<llvm::Module>("test.c", *LLVMContext);
auto LLVMBuilder = std::make_unique<llvm::IRBuilder<>>(*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
// llvm_hello_world(); // llvm_hello_world();