diff --git a/src/libponyc/codegen/genexe.c b/src/libponyc/codegen/genexe.c index ba1e3e0583..28997277a3 100644 --- a/src/libponyc/codegen/genexe.c +++ b/src/libponyc/codegen/genexe.c @@ -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; diff --git a/src/libponyc/codegen/genobj.c b/src/libponyc/codegen/genobj.c index e4ea2347e1..43ff06913d 100644 --- a/src/libponyc/codegen/genobj.c +++ b/src/libponyc/codegen/genobj.c @@ -1,7 +1,10 @@ #include "genobj.h" +#include "../pkg/program.h" #include +#include +#include -const char* genobj(compile_t* c) +const char* genobj(compile_t* c, ast_t* program) { errors_t* errors = c->opt->check.errors; @@ -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; diff --git a/src/libponyc/codegen/genobj.h b/src/libponyc/codegen/genobj.h index 78a4cf55c8..8511123e79 100644 --- a/src/libponyc/codegen/genobj.h +++ b/src/libponyc/codegen/genobj.h @@ -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 diff --git a/src/libponyc/pkg/program.c b/src/libponyc/pkg/program.c index a27095a91b..28bd8726cc 100644 --- a/src/libponyc/pkg/program.c +++ b/src/libponyc/pkg/program.c @@ -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; @@ -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, @@ -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, diff --git a/src/libponyc/pkg/program.h b/src/libponyc/pkg/program.h index 7871ecbf50..1f8545eba5 100644 --- a/src/libponyc/pkg/program.h +++ b/src/libponyc/pkg/program.h @@ -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. */ diff --git a/src/libponyc/pkg/use.c b/src/libponyc/pkg/use.c index 7b25f5f06c..9a36f9154a 100644 --- a/src/libponyc/pkg/use.c +++ b/src/libponyc/pkg/use.c @@ -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