Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 608f324

Browse files
committed
Auto merge of rust-lang#117873 - quininer:android-emutls, r=Amanieu
Add emulated TLS support This is a reopen of rust-lang#96317 . many android devices still only use 128 pthread keys, so using emutls can be helpful. Currently LLVM uses emutls by default for some targets (such as android, openbsd), but rust does not use it, because `has_thread_local` is false. This commit has some changes to allow users to enable emutls: 1. add `-Zhas-thread-local` flag to specify that std uses `#[thread_local]` instead of pthread key. 2. when using emutls, decorate symbol names to find thread local symbol correctly. 3. change `-Zforce-emulated-tls` to `-Ztls-model=emulated` to explicitly specify whether to generate emutls. r? `@Amanieu`
2 parents 1a3aa4a + e5b7689 commit 608f324

File tree

17 files changed

+71
-28
lines changed

17 files changed

+71
-28
lines changed

compiler/rustc_codegen_gcc/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,5 +569,6 @@ fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
569569
TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
570570
TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
571571
TlsModel::LocalExec => gccjit::TlsModel::LocalExec,
572+
TlsModel::Emulated => gccjit::TlsModel::GlobalDynamic,
572573
}
573574
}

compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl OwnedTargetMachine {
3939
split_dwarf_file: &CStr,
4040
output_obj_file: &CStr,
4141
debug_info_compression: &CStr,
42-
force_emulated_tls: bool,
42+
use_emulated_tls: bool,
4343
args_cstr_buff: &[u8],
4444
) -> Result<Self, LlvmError<'static>> {
4545
assert!(args_cstr_buff.len() > 0);
@@ -71,7 +71,7 @@ impl OwnedTargetMachine {
7171
split_dwarf_file.as_ptr(),
7272
output_obj_file.as_ptr(),
7373
debug_info_compression.as_ptr(),
74-
force_emulated_tls,
74+
use_emulated_tls,
7575
args_cstr_buff.as_ptr() as *const c_char,
7676
args_cstr_buff.len(),
7777
)

compiler/rustc_codegen_llvm/src/back/write.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, Switc
3333
use rustc_session::Session;
3434
use rustc_span::symbol::sym;
3535
use rustc_span::InnerSpan;
36-
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo};
36+
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
3737

3838
use crate::llvm::diagnostic::OptimizationDiagnosticKind;
3939
use libc::{c_char, c_int, c_uint, c_void, size_t};
@@ -223,7 +223,7 @@ pub fn target_machine_factory(
223223

224224
let path_mapping = sess.source_map().path_mapping().clone();
225225

226-
let force_emulated_tls = sess.target.force_emulated_tls;
226+
let use_emulated_tls = matches!(sess.tls_model(), TlsModel::Emulated);
227227

228228
// copy the exe path, followed by path all into one buffer
229229
// null terminating them so we can use them as null terminated strings
@@ -297,7 +297,7 @@ pub fn target_machine_factory(
297297
&split_dwarf_file,
298298
&output_obj_file,
299299
&debuginfo_compression,
300-
force_emulated_tls,
300+
use_emulated_tls,
301301
&args_cstr_buff,
302302
)
303303
})

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
120120
TlsModel::LocalDynamic => llvm::ThreadLocalMode::LocalDynamic,
121121
TlsModel::InitialExec => llvm::ThreadLocalMode::InitialExec,
122122
TlsModel::LocalExec => llvm::ThreadLocalMode::LocalExec,
123+
TlsModel::Emulated => llvm::ThreadLocalMode::GeneralDynamic,
123124
}
124125
}
125126

compiler/rustc_codegen_llvm/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,9 @@ impl CodegenBackend for LlvmCodegenBackend {
306306
}
307307
PrintKind::TlsModels => {
308308
writeln!(out, "Available TLS models:");
309-
for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
309+
for name in
310+
&["global-dynamic", "local-dynamic", "initial-exec", "local-exec", "emulated"]
311+
{
310312
writeln!(out, " {name}");
311313
}
312314
writeln!(out);

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2159,7 +2159,7 @@ extern "C" {
21592159
SplitDwarfFile: *const c_char,
21602160
OutputObjFile: *const c_char,
21612161
DebugInfoCompression: *const c_char,
2162-
ForceEmulatedTls: bool,
2162+
UseEmulatedTls: bool,
21632163
ArgsCstrBuff: *const c_char,
21642164
ArgsCstrBuffLen: usize,
21652165
) -> *mut TargetMachine;

compiler/rustc_codegen_ssa/src/back/linker.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1748,7 +1748,9 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
17481748
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
17491749
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
17501750
if info.level.is_below_threshold(export_threshold) {
1751-
symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
1751+
symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
1752+
tcx, symbol, cnum,
1753+
));
17521754
}
17531755
});
17541756

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_middle::ty::{self, SymbolName, TyCtxt};
1616
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
1717
use rustc_middle::util::Providers;
1818
use rustc_session::config::{CrateType, OomStrategy};
19-
use rustc_target::spec::SanitizerSet;
19+
use rustc_target::spec::{SanitizerSet, TlsModel};
2020

2121
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
2222
crates_export_threshold(tcx.crate_types())
@@ -564,6 +564,12 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
564564

565565
let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
566566

567+
// thread local will not be a function call,
568+
// so it is safe to return before windows symbol decoration check.
569+
if let Some(name) = maybe_emutls_symbol_name(tcx, symbol, &undecorated) {
570+
return name;
571+
}
572+
567573
let target = &tcx.sess.target;
568574
if !target.is_like_windows {
569575
// Mach-O has a global "_" suffix and `object` crate will handle it.
@@ -624,6 +630,32 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
624630
format!("{prefix}{undecorated}{suffix}{args_in_bytes}")
625631
}
626632

633+
pub fn exporting_symbol_name_for_instance_in_crate<'tcx>(
634+
tcx: TyCtxt<'tcx>,
635+
symbol: ExportedSymbol<'tcx>,
636+
cnum: CrateNum,
637+
) -> String {
638+
let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, cnum);
639+
maybe_emutls_symbol_name(tcx, symbol, &undecorated).unwrap_or(undecorated)
640+
}
641+
642+
fn maybe_emutls_symbol_name<'tcx>(
643+
tcx: TyCtxt<'tcx>,
644+
symbol: ExportedSymbol<'tcx>,
645+
undecorated: &str,
646+
) -> Option<String> {
647+
if matches!(tcx.sess.tls_model(), TlsModel::Emulated)
648+
&& let ExportedSymbol::NonGeneric(def_id) = symbol
649+
&& tcx.is_thread_local_static(def_id)
650+
{
651+
// When using emutls, LLVM will add the `__emutls_v.` prefix to thread local symbols,
652+
// and exported symbol name need to match this.
653+
Some(format!("__emutls_v.{undecorated}"))
654+
} else {
655+
None
656+
}
657+
}
658+
627659
fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> {
628660
// Build up a map from DefId to a `NativeLib` structure, where
629661
// `NativeLib` internally contains information about

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
410410
const char *SplitDwarfFile,
411411
const char *OutputObjFile,
412412
const char *DebugInfoCompression,
413-
bool ForceEmulatedTls,
413+
bool UseEmulatedTls,
414414
const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
415415

416416
auto OptLevel = fromRust(RustOptLevel);
@@ -456,13 +456,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
456456
Options.UseInitArray = UseInitArray;
457457

458458
#if LLVM_VERSION_LT(17, 0)
459-
if (ForceEmulatedTls) {
460-
Options.ExplicitEmulatedTLS = true;
461-
Options.EmulatedTLS = true;
462-
}
463-
#else
464-
Options.EmulatedTLS = ForceEmulatedTls || Trip.hasDefaultEmulatedTLS();
459+
Options.ExplicitEmulatedTLS = true;
465460
#endif
461+
Options.EmulatedTLS = UseEmulatedTls;
466462

467463
if (TrapUnreachable) {
468464
// Tell LLVM to codegen `unreachable` into an explicit trap instruction.

compiler/rustc_session/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,7 @@ fn default_configuration(sess: &Session) -> Cfg {
12831283
ret.insert((sym::relocation_model, Some(relocation_model)));
12841284
}
12851285
ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
1286-
if sess.target.has_thread_local {
1286+
if sess.opts.unstable_opts.has_thread_local.unwrap_or(sess.target.has_thread_local) {
12871287
ret.insert((sym::target_thread_local, None));
12881288
}
12891289
let mut has_atomic = false;

0 commit comments

Comments
 (0)