From 2b1dc3144bd38e3f655bcc991b685d824f4176f6 Mon Sep 17 00:00:00 2001 From: "Eddy (Eduard) Stefes" Date: Wed, 14 Jan 2026 13:08:10 +0100 Subject: [PATCH] add a new s390x-unknown-none-softfloat target This target is intended to be used for kernel development. Becasue on s390x float and vector registers overlap we have to disable the vector extension. The default s390x-unknown-gnu-linux target will not allow use of softfloat. Co-authored-by: Jubilee --- compiler/rustc_target/src/spec/mod.rs | 8 ++ .../targets/s390x_unknown_none_softfloat.rs | 39 ++++++++++ compiler/rustc_target/src/target_features.rs | 29 +++++-- src/bootstrap/src/core/sanity.rs | 1 + src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../s390x-unknown-none-softfloat.md | 77 +++++++++++++++++++ tests/assembly-llvm/targets/targets-elf.rs | 3 + 8 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs create mode 100644 src/doc/rustc/src/platform-support/s390x-unknown-none-softfloat.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 9799f3e50ae2..eabfda35028d 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1007,6 +1007,8 @@ crate::target_spec_enum! { X86Sse2 = "x86-sse2", /// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI. X86Softfloat = "x86-softfloat", + // On S390x only: do not use any FPU or Vector registers for the ABI. + S390xSoftFloat = "s390x-softfloat", } parse_error_type = "rustc abi"; @@ -1460,6 +1462,7 @@ supported_targets! { ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), ("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl), ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), + ("s390x-unknown-none-softfloat", s390x_unknown_none_softfloat), ("s390x-unknown-linux-musl", s390x_unknown_linux_musl), ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu), ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), @@ -3209,6 +3212,11 @@ impl Target { Arch::X86 | Arch::X86_64, "`x86-softfloat` ABI is only valid for x86 targets" ), + RustcAbi::S390xSoftFloat => check_matches!( + self.arch, + Arch::S390x, + "`s390x-softfloat` ABI is only valid for s390x targets" + ), } } diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs new file mode 100644 index 000000000000..1453a3d6c9b3 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs @@ -0,0 +1,39 @@ +use rustc_abi::{Align, Endian}; + +use crate::spec::{ + Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, + StackProbeType, Target, TargetMetadata, TargetOptions, +}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + abi: Abi::SoftFloat, + cpu: "z10".into(), + endian: Endian::Big, + features: "+soft-float,-vector".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + max_atomic_width: Some(128), + min_global_align: Some(Align::from_bits(16).unwrap()), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + rustc_abi: Some(RustcAbi::S390xSoftFloat), + stack_probes: StackProbeType::Inline, + supported_sanitizers: SanitizerSet::KERNELADDRESS, + ..Default::default() + }; + + Target { + llvm_target: "s390x-unknown-linux-gnu".into(), + metadata: TargetMetadata { + description: Some("S390x Linux".into()), + host_tools: Some(false), + std: Some(false), + tier: Some(2), + }, + arch: Arch::S390x, + data_layout: "E-S64-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), + options: opts, + pointer_width: 64, + } +} diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index bc12e1eb9737..671761a4edd4 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -863,7 +863,7 @@ const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("miscellaneous-extensions-3", Stable, &[]), ("miscellaneous-extensions-4", Stable, &[]), ("nnp-assist", Stable, &["vector"]), - ("soft-float", Forbidden { reason: "currently unsupported ABI-configuration feature" }, &[]), + ("soft-float", Forbidden { reason: "unsupported ABI-configuration feature" }, &[]), ("transactional-execution", Unstable(sym::s390x_target_feature), &[]), ("vector", Stable, &[]), ("vector-enhancements-1", Stable, &["vector"]), @@ -1105,6 +1105,7 @@ impl Target { // LLVM handles the rest. FeatureConstraints { required: &["soft-float"], incompatible: &[] } } + Some(r) => panic!("invalid Rust ABI for x86: {r:?}"), } } Arch::X86_64 => { @@ -1218,11 +1219,27 @@ impl Target { } } Arch::S390x => { - // We don't currently support a softfloat target on this architecture. - // As usual, we have to reject swapping the `soft-float` target feature. - // The "vector" target feature does not affect the ABI for floats - // because the vector and float registers overlap. - FeatureConstraints { required: &[], incompatible: &["soft-float"] } + // Same as x86, We use our own ABI indicator here; + // LLVM does not have anything native and will switch ABI based + // on the soft-float target feature. + // Every case should require or forbid `soft-float`! + // The "vector" target feature may only be used without soft-float + // because the float and vector registers overlap and the + // standard s390x C ABI may pass vectors via these registers. + match self.rustc_abi { + None => { + // Default hardfloat ABI. + FeatureConstraints { required: &[], incompatible: &["soft-float"] } + } + Some(RustcAbi::S390xSoftFloat) => { + // Softfloat ABI, requires corresponding target feature. + // llvm will switch to soft-float ABI just based on this feature. + FeatureConstraints { required: &["soft-float"], incompatible: &["vector"] } + } + Some(r) => { + panic!("invalid Rust ABI for s390x: {r:?}"); + } + } } _ => NOTHING, } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 8b6405afa892..e5327ab79ee2 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -48,6 +48,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ "thumbv6-none-eabi", "aarch64v8r-unknown-none", "aarch64v8r-unknown-none-softfloat", + "s390x-unknown-none-softfloat", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 2ec0c3648bdf..9049828c8b12 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -120,6 +120,7 @@ - [riscv64a23-unknown-linux-gnu](platform-support/riscv64a23-unknown-linux-gnu.md) - [s390x-unknown-linux-gnu](platform-support/s390x-unknown-linux-gnu.md) - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md) + - [s390x-unknown-none-softfloat](platform-support/s390x-unknown-none-softfloat.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) - [solaris](platform-support/solaris.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 114f66282afd..29553f9c2a00 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -188,6 +188,7 @@ target | std | notes [`riscv64im-unknown-none-elf`](platform-support/riscv64im-unknown-none-elf.md) | * | Bare RISC-V (RV64IM ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4+, glibc 2.23) +[`s390x-unknown-none-softfloat`](platform-support/s390x-unknown-none-softfloat.md) | * | Bare S390x (softfloat ABI) [`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M [`thumbv7em-none-eabi`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M [`thumbv7em-none-eabihf`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M, hardfloat diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-none-softfloat.md b/src/doc/rustc/src/platform-support/s390x-unknown-none-softfloat.md new file mode 100644 index 000000000000..39a1a7c52c39 --- /dev/null +++ b/src/doc/rustc/src/platform-support/s390x-unknown-none-softfloat.md @@ -0,0 +1,77 @@ +# `s390x-unknown-none-softfloat` + +**Tier: 2** + +IBM z/Architecture (s390x) code in ELF format for kernels, etc. + +## Target maintainers + +[@uweigand](https://github.com/uweigand) +[@cuviper](https://github.com/cuviper) + +## Requirements + +This target is intended for kernel development on s390x only. This target is +cross-compiled. There is no support for `std`.There is no default allocator, +but it's possible to use `alloc` by supplying an allocator. + +The target does not assume existence of a FPU and does not make use of any +non-GPR register. This allows the generated code to run in environments, such +as kernels, which may need to avoid the use of such registers or which may have +special considerations about the use of such registers (e.g. saving and +restoring them to avoid breaking userspace code using the same registers). You +can change code generation to use additional CPU features via the +`-C target-feature=` codegen options to rustc, or via the `#[target_feature]` +mechanism within Rust code. + +By default, code generated with the soft-float target should run on any Z System +starting at [Z10][s390x-isa]. Enabling additional target features or changing the +`-Ctarget-cpu` may raise the ISA required from the `z10` baseline. + +`extern "C"` does not use a stable ABI and is subject to change between compiler +or codegen backend versions. + +The target only generates object files in the ELF format. Any alternate formats +or special considerations for binary layout will require linker options or linker +scripts. + +* [z/Architecture Principles of Operation][s390x-isa] + +[s390x-isa]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf +[s390x-abi]: https://github.com/IBM/s390x-abi + +## Building the target + +You can build Rust with support for the target by adding it to the `target` +list in `bootstrap.toml`: + +```toml +[build] +target = ["s390x-unknown-none-softfloat"] +``` + +## Building Rust programs + +This target is not intended to build stand-alone binaries. You should only use +it in conjunction with the kernel build toolchain. + +## Testing + +As code generated by this target is intended to always be part of the kernel, +there are no additional requirements for testing. + +If you want to do native testing but do not have your own s390x +machine, there are several options how to get access to one: + +* The [IBM LinuxONE Community Cloud][cloud-community] provides a + self-service portal where you can create s390x virtual machine + instances. These are intended for temporary use (limited to 120 days). + +* The [IBM LinuxONE Open Source Cloud][cloud-opensource] provides + permanent access to s390x machines. This requires approval by IBM, + which will normally be granted if you're planning to use the machine + to work on an open-source project that is relevant to the IBM Z + ecosystem - the Rust compiler would certainly qualify. + +[cloud-community]: https://linuxone.cloud.marist.edu/ +[cloud-opensource]: https://community.ibm.com/zsystems/form/l1cc-oss-vm-request/ diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index c38e86315b27..b7deb6686cfe 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -544,6 +544,9 @@ //@ revisions: s390x_unknown_linux_musl //@ [s390x_unknown_linux_musl] compile-flags: --target s390x-unknown-linux-musl //@ [s390x_unknown_linux_musl] needs-llvm-components: systemz +//@ revisions: s390x_unknown_none_softfloat +//@ [s390x_unknown_none_softfloat] compile-flags: --target s390x-unknown-none-softfloat +//@ [s390x_unknown_none_softfloat] needs-llvm-components: systemz //@ revisions: sparc64_unknown_helenos //@ [sparc64_unknown_helenos] compile-flags: --target sparc64-unknown-helenos //@ [sparc64_unknown_helenos] needs-llvm-components: sparc