diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 0f8312abc3f..d1d04e883b8 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -368,6 +368,7 @@ pub enum PrintRequest { TargetFeatures, RelocationModels, CodeModels, + TlsModels, TargetSpec, NativeStaticLibs, } @@ -910,6 +911,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "choose the relocation model to use (rustc --print relocation-models for details)"), code_model: Option = (None, parse_opt_string, [TRACKED], "choose the code model to use (rustc --print code-models for details)"), + tls_model: Option = (None, parse_opt_string, [TRACKED], + "choose the TLS model to use (rustc --print tls-models for details)"), metadata: Vec = (Vec::new(), parse_list, [TRACKED], "metadata to mangle symbol names with"), extra_filename: String = ("".to_string(), parse_string, [UNTRACKED], @@ -1330,7 +1333,7 @@ pub fn rustc_short_optgroups() -> Vec { print on stdout", "[crate-name|file-names|sysroot|cfg|target-list|\ target-cpus|target-features|relocation-models|\ - code-models|target-spec-json|native-static-libs]"), + code-models|tls-models|target-spec-json|native-static-libs]"), opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), opt::opt_s("o", "", "Write output to ", "FILENAME"), @@ -1573,6 +1576,10 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) prints.push(PrintRequest::CodeModels); cg.code_model = None; } + if cg.tls_model.as_ref().map_or(false, |s| s == "help") { + prints.push(PrintRequest::TlsModels); + cg.tls_model = None; + } let cg = cg; @@ -1672,6 +1679,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) "target-features" => PrintRequest::TargetFeatures, "relocation-models" => PrintRequest::RelocationModels, "code-models" => PrintRequest::CodeModels, + "tls-models" => PrintRequest::TlsModels, "native-static-libs" => PrintRequest::NativeStaticLibs, "target-spec-json" => { if nightly_options::is_unstable_enabled(matches) { @@ -2514,6 +2522,10 @@ mod tests { opts.cg.code_model = Some(String::from("code model")); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + opts = reference.clone(); + opts.cg.tls_model = Some(String::from("tls model")); + assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + opts = reference.clone(); opts.cg.metadata = vec![String::from("A"), String::from("B")]; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fc503f4eb4b..c5cce70c945 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -177,6 +177,7 @@ mod rustc_trans { pub mod write { pub const RELOC_MODEL_ARGS: [(&'static str, ()); 0] = []; pub const CODE_GEN_MODEL_ARGS: [(&'static str, ()); 0] = []; + pub const TLS_MODEL_ARGS: [(&'static str, ()); 0] = []; } } } @@ -797,6 +798,13 @@ impl RustcDefaultCalls { } println!(""); } + PrintRequest::TlsModels => { + println!("Available TLS models:"); + for &(name, _) in rustc_trans::back::write::TLS_MODEL_ARGS.iter(){ + println!(" {}", name); + } + println!(""); + } PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => { rustc_trans::print(*req, sess); } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 3399bf2acd8..ac0e4dde0c1 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -359,6 +359,17 @@ pub struct ThinLTOModule { pub len: usize, } +/// LLVMThreadLocalMode +#[derive(Copy, Clone)] +#[repr(C)] +pub enum ThreadLocalMode { + NotThreadLocal, + GeneralDynamic, + LocalDynamic, + InitialExec, + LocalExec +} + // Opaque pointer types #[allow(missing_copy_implementations)] pub enum Module_opaque {} @@ -709,6 +720,7 @@ extern "C" { pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef; pub fn LLVMSetInitializer(GlobalVar: ValueRef, ConstantVal: ValueRef); pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); + pub fn LLVMSetThreadLocalMode(GlobalVar: ValueRef, Mode: ThreadLocalMode); pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 98172bca177..5ccce8de706 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -172,6 +172,11 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) { LLVMSetThreadLocal(global, is_thread_local as Bool); } } +pub fn set_thread_local_mode(global: ValueRef, mode: ThreadLocalMode) { + unsafe { + LLVMSetThreadLocalMode(global, mode); + } +} impl Attribute { pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 6153d3dcdbb..3d923922bb1 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -76,6 +76,13 @@ pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [ ("large", llvm::CodeModel::Large), ]; +pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [ + ("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic), + ("local-dynamic", llvm::ThreadLocalMode::LocalDynamic), + ("initial-exec", llvm::ThreadLocalMode::InitialExec), + ("local-exec", llvm::ThreadLocalMode::LocalExec), +]; + pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError { match llvm::last_error() { Some(err) => handler.fatal(&format!("{}: {}", msg, err)), diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index eaf7392aab5..0f5ede91c7d 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -23,6 +23,7 @@ use monomorphize::Instance; use type_::Type; use type_of; use rustc::ty; +use context::get_tls_model; use rustc::hir; @@ -196,7 +197,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { for attr in attrs { if attr.check_name("thread_local") { - llvm::set_thread_local(g, true); + llvm::set_thread_local_mode(g, get_tls_model(ccx.sess())); } } @@ -215,7 +216,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { // symbol and another one doesn't. for attr in ccx.tcx().get_attrs(def_id).iter() { if attr.check_name("thread_local") { - llvm::set_thread_local(g, true); + llvm::set_thread_local_mode(g, get_tls_model(ccx.sess())); } } if ccx.use_dll_storage_attrs() && !ccx.tcx().is_foreign_item(def_id) { @@ -305,9 +306,8 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debuginfo::create_global_var_metadata(ccx, id, g); - if attr::contains_name(attrs, - "thread_local") { - llvm::set_thread_local(g, true); + if attr::contains_name(attrs, "thread_local") { + llvm::set_thread_local_mode(g, get_tls_model(ccx.sess())); } base::set_link_section(ccx, g, attrs); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index cd9cb8c0df5..afdbc31c456 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -166,6 +166,24 @@ pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { } } +pub fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode { + let tls_model_arg = match sess.opts.cg.tls_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.tls_model[..], + }; + + match ::back::write::TLS_MODEL_ARGS.iter().find( + |&&arg| arg.0 == tls_model_arg) { + Some(x) => x.1, + _ => { + sess.err(&format!("{:?} is not a valid TLS model", + tls_model_arg)); + sess.abort_if_errors(); + bug!(); + } + } +} + fn is_any_library(sess: &Session) -> bool { sess.crate_types.borrow().iter().any(|ty| { *ty != config::CrateTypeExecutable