Skip to content

Commit c343781

Browse files
Rollup merge of #136146 - RalfJung:x86-abi, r=workingjubilee
Explicitly choose x86 softfloat/hardfloat ABI Part of #135408: Instead of choosing this based on the target features listed in the target spec, make that choice explicit. This means that all x86 (32bit and 64bit) softfloat target need to explicitly set `rustc-abi` to `x86-softfloat`. Also fix some mistakes in the platform-docs where the x87 errata footnotes were missing or wrong.
2 parents 9ec6ab8 + 6fe68d0 commit c343781

22 files changed

+164
-63
lines changed

compiler/rustc_target/src/spec/json.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,19 @@ impl Target {
128128
Some(Ok(()))
129129
})).unwrap_or(Ok(()))
130130
} );
131+
($key_name:ident, RustcAbi) => ( {
132+
let name = (stringify!($key_name)).replace("_", "-");
133+
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
134+
match s.parse::<super::RustcAbi>() {
135+
Ok(rustc_abi) => base.$key_name = Some(rustc_abi),
136+
_ => return Some(Err(format!(
137+
"'{s}' is not a valid value for rustc-abi. \
138+
Use 'x86-softfloat' or leave the field unset."
139+
))),
140+
}
141+
Some(Ok(()))
142+
})).unwrap_or(Ok(()))
143+
} );
131144
($key_name:ident, RelocModel) => ( {
132145
let name = (stringify!($key_name)).replace("_", "-");
133146
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
@@ -612,6 +625,7 @@ impl Target {
612625
key!(llvm_mcount_intrinsic, optional);
613626
key!(llvm_abiname);
614627
key!(llvm_floatabi, FloatAbi)?;
628+
key!(rustc_abi, RustcAbi)?;
615629
key!(relax_elf_relocations, bool);
616630
key!(llvm_args, list);
617631
key!(use_ctors_section, bool);
@@ -788,6 +802,7 @@ impl ToJson for Target {
788802
target_option_val!(llvm_mcount_intrinsic);
789803
target_option_val!(llvm_abiname);
790804
target_option_val!(llvm_floatabi);
805+
target_option_val!(rustc_abi);
791806
target_option_val!(relax_elf_relocations);
792807
target_option_val!(llvm_args);
793808
target_option_val!(use_ctors_section);

compiler/rustc_target/src/spec/mod.rs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,33 @@ impl ToJson for FloatAbi {
11141114
}
11151115
}
11161116

1117+
/// The Rustc-specific variant of the ABI used for this target.
1118+
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
1119+
pub enum RustcAbi {
1120+
/// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI.
1121+
X86Softfloat,
1122+
}
1123+
1124+
impl FromStr for RustcAbi {
1125+
type Err = ();
1126+
1127+
fn from_str(s: &str) -> Result<RustcAbi, ()> {
1128+
Ok(match s {
1129+
"x86-softfloat" => RustcAbi::X86Softfloat,
1130+
_ => return Err(()),
1131+
})
1132+
}
1133+
}
1134+
1135+
impl ToJson for RustcAbi {
1136+
fn to_json(&self) -> Json {
1137+
match *self {
1138+
RustcAbi::X86Softfloat => "x86-softfloat",
1139+
}
1140+
.to_json()
1141+
}
1142+
}
1143+
11171144
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
11181145
pub enum TlsModel {
11191146
GeneralDynamic,
@@ -2505,6 +2532,12 @@ pub struct TargetOptions {
25052532
/// If not provided, LLVM will infer the float ABI from the target triple (`llvm_target`).
25062533
pub llvm_floatabi: Option<FloatAbi>,
25072534

2535+
/// Picks a specific ABI for this target. This is *not* just for "Rust" ABI functions,
2536+
/// it can also affect "C" ABI functions; the point is that this flag is interpreted by
2537+
/// rustc and not forwarded to LLVM.
2538+
/// So far, this is only used on x86.
2539+
pub rustc_abi: Option<RustcAbi>,
2540+
25082541
/// Whether or not RelaxElfRelocation flag will be passed to the linker
25092542
pub relax_elf_relocations: bool,
25102543

@@ -2664,10 +2697,6 @@ impl TargetOptions {
26642697
.collect();
26652698
}
26662699
}
2667-
2668-
pub(crate) fn has_feature(&self, search_feature: &str) -> bool {
2669-
self.features.split(',').any(|f| f.strip_prefix('+').is_some_and(|f| f == search_feature))
2670-
}
26712700
}
26722701

26732702
impl Default for TargetOptions {
@@ -2774,6 +2803,7 @@ impl Default for TargetOptions {
27742803
llvm_mcount_intrinsic: None,
27752804
llvm_abiname: "".into(),
27762805
llvm_floatabi: None,
2806+
rustc_abi: None,
27772807
relax_elf_relocations: false,
27782808
llvm_args: cvs![],
27792809
use_ctors_section: false,
@@ -3240,6 +3270,17 @@ impl Target {
32403270
_ => {}
32413271
}
32423272

3273+
// Check consistency of Rust ABI declaration.
3274+
if let Some(rust_abi) = self.rustc_abi {
3275+
match rust_abi {
3276+
RustcAbi::X86Softfloat => check_matches!(
3277+
&*self.arch,
3278+
"x86" | "x86_64",
3279+
"`x86-softfloat` ABI is only valid for x86 targets"
3280+
),
3281+
}
3282+
}
3283+
32433284
// Check that the given target-features string makes some basic sense.
32443285
if !self.features.is_empty() {
32453286
let mut features_enabled = FxHashSet::default();

compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// The cdecl ABI is used. It differs from the stdcall or fastcall ABI.
66
// "i686-unknown-windows" is used to get the minimal subset of windows-specific features.
77

8-
use crate::spec::{Target, base};
8+
use crate::spec::{RustcAbi, Target, base};
99

1010
pub(crate) fn target() -> Target {
1111
let mut base = base::uefi_msvc::opts();
@@ -22,6 +22,7 @@ pub(crate) fn target() -> Target {
2222
// If you initialize FP units yourself, you can override these flags with custom linker
2323
// arguments, thus giving you access to full MMX/SSE acceleration.
2424
base.features = "-mmx,-sse,+soft-float".into();
25+
base.rustc_abi = Some(RustcAbi::X86Softfloat);
2526

2627
// Use -GNU here, because of the reason below:
2728
// Background and Problem:

compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
// features.
66

77
use crate::spec::{
8-
Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelroLevel, SanitizerSet, StackProbeType,
9-
Target, TargetOptions,
8+
Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelroLevel, RustcAbi, SanitizerSet,
9+
StackProbeType, Target, TargetOptions,
1010
};
1111

1212
pub(crate) fn target() -> Target {
@@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
2020
relro_level: RelroLevel::Full,
2121
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
2222
linker: Some("rust-lld".into()),
23+
rustc_abi: Some(RustcAbi::X86Softfloat),
2324
features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float".into(),
2425
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
2526
disable_redzone: true,

compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
77

88
use crate::abi::call::Conv;
9-
use crate::spec::{Target, base};
9+
use crate::spec::{RustcAbi, Target, base};
1010

1111
pub(crate) fn target() -> Target {
1212
let mut base = base::uefi_msvc::opts();
@@ -26,6 +26,7 @@ pub(crate) fn target() -> Target {
2626
// If you initialize FP units yourself, you can override these flags with custom linker
2727
// arguments, thus giving you access to full MMX/SSE acceleration.
2828
base.features = "-mmx,-sse,+soft-float".into();
29+
base.rustc_abi = Some(RustcAbi::X86Softfloat);
2930

3031
Target {
3132
llvm_target: "x86_64-unknown-windows".into(),

compiler/rustc_target/src/target_features.rs

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
55
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
66
use rustc_span::{Symbol, sym};
77

8-
use crate::spec::{FloatAbi, Target};
8+
use crate::spec::{FloatAbi, RustcAbi, Target};
99

1010
/// Features that control behaviour of rustc, rather than the codegen.
1111
/// These exist globally and are not in the target-specific lists below.
@@ -422,7 +422,9 @@ const X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
422422
("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
423423
("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
424424
("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
425-
("soft-float", Stability::Forbidden { reason: "unsound because it changes float ABI" }, &[]),
425+
// This cannot actually be toggled, the ABI always fixes it, so it'd make little sense to
426+
// stabilize. It must be in this list for the ABI check to be able to use it.
427+
("soft-float", Stability::Unstable(sym::x87_target_feature), &[]),
426428
("sse", Stable, &[]),
427429
("sse2", Stable, &["sse"]),
428430
("sse3", Stable, &["sse2"]),
@@ -773,23 +775,41 @@ impl Target {
773775
// questions "which ABI is used".
774776
match &*self.arch {
775777
"x86" => {
776-
// We support 2 ABIs, hardfloat (default) and softfloat.
777-
// x86 has no sane ABI indicator so we have to use the target feature.
778-
if self.has_feature("soft-float") {
779-
NOTHING
780-
} else {
781-
// Hardfloat ABI. x87 must be enabled.
782-
FeatureConstraints { required: &["x87"], incompatible: &[] }
778+
// We use our own ABI indicator here; LLVM does not have anything native.
779+
// Every case should require or forbid `soft-float`!
780+
match self.rustc_abi {
781+
None => {
782+
// Default hardfloat ABI.
783+
// x87 must be enabled, soft-float must be disabled.
784+
FeatureConstraints { required: &["x87"], incompatible: &["soft-float"] }
785+
}
786+
Some(RustcAbi::X86Softfloat) => {
787+
// Softfloat ABI, requires corresponding target feature. That feature trumps
788+
// `x87` and all other FPU features so those do not matter.
789+
// Note that this one requirement is the entire implementation of the ABI!
790+
// LLVM handles the rest.
791+
FeatureConstraints { required: &["soft-float"], incompatible: &[] }
792+
}
783793
}
784794
}
785795
"x86_64" => {
786-
// We support 2 ABIs, hardfloat (default) and softfloat.
787-
// x86 has no sane ABI indicator so we have to use the target feature.
788-
if self.has_feature("soft-float") {
789-
NOTHING
790-
} else {
791-
// Hardfloat ABI. x87 and SSE2 must be enabled.
792-
FeatureConstraints { required: &["x87", "sse2"], incompatible: &[] }
796+
// We use our own ABI indicator here; LLVM does not have anything native.
797+
// Every case should require or forbid `soft-float`!
798+
match self.rustc_abi {
799+
None => {
800+
// Default hardfloat ABI. On x86-64, this always includes SSE2.
801+
FeatureConstraints {
802+
required: &["x87", "sse2"],
803+
incompatible: &["soft-float"],
804+
}
805+
}
806+
Some(RustcAbi::X86Softfloat) => {
807+
// Softfloat ABI, requires corresponding target feature. That feature trumps
808+
// `x87` and all other FPU features so those do not matter.
809+
// Note that this one requirement is the entire implementation of the ABI!
810+
// LLVM handles the rest.
811+
FeatureConstraints { required: &["soft-float"], incompatible: &[] }
812+
}
793813
}
794814
}
795815
"arm" => {

src/doc/rustc/src/platform-support.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,13 +309,13 @@ target | std | host | notes
309309
[`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | | Bare Hexagon (v60+, HVX)
310310
[`i386-apple-ios`](platform-support/apple-ios.md) | ✓ | | 32-bit x86 iOS [^x86_32-floats-return-ABI]
311311
[`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS [^x86_32-floats-return-ABI]
312-
[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86, restricted to Pentium
312+
[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86, restricted to Pentium [^x86_32-floats-x87]
313313
[`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI]
314-
`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku [^x86_32-floats-return-ABI]
315-
[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI]
314+
`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku with SSE [^x86_32-floats-return-ABI]
315+
[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd w/o SSE [^x86_32-floats-x87]
316316
[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI]
317-
[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [^x86_32-floats-return-ABI]
318-
[`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS
317+
[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD with SSE2 [^x86_32-floats-return-ABI]
318+
[`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS w/o SSE [^x86_32-floats-x87]
319319
`i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI]
320320
[`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [^x86_32-floats-return-ABI]
321321
[`i686-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI]

tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! Ensure ABI-incompatible features cannot be enabled via `#[target_feature]`.
12
//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib
23
//@ needs-llvm-components: riscv
34
#![feature(no_core, lang_items, riscv_target_feature)]

tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI
2-
--> $DIR/forbidden-hardfloat-target-feature-attribute.rs:9:18
2+
--> $DIR/forbidden-hardfloat-target-feature-attribute.rs:10:18
33
|
44
LL | #[target_feature(enable = "d")]
55
| ^^^^^^^^^^^^

tests/ui/target-feature/forbidden-hardfloat-target-feature-cfg.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.

tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
//! Ensure that if disabling a target feature implies disabling an ABI-required target feature,
2+
//! we complain.
13
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
24
//@ needs-llvm-components: x86
35
//@ compile-flags: -Ctarget-feature=-sse
46
// For now this is just a warning.
57
//@ build-pass
8+
//@error-pattern: must be enabled to ensure that the ABI
69
#![feature(no_core, lang_items)]
710
#![no_core]
811

tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//@ compile-flags: -Ctarget-feature=-neon
44
// For now this is just a warning.
55
//@ build-pass
6+
//@error-pattern: must be enabled to ensure that the ABI
67
#![feature(no_core, lang_items)]
78
#![no_core]
89

tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
//! Ensure ABI-required features cannot be disabled via `-Ctarget-feature`.
12
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
23
//@ needs-llvm-components: x86
34
//@ compile-flags: -Ctarget-feature=-x87
45
// For now this is just a warning.
56
//@ build-pass
7+
//@error-pattern: must be enabled to ensure that the ABI
68
#![feature(no_core, lang_items)]
79
#![no_core]
810

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! Ensure ABI-incompatible features cannot be enabled via `-Ctarget-feature`.
2+
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
3+
//@ needs-llvm-components: x86
4+
//@ compile-flags: -Ctarget-feature=+soft-float
5+
// For now this is just a warning.
6+
//@ build-pass
7+
//@error-pattern: must be disabled to ensure that the ABI
8+
#![feature(no_core, lang_items, riscv_target_feature)]
9+
#![no_core]
10+
11+
#[lang = "sized"]
12+
pub trait Sized {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly
2+
|
3+
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
4+
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
5+
6+
warning: unstable feature specified for `-Ctarget-feature`: `soft-float`
7+
|
8+
= note: this feature is not stably supported; its behavior can change in the future
9+
10+
warning: 2 warnings emitted
11+
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
2-
//@ needs-llvm-components: x86
1+
//! Ensure "forbidden" target features cannot be enabled via `#[target_feature]`.
2+
//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib
3+
//@ needs-llvm-components: riscv
34
#![feature(no_core, lang_items)]
45
#![no_core]
56

67
#[lang = "sized"]
78
pub trait Sized {}
89

9-
#[target_feature(enable = "soft-float")]
10+
#[target_feature(enable = "forced-atomics")]
1011
//~^ERROR: cannot be enabled with
1112
pub unsafe fn my_fun() {}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: target feature `soft-float` cannot be enabled with `#[target_feature]`: unsound because it changes float ABI
2-
--> $DIR/forbidden-target-feature-attribute.rs:9:18
1+
error: target feature `forced-atomics` cannot be enabled with `#[target_feature]`: unsound because it changes the ABI of atomic operations
2+
--> $DIR/forbidden-target-feature-attribute.rs:10:18
33
|
4-
LL | #[target_feature(enable = "soft-float")]
5-
| ^^^^^^^^^^^^^^^^^^^^^
4+
LL | #[target_feature(enable = "forced-atomics")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
66

77
error: aborting due to 1 previous error
88

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
//@ compile-flags: --target=x86_64-unknown-none --crate-type=lib
2-
//@ needs-llvm-components: x86
1+
//! Ensure "forbidden" target features are not exposed via `cfg`.
2+
//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib
3+
//@ needs-llvm-components: riscv
34
//@ check-pass
45
#![feature(no_core, lang_items)]
56
#![no_core]
@@ -10,5 +11,5 @@ pub trait Sized {}
1011

1112
// The compile_error macro does not exist, so if the `cfg` evaluates to `true` this
1213
// complains about the missing macro rather than showing the error... but that's good enough.
13-
#[cfg(target_feature = "soft-float")]
14-
compile_error!("the soft-float feature should not be exposed in `cfg`");
14+
#[cfg(target_feature = "forced-atomics")]
15+
compile_error!("the forced-atomics feature should not be exposed in `cfg`");

0 commit comments

Comments
 (0)