1
Fork 0

Auto merge of #136146 - RalfJung:x86-abi, r=workingjubilee

Explicitly choose x86 softfloat/hardfloat ABI

Part of https://github.com/rust-lang/rust/pull/135408:
Instead of choosing this based on the target features listed in the target spec, make that choice explicit.
All built-in targets are being updated here; custom (JSON-defined) x86 (32bit and 64bit) softfloat targets need to explicitly set `rustc-abi` to `x86-softfloat`.
This commit is contained in:
bors 2025-02-03 20:02:54 +00:00
commit f027438f8b
22 changed files with 161 additions and 60 deletions

View file

@ -128,6 +128,19 @@ impl Target {
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, RustcAbi) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<super::RustcAbi>() {
Ok(rustc_abi) => base.$key_name = Some(rustc_abi),
_ => return Some(Err(format!(
"'{s}' is not a valid value for rustc-abi. \
Use 'x86-softfloat' or leave the field unset."
))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, RelocModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
@ -612,6 +625,7 @@ impl Target {
key!(llvm_mcount_intrinsic, optional);
key!(llvm_abiname);
key!(llvm_floatabi, FloatAbi)?;
key!(rustc_abi, RustcAbi)?;
key!(relax_elf_relocations, bool);
key!(llvm_args, list);
key!(use_ctors_section, bool);
@ -788,6 +802,7 @@ impl ToJson for Target {
target_option_val!(llvm_mcount_intrinsic);
target_option_val!(llvm_abiname);
target_option_val!(llvm_floatabi);
target_option_val!(rustc_abi);
target_option_val!(relax_elf_relocations);
target_option_val!(llvm_args);
target_option_val!(use_ctors_section);

View file

@ -1114,6 +1114,33 @@ impl ToJson for FloatAbi {
}
}
/// The Rustc-specific variant of the ABI used for this target.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum RustcAbi {
/// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI.
X86Softfloat,
}
impl FromStr for RustcAbi {
type Err = ();
fn from_str(s: &str) -> Result<RustcAbi, ()> {
Ok(match s {
"x86-softfloat" => RustcAbi::X86Softfloat,
_ => return Err(()),
})
}
}
impl ToJson for RustcAbi {
fn to_json(&self) -> Json {
match *self {
RustcAbi::X86Softfloat => "x86-softfloat",
}
.to_json()
}
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum TlsModel {
GeneralDynamic,
@ -2505,6 +2532,12 @@ pub struct TargetOptions {
/// If not provided, LLVM will infer the float ABI from the target triple (`llvm_target`).
pub llvm_floatabi: Option<FloatAbi>,
/// Picks a specific ABI for this target. This is *not* just for "Rust" ABI functions,
/// it can also affect "C" ABI functions; the point is that this flag is interpreted by
/// rustc and not forwarded to LLVM.
/// So far, this is only used on x86.
pub rustc_abi: Option<RustcAbi>,
/// Whether or not RelaxElfRelocation flag will be passed to the linker
pub relax_elf_relocations: bool,
@ -2664,10 +2697,6 @@ impl TargetOptions {
.collect();
}
}
pub(crate) fn has_feature(&self, search_feature: &str) -> bool {
self.features.split(',').any(|f| f.strip_prefix('+').is_some_and(|f| f == search_feature))
}
}
impl Default for TargetOptions {
@ -2774,6 +2803,7 @@ impl Default for TargetOptions {
llvm_mcount_intrinsic: None,
llvm_abiname: "".into(),
llvm_floatabi: None,
rustc_abi: None,
relax_elf_relocations: false,
llvm_args: cvs![],
use_ctors_section: false,
@ -3240,6 +3270,17 @@ impl Target {
_ => {}
}
// Check consistency of Rust ABI declaration.
if let Some(rust_abi) = self.rustc_abi {
match rust_abi {
RustcAbi::X86Softfloat => check_matches!(
&*self.arch,
"x86" | "x86_64",
"`x86-softfloat` ABI is only valid for x86 targets"
),
}
}
// Check that the given target-features string makes some basic sense.
if !self.features.is_empty() {
let mut features_enabled = FxHashSet::default();

View file

@ -5,7 +5,7 @@
// The cdecl ABI is used. It differs from the stdcall or fastcall ABI.
// "i686-unknown-windows" is used to get the minimal subset of windows-specific features.
use crate::spec::{Target, base};
use crate::spec::{RustcAbi, Target, base};
pub(crate) fn target() -> Target {
let mut base = base::uefi_msvc::opts();
@ -22,6 +22,7 @@ pub(crate) fn target() -> Target {
// If you initialize FP units yourself, you can override these flags with custom linker
// arguments, thus giving you access to full MMX/SSE acceleration.
base.features = "-mmx,-sse,+soft-float".into();
base.rustc_abi = Some(RustcAbi::X86Softfloat);
// Use -GNU here, because of the reason below:
// Background and Problem:

View file

@ -5,8 +5,8 @@
// features.
use crate::spec::{
Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelroLevel, SanitizerSet, StackProbeType,
Target, TargetOptions,
Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelroLevel, RustcAbi, SanitizerSet,
StackProbeType, Target, TargetOptions,
};
pub(crate) fn target() -> Target {
@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
relro_level: RelroLevel::Full,
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
rustc_abi: Some(RustcAbi::X86Softfloat),
features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float".into(),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
disable_redzone: true,

View file

@ -6,7 +6,7 @@
// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
use crate::abi::call::Conv;
use crate::spec::{Target, base};
use crate::spec::{RustcAbi, Target, base};
pub(crate) fn target() -> Target {
let mut base = base::uefi_msvc::opts();
@ -26,6 +26,7 @@ pub(crate) fn target() -> Target {
// If you initialize FP units yourself, you can override these flags with custom linker
// arguments, thus giving you access to full MMX/SSE acceleration.
base.features = "-mmx,-sse,+soft-float".into();
base.rustc_abi = Some(RustcAbi::X86Softfloat);
Target {
llvm_target: "x86_64-unknown-windows".into(),

View file

@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_span::{Symbol, sym};
use crate::spec::{FloatAbi, Target};
use crate::spec::{FloatAbi, RustcAbi, Target};
/// Features that control behaviour of rustc, rather than the codegen.
/// These exist globally and are not in the target-specific lists below.
@ -422,7 +422,9 @@ const X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
("soft-float", Stability::Forbidden { reason: "unsound because it changes float ABI" }, &[]),
// This cannot actually be toggled, the ABI always fixes it, so it'd make little sense to
// stabilize. It must be in this list for the ABI check to be able to use it.
("soft-float", Stability::Unstable(sym::x87_target_feature), &[]),
("sse", Stable, &[]),
("sse2", Stable, &["sse"]),
("sse3", Stable, &["sse2"]),
@ -773,23 +775,41 @@ impl Target {
// questions "which ABI is used".
match &*self.arch {
"x86" => {
// We support 2 ABIs, hardfloat (default) and softfloat.
// x86 has no sane ABI indicator so we have to use the target feature.
if self.has_feature("soft-float") {
NOTHING
} else {
// Hardfloat ABI. x87 must be enabled.
FeatureConstraints { required: &["x87"], incompatible: &[] }
// We use our own ABI indicator here; LLVM does not have anything native.
// Every case should require or forbid `soft-float`!
match self.rustc_abi {
None => {
// Default hardfloat ABI.
// x87 must be enabled, soft-float must be disabled.
FeatureConstraints { required: &["x87"], incompatible: &["soft-float"] }
}
Some(RustcAbi::X86Softfloat) => {
// Softfloat ABI, requires corresponding target feature. That feature trumps
// `x87` and all other FPU features so those do not matter.
// Note that this one requirement is the entire implementation of the ABI!
// LLVM handles the rest.
FeatureConstraints { required: &["soft-float"], incompatible: &[] }
}
}
}
"x86_64" => {
// We support 2 ABIs, hardfloat (default) and softfloat.
// x86 has no sane ABI indicator so we have to use the target feature.
if self.has_feature("soft-float") {
NOTHING
} else {
// Hardfloat ABI. x87 and SSE2 must be enabled.
FeatureConstraints { required: &["x87", "sse2"], incompatible: &[] }
// We use our own ABI indicator here; LLVM does not have anything native.
// Every case should require or forbid `soft-float`!
match self.rustc_abi {
None => {
// Default hardfloat ABI. On x86-64, this always includes SSE2.
FeatureConstraints {
required: &["x87", "sse2"],
incompatible: &["soft-float"],
}
}
Some(RustcAbi::X86Softfloat) => {
// Softfloat ABI, requires corresponding target feature. That feature trumps
// `x87` and all other FPU features so those do not matter.
// Note that this one requirement is the entire implementation of the ABI!
// LLVM handles the rest.
FeatureConstraints { required: &["soft-float"], incompatible: &[] }
}
}
}
"arm" => {