diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 0f8312abc3f9f..558761256d2a9 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, } @@ -1104,6 +1105,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable ThinLTO when possible"), inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], "control whether #[inline] functions are in all cgus"), + tls_model: Option = (None, parse_opt_string, [TRACKED], + "choose the TLS model to use (rustc --print tls-models for details)"), } pub fn default_lib_output() -> CrateType { @@ -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"), @@ -1472,7 +1475,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) }) }); - let debugging_opts = build_debugging_options(matches, error_format); + let mut debugging_opts = build_debugging_options(matches, error_format); let mut output_types = BTreeMap::new(); if !debugging_opts.parse_only { @@ -1573,6 +1576,10 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) prints.push(PrintRequest::CodeModels); cg.code_model = None; } + if debugging_opts.tls_model.as_ref().map_or(false, |s| s == "help") { + prints.push(PrintRequest::TlsModels); + debugging_opts.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.debugging_opts.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_back/target/mod.rs b/src/librustc_back/target/mod.rs index a56d067815819..8fd4aad89c643 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -311,6 +311,9 @@ pub struct TargetOptions { pub relocation_model: String, /// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default". pub code_model: String, + /// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec" + /// and "local-exec". This is similar to the -ftls-model option in GCC/Clang. + pub tls_model: String, /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false. pub disable_redzone: bool, /// Eliminate frame pointers from stack frames if possible. Defaults to true. @@ -450,6 +453,7 @@ impl Default for TargetOptions { executables: false, relocation_model: "pic".to_string(), code_model: "default".to_string(), + tls_model: "global-dynamic".to_string(), disable_redzone: false, eliminate_frame_pointer: true, function_sections: true, @@ -696,6 +700,7 @@ impl Target { key!(executables, bool); key!(relocation_model); key!(code_model); + key!(tls_model); key!(disable_redzone, bool); key!(eliminate_frame_pointer, bool); key!(function_sections, bool); @@ -888,6 +893,7 @@ impl ToJson for Target { target_option_val!(executables); target_option_val!(relocation_model); target_option_val!(code_model); + target_option_val!(tls_model); target_option_val!(disable_redzone); target_option_val!(eliminate_frame_pointer); target_option_val!(function_sections); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fc503f4eb4be1..c5cce70c94566 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 3399bf2acd891..ac0e4dde0c102 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 98172bca17786..5ccce8de70639 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 5550ab9fa55e6..3d923922bb1cf 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)), @@ -173,9 +180,7 @@ pub fn target_machine_factory(sess: &Session) Some(x) => x.1, _ => { sess.err(&format!("{:?} is not a valid code model", - sess.opts - .cg - .code_model)); + code_model_arg)); sess.abort_if_errors(); bug!(); } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index eaf7392aab5b4..4ae289cfada00 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -196,7 +196,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, ccx.tls_model()); } } @@ -215,7 +215,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, ccx.tls_model()); } } if ccx.use_dll_storage_attrs() && !ccx.tcx().is_foreign_item(def_id) { @@ -305,9 +305,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, ccx.tls_model()); } base::set_link_section(ccx, g, attrs); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 9df057c77a95d..cb71ef104d3d9 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -52,6 +52,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, check_overflow: bool, use_dll_storage_attrs: bool, + tls_model: llvm::ThreadLocalMode, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -159,9 +160,25 @@ pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { Some(x) => x.1, _ => { sess.err(&format!("{:?} is not a valid relocation mode", - sess.opts - .cg - .code_model)); + reloc_model_arg)); + sess.abort_if_errors(); + bug!(); + } + } +} + +fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode { + let tls_model_arg = match sess.opts.debugging_opts.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!(); } @@ -283,10 +300,13 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { let check_overflow = tcx.sess.overflow_checks(); + let tls_model = get_tls_model(&tcx.sess); + SharedCrateContext { tcx, check_overflow, use_dll_storage_attrs, + tls_model, } } @@ -528,6 +548,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.shared.use_dll_storage_attrs() } + pub fn tls_model(&self) -> llvm::ThreadLocalMode { + self.shared.tls_model + } + /// Generate a new symbol name with the given prefix. This symbol name must /// only be used for definitions with `internal` or `private` linkage. pub fn generate_local_symbol_name(&self, prefix: &str) -> String {