#[fast_ffi]
pub unsafe fn LLVMContextCreate() -> ContextRef;
#[fast_ffi]
- pub unsafe fn LLVMGetGlobalContext() -> ContextRef;
- #[fast_ffi]
pub unsafe fn LLVMContextDispose(C: ContextRef);
#[fast_ffi]
pub unsafe fn LLVMGetMDKindIDInContext(C: ContextRef,
Name: *c_char,
SLen: c_uint)
-> c_uint;
- #[fast_ffi]
- pub unsafe fn LLVMGetMDKindID(Name: *c_char, SLen: c_uint) -> c_uint;
/* Create and destroy modules. */
#[fast_ffi]
C: ContextRef)
-> ModuleRef;
#[fast_ffi]
+ pub unsafe fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef;
+ #[fast_ffi]
pub unsafe fn LLVMDisposeModule(M: ModuleRef);
/** Data layout. See Module::getDataLayout. */
pub unsafe fn LLVMIntTypeInContext(C: ContextRef,
NumBits: c_uint) -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMInt1Type() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMInt8Type() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMInt16Type() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMInt32Type() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMInt64Type() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMIntType(NumBits: c_uint) -> TypeRef;
#[fast_ffi]
pub unsafe fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint;
#[fast_ffi]
pub unsafe fn LLVMPPCFP128TypeInContext(C: ContextRef) -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMFloatType() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMDoubleType() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMX86FP80Type() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMFP128Type() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMPPCFP128Type() -> TypeRef;
-
/* Operations on function types */
#[fast_ffi]
pub unsafe fn LLVMFunctionType(ReturnType: TypeRef,
ElementCount: c_uint,
Packed: Bool) -> TypeRef;
#[fast_ffi]
- pub unsafe fn LLVMStructType(ElementTypes: *TypeRef,
- ElementCount: c_uint,
- Packed: Bool)
- -> TypeRef;
- #[fast_ffi]
pub unsafe fn LLVMCountStructElementTypes(StructTy: TypeRef)
-> c_uint;
#[fast_ffi]
#[fast_ffi]
pub unsafe fn LLVMMetadataTypeInContext(C: ContextRef) -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMVoidType() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMLabelType() -> TypeRef;
- #[fast_ffi]
- pub unsafe fn LLVMMetadataType() -> TypeRef;
-
/* Operations on all values */
#[fast_ffi]
pub unsafe fn LLVMTypeOf(Val: ValueRef) -> TypeRef;
SLen: c_uint)
-> ValueRef;
#[fast_ffi]
- pub unsafe fn LLVMMDString(Str: *c_char, SLen: c_uint) -> ValueRef;
- #[fast_ffi]
pub unsafe fn LLVMMDNodeInContext(C: ContextRef,
Vals: *ValueRef,
Count: c_uint)
-> ValueRef;
#[fast_ffi]
- pub unsafe fn LLVMMDNode(Vals: *ValueRef, Count: c_uint) -> ValueRef;
- #[fast_ffi]
pub unsafe fn LLVMAddNamedMetadataOperand(M: ModuleRef, Str: *c_char,
Val: ValueRef);
Packed: Bool) -> ValueRef;
#[fast_ffi]
- pub unsafe fn LLVMConstString(Str: *c_char,
- Length: c_uint,
- DontNullTerminate: Bool)
- -> ValueRef;
- #[fast_ffi]
pub unsafe fn LLVMConstArray(ElementTy: TypeRef,
ConstantVals: *ValueRef,
Length: c_uint)
-> ValueRef;
#[fast_ffi]
- pub unsafe fn LLVMConstStruct(ConstantVals: *ValueRef,
- Count: c_uint,
- Packed: Bool) -> ValueRef;
- #[fast_ffi]
pub unsafe fn LLVMConstVector(ScalarConstantVals: *ValueRef,
Size: c_uint) -> ValueRef;
BB: BasicBlockRef,
Name: *c_char)
-> BasicBlockRef;
-
- #[fast_ffi]
- pub unsafe fn LLVMAppendBasicBlock(Fn: ValueRef,
- Name: *c_char)
- -> BasicBlockRef;
- #[fast_ffi]
- pub unsafe fn LLVMInsertBasicBlock(InsertBeforeBB: BasicBlockRef,
- Name: *c_char)
- -> BasicBlockRef;
#[fast_ffi]
pub unsafe fn LLVMDeleteBasicBlock(BB: BasicBlockRef);
#[fast_ffi]
pub unsafe fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef;
#[fast_ffi]
- pub unsafe fn LLVMCreateBuilder() -> BuilderRef;
- #[fast_ffi]
pub unsafe fn LLVMPositionBuilder(Builder: BuilderRef,
Block: BasicBlockRef,
Instr: ValueRef);
/** Parses LLVM asm in the given file */
#[fast_ffi]
- pub unsafe fn LLVMRustParseAssemblyFile(Filename: *c_char)
+ pub unsafe fn LLVMRustParseAssemblyFile(Filename: *c_char,
+ C: ContextRef)
-> ModuleRef;
#[fast_ffi]
#[fast_ffi]
pub unsafe fn LLVMRustPrintPassTimings();
+ #[fast_ffi]
+ pub unsafe fn LLVMRustStartMultithreading() -> bool;
+
#[fast_ffi]
pub unsafe fn LLVMStructCreateNamed(C: ContextRef, Name: *c_char)
-> TypeRef;
use back::{link, abi, upcall};
use driver::session;
use driver::session::Session;
-use lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef};
+use lib::llvm::{ContextRef, ModuleRef, ValueRef, TypeRef, BasicBlockRef};
use lib::llvm::{True, False};
use lib::llvm::{llvm, mk_target_data, mk_type_names};
use lib;
use core::str;
use core::uint;
use core::vec;
+use core::local_data;
use extra::time;
use syntax::ast::ident;
use syntax::ast_map::{path, path_elt_to_str, path_name};
};
unsafe {
let llbb = str::as_c_str(cx.ccx.sess.str_of(s), |buf| {
- llvm::LLVMAppendBasicBlock(cx.llfn, buf)
+ llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf)
});
let bcx = mk_block(llbb,
parent,
// Creates the standard set of basic blocks for a function
pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks {
unsafe {
+ let cx = task_llcx();
BasicBlocks {
sa: str::as_c_str("static_allocas",
- |buf| llvm::LLVMAppendBasicBlock(llfn, buf)),
+ |buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)),
rt: str::as_c_str("return",
- |buf| llvm::LLVMAppendBasicBlock(llfn, buf))
+ |buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf))
}
}
}
};
let llbb = str::as_c_str("top", |buf| {
unsafe {
- llvm::LLVMAppendBasicBlock(llfn, buf)
+ llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
}
});
let bld = ccx.builder.B;
T_void()));
let memcpy32 =
decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i32",
- T_fn(copy T_memcpy32_args, T_void()));
+ T_fn(T_memcpy32_args, T_void()));
let memcpy64 =
decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i64",
- T_fn(copy T_memcpy64_args, T_void()));
+ T_fn(T_memcpy64_args, T_void()));
let memmove32 =
decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i32",
T_fn(T_memcpy32_args, T_void()));
let llmod_id = link_meta.name.to_owned() + ".rc";
unsafe {
+ if !llvm::LLVMRustStartMultithreading() {
+ sess.bug("couldn't enable multi-threaded LLVM");
+ }
+ let llcx = llvm::LLVMContextCreate();
+ set_task_llcx(llcx);
let llmod = str::as_c_str(llmod_id, |buf| {
- llvm::LLVMModuleCreateWithNameInContext
- (buf, llvm::LLVMGetGlobalContext())
+ llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
});
let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
let ccx = @CrateContext {
sess: sess,
llmod: llmod,
+ llcx: llcx,
td: td,
tn: tn,
externs: @mut HashMap::new(),
int_type: int_type,
float_type: float_type,
opaque_vec_type: T_opaque_vec(targ_cfg),
- builder: BuilderRef_res(unsafe { llvm::LLVMCreateBuilder() }),
+ builder: BuilderRef_res(unsafe {
+ llvm::LLVMCreateBuilderInContext(llcx)
+ }),
shape_cx: mk_ctxt(llmod),
crate_map: crate_map,
uses_gc: @mut false,
return (llmod, link_meta);
}
}
+
+fn task_local_llcx_key(_v: @ContextRef) {}
+
+pub fn task_llcx() -> ContextRef {
+ let opt = unsafe { local_data::local_data_get(task_local_llcx_key) };
+ *opt.expect("task-local LLVMContextRef wasn't ever set!")
+}
+
+fn set_task_llcx(c: ContextRef) {
+ unsafe {
+ local_data::local_data_set(task_local_llcx_key, @c);
+ }
+}
do vec::as_imm_buf([min, max]) |ptr, len| {
llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
- llvm::LLVMMDNode(ptr, len as c_uint));
+ llvm::LLVMMDNodeInContext(cx.fcx.ccx.llcx,
+ ptr, len as c_uint));
}
}
use lib::llvm::{Struct, Array, Attribute};
use lib::llvm::{StructRetAttribute};
use lib::llvm::True;
+use middle::trans::base::task_llcx;
use middle::trans::common::*;
use middle::trans::cabi::*;
let r = size % 32;
if r > 0 {
unsafe {
- args.push(llvm::LLVMIntType(r as c_uint))
+ args.push(llvm::LLVMIntTypeInContext(task_llcx(), r as c_uint))
}
}
str::as_c_str("load_env",
|buf|
unsafe {
- llvm::LLVMAppendBasicBlock(fcx.llfn, buf)
+ llvm::LLVMAppendBasicBlockInContext(fcx.ccx.llcx,
+ fcx.llfn,
+ buf)
});
fcx.llloadenv = Some(ll);
ll
use driver::session;
use driver::session::Session;
use lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef, BuilderRef};
-use lib::llvm::{True, False, Bool};
+use lib::llvm::{ContextRef, True, False, Bool};
use lib::llvm::{llvm, TargetData, TypeNames, associate_type, name_has_type};
use lib;
use metadata::common::LinkMeta;
pub struct CrateContext {
sess: session::Session,
llmod: ModuleRef,
+ llcx: ContextRef,
td: TargetData,
tn: @TypeNames,
externs: ExternMap,
// LLVM type constructors.
pub fn T_void() -> TypeRef {
- unsafe {
- return llvm::LLVMVoidType();
- }
+ unsafe { return llvm::LLVMVoidTypeInContext(base::task_llcx()); }
}
pub fn T_nil() -> TypeRef {
return T_struct([], false)
}
-pub fn T_metadata() -> TypeRef { unsafe { return llvm::LLVMMetadataType(); } }
+pub fn T_metadata() -> TypeRef {
+ unsafe { return llvm::LLVMMetadataTypeInContext(base::task_llcx()); }
+}
-pub fn T_i1() -> TypeRef { unsafe { return llvm::LLVMInt1Type(); } }
+pub fn T_i1() -> TypeRef {
+ unsafe { return llvm::LLVMInt1TypeInContext(base::task_llcx()); }
+}
-pub fn T_i8() -> TypeRef { unsafe { return llvm::LLVMInt8Type(); } }
+pub fn T_i8() -> TypeRef {
+ unsafe { return llvm::LLVMInt8TypeInContext(base::task_llcx()); }
+}
-pub fn T_i16() -> TypeRef { unsafe { return llvm::LLVMInt16Type(); } }
+pub fn T_i16() -> TypeRef {
+ unsafe { return llvm::LLVMInt16TypeInContext(base::task_llcx()); }
+}
-pub fn T_i32() -> TypeRef { unsafe { return llvm::LLVMInt32Type(); } }
+pub fn T_i32() -> TypeRef {
+ unsafe { return llvm::LLVMInt32TypeInContext(base::task_llcx()); }
+}
-pub fn T_i64() -> TypeRef { unsafe { return llvm::LLVMInt64Type(); } }
+pub fn T_i64() -> TypeRef {
+ unsafe { return llvm::LLVMInt64TypeInContext(base::task_llcx()); }
+}
-pub fn T_f32() -> TypeRef { unsafe { return llvm::LLVMFloatType(); } }
+pub fn T_f32() -> TypeRef {
+ unsafe { return llvm::LLVMFloatTypeInContext(base::task_llcx()); }
+}
-pub fn T_f64() -> TypeRef { unsafe { return llvm::LLVMDoubleType(); } }
+pub fn T_f64() -> TypeRef {
+ unsafe { return llvm::LLVMDoubleTypeInContext(base::task_llcx()); }
+}
pub fn T_bool() -> TypeRef { return T_i8(); }
pub fn T_fn(inputs: &[TypeRef], output: TypeRef) -> TypeRef {
unsafe {
return llvm::LLVMFunctionType(output, to_ptr(inputs),
- inputs.len() as c_uint,
- False);
+ inputs.len() as c_uint,
+ False);
}
}
pub fn T_struct(elts: &[TypeRef], packed: bool) -> TypeRef {
unsafe {
- return llvm::LLVMStructType(to_ptr(elts),
- elts.len() as c_uint,
- packed as Bool);
+ return llvm::LLVMStructTypeInContext(base::task_llcx(),
+ to_ptr(elts),
+ elts.len() as c_uint,
+ packed as Bool);
}
}
pub fn T_named_struct(name: &str) -> TypeRef {
unsafe {
- let c = llvm::LLVMGetGlobalContext();
- return str::as_c_str(name, |buf| llvm::LLVMStructCreateNamed(c, buf));
+ return str::as_c_str(name, |buf| {
+ llvm::LLVMStructCreateNamed(base::task_llcx(), buf)
+ });
}
}
}
let sc = do str::as_c_str(s) |buf| {
- llvm::LLVMConstString(buf, s.len() as c_uint, False)
+ llvm::LLVMConstStringInContext(cx.llcx, buf, s.len() as c_uint,
+ False)
};
let g =
str::as_c_str(fmt!("str%u", (cx.names)("str").name),
pub fn C_postr(s: &str) -> ValueRef {
unsafe {
return do str::as_c_str(s) |buf| {
- llvm::LLVMConstString(buf, s.len() as c_uint, False)
+ llvm::LLVMConstStringInContext(base::task_llcx(),
+ buf, s.len() as c_uint, False)
};
}
}
pub fn C_struct(elts: &[ValueRef]) -> ValueRef {
unsafe {
do vec::as_imm_buf(elts) |ptr, len| {
- llvm::LLVMConstStruct(ptr, len as c_uint, False)
+ llvm::LLVMConstStructInContext(base::task_llcx(),
+ ptr, len as c_uint, False)
}
}
}
pub fn C_packed_struct(elts: &[ValueRef]) -> ValueRef {
unsafe {
do vec::as_imm_buf(elts) |ptr, len| {
- llvm::LLVMConstStruct(ptr, len as c_uint, True)
+ llvm::LLVMConstStructInContext(base::task_llcx(),
+ ptr, len as c_uint, True)
}
}
}
pub fn C_array(ty: TypeRef, elts: &[ValueRef]) -> ValueRef {
unsafe {
return llvm::LLVMConstArray(ty, vec::raw::to_ptr(elts),
- elts.len() as c_uint);
+ elts.len() as c_uint);
}
}
pub fn C_bytes(bytes: &[u8]) -> ValueRef {
unsafe {
- return llvm::LLVMConstString(
+ return llvm::LLVMConstStringInContext(base::task_llcx(),
cast::transmute(vec::raw::to_ptr(bytes)),
bytes.len() as c_uint, True);
}
pub fn C_bytes_plus_null(bytes: &[u8]) -> ValueRef {
unsafe {
- return llvm::LLVMConstString(
+ return llvm::LLVMConstStringInContext(base::task_llcx(),
cast::transmute(vec::raw::to_ptr(bytes)),
bytes.len() as c_uint, False);
}
use driver::session;
use lib::llvm::ValueRef;
use lib::llvm::llvm;
+use middle::trans::base::task_llcx;
use middle::trans::common::*;
use middle::trans::machine;
use middle::trans::type_of;
fn llstr(s: &str) -> ValueRef {
do str::as_c_str(s) |sbuf| {
unsafe {
- llvm::LLVMMDString(sbuf, s.len() as libc::c_uint)
+ llvm::LLVMMDStringInContext(task_llcx(),
+ sbuf,
+ s.len() as libc::c_uint)
}
}
}
}
fn llmdnode(elems: &[ValueRef]) -> ValueRef {
unsafe {
- llvm::LLVMMDNode(vec::raw::to_ptr(elems), elems.len() as libc::c_uint)
+ llvm::LLVMMDNodeInContext(task_llcx(),
+ vec::raw::to_ptr(elems),
+ elems.len() as libc::c_uint)
}
}
fn llunused() -> ValueRef {
if output_is_immediate {
T_fn(atys, lloutputtype)
} else {
- T_fn(atys, llvm::LLVMVoidType())
+ T_fn(atys, llvm::LLVMVoidTypeInContext(cx.llcx))
}
}
}
fn f() {}
f()
");
+
+ debug!("regression test for #5803");
+ run_cmds(["spawn( || println(\"Please don't segfault\") );",
+ "do spawn { println(\"Please?\"); }"]);
}
}
return true;
}
-extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(const char *Filename) {
+extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(LLVMContextRef C,
+ const char *Filename) {
SMDiagnostic d;
- Module *m = ParseAssemblyFile(Filename, d, getGlobalContext());
+ Module *m = ParseAssemblyFile(Filename, d, *unwrap(C));
if (m) {
return wrap(m);
} else {
extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) {
return wrap(Type::getMetadataTy(*unwrap(C)));
}
-extern "C" LLVMTypeRef LLVMMetadataType(void) {
- return LLVMMetadataTypeInContext(LLVMGetGlobalContext());
-}
extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B,
LLVMValueRef source,
Constraints, HasSideEffects,
IsAlignStack, (InlineAsm::AsmDialect) Dialect));
}
+
+/**
+ * This function is intended to be a threadsafe interface into enabling a
+ * multithreaded LLVM. This is invoked at the start of the translation phase of
+ * compilation to ensure that LLVM is ready.
+ *
+ * All of trans properly isolates LLVM with the use of a different
+ * LLVMContextRef per task, thus allowing parallel compilation of different
+ * crates in the same process. At the time of this writing, the use case for
+ * this is unit tests for rusti, but there are possible other applications.
+ */
+extern "C" bool LLVMRustStartMultithreading() {
+ static Mutex lock;
+ bool ret = true;
+ assert(lock.acquire());
+ if (!LLVMIsMultithreaded()) {
+ ret = LLVMStartMultithreaded();
+ }
+ assert(lock.release());
+ return ret;
+}
LLVMRustParseBitcode
LLVMRustParseAssemblyFile
LLVMRustPrintPassTimings
+LLVMRustStartMultithreading
LLVMCreateObjectFile
LLVMDisposeObjectFile
LLVMGetSections
LLVMGetFunctionCallConv
LLVMGetGC
LLVMGetGlobalContext
-LLVMGetGlobalContext
LLVMGetGlobalParent
LLVMGetGlobalPassRegistry
LLVMGetIncomingBlock
LLVMMDNodeInContext
LLVMMDString
LLVMMDStringInContext
-LLVMMetadataType
LLVMMetadataTypeInContext
LLVMModuleCreateWithName
LLVMModuleCreateWithNameInContext