Skip to content

Cleanup and document -Z tls-model #71558

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 28, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/doc/unstable-book/src/compiler-flags/tls-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# `tls_model`

The tracking issue for this feature is: None.

------------------------

Option `-Z tls-model` controls [TLS model](https://www.akkadia.org/drepper/tls.pdf) used to
generate code for accessing `#[thread_local]` `static` items.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically speaking, the TLS model is supposed to be a per-variable attribute rather than a global one. However we don't currently have such an attribute, only a global setting which sets the default TLS model for all variables.


Supported values for this option are:

- `global-dynamic` - General Dynamic TLS Model (alternatively called Global Dynamic) is the most
general option usable in all circumstances, even if the TLS data is defined in a shared library
loaded at runtime and is accessed from code outside of that library.
This is the default for most targets.
- `local-dynamic` - model usable if the TLS data is only accessed from the shared library or
executable it is defined in. The TLS data may be in a library loaded after startup (via `dlopen`).
- `initial-exec` - model usable if the TLS data is defined in the executable or in a shared library
loaded at program startup.
The TLS data must not be in a library loaded after startup (via `dlopen`).
- `local-exec` - model usable only if the TLS data is defined directly in the executable,
but not in a shared library, and is accessed only from that executable.

`rustc` and LLVM may use a more optimized model than specified if they know that we are producing
and executable rather than a library, or that the `static` item is private enough.
7 changes: 0 additions & 7 deletions src/librustc_codegen_llvm/back/write.rs
Original file line number Diff line number Diff line change
@@ -43,13 +43,6 @@ pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[
("large", llvm::CodeModel::Large),
];

pub const TLS_MODEL_ARGS: [(&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: &rustc_errors::Handler, msg: &str) -> FatalError {
match llvm::last_error() {
Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
23 changes: 8 additions & 15 deletions src/librustc_codegen_llvm/context.rs
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ use rustc_session::Session;
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_span::symbol::Symbol;
use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_target::spec::{HasTargetSpec, RelocModel, Target};
use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};

use std::cell::{Cell, RefCell};
use std::ffi::CStr;
@@ -87,19 +87,12 @@ pub struct CodegenCx<'ll, 'tcx> {
local_gen_sym_counter: Cell<usize>,
}

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 crate::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 to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
match tls_model {
TlsModel::GeneralDynamic => llvm::ThreadLocalMode::GeneralDynamic,
TlsModel::LocalDynamic => llvm::ThreadLocalMode::LocalDynamic,
TlsModel::InitialExec => llvm::ThreadLocalMode::InitialExec,
TlsModel::LocalExec => llvm::ThreadLocalMode::LocalExec,
}
}

@@ -267,7 +260,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {

let check_overflow = tcx.sess.overflow_checks();

let tls_model = get_tls_model(&tcx.sess);
let tls_model = to_llvm_tls_model(tcx.sess.tls_model());

let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod());

2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/lib.rs
Original file line number Diff line number Diff line change
@@ -216,7 +216,7 @@ impl CodegenBackend for LlvmCodegenBackend {
}
PrintRequest::TlsModels => {
println!("Available TLS models:");
for &(name, _) in back::write::TLS_MODEL_ARGS.iter() {
for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
println!(" {}", name);
}
println!();
5 changes: 3 additions & 2 deletions src/librustc_interface/tests.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,8 @@ use rustc_session::{build_session, Session};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelocModel, RelroLevel};
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy};
use rustc_target::spec::{RelocModel, RelroLevel, TlsModel};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
use std::path::PathBuf;
@@ -567,7 +568,7 @@ fn test_debugging_options_tracking_hash() {
tracked!(symbol_mangling_version, SymbolManglingVersion::V0);
tracked!(teach, true);
tracked!(thinlto, Some(true));
tracked!(tls_model, Some(String::from("tls model")));
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
tracked!(treat_err_as_bug, Some(1));
tracked!(unleash_the_miri_inside_of_you, true);
tracked!(verify_llvm_ir, true);
8 changes: 3 additions & 5 deletions src/librustc_session/config.rs
Original file line number Diff line number Diff line change
@@ -1315,10 +1315,6 @@ fn collect_print_requests(
prints.push(PrintRequest::CodeModels);
cg.code_model = None;
}
if dopts.tls_model.as_ref().map_or(false, |s| s == "help") {
prints.push(PrintRequest::TlsModels);
dopts.tls_model = None;
}

prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
"crate-name" => PrintRequest::CrateName,
@@ -2001,7 +1997,8 @@ crate mod dep_tracking {
use crate::utils::NativeLibraryKind;
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_target::spec::{MergeFunctions, PanicStrategy, RelocModel, RelroLevel, TargetTriple};
use rustc_target::spec::{MergeFunctions, PanicStrategy, RelocModel};
use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::hash::Hash;
@@ -2050,6 +2047,7 @@ crate mod dep_tracking {
impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
15 changes: 13 additions & 2 deletions src/librustc_session/options.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,8 @@ use crate::search_paths::SearchPath;
use crate::utils::NativeLibraryKind;

use rustc_target::spec::TargetTriple;
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelocModel, RelroLevel};
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy};
use rustc_target::spec::{RelocModel, RelroLevel, TlsModel};

use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
@@ -267,6 +268,8 @@ macro_rules! options {
pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
pub const parse_relocation_model: &str =
"one of supported relocation models (`rustc --print relocation-models`)";
pub const parse_tls_model: &str =
"one of supported TLS models (`rustc --print tls-models`)";
}

#[allow(dead_code)]
@@ -606,6 +609,14 @@ macro_rules! options {
true
}

fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
match v.and_then(|s| TlsModel::from_str(s).ok()) {
Some(tls_model) => *slot = Some(tls_model),
_ => return false,
}
true
}

fn parse_symbol_mangling_version(
slot: &mut SymbolManglingVersion,
v: Option<&str>,
@@ -977,7 +988,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"measure time of each LLVM pass (default: no)"),
time_passes: bool = (false, parse_bool, [UNTRACKED],
"measure time of each rustc pass (default: no)"),
tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
"choose the TLS model to use (`rustc --print tls-models` for details)"),
trace_macros: bool = (false, parse_bool, [UNTRACKED],
"for every macro invocation, print its name and arguments (default: no)"),
6 changes: 5 additions & 1 deletion src/librustc_session/session.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported
use rustc_span::edition::Edition;
use rustc_span::source_map::{self, FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target, TargetTriple};
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target, TargetTriple, TlsModel};

use std::cell::{self, RefCell};
use std::env;
@@ -588,6 +588,10 @@ impl Session {
self.opts.cg.relocation_model.unwrap_or(self.target.target.options.relocation_model)
}

pub fn tls_model(&self) -> TlsModel {
self.opts.debugging_opts.tls_model.unwrap_or(self.target.target.options.tls_model)
}

pub fn must_not_eliminate_frame_pointers(&self) -> bool {
// "mcount" function relies on stack pointer.
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
4 changes: 2 additions & 2 deletions src/librustc_target/spec/cloudabi_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions, TlsModel};

pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
@@ -29,7 +29,7 @@ pub fn opts() -> TargetOptions {
// (Global Offset Table) to obtain the effective address of a
// thread-local variable. Using a GOT is useful only when doing
// dynamic linking.
tls_model: "local-exec".to_string(),
tls_model: TlsModel::LocalExec,
relro_level: RelroLevel::Full,
..Default::default()
}
5 changes: 3 additions & 2 deletions src/librustc_target/spec/hermit_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions};
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy};
use crate::spec::{RelocModel, TargetOptions, TlsModel};

pub fn opts() -> TargetOptions {
let mut pre_link_args = LinkArgs::new();
@@ -17,7 +18,7 @@ pub fn opts() -> TargetOptions {
position_independent_executables: true,
relocation_model: RelocModel::Static,
target_family: None,
tls_model: "initial-exec".to_string(),
tls_model: TlsModel::InitialExec,
..Default::default()
}
}
5 changes: 3 additions & 2 deletions src/librustc_target/spec/hermit_kernel_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions};
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy};
use crate::spec::{RelocModel, TargetOptions, TlsModel};

pub fn opts() -> TargetOptions {
let mut pre_link_args = LinkArgs::new();
@@ -18,7 +19,7 @@ pub fn opts() -> TargetOptions {
position_independent_executables: true,
relocation_model: RelocModel::Static,
target_family: None,
tls_model: "initial-exec".to_string(),
tls_model: TlsModel::InitialExec,
..Default::default()
}
}
54 changes: 51 additions & 3 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
@@ -305,6 +305,42 @@ impl ToJson for RelocModel {
}
}

#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum TlsModel {
GeneralDynamic,
LocalDynamic,
InitialExec,
LocalExec,
}

impl FromStr for TlsModel {
type Err = ();

fn from_str(s: &str) -> Result<TlsModel, ()> {
Ok(match s {
// Note the difference "general" vs "global" difference. The model name is "general",
// but the user-facing option name is "global" for consistency with other compilers.
"global-dynamic" => TlsModel::GeneralDynamic,
"local-dynamic" => TlsModel::LocalDynamic,
"initial-exec" => TlsModel::InitialExec,
"local-exec" => TlsModel::LocalExec,
_ => return Err(()),
})
}
}

impl ToJson for TlsModel {
fn to_json(&self) -> Json {
match *self {
TlsModel::GeneralDynamic => "global-dynamic",
TlsModel::LocalDynamic => "local-dynamic",
TlsModel::InitialExec => "initial-exec",
TlsModel::LocalExec => "local-exec",
}
.to_json()
}
}

pub enum LoadTargetError {
BuiltinTargetNotFound(String),
Other(String),
@@ -660,7 +696,7 @@ pub struct TargetOptions {
pub code_model: Option<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,
pub tls_model: TlsModel,
/// 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.
@@ -863,7 +899,7 @@ impl Default for TargetOptions {
executables: false,
relocation_model: RelocModel::Pic,
code_model: None,
tls_model: "global-dynamic".to_string(),
tls_model: TlsModel::GeneralDynamic,
disable_redzone: false,
eliminate_frame_pointer: true,
function_sections: true,
@@ -1060,6 +1096,18 @@ impl Target {
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, TlsModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
match s.parse::<TlsModel>() {
Ok(tls_model) => base.options.$key_name = tls_model,
_ => return Some(Err(format!("'{}' is not a valid TLS model. \
Run `rustc --print tls-models` to \
see the list of supported values.", s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, PanicStrategy) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
@@ -1200,7 +1248,7 @@ impl Target {
key!(executables, bool);
key!(relocation_model, RelocModel)?;
key!(code_model, optional);
key!(tls_model);
key!(tls_model, TlsModel)?;
key!(disable_redzone, bool);
key!(eliminate_frame_pointer, bool);
key!(function_sections, bool);
4 changes: 2 additions & 2 deletions src/librustc_target/spec/wasm32_base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions};
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel};
use std::collections::BTreeMap;

pub fn options() -> TargetOptions {
@@ -138,7 +138,7 @@ pub fn options() -> TargetOptions {
// `has_elf_tls`) and we need to get it to work by specifying
// `local-exec` as that's all that's implemented in LLVM today for wasm.
has_elf_tls: true,
tls_model: "local-exec".to_string(),
tls_model: TlsModel::LocalExec,

// gdb scripts don't work on wasm blobs
emit_debug_gdb_scripts: false,