Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add support for the llvm: use scheme #3924

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libponyc/codegen/genexe.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ bool genexe(compile_t* c, ast_t* program)
return false;
}

const char* file_o = genobj(c);
const char* file_o = genobj(c, program);

if(file_o == NULL)
return false;
Expand Down
37 changes: 36 additions & 1 deletion src/libponyc/codegen/genobj.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include "genobj.h"
#include "../pkg/program.h"
#include <llvm-c/BitWriter.h>
#include <llvm-c/IRReader.h>
#include <llvm-c/Linker.h>

const char* genobj(compile_t* c)
const char* genobj(compile_t* c, ast_t* program)
{
errors_t* errors = c->opt->check.errors;

Expand Down Expand Up @@ -48,6 +51,38 @@ const char* genobj(compile_t* c)
return file_o;
}

for(strlist_t* p = program_llvm_irs(program); p != NULL ; p = strlist_next(p))
{
const char* llvmir = strlist_data(p);

if(c->opt->verbosity >= VERBOSITY_ALL)
fprintf(stderr, "Reading llvm: %s\n", llvmir);

char* err;

LLVMMemoryBufferRef buf;
if(LLVMCreateMemoryBufferWithContentsOfFile(llvmir, &buf, &err) != 0)
{
errorf(errors, NULL, "couldn't find LLVMIR at %s: %s", llvmir, err);
LLVMDisposeMessage(err);
return NULL;
}

LLVMModuleRef mod;
if (LLVMParseIRInContext(c->context, buf, &mod, &err) != 0)
{
errorf(errors, NULL, "couldn't parse LLVMIR at %s: %s", llvmir, err);
LLVMDisposeMessage(err);
return NULL;
}

if (LLVMLinkModules2(c->module, mod) != 0)
{
errorf(errors, NULL, "failed to link: %s", llvmir);
return NULL;
}
}

LLVMCodeGenFileType fmt;
const char* file_o;

Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/codegen/genobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

PONY_EXTERN_C_BEGIN

const char* genobj(compile_t* c);
const char* genobj(compile_t* c, ast_t* program);

PONY_EXTERN_C_END

Expand Down
46 changes: 46 additions & 0 deletions src/libponyc/pkg/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ typedef struct program_t
uint32_t next_package_id;
strlist_t* libpaths;
strlist_t* libs;
strlist_t* llvm_irs;
size_t lib_args_size;
size_t lib_args_alloced;
char* lib_args;
Expand Down Expand Up @@ -142,6 +143,41 @@ bool use_library(ast_t* use, const char* locator, ast_t* name,
return true;
}

/// Process a "llvm:" scheme use command.
bool use_llvm(ast_t* use, const char* locator, ast_t* name,
pass_opt_t* options)
{
(void)name;
(void)options;

char absolute[FILENAME_MAX];
const char* prefix = NULL;

if(!is_path_absolute(locator)) {
ast_t* pkg_ast = ast_nearest(use, TK_PACKAGE);
prefix = package_path(pkg_ast);
}

path_cat(prefix, locator, absolute);

size_t len = strlen(absolute);
char* allocated = (char*)ponyint_pool_alloc_size(len + 4); // ".ll\0"
memcpy(allocated, absolute, len);
allocated[len] = '.';
allocated[len + 1] = 'l';
allocated[len + 2] = 'l';
allocated[len + 3] = '\0';
const char* libname = stringtab_consume(allocated, len + 4);

if(libname == NULL)
return false;

ast_t* p = ast_nearest(use, TK_PROGRAM);
program_t* prog = (program_t*)ast_data(p);

prog->llvm_irs = strlist_append(prog->llvm_irs, libname);
return true;
}

/// Process a "path:" scheme use command.
bool use_path(ast_t* use, const char* locator, ast_t* name,
Expand Down Expand Up @@ -173,6 +209,16 @@ bool use_path(ast_t* use, const char* locator, ast_t* name,
return true;
}

strlist_t* program_llvm_irs(ast_t* program)
{
pony_assert(program != NULL);
pony_assert(ast_id(program) == TK_PROGRAM);

program_t* data = (program_t*)ast_data(program);
pony_assert(data != NULL);

return data->llvm_irs;
}

void program_lib_build_args(ast_t* program, pass_opt_t* opt,
const char* path_preamble, const char* rpath_preamble,
Expand Down
10 changes: 10 additions & 0 deletions src/libponyc/pkg/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,24 @@ void program_free(program_t* program);
/// The actual AST node passed in may be anywhere in the tree.
uint32_t program_assign_pkg_id(ast_t* ast);


/// Process a "lib:" scheme use command.
bool use_library(ast_t* use, const char* locator, ast_t* name,
pass_opt_t* options);

/// Process an "llvm:" scheme use command.
bool use_llvm(ast_t* use, const char* locator, ast_t* name,
pass_opt_t* options);

/// Process a "path:" scheme use command.
bool use_path(ast_t* use, const char* locator, ast_t* name,
pass_opt_t* options);

/** Assert that the provided ast_t* and the required field
* llvm_irs are not NULL before returning the field
*/
strlist_t* program_llvm_irs(ast_t* program);

/** Build the required linker arguments based on the libraries we're using.
* Once this has been called no more calls to use_library() are permitted.
*/
Expand Down
1 change: 1 addition & 0 deletions src/libponyc/pkg/use.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static __pony_thread_local use_scheme_t handlers[] =
{"package:", 8, true, false, use_package},
{"lib:", 4, false, true, use_library},
{"path:", 5, false, true, use_path},
{"llvm:", 5, false, true, use_llvm},

{"test:", 5, false, false, NULL}, // For testing
{NULL, 0, false, false, NULL} // Terminator
Expand Down