Skip to content

Lazify Target::llvm_target field #126702

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
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
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
144 changes: 144 additions & 0 deletions compiler/rustc_target/src/spec/maybe_lazy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
//! A custom LazyLock+Cow suitable for holding borrowed, owned or lazy data.

use std::borrow::{Borrow, Cow};
use std::fmt::{Debug, Display};
use std::ops::Deref;
use std::sync::LazyLock;

enum MaybeLazyInner<T: 'static + ToOwned + ?Sized, F> {
Lazy(LazyLock<T::Owned, F>),
Cow(Cow<'static, T>),
}

/// A custom LazyLock+Cow suitable for holding borrowed, owned or lazy data.
///
/// Technically this structure has 3 states: borrowed, owned and lazy
/// They can all be constructed from the [`MaybeLazy::borrowed`], [`MaybeLazy::owned`] and
/// [`MaybeLazy::lazy`] methods.
#[repr(transparent)]
pub struct MaybeLazy<T: 'static + ToOwned + ?Sized, F = fn() -> <T as ToOwned>::Owned> {
// Inner state.
//
// Not to be inlined since we may want in the future to
// make this struct usable to statics and we might need to
// workaround const-eval limitation (particulary around drop).
inner: MaybeLazyInner<T, F>,
}

impl<T: 'static + ?Sized + ToOwned, F: FnOnce() -> T::Owned> MaybeLazy<T, F> {
/// Create a [`MaybeLazy`] from an borrowed `T`.
#[inline]
pub const fn borrowed(a: &'static T) -> Self {
MaybeLazy { inner: MaybeLazyInner::Cow(Cow::Borrowed(a)) }
}

/// Create a [`MaybeLazy`] from an borrowed `T`.
#[inline]
pub const fn owned(a: T::Owned) -> Self {
MaybeLazy { inner: MaybeLazyInner::Cow(Cow::Owned(a)) }
}

/// Create a [`MaybeLazy`] from a function-able `F`.
#[inline]
pub const fn lazied(f: F) -> Self {
MaybeLazy { inner: MaybeLazyInner::Lazy(LazyLock::new(f)) }
}
}

impl<T: 'static + ?Sized + ToOwned> MaybeLazy<T> {
/// Create a [`MaybeLazy`] from a function pointer.
#[inline]
pub const fn lazy(a: fn() -> T::Owned) -> Self {
Self::lazied(a)
}
}

impl<T: 'static + ?Sized + ToOwned<Owned: Clone>, F: FnOnce() -> T::Owned> Clone
for MaybeLazy<T, F>
{
#[inline]
fn clone(&self) -> Self {
MaybeLazy {
inner: MaybeLazyInner::Cow(match &self.inner {
MaybeLazyInner::Lazy(f) => Cow::Owned((*f).to_owned()),
MaybeLazyInner::Cow(c) => c.clone(),
}),
}
}
}

impl<T: 'static + ?Sized + ToOwned<Owned: Default>, F: FnOnce() -> T::Owned> Default
for MaybeLazy<T, F>
{
#[inline]
fn default() -> MaybeLazy<T, F> {
MaybeLazy::owned(T::Owned::default())
}
}

// `Debug`, `Display` and other traits below are implemented in terms of this `Deref`
impl<T: 'static + ?Sized + ToOwned<Owned: Borrow<T>>, F: FnOnce() -> T::Owned> Deref
for MaybeLazy<T, F>
{
type Target = T;

#[inline]
fn deref(&self) -> &T {
match &self.inner {
MaybeLazyInner::Lazy(f) => (&**f).borrow(),
MaybeLazyInner::Cow(c) => &*c,
}
}
}

impl<T: 'static + ?Sized + ToOwned<Owned: Debug> + Debug, F: FnOnce() -> T::Owned> Debug
for MaybeLazy<T, F>
{
#[inline]
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&**self, fmt)
}
}

impl<T: 'static + ?Sized + ToOwned<Owned: Display> + Display, F: FnOnce() -> T::Owned> Display
for MaybeLazy<T, F>
{
#[inline]
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&**self, fmt)
}
}

impl<T: 'static + ?Sized + ToOwned, F: FnOnce() -> T::Owned> AsRef<T> for MaybeLazy<T, F> {
#[inline]
fn as_ref(&self) -> &T {
&**self
}
}

impl<
T1: ?Sized + PartialEq<T2> + ToOwned,
T2: ?Sized + ToOwned,
F1: FnOnce() -> T1::Owned,
F2: FnOnce() -> T2::Owned,
> PartialEq<MaybeLazy<T2, F2>> for MaybeLazy<T1, F1>
{
#[inline]
fn eq(&self, other: &MaybeLazy<T2, F2>) -> bool {
PartialEq::eq(&**self, &**other)
}
}

impl<F: FnOnce() -> String> PartialEq<&str> for MaybeLazy<str, F> {
#[inline]
fn eq(&self, other: &&str) -> bool {
&**self == *other
}
}

impl<F: FnOnce() -> String> From<&'static str> for MaybeLazy<str, F> {
#[inline]
fn from(s: &'static str) -> MaybeLazy<str, F> {
MaybeLazy::borrowed(s)
}
}
6 changes: 4 additions & 2 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors
use crate::json::{Json, ToJson};
use crate::spec::abi::Abi;
use crate::spec::crt_objects::CrtObjects;
use crate::spec::maybe_lazy::MaybeLazy;
use rustc_fs_util::try_canonicalize;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
Expand All @@ -55,6 +56,7 @@ use tracing::debug;

pub mod abi;
pub mod crt_objects;
pub mod maybe_lazy;

mod base;
pub use base::apple::deployment_target as current_apple_deployment_target;
Expand Down Expand Up @@ -1879,7 +1881,7 @@ impl TargetWarnings {
#[derive(PartialEq, Clone, Debug)]
pub struct Target {
/// Target triple to pass to LLVM.
pub llvm_target: StaticCow<str>,
pub llvm_target: MaybeLazy<str>,
/// Metadata about a target, for example the description or tier.
/// Used for generating target documentation.
pub metadata: TargetMetadata,
Expand Down Expand Up @@ -2734,7 +2736,7 @@ impl Target {
};

let mut base = Target {
llvm_target: get_req_field("llvm-target")?.into(),
llvm_target: MaybeLazy::owned(get_req_field("llvm-target")?),
metadata: Default::default(),
pointer_width: get_req_field("target-pointer-width")?
.parse::<u32>()
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, MaybeLazy, SanitizerSet, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
let mut base = opts("macos", arch, TargetAbi::Normal);
const ARCH: Arch = Arch::Arm64;
const OS: &'static str = "macos";
const ABI: TargetAbi = TargetAbi::Normal;

let mut base = opts(OS, ARCH, ABI);
base.cpu = "apple-m1".into();
base.max_atomic_width = Some(128);

Expand All @@ -14,7 +17,7 @@ pub fn target() -> Target {
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
// correctly, we do too.
llvm_target: macos_llvm_target(arch).into(),
llvm_target: MaybeLazy::lazy(|| macos_llvm_target(ARCH)),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
Expand All @@ -23,7 +26,7 @@ pub fn target() -> Target {
},
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: arch.target_arch(),
arch: ARCH.target_arch(),
options: TargetOptions {
mcount: "\u{1}mcount".into(),
frame_pointer: FramePointer::NonLeaf,
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, MaybeLazy, SanitizerSet, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
let mut base = opts("ios", arch, TargetAbi::Normal);
const ARCH: Arch = Arch::Arm64;
const OS: &'static str = "ios";
const ABI: TargetAbi = TargetAbi::Normal;

let mut base = opts(OS, ARCH, ABI);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;

Target {
// Clang automatically chooses a more specific target based on
// IPHONEOS_DEPLOYMENT_TARGET.
// This is required for the target to pick the right
// MACH-O commands, so we do too.
llvm_target: ios_llvm_target(arch).into(),
llvm_target: MaybeLazy::lazy(|| ios_llvm_target(ARCH)),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
Expand All @@ -20,7 +23,7 @@ pub fn target() -> Target {
},
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: arch.target_arch(),
arch: ARCH.target_arch(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".into(),
max_atomic_width: Some(128),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch, TargetAbi};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, MaybeLazy, SanitizerSet, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
let mut base = opts("ios", arch, TargetAbi::MacCatalyst);
const ARCH: Arch = Arch::Arm64;
const OS: &'static str = "ios";
const ABI: TargetAbi = TargetAbi::MacCatalyst;

let mut base = opts(OS, ARCH, ABI);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;

Target {
llvm_target: mac_catalyst_llvm_target(arch).into(),
llvm_target: MaybeLazy::lazy(|| mac_catalyst_llvm_target(ARCH)),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
Expand All @@ -16,7 +19,7 @@ pub fn target() -> Target {
},
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: arch.target_arch(),
arch: ARCH.target_arch(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a12".into(),
max_atomic_width: Some(128),
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, MaybeLazy, SanitizerSet, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
let mut base = opts("ios", arch, TargetAbi::Simulator);
const ARCH: Arch = Arch::Arm64;
const OS: &'static str = "ios";
const ABI: TargetAbi = TargetAbi::Simulator;

let mut base = opts(OS, ARCH, ABI);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;

Target {
// Clang automatically chooses a more specific target based on
// IPHONEOS_DEPLOYMENT_TARGET.
// This is required for the simulator target to pick the right
// MACH-O commands, so we do too.
llvm_target: ios_sim_llvm_target(arch).into(),
llvm_target: MaybeLazy::lazy(|| ios_sim_llvm_target(ARCH)),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
Expand All @@ -20,7 +23,7 @@ pub fn target() -> Target {
},
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: arch.target_arch(),
arch: ARCH.target_arch(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".into(),
max_atomic_width: Some(128),
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::spec::base::apple::{opts, tvos_llvm_target, Arch, TargetAbi};
use crate::spec::{FramePointer, Target, TargetOptions};
use crate::spec::{FramePointer, MaybeLazy, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
const ARCH: Arch = Arch::Arm64;
const OS: &'static str = "tvos";
const ABI: TargetAbi = TargetAbi::Normal;

Target {
llvm_target: tvos_llvm_target(arch).into(),
llvm_target: MaybeLazy::lazy(|| tvos_llvm_target(ARCH)),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
Expand All @@ -13,12 +16,12 @@ pub fn target() -> Target {
},
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: arch.target_arch(),
arch: ARCH.target_arch(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".into(),
max_atomic_width: Some(128),
frame_pointer: FramePointer::NonLeaf,
..opts("tvos", arch, TargetAbi::Normal)
..opts(OS, ARCH, ABI)
},
}
}
13 changes: 8 additions & 5 deletions compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch, TargetAbi};
use crate::spec::{FramePointer, Target, TargetOptions};
use crate::spec::{FramePointer, MaybeLazy, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
const ARCH: Arch = Arch::Arm64;
const OS: &'static str = "tvos";
const ABI: TargetAbi = TargetAbi::Normal;

Target {
llvm_target: tvos_sim_llvm_target(arch).into(),
llvm_target: MaybeLazy::lazy(|| tvos_sim_llvm_target(ARCH)),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
Expand All @@ -13,12 +16,12 @@ pub fn target() -> Target {
},
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: arch.target_arch(),
arch: ARCH.target_arch(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".into(),
max_atomic_width: Some(128),
frame_pointer: FramePointer::NonLeaf,
..opts("tvos", arch, TargetAbi::Simulator)
..opts(OS, ARCH, ABI)
},
}
}
Loading
Loading