Commit c8c90822 authored by Yi Lin's avatar Yi Lin

Merge branch 'jit-test' into 'master'

Merge jit-test branch to master



See merge request !2
parents bec493dc b8286940
Pipeline #21 failed with stage
in 7 seconds
......@@ -13,4 +13,5 @@ pub extern crate ast;
pub extern crate utils;
pub mod vm;
pub mod compiler;
pub mod runtime;
\ No newline at end of file
pub mod runtime;
pub mod testutil;
extern crate log;
extern crate simple_logger;
extern crate libloading as ll;
use compiler::*;
use ast::ir::*;
use vm::*;
use std::sync::Arc;
pub mod aot {
use ast::ir::MuName;
use runtime;
use compiler::backend;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;
fn get_test_clang_path() -> String {
use std::env;
match env::var("CLANG_FOR_AOT") {
Ok(val) => val,
Err(_) => "clang".to_string()
}
}
fn exec (mut cmd: Command) -> Output {
println!("executing: {:?}", cmd);
let output = cmd.output().expect("failed to execute");
println!("---out---");
println!("{}", String::from_utf8_lossy(&output.stdout));
println!("---err---");
println!("{}", String::from_utf8_lossy(&output.stderr));
output
}
fn link_executable_internal (files: Vec<PathBuf>, out: PathBuf) -> PathBuf {
let mut gcc = Command::new(get_test_clang_path());
for file in files {
println!("link with {:?}", file.as_path());
gcc.arg(file.as_path());
}
println!("output as {:?}", out.as_path());
if cfg!(target_os = "linux") {
gcc.arg("-lrt");
gcc.arg("-ldl");
gcc.arg("-lpthread");
}
// so we can find symbols in itself
gcc.arg("-rdynamic");
gcc.arg("-o");
gcc.arg(out.as_os_str());
assert!(exec(gcc).status.success());
out
}
fn link_dylib_internal (files: Vec<PathBuf>, out: PathBuf) -> PathBuf {
let mut object_files : Vec<PathBuf> = vec![];
for file in files {
let mut gcc = Command::new(get_test_clang_path());
gcc.arg("-c");
gcc.arg("-fpic");
let mut out = file.clone();
out.set_extension("o");
gcc.arg(file.as_os_str());
gcc.arg("-o");
gcc.arg(out.as_os_str());
object_files.push(out);
exec(gcc);
}
let mut gcc = Command::new(get_test_clang_path());
gcc.arg("-shared");
gcc.arg("-Wl");
gcc.arg("-undefined");
gcc.arg("dynamic_lookup");
for obj in object_files {
gcc.arg(obj.as_os_str());
}
gcc.arg("-o");
gcc.arg(out.as_os_str());
exec(gcc);
out
}
fn get_path_for_mu_func (f: MuName) -> PathBuf {
let mut ret = PathBuf::from(backend::AOT_EMIT_DIR);
ret.push(f);
ret.set_extension("s");
ret
}
fn get_path_for_mu_context () -> PathBuf {
let mut ret = PathBuf::from(backend::AOT_EMIT_DIR);
ret.push(backend::AOT_EMIT_CONTEXT_FILE);
ret
}
pub fn link_primordial (funcs: Vec<MuName>, out: &str) -> PathBuf {
let emit_dir = PathBuf::from(backend::AOT_EMIT_DIR);
let files : Vec<PathBuf> = {
use std::fs;
let mut ret = vec![];
// all interested mu funcs
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
// mu context
ret.push(get_path_for_mu_context());
// copy primoridal entry
let source = PathBuf::from(runtime::PRIMORDIAL_ENTRY);
let mut dest = PathBuf::from(backend::AOT_EMIT_DIR);
dest.push("main.c");
fs::copy(source.as_path(), dest.as_path()).unwrap();
// include the primordial C main
ret.push(dest);
// include mu static lib
let libmu = PathBuf::from("target/debug/libmu.a");
ret.push(libmu);
ret
};
let mut out_path = emit_dir.clone();
out_path.push(out);
link_executable_internal(files, out_path)
}
pub fn execute(executable: PathBuf) {
let run = Command::new(executable.as_os_str());
assert!(exec(run).status.success());
}
pub fn link_dylib (funcs: Vec<MuName>, out: &str) -> PathBuf {
let files = {
let mut ret = vec![];
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
ret.push(get_path_for_mu_context());
ret
};
let mut out_path = PathBuf::from(backend::AOT_EMIT_DIR);
out_path.push(out);
link_dylib_internal(files, out_path)
}
}
pub fn compile_fnc<'a>(fnc_name: &'static str, build_fnc: &'a Fn() -> VM) -> ll::Library {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm = Arc::new(build_fnc());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of(fnc_name);
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
let libname = &format!("lib{}.dylib", fnc_name);
let dylib = aot::link_dylib(vec![Mu(fnc_name)], libname);
ll::Library::new(dylib.as_os_str()).unwrap()
}
......@@ -243,6 +243,14 @@ extern fn _forwarder__MuVM__set_trap_handler(mvm: *mut CMuVM, trap_handler: CMuT
};
}
extern fn _forwarder__MuVM__compile_to_sharedlib(mvm: *mut CMuVM, lib_name: CMuCString) {
let mut _arg_mvm = from_MuVM_ptr(mvm);
let mut _arg_lib_name = from_MuCString(lib_name);
unsafe {
(*_arg_mvm).compile_to_sharedlib(&_arg_lib_name)
};
}
extern fn _forwarder__MuCtx__id_of(ctx: *mut CMuCtx, name: CMuName) -> CMuID {
let mut _arg_ctx = from_MuCtx_ptr(ctx);
let mut _arg_name = from_MuName(name);
......@@ -2037,6 +2045,7 @@ pub fn make_new_MuVM(header: *mut c_void) -> *mut CMuVM {
id_of: _forwarder__MuVM__id_of,
name_of: _forwarder__MuVM__name_of,
set_trap_handler: _forwarder__MuVM__set_trap_handler,
compile_to_sharedlib: _forwarder__MuVM__compile_to_sharedlib,
});
Box::into_raw(bx)
......
......@@ -109,6 +109,8 @@ pub struct CMuVM {
pub id_of: extern fn(*mut CMuVM, CMuName) -> CMuID,
pub name_of: extern fn(*mut CMuVM, CMuID) -> CMuName,
pub set_trap_handler: extern fn(*mut CMuVM, CMuTrapHandler, CMuCPtr),
// this function is only used in testing jit
pub compile_to_sharedlib: extern fn(*mut CMuVM, CMuCString),
}
#[repr(C)]
......
use super::common::*;
use std::sync::Arc;
pub struct MuVM {
// The actual VM
pub vm: VM,
pub vm: Arc<VM>,
// Cache C strings. The C client expects `char*` from `name_of`. We assume the client won't
// call `name_of` very often, so that we don't need to initialise this hashmap on startup.
......@@ -19,7 +20,7 @@ impl MuVM {
*/
pub fn new() -> MuVM {
MuVM {
vm: VM::new(),
vm: Arc::new(VM::new()),
// Cache C strings. The C client expects `char*` from `name_of`. We assume the client
// won't call `name_of` very often, so that we don't need to initialise this hashmap on
// startup.
......@@ -69,6 +70,28 @@ impl MuVM {
panic!("Not implemented")
}
pub fn compile_to_sharedlib(&self, lib_name: &str) {
extern crate libloading as ll;
use compiler::*;
use testutil::aot;
let compiler = Compiler::new(CompilerPolicy::default(), self.vm.clone());
let funcs = self.vm.funcs().read().unwrap();
let mut func_names = vec![];
// NOTE: this fails because load() API call is not properly implemented yet.
for (func_id, ref f) in funcs.iter() {
let func = f.read().unwrap();
let func_vers = self.vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
func_names.push(func.name().unwrap());
}
backend::emit_context(&self.vm);
let libname = &format!("lib{}.dylib", lib_name);
aot::link_dylib(func_names, libname);
}
}
/**
......
......@@ -270,6 +270,8 @@ struct MuVM {
// Set handlers
void (*set_trap_handler)(MuVM *mvm, MuTrapHandler trap_handler, MuCPtr userdata);
void (*compile_to_sharedlib)(MuVM *mvm, MuCString lib_name);
};
// A local context. It can only be used by one thread at a time. It holds many
......
......@@ -30,168 +30,3 @@ mod common {
assert_eq!(format!("{:?}", left), format!("{:?}", right))
}
}
mod aot {
use mu::ast::ir::MuName;
use mu::runtime;
use mu::compiler::backend;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;
fn get_test_clang_path() -> String {
use std::env;
match env::var("CLANG_FOR_AOT") {
Ok(val) => val,
Err(_) => "clang".to_string()
}
}
fn exec (mut cmd: Command) -> Output {
println!("executing: {:?}", cmd);
let output = cmd.output().expect("failed to execute");
println!("---out---");
println!("{}", String::from_utf8_lossy(&output.stdout));
println!("---err---");
println!("{}", String::from_utf8_lossy(&output.stderr));
output
}
fn link_executable_internal (files: Vec<PathBuf>, out: PathBuf) -> PathBuf {
let mut gcc = Command::new(get_test_clang_path());
for file in files {
println!("link with {:?}", file.as_path());
gcc.arg(file.as_path());
}
println!("output as {:?}", out.as_path());
if cfg!(target_os = "linux") {
gcc.arg("-lrt");
gcc.arg("-ldl");
gcc.arg("-lpthread");
}
// so we can find symbols in itself
gcc.arg("-rdynamic");
gcc.arg("-o");
gcc.arg(out.as_os_str());
assert!(exec(gcc).status.success());
out
}
fn link_dylib_internal (files: Vec<PathBuf>, out: PathBuf) -> PathBuf {
let mut object_files : Vec<PathBuf> = vec![];
for file in files {
let mut gcc = Command::new(get_test_clang_path());
gcc.arg("-c");
gcc.arg("-fpic");
let mut out = file.clone();
out.set_extension("o");
gcc.arg(file.as_os_str());
gcc.arg("-o");
gcc.arg(out.as_os_str());
object_files.push(out);
exec(gcc);
}
let mut gcc = Command::new(get_test_clang_path());
gcc.arg("-shared");
gcc.arg("-Wl");
gcc.arg("-undefined");
gcc.arg("dynamic_lookup");
for obj in object_files {
gcc.arg(obj.as_os_str());
}
gcc.arg("-o");
gcc.arg(out.as_os_str());
exec(gcc);
out
}
fn get_path_for_mu_func (f: MuName) -> PathBuf {
let mut ret = PathBuf::from(backend::AOT_EMIT_DIR);
ret.push(f);
ret.set_extension("s");
ret
}
fn get_path_for_mu_context () -> PathBuf {
let mut ret = PathBuf::from(backend::AOT_EMIT_DIR);
ret.push(backend::AOT_EMIT_CONTEXT_FILE);
ret
}
pub fn link_primordial (funcs: Vec<MuName>, out: &str) -> PathBuf {
let emit_dir = PathBuf::from(backend::AOT_EMIT_DIR);
let files : Vec<PathBuf> = {
use std::fs;
let mut ret = vec![];
// all interested mu funcs
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
// mu context
ret.push(get_path_for_mu_context());
// copy primoridal entry
let source = PathBuf::from(runtime::PRIMORDIAL_ENTRY);
let mut dest = PathBuf::from(backend::AOT_EMIT_DIR);
dest.push("main.c");
fs::copy(source.as_path(), dest.as_path()).unwrap();
// include the primordial C main
ret.push(dest);
// include mu static lib
let libmu = PathBuf::from("target/debug/libmu.a");
ret.push(libmu);
ret
};
let mut out_path = emit_dir.clone();
out_path.push(out);
link_executable_internal(files, out_path)
}
pub fn execute(executable: PathBuf) {
let run = Command::new(executable.as_os_str());
assert!(exec(run).status.success());
}
pub fn link_dylib (funcs: Vec<MuName>, out: &str) -> PathBuf {
let files = {
let mut ret = vec![];
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
ret.push(get_path_for_mu_context());
ret
};
let mut out_path = PathBuf::from(backend::AOT_EMIT_DIR);
out_path.push(out);
link_dylib_internal(files, out_path)
}
}
\ No newline at end of file
......@@ -12,7 +12,7 @@ use self::mu::compiler::*;
use std::sync::Arc;
use std::sync::RwLock;
use std::collections::HashMap;
use aot;
use self::mu::testutil::aot;
#[test]
fn test_instruction_new() {
......
extern crate libloading as ll;
extern crate mu;
extern crate log;
extern crate simple_logger;
extern crate libloading;
use test_ir::test_ir::sum;
use test_ir::test_ir::factorial;
use self::mu::compiler::*;
use self::mu::ast::ir::*;
use std::sync::Arc;
use aot;
use mu::testutil;
#[test]
fn test_regalloc_fac() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm = Arc::new(factorial());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("fac");
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
let dylib = aot::link_dylib(vec![Mu("fac")], "libfac.dylib");
let lib = libloading::Library::new(dylib.as_os_str()).unwrap();
fn test_factorial() {
let lib = testutil::compile_fnc("fac", &factorial);
unsafe {
let fac : libloading::Symbol<unsafe extern fn(u64) -> u64> = lib.get(b"fac").unwrap();
let fac5 = fac(5);
println!("fac(5) = {}", fac5);
assert!(fac5 == 120);
let fac: ll::Symbol<unsafe extern fn (u64) -> u64> = lib.get(b"fac").unwrap();
println!("fac(10) = {}", fac(10));
assert!(fac(10) == 3628800);
}
}
#[test]
fn test_regalloc_sum() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm = Arc::new(sum());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("sum");
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
let dylib = aot::link_dylib(vec![Mu("sum")], "libsum.dylib");
let lib = libloading::Library::new(dylib.as_os_str()).unwrap();
fn test_sum() {
let lib = testutil::compile_fnc("sum", &sum);
unsafe {
let sum : libloading::Symbol<unsafe extern fn(u64) -> u64> = lib.get(b"sum").unwrap();
let sum5 = sum(5);
println!("sum(1..4) = {}", sum5);
assert!(sum5 == 10);
let sum10 = sum(10);
println!("sum(0..9) = {}", sum10);
assert!(sum10 == 45);
}
}
\ No newline at end of file
let sumptr: ll::Symbol<unsafe extern fn (u64) -> u64> = lib.get(b"sum").unwrap();
assert!(sumptr(5) == 10);
assert!(sumptr(10) == 45);
}
}
......@@ -9,7 +9,7 @@ use self::mu::ast::inst::*;
use self::mu::vm::*;
use self::mu::compiler::*;
use aot;
use self::mu::testutil::aot;
use std::sync::Arc;
use std::sync::RwLock;
......
......@@ -12,7 +12,7 @@ use self::mu::compiler::*;
use std::sync::RwLock;
use std::sync::Arc;
use aot;
use mu::testutil::aot;
#[test]
fn test_fp_add() {
......
......@@ -3,7 +3,7 @@ extern crate log;
extern crate simple_logger;
extern crate libloading;
use aot;
use mu::testutil::aot;
use test_ir::test_ir::factorial;
use self::mu::compiler::*;
use self::mu::utils::vec_utils;
......
......@@ -11,7 +11,7 @@ use self::mu::ast::op::*;
use self::mu::vm::*;
use self::mu::compiler::*;
use aot;
use self::mu::testutil::aot;
use std::sync::Arc;
use std::sync::RwLock;
......
// Compile with flag -std=c99
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <dlfcn.h>
#include "muapi.h"
#include "mu-fastimpl.h"
int main(int argc, char** argv) {
MuVM* mu;
MuCtx* ctx;
MuIRBuilder* bldr;
MuID id;
MuID id_2;
MuID id_3;
MuID id_4;
MuID id_5;
MuID id_6;
MuID id_7;
MuID id_8;
MuID id_9;
MuID id_10;
mu = mu_fastimpl_new();
ctx = mu->new_context(mu);
bldr = ctx->new_ir_builder(ctx);
id = bldr->gen_sym(bldr, "@i8");
bldr->new_type_int(bldr, id, 8);
id_2 = bldr->gen_sym(bldr, "@0xff_i8");
bldr->new_const_int(bldr, id_2, id, 255);
id_3 = bldr->gen_sym(bldr, "@0x0a_i8");
bldr->new_const_int(bldr, id_3, id, 10);
id_4 = bldr->gen_sym(bldr, "@sig__i8");
bldr->new_funcsig(bldr, id_4, NULL, 0, (MuTypeNode [1]){id}, 1);
id_5 = bldr->gen_sym(bldr, "@test_fnc");
bldr->new_func(bldr, id_5, id_4);
id_6 = bldr->gen_sym(bldr, "@test_fnc_v1");
id_7 = bldr->gen_sym(bldr, "@test_fnc_v1.blk0");
id_8 = bldr->gen_sym(bldr, "@test_fnc_v1.blk0.res");
id_9 = bldr->gen_sym(bldr, NULL);
bldr->new_binop(bldr, id_9, id_8, MU_BINOP_ADD, id, id_2, id_3, MU_NO_ID);
id_10 = bldr->gen_sym(bldr, NULL);
bldr->new_ret(bldr, id_10, (MuVarNode [1]){id_8}, 1);
bldr->new_bb(bldr, id_7, NULL, NULL, 0, MU_NO_ID, (MuInstNode [2]){id_9, id_10}, 2);
bldr->new_func_ver(bldr, id_6, id_5, (MuBBNode [1]){id_7}, 1);
bldr->load(bldr);
mu->compile_to_sharedlib(mu, "test_add.dylib");
printf("%s\n", "test_add.dylib");
return 0;
}
// Compile with flag -std=c99
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <dlfcn.h>
#include "muapi.h"
#include "mu-fastimpl.h"
int main(int argc, char** argv) {
MuVM* mu_8;
MuCtx* ctx_8;
MuIRBuilder* bldr_8;
MuID id_71;
MuID id_72;
MuID id_73;
MuID id_74;
MuID id_75;
MuID id_76;
MuID id_77;
MuID id_78;
MuID id_79;
MuID id_80;
mu_8 = mu_fastimpl_new();
ctx_8 = mu_8->new_context(mu_8);
bldr_8 = ctx_8->new_ir_builder(ctx_8);
id_71 = bldr_8->gen_sym(bldr_8, "@i64");
bldr_8->new_type_int(bldr_8, id_71, 64);
id_72 = bldr_8->gen_sym(bldr_8, "@0x8d9f9c1d58324b55_i64");
bldr_8->new_const_int(bldr_8, id_72, id_71, 10205046930492509013);
id_73 = bldr_8->gen_sym(bldr_8, "@0xd5a8f2deb00debb4_i64");
bldr_8->new_const_int(bldr_8, id_73, id_71, 15395822364416404404);
id_74 = bldr_8->gen_sym(bldr_8, "@sig__i64");
bldr_8->new_funcsig(bldr_8, id_74, NULL, 0, (MuTypeNode [1]){id_71}, 1);
id_75 = bldr_8->gen_sym(bldr_8, "@test_fnc");
bldr_8->new_func(bldr_8, id_75, id_74);
id_76 = bldr_8->gen_sym(bldr_8, "@test_fnc_v1");
id_77 = bldr_8->gen_sym(bldr_8, "@test_fnc_v1.blk0");
id_78 = bldr_8->gen_sym(bldr_8, "@test_fnc_v1.blk0.res");
id_79 = bldr_8->gen_sym(bldr_8, NULL);
bldr_8->new_binop(bldr_8, id_79, id_78, MU_BINOP_AND, id_71, id_72, id_73, MU_NO_ID);
id_80 = bldr_8->gen_sym(bldr_8, NULL);
bldr_8->new_ret(bldr_8, id_80, (MuVarNode [1]){id_78}, 1);
bldr_8->new_bb(bldr_8, id_77, NULL, NULL, 0, MU_NO_ID, (MuInstNode [2]){id_79, id_80}, 2);
bldr_8->new_func_ver(bldr_8, id_76, id_75, (MuBBNode [1]){id_77}, 1);
bldr_8->load(bldr_8);
mu_8->compile_to_sharedlib(mu_8, "test_and.dylib");