Compile test.c using LLVM
This commit is contained in:
parent
74a3914fdf
commit
c314ca4cb7
@ -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
|
||||
|
||||
24
src/ast.h
24
src/ast.h
@ -1,6 +1,8 @@
|
||||
#ifndef AST_H
|
||||
#define AST_H
|
||||
|
||||
#include "codegen.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
@ -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<Expression> 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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
58
src/codegen.cpp
Normal file
58
src/codegen.cpp
Normal 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
17
src/codegen.h
Normal 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
|
||||
40
src/main.cpp
40
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<llvm::LLVMContext>();
|
||||
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();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user