Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add experimental option to generate native code shared library

  • Loading branch information...
commit 8c75456b451f87f351481483b77ad2f88bf854b1 1 parent 12dbd4d
@nickg authored
Showing with 207 additions and 66 deletions.
  1. +85 −40 src/link.c
  2. +5 −0 src/nvc.c
  3. +4 −1 src/phase.h
  4. +113 −25 src/rt/jit.c
View
125 src/link.c
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2011 Nick Gasson
+// Copyright (C) 2011-2012 Nick Gasson
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -32,6 +32,7 @@
static char **args = NULL;
static int n_args = 0;
static bool optimise = true;
+static bool native = false;
__attribute__((format(printf, 1, 2)))
static void link_arg_f(const char *fmt, ...)
@@ -45,12 +46,17 @@ static void link_arg_f(const char *fmt, ...)
args[++n_args] = NULL;
}
-static void link_arg_bc(lib_t lib, ident_t name)
+static void link_product(lib_t lib, ident_t name, const char *ext)
{
char path[256];
lib_realpath(lib, NULL, path, sizeof(path));
- link_arg_f("%s/_%s.bc", path, istr(name));
+ link_arg_f("%s/_%s.%s", path, istr(name), ext);
+}
+
+static void link_arg_bc(lib_t lib, ident_t name)
+{
+ link_product(lib, name, "bc");
}
static bool link_needs_body(tree_t pack)
@@ -85,49 +91,28 @@ static void link_context(context_t ctx)
link_arg_bc(lib, body_i);
}
-static void link_output(tree_t top)
+static void link_output(tree_t top, const char *ext)
{
- link_arg_f("-b");
-
ident_t orig = ident_strip(tree_ident(top), ident_new(".elab"));
ident_t final = ident_prefix(orig, ident_new("final"), '.');
- link_arg_bc(lib_work(), final);
+ link_product(lib_work(), final, ext);
}
-char * get_llvm_bindir_path (char * default_llvm_bindir )
+static void link_args_begin(void)
{
- if (getenv("NVC_LLVM_BINDIR_PATH") == NULL)
- /* no preemptive environmental variable set */
-
- if ( access(default_llvm_bindir, F_OK) == 0)
- return (default_llvm_bindir);
- else
- fatal("can't access llvm bin directory %s", default_llvm_bindir);
-
- else /* environmental variable was present */
- if (access(getenv("NVC_LLVM_BINDIR_PATH"), F_OK) == 0)
- return(getenv("NVC_LLVM_BINDIR_PATH")); /* static, optimized */
- else
- fatal("nvc override env variable NVC_LLVM_BINDIR_PATH not valid - %s",
- getenv("NVC_LLVM_BINDIR_PATH"));
+ args = xmalloc(MAX_ARGS * sizeof(char*));
+ n_args = 0;
}
-void link_bc(tree_t top)
+static void link_args_end(void)
{
- args = xmalloc(MAX_ARGS * sizeof(char*));
-
- link_arg_f("%s/llvm-ld", LLVM_CONFIG_BINDIR);
- link_arg_f("-r");
-
- if (!optimise)
- link_arg_f("--disable-opt");
-
- link_output(top);
- link_arg_bc(lib_work(), tree_ident(top));
-
- for (unsigned i = 0; i < tree_contexts(top); i++)
- link_context(tree_context(top, i));
+ for (int i = 0; i < n_args; i++)
+ free(args[i]);
+ free(args);
+}
+static void link_exec(void)
+{
for (int i = 0; i < n_args; i++)
printf("%s%c", args[i], (i + 1 == n_args ? '\n' : ' '));
@@ -142,17 +127,77 @@ void link_bc(tree_t top)
fatal_errno("waitpid");
if (WEXITSTATUS(status) != 0)
- fatal("llvm-ld failed with status %d", WEXITSTATUS(status));
+ fatal("%s failed with status %d", args[0], WEXITSTATUS(status));
}
else
fatal_errno("fork");
+}
- for (int i = 0; i < n_args; i++)
- free(args[i]);
- free(args);
+static void link_assembly(tree_t top)
+{
+ link_args_begin();
+
+ link_arg_f("%s/llc", LLVM_CONFIG_BINDIR);
+ link_arg_f("-relocation-model=pic");
+ link_output(top, "bc");
+
+ link_exec();
+
+ link_args_end();
+}
+
+static void link_shared(tree_t top)
+{
+ link_args_begin();
+
+ link_arg_f("/usr/bin/cc");
+ link_arg_f("-shared");
+ link_arg_f("-o");
+ link_output(top, "so"); // TODO: different on OS X, etc.
+ link_output(top, "s");
+
+ link_exec();
+
+ link_args_end();
+}
+
+static void link_native(tree_t top)
+{
+ link_assembly(top);
+ link_shared(top);
+}
+
+void link_bc(tree_t top)
+{
+ link_args_begin();
+
+ link_arg_f("%s/llvm-ld", LLVM_CONFIG_BINDIR);
+ link_arg_f("-r");
+
+ if (!optimise)
+ link_arg_f("--disable-opt");
+
+ link_arg_f("-b");
+ link_output(top, "bc");
+ link_arg_bc(lib_work(), tree_ident(top));
+
+ for (unsigned i = 0; i < tree_contexts(top); i++)
+ link_context(tree_context(top, i));
+
+ link_exec();
+
+ link_args_end();
+
+ if (native)
+ link_native(top);
}
void link_optimise_en(bool en)
{
optimise = en;
}
+
+void link_native_en(bool en)
+{
+ native = en;
+}
View
5 src/nvc.c
@@ -133,6 +133,7 @@ static int elaborate(int argc, char **argv)
static struct option long_options[] = {
{"disable-opt", no_argument, 0, 'o'},
{"dump-llvm", no_argument, 0, 'd'},
+ {"native", no_argument, 0, 'n'},
{0, 0, 0, 0}
};
@@ -148,6 +149,9 @@ static int elaborate(int argc, char **argv)
case 'd':
cgen_dump_en(true);
break;
+ case 'n':
+ link_native_en(true);
+ break;
case 0:
// Set a flag
break;
@@ -361,6 +365,7 @@ static void usage(void)
"Elaborate options:\n"
" --disable-opt\tDisable LLVM optimisations\n"
" --dump-llvm\tPrint generated LLVM IR\n"
+ " --native\t\tGenerate native code shared library\n"
"\n"
"Run options:\n"
" -b, --batch\t\tRun in batch mode (default)\n"
View
5 src/phase.h
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2011 Nick Gasson
+// Copyright (C) 2011-2012 Nick Gasson
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -64,4 +64,7 @@ void opt(tree_t top);
// Link together bitcode packages with elaborated design
void link_bc(tree_t top);
+// Enable native code output
+void link_native_en(bool en);
+
#endif // _PHASE_H
View
138 src/rt/jit.c
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2011 Nick Gasson
+// Copyright (C) 2011-2012 Nick Gasson
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -21,6 +21,11 @@
#include <assert.h>
#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dlfcn.h>
#include <llvm-c/Core.h>
#include <llvm-c/BitReader.h>
@@ -29,44 +34,85 @@
static LLVMModuleRef module = NULL;
static LLVMExecutionEngineRef exec_engine = NULL;
+static bool using_jit = true;
+static void *dl_handle = NULL;
+
void *jit_fun_ptr(const char *name)
{
- LLVMValueRef fn;
- if (LLVMFindFunction(exec_engine, name, &fn))
- fatal("cannot find function %s", name);
+ if (using_jit) {
+ LLVMValueRef fn;
+ if (LLVMFindFunction(exec_engine, name, &fn))
+ fatal("cannot find function %s", name);
+
+ return LLVMGetPointerToGlobal(exec_engine, fn);
+ }
+ else
+ return jit_var_ptr(name);
+}
- return LLVMGetPointerToGlobal(exec_engine, fn);
+static char *jit_str_add(char *p, const char *s)
+{
+ while (*s != '\0')
+ *p++ = *s++;
+ return p;
}
-void *jit_var_ptr(const char *name)
+static void jit_native_name(const char *name, char *buf, size_t len)
{
- LLVMValueRef var = LLVMGetNamedGlobal(module, name);
- if (var == NULL)
- fatal("cannot find global %s", name);
+ char *p = buf;
+ char ch;
+ while ((ch = *(name++)) && (p < buf + len - 4)) {
+ switch (ch) {
+ case ':':
+ p = jit_str_add(p, "_3A_");
+ break;
+ case '(':
+ p = jit_str_add(p, "_28_");
+ break;
+ case ')':
+ p = jit_str_add(p, "_29_");
+ break;
+ default:
+ *p++ = ch;
+ }
+ }
+ *p = '\0';
+}
- return LLVMGetPointerToGlobal(exec_engine, var);
+void *jit_var_ptr(const char *name)
+{
+ if (using_jit) {
+ LLVMValueRef var = LLVMGetNamedGlobal(module, name);
+ if (var == NULL)
+ fatal("cannot find global %s", name);
+
+ return LLVMGetPointerToGlobal(exec_engine, var);
+ }
+ else {
+ dlerror(); // Clear any previous error
+ char dlname[256];
+ jit_native_name(name, dlname, sizeof(dlname));
+ void *sym = dlsym(dl_handle, dlname);
+ const char *error = dlerror();
+ if (error != NULL)
+ fatal("%s", error);
+ return sym;
+ }
}
void jit_bind_fn(const char *name, void *ptr)
{
- LLVMValueRef fn;
- if (LLVMFindFunction(exec_engine, name, &fn))
- return;
+ if (using_jit) {
+ LLVMValueRef fn;
+ if (LLVMFindFunction(exec_engine, name, &fn))
+ return;
- LLVMAddGlobalMapping(exec_engine, fn, ptr);
+ LLVMAddGlobalMapping(exec_engine, fn, ptr);
+ }
}
-void jit_init(ident_t top)
+static void jit_init_llvm(const char *path)
{
- ident_t orig = ident_strip(top, ident_new(".elab"));
- ident_t final = ident_prefix(orig, ident_new("final"), '.');
-
- char fname[128];
- snprintf(fname, sizeof(fname), "_%s.bc", istr(final));
-
- char path[PATH_MAX];
- lib_realpath(lib_work(), fname, path, sizeof(path));
-
char *error;
LLVMMemoryBufferRef buf;
if (LLVMCreateMemoryBufferWithContentsOfFile(path, &buf, &error))
@@ -84,7 +130,49 @@ void jit_init(ident_t top)
fatal("error creating execution engine: %s", error);
}
+static void jit_init_native(const char *path)
+{
+ if ((dl_handle = dlopen(path, RTLD_LAZY)) == NULL)
+ fatal("%s: %s", path, dlerror());
+}
+
+static time_t jit_mod_time(const char *path)
+{
+ struct stat st;
+ if (stat(path, &st) == -1) {
+ if (errno == ENOENT)
+ return 0;
+ else
+ fatal_errno(path);
+ }
+ return st.st_mtime;
+}
+
+void jit_init(ident_t top)
+{
+ ident_t orig = ident_strip(top, ident_new(".elab"));
+ ident_t final = ident_prefix(orig, ident_new("final"), '.');
+
+ char bc_fname[64], so_fname[64];;
+ snprintf(bc_fname, sizeof(bc_fname), "_%s.bc", istr(final));
+ snprintf(so_fname, sizeof(so_fname), "_%s.so", istr(final));
+
+ char bc_path[PATH_MAX], so_path[PATH_MAX];
+ lib_realpath(lib_work(), bc_fname, bc_path, sizeof(bc_path));
+ lib_realpath(lib_work(), so_fname, so_path, sizeof(so_path));
+
+ using_jit = (jit_mod_time(bc_path) > jit_mod_time(so_path));
+
+ if (using_jit)
+ jit_init_llvm(bc_path);
+ else
+ jit_init_native(so_path);
+}
+
void jit_shutdown(void)
{
- LLVMDisposeExecutionEngine(exec_engine);
+ if (using_jit)
+ LLVMDisposeExecutionEngine(exec_engine);
+ else
+ dlclose(dl_handle);
}
Please sign in to comment.
Something went wrong with that request. Please try again.