diff --git a/Makefile.in b/Makefile.in index 79c6e7e345ac..608f4a3d3ceb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -216,7 +216,8 @@ RUSTC_INPUTS := $(S)src/rustc/driver/rustc.rs ###################################################################### # FIXME: x86-ism -LLVM_COMPONENTS=x86 ipo bitreader bitwriter linker asmparser +LLVM_COMPONENTS=x86 ipo bitreader bitwriter linker asmparser jit mcjit \ + interpreter define DEF_LLVM_VARS # The configure script defines these variables with the target triples diff --git a/configure b/configure index 040bae9fe60a..8cc6f02c7dbb 100755 --- a/configure +++ b/configure @@ -595,7 +595,7 @@ do LLVM_TARGET="--target=$t" # Disable unused LLVM features - LLVM_OPTS="$LLVM_DBG_OPTS --disable-docs --disable-jit \ + LLVM_OPTS="$LLVM_DBG_OPTS --disable-docs \ --enable-bindings=none --disable-threads \ --disable-pthreads" diff --git a/src/rustc/back/link.rs b/src/rustc/back/link.rs index a81755be9333..04c38c11d62a 100644 --- a/src/rustc/back/link.rs +++ b/src/rustc/back/link.rs @@ -76,6 +76,7 @@ fn run_passes(sess: session, llmod: ModuleRef, output: &Path) { // Generate a pre-optimization intermediate file if -save-temps was // specified. + if opts.save_temps { match opts.output_type { output_type_bitcode => { @@ -135,7 +136,7 @@ fn run_passes(sess: session, llmod: ModuleRef, output: &Path) { llvm::LLVMPassManagerBuilderDispose(MPMB); } if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); } - if is_object_or_assembly_or_exe(opts.output_type) { + if is_object_or_assembly_or_exe(opts.output_type) || opts.jit { let LLVMOptNone = 0 as c_int; // -O0 let LLVMOptLess = 1 as c_int; // -O1 let LLVMOptDefault = 2 as c_int; // -O2, -Os @@ -148,6 +149,29 @@ fn run_passes(sess: session, llmod: ModuleRef, output: &Path) { session::Aggressive => LLVMOptAggressive }; + if opts.jit { + // If we are using JIT, go ahead and create and + // execute the engine now. + + /*llvm::LLVMAddBasicAliasAnalysisPass(pm.llpm); + llvm::LLVMAddInstructionCombiningPass(pm.llpm); + llvm::LLVMAddReassociatePass(pm.llpm); + llvm::LLVMAddGVNPass(pm.llpm); + llvm::LLVMAddCFGSimplificationPass(pm.llpm);*/ + + // JIT execution takes ownership of the module, + // so don't dispose and return. + + if !llvm::LLVMRustJIT(pm.llpm, + llmod, + CodeGenOptLevel, + true) { + llvm_err(sess, ~"Could not JIT"); + } + if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); } + return; + } + let mut FileType; if opts.output_type == output_type_object || opts.output_type == output_type_exe { diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index c9be01f4d564..2d5b36debaa7 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -259,7 +259,8 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, let stop_after_codegen = sess.opts.output_type != link::output_type_exe || - sess.opts.static && sess.building_library; + (sess.opts.static && sess.building_library) || + sess.opts.jit; if stop_after_codegen { return {crate: crate, tcx: Some(ty_cx)}; } @@ -483,6 +484,7 @@ fn build_session_options(matches: getopts::Matches, llvm::LLVMSetDebug(1); } + let jit = opt_present(matches, ~"jit"); let output_type = if parse_only || no_trans { link::output_type_none @@ -545,6 +547,7 @@ fn build_session_options(matches: getopts::Matches, extra_debuginfo: extra_debuginfo, lint_opts: lint_opts, save_temps: save_temps, + jit: jit, output_type: output_type, addl_lib_search_paths: addl_lib_search_paths, maybe_sysroot: sysroot_opt, @@ -620,6 +623,7 @@ fn opts() -> ~[getopts::Opt] { optopt(~"o"), optopt(~"out-dir"), optflag(~"xg"), optflag(~"c"), optflag(~"g"), optflag(~"save-temps"), optopt(~"sysroot"), optopt(~"target"), + optflag(~"jit"), optmulti(~"W"), optmulti(~"warn"), optmulti(~"A"), optmulti(~"allow"), diff --git a/src/rustc/driver/rustc.rs b/src/rustc/driver/rustc.rs index d1929a686297..42982550325e 100644 --- a/src/rustc/driver/rustc.rs +++ b/src/rustc/driver/rustc.rs @@ -42,6 +42,7 @@ fn usage(argv0: ~str) { -L Add a directory to the library search path --lib Compile a library crate --ls List the symbols defined by a compiled library crate + --jit Execute using JIT (experimental) --no-trans Run all passes except translation; no output -O Equivalent to --opt-level=2 -o Write output to diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs index 59c4e5697adc..47aa3019de10 100644 --- a/src/rustc/driver/session.rs +++ b/src/rustc/driver/session.rs @@ -108,6 +108,7 @@ impl OptLevel : cmp::Eq { extra_debuginfo: bool, lint_opts: ~[(lint::lint, lint::level)], save_temps: bool, + jit: bool, output_type: back::link::output_type, addl_lib_search_paths: ~[Path], maybe_sysroot: Option, @@ -249,6 +250,7 @@ fn basic_options() -> @options { extra_debuginfo: false, lint_opts: ~[], save_temps: false, + jit: false, output_type: link::output_type_exe, addl_lib_search_paths: ~[], maybe_sysroot: None, diff --git a/src/rustc/lib/llvm.rs b/src/rustc/lib/llvm.rs index 1440a654a897..5c8bab166ecb 100644 --- a/src/rustc/lib/llvm.rs +++ b/src/rustc/lib/llvm.rs @@ -986,6 +986,12 @@ fn LLVMRustWriteOutputFile(PM: PassManagerRef, M: ModuleRef, call. */ fn LLVMRustGetLastError() -> *c_char; + /** JIT the module. **/ + fn LLVMRustJIT(PM: PassManagerRef, + M: ModuleRef, + OptLevel: c_int, + EnableSegmentedStacks: bool) -> bool; + /** Parses the bitcode in the given memory buffer. */ fn LLVMRustParseBitcode(MemBuf: MemoryBufferRef) -> ModuleRef; diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 4a927744f07a..8f8503a74d49 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -28,6 +28,11 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/Support/Host.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/ExecutionEngine/Interpreter.h" +#include "llvm/ExecutionEngine/GenericValue.h" #include "llvm-c/Core.h" #include "llvm-c/BitReader.h" #include "llvm-c/Object.h" @@ -68,6 +73,61 @@ void LLVMInitializeX86TargetMC(); void LLVMInitializeX86AsmPrinter(); void LLVMInitializeX86AsmParser(); +// Only initialize the platforms supported by Rust here, +// because using --llvm-root will have multiple platforms +// that rustllvm doesn't actually link to and it's pointless to put target info +// into the registry that Rust can not generate machine code for. + +#define INITIALIZE_TARGETS() LLVMInitializeX86TargetInfo(); \ + LLVMInitializeX86Target(); \ + LLVMInitializeX86TargetMC(); \ + LLVMInitializeX86AsmPrinter(); \ + LLVMInitializeX86AsmParser(); + +extern "C" bool +LLVMRustJIT(LLVMPassManagerRef PMR, + LLVMModuleRef M, + CodeGenOpt::Level OptLevel, + bool EnableSegmentedStacks) { + + INITIALIZE_TARGETS(); + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + + std::string Err; + TargetOptions Options; + Options.NoFramePointerElim = true; + Options.EnableSegmentedStacks = EnableSegmentedStacks; + + PassManager *PM = unwrap(PMR); + + PM->run(*unwrap(M)); + + ExecutionEngine* EE = EngineBuilder(unwrap(M)) + .setTargetOptions(Options) + .setOptLevel(OptLevel) + .setUseMCJIT(true) + .create(); + + if(!EE || Err != "") { + LLVMRustError = Err.c_str(); + return false; + } + + Function* func = EE->FindFunctionNamed("main"); + + if(!func || Err != "") { + LLVMRustError = Err.c_str(); + return false; + } + + std::vector args; + + EE->runFunction(func, args); + + return true; +} + extern "C" bool LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, LLVMModuleRef M, @@ -77,16 +137,7 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, CodeGenOpt::Level OptLevel, bool EnableSegmentedStacks) { - // Only initialize the platforms supported by Rust here, - // because using --llvm-root will have multiple platforms - // that rustllvm doesn't actually link to and it's pointless to put target info - // into the registry that Rust can not generate machine code for. - - LLVMInitializeX86TargetInfo(); - LLVMInitializeX86Target(); - LLVMInitializeX86TargetMC(); - LLVMInitializeX86AsmPrinter(); - LLVMInitializeX86AsmParser(); + INITIALIZE_TARGETS(); TargetOptions Options; Options.NoFramePointerElim = true; diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index 64b560999bec..2fd4b3fa6f35 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -4,6 +4,7 @@ LLVMRustWriteOutputFile LLVMRustGetLastError LLVMRustConstSmallInt LLVMRustConstInt +LLVMRustJIT LLVMRustParseBitcode LLVMRustParseAssemblyFile LLVMRustPrintPassTimings @@ -485,6 +486,7 @@ LLVMIsThreadLocal LLVMIsUndef LLVMLabelType LLVMLabelTypeInContext +LLVMLinkInInterpreter LLVMMDNode LLVMMDNodeInContext LLVMMDString