Skip to content
Merged
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
12 changes: 3 additions & 9 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use rustc_fs_util::{link_or_copy, path_to_c_string};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym};
use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext};
use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
use tracing::{debug, trace};

Expand Down Expand Up @@ -209,14 +209,8 @@ pub(crate) fn target_machine_factory(

let code_model = to_llvm_code_model(sess.code_model());

let mut singlethread = sess.target.singlethread;

// On the wasm target once the `atomics` feature is enabled that means that
// we're no longer single-threaded, or otherwise we don't want LLVM to
// lower atomic operations to single-threaded operations.
if singlethread && sess.target.is_like_wasm && sess.target_features.contains(&sym::atomics) {
singlethread = false;
}
// This is used to set cfg_has_threads, so all logic must be in this method.
let singlethread = sess.target.singlethread(&sess.target_features);

let triple = SmallCStr::new(&versioned_llvm_target(sess));
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const GATED_CFGS: &[GatedCfg] = &[
sym::cfg_target_has_reliable_f16_f128,
Features::cfg_target_has_reliable_f16_f128,
),
(sym::target_has_threads, sym::cfg_target_has_threads, Features::cfg_target_has_threads),
(sym::target_object_format, sym::cfg_target_object_format, Features::cfg_target_object_format),
];

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ declare_features! (
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
/// Allows checking whether or not the backend correctly supports unstable float types.
(internal, cfg_target_has_reliable_f16_f128, "1.88.0", None),
/// Allows checking whether or not the target might have thread support.
(internal, cfg_target_has_threads, "CURRENT_RUSTC_VERSION", None),
/// Allows identifying the `compiler_builtins` crate.
(internal, compiler_builtins, "1.13.0", None),
/// Allows skipping `ConstParamTy_` trait implementation checks
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_session/src/config/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
| (sym::target_pointer_width, Some(_))
| (sym::target_vendor, None | Some(_))
| (sym::target_has_atomic, Some(_))
| (sym::target_has_threads, None | Some(_))
| (sym::target_has_atomic_primitive_alignment, Some(_))
| (sym::target_has_atomic_load_store, Some(_))
| (sym::target_has_reliable_f16, None | Some(_))
Expand Down Expand Up @@ -303,6 +304,10 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
}
}

if !sess.target.singlethread(&sess.target_features) {
ins_none!(sym::target_has_threads);
}

ins_sym!(sym::target_os, sess.target.os.desc_symbol());
ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width));

Expand Down Expand Up @@ -485,6 +490,7 @@ impl CheckCfg {
ins!(sym::target_has_atomic_primitive_alignment, empty_values).extend(atomic_values);

ins!(sym::target_thread_local, no_values);
ins!(sym::target_has_threads, no_values);

ins!(sym::ub_checks, no_values);
ins!(sym::contract_checks, no_values);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,7 @@ symbols! {
cfg_target_has_atomic,
cfg_target_has_atomic_equal_alignment,
cfg_target_has_reliable_f16_f128,
cfg_target_has_threads,
cfg_target_object_format,
cfg_target_thread_local,
cfg_target_vendor,
Expand Down Expand Up @@ -2084,6 +2085,7 @@ symbols! {
target_has_reliable_f16_math,
target_has_reliable_f128,
target_has_reliable_f128_math,
target_has_threads,
target_object_format,
target_os,
target_pointer_width,
Expand Down
170 changes: 26 additions & 144 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,19 @@
use core::result::Result;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
use std::fmt;
use std::hash::Hash;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{fmt, io};

use rustc_abi::{
Align, CVariadicStatus, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout,
TargetDataLayoutError,
};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display};
use rustc_fs_util::try_canonicalize;
use rustc_macros::{BlobDecodable, Decodable, Encodable, StableHash};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::{Symbol, kw, sym};
use serde_json::Value;
use tracing::debug;
Expand All @@ -67,11 +65,13 @@ pub mod crt_objects;
mod abi_map;
mod base;
mod json;
mod tuple;

pub use abi_map::{AbiMap, AbiMapping};
pub use base::apple;
pub use base::avr::ef_avr_arch;
pub use json::json_schema;
pub use tuple::TargetTuple;

/// Linker is called through a C/C++ compiler.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
Expand Down Expand Up @@ -2256,6 +2256,26 @@ impl Target {
}
}
}

/// Is this target single-threaded?
///
/// This affects both optimizations (e.g., atomics can be lowered to regular operations) and
/// is also exposed as cfg(target_has_threads).
pub fn singlethread(&self, target_features: &FxIndexSet<Symbol>) -> bool {
// On the wasm target once the `atomics` feature is enabled that means that
// we're no longer single-threaded, or otherwise we don't want LLVM to
// lower atomic operations to single-threaded operations.
//
// FIXME: This (probably?) implies that atomics should be a target modifier, at which point
// it probably makes sense to be a separate target to ship precompiled artifacts for it?
//
// cc #77839 (tracking issue for wasm atomics)
if self.singlethread && self.is_like_wasm && target_features.contains(&sym::atomics) {
return false;
}

self.singlethread
}
}

pub trait HasTargetSpec {
Expand Down Expand Up @@ -2571,7 +2591,8 @@ pub struct TargetOptions {
pub requires_lto: bool,

/// This target has no support for threads.
pub singlethread: bool,
// This is private because wasm changes this depending on target features.
singlethread: bool,

/// Whether library functions call lowering/optimization is disabled in LLVM
/// for this target unconditionally.
Expand Down Expand Up @@ -3893,142 +3914,3 @@ impl Target {
Symbol::intern(&self.vendor)
}
}

/// Either a target tuple string or a path to a JSON file.
#[derive(Clone, Debug)]
pub enum TargetTuple {
TargetTuple(String),
TargetJson {
/// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to
/// inconsistencies as it is discarded during serialization.
path_for_rustdoc: PathBuf,
tuple: String,
contents: String,
},
}

// Use a manual implementation to ignore the path field
impl PartialEq for TargetTuple {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::TargetTuple(l0), Self::TargetTuple(r0)) => l0 == r0,
(
Self::TargetJson { path_for_rustdoc: _, tuple: l_tuple, contents: l_contents },
Self::TargetJson { path_for_rustdoc: _, tuple: r_tuple, contents: r_contents },
) => l_tuple == r_tuple && l_contents == r_contents,
_ => false,
}
}
}

// Use a manual implementation to ignore the path field
impl Hash for TargetTuple {
fn hash<H: Hasher>(&self, state: &mut H) -> () {
match self {
TargetTuple::TargetTuple(tuple) => {
0u8.hash(state);
tuple.hash(state)
}
TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => {
1u8.hash(state);
tuple.hash(state);
contents.hash(state)
}
}
}
}

// Use a manual implementation to prevent encoding the target json file path in the crate metadata
impl<S: Encoder> Encodable<S> for TargetTuple {
fn encode(&self, s: &mut S) {
match self {
TargetTuple::TargetTuple(tuple) => {
s.emit_u8(0);
s.emit_str(tuple);
}
TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => {
s.emit_u8(1);
s.emit_str(tuple);
s.emit_str(contents);
}
}
}
}

impl<D: Decoder> Decodable<D> for TargetTuple {
fn decode(d: &mut D) -> Self {
match d.read_u8() {
0 => TargetTuple::TargetTuple(d.read_str().to_owned()),
1 => TargetTuple::TargetJson {
path_for_rustdoc: PathBuf::new(),
tuple: d.read_str().to_owned(),
contents: d.read_str().to_owned(),
},
_ => {
panic!("invalid enum variant tag while decoding `TargetTuple`, expected 0..2");
}
}
}
}

impl TargetTuple {
/// Creates a target tuple from the passed target tuple string.
pub fn from_tuple(tuple: &str) -> Self {
TargetTuple::TargetTuple(tuple.into())
}

/// Creates a target tuple from the passed target path.
pub fn from_path(path: &Path) -> Result<Self, io::Error> {
let canonicalized_path = try_canonicalize(path)?;
let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("target path {canonicalized_path:?} is not a valid file: {err}"),
)
})?;
let tuple = canonicalized_path
.file_stem()
.expect("target path must not be empty")
.to_str()
.expect("target path must be valid unicode")
.to_owned();
Ok(TargetTuple::TargetJson { path_for_rustdoc: canonicalized_path, tuple, contents })
}

/// Returns a string tuple for this target.
///
/// If this target is a path, the file name (without extension) is returned.
pub fn tuple(&self) -> &str {
match *self {
TargetTuple::TargetTuple(ref tuple) | TargetTuple::TargetJson { ref tuple, .. } => {
tuple
}
}
}

/// Returns an extended string tuple for this target.
///
/// If this target is a path, a hash of the path is appended to the tuple returned
/// by `tuple()`.
pub fn debug_tuple(&self) -> String {
use std::hash::DefaultHasher;

match self {
TargetTuple::TargetTuple(tuple) => tuple.to_owned(),
TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents: content } => {
let mut hasher = DefaultHasher::new();
content.hash(&mut hasher);
let hash = hasher.finish();
format!("{tuple}-{hash}")
}
}
}
}

impl fmt::Display for TargetTuple {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.debug_tuple())
}
}

into_diag_arg_using_display!(&TargetTuple);
Loading
Loading