Skip to content

Commit

Permalink
Auto merge of rust-lang#122703 - Urgau:lazy-targets, r=<try>
Browse files Browse the repository at this point in the history
Lazify more work in builtins targets

This PR make some fields in `Target` and `TargetOptions` lazy.

This is done in order to reduce the impact of check-cfg which needs to load all the built-ins targets but doesn't need all the fields.

In particular this PR introduce a `MaybeLazy<T>` struct to support a borrowed, owned and lazy state.

~~The fields that are changed are:~~
 - ~~`LinkArgs` fields (access to env + allocate): 54 023 236 ins[^1] -> 53 478 072 ins~~
 - ~~`CrtObjects` fields (allocate): 53 478 072 ins -> 53 127 832 ins~~
 - ~~`llvm_name` field (access to env + allocate): 53 127 832 ins -> 53 057 110 ins~~

~~This brings around -1 000 000 ins*tructions* and -0.2/0.3ms of less wall-time (with some measurement even having the same minimum wall-time with or without check-cfg) 🎉.~~

See the latest perf run for the actual improvements, rust-lang#122703 (comment).

*This PR is also a step further to completely `static`-fying all the build-in targets, if we one day we decide to do it, but that's a separate conversion.*

[^1]: This is the total number of instructions as measured with `cachegrind` for the entire `rustc` invocation on a cargo --lib hello world, variance was really low (<15 000 ins).
In the scale of the check-cfg feature, last time I measured `CheckCfg::fill_well_known` was around ~2.8 millions ins.

r? `@petrochenkov`
  • Loading branch information
bors committed Jun 18, 2024
2 parents af3d100 + d7ef5e6 commit d013d1a
Show file tree
Hide file tree
Showing 101 changed files with 757 additions and 439 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_target/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(fn_traits)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(min_exhaustive_patterns)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(unboxed_closures)]
// tidy-alphabetical-end

use std::path::{Path, PathBuf};
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/spec/base/aix.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::abi::Endian;
use crate::spec::{crt_objects, cvs, Cc, CodeModel, LinkOutputKind, LinkerFlavor, TargetOptions};
use crate::spec::TargetOptions;
use crate::spec::{crt_objects, cvs, Cc, CodeModel, LinkOutputKind, LinkerFlavor};

pub fn opts() -> TargetOptions {
TargetOptions {
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_target/src/spec/base/apple/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{borrow::Cow, env};

use crate::spec::{add_link_args, add_link_args_iter};
use crate::spec::link_args::LazyLinkArgsState;
use crate::spec::{add_link_args, add_link_args_iter, MaybeLazy};
use crate::spec::{cvs, Cc, DebuginfoKind, FramePointer, LinkArgs, LinkerFlavor, Lld};
use crate::spec::{SplitDebuginfo, StackProbeType, StaticCow, Target, TargetOptions};

Expand Down Expand Up @@ -94,7 +95,10 @@ impl TargetAbi {
}
}

fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs {
pub(crate) type ApplePreLinkArgs =
(/*os:*/ &'static str, /*arch:*/ Arch, /*abi:*/ TargetAbi);

pub(crate) fn pre_link_args((os, arch, abi): ApplePreLinkArgs) -> LinkArgs {
let platform_name: StaticCow<str> = match abi {
TargetAbi::Normal => os.into(),
TargetAbi::Simulator => format!("{os}-simulator").into(),
Expand All @@ -114,7 +118,9 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs {
};
let sdk_version = min_version.clone();

let mut args = TargetOptions::link_args(
let mut args = LinkArgs::new();
add_link_args(
&mut args,
LinkerFlavor::Darwin(Cc::No, Lld::No),
&["-arch", arch.target_name(), "-platform_version"],
);
Expand Down Expand Up @@ -151,7 +157,7 @@ pub fn opts(os: &'static str, arch: Arch, abi: TargetAbi) -> TargetOptions {
// macOS has -dead_strip, which doesn't rely on function_sections
function_sections: false,
dynamic_linking: true,
pre_link_args: pre_link_args(os, arch, abi),
pre_link_args: MaybeLazy::lazied(LazyLinkArgsState::Apple((os, arch, abi))),
families: cvs!["unix"],
is_like_osx: true,
// LLVM notes that macOS 10.11+ and iOS 9+ default
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_target/src/spec/base/avr_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use object::elf;
/// A base target for AVR devices using the GNU toolchain.
///
/// Requires GNU avr-gcc and avr-binutils on the host system.
/// FIXME: Remove the second parameter when const string concatenation is possible.
pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
pub fn target(target_cpu: &'static str) -> Target {
Target {
arch: "avr".into(),
metadata: crate::spec::TargetMetadata {
Expand All @@ -24,7 +23,10 @@ pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {

linker: Some("avr-gcc".into()),
eh_frame_header: false,
pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[mmcu]),
pre_link_args: TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&["-mmcu=atmega328"],
),
late_link_args: TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&["-lgcc"],
Expand Down
16 changes: 10 additions & 6 deletions compiler/rustc_target/src/spec/base/teeos.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use crate::spec::{add_link_args, Cc, LinkerFlavor, Lld, PanicStrategy, RelroLevel, TargetOptions};
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelroLevel, TargetOptions};

pub fn opts() -> TargetOptions {
let lld_args = &["-zmax-page-size=4096", "-znow", "-ztext", "--execute-only"];
let cc_args = &["-Wl,-zmax-page-size=4096", "-Wl,-znow", "-Wl,-ztext", "-mexecute-only"];

let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), lld_args);
add_link_args(&mut pre_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), cc_args);
let pre_link_args = {
const LLD_ARGS: &[&str] = &["-zmax-page-size=4096", "-znow", "-ztext", "--execute-only"];
const CC_ARGS: &[&str] =
&["-Wl,-zmax-page-size=4096", "-Wl,-znow", "-Wl,-ztext", "-mexecute-only"];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), LLD_ARGS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), CC_ARGS),
])
};

TargetOptions {
os: "teeos".into(),
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_target/src/spec/base/uefi_msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
// code runs in the same environment, no process separation is supported.

use crate::spec::{base, LinkerFlavor, Lld, PanicStrategy, StackProbeType, TargetOptions};
use crate::spec::{base, LinkerFlavor, Lld};
use crate::spec::{PanicStrategy, StackProbeType, TargetOptions};

pub fn opts() -> TargetOptions {
let mut base = base::msvc::opts();

base.add_pre_link_args(
base.pre_link_args = TargetOptions::link_args(
LinkerFlavor::Msvc(Lld::No),
&[
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_target/src/spec/base/wasm.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::spec::{
add_link_args, cvs, Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel,
TargetOptions, TlsModel,
};
use crate::spec::{cvs, Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy};
use crate::spec::{RelocModel, TargetOptions, TlsModel};

pub fn options() -> TargetOptions {
macro_rules! args {
Expand Down Expand Up @@ -48,8 +46,10 @@ pub fn options() -> TargetOptions {
};
}

let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::WasmLld(Cc::No), args!(""));
add_link_args(&mut pre_link_args, LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,"));
let pre_link_args = TargetOptions::link_args_list(&[
(LinkerFlavor::WasmLld(Cc::No), args!("")),
(LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,")),
]);

TargetOptions {
is_like_wasm: true,
Expand Down
124 changes: 63 additions & 61 deletions compiler/rustc_target/src/spec/base/windows_gnu.rs
Original file line number Diff line number Diff line change
@@ -1,78 +1,80 @@
use crate::spec::crt_objects;
use crate::spec::LinkSelfContainedDefault;
use crate::spec::{add_link_args, crt_objects};
use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
use std::borrow::Cow;

pub fn opts() -> TargetOptions {
let mut pre_link_args = TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::No, Lld::No),
&[
// Enable ASLR
"--dynamicbase",
// ASLR will rebase it anyway so leaving that option enabled only leads to confusion
"--disable-auto-image-base",
],
);
add_link_args(
&mut pre_link_args,
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&[
// Tell GCC to avoid linker plugins, because we are not bundling
// them with Windows installer, and Rust does its own LTO anyways.
"-fno-use-linker-plugin",
"-Wl,--dynamicbase",
"-Wl,--disable-auto-image-base",
],
);
let pre_link_args = TargetOptions::link_args_list(&[
(
LinkerFlavor::Gnu(Cc::No, Lld::No),
&[
// Enable ASLR
"--dynamicbase",
// ASLR will rebase it anyway so leaving that option enabled only leads to confusion
"--disable-auto-image-base",
],
),
(
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&[
// Tell GCC to avoid linker plugins, because we are not bundling
// them with Windows installer, and Rust does its own LTO anyways.
"-fno-use-linker-plugin",
"-Wl,--dynamicbase",
"-Wl,--disable-auto-image-base",
],
),
]);

// Order of `late_link_args*` was found through trial and error to work with various
// mingw-w64 versions (not tested on the CI). It's expected to change from time to time.
let mingw_libs = &[
"-lmsvcrt",
"-lmingwex",
"-lmingw32",
"-lgcc", // alas, mingw* libraries above depend on libgcc
// mingw's msvcrt is a weird hybrid import library and static library.
// And it seems that the linker fails to use import symbols from msvcrt
// that are required from functions in msvcrt in certain cases. For example
// `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
// The library is purposely listed twice to fix that.
//
// See https://github.com/rust-lang/rust/pull/47483 for some more details.
"-lmsvcrt",
// Math functions missing in MSVCRT (they are present in UCRT) require
// this dependency cycle: `libmingwex.a` -> `libmsvcrt.a` -> `libmingwex.a`.
"-lmingwex",
"-luser32",
"-lkernel32",
];
let mut late_link_args =
TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs);
add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs);
let late_link_args = {
// Order of `late_link_args*` was found through trial and error to work with various
// mingw-w64 versions (not tested on the CI). It's expected to change from time to time.
const MINGW_LIBS: &[&str] = &[
"-lmsvcrt",
"-lmingwex",
"-lmingw32",
"-lgcc", // alas, mingw* libraries above depend on libgcc
// mingw's msvcrt is a weird hybrid import library and static library.
// And it seems that the linker fails to use import symbols from msvcrt
// that are required from functions in msvcrt in certain cases. For example
// `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
// The library is purposely listed twice to fix that.
//
// See https://github.com/rust-lang/rust/pull/47483 for some more details.
"-lmsvcrt",
// Math functions missing in MSVCRT (they are present in UCRT) require
// this dependency cycle: `libmingwex.a` -> `libmsvcrt.a` -> `libmingwex.a`.
"-lmingwex",
"-luser32",
"-lkernel32",
];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), MINGW_LIBS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), MINGW_LIBS),
])
};
// If any of our crates are dynamically linked then we need to use
// the shared libgcc_s-dw2-1.dll. This is required to support
// unwinding across DLL boundaries.
let dynamic_unwind_libs = &["-lgcc_s"];
let mut late_link_args_dynamic =
TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), dynamic_unwind_libs);
add_link_args(
&mut late_link_args_dynamic,
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
dynamic_unwind_libs,
);
let late_link_args_dynamic = {
const DYNAMIC_UNWIND_LIBS: &[&str] = &["-lgcc_s"];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), DYNAMIC_UNWIND_LIBS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), DYNAMIC_UNWIND_LIBS),
])
};
// If all of our crates are statically linked then we can get away
// with statically linking the libgcc unwinding code. This allows
// binaries to be redistributed without the libgcc_s-dw2-1.dll
// dependency, but unfortunately break unwinding across DLL
// boundaries when unwinding across FFI boundaries.
let static_unwind_libs = &["-lgcc_eh", "-l:libpthread.a"];
let mut late_link_args_static =
TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), static_unwind_libs);
add_link_args(
&mut late_link_args_static,
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
static_unwind_libs,
);
let late_link_args_static = {
const STATIC_UNWIND_LIBS: &[&str] = &["-lgcc_eh", "-l:libpthread.a"];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), STATIC_UNWIND_LIBS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), STATIC_UNWIND_LIBS),
])
};

TargetOptions {
os: "windows".into(),
Expand Down
39 changes: 21 additions & 18 deletions compiler/rustc_target/src/spec/base/windows_uwp_gnu.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
use crate::spec::{add_link_args, base, Cc, LinkArgs, LinkerFlavor, Lld, TargetOptions};
use crate::spec::{base, Cc, LinkerFlavor, Lld, TargetOptions};

pub fn opts() -> TargetOptions {
let base = base::windows_gnu::opts();

// FIXME: This should be updated for the exception machinery changes from #67502
// and inherit from `windows_gnu_base`, at least partially.
let mingw_libs = &[
"-lwinstorecompat",
"-lruntimeobject",
"-lsynchronization",
"-lvcruntime140_app",
"-lucrt",
"-lwindowsapp",
"-lmingwex",
"-lmingw32",
];
let mut late_link_args =
TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs);
add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs);
let late_link_args = {
// FIXME: This should be updated for the exception machinery changes from #67502
// and inherit from `windows_gnu_base`, at least partially.
const MINGW_LIBS: &[&str] = &[
"-lwinstorecompat",
"-lruntimeobject",
"-lsynchronization",
"-lvcruntime140_app",
"-lucrt",
"-lwindowsapp",
"-lmingwex",
"-lmingw32",
];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), MINGW_LIBS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), MINGW_LIBS),
])
};
// Reset the flags back to empty until the FIXME above is addressed.
let late_link_args_dynamic = LinkArgs::new();
let late_link_args_static = LinkArgs::new();
let late_link_args_dynamic = Default::default();
let late_link_args_static = Default::default();

TargetOptions {
abi: "uwp".into(),
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ pub fn opts() -> TargetOptions {

opts.abi = "uwp".into();
opts.vendor = "uwp".into();
opts.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/APPCONTAINER", "mincore.lib"]);
opts.pre_link_args =
TargetOptions::link_args(LinkerFlavor::Msvc(Lld::No), &["/APPCONTAINER", "mincore.lib"]);

opts
}
Loading

0 comments on commit d013d1a

Please sign in to comment.