Skip to content

Commit

Permalink
Another take on an llvm backend
Browse files Browse the repository at this point in the history
  • Loading branch information
Spydr06 committed May 16, 2022
1 parent 1774640 commit c41e69e
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 7 deletions.
4 changes: 0 additions & 4 deletions examples/features.csp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ import "std.csp";

fn main(): i32
{
using std::io;

printf("%i\n", last!([1, 2, 3, 4]));
printf("%i\n", first!([11, 22, 33]));

<- 0;
}
16 changes: 15 additions & 1 deletion src/compiler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,27 @@ file(GLOB_RECURSE compiler_source *.c *.cpp *.cc *.c++)
list(REMOVE_ITEM compiler_source "main.c")

add_library(libcspc ${compiler_source})
target_link_libraries(libcspc LINK_PUBLIC m json-c bsd)
set_target_properties(libcspc PROPERTIES LINKER_LANGUAGE C)

if(${NO_LLVM})
add_compile_definitions(CSPYDR_NO_LLVM)
target_link_libraries(libcspc LINK_PUBLIC m json-c bsd)
else()
add_compile_definitions(CSPYDR_USE_LLVM)

find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")

execute_process(COMMAND llvm-config --libs all OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE llvm_libraries)
target_include_directories(libcspc INTERFACE ${LLVM_INCLUDE_DIRS})
target_link_libraries(libcspc LINK_PUBLIC m json-c bsd "${llvm_libraries}")
endif()

# build the main executable
add_executable(cspc main.c)
target_link_libraries(cspc libcspc)


install(PROGRAMS ${PROJECT_SOURCE_DIR}/bin/cspc
DESTINATION bin
RENAME "cspc"
Expand Down
122 changes: 122 additions & 0 deletions src/compiler/codegen/llvm/llvm_codegen.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#include <llvm-c/BitWriter.h>
#ifdef CSPYDR_USE_LLVM

#include <string.h>

#include "ast/ast.h"
#include "io/log.h"
#include "llvm_codegen.h"
#include "llvm_includes.h"
#include "globals.h"

typedef struct
{
ASTProg_T* ast;

LLVMModuleRef module;
LLVMBuilderRef builder;

LLVMValueRef current_fn_value;
ASTObj_T* current_fn;
LLVMBasicBlockRef current_block;
} LLVMCodegenData_T;

static void optimize_llvm(LLVMCodegenData_T* cg);
static char* llvm_emit_bc(LLVMCodegenData_T* cg, char* output_file);
static void llvm_link_bc(LLVMCodegenData_T* cg, char* bc_file, char* output_file);

static void init_llvm_codegen(LLVMCodegenData_T* cg, ASTProg_T* ast)
{
memset(cg, 0, sizeof(LLVMCodegenData_T));
cg->ast = ast;
cg->module = LLVMModuleCreateWithName(ast->main_file_path);
LLVMSetDataLayout(cg->module, "");
cg->builder = LLVMCreateBuilder();
}

static void free_llvm_codegen(LLVMCodegenData_T* cg)
{
}

void generate_llvm(ASTProg_T *ast, char *output_file, bool print_code, bool is_silent)
{
LLVMCodegenData_T cg;
init_llvm_codegen(&cg, ast);

char* target = LLVMGetDefaultTargetTriple();
LLVMSetTarget(cg.module, target);
if(!is_silent)
LOG_OK_F(COLOR_BOLD_BLUE " Generating" COLOR_RESET " LLVM-IR for " COLOR_BOLD_WHITE "%s" COLOR_RESET "\n", target);
LLVMDisposeMessage(target);

char* error = NULL;
if(LLVMVerifyModule(cg.module, LLVMAbortProcessAction, &error))
{
LOG_ERROR_F(COLOR_BOLD_RED "[Error]" COLOR_RESET COLOR_RED " error while generating llvm-ir: %s\n", error);
exit(1);
}
LLVMDisposeMessage(error);

if(global.optimize)
optimize_llvm(&cg);

if(print_code)
{
char* code = LLVMPrintModuleToString(cg.module);
LOG_INFO_F(COLOR_RESET "%s\n", code);
LLVMDisposeMessage(code);
}

char* file = NULL;

if(!global.do_assemble)
goto finish;

file = llvm_emit_bc(&cg, output_file);

if(!global.do_link)
goto finish;

if(!is_silent)
LOG_OK_F(COLOR_BOLD_BLUE " Linking" COLOR_RESET " %s\n", output_file);
llvm_link_bc(&cg, file, output_file);

finish:
if(file)
free(file);
free_llvm_codegen(&cg);
}

static void optimize_llvm(LLVMCodegenData_T* cg)
{
LLVMPassManagerRef pass = LLVMCreatePassManager();
LLVMAddInstructionCombiningPass(pass);
LLVMAddMemCpyOptPass(pass);
LLVMAddGVNPass(pass);
LLVMAddCFGSimplificationPass(pass);
LLVMAddVerifierPass(pass);

LLVMRunPassManager(pass, cg->module);
LLVMDisposePassManager(pass);
}

static char* llvm_emit_bc(LLVMCodegenData_T* cg, char* output_file)
{
char* file = calloc(strlen(output_file) + 4, sizeof(char));
sprintf(file, "%s.bc", output_file);

if(LLVMWriteBitcodeToFile(cg->module, file))
{
LOG_ERROR_F(COLOR_BOLD_RED "[Error]" COLOR_RESET COLOR_RED " while trying to output llvm-ir to \"%s\"\n" COLOR_RESET, file);
exit(1);
}

return file;
}

static void llvm_link_bc(LLVMCodegenData_T* cg, char* bc_file, char* output_file)
{

}

#endif
10 changes: 10 additions & 0 deletions src/compiler/codegen/llvm/llvm_codegen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifdef CSPYDR_USE_LLVM
#ifndef CSPYDR_LLVM_CODEGEN_H
#define CSPYDR_LLVM_CODEGEN_H

#include "ast/ast.h"

void generate_llvm(ASTProg_T *ast, char *output_file, bool print_code, bool is_silent);

#endif
#endif
18 changes: 18 additions & 0 deletions src/compiler/codegen/llvm/llvm_includes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifdef CSPYDR_USE_LLVM
#ifndef CSPYDR_LLVM_INCLUDES_H
#define CSPYDR_LLVM_INCLUDES_H

#include <llvm-c/Core.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/TargetMachine.h>
#include <llvm-c/ErrorHandling.h>
#include <llvm-c/Types.h>
#include <llvm-c/Transforms/Scalar.h>
#include <llvm-c/Target.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/BitWriter.h>
#include <llvm-c/TargetMachine.h>
#include <llvm-c/Linker.h>

#endif
#endif
9 changes: 8 additions & 1 deletion src/compiler/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ const char help_text[] = "%s"
" -i, --info | Displays information text and quits\n"
" -o, --output [file] | Sets the target output file (default: `" DEFAULT_OUTPUT_FILE "`)\n"
" -t, --transpile | Instructs the compiler to compile to C source code (deprecated)\n"
" -a, --asm | Instructs the compile to compile to x86_64 gnu assembly code\n"
" -a, --asm | Instructs the compiler to compile to x86_64 gnu assembly code\n"
#ifdef CSPYDR_USE_LLVM
" -l, --llvm | Instructs the compiler to use the llvm backend\n"
#endif
" --to-json | Emit the AST directly as a JSON file (for debugging purposes)\n"
" --print-code | Prints the generated code (C | Assembly | LLVM IR)\n"
" --silent | Disables all command line output except error messages\n"
Expand Down Expand Up @@ -181,6 +184,10 @@ i32 main(i32 argc, char* argv[])
global.ct = CT_TRANSPILE;
else if(streq(arg, "-a") || streq(arg, "--asm"))
global.ct = CT_ASM;
#ifdef CSPYDR_USE_LLVM
else if(streq(arg, "-l") || streq(arg, "--llvm"))
global.ct = CT_LLVM;
#endif
else if(streq(arg, "--to-json"))
global.ct = CT_TO_JSON;
else if(streq(arg, "--from-json"))
Expand Down
6 changes: 6 additions & 0 deletions src/compiler/toolchain.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "ast/ast_json.h"
#include "debugger/dbg.h"
#include "globals.h"
#include "codegen/llvm/llvm_codegen.h"

// generate the ast from the source file (lexing, preprocessing, parsing)
static void generate_ast(ASTProg_T* ast, char* path, bool silent);
Expand Down Expand Up @@ -48,6 +49,11 @@ void compile(char* input_file, char* output_file, Action_T action)
case CT_ASM:
generate_asm(&ast, output_file, global.print_code, global.silent);
break;
#ifdef CSPYDR_USE_LLVM
case CT_LLVM:
generate_llvm(&ast, output_file, global.print_code, global.silent);
break;
#endif
case CT_TO_JSON:
generate_json(&ast, output_file, global.print_code, global.silent);
break;
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/toolchain.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
#ifndef CSPYDR_TOOLCHAIN_H
#define CSPYDR_TOOLCHAIN_H

#include "config.h"

typedef enum COMPILE_TYPE_ENUM
{
CT_TRANSPILE,
CT_ASM,
#ifdef CSPYDR_USE_LLVM
CT_LLVM,
#endif
CT_TO_JSON,
} CompileType_T;

Expand Down
2 changes: 1 addition & 1 deletion src/std/std.csp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "error.csp";
import "file.csp";
import "io.csp";
import "math.csp";
import "mem.csp";
import "memory.csp";
import "net.csp";
import "option.csp";
import "process.csp";
Expand Down

0 comments on commit c41e69e

Please sign in to comment.