summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_ssa/src/back
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_codegen_ssa/src/back
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs92
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs48
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs96
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs38
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath/tests.rs35
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs59
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs359
7 files changed, 379 insertions, 348 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index b603a8787..a7ac728c5 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -12,8 +12,8 @@ use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, Strip};
-use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, OutFileName, Strip};
+use rustc_session::config::{OutputFilenames, OutputType, PrintKind, SplitDwarfKind};
use rustc_session::cstore::DllImport;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
use rustc_session::search_paths::PathKind;
@@ -69,7 +69,7 @@ pub fn link_binary<'a>(
let _timer = sess.timer("link_binary");
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new();
- for &crate_type in sess.crate_types().iter() {
+ for &crate_type in &codegen_results.crate_info.crate_types {
// Ignore executable crates if we have -Z no-codegen, as they will error.
if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen())
&& !output_metadata
@@ -596,8 +596,10 @@ fn link_staticlib<'a>(
all_native_libs.extend_from_slice(&codegen_results.crate_info.used_libraries);
- if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) {
- print_native_static_libs(sess, &all_native_libs, &all_rust_dylibs);
+ for print in &sess.opts.prints {
+ if print.kind == PrintKind::NativeStaticLibs {
+ print_native_static_libs(sess, &print.out, &all_native_libs, &all_rust_dylibs);
+ }
}
Ok(())
@@ -744,8 +746,11 @@ fn link_natively<'a>(
cmd.env_remove(k.as_ref());
}
- if sess.opts.prints.contains(&PrintRequest::LinkArgs) {
- println!("{:?}", &cmd);
+ for print in &sess.opts.prints {
+ if print.kind == PrintKind::LinkArgs {
+ let content = format!("{cmd:?}");
+ print.out.overwrite(&content, sess);
+ }
}
// May have not found libraries in the right formats.
@@ -1231,22 +1236,21 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
}
}
- let channel = option_env!("CFG_RELEASE_CHANNEL")
- .map(|channel| format!("-{}", channel))
- .unwrap_or_default();
+ let channel =
+ option_env!("CFG_RELEASE_CHANNEL").map(|channel| format!("-{channel}")).unwrap_or_default();
if sess.target.is_like_osx {
// On Apple platforms, the sanitizer is always built as a dylib, and
// LLVM will link to `@rpath/*.dylib`, so we need to specify an
// rpath to the library as well (the rpath should be absolute, see
// PR #41352 for details).
- let filename = format!("rustc{}_rt.{}", channel, name);
+ let filename = format!("rustc{channel}_rt.{name}");
let path = find_sanitizer_runtime(&sess, &filename);
let rpath = path.to_str().expect("non-utf8 component in path");
linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
linker.link_dylib(&filename, false, true);
} else {
- let filename = format!("librustc{}_rt.{}.a", channel, name);
+ let filename = format!("librustc{channel}_rt.{name}.a");
let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
linker.link_whole_rlib(&path);
}
@@ -1386,12 +1390,18 @@ enum RlibFlavor {
fn print_native_static_libs(
sess: &Session,
+ out: &OutFileName,
all_native_libs: &[NativeLib],
all_rust_dylibs: &[&Path],
) {
let mut lib_args: Vec<_> = all_native_libs
.iter()
.filter(|l| relevant_lib(sess, l))
+ // Deduplication of successive repeated libraries, see rust-lang/rust#113209
+ //
+ // note: we don't use PartialEq/Eq because NativeLib transitively depends on local
+ // elements like spans, which we don't care about and would make the deduplication impossible
+ .dedup_by(|l1, l2| l1.name == l2.name && l1.kind == l2.kind && l1.verbatim == l2.verbatim)
.filter_map(|lib| {
let name = lib.name;
match lib.kind {
@@ -1404,12 +1414,12 @@ fn print_native_static_libs(
} else if sess.target.linker_flavor.is_gnu() {
Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))
} else {
- Some(format!("-l{}", name))
+ Some(format!("-l{name}"))
}
}
NativeLibKind::Framework { .. } => {
// ld-only syntax, since there are no frameworks in MSVC
- Some(format!("-framework {}", name))
+ Some(format!("-framework {name}"))
}
// These are included, no need to print them
NativeLibKind::Static { bundle: None | Some(true), .. }
@@ -1446,19 +1456,30 @@ fn print_native_static_libs(
// `foo.lib` file if the dll doesn't actually export any symbols, so we
// check to see if the file is there and just omit linking to it if it's
// not present.
- let name = format!("{}.dll.lib", lib);
+ let name = format!("{lib}.dll.lib");
if path.join(&name).exists() {
lib_args.push(name);
}
} else {
- lib_args.push(format!("-l{}", lib));
+ lib_args.push(format!("-l{lib}"));
}
}
- if !lib_args.is_empty() {
- sess.emit_note(errors::StaticLibraryNativeArtifacts);
- // Prefix for greppability
- // Note: This must not be translated as tools are allowed to depend on this exact string.
- sess.note_without_error(format!("native-static-libs: {}", &lib_args.join(" ")));
+
+ match out {
+ OutFileName::Real(path) => {
+ out.overwrite(&lib_args.join(" "), sess);
+ if !lib_args.is_empty() {
+ sess.emit_note(errors::StaticLibraryNativeArtifactsToFile { path });
+ }
+ }
+ OutFileName::Stdout => {
+ if !lib_args.is_empty() {
+ sess.emit_note(errors::StaticLibraryNativeArtifacts);
+ // Prefix for greppability
+ // Note: This must not be translated as tools are allowed to depend on this exact string.
+ sess.note_without_error(format!("native-static-libs: {}", &lib_args.join(" ")));
+ }
+ }
}
}
@@ -1606,8 +1627,8 @@ fn exec_linker(
write!(f, "\"")?;
for c in self.arg.chars() {
match c {
- '"' => write!(f, "\\{}", c)?,
- c => write!(f, "{}", c)?,
+ '"' => write!(f, "\\{c}")?,
+ c => write!(f, "{c}")?,
}
}
write!(f, "\"")?;
@@ -1624,8 +1645,8 @@ fn exec_linker(
// ensure the line is interpreted as one whole argument.
for c in self.arg.chars() {
match c {
- '\\' | ' ' => write!(f, "\\{}", c)?,
- c => write!(f, "{}", c)?,
+ '\\' | ' ' => write!(f, "\\{c}")?,
+ c => write!(f, "{c}")?,
}
}
}
@@ -2262,7 +2283,7 @@ fn add_order_independent_options(
} else {
""
};
- cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
+ cmd.arg(format!("--dynamic-linker={prefix}ld.so.1"));
}
if sess.target.eh_frame_header {
@@ -2970,25 +2991,10 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
return;
}
- let self_contained_linker = sess.opts.cg.link_self_contained.linker();
-
- // FIXME: some targets default to using `lld`, but users can only override the linker on the CLI
- // and cannot yet select the precise linker flavor to opt out of that. See for example issue
- // #113597 for the `thumbv6m-none-eabi` target: a driver is used, and its default linker
- // conflicts with the target's flavor, causing unexpected arguments being passed.
- //
- // Until the new `LinkerFlavor`-like CLI options are stabilized, we only adopt MCP510's behavior
- // if its dedicated unstable CLI flags are used, to keep the current sub-optimal stable
- // behavior.
- let using_mcp510 =
- self_contained_linker || sess.opts.cg.linker_flavor.is_some_and(|f| f.is_unstable());
- if !using_mcp510 && !unstable_use_lld {
- return;
- }
-
// 1. Implement the "self-contained" part of this feature by adding rustc distribution
// directories to the tool's search path.
- if self_contained_linker || unstable_use_lld {
+ let self_contained_linker = sess.opts.cg.link_self_contained.linker() || unstable_use_lld;
+ if self_contained_linker {
for path in sess.get_tools_search_paths(false) {
cmd.arg({
let mut arg = OsString::from("-B");
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 8ac86fa4b..11afe0fbc 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -310,7 +310,7 @@ impl<'a> GccLinker<'a> {
self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
};
self.linker_args(&[
- &format!("-plugin-opt={}", opt_level),
+ &format!("-plugin-opt={opt_level}"),
&format!("-plugin-opt=mcpu={}", self.target_cpu),
]);
}
@@ -488,7 +488,7 @@ impl<'a> Linker for GccLinker<'a> {
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
self.hint_dynamic();
- self.cmd.arg(format!("-l{}", lib));
+ self.cmd.arg(format!("-l{lib}"));
}
fn link_framework(&mut self, framework: &str, as_needed: bool) {
@@ -670,8 +670,8 @@ impl<'a> Linker for GccLinker<'a> {
let res: io::Result<()> = try {
let mut f = BufWriter::new(File::create(&path)?);
for sym in symbols {
- debug!(" _{}", sym);
- writeln!(f, "_{}", sym)?;
+ debug!(" _{sym}");
+ writeln!(f, "_{sym}")?;
}
};
if let Err(error) = res {
@@ -685,8 +685,8 @@ impl<'a> Linker for GccLinker<'a> {
// because LD doesn't like when it's empty
writeln!(f, "EXPORTS")?;
for symbol in symbols {
- debug!(" _{}", symbol);
- writeln!(f, " {}", symbol)?;
+ debug!(" _{symbol}");
+ writeln!(f, " {symbol}")?;
}
};
if let Err(error) = res {
@@ -700,8 +700,8 @@ impl<'a> Linker for GccLinker<'a> {
if !symbols.is_empty() {
writeln!(f, " global:")?;
for sym in symbols {
- debug!(" {};", sym);
- writeln!(f, " {};", sym)?;
+ debug!(" {sym};");
+ writeln!(f, " {sym};")?;
}
}
writeln!(f, "\n local:\n *;\n}};")?;
@@ -836,7 +836,7 @@ impl<'a> Linker for MsvcLinker<'a> {
// `foo.lib` file if the dll doesn't actually export any symbols, so we
// check to see if the file is there and just omit linking to it if it's
// not present.
- let name = format!("{}.dll.lib", lib);
+ let name = format!("{lib}.dll.lib");
if path.join(&name).exists() {
self.cmd.arg(name);
}
@@ -976,8 +976,8 @@ impl<'a> Linker for MsvcLinker<'a> {
writeln!(f, "LIBRARY")?;
writeln!(f, "EXPORTS")?;
for symbol in symbols {
- debug!(" _{}", symbol);
- writeln!(f, " {}", symbol)?;
+ debug!(" _{symbol}");
+ writeln!(f, " {symbol}")?;
}
};
if let Err(error) = res {
@@ -991,7 +991,7 @@ impl<'a> Linker for MsvcLinker<'a> {
fn subsystem(&mut self, subsystem: &str) {
// Note that previous passes of the compiler validated this subsystem,
// so we just blindly pass it to the linker.
- self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));
+ self.cmd.arg(&format!("/SUBSYSTEM:{subsystem}"));
// Windows has two subsystems we're interested in right now, the console
// and windows subsystems. These both implicitly have different entry
@@ -1146,7 +1146,7 @@ impl<'a> Linker for EmLinker<'a> {
&symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
)
.unwrap();
- debug!("{}", encoded);
+ debug!("{encoded}");
arg.push(encoded);
@@ -1349,7 +1349,7 @@ impl<'a> Linker for L4Bender<'a> {
}
fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
self.hint_static();
- self.cmd.arg(format!("-PC{}", lib));
+ self.cmd.arg(format!("-PC{lib}"));
}
fn link_rlib(&mut self, lib: &Path) {
self.hint_static();
@@ -1398,7 +1398,7 @@ impl<'a> Linker for L4Bender<'a> {
fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
self.hint_static();
- self.cmd.arg("--whole-archive").arg(format!("-l{}", lib));
+ self.cmd.arg("--whole-archive").arg(format!("-l{lib}"));
self.cmd.arg("--no-whole-archive");
}
@@ -1452,7 +1452,7 @@ impl<'a> Linker for L4Bender<'a> {
}
fn subsystem(&mut self, subsystem: &str) {
- self.cmd.arg(&format!("--subsystem {}", subsystem));
+ self.cmd.arg(&format!("--subsystem {subsystem}"));
}
fn reset_per_library_state(&mut self) {
@@ -1517,12 +1517,12 @@ impl<'a> AixLinker<'a> {
impl<'a> Linker for AixLinker<'a> {
fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
self.hint_dynamic();
- self.cmd.arg(format!("-l{}", lib));
+ self.cmd.arg(format!("-l{lib}"));
}
fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
self.hint_static();
- self.cmd.arg(format!("-l{}", lib));
+ self.cmd.arg(format!("-l{lib}"));
}
fn link_rlib(&mut self, lib: &Path) {
@@ -1572,7 +1572,7 @@ impl<'a> Linker for AixLinker<'a> {
fn link_rust_dylib(&mut self, lib: &str, _: &Path) {
self.hint_dynamic();
- self.cmd.arg(format!("-l{}", lib));
+ self.cmd.arg(format!("-l{lib}"));
}
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
@@ -1625,12 +1625,12 @@ impl<'a> Linker for AixLinker<'a> {
let mut f = BufWriter::new(File::create(&path)?);
// FIXME: use llvm-nm to generate export list.
for symbol in symbols {
- debug!(" _{}", symbol);
- writeln!(f, " {}", symbol)?;
+ debug!(" _{symbol}");
+ writeln!(f, " {symbol}")?;
}
};
if let Err(e) = res {
- self.sess.fatal(format!("failed to write export file: {}", e));
+ self.sess.fatal(format!("failed to write export file: {e}"));
}
self.cmd.arg(format!("-bE:{}", path.to_str().unwrap()));
}
@@ -1703,7 +1703,7 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
return Vec::new();
}
- let stable_crate_id = tcx.sess.local_stable_crate_id();
+ let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
@@ -1927,7 +1927,7 @@ impl<'a> Linker for BpfLinker<'a> {
let res: io::Result<()> = try {
let mut f = BufWriter::new(File::create(&path)?);
for sym in symbols {
- writeln!(f, "{}", sym)?;
+ writeln!(f, "{sym}")?;
}
};
if let Err(error) = res {
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 00e6acb5c..4c8547407 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -10,15 +10,13 @@ use object::{
ObjectSymbol, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
};
-use snap::write::FrameEncoder;
-
-use object::elf::NT_GNU_PROPERTY_TYPE_0;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
use rustc_metadata::fs::METADATA_FILENAME;
use rustc_metadata::EncodedMetadata;
use rustc_session::cstore::MetadataLoader;
use rustc_session::Session;
+use rustc_span::sym;
use rustc_target::abi::Endian;
use rustc_target::spec::{ef_avr_arch, RelocModel, Target};
@@ -124,7 +122,7 @@ fn add_gnu_property_note(
let mut data: Vec<u8> = Vec::new();
let n_namsz: u32 = 4; // Size of the n_name field
let n_descsz: u32 = 16; // Size of the n_desc field
- let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor
+ let n_type: u32 = object::elf::NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor
let header_values = [n_namsz, n_descsz, n_type];
header_values.iter().for_each(|v| {
data.extend_from_slice(&match endianness {
@@ -134,8 +132,8 @@ fn add_gnu_property_note(
});
data.extend_from_slice(b"GNU\0"); // Owner of the program property note
let pr_type: u32 = match architecture {
- Architecture::X86_64 => 0xc0000002,
- Architecture::Aarch64 => 0xc0000000,
+ Architecture::X86_64 => object::elf::GNU_PROPERTY_X86_FEATURE_1_AND,
+ Architecture::Aarch64 => object::elf::GNU_PROPERTY_AARCH64_FEATURE_1_AND,
_ => unreachable!(),
};
let pr_datasz: u32 = 4; //size of the pr_data field
@@ -161,20 +159,19 @@ pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a
{
let offset = metadata_symbol.address() as usize;
if offset < 4 {
- return Err(format!("Invalid metadata symbol offset: {}", offset));
+ return Err(format!("Invalid metadata symbol offset: {offset}"));
}
// The offset specifies the location of rustc metadata in the comment section.
// The metadata is preceded by a 4-byte length field.
let len = u32::from_be_bytes(info_data[(offset - 4)..offset].try_into().unwrap()) as usize;
if offset + len > (info_data.len() as usize) {
return Err(format!(
- "Metadata at offset {} with size {} is beyond .info section",
- offset, len
+ "Metadata at offset {offset} with size {len} is beyond .info section"
));
}
return Ok(&info_data[offset..(offset + len)]);
} else {
- return Err(format!("Unable to find symbol {}", AIX_METADATA_SYMBOL_NAME));
+ return Err(format!("Unable to find symbol {AIX_METADATA_SYMBOL_NAME}"));
};
}
@@ -194,8 +191,8 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
}
"x86" => Architecture::I386,
"s390x" => Architecture::S390x,
- "mips" => Architecture::Mips,
- "mips64" => Architecture::Mips64,
+ "mips" | "mips32r6" => Architecture::Mips,
+ "mips64" | "mips64r6" => Architecture::Mips64,
"x86_64" => {
if sess.target.pointer_width == 32 {
Architecture::X86_64_X32
@@ -213,6 +210,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
"hexagon" => Architecture::Hexagon,
"bpf" => Architecture::Bpf,
"loongarch64" => Architecture::LoongArch64,
+ "csky" => Architecture::Csky,
// Unsupported architecture.
_ => return None,
};
@@ -243,8 +241,16 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
_ => elf::EF_MIPS_ARCH_32R2,
};
- // The only ABI LLVM supports for 32-bit MIPS CPUs is o32.
- let mut e_flags = elf::EF_MIPS_CPIC | elf::EF_MIPS_ABI_O32 | arch;
+
+ let mut e_flags = elf::EF_MIPS_CPIC | arch;
+
+ // If the ABI is explicitly given, use it or default to O32.
+ match sess.target.options.llvm_abiname.to_lowercase().as_str() {
+ "n32" => e_flags |= elf::EF_MIPS_ABI2,
+ "o32" => e_flags |= elf::EF_MIPS_ABI_O32,
+ _ => e_flags |= elf::EF_MIPS_ABI_O32,
+ };
+
if sess.target.options.relocation_model != RelocModel::Static {
e_flags |= elf::EF_MIPS_PIC;
}
@@ -267,35 +273,38 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
Architecture::Riscv32 | Architecture::Riscv64 => {
// Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
let mut e_flags: u32 = 0x0;
- let features = &sess.target.options.features;
+
// Check if compressed is enabled
- if features.contains("+c") {
+ // `unstable_target_features` is used here because "c" is gated behind riscv_target_feature.
+ if sess.unstable_target_features.contains(&sym::c) {
e_flags |= elf::EF_RISCV_RVC;
}
- // Select the appropriate floating-point ABI
- if features.contains("+d") {
- e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
- } else if features.contains("+f") {
- e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
- } else {
- e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
+ // Set the appropriate flag based on ABI
+ // This needs to match LLVM `RISCVELFStreamer.cpp`
+ match &*sess.target.llvm_abiname {
+ "" | "ilp32" | "lp64" => (),
+ "ilp32f" | "lp64f" => e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE,
+ "ilp32d" | "lp64d" => e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE,
+ "ilp32e" => e_flags |= elf::EF_RISCV_RVE,
+ _ => bug!("unknown RISC-V ABI name"),
}
+
e_flags
}
Architecture::LoongArch64 => {
// Source: https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc#e_flags-identifies-abi-type-and-version
let mut e_flags: u32 = elf::EF_LARCH_OBJABI_V1;
- let features = &sess.target.options.features;
- // Select the appropriate floating-point ABI
- if features.contains("+d") {
- e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT;
- } else if features.contains("+f") {
- e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT;
- } else {
- e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT;
+ // Set the appropriate flag based on ABI
+ // This needs to match LLVM `LoongArchELFStreamer.cpp`
+ match &*sess.target.llvm_abiname {
+ "ilp32s" | "lp64s" => e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT,
+ "ilp32f" | "lp64f" => e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT,
+ "ilp32d" | "lp64d" => e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT,
+ _ => bug!("unknown RISC-V ABI name"),
}
+
e_flags
}
Architecture::Avr => {
@@ -303,6 +312,13 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
// the appropriate EF_AVR_ARCH flag.
ef_avr_arch(&sess.target.options.cpu)
}
+ Architecture::Csky => {
+ let e_flags = match sess.target.options.abi.as_ref() {
+ "abiv2" => elf::EF_CSKY_ABIV2,
+ _ => elf::EF_CSKY_ABIV1,
+ };
+ e_flags
+ }
_ => 0,
};
// adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
@@ -474,19 +490,15 @@ pub fn create_compressed_metadata_file(
metadata: &EncodedMetadata,
symbol_name: &str,
) -> Vec<u8> {
- let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
- // Our length will be backfilled once we're done writing
- compressed.write_all(&[0; 4]).unwrap();
- FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
- let meta_len = rustc_metadata::METADATA_HEADER.len();
- let data_len = (compressed.len() - meta_len - 4) as u32;
- compressed[meta_len..meta_len + 4].copy_from_slice(&data_len.to_be_bytes());
+ let mut packed_metadata = rustc_metadata::METADATA_HEADER.to_vec();
+ packed_metadata.write_all(&(metadata.raw_data().len() as u32).to_be_bytes()).unwrap();
+ packed_metadata.extend(metadata.raw_data());
let Some(mut file) = create_object_file(sess) else {
- return compressed.to_vec();
+ return packed_metadata.to_vec();
};
if file.format() == BinaryFormat::Xcoff {
- return create_compressed_metadata_file_for_xcoff(file, &compressed, symbol_name);
+ return create_compressed_metadata_file_for_xcoff(file, &packed_metadata, symbol_name);
}
let section = file.add_section(
file.segment_name(StandardSegment::Data).to_vec(),
@@ -500,14 +512,14 @@ pub fn create_compressed_metadata_file(
}
_ => {}
};
- let offset = file.append_section_data(section, &compressed, 1);
+ let offset = file.append_section_data(section, &packed_metadata, 1);
// For MachO and probably PE this is necessary to prevent the linker from throwing away the
// .rustc section. For ELF this isn't necessary, but it also doesn't harm.
file.add_symbol(Symbol {
name: symbol_name.as_bytes().to_vec(),
value: offset,
- size: compressed.len() as u64,
+ size: packed_metadata.len() as u64,
kind: SymbolKind::Data,
scope: SymbolScope::Dynamic,
weak: false,
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index 0b5656c9a..ebf04e7a3 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -1,6 +1,7 @@
use pathdiff::diff_paths;
use rustc_data_structures::fx::FxHashSet;
use std::env;
+use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
@@ -12,7 +13,7 @@ pub struct RPathConfig<'a> {
pub linker_is_gnu: bool,
}
-pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
+pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<OsString> {
// No rpath on windows
if !config.has_rpath {
return Vec::new();
@@ -21,36 +22,38 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
debug!("preparing the RPATH!");
let rpaths = get_rpaths(config);
- let mut flags = rpaths_to_flags(&rpaths);
+ let mut flags = rpaths_to_flags(rpaths);
if config.linker_is_gnu {
// Use DT_RUNPATH instead of DT_RPATH if available
- flags.push("-Wl,--enable-new-dtags".to_owned());
+ flags.push("-Wl,--enable-new-dtags".into());
// Set DF_ORIGIN for substitute $ORIGIN
- flags.push("-Wl,-z,origin".to_owned());
+ flags.push("-Wl,-z,origin".into());
}
flags
}
-fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> {
+fn rpaths_to_flags(rpaths: Vec<OsString>) -> Vec<OsString> {
let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity
for rpath in rpaths {
- if rpath.contains(',') {
+ if rpath.to_string_lossy().contains(',') {
ret.push("-Wl,-rpath".into());
ret.push("-Xlinker".into());
- ret.push(rpath.clone());
+ ret.push(rpath);
} else {
- ret.push(format!("-Wl,-rpath,{}", &(*rpath)));
+ let mut single_arg = OsString::from("-Wl,-rpath,");
+ single_arg.push(rpath);
+ ret.push(single_arg);
}
}
ret
}
-fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<String> {
+fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<OsString> {
debug!("output: {:?}", config.out_filename.display());
debug!("libs:");
for libpath in config.libs {
@@ -64,18 +67,18 @@ fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<String> {
debug!("rpaths:");
for rpath in &rpaths {
- debug!(" {}", rpath);
+ debug!(" {:?}", rpath);
}
// Remove duplicates
minimize_rpaths(&rpaths)
}
-fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec<String> {
+fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec<OsString> {
config.libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
}
-fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String {
+fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> OsString {
// Mac doesn't appear to support $ORIGIN
let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" };
@@ -86,9 +89,12 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> Str
output.pop(); // strip filename
let output = fs::canonicalize(&output).unwrap_or(output);
let relative = path_relative_from(&lib, &output)
- .unwrap_or_else(|| panic!("couldn't create relative path from {:?} to {:?}", output, lib));
- // FIXME (#9639): This needs to handle non-utf8 paths
- format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path"))
+ .unwrap_or_else(|| panic!("couldn't create relative path from {output:?} to {lib:?}"));
+
+ let mut rpath = OsString::from(prefix);
+ rpath.push("/");
+ rpath.push(relative);
+ rpath
}
// This routine is adapted from the *old* Path's `path_relative_from`
@@ -99,7 +105,7 @@ fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
diff_paths(path, base)
}
-fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
+fn minimize_rpaths(rpaths: &[OsString]) -> Vec<OsString> {
let mut set = FxHashSet::default();
let mut minimized = Vec::new();
for rpath in rpaths {
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
index 604f19144..ac2e54072 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
@@ -1,32 +1,33 @@
use super::RPathConfig;
use super::{get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags};
+use std::ffi::OsString;
use std::path::{Path, PathBuf};
#[test]
fn test_rpaths_to_flags() {
- let flags = rpaths_to_flags(&["path1".to_string(), "path2".to_string()]);
+ let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]);
assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]);
}
#[test]
fn test_minimize1() {
- let res = minimize_rpaths(&["rpath1".to_string(), "rpath2".to_string(), "rpath1".to_string()]);
+ let res = minimize_rpaths(&["rpath1".into(), "rpath2".into(), "rpath1".into()]);
assert!(res == ["rpath1", "rpath2",]);
}
#[test]
fn test_minimize2() {
let res = minimize_rpaths(&[
- "1a".to_string(),
- "2".to_string(),
- "2".to_string(),
- "1a".to_string(),
- "4a".to_string(),
- "1a".to_string(),
- "2".to_string(),
- "3".to_string(),
- "4a".to_string(),
- "3".to_string(),
+ "1a".into(),
+ "2".into(),
+ "2".into(),
+ "1a".into(),
+ "4a".into(),
+ "1a".into(),
+ "2".into(),
+ "3".into(),
+ "4a".into(),
+ "3".into(),
]);
assert!(res == ["1a", "2", "4a", "3",]);
}
@@ -58,15 +59,15 @@ fn test_rpath_relative() {
#[test]
fn test_xlinker() {
- let args = rpaths_to_flags(&["a/normal/path".to_string(), "a,comma,path".to_string()]);
+ let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]);
assert_eq!(
args,
vec![
- "-Wl,-rpath,a/normal/path".to_string(),
- "-Wl,-rpath".to_string(),
- "-Xlinker".to_string(),
- "a,comma,path".to_string()
+ OsString::from("-Wl,-rpath,a/normal/path"),
+ OsString::from("-Wl,-rpath"),
+ OsString::from("-Xlinker"),
+ OsString::from("a,comma,path")
]
);
}
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index a8b6030ac..8fb2ccb7e 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -12,14 +12,14 @@ use rustc_middle::middle::exported_symbols::{
};
use rustc_middle::query::LocalCrate;
use rustc_middle::query::{ExternProviders, Providers};
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, SymbolName, TyCtxt};
+use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
use rustc_session::config::{CrateType, OomStrategy};
use rustc_target::spec::SanitizerSet;
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
- crates_export_threshold(&tcx.sess.crate_types())
+ crates_export_threshold(tcx.crate_types())
}
fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
@@ -233,15 +233,6 @@ fn exported_symbols_provider_local(
));
}
- symbols.push((
- ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)),
- SymbolExportInfo {
- level: SymbolExportLevel::Rust,
- kind: SymbolExportKind::Text,
- used: false,
- },
- ));
-
let exported_symbol =
ExportedSymbol::NoDefId(SymbolName::new(tcx, NO_ALLOC_SHIM_IS_UNSTABLE));
symbols.push((
@@ -299,8 +290,8 @@ fn exported_symbols_provider_local(
}));
}
- if tcx.sess.crate_types().contains(&CrateType::Dylib)
- || tcx.sess.crate_types().contains(&CrateType::ProcMacro)
+ if tcx.crate_types().contains(&CrateType::Dylib)
+ || tcx.crate_types().contains(&CrateType::ProcMacro)
{
let symbol_name = metadata_symbol_name(tcx);
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
@@ -328,23 +319,23 @@ fn exported_symbols_provider_local(
let (_, cgus) = tcx.collect_and_partition_mono_items(());
- for (mono_item, &(linkage, visibility)) in cgus.iter().flat_map(|cgu| cgu.items().iter()) {
- if linkage != Linkage::External {
+ for (mono_item, data) in cgus.iter().flat_map(|cgu| cgu.items().iter()) {
+ if data.linkage != Linkage::External {
// We can only re-use things with external linkage, otherwise
// we'll get a linker error
continue;
}
- if need_visibility && visibility == Visibility::Hidden {
+ if need_visibility && data.visibility == Visibility::Hidden {
// If we potentially share things from Rust dylibs, they must
// not be hidden
continue;
}
match *mono_item {
- MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => {
- if substs.non_erasable_generics().next().is_some() {
- let symbol = ExportedSymbol::Generic(def, substs);
+ MonoItem::Fn(Instance { def: InstanceDef::Item(def), args }) => {
+ if args.non_erasable_generics().next().is_some() {
+ let symbol = ExportedSymbol::Generic(def, args);
symbols.push((
symbol,
SymbolExportInfo {
@@ -355,10 +346,10 @@ fn exported_symbols_provider_local(
));
}
}
- MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => {
+ MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), args }) => {
// A little sanity-check
debug_assert_eq!(
- substs.non_erasable_generics().next(),
+ args.non_erasable_generics().next(),
Some(GenericArgKind::Type(ty))
);
symbols.push((
@@ -386,7 +377,7 @@ fn exported_symbols_provider_local(
fn upstream_monomorphizations_provider(
tcx: TyCtxt<'_>,
(): (),
-) -> DefIdMap<FxHashMap<SubstsRef<'_>, CrateNum>> {
+) -> DefIdMap<FxHashMap<GenericArgsRef<'_>, CrateNum>> {
let cnums = tcx.crates(());
let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default();
@@ -395,11 +386,11 @@ fn upstream_monomorphizations_provider(
for &cnum in cnums.iter() {
for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
- let (def_id, substs) = match *exported_symbol {
- ExportedSymbol::Generic(def_id, substs) => (def_id, substs),
+ let (def_id, args) = match *exported_symbol {
+ ExportedSymbol::Generic(def_id, args) => (def_id, args),
ExportedSymbol::DropGlue(ty) => {
if let Some(drop_in_place_fn_def_id) = drop_in_place_fn_def_id {
- (drop_in_place_fn_def_id, tcx.mk_substs(&[ty.into()]))
+ (drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()]))
} else {
// `drop_in_place` in place does not exist, don't try
// to use it.
@@ -414,9 +405,9 @@ fn upstream_monomorphizations_provider(
}
};
- let substs_map = instances.entry(def_id).or_default();
+ let args_map = instances.entry(def_id).or_default();
- match substs_map.entry(substs) {
+ match args_map.entry(args) {
Occupied(mut e) => {
// If there are multiple monomorphizations available,
// we select one deterministically.
@@ -438,17 +429,17 @@ fn upstream_monomorphizations_provider(
fn upstream_monomorphizations_for_provider(
tcx: TyCtxt<'_>,
def_id: DefId,
-) -> Option<&FxHashMap<SubstsRef<'_>, CrateNum>> {
+) -> Option<&FxHashMap<GenericArgsRef<'_>, CrateNum>> {
debug_assert!(!def_id.is_local());
tcx.upstream_monomorphizations(()).get(&def_id)
}
fn upstream_drop_glue_for_provider<'tcx>(
tcx: TyCtxt<'tcx>,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
) -> Option<CrateNum> {
if let Some(def_id) = tcx.lang_items().drop_in_place_fn() {
- tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&substs).cloned())
+ tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&args).cloned())
} else {
None
}
@@ -521,10 +512,10 @@ pub fn symbol_name_for_instance_in_crate<'tcx>(
instantiating_crate,
)
}
- ExportedSymbol::Generic(def_id, substs) => {
+ ExportedSymbol::Generic(def_id, args) => {
rustc_symbol_mangling::symbol_name_for_instance_in_crate(
tcx,
- Instance::new(def_id, substs),
+ Instance::new(def_id, args),
instantiating_crate,
)
}
@@ -533,7 +524,7 @@ pub fn symbol_name_for_instance_in_crate<'tcx>(
tcx,
ty::Instance {
def: ty::InstanceDef::ThreadLocalShim(def_id),
- substs: ty::InternalSubsts::empty(),
+ args: ty::GenericArgs::empty(),
},
instantiating_crate,
)
@@ -580,7 +571,7 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
None
}
ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)),
- ExportedSymbol::Generic(def_id, substs) => Some(Instance::new(def_id, substs)),
+ ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)),
// DropGlue always use the Rust calling convention and thus follow the target's default
// symbol decoration scheme.
ExportedSymbol::DropGlue(..) => None,
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index ececa29b2..f485af00b 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -123,7 +123,7 @@ pub struct ModuleConfig {
impl ModuleConfig {
fn new(
kind: ModuleKind,
- sess: &Session,
+ tcx: TyCtxt<'_>,
no_builtins: bool,
is_compiler_builtins: bool,
) -> ModuleConfig {
@@ -135,6 +135,7 @@ impl ModuleConfig {
};
}
+ let sess = tcx.sess;
let opt_level_and_size = if_regular!(Some(sess.opts.optimize), None);
let save_temps = sess.opts.cg.save_temps;
@@ -166,7 +167,7 @@ impl ModuleConfig {
// `#![no_builtins]` is assumed to not participate in LTO and
// instead goes on to generate object code.
EmitObj::Bitcode
- } else if need_bitcode_in_object(sess) {
+ } else if need_bitcode_in_object(tcx) {
EmitObj::ObjectCode(BitcodeSection::Full)
} else {
EmitObj::ObjectCode(BitcodeSection::None)
@@ -349,8 +350,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
/// Directory into which should the LLVM optimization remarks be written.
/// If `None`, they will be written to stderr.
pub remark_dir: Option<PathBuf>,
- /// Worker thread number
- pub worker: usize,
/// The incremental compilation session directory, or None if we are not
/// compiling incrementally
pub incr_comp_session_dir: Option<PathBuf>,
@@ -362,7 +361,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
impl<B: WriteBackendMethods> CodegenContext<B> {
pub fn create_diag_handler(&self) -> Handler {
- Handler::with_emitter(true, None, Box::new(self.diag_emitter.clone()))
+ Handler::with_emitter(Box::new(self.diag_emitter.clone()))
}
pub fn config(&self, kind: ModuleKind) -> &ModuleConfig {
@@ -376,38 +375,39 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
fn generate_lto_work<B: ExtraBackendMethods>(
cgcx: &CodegenContext<B>,
- needs_fat_lto: Vec<FatLTOInput<B>>,
+ needs_fat_lto: Vec<FatLtoInput<B>>,
needs_thin_lto: Vec<(String, B::ThinBuffer)>,
import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>,
) -> Vec<(WorkItem<B>, u64)> {
let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work");
- let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() {
+ if !needs_fat_lto.is_empty() {
assert!(needs_thin_lto.is_empty());
- let lto_module =
+ let module =
B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise());
- (vec![lto_module], vec![])
+ // We are adding a single work item, so the cost doesn't matter.
+ vec![(WorkItem::LTO(module), 0)]
} else {
assert!(needs_fat_lto.is_empty());
- B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules).unwrap_or_else(|e| e.raise())
- };
-
- lto_modules
- .into_iter()
- .map(|module| {
- let cost = module.cost();
- (WorkItem::LTO(module), cost)
- })
- .chain(copy_jobs.into_iter().map(|wp| {
- (
- WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
- name: wp.cgu_name.clone(),
- source: wp,
- }),
- 0,
- )
- }))
- .collect()
+ let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules)
+ .unwrap_or_else(|e| e.raise());
+ lto_modules
+ .into_iter()
+ .map(|module| {
+ let cost = module.cost();
+ (WorkItem::LTO(module), cost)
+ })
+ .chain(copy_jobs.into_iter().map(|wp| {
+ (
+ WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
+ name: wp.cgu_name.clone(),
+ source: wp,
+ }),
+ 0, // copying is very cheap
+ )
+ }))
+ .collect()
+ }
}
pub struct CompiledModules {
@@ -415,9 +415,10 @@ pub struct CompiledModules {
pub allocator_module: Option<CompiledModule>,
}
-fn need_bitcode_in_object(sess: &Session) -> bool {
+fn need_bitcode_in_object(tcx: TyCtxt<'_>) -> bool {
+ let sess = tcx.sess;
let requested_for_rlib = sess.opts.cg.embed_bitcode
- && sess.crate_types().contains(&CrateType::Rlib)
+ && tcx.crate_types().contains(&CrateType::Rlib)
&& sess.opts.output_types.contains_key(&OutputType::Exe);
let forced_by_target = sess.target.forces_embed_bitcode;
requested_for_rlib || forced_by_target
@@ -451,11 +452,11 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
let crate_info = CrateInfo::new(tcx, target_cpu);
let regular_config =
- ModuleConfig::new(ModuleKind::Regular, sess, no_builtins, is_compiler_builtins);
+ ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins, is_compiler_builtins);
let metadata_config =
- ModuleConfig::new(ModuleKind::Metadata, sess, no_builtins, is_compiler_builtins);
+ ModuleConfig::new(ModuleKind::Metadata, tcx, no_builtins, is_compiler_builtins);
let allocator_config =
- ModuleConfig::new(ModuleKind::Allocator, sess, no_builtins, is_compiler_builtins);
+ ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins, is_compiler_builtins);
let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
let (codegen_worker_send, codegen_worker_receive) = channel();
@@ -709,7 +710,7 @@ impl<B: WriteBackendMethods> WorkItem<B> {
fn desc(short: &str, _long: &str, name: &str) -> String {
// The short label is three bytes, and is followed by a space. That
// leaves 11 bytes for the CGU name. How we obtain those 11 bytes
- // depends on the the CGU name form.
+ // depends on the CGU name form.
//
// - Non-incremental, e.g. `regex.f10ba03eb5ec7975-cgu.0`: the part
// before the `-cgu.0` is the same for every CGU, so use the
@@ -742,22 +743,32 @@ impl<B: WriteBackendMethods> WorkItem<B> {
}
match self {
- WorkItem::Optimize(m) => desc("opt", "optimize module {}", &m.name),
- WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for {}", &m.name),
- WorkItem::LTO(m) => desc("lto", "LTO module {}", m.name()),
+ WorkItem::Optimize(m) => desc("opt", "optimize module", &m.name),
+ WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for", &m.name),
+ WorkItem::LTO(m) => desc("lto", "LTO module", m.name()),
}
}
}
/// A result produced by the backend.
pub(crate) enum WorkItemResult<B: WriteBackendMethods> {
- Compiled(CompiledModule),
+ /// The backend has finished compiling a CGU, nothing more required.
+ Finished(CompiledModule),
+
+ /// The backend has finished compiling a CGU, which now needs linking
+ /// because `-Zcombine-cgu` was specified.
NeedsLink(ModuleCodegen<B::Module>),
- NeedsFatLTO(FatLTOInput<B>),
- NeedsThinLTO(String, B::ThinBuffer),
+
+ /// The backend has finished compiling a CGU, which now needs to go through
+ /// fat LTO.
+ NeedsFatLto(FatLtoInput<B>),
+
+ /// The backend has finished compiling a CGU, which now needs to go through
+ /// thin LTO.
+ NeedsThinLto(String, B::ThinBuffer),
}
-pub enum FatLTOInput<B: WriteBackendMethods> {
+pub enum FatLtoInput<B: WriteBackendMethods> {
Serialized { name: String, buffer: B::ModuleBuffer },
InMemory(ModuleCodegen<B::Module>),
}
@@ -846,7 +857,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
});
}
- Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))
+ Ok(WorkItemResult::NeedsThinLto(name, thin_buffer))
}
ComputedLtoType::Fat => match bitcode {
Some(path) => {
@@ -854,9 +865,9 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
fs::write(&path, buffer.data()).unwrap_or_else(|e| {
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
});
- Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }))
+ Ok(WorkItemResult::NeedsFatLto(FatLtoInput::Serialized { name, buffer }))
}
- None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))),
+ None => Ok(WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module))),
},
}
}
@@ -906,7 +917,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
load_from_incr_comp_dir(dwarf_obj_out, &saved_dwarf_object_file)
});
- WorkItemResult::Compiled(CompiledModule {
+ WorkItemResult::Finished(CompiledModule {
name: module.name,
kind: ModuleKind::Regular,
object,
@@ -936,7 +947,7 @@ fn finish_intra_module_work<B: ExtraBackendMethods>(
|| module.kind == ModuleKind::Allocator
{
let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
- Ok(WorkItemResult::Compiled(module))
+ Ok(WorkItemResult::Finished(module))
} else {
Ok(WorkItemResult::NeedsLink(module))
}
@@ -987,10 +998,15 @@ struct Diagnostic {
}
#[derive(PartialEq, Clone, Copy, Debug)]
-enum MainThreadWorkerState {
+enum MainThreadState {
+ /// Doing nothing.
Idle,
+
+ /// Doing codegen, i.e. MIR-to-LLVM-IR conversion.
Codegenning,
- LLVMing,
+
+ /// Idle, but lending the compiler process's Token to an LLVM thread so it can do useful work.
+ Lending,
}
fn start_executing_work<B: ExtraBackendMethods>(
@@ -1078,7 +1094,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
};
let cgcx = CodegenContext::<B> {
- crate_types: sess.crate_types().to_vec(),
+ crate_types: tcx.crate_types().to_vec(),
each_linked_rlib_for_lto,
lto: sess.lto(),
fewer_names: sess.fewer_names(),
@@ -1089,7 +1105,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
exported_symbols,
remark: sess.opts.cg.remark.clone(),
remark_dir,
- worker: 0,
incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),
coordinator_send,
@@ -1242,7 +1257,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// Each LLVM module is automatically sent back to the coordinator for LTO if
// necessary. There's already optimizations in place to avoid sending work
// back to the coordinator if LTO isn't requested.
- return B::spawn_thread(cgcx.time_trace, move || {
+ return B::spawn_named_thread(cgcx.time_trace, "coordinator".to_string(), move || {
let mut worker_id_counter = 0;
let mut free_worker_ids = Vec::new();
let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
@@ -1285,10 +1300,19 @@ fn start_executing_work<B: ExtraBackendMethods>(
// the implicit Token the compiler process owns no matter what.
let mut tokens = Vec::new();
- let mut main_thread_worker_state = MainThreadWorkerState::Idle;
- let mut running = 0;
+ let mut main_thread_state = MainThreadState::Idle;
+
+ // How many LLVM worker threads are running while holding a Token. This
+ // *excludes* any that the main thread is lending a Token to.
+ let mut running_with_own_token = 0;
+
+ // How many LLVM worker threads are running in total. This *includes*
+ // any that the main thread is lending a Token to.
+ let running_with_any_token = |main_thread_state, running_with_own_token| {
+ running_with_own_token
+ + if main_thread_state == MainThreadState::Lending { 1 } else { 0 }
+ };
- let prof = &cgcx.prof;
let mut llvm_start_time: Option<VerboseTimingGuard<'_>> = None;
// Run the message loop while there's still anything that needs message
@@ -1296,66 +1320,62 @@ fn start_executing_work<B: ExtraBackendMethods>(
// wait for all existing work to finish, so many of the conditions here
// only apply if codegen hasn't been aborted as they represent pending
// work to be done.
- while codegen_state == Ongoing
- || running > 0
- || main_thread_worker_state == MainThreadWorkerState::LLVMing
- || (codegen_state == Completed
- && !(work_items.is_empty()
- && needs_fat_lto.is_empty()
- && needs_thin_lto.is_empty()
- && lto_import_only_modules.is_empty()
- && main_thread_worker_state == MainThreadWorkerState::Idle))
- {
+ loop {
// While there are still CGUs to be codegened, the coordinator has
// to decide how to utilize the compiler processes implicit Token:
// For codegenning more CGU or for running them through LLVM.
if codegen_state == Ongoing {
- if main_thread_worker_state == MainThreadWorkerState::Idle {
+ if main_thread_state == MainThreadState::Idle {
// Compute the number of workers that will be running once we've taken as many
// items from the work queue as we can, plus one for the main thread. It's not
- // critically important that we use this instead of just `running`, but it
- // prevents the `queue_full_enough` heuristic from fluctuating just because a
- // worker finished up and we decreased the `running` count, even though we're
- // just going to increase it right after this when we put a new worker to work.
- let extra_tokens = tokens.len().checked_sub(running).unwrap();
+ // critically important that we use this instead of just
+ // `running_with_own_token`, but it prevents the `queue_full_enough` heuristic
+ // from fluctuating just because a worker finished up and we decreased the
+ // `running_with_own_token` count, even though we're just going to increase it
+ // right after this when we put a new worker to work.
+ let extra_tokens = tokens.len().checked_sub(running_with_own_token).unwrap();
let additional_running = std::cmp::min(extra_tokens, work_items.len());
- let anticipated_running = running + additional_running + 1;
+ let anticipated_running = running_with_own_token + additional_running + 1;
if !queue_full_enough(work_items.len(), anticipated_running) {
// The queue is not full enough, process more codegen units:
if codegen_worker_send.send(CguMessage).is_err() {
panic!("Could not send CguMessage to main thread")
}
- main_thread_worker_state = MainThreadWorkerState::Codegenning;
+ main_thread_state = MainThreadState::Codegenning;
} else {
// The queue is full enough to not let the worker
// threads starve. Use the implicit Token to do some
// LLVM work too.
let (item, _) =
work_items.pop().expect("queue empty - queue_full_enough() broken?");
- let cgcx = CodegenContext {
- worker: get_worker_id(&mut free_worker_ids),
- ..cgcx.clone()
- };
- maybe_start_llvm_timer(
- prof,
- cgcx.config(item.module_kind()),
+ main_thread_state = MainThreadState::Lending;
+ spawn_work(
+ &cgcx,
&mut llvm_start_time,
+ get_worker_id(&mut free_worker_ids),
+ item,
);
- main_thread_worker_state = MainThreadWorkerState::LLVMing;
- spawn_work(cgcx, item);
}
}
} else if codegen_state == Completed {
- // If we've finished everything related to normal codegen
- // then it must be the case that we've got some LTO work to do.
- // Perform the serial work here of figuring out what we're
- // going to LTO and then push a bunch of work items onto our
- // queue to do LTO
- if work_items.is_empty()
- && running == 0
- && main_thread_worker_state == MainThreadWorkerState::Idle
+ if running_with_any_token(main_thread_state, running_with_own_token) == 0
+ && work_items.is_empty()
{
+ // All codegen work is done. Do we have LTO work to do?
+ if needs_fat_lto.is_empty()
+ && needs_thin_lto.is_empty()
+ && lto_import_only_modules.is_empty()
+ {
+ // Nothing more to do!
+ break;
+ }
+
+ // We have LTO work to do. Perform the serial work here of
+ // figuring out what we're going to LTO and then push a
+ // bunch of work items onto our queue to do LTO. This all
+ // happens on the coordinator thread but it's very quick so
+ // we don't worry about tokens.
assert!(!started_lto);
started_lto = true;
@@ -1379,20 +1399,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
// In this branch, we know that everything has been codegened,
// so it's just a matter of determining whether the implicit
// Token is free to use for LLVM work.
- match main_thread_worker_state {
- MainThreadWorkerState::Idle => {
+ match main_thread_state {
+ MainThreadState::Idle => {
if let Some((item, _)) = work_items.pop() {
- let cgcx = CodegenContext {
- worker: get_worker_id(&mut free_worker_ids),
- ..cgcx.clone()
- };
- maybe_start_llvm_timer(
- prof,
- cgcx.config(item.module_kind()),
+ main_thread_state = MainThreadState::Lending;
+ spawn_work(
+ &cgcx,
&mut llvm_start_time,
+ get_worker_id(&mut free_worker_ids),
+ item,
);
- main_thread_worker_state = MainThreadWorkerState::LLVMing;
- spawn_work(cgcx, item);
} else {
// There is no unstarted work, so let the main thread
// take over for a running worker. Otherwise the
@@ -1400,16 +1416,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
// We reduce the `running` counter by one. The
// `tokens.truncate()` below will take care of
// giving the Token back.
- debug_assert!(running > 0);
- running -= 1;
- main_thread_worker_state = MainThreadWorkerState::LLVMing;
+ debug_assert!(running_with_own_token > 0);
+ running_with_own_token -= 1;
+ main_thread_state = MainThreadState::Lending;
}
}
- MainThreadWorkerState::Codegenning => bug!(
+ MainThreadState::Codegenning => bug!(
"codegen worker should not be codegenning after \
codegen was already completed"
),
- MainThreadWorkerState::LLVMing => {
+ MainThreadState::Lending => {
// Already making good use of that token
}
}
@@ -1417,35 +1433,39 @@ fn start_executing_work<B: ExtraBackendMethods>(
// Don't queue up any more work if codegen was aborted, we're
// just waiting for our existing children to finish.
assert!(codegen_state == Aborted);
+ if running_with_any_token(main_thread_state, running_with_own_token) == 0 {
+ break;
+ }
}
// Spin up what work we can, only doing this while we've got available
// parallelism slots and work left to spawn.
- while codegen_state != Aborted && !work_items.is_empty() && running < tokens.len() {
- let (item, _) = work_items.pop().unwrap();
-
- maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time);
-
- let cgcx =
- CodegenContext { worker: get_worker_id(&mut free_worker_ids), ..cgcx.clone() };
-
- spawn_work(cgcx, item);
- running += 1;
+ if codegen_state != Aborted {
+ while !work_items.is_empty() && running_with_own_token < tokens.len() {
+ let (item, _) = work_items.pop().unwrap();
+ spawn_work(
+ &cgcx,
+ &mut llvm_start_time,
+ get_worker_id(&mut free_worker_ids),
+ item,
+ );
+ running_with_own_token += 1;
+ }
}
- // Relinquish accidentally acquired extra tokens
- tokens.truncate(running);
+ // Relinquish accidentally acquired extra tokens.
+ tokens.truncate(running_with_own_token);
// If a thread exits successfully then we drop a token associated
- // with that worker and update our `running` count. We may later
- // re-acquire a token to continue running more work. We may also not
- // actually drop a token here if the worker was running with an
- // "ephemeral token"
+ // with that worker and update our `running_with_own_token` count.
+ // We may later re-acquire a token to continue running more work.
+ // We may also not actually drop a token here if the worker was
+ // running with an "ephemeral token".
let mut free_worker = |worker_id| {
- if main_thread_worker_state == MainThreadWorkerState::LLVMing {
- main_thread_worker_state = MainThreadWorkerState::Idle;
+ if main_thread_state == MainThreadState::Lending {
+ main_thread_state = MainThreadState::Idle;
} else {
- running -= 1;
+ running_with_own_token -= 1;
}
free_worker_ids.push(worker_id);
@@ -1461,17 +1481,17 @@ fn start_executing_work<B: ExtraBackendMethods>(
Ok(token) => {
tokens.push(token);
- if main_thread_worker_state == MainThreadWorkerState::LLVMing {
+ if main_thread_state == MainThreadState::Lending {
// If the main thread token is used for LLVM work
// at the moment, we turn that thread into a regular
// LLVM worker thread, so the main thread is free
// to react to codegen demand.
- main_thread_worker_state = MainThreadWorkerState::Idle;
- running += 1;
+ main_thread_state = MainThreadState::Idle;
+ running_with_own_token += 1;
}
}
Err(e) => {
- let msg = &format!("failed to acquire jobserver token: {}", e);
+ let msg = &format!("failed to acquire jobserver token: {e}");
shared_emitter.fatal(msg);
codegen_state = Aborted;
}
@@ -1496,16 +1516,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
if !cgcx.opts.unstable_opts.no_parallel_llvm {
helper.request_token();
}
- assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
- main_thread_worker_state = MainThreadWorkerState::Idle;
+ assert_eq!(main_thread_state, MainThreadState::Codegenning);
+ main_thread_state = MainThreadState::Idle;
}
Message::CodegenComplete => {
if codegen_state != Aborted {
codegen_state = Completed;
}
- assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
- main_thread_worker_state = MainThreadWorkerState::Idle;
+ assert_eq!(main_thread_state, MainThreadState::Codegenning);
+ main_thread_state = MainThreadState::Idle;
}
// If codegen is aborted that means translation was aborted due
@@ -1513,7 +1533,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
// to exit as soon as possible, but we want to make sure all
// existing work has finished. Flag codegen as being done, and
// then conditions above will ensure no more work is spawned but
- // we'll keep executing this loop until `running` hits 0.
+ // we'll keep executing this loop until `running_with_own_token`
+ // hits 0.
Message::CodegenAborted => {
codegen_state = Aborted;
}
@@ -1522,9 +1543,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
free_worker(worker_id);
match result {
- Ok(WorkItemResult::Compiled(compiled_module)) => {
+ Ok(WorkItemResult::Finished(compiled_module)) => {
match compiled_module.kind {
ModuleKind::Regular => {
+ assert!(needs_link.is_empty());
compiled_modules.push(compiled_module);
}
ModuleKind::Allocator => {
@@ -1535,14 +1557,17 @@ fn start_executing_work<B: ExtraBackendMethods>(
}
}
Ok(WorkItemResult::NeedsLink(module)) => {
+ assert!(compiled_modules.is_empty());
needs_link.push(module);
}
- Ok(WorkItemResult::NeedsFatLTO(fat_lto_input)) => {
+ Ok(WorkItemResult::NeedsFatLto(fat_lto_input)) => {
assert!(!started_lto);
+ assert!(needs_thin_lto.is_empty());
needs_fat_lto.push(fat_lto_input);
}
- Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) => {
+ Ok(WorkItemResult::NeedsThinLto(name, thin_buffer)) => {
assert!(!started_lto);
+ assert!(needs_fat_lto.is_empty());
needs_thin_lto.push((name, thin_buffer));
}
Err(Some(WorkerFatalError)) => {
@@ -1560,9 +1585,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
Message::AddImportOnlyModule { module_data, work_product } => {
assert!(!started_lto);
assert_eq!(codegen_state, Ongoing);
- assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
+ assert_eq!(main_thread_state, MainThreadState::Codegenning);
lto_import_only_modules.push((module_data, work_product));
- main_thread_worker_state = MainThreadWorkerState::Idle;
+ main_thread_state = MainThreadState::Idle;
}
}
}
@@ -1595,7 +1620,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
modules: compiled_modules,
allocator_module: compiled_allocator_module,
})
- });
+ })
+ .expect("failed to spawn coordinator thread");
// A heuristic that determines if we have enough LLVM WorkItems in the
// queue so that the main thread can do LLVM work instead of codegen
@@ -1653,23 +1679,24 @@ fn start_executing_work<B: ExtraBackendMethods>(
let quarter_of_workers = workers_running - 3 * workers_running / 4;
items_in_queue > 0 && items_in_queue >= quarter_of_workers
}
-
- fn maybe_start_llvm_timer<'a>(
- prof: &'a SelfProfilerRef,
- config: &ModuleConfig,
- llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
- ) {
- if config.time_module && llvm_start_time.is_none() {
- *llvm_start_time = Some(prof.verbose_generic_activity("LLVM_passes"));
- }
- }
}
/// `FatalError` is explicitly not `Send`.
#[must_use]
pub struct WorkerFatalError;
-fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) {
+fn spawn_work<'a, B: ExtraBackendMethods>(
+ cgcx: &'a CodegenContext<B>,
+ llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
+ worker_id: usize,
+ work: WorkItem<B>,
+) {
+ if cgcx.config(work.module_kind()).time_module && llvm_start_time.is_none() {
+ *llvm_start_time = Some(cgcx.prof.verbose_generic_activity("LLVM_passes"));
+ }
+
+ let cgcx = cgcx.clone();
+
B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
// Set up a destructor which will fire off a message that we're done as
// we exit.
@@ -1692,11 +1719,8 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
}
}
- let mut bomb = Bomb::<B> {
- coordinator_send: cgcx.coordinator_send.clone(),
- result: None,
- worker_id: cgcx.worker,
- };
+ let mut bomb =
+ Bomb::<B> { coordinator_send: cgcx.coordinator_send.clone(), result: None, worker_id };
// Execute the work itself, and if it finishes successfully then flag
// ourselves as a success as well.
@@ -1728,7 +1752,7 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
})
};
})
- .expect("failed to spawn thread");
+ .expect("failed to spawn work thread");
}
enum SharedEmitterMessage {
@@ -1945,6 +1969,10 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
self.backend.print_pass_timings()
}
+ if sess.print_llvm_stats() {
+ self.backend.print_statistics()
+ }
+
(
CodegenResults {
metadata: self.metadata,
@@ -1958,19 +1986,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
)
}
- pub fn submit_pre_codegened_module_to_llvm(
- &self,
- tcx: TyCtxt<'_>,
- module: ModuleCodegen<B::Module>,
- ) {
- self.wait_for_signal_to_codegen_item();
- self.check_for_errors(tcx.sess);
-
- // These are generally cheap and won't throw off scheduling.
- let cost = 0;
- submit_codegened_module_to_llvm(&self.backend, &self.coordinator.sender, module, cost);
- }
-
pub fn codegen_finished(&self, tcx: TyCtxt<'_>) {
self.wait_for_signal_to_codegen_item();
self.check_for_errors(tcx.sess);
@@ -2036,8 +2051,8 @@ pub fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
})));
}
-pub fn pre_lto_bitcode_filename(module_name: &str) -> String {
- format!("{}.{}", module_name, PRE_LTO_BC_EXT)
+fn pre_lto_bitcode_filename(module_name: &str) -> String {
+ format!("{module_name}.{PRE_LTO_BC_EXT}")
}
fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
@@ -2050,7 +2065,7 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
);
tcx.sess.target.is_like_windows &&
- tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
+ tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
// ThinLTO can't handle this workaround in all cases, so we don't
// emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
// dynamic linking when linker plugin LTO is enabled.