From 624135bd79ccfc6602b013225de4a33d5701035f Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Sat, 13 Dec 2025 20:16:12 +0100 Subject: [PATCH 01/17] Promote powerpc64-unknown-linux-musl to tier 2 with host tools Signed-off-by: Jens Reidel --- .../targets/powerpc64_unknown_linux_musl.rs | 4 +- src/bootstrap/src/core/build_steps/llvm.rs | 1 + src/bootstrap/src/core/download.rs | 1 + .../Dockerfile | 2 +- .../powerpc64-linux-gnu.defconfig | 0 .../dist-powerpc64-linux-musl/Dockerfile | 39 +++++++++++++++++++ .../powerpc64-unknown-linux-musl.defconfig | 15 +++++++ src/ci/github-actions/jobs.yml | 5 ++- src/doc/rustc/src/platform-support.md | 2 +- .../powerpc64-unknown-linux-musl.md | 10 +++-- 10 files changed, 70 insertions(+), 9 deletions(-) rename src/ci/docker/host-x86_64/{dist-powerpc64-linux => dist-powerpc64-linux-gnu}/Dockerfile (89%) rename src/ci/docker/host-x86_64/{dist-powerpc64-linux => dist-powerpc64-linux-gnu}/powerpc64-linux-gnu.defconfig (100%) create mode 100644 src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile create mode 100644 src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index b663ddf962ea..130bcacfc8cc 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -17,8 +17,8 @@ pub(crate) fn target() -> Target { llvm_target: "powerpc64-unknown-linux-musl".into(), metadata: TargetMetadata { description: Some("64-bit PowerPC Linux with musl 1.2.5".into()), - tier: Some(3), - host_tools: Some(false), + tier: Some(2), + host_tools: Some(true), std: Some(true), }, pointer_width: 64, diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index db2a76c4a2df..8acc92451519 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -223,6 +223,7 @@ pub(crate) fn is_ci_llvm_available_for_target( ("loongarch64-unknown-linux-musl", false), ("powerpc-unknown-linux-gnu", false), ("powerpc64-unknown-linux-gnu", false), + ("powerpc64-unknown-linux-musl", false), ("powerpc64le-unknown-linux-gnu", false), ("powerpc64le-unknown-linux-musl", false), ("riscv64gc-unknown-linux-gnu", false), diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index d950dc1a1c58..274bd56aff7e 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -460,6 +460,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo "loongarch64-unknown-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc64-unknown-linux-gnu", + "powerpc64-unknown-linux-musl", "powerpc64le-unknown-linux-gnu", "powerpc64le-unknown-linux-musl", "riscv64gc-unknown-linux-gnu", diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile similarity index 89% rename from src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile rename to src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile index 298282a76463..046406224c34 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile @@ -11,7 +11,7 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.defconfig /tmp/crosstool.defconfig +COPY host-x86_64/dist-powerpc64-linux-gnu/powerpc64-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/powerpc64-linux-gnu.defconfig similarity index 100% rename from src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.defconfig rename to src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/powerpc64-linux-gnu.defconfig diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile new file mode 100644 index 000000000000..7c8a1e657ac2 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /scripts/ +RUN sh /scripts/cross-apt-packages.sh + +COPY scripts/crosstool-ng.sh /scripts/ +RUN sh /scripts/crosstool-ng.sh + +COPY scripts/rustbuild-setup.sh /scripts/ +RUN sh /scripts/rustbuild-setup.sh + +WORKDIR /tmp + +COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig /tmp/crosstool.defconfig +RUN /scripts/crosstool-ng-build.sh + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-musl/bin + +ENV \ + AR_powerpc64_unknown_linux_musl=powerpc64-unknown-linux-musl-ar \ + CC_powerpc64_unknown_linux_musl=powerpc64-unknown-linux-musl-gcc \ + CXX_powerpc64_unknown_linux_musl=powerpc64-unknown-linux-musl-g++ + +ENV HOSTS=powerpc64-unknown-linux-musl + +ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ + --enable-full-tools \ + --enable-profiler \ + --enable-sanitizers \ + --disable-docs \ + --set target.powerpc64-unknown-linux-musl.crt-static=false \ + --musl-root-powerpc64=/x-tools/powerpc64-unknown-linux-musl/powerpc64-unknown-linux-musl/sysroot/usr + +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig new file mode 100644 index 000000000000..08132d3ab8ba --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig @@ -0,0 +1,15 @@ +CT_CONFIG_VERSION="4" +CT_EXPERIMENTAL=y +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_USE_MIRROR=y +CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_ARCH_POWERPC=y +CT_ARCH_64=y +CT_ARCH_ABI="elfv2" +# CT_DEMULTILIB is not set +CT_KERNEL_LINUX=y +CT_LINUX_V_4_19=y +CT_LIBC_MUSL=y +CT_MUSL_V_1_2_5=y +CT_CC_LANG_CXX=y +CT_GETTEXT_NEEDED=y diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 9acad5c06b21..38c30f8b8e29 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -232,7 +232,10 @@ auto: - name: dist-powerpc-linux <<: *job-linux-4c - - name: dist-powerpc64-linux + - name: dist-powerpc64-linux-gnu + <<: *job-linux-4c + + - name: dist-powerpc64-linux-musl <<: *job-linux-4c - name: dist-powerpc64le-linux-gnu diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d772702df76e..c2b26e56ef49 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -100,6 +100,7 @@ target | notes [`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2+, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2+, glibc 2.17) +[`powerpc64-unknown-linux-musl`](platform-support/powerpc64-unknown-linux-musl.md) | PPC64 Linux (kernel 4.19+, musl 1.2.5) [`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10+, glibc 2.17) [`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19+, musl 1.2.5) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20+, glibc 2.29) @@ -369,7 +370,6 @@ target | std | host | notes [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) [`powerpc64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64 FreeBSD (ELFv2) -[`powerpc64-unknown-linux-musl`](platform-support/powerpc64-unknown-linux-musl.md) | ✓ | ✓ | PPC64 Linux (kernel 4.19, musl 1.2.5) [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`powerpc64le-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64LE FreeBSD diff --git a/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md index 7213e54d5a1a..23cb31af6a26 100644 --- a/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md @@ -1,10 +1,13 @@ # powerpc64-unknown-linux-musl -**Tier: 3** +**Tier: 2** Target for 64-bit big endian PowerPC Linux programs using musl libc. This target uses the ELF v2 ABI. +The baseline CPU required is a PowerPC 970, which means AltiVec is required and +the oldest IBM server CPU supported is therefore POWER6. + ## Target maintainers [@Gelbpunkt](https://github.com/Gelbpunkt) @@ -38,9 +41,8 @@ linker = "powerpc64-linux-musl-gcc" ## Building Rust programs -Rust does not yet ship pre-compiled artifacts for this target. To compile for -this target, you will first need to build Rust with the target enabled (see -"Building the target" above). +This target is distributed through `rustup`, and otherwise requires no +special configuration. ## Cross-compilation From 3f51a315e0668ff1c72459a08dfc42780032918c Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Fri, 9 Jan 2026 21:20:39 +0100 Subject: [PATCH 02/17] Fix(lib/win/net): Remove hostname support under Win7 `GetHostNameW` is not available under Windows 7, leading to dynamic linking failures upon program executions. For now, as it is still unstable, this therefore appropriately cfg-gates the feature in order to mark the Win7 as unsupported with regards to this particular feature. Porting the functionality for Windows 7 would require changing the underlying system call and so more work for the immediate need. Signed-off-by: Paul Mabileau --- library/std/src/net/hostname.rs | 8 ++++---- library/std/src/sys/net/hostname/mod.rs | 3 ++- library/std/src/sys/pal/windows/c.rs | 4 ++++ library/std/src/sys/pal/windows/c/bindings.txt | 1 - library/std/src/sys/pal/windows/c/windows_sys.rs | 1 - 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/library/std/src/net/hostname.rs b/library/std/src/net/hostname.rs index b1010cec6005..4042496d534f 100644 --- a/library/std/src/net/hostname.rs +++ b/library/std/src/net/hostname.rs @@ -8,10 +8,10 @@ use crate::ffi::OsString; /// /// # Underlying system calls /// -/// | Platform | System call | -/// |----------|---------------------------------------------------------------------------------------------------------| -/// | UNIX | [`gethostname`](https://www.man7.org/linux/man-pages/man2/gethostname.2.html) | -/// | Windows | [`GetHostNameW`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew) | +/// | Platform | System call | +/// |--------------|---------------------------------------------------------------------------------------------------------| +/// | UNIX | [`gethostname`](https://www.man7.org/linux/man-pages/man2/gethostname.2.html) | +/// | Windows (8+) | [`GetHostNameW`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew) | /// /// Note that platform-specific behavior [may change in the future][changes]. /// diff --git a/library/std/src/sys/net/hostname/mod.rs b/library/std/src/sys/net/hostname/mod.rs index 8ffe4894d718..65fcd6bfb00d 100644 --- a/library/std/src/sys/net/hostname/mod.rs +++ b/library/std/src/sys/net/hostname/mod.rs @@ -3,7 +3,8 @@ cfg_select! { mod unix; pub use unix::hostname; } - target_os = "windows" => { + // `GetHostNameW` is only available starting with Windows 8. + all(target_os = "windows", not(target_vendor = "win7")) => { mod windows; pub use windows::hostname; } diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 25c1a82cc426..0f54f80d72ee 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -237,3 +237,7 @@ cfg_select! { } _ => {} } + +// Only available starting with Windows 8. +#[cfg(not(target_vendor = "win7"))] +windows_targets::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32); diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 9009aa09f48e..12babcb84ccf 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2170,7 +2170,6 @@ GetFileType GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW GetFullPathNameW -GetHostNameW GetLastError GetModuleFileNameW GetModuleHandleA diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 98f277b33780..edc9d2d11f7c 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -49,7 +49,6 @@ windows_targets::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE); windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32); -windows_targets::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32); windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR); windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE); From b202eee0816938126195e95488ce6df8e9602214 Mon Sep 17 00:00:00 2001 From: Taeyoon Kim Date: Wed, 14 Jan 2026 10:06:39 +0900 Subject: [PATCH 03/17] Add Korean translation to Rust By Example Add korean translation. Thanks in advanced --- src/bootstrap/src/core/build_steps/doc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index b86582807f72..9bb16fe33fd5 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -75,7 +75,7 @@ book!( EditionGuide, "src/doc/edition-guide", "edition-guide", &[]; EmbeddedBook, "src/doc/embedded-book", "embedded-book", &[]; Nomicon, "src/doc/nomicon", "nomicon", &[]; - RustByExample, "src/doc/rust-by-example", "rust-by-example", &["es", "ja", "zh"]; + RustByExample, "src/doc/rust-by-example", "rust-by-example", &["es", "ja", "zh", "ko"]; RustdocBook, "src/doc/rustdoc", "rustdoc", &[]; StyleGuide, "src/doc/style-guide", "style-guide", &[]; ); From 795745ccf1f7af296334204931ae1d0e467d62c2 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 13 Jan 2026 19:48:38 -0500 Subject: [PATCH 04/17] remote-test-server: Fix compilation on UEFI targets Tested with: ./x build src/tools/remote-test-server --target x86_64-unknown-uefi --- src/tools/remote-test-server/src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index bfe8f54937f6..a15f30d4659e 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -10,13 +10,13 @@ //! themselves having support libraries. All data over the TCP sockets is in a //! basically custom format suiting our needs. -#[cfg(all(not(windows), not(target_os = "motor")))] +#[cfg(not(any(windows, target_os = "motor", target_os = "uefi")))] use std::fs::Permissions; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufReader}; use std::net::{SocketAddr, TcpListener, TcpStream}; -#[cfg(all(not(windows), not(target_os = "motor")))] +#[cfg(not(any(windows, target_os = "motor", target_os = "uefi")))] use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Stdio}; @@ -325,7 +325,7 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf ])); } -#[cfg(all(not(windows), not(target_os = "motor")))] +#[cfg(not(any(windows, target_os = "motor", target_os = "uefi")))] fn get_status_code(status: &ExitStatus) -> (u8, i32) { match status.code() { Some(n) => (0, n), @@ -333,7 +333,7 @@ fn get_status_code(status: &ExitStatus) -> (u8, i32) { } } -#[cfg(any(windows, target_os = "motor"))] +#[cfg(any(windows, target_os = "motor", target_os = "uefi"))] fn get_status_code(status: &ExitStatus) -> (u8, i32) { (0, status.code().unwrap()) } @@ -359,11 +359,11 @@ fn recv(dir: &Path, io: &mut B) -> PathBuf { dst } -#[cfg(all(not(windows), not(target_os = "motor")))] +#[cfg(not(any(windows, target_os = "motor", target_os = "uefi")))] fn set_permissions(path: &Path) { t!(fs::set_permissions(&path, Permissions::from_mode(0o755))); } -#[cfg(any(windows, target_os = "motor"))] +#[cfg(any(windows, target_os = "motor", target_os = "uefi"))] fn set_permissions(_path: &Path) {} fn my_copy(src: &mut dyn Read, which: u8, dst: &Mutex) { From 55abc484d7243eea77fd40247b531bcb0796e697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 15 Jan 2026 11:29:07 +0100 Subject: [PATCH 05/17] Extend build-manifest local test guide Fill in more blanks about how to test build-manifest changes with Rustup. --- src/tools/build-manifest/README.md | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md index bc1992ef80cc..f88949f48d8b 100644 --- a/src/tools/build-manifest/README.md +++ b/src/tools/build-manifest/README.md @@ -18,7 +18,7 @@ This gets called by `promote-release` build/dist/channel-rust-nightly.toml.sha256 +``` + +And start a HTTP server from the `build` directory: +```sh +cd build +python3 -m http.server 8000 +``` + +After you do all that, you can then install the locally generated components with rustup: +``` +rustup uninstall nightly +RUSTUP_DIST_SERVER=http://localhost:8000 rustup toolchain install nightly --profile minimal +RUSTUP_DIST_SERVER=http://localhost:8000 rustup +nightly component add +``` + +Note that generally it will not work to combine components built locally and those built from CI (nightly). Ideally, if you want to ship new rustup components, first dist them in nightly, and then test everything from nightly here after it's available on CI. From 80c0b99de0e4fce49a186e507778fb179a87dff0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 19 Jan 2026 00:42:38 +0100 Subject: [PATCH 06/17] add `simd_splat` intrinsic --- .../src/intrinsics/simd.rs | 25 +++++++++ .../rustc_codegen_gcc/src/intrinsic/simd.rs | 29 +++++++++++ compiler/rustc_codegen_llvm/src/intrinsic.rs | 25 +++++++++ .../src/interpret/intrinsics/simd.rs | 9 ++++ .../rustc_hir_analysis/src/check/intrinsic.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/simd.rs | 7 +++ tests/codegen-llvm/simd/splat.rs | 32 ++++++++++++ tests/ui/simd/intrinsic/splat.rs | 52 +++++++++++++++++++ 9 files changed, 181 insertions(+) create mode 100644 tests/codegen-llvm/simd/splat.rs create mode 100644 tests/ui/simd/intrinsic/splat.rs diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index bef9c6747457..200cedf0f6ae 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -348,6 +348,31 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ret.write_cvalue(fx, ret_lane); } + sym::simd_splat => { + intrinsic_args!(fx, args => (value); intrinsic); + + if !ret.layout().ty.is_simd() { + report_simd_type_validation_error(fx, intrinsic, span, ret.layout().ty); + return; + } + let (lane_count, lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + + if value.layout().ty != lane_ty { + fx.tcx.dcx().span_fatal( + span, + format!( + "[simd_splat] expected element type {lane_ty:?}, got {got:?}", + got = value.layout().ty + ), + ); + } + + for i in 0..lane_count { + let ret_lane = ret.place_lane(fx, i.into()); + ret_lane.write_cvalue(fx, value); + } + } + sym::simd_neg | sym::simd_bswap | sym::simd_bitreverse diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 39b4bb3ebefa..0606639d1731 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -121,6 +121,35 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(bx.vector_select(vector_mask, arg1, args[2].immediate())); } + if name == sym::simd_splat { + require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); + + require!( + args[0].layout.ty == out_ty, + InvalidMonomorphization::ExpectedVectorElementType { + span, + name, + expected_element: out_ty, + vector_type: ret_ty, + } + ); + + let vec_ty = llret_ty.unqualified().dyncast_vector().expect("vector return type"); + let elem_ty = vec_ty.get_element_type(); + + // Cast pointer type to usize (GCC does not support pointer SIMD vectors). + let scalar = args[0].immediate(); + let scalar = if scalar.get_type().unqualified() != elem_ty.unqualified() { + bx.ptrtoint(scalar, elem_ty) + } else { + scalar + }; + + let elements = vec![scalar; out_len as usize]; + return Ok(bx.context.new_rvalue_from_vector(bx.location, llret_ty, &elements)); + } + // every intrinsic below takes a SIMD vector as its first argument require_simd!( args[0].layout.ty, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c6aae89f1e51..a2e2acf58953 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1588,6 +1588,31 @@ fn generic_simd_intrinsic<'ll, 'tcx>( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } + if name == sym::simd_splat { + let (_out_len, out_ty) = require_simd!(ret_ty, SimdReturn); + + require!( + args[0].layout.ty == out_ty, + InvalidMonomorphization::ExpectedVectorElementType { + span, + name, + expected_element: out_ty, + vector_type: ret_ty, + } + ); + + // `insertelement poison, elem %x, i32 0` + let poison_vec = bx.const_poison(llret_ty); + let idx0 = bx.const_i32(0); + let v0 = bx.insert_element(poison_vec, args[0].immediate(), idx0); + + // `shufflevector v0, poison, zeroinitializer` + // The masks is all zeros, so this splats lane 0 (which has our element in it). + let splat = bx.shuffle_vector(v0, poison_vec, bx.const_null(llret_ty)); + + return Ok(splat); + } + // every intrinsic below takes a SIMD vector as its first argument let (in_len, in_elem) = require_simd!(args[0].layout.ty, SimdInput); let in_ty = args[0].layout.ty; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index 33a115384a88..f9ba47daac5d 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -60,6 +60,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } self.copy_op(&self.project_index(&input, index)?, &dest)?; } + sym::simd_splat => { + let elem = &args[0]; + let (dest, dest_len) = self.project_to_simd(&dest)?; + + for i in 0..dest_len { + let place = self.project_index(&dest, i)?; + self.copy_op(elem, &place)?; + } + } sym::simd_neg | sym::simd_fabs | sym::simd_ceil diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index d3d167f6e254..f4deb1fc9029 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -746,6 +746,7 @@ pub(crate) fn check_intrinsic_type( sym::simd_extract | sym::simd_extract_dyn => { (2, 0, vec![param(0), tcx.types.u32], param(1)) } + sym::simd_splat => (2, 0, vec![param(1)], param(0)), sym::simd_cast | sym::simd_as | sym::simd_cast_ptr diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d21580c16db2..edf716cc0a86 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2140,6 +2140,7 @@ symbols! { simd_shr, simd_shuffle, simd_shuffle_const_generic, + simd_splat, simd_sub, simd_trunc, simd_with_exposed_provenance, diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 722a765cd01e..9c24a2294797 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -59,6 +59,13 @@ pub unsafe fn simd_extract_dyn(x: T, idx: u32) -> U { unsafe { (&raw const x).cast::().add(idx as usize).read() } } +/// Creates a vector where every lane has the provided value. +/// +/// `T` must be a vector with element type `U`. +#[rustc_nounwind] +#[rustc_intrinsic] +pub const unsafe fn simd_splat(value: U) -> T; + /// Adds two simd vectors elementwise. /// /// `T` must be a vector of integers or floats. diff --git a/tests/codegen-llvm/simd/splat.rs b/tests/codegen-llvm/simd/splat.rs new file mode 100644 index 000000000000..f3e1866fd64a --- /dev/null +++ b/tests/codegen-llvm/simd/splat.rs @@ -0,0 +1,32 @@ +#![crate_type = "lib"] +#![no_std] +#![feature(repr_simd, core_intrinsics)] +use core::intrinsics::simd::simd_splat; + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +// Test that `simd_splat` produces the canonical LLVM splat sequence. + +#[no_mangle] +unsafe fn int(x: u16) -> u16x2 { + // CHECK-LABEL: int + // CHECK: start: + // CHECK-NEXT: %0 = insertelement <2 x i16> poison, i16 %x, i64 0 + // CHECK-NEXT: %1 = shufflevector <2 x i16> %0, <2 x i16> poison, <2 x i32> zeroinitializer + // CHECK-NEXT: store + // CHECK-NEXT: ret + simd_splat(x) +} + +#[no_mangle] +unsafe fn float(x: f32) -> f32x4 { + // CHECK-LABEL: float + // CHECK: start: + // CHECK-NEXT: %0 = insertelement <4 x float> poison, float %x, i64 0 + // CHECK-NEXT: %1 = shufflevector <4 x float> %0, <4 x float> poison, <4 x i32> zeroinitializer + // CHECK-NEXT: store + // CHECK-NEXT: ret + simd_splat(x) +} diff --git a/tests/ui/simd/intrinsic/splat.rs b/tests/ui/simd/intrinsic/splat.rs new file mode 100644 index 000000000000..af3d2270061d --- /dev/null +++ b/tests/ui/simd/intrinsic/splat.rs @@ -0,0 +1,52 @@ +//@ run-pass +#![feature(repr_simd, core_intrinsics)] + +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_splat; + +fn main() { + unsafe { + let x: Simd = simd_splat(123u32); + let y: Simd = const { simd_splat(123u32) }; + assert_eq!(x.into_array(), [123; 1]); + assert_eq!(x.into_array(), y.into_array()); + + let x: u16x2 = simd_splat(42u16); + let y: u16x2 = const { simd_splat(42u16) }; + assert_eq!(x.into_array(), [42; 2]); + assert_eq!(x.into_array(), y.into_array()); + + let x: u128x4 = simd_splat(42u128); + let y: u128x4 = const { simd_splat(42u128) }; + assert_eq!(x.into_array(), [42; 4]); + assert_eq!(x.into_array(), y.into_array()); + + let x: i32x4 = simd_splat(-7i32); + let y: i32x4 = const { simd_splat(-7i32) }; + assert_eq!(x.into_array(), [-7; 4]); + assert_eq!(x.into_array(), y.into_array()); + + let x: f32x4 = simd_splat(42.0f32); + let y: f32x4 = const { simd_splat(42.0f32) }; + assert_eq!(x.into_array(), [42.0; 4]); + assert_eq!(x.into_array(), y.into_array()); + + let x: f64x2 = simd_splat(42.0f64); + let y: f64x2 = const { simd_splat(42.0f64) }; + assert_eq!(x.into_array(), [42.0; 2]); + assert_eq!(x.into_array(), y.into_array()); + + static ZERO: u8 = 0u8; + let x: Simd<*const u8, 2> = simd_splat(&raw const ZERO); + assert_eq!(x.into_array(), [&raw const ZERO; 2]); + + // FIXME: this hits "could not evaluate shuffle_indices at compile time", + // emitted in `immediate_const_vector`. const-eval should be able to handle + // this though I think? `const { [&raw const ZERO; 2] }` appears to work. + // let y: Simd<*const u8, 2> = const { simd_splat(&raw const ZERO) }; + // assert_eq!(x.into_array(), y.into_array()); + } +} From 120388c063b809d7d4f82b4bbf0077e6138d3e67 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 19 Jan 2026 15:44:11 +0100 Subject: [PATCH 07/17] `simd_splat`: custom error in gcc backend for invalid element type --- .../rustc_codegen_gcc/src/intrinsic/simd.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 0606639d1731..eab067a02b7b 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -121,9 +121,9 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(bx.vector_select(vector_mask, arg1, args[2].immediate())); } + #[cfg(feature = "master")] if name == sym::simd_splat { - require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); - let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); + let (out_len, out_ty) = require_simd2!(ret_ty, SimdReturn); require!( args[0].layout.ty == out_ty, @@ -139,11 +139,18 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let elem_ty = vec_ty.get_element_type(); // Cast pointer type to usize (GCC does not support pointer SIMD vectors). - let scalar = args[0].immediate(); - let scalar = if scalar.get_type().unqualified() != elem_ty.unqualified() { - bx.ptrtoint(scalar, elem_ty) + let value = args[0]; + let scalar = if value.layout.ty.is_numeric() { + value.immediate() + } else if value.layout.ty.is_raw_ptr() { + bx.ptrtoint(value.immediate(), elem_ty) } else { - scalar + return_error!(InvalidMonomorphization::UnsupportedOperation { + span, + name, + in_ty: ret_ty, + in_elem: value.layout.ty + }); }; let elements = vec![scalar; out_len as usize]; From 9aaa581fe8ad8517f28e5cebc4f240eebbea23b0 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 19 Jan 2026 20:42:24 +0100 Subject: [PATCH 08/17] rustc-dev-guide: Mention `--extern` modifiers for `aux-crate` directive --- src/doc/rustc-dev-guide/src/tests/compiletest.md | 4 +++- src/doc/rustc-dev-guide/src/tests/directives.md | 16 ++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index d69e0a5ce988..b212675d3fcf 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -655,7 +655,9 @@ to link to the extern crate to make the crate be available as an extern prelude. That allows you to specify the additional syntax of the `--extern` flag, such as renaming a dependency. For example, `//@ aux-crate:foo=bar.rs` will compile `auxiliary/bar.rs` and make it available under then name `foo` within the test. -This is similar to how Cargo does dependency renaming. +This is similar to how Cargo does dependency renaming. It is also possible to +specify [`--extern` modifiers](https://github.com/rust-lang/rust/issues/98405). +For example, `//@ aux-crate:noprelude:foo=bar.rs`. `aux-bin` is similar to `aux-build` but will build a binary instead of a library. The binary will be available in `auxiliary/bin` relative to the working diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index ae341599f15a..81c421bc92c4 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -53,14 +53,14 @@ Directives can generally be found by browsing the See [Building auxiliary crates](compiletest.html#building-auxiliary-crates) -| Directive | Explanation | Supported test suites | Possible values | -|-----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------|-----------------------------------------------| -| `aux-bin` | Build a aux binary, made available in `auxiliary/bin` relative to test directory | All except `run-make`/`run-make-cargo` | Path to auxiliary `.rs` file | -| `aux-build` | Build a separate crate from the named source file | All except `run-make`/`run-make-cargo` | Path to auxiliary `.rs` file | -| `aux-crate` | Like `aux-build` but makes available as extern prelude | All except `run-make`/`run-make-cargo` | `=` | -| `aux-codegen-backend` | Similar to `aux-build` but pass the compiled dylib to `-Zcodegen-backend` when building the main file | `ui-fulldeps` | Path to codegen backend file | -| `proc-macro` | Similar to `aux-build`, but for aux forces host and don't use `-Cprefer-dynamic`[^pm]. | All except `run-make`/`run-make-cargo` | Path to auxiliary proc-macro `.rs` file | -| `build-aux-docs` | Build docs for auxiliaries as well. Note that this only works with `aux-build`, not `aux-crate`. | All except `run-make`/`run-make-cargo` | N/A | +| Directive | Explanation | Supported test suites | Possible values | +|-----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------|--------------------------------------------------------------------| +| `aux-bin` | Build a aux binary, made available in `auxiliary/bin` relative to test directory | All except `run-make`/`run-make-cargo` | Path to auxiliary `.rs` file | +| `aux-build` | Build a separate crate from the named source file | All except `run-make`/`run-make-cargo` | Path to auxiliary `.rs` file | +| `aux-crate` | Like `aux-build` but makes available as extern prelude | All except `run-make`/`run-make-cargo` | `[:]=` | +| `aux-codegen-backend` | Similar to `aux-build` but pass the compiled dylib to `-Zcodegen-backend` when building the main file | `ui-fulldeps` | Path to codegen backend file | +| `proc-macro` | Similar to `aux-build`, but for aux forces host and don't use `-Cprefer-dynamic`[^pm]. | All except `run-make`/`run-make-cargo` | Path to auxiliary proc-macro `.rs` file | +| `build-aux-docs` | Build docs for auxiliaries as well. Note that this only works with `aux-build`, not `aux-crate`. | All except `run-make`/`run-make-cargo` | N/A | [^pm]: please see the [Auxiliary proc-macro section](compiletest.html#auxiliary-proc-macro) in the compiletest chapter for specifics. From 93929ef064b1497182acd2929137d6e4886c0e47 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 20 Jan 2026 11:15:12 +0100 Subject: [PATCH 09/17] std: use 64-bit `clock_nanosleep` on Linux if available --- library/std/src/sys/thread/unix.rs | 50 +++++++++++++++++++++++ src/tools/miri/src/shims/extern_static.rs | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index b1f27c32fedd..cf3d31835b09 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -609,6 +609,56 @@ pub fn sleep(dur: Duration) { pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; + #[cfg(all( + target_os = "linux", + target_env = "gnu", + target_pointer_width = "32", + not(target_arch = "riscv32") + ))] + { + use crate::sys::pal::time::__timespec64; + use crate::sys::pal::weak::weak; + + // This got added in glibc 2.31, along with a 64-bit `clock_gettime` + // function. + weak! { + fn __clock_nanosleep_time64( + clock_id: libc::clockid_t, + flags: libc::c_int, + req: *const __timespec64, + rem: *mut __timespec64, + ) -> libc::c_int; + } + + if let Some(clock_nanosleep) = __clock_nanosleep_time64.get() { + let ts = deadline.into_inner().into_timespec().to_timespec64(); + loop { + let r = unsafe { + clock_nanosleep( + crate::sys::time::Instant::CLOCK_ID, + libc::TIMER_ABSTIME, + &ts, + core::ptr::null_mut(), + ) + }; + + match r { + 0 => return, + libc::EINTR => continue, + // If the underlying kernel doesn't support the 64-bit + // syscall, `__clock_nanosleep_time64` will fail. The + // error code nowadays is EOVERFLOW, but it used to be + // ENOSYS – so just don't rely on any particular value. + // The parameters are all valid, so the only reasons + // why the call might fail are EINTR and the call not + // being supported. Fall through to the clamping version + // in that case. + _ => break, + } + } + } + } + let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else { // The deadline is further in the future then can be passed to // clock_nanosleep. We have to use Self::sleep instead. This might diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index fc9971641088..6c7f3470600b 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -55,7 +55,7 @@ impl<'tcx> MiriMachine<'tcx> { Os::Linux => { Self::null_ptr_extern_statics( ecx, - &["__cxa_thread_atexit_impl", "__clock_gettime64"], + &["__cxa_thread_atexit_impl", "__clock_gettime64", "__clock_nanosleep_time64"], )?; Self::weak_symbol_extern_statics(ecx, &["getrandom", "gettid", "statx"])?; } From bd4211595d273a063d26f9e5025901969a553f2f Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 23 Jan 2026 13:21:23 +0100 Subject: [PATCH 10/17] std: implement `sleep_until` on Motor --- library/std/src/sys/thread/mod.rs | 1 + library/std/src/sys/thread/motor.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index 381031e318c9..a5bfc8c609c0 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -135,6 +135,7 @@ cfg_select! { target_os = "vxworks", target_os = "wasi", target_vendor = "apple", + target_os = "motor", )))] pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; diff --git a/library/std/src/sys/thread/motor.rs b/library/std/src/sys/thread/motor.rs index 3c6df936b0ae..c6a7b5ac356b 100644 --- a/library/std/src/sys/thread/motor.rs +++ b/library/std/src/sys/thread/motor.rs @@ -3,7 +3,7 @@ use crate::io; use crate::num::NonZeroUsize; use crate::sys::map_motor_error; use crate::thread::ThreadInit; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 256; @@ -62,3 +62,7 @@ pub fn yield_now() { pub fn sleep(dur: Duration) { moto_rt::thread::sleep_until(moto_rt::time::Instant::now() + dur) } + +pub fn sleep_until(deadline: Instant) { + moto_rt::thread::sleep_until(deadline.into_inner()) +} From dee0e394714d9d21aca63e2a4c30df1629a867bb Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 23 Jan 2026 23:15:12 +0100 Subject: [PATCH 11/17] std: implement `sleep_until` on VEX --- library/std/src/sys/thread/mod.rs | 3 ++- library/std/src/sys/thread/vexos.rs | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index a5bfc8c609c0..5010774dafde 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -91,7 +91,7 @@ cfg_select! { } target_os = "vexos" => { mod vexos; - pub use vexos::{sleep, yield_now}; + pub use vexos::{sleep, sleep_until, yield_now}; #[expect(dead_code)] mod unsupported; pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, DEFAULT_MIN_STACK_SIZE}; @@ -136,6 +136,7 @@ cfg_select! { target_os = "wasi", target_vendor = "apple", target_os = "motor", + target_os = "vexos" )))] pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; diff --git a/library/std/src/sys/thread/vexos.rs b/library/std/src/sys/thread/vexos.rs index d917dde4d0bc..4311786720c4 100644 --- a/library/std/src/sys/thread/vexos.rs +++ b/library/std/src/sys/thread/vexos.rs @@ -10,8 +10,12 @@ pub fn sleep(dur: Duration) { let start = Instant::now(); while start.elapsed() < dur { - unsafe { - vex_sdk::vexTasksRun(); - } + yield_now(); + } +} + +pub fn sleep_until(deadline: Instant) { + while Instant::now() < deadline { + yield_now(); } } From e5585445655fd663bfb8f2887498e0f9b92b11ad Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 23 Jan 2026 23:25:43 -0600 Subject: [PATCH 12/17] Fix cstring-merging test for Hexagon target Hexagon assembler uses `.string` directive instead of `.asciz` for null-terminated strings. Both are equivalent but the test was only checking for `.asciz`. Update the CHECK patterns to accept both directives using `.{{asciz|string}}` regex pattern. --- tests/assembly-llvm/cstring-merging.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/assembly-llvm/cstring-merging.rs b/tests/assembly-llvm/cstring-merging.rs index 03688e0068b7..9c1af4ebb4c0 100644 --- a/tests/assembly-llvm/cstring-merging.rs +++ b/tests/assembly-llvm/cstring-merging.rs @@ -1,5 +1,6 @@ // MIPS assembler uses the label prefix `$anon.` for local anonymous variables // other architectures (including ARM and x86-64) use the prefix `.Lanon.` +// Hexagon uses `.string` instead of `.asciz` for null-terminated strings //@ only-linux //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -Cllvm-args=-enable-global-merge=0 @@ -9,13 +10,13 @@ use std::ffi::CStr; // CHECK: .section .rodata.str1.{{[12]}},"aMS" // CHECK: {{(\.L|\$)}}anon.{{.+}}: -// CHECK-NEXT: .asciz "foo" +// CHECK-NEXT: .{{asciz|string}} "foo" #[unsafe(no_mangle)] static CSTR: &[u8; 4] = b"foo\0"; // CHECK-NOT: .section // CHECK: {{(\.L|\$)}}anon.{{.+}}: -// CHECK-NEXT: .asciz "bar" +// CHECK-NEXT: .{{asciz|string}} "bar" #[unsafe(no_mangle)] pub fn cstr() -> &'static CStr { c"bar" @@ -23,7 +24,7 @@ pub fn cstr() -> &'static CStr { // CHECK-NOT: .section // CHECK: {{(\.L|\$)}}anon.{{.+}}: -// CHECK-NEXT: .asciz "baz" +// CHECK-NEXT: .{{asciz|string}} "baz" #[unsafe(no_mangle)] pub fn manual_cstr() -> &'static str { "baz\0" From 71f34429ac7cb65a00ec413a546ad760f6c6aa91 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 19 Jan 2026 15:53:12 +0100 Subject: [PATCH 13/17] const-eval: do not call `immediate_const_vector` on vector of pointers --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 8 +++++++- tests/codegen-llvm/simd/splat.rs | 1 + tests/ui/simd/intrinsic/splat.rs | 8 ++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 78dfecdd1818..50ca676b5d05 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -1074,8 +1074,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if constant_ty.is_simd() { // However, some SIMD types do not actually use the vector ABI // (in particular, packed SIMD types do not). Ensure we exclude those. + // + // We also have to exclude vectors of pointers because `immediate_const_vector` + // does not work for those. let layout = bx.layout_of(constant_ty); - if let BackendRepr::SimdVector { .. } = layout.backend_repr { + let (_, element_ty) = constant_ty.simd_size_and_type(bx.tcx()); + if let BackendRepr::SimdVector { .. } = layout.backend_repr + && element_ty.is_numeric() + { let (llval, ty) = self.immediate_const_vector(bx, constant); return OperandRef { val: OperandValue::Immediate(llval), diff --git a/tests/codegen-llvm/simd/splat.rs b/tests/codegen-llvm/simd/splat.rs index f3e1866fd64a..7a24162321bd 100644 --- a/tests/codegen-llvm/simd/splat.rs +++ b/tests/codegen-llvm/simd/splat.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Copt-level=3 #![crate_type = "lib"] #![no_std] #![feature(repr_simd, core_intrinsics)] diff --git a/tests/ui/simd/intrinsic/splat.rs b/tests/ui/simd/intrinsic/splat.rs index af3d2270061d..38260a124d44 100644 --- a/tests/ui/simd/intrinsic/splat.rs +++ b/tests/ui/simd/intrinsic/splat.rs @@ -41,12 +41,8 @@ fn main() { static ZERO: u8 = 0u8; let x: Simd<*const u8, 2> = simd_splat(&raw const ZERO); + let y: Simd<*const u8, 2> = const { simd_splat(&raw const ZERO) }; assert_eq!(x.into_array(), [&raw const ZERO; 2]); - - // FIXME: this hits "could not evaluate shuffle_indices at compile time", - // emitted in `immediate_const_vector`. const-eval should be able to handle - // this though I think? `const { [&raw const ZERO; 2] }` appears to work. - // let y: Simd<*const u8, 2> = const { simd_splat(&raw const ZERO) }; - // assert_eq!(x.into_array(), y.into_array()); + assert_eq!(x.into_array(), y.into_array()); } } From 6f767b686044e59e37c31b17a8f00cac7092fa7c Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 19 Jan 2026 05:25:31 +0100 Subject: [PATCH 14/17] compiletest: Make `aux-crate` directive explicitly handle `--extern` modifiers To make it clearer what happens. In other words, do not silently keep modifiers as part of `AuxCrate::name`. --- .../compiletest/src/directives/auxiliary.rs | 33 +++++++++++++++---- .../src/directives/auxiliary/tests.rs | 27 +++++++++++++++ src/tools/compiletest/src/runtest.rs | 33 +++++++++++++------ 3 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 src/tools/compiletest/src/directives/auxiliary/tests.rs diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 1b72931949c5..1d5b7926a8e3 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -6,12 +6,20 @@ use std::iter; use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO}; use crate::common::Config; use crate::directives::DirectiveLine; +use crate::util::static_regex; + +#[cfg(test)] +mod tests; /// The value of an `aux-crate` directive. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct AuxCrate { + /// Contains `--extern` modifiers, if any. See the tracking issue for more + /// info: + /// With `aux-crate: noprelude:foo=bar.rs` this will be `noprelude`. + pub extern_modifiers: Option, /// With `aux-crate: foo=bar.rs` this will be `foo`. - /// With `aux-crate: noprelude:foo=bar.rs` this will be `noprelude:foo`. + /// With `aux-crate: noprelude:foo=bar.rs` this will be `foo`. pub name: String, /// With `aux-crate: foo=bar.rs` this will be `bar.rs`. pub path: String, @@ -74,9 +82,20 @@ pub(super) fn parse_and_update_aux( } fn parse_aux_crate(r: String) -> AuxCrate { - let mut parts = r.trim().splitn(2, '='); - AuxCrate { - name: parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), - path: parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), - } + let r = r.trim(); + + // Matches: + // name=path + // modifiers:name=path + let caps = static_regex!(r"^(?:(?[^=]*?):)?(?[^=]*)=(?.*)$") + .captures(r) + .unwrap_or_else(|| { + panic!("couldn't parse aux-crate value `{r}` (should be e.g. `log=log.rs`)") + }); + + let modifiers = caps.name("modifiers").map(|m| m.as_str().to_string()); + let name = caps["name"].to_string(); + let path = caps["path"].to_string(); + + AuxCrate { extern_modifiers: modifiers, name, path } } diff --git a/src/tools/compiletest/src/directives/auxiliary/tests.rs b/src/tools/compiletest/src/directives/auxiliary/tests.rs new file mode 100644 index 000000000000..ad205eaabfda --- /dev/null +++ b/src/tools/compiletest/src/directives/auxiliary/tests.rs @@ -0,0 +1,27 @@ +use super::*; + +#[test] +fn test_aux_crate_value_no_modifiers() { + assert_eq!( + AuxCrate { extern_modifiers: None, name: "foo".to_string(), path: "foo.rs".to_string() }, + parse_aux_crate("foo=foo.rs".to_string()) + ); +} + +#[test] +fn test_aux_crate_value_with_modifiers() { + assert_eq!( + AuxCrate { + extern_modifiers: Some("noprelude".to_string()), + name: "foo".to_string(), + path: "foo.rs".to_string() + }, + parse_aux_crate("noprelude:foo=foo.rs".to_string()) + ); +} + +#[test] +#[should_panic(expected = "couldn't parse aux-crate value `foo.rs` (should be e.g. `log=log.rs`)")] +fn test_aux_crate_value_invalid() { + parse_aux_crate("foo.rs".to_string()); +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 901ce8421ebf..dfbe84d5da72 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1277,23 +1277,36 @@ impl<'test> TestCx<'test> { .replace('-', "_") }; - let add_extern = - |rustc: &mut Command, aux_name: &str, aux_path: &str, aux_type: AuxType| { - let lib_name = get_lib_name(&path_to_crate_name(aux_path), aux_type); - if let Some(lib_name) = lib_name { - rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir, lib_name)); - } - }; + let add_extern = |rustc: &mut Command, + extern_modifiers: Option<&str>, + aux_name: &str, + aux_path: &str, + aux_type: AuxType| { + let lib_name = get_lib_name(&path_to_crate_name(aux_path), aux_type); + if let Some(lib_name) = lib_name { + let modifiers_and_name = match extern_modifiers { + Some(modifiers) => format!("{modifiers}:{aux_name}"), + None => aux_name.to_string(), + }; + rustc.arg("--extern").arg(format!("{modifiers_and_name}={aux_dir}/{lib_name}")); + } + }; - for AuxCrate { name, path } in &self.props.aux.crates { + for AuxCrate { extern_modifiers, name, path } in &self.props.aux.crates { let aux_type = self.build_auxiliary(&path, &aux_dir, None); - add_extern(rustc, name, path, aux_type); + add_extern(rustc, extern_modifiers.as_deref(), name, path, aux_type); } for proc_macro in &self.props.aux.proc_macros { self.build_auxiliary(proc_macro, &aux_dir, Some(AuxType::ProcMacro)); let crate_name = path_to_crate_name(proc_macro); - add_extern(rustc, &crate_name, proc_macro, AuxType::ProcMacro); + add_extern( + rustc, + None, // `extern_modifiers` + &crate_name, + proc_macro, + AuxType::ProcMacro, + ); } // Build any `//@ aux-codegen-backend`, and pass the resulting library From 96897f016ed357532f98259cef1639601ad66957 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sun, 16 Nov 2025 20:21:42 +0000 Subject: [PATCH 15/17] Add ARMv6 bare-metal targets Three targets, covering A32 and T32 instructions, and soft-float and hard-float ABIs. Hard-float not available in Thumb mode. Atomics in Thumb mode require __sync* functions from compiler-builtins. --- compiler/rustc_target/src/spec/mod.rs | 8 +++- .../src/spec/targets/armv6_none_eabi.rs | 29 ++++++++++++++ .../src/spec/targets/armv6_none_eabihf.rs | 29 ++++++++++++++ .../src/spec/targets/thumbv6_none_eabi.rs | 30 ++++++++++++++ library/core/src/hint.rs | 10 ++++- .../crates/core_arch/src/arm_shared/hints.rs | 6 ++- src/bootstrap/src/core/sanity.rs | 3 ++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 3 ++ .../src/platform-support/arm-none-eabi.md | 1 + .../src/platform-support/armv6-none-eabi.md | 39 +++++++++++++++++++ tests/assembly-llvm/targets/targets-elf.rs | 9 +++++ 12 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/armv6_none_eabi.rs create mode 100644 compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs create mode 100644 compiler/rustc_target/src/spec/targets/thumbv6_none_eabi.rs create mode 100644 src/doc/rustc/src/platform-support/armv6-none-eabi.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c5a7f119118c..fe4b91c53f63 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1746,10 +1746,14 @@ supported_targets! { ("mipsel-unknown-none", mipsel_unknown_none), ("mips-mti-none-elf", mips_mti_none_elf), ("mipsel-mti-none-elf", mipsel_mti_none_elf), - ("thumbv4t-none-eabi", thumbv4t_none_eabi), + ("armv4t-none-eabi", armv4t_none_eabi), - ("thumbv5te-none-eabi", thumbv5te_none_eabi), ("armv5te-none-eabi", armv5te_none_eabi), + ("armv6-none-eabi", armv6_none_eabi), + ("armv6-none-eabihf", armv6_none_eabihf), + ("thumbv4t-none-eabi", thumbv4t_none_eabi), + ("thumbv5te-none-eabi", thumbv5te_none_eabi), + ("thumbv6-none-eabi", thumbv6_none_eabi), ("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu), ("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32), diff --git a/compiler/rustc_target/src/spec/targets/armv6_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv6_none_eabi.rs new file mode 100644 index 000000000000..48a196b231b0 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv6_none_eabi.rs @@ -0,0 +1,29 @@ +//! Targets the ARMv6K architecture, with `a32` code by default. + +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "armv6-none-eabi".into(), + metadata: TargetMetadata { + description: Some("Bare ARMv6 soft-float".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + arch: Arch::Arm, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + options: TargetOptions { + abi: Abi::Eabi, + llvm_floatabi: Some(FloatAbi::Soft), + asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",], + features: "+soft-float,+strict-align,+v6k".into(), + atomic_cas: true, + has_thumb_interworking: true, + // LDREXD/STREXD available as of ARMv6K + max_atomic_width: Some(64), + ..base::arm_none::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs new file mode 100644 index 000000000000..8bc6b06ecee3 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs @@ -0,0 +1,29 @@ +//! Targets the ARMv6K architecture, with `a32` code by default, and hard-float ABI + +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "armv6-none-eabihf".into(), + metadata: TargetMetadata { + description: Some("Bare ARMv6 hard-float".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + arch: Arch::Arm, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + options: TargetOptions { + abi: Abi::EabiHf, + llvm_floatabi: Some(FloatAbi::Hard), + asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",], + features: "+strict-align,+v6k,+vfp2,-d32".into(), + atomic_cas: true, + has_thumb_interworking: true, + // LDREXD/STREXD available as of ARMv6K + max_atomic_width: Some(64), + ..base::arm_none::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/thumbv6_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6_none_eabi.rs new file mode 100644 index 000000000000..077f02818085 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/thumbv6_none_eabi.rs @@ -0,0 +1,30 @@ +//! Targets the ARMv6K architecture, with `t32` code by default. + +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "thumbv6-none-eabi".into(), + metadata: TargetMetadata { + description: Some("Thumb-mode Bare ARMv6 soft-float".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + arch: Arch::Arm, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + options: TargetOptions { + abi: Abi::Eabi, + llvm_floatabi: Some(FloatAbi::Soft), + asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",], + features: "+soft-float,+strict-align,+v6k".into(), + // CAS atomics are implemented in LLVM on this target using __sync* functions, + // which were added to compiler-builtins in https://github.com/rust-lang/compiler-builtins/pull/1050 + atomic_cas: true, + has_thumb_interworking: true, + max_atomic_width: Some(32), + ..base::arm_none::opts() + }, + } +} diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 4c050b49bf7e..e945b40dfaa5 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -292,7 +292,15 @@ pub fn spin_loop() { // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) } } - all(target_arch = "arm", target_feature = "v6") => { + all( + target_arch = "arm", + any( + all(target_feature = "v6k", not(target_feature = "thumb-mode")), + target_feature = "v6t2", + all(target_feature = "v6", target_feature = "mclass"), + target_feature = "v7", + ) + ) => { // SAFETY: the `cfg` attr ensures that we only execute this on arm targets // with support for the v6 feature. unsafe { crate::arch::arm::__yield() } diff --git a/library/stdarch/crates/core_arch/src/arm_shared/hints.rs b/library/stdarch/crates/core_arch/src/arm_shared/hints.rs index 54fd78270abd..dade0d99e5a2 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/hints.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/hints.rs @@ -83,8 +83,12 @@ pub unsafe fn __sevl() { /// improve overall system performance. // Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M // LLVM says "instruction requires: armv6k" +// On ARMv6 in Thumb mode, T2 is required. #[cfg(any( - target_feature = "v6", + all(target_feature = "v6k", not(target_feature = "thumb-mode")), + target_feature = "v6t2", + all(target_feature = "v6", target_feature = "mclass"), + target_feature = "v7", target_arch = "aarch64", target_arch = "arm64ec", doc diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 235bbf8ddb78..a16a2b17be17 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -43,6 +43,9 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ "thumbv7r-none-eabi", "thumbv7r-none-eabihf", "thumbv8r-none-eabihf", + "armv6-none-eabi", + "armv6-none-eabihf", + "thumbv6-none-eabi", ]; /// 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 5d000c900aaa..632b9e2fc431 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -56,6 +56,7 @@ - [arm-none-eabi](platform-support/arm-none-eabi.md) - [{arm,thumb}v4t-none-eabi](platform-support/armv4t-none-eabi.md) - [{arm,thumb}v5te-none-eabi](platform-support/armv5te-none-eabi.md) + - [{arm,thumb}v6-none-eabi{,hf}](platform-support/armv6-none-eabi.md) - [{arm,thumb}v7a-none-eabi{,hf}](platform-support/armv7a-none-eabi.md) - [{arm,thumb}v7r-none-eabi{,hf}](platform-support/armv7r-none-eabi.md) - [{arm,thumb}v8r-none-eabihf](platform-support/armv8r-none-eabihf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 9362c8b98fe3..eaab92a7bf1f 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -292,6 +292,8 @@ target | std | host | notes `armv4t-unknown-linux-gnueabi` | ? | | Armv4T Linux [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare Armv5TE `armv5te-unknown-linux-uclibceabi` | ? | | Armv5TE Linux with uClibc +[`armv6-none-eabi`](platform-support/armv6-none-eabi.md) | * | | Bare Armv6 +[`armv6-none-eabihf`](platform-support/armv6-none-eabi.md) | * | | Bare Armv6, hardfloat [`armv6-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | Armv6 FreeBSD [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain) @@ -410,6 +412,7 @@ target | std | host | notes [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 [`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Thumb-mode Bare Armv4T [`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare Armv5TE +[`thumbv6-none-eabi`](platform-support/armv6-none-eabi.md) | * | | Thumb-mode Bare Armv6 [`thumbv6m-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv6M with NuttX [`thumbv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | | Thumb-mode Bare Armv7-A [`thumbv7a-none-eabihf`](platform-support/armv7a-none-eabi.md) | * | | Thumb-mode Bare Armv7-A, hardfloat diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index 81545db6c51f..cf1fe9ed59ed 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -37,6 +37,7 @@ their own document. - *Legacy* Arm Architectures - [`armv4t-none-eabi` and `thumbv4t-none-eabi`](armv4t-none-eabi.md) - [`armv5te-none-eabi` and `thumbv5te-none-eabi`](armv5te-none-eabi.md) + - [`armv6-none-eabi`, `armv6-none-eabihf`, `thumbv6-none-eabi`](armv6-none-eabi.md) ## Instruction Sets diff --git a/src/doc/rustc/src/platform-support/armv6-none-eabi.md b/src/doc/rustc/src/platform-support/armv6-none-eabi.md new file mode 100644 index 000000000000..ae88356e12ce --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv6-none-eabi.md @@ -0,0 +1,39 @@ +# `armv6-none-eabi*` and `thumbv6-none-eabi` + +* **Tier: 3** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) + +Bare-metal target for any cpu in the Armv6 architecture family, supporting +ARM/Thumb code interworking (aka `Arm`/`Thumb`), with `Arm` code as the default +code generation. The most common processor family using the Armv6 architecture +is the ARM11, which includes the ARM1176JZF-S used in the original Raspberry Pi +and in the Raspberry Pi Zero. + +This target assumes your processor has the Armv6K extensions, as basically all +Armv6 processors do[^1]. The Armv6K extension adds the `LDREXB` and `STREXB` +instructions required to efficiently implement CAS on the [`AtomicU8`] and +[`AtomicI8`] types. + +The `thumbv6-none-eabi` target is the same as this one, but the instruction set +defaults to `Thumb`. Note that this target only supports the old Thumb-1 +instruction set, not the later Thumb-2 instruction set that was added in the +Armv6T2 extension. Note that the Thumb-1 instruction set does not support +atomics. + +The `armv6-none-eabihf` target uses the EABIHF hard-float ABI, and requires an +FPU - it assumes a VFP2D16 FPU is present. The FPU is not available from Thumb +mode so there is no `thumbv6-none-eabihf` target. + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + +[`AtomicU8`]: https://docs.rust-lang.org/stable/core/sync/atomic/struct.AtomicU8.html +[`AtomicI8`]: https://docs.rust-lang.org/stable/core/sync/atomic/struct.AtomicI8.html + +## Target Maintainers + +[@thejpster](https://github.com/thejpster) + +[^1]: The only ARMv6 processor without the Armv6k extensions is the first (r0) +revision of the ARM1136 - in the unlikely event you have a chip with one of +these processors, use the ARMv5TE target instead. diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index 17553fc8f4e4..0d5cd796aa48 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -139,6 +139,12 @@ //@ revisions: armv5te_unknown_linux_uclibceabi //@ [armv5te_unknown_linux_uclibceabi] compile-flags: --target armv5te-unknown-linux-uclibceabi //@ [armv5te_unknown_linux_uclibceabi] needs-llvm-components: arm +//@ revisions: armv6_none_eabi +//@ [armv6_none_eabi] compile-flags: --target armv6-none-eabi +//@ [armv6_none_eabi] needs-llvm-components: arm +//@ revisions: armv6_none_eabihf +//@ [armv6_none_eabihf] compile-flags: --target armv6-none-eabihf +//@ [armv6_none_eabihf] needs-llvm-components: arm //@ revisions: armv6_unknown_freebsd //@ [armv6_unknown_freebsd] compile-flags: --target armv6-unknown-freebsd //@ [armv6_unknown_freebsd] needs-llvm-components: arm @@ -559,6 +565,9 @@ //@ revisions: thumbv5te_none_eabi //@ [thumbv5te_none_eabi] compile-flags: --target thumbv5te-none-eabi //@ [thumbv5te_none_eabi] needs-llvm-components: arm +//@ revisions: thumbv6_none_eabi +//@ [thumbv6_none_eabi] compile-flags: --target thumbv6-none-eabi +//@ [thumbv6_none_eabi] needs-llvm-components: arm //@ revisions: thumbv7a_none_eabi //@ [thumbv7a_none_eabi] compile-flags: --target thumbv7a-none-eabi //@ [thumbv7a_none_eabi] needs-llvm-components: arm From 9d9870b7359eb350ee82fa640af9541e30415e2a Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Thu, 18 Dec 2025 19:24:25 +0000 Subject: [PATCH 16/17] Fix typo in thumbv4t/v5te README --- compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs | 2 +- compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs | 2 +- compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs | 2 +- compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs index fc66a2fa8f9e..c917531932f6 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs @@ -1,4 +1,4 @@ -//! Targets the ARMv4T, with code as `a32` code by default. +//! Targets the ARMv4T architecture, with `a32` code by default. //! //! Primarily of use for the GBA, but usable with other devices too. //! diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs index 8089e9a7a064..b8ae881f3dae 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs @@ -1,4 +1,4 @@ -//! Targets the ARMv5TE, with code as `a32` code by default. +//! Targets the ARMv5TE architecture, with `a32` code by default. use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs index 50eccbed3ac1..dfb8ccb06bc2 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs @@ -1,4 +1,4 @@ -//! Targets the ARMv4T, with code as `t32` code by default. +//! Targets the ARMv4T architecture, with `t32` code by default. //! //! Primarily of use for the GBA, but usable with other devices too. //! diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs index 6acb03e3b296..3b41208b69f4 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs @@ -1,4 +1,4 @@ -//! Targets the ARMv5TE, with code as `t32` code by default. +//! Targets the ARMv5TE architecture, with `t32` code by default. use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; From 7cc102a4ee349e31baf2ee24be0634ad80fe4cdc Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Fri, 19 Dec 2025 11:02:19 +0000 Subject: [PATCH 17/17] Revised yield hints Turns out v7 targets always have v6t2 set, so that line was redundant. Also add a link to the Arm Armv7 A.R.M. --- library/core/src/hint.rs | 7 ++++--- library/stdarch/crates/core_arch/src/arm_shared/hints.rs | 3 +-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index e945b40dfaa5..b7f78288b2b6 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -298,11 +298,12 @@ pub fn spin_loop() { all(target_feature = "v6k", not(target_feature = "thumb-mode")), target_feature = "v6t2", all(target_feature = "v6", target_feature = "mclass"), - target_feature = "v7", ) ) => { - // SAFETY: the `cfg` attr ensures that we only execute this on arm targets - // with support for the v6 feature. + // SAFETY: the `cfg` attr ensures that we only execute this on arm + // targets with support for the this feature. On ARMv6 in Thumb + // mode, T2 is required (see Arm DDI0406C Section A8.8.427), + // otherwise ARMv6-M or ARMv6K is enough unsafe { crate::arch::arm::__yield() } } target_arch = "loongarch32" => crate::arch::loongarch32::ibar::<0>(), diff --git a/library/stdarch/crates/core_arch/src/arm_shared/hints.rs b/library/stdarch/crates/core_arch/src/arm_shared/hints.rs index dade0d99e5a2..8a25cc1163cc 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/hints.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/hints.rs @@ -83,12 +83,11 @@ pub unsafe fn __sevl() { /// improve overall system performance. // Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M // LLVM says "instruction requires: armv6k" -// On ARMv6 in Thumb mode, T2 is required. +// On ARMv6 in Thumb mode, T2 is required (see Arm DDI0406C Section A8.8.427) #[cfg(any( all(target_feature = "v6k", not(target_feature = "thumb-mode")), target_feature = "v6t2", all(target_feature = "v6", target_feature = "mclass"), - target_feature = "v7", target_arch = "aarch64", target_arch = "arm64ec", doc