Add experimental JIT compiler

This commit is contained in:
Zack Corr 2012-08-25 14:54:30 +10:00 committed by Brian Anderson
parent 97bb812238
commit d7aa9918ef
9 changed files with 105 additions and 14 deletions

View file

@ -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

2
configure vendored
View file

@ -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"

View file

@ -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 {

View file

@ -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"),

View file

@ -42,6 +42,7 @@ fn usage(argv0: ~str) {
-L <path> 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 <filename> Write output to <filename>

View file

@ -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<Path>,
@ -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,

View file

@ -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;

View file

@ -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<PassManager>(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<GenericValue> 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;

View file

@ -4,6 +4,7 @@ LLVMRustWriteOutputFile
LLVMRustGetLastError
LLVMRustConstSmallInt
LLVMRustConstInt
LLVMRustJIT
LLVMRustParseBitcode
LLVMRustParseAssemblyFile
LLVMRustPrintPassTimings
@ -485,6 +486,7 @@ LLVMIsThreadLocal
LLVMIsUndef
LLVMLabelType
LLVMLabelTypeInContext
LLVMLinkInInterpreter
LLVMMDNode
LLVMMDNodeInContext
LLVMMDString