From 1ca775749ef57d8549175e53fc31534bdef88446 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Aug 2026 15:13:06 -0700 Subject: [PATCH 01/10] Re-export `core::fmt::NumBuffer` in `alloc` (and `std`) (cherry picked from commit dad850cc5243ba1d66bfa0be5dfd02cb05767507) --- library/alloc/src/fmt.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index e3ff2ba51aba0..0129b04137a50 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -595,6 +595,8 @@ pub use core::fmt::Alignment; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::Error; +#[stable(feature = "fmt_numbuffer", since = "CURRENT_RUSTC_VERSION")] +pub use core::fmt::NumBuffer; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Arguments, write}; #[stable(feature = "rust1", since = "1.0.0")] From fb137e98114d44c580c61c56138d4ebb70c639ca Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 18 Sep 2026 13:13:43 -0700 Subject: [PATCH 02/10] replace-version-placeholder --- library/alloc/src/fmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 0129b04137a50..78c7b76c0f5b4 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -595,7 +595,7 @@ pub use core::fmt::Alignment; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::Error; -#[stable(feature = "fmt_numbuffer", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "fmt_numbuffer", since = "1.99.0")] pub use core::fmt::NumBuffer; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Arguments, write}; From 3a8d68dfdd0a9662ca56c12a1a1e973eda2c6c95 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sun, 6 Sep 2026 21:01:08 +0700 Subject: [PATCH 03/10] Make `VaArgSafe` dyn-incompatible This is done just in case we want to later do stuff like adding a `Sized` supertrait. See discussion at https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/Should.20.60VaArgSafe.60.20require.20.60Sized.60.3F/with/622074620 (cherry picked from commit 16529d723a1d66fbd926d7a8e78fb0448622a316) --- library/core/src/ffi/va_list.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index e143fcc5a3a7f..7ab4b31d6e496 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -313,6 +313,7 @@ const impl<'f> Drop for VaList<'f> { // meantime. #[lang = "va_arg_safe"] #[stable(feature = "c_variadic", since = "1.99.0")] +#[rustc_dyn_incompatible_trait] pub impl(self) unsafe trait VaArgSafe {} crate::cfg_select! { From b62036812a8c78140a7fe6eb44ae615bfe5a30a7 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Mon, 7 Sep 2026 01:17:13 +0700 Subject: [PATCH 04/10] Acknowledge "breaking" change This PR does a "breaking" change on API that's stabilized in 1.99.0 beta, but has not reached stable yet, so we can make this change. H th is PR will need a beta backport. (cherry picked from commit 246105d1a14a4dfa124d503b1b9fd929606014e6) --- src/bootstrap/stdlib-semver-check-stamp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/stdlib-semver-check-stamp b/src/bootstrap/stdlib-semver-check-stamp index d93ba46345c85..a7221ad6185e3 100644 --- a/src/bootstrap/stdlib-semver-check-stamp +++ b/src/bootstrap/stdlib-semver-check-stamp @@ -2,4 +2,4 @@ Change this file to explicitly acknowledge making a breaking change to the Rust If this file is modified in the same PR as the breaking change, then CI will not fail due to the breaking change being detected by cargo-semver-checks. -Last change is for: https://github.com/rust-lang/rust/pull/160253 +Last change is for: https://github.com/rust-lang/rust/pull/162374 From 9cd3215560c224980aa093c5b2a4f9e7c6c1fd0c Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Thu, 17 Sep 2026 16:25:37 +0200 Subject: [PATCH 05/10] Claw back `VaArgSafe` (cherry picked from commit 5e3ad0017d8b3e193c10ab6230369aead2e9ea69) --- library/core/src/ffi/va_list.rs | 26 +++++++++---------- library/std/src/ffi/mod.rs | 6 +++-- src/bootstrap/stdlib-semver-check-stamp | 2 +- tests/ui/c-variadic/roundtrip.rs | 8 +++++- tests/ui/consts/const-eval/c-variadic-fail.rs | 2 +- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 7ab4b31d6e496..f9128e97d0c7f 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -312,7 +312,7 @@ const impl<'f> Drop for VaList<'f> { // types with a non-scalar layout. Inline assembly can be used to accept unsupported types in the // meantime. #[lang = "va_arg_safe"] -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] #[rustc_dyn_incompatible_trait] pub impl(self) unsafe trait VaArgSafe {} @@ -322,9 +322,9 @@ crate::cfg_select! { // // - i8 is implicitly promoted to c_int in C, and cannot implement `VaArgSafe`. // - u8 is implicitly promoted to c_uint in C, and cannot implement `VaArgSafe`. - #[stable(feature = "c_variadic", since = "1.99.0")] + #[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for i16 {} - #[stable(feature = "c_variadic", since = "1.99.0")] + #[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for u16 {} } _ => { @@ -338,7 +338,7 @@ crate::cfg_select! { crate::cfg_select! { target_arch = "avr" => { // c_double is f32 on this target. - #[stable(feature = "c_variadic", since = "1.99.0")] + #[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for f32 {} } _ => { @@ -348,18 +348,18 @@ crate::cfg_select! { } } -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for i32 {} -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for i64 {} -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for isize {} -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for u32 {} -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for u64 {} -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for usize {} // Implement `VaArgSafe` for 128-bit integers on targets where clang provides `__int128`. @@ -417,12 +417,12 @@ cfg_select! { } } -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for f64 {} -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for *mut T {} -#[stable(feature = "c_variadic", since = "1.99.0")] +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] unsafe impl VaArgSafe for *const T {} // Check that relevant `core::ffi` types implement `VaArgSafe`. diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index b339a80f45397..5be3475afd522 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -164,10 +164,12 @@ #[stable(feature = "c_str_module", since = "1.88.0")] pub mod c_str; +#[unstable(feature = "c_variadic_va_arg_safe", issue = "162911", implied_by = "c_variadic")] +pub use core::ffi::VaArgSafe; +#[stable(feature = "c_variadic", since = "1.99.0")] +pub use core::ffi::VaList; #[stable(feature = "core_c_void", since = "1.30.0")] pub use core::ffi::c_void; -#[stable(feature = "c_variadic", since = "1.99.0")] -pub use core::ffi::{VaArgSafe, VaList}; #[stable(feature = "core_ffi_c", since = "1.64.0")] pub use core::ffi::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, diff --git a/src/bootstrap/stdlib-semver-check-stamp b/src/bootstrap/stdlib-semver-check-stamp index a7221ad6185e3..a2f33f00e3ec3 100644 --- a/src/bootstrap/stdlib-semver-check-stamp +++ b/src/bootstrap/stdlib-semver-check-stamp @@ -2,4 +2,4 @@ Change this file to explicitly acknowledge making a breaking change to the Rust If this file is modified in the same PR as the breaking change, then CI will not fail due to the breaking change being detected by cargo-semver-checks. -Last change is for: https://github.com/rust-lang/rust/pull/162374 +Last change is for: https://github.com/rust-lang/rust/pull/162909 diff --git a/tests/ui/c-variadic/roundtrip.rs b/tests/ui/c-variadic/roundtrip.rs index 59ab4099f7620..9fa55c36e2441 100644 --- a/tests/ui/c-variadic/roundtrip.rs +++ b/tests/ui/c-variadic/roundtrip.rs @@ -1,6 +1,12 @@ //@ run-pass //@ ignore-backends: gcc -#![feature(const_c_variadic, c_variadic_int128, const_destruct, const_raw_ptr_comparison)] +#![feature( + const_c_variadic, + c_variadic_va_arg_safe, + c_variadic_int128, + const_destruct, + const_raw_ptr_comparison +)] #![allow(unused_features)] // c_variadic_int128 is only used on 64-bit targets. use std::ffi::*; diff --git a/tests/ui/consts/const-eval/c-variadic-fail.rs b/tests/ui/consts/const-eval/c-variadic-fail.rs index 97236c6ec8f90..8a46a80653ad1 100644 --- a/tests/ui/consts/const-eval/c-variadic-fail.rs +++ b/tests/ui/consts/const-eval/c-variadic-fail.rs @@ -1,5 +1,5 @@ //@ build-fail - +#![feature(c_variadic_va_arg_safe)] #![feature(const_c_variadic)] #![feature(const_trait_impl)] #![feature(const_destruct)] From 80dea6aea045a4e007aae5a84fc489e619bfefb4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 6 Aug 2026 00:01:00 +0200 Subject: [PATCH 06/10] forward global target features to module-level assembly (cherry picked from commit 37aaf5c30436c34ca2426b5356bebadded2b1f4c) --- compiler/rustc_codegen_llvm/src/asm.rs | 12 ++++- compiler/rustc_codegen_llvm/src/back/write.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 18 ++++--- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 19 +++++-- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 14 ++++++ tests/ui/asm/global-target-feature.rs | 49 +++++++++++++++++++ tests/ui/asm/inline-syntax.arm.stderr | 1 + tests/ui/asm/inline-syntax.rs | 2 +- 8 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 tests/ui/asm/global-target-feature.rs diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 31701acd7bf78..d8874a56a61b2 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -16,12 +16,12 @@ use rustc_target::spec::HasTargetSpec; use smallvec::SmallVec; use tracing::debug; -use crate::attributes; use crate::builder::Builder; use crate::common::Funclet; use crate::context::CodegenCx; use crate::llvm::{self, ToLlvmBool, Type, Value}; use crate::type_of::LayoutLlvmExt; +use crate::{attributes, llvm_util}; impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn codegen_inline_asm( @@ -499,7 +499,15 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { template_str.push_str("\n.att_syntax\n"); } - llvm::append_module_inline_asm(self.llmod, template_str.as_bytes()); + let target_features = self.tcx.global_backend_features(()).join(","); + let target_cpu = llvm_util::target_cpu(self.tcx.sess); + + llvm::append_module_inline_asm( + self.llmod, + template_str.as_bytes(), + &target_features, + target_cpu, + ); } fn mangled_name(&self, instance: Instance<'tcx>) -> String { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 66b51d9184a79..b8952ffc6bf81 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1303,9 +1303,9 @@ fn embed_bitcode( // We need custom section flags, so emit module-level inline assembly. let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::append_module_inline_asm(llmod, &asm); + llvm::append_module_inline_asm(llmod, &asm, "", ""); let asm = create_section_with_flags_asm(".llvmcmd", section_flags, &[]); - llvm::append_module_inline_asm(llmod, &asm); + llvm::append_module_inline_asm(llmod, &asm, "", ""); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index f575f37440f54..1f0a2f662075b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -909,13 +909,6 @@ unsafe extern "C" { pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char; pub(crate) fn LLVMSetDataLayout(M: &Module, Triple: *const c_char); - /// Append inline assembly to a module. See `Module::appendModuleInlineAsm`. - pub(crate) fn LLVMAppendModuleInlineAsm( - M: &Module, - Asm: *const c_uchar, // See "PTR_LEN_STR". - Len: size_t, - ); - /// Create the specified uniqued inline asm string. See `InlineAsm::get()`. pub(crate) fn LLVMGetInlineAsm<'ll>( Ty: &'ll Type, @@ -2121,6 +2114,17 @@ unsafe extern "C" { ConstraintsLen: size_t, ) -> bool; + /// Append inline assembly to a module. See `Module::appendModuleInlineAsm`. + pub(crate) fn LLVMRustAppendModuleInlineAsm( + M: &Module, + Asm: *const c_uchar, // See "PTR_LEN_STR". + AsmLen: size_t, + TargetFeatures: *const c_uchar, // See "PTR_LEN_STR". + TargetFeaturesLen: size_t, + TargetCpu: *const c_uchar, // See "PTR_LEN_STR". + TargetCpuLen: size_t, + ); + /// A list of pointer-length strings is passed as two pointer-length slices, /// one slice containing pointers and one slice containing their corresponding /// lengths. The implementation will check that both slices have the same length. diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index eb7a529c0b198..5452f4abc5c33 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -474,11 +474,24 @@ pub(crate) fn set_dso_local<'ll>(v: &'ll Value) { } } -/// Safe wrapper for `LLVMAppendModuleInlineAsm`, which delegates to +/// Safe wrapper for `LLVMRustAppendModuleInlineAsm`, which delegates to /// `Module::appendModuleInlineAsm`. -pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) { +pub(crate) fn append_module_inline_asm<'ll>( + llmod: &'ll Module, + asm: &[u8], + target_features: &str, + target_cpu: &str, +) { unsafe { - LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len()); + LLVMRustAppendModuleInlineAsm( + llmod, + asm.as_ptr(), + asm.len(), + target_features.as_ptr(), + target_features.len(), + target_cpu.as_ptr(), + target_cpu.len(), + ); } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 983a506bd4ac6..c928282596cdd 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -661,6 +661,20 @@ extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, unwrap(Ty), StringRef(Constraints, ConstraintsLen))); } +extern "C" void LLVMRustAppendModuleInlineAsm( + LLVMModuleRef M, const char *Asm, size_t AsmLen, const char *TargetFeatures, + size_t TargetFeaturesLen, const char *TargetCPU, size_t TargetCPULen) { +#if LLVM_VERSION_GE(23, 0) + Module::GlobalAsmProperties Props; + Props.TargetFeatures = std::string(TargetFeatures, TargetFeaturesLen); + Props.TargetCPU = std::string(TargetCPU, TargetCPULen); + unwrap(M)->appendModuleInlineAsm( + Module::GlobalAsmFragment(std::string(Asm, AsmLen), Props)); +#else + unwrap(M)->appendModuleInlineAsm(StringRef(Asm, AsmLen)); +#endif +} + template DIT *unwrapDIPtr(LLVMMetadataRef Ref) { return (DIT *)(Ref ? unwrap(Ref) : nullptr); } diff --git a/tests/ui/asm/global-target-feature.rs b/tests/ui/asm/global-target-feature.rs new file mode 100644 index 0000000000000..d84b4d51e6582 --- /dev/null +++ b/tests/ui/asm/global-target-feature.rs @@ -0,0 +1,49 @@ +//@ build-pass +//@ add-minicore +//@ min-llvm-version: 23 +//@ ignore-backends: gcc +// +//@ revisions: riscv opt-0-bitcode-no opt-0 opt-s-bitcode-no +// +//@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu -Clto=thin +//@[riscv] needs-llvm-components: riscv +// +//@[opt-0-bitcode-no] compile-flags: --target armv7r-none-eabihf -Copt-level=0 -Cembed-bitcode=no +//@[opt-0-bitcode-no] needs-llvm-components: arm +// +//@[opt-0] compile-flags: --target armv7r-none-eabihf -Copt-level=0 +//@[opt-0] needs-llvm-components: arm +// +//@[opt-s-bitcode-no] compile-flags: --target armv7r-none-eabihf -Copt-level=s -Cembed-bitcode=no +//@[opt-s-bitcode-no] needs-llvm-components: arm + +// Regression test for +// +// - https://github.com/llvm/llvm-project/issues/61991 +// - https://github.com/rust-lang/rust/issues/80608 +// - https://github.com/rust-lang/rust/issues/127269 +// +// Since LLVM 23 target features are taken into account for module-level assembly. + +#![feature(no_core)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[cfg(target_arch = "riscv64")] +global_asm!("fld f0, 0(sp)"); + +#[cfg(target_arch = "arm")] +global_asm!( + r#" +.section .text.startup +.global _start +.code 32 +.align 0 + +_start: + vmsr fpexc, r0 +"# +); diff --git a/tests/ui/asm/inline-syntax.arm.stderr b/tests/ui/asm/inline-syntax.arm.stderr index 5b4eb3cc1409c..5b193d26c8776 100644 --- a/tests/ui/asm/inline-syntax.arm.stderr +++ b/tests/ui/asm/inline-syntax.arm.stderr @@ -13,6 +13,7 @@ note: instantiated into assembly here | LL | .intel_syntax noprefix | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unknown directive --> $DIR/inline-syntax.rs:21:15 diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index b48841aabfe7b..63395c1096c09 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -3,10 +3,10 @@ //@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu //@[x86_64] check-pass //@[x86_64] needs-llvm-components: x86 -// LLVM 19+ has full support for 64-bit cookies. //@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf //@[arm] build-fail //@[arm] needs-llvm-components: arm +//@[arm] min-llvm-version: 23 //@ ignore-backends: gcc #![feature(no_core)] From efe1340d671d8df30af79a20791a2a443a4158fb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 8 Sep 2026 01:27:34 -0400 Subject: [PATCH 07/10] build: Rename `thumb_1` to `thumb1_only` This is a rather old config, added in c924aed0b9ac ("Fix Armv8-M Baseline compilation"). `thumb_1` is somewhat misleading, since targets with `thumb2` also support basic `thumb` instructions. Rename it to be more clear about what this is actually checking. The config is not currently used but may be in the future. (cherry picked from commit 5c592638da16c87a5ff3bf487efb5236459c2c31) --- library/compiler-builtins/libm/configure.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index ec4e46c391042..b204eb01b5bd2 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -112,7 +112,7 @@ pub fn emit(cfg: &Config) { // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because // these targets do not have full Thumb-2 support but only original Thumb-1. // We have to cfg our code accordingly. - let thumb_1 = split[0] == "thumbv6m" || split[0] == "thumbv8m.base"; + let thumb1_only = split[0] == "thumbv6m" || split[0] == "thumbv8m.base"; // Shorthand to detect i586 targets let x86_no_sse2 = cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse2"); @@ -122,7 +122,7 @@ pub fn emit(cfg: &Config) { // Arch shorthand config is used in most crates. set_cfg("thumb", thumb); - set_cfg("thumb_1", thumb_1); + set_cfg("thumb1_only", thumb1_only); set_cfg("x86_no_sse2", x86_no_sse2); match cfg.library { From fac00d1313db4a1e4d4d86f26a9e17d4bd0726b3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 8 Sep 2026 01:18:40 -0400 Subject: [PATCH 08/10] build: Add a disabled assertion for thumb mode config We still match on target name because we can't always rely on config from the unstable `arm_target_feature`. However, we can still assert that things match up when running in the compiler-builtins CI. This is disabled for now because it fails on three thumb targets: * thumbv4t-none-eabi * thumbv5te-none-eabi * thumbv6-none-eabi This will be resolved in a future commit. Checking for the verbose build is a good indicator that we are in our CI, rather than any other that might set the `CI` env. (cherry picked from commit 9e5d24801ad6c3cc8e5b3bf64614d569dc945134) --- library/compiler-builtins/libm/configure.rs | 24 +++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index b204eb01b5bd2..de50de3497f92 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -27,12 +27,14 @@ pub struct Config { pub target_features: Vec, pub reliable_f128: bool, pub reliable_f16: bool, + pub verbose_build: bool, } impl Config { pub fn from_env(library: Library) -> Self { println!("cargo:rerun-if-env-changed=LIBM_BUILD_VERBOSE"); - if env_flag("LIBM_BUILD_VERBOSE") { + let verbose_build = env_flag("LIBM_BUILD_VERBOSE"); + if verbose_build { VERBOSE_BUILD.store(true, Relaxed); } @@ -48,7 +50,7 @@ impl Config { .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) .map(|s| s.to_lowercase().replace("_", "-")) .collect(); - if VERBOSE_BUILD.load(Relaxed) { + if verbose_build { for feature in &cargo_features { println!("cargo:warning=feature `{feature}` enabled"); } @@ -73,6 +75,7 @@ impl Config { // with `RUSTC_BOOTSTRAP=1` (which is required to use the types anyway). reliable_f128: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F128").is_some(), reliable_f16: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F16").is_some(), + verbose_build, } } @@ -120,6 +123,23 @@ pub fn emit(cfg: &Config) { // If set, enable `no-panic` for `libm`. Requires LTO (`release-opt` profile). let assert_no_panic = env_flag("ENSURE_NO_PANIC"); + // Ensure that thumb is set when expected. We match on target name rather than using target + // features directly, since `arm_target_feature` is unfortunately not yet stable. If any + // target features are present, we are running on nightly and can do these checks. + /* FIXME: fails on targets such as thumbv5te-none-eabi + if cfg.verbose_build && !cfg.target_features.is_empty() { + if thumb { + assert!(cfg.has_target_feature("thumb-mode")); + } + if thumb1_only { + assert!(cfg.has_target_feature("thumb-mode")); + assert!(!cfg.has_target_feature("thumb2")); + } else if thumb { + assert!(cfg.has_target_feature("thumb2")); + } + } + */ + // Arch shorthand config is used in most crates. set_cfg("thumb", thumb); set_cfg("thumb1_only", thumb1_only); From bc562d5bd84fc1173c527c973e390d33c4ef4a8c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 7 Sep 2026 20:14:21 +0200 Subject: [PATCH 09/10] c-b: Add `aeabi_u(read|write)(4|8)` intrinsics. Fixes: https://github.com/rust-lang/rust/issues/162259 (cherry picked from commit a7f33f3f8c9077193833ef1dacfcc974b583abcb) --- .../builtins-test-intrinsics/src/main.rs | 49 ++++ .../builtins-test/tests/mem.rs | 62 +++++ .../compiler-builtins/README.md | 4 + .../compiler-builtins/build.rs | 4 - .../compiler-builtins/src/arm.rs | 261 ++++++++++++++++++ 5 files changed, 376 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index e390590946f4c..4bdfd4d73c85d 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -10,6 +10,7 @@ #![feature(f128)] #![feature(f16)] #![feature(lang_items)] +#![feature(optimize_attribute)] #![no_std] #![no_main] @@ -389,6 +390,47 @@ mod intrinsics { a % b } + /* Unaligned memory access */ + + // LLVM only emits calls to `__aeabi_uread*` and `__aeabi_uwrite*` for functions optimized + // for minimum size on AEABI targets without unaligned access support. + + /// # Safety + /// + /// `p` must be valid for reading four bytes. + #[optimize(size)] + pub unsafe fn aeabi_uread4(p: *const u8) -> u32 { + // SAFETY: guaranteed by the caller. + unsafe { p.cast::().read_unaligned() } + } + + /// # Safety + /// + /// `p` must be valid for reading eight bytes. + #[optimize(size)] + pub unsafe fn aeabi_uread8(p: *const u8) -> u64 { + // SAFETY: guaranteed by the caller. + unsafe { p.cast::().read_unaligned() } + } + + /// # Safety + /// + /// `p` must be valid for writing four bytes. + #[optimize(size)] + pub unsafe fn aeabi_uwrite4(x: u32, p: *mut u8) { + // SAFETY: guaranteed by the caller. + unsafe { p.cast::().write_unaligned(x) } + } + + /// # Safety + /// + /// `p` must be valid for writing eight bytes. + #[optimize(size)] + pub unsafe fn aeabi_uwrite8(x: u64, p: *mut u8) { + // SAFETY: guaranteed by the caller. + unsafe { p.cast::().write_unaligned(x) } + } + /* u64 operations */ // floatundisf @@ -500,6 +542,13 @@ fn run() { bb(aeabi_ui2f(bb(2))); bb(aeabi_uidiv(bb(2), bb(3))); bb(aeabi_uidivmod(bb(2), bb(3))); + // SAFETY: the pointers point to buffers large enough for the access. + unsafe { + bb(aeabi_uread4(bb([0u8; 4].as_ptr()))); + bb(aeabi_uread8(bb([0u8; 8].as_ptr()))); + bb(aeabi_uwrite4(bb(2), bb([0u8; 4].as_mut_ptr()))); + bb(aeabi_uwrite8(bb(2), bb([0u8; 8].as_mut_ptr()))); + } bb(aeabi_ul2d(bb(2))); bb(aeabi_ul2f(bb(2))); bb(aeabi_uldivmod(bb(2), bb(3))); diff --git a/library/compiler-builtins/builtins-test/tests/mem.rs b/library/compiler-builtins/builtins-test/tests/mem.rs index d838ef159a024..3c01a6179502f 100644 --- a/library/compiler-builtins/builtins-test/tests/mem.rs +++ b/library/compiler-builtins/builtins-test/tests/mem.rs @@ -284,3 +284,65 @@ fn memset_backward_aligned() { assert_eq!(arr.0, reference.0); } } + +#[cfg(all( + target_arch = "arm", + not(any(target_vendor = "apple", target_env = "msvc")) +))] +mod aeabi_unaligned { + use compiler_builtins::arm::__aeabi_uread4::__aeabi_uread4; + use compiler_builtins::arm::__aeabi_uread8::__aeabi_uread8; + use compiler_builtins::arm::__aeabi_uwrite4::__aeabi_uwrite4; + use compiler_builtins::arm::__aeabi_uwrite8::__aeabi_uwrite8; + + /// A buffer with distinct bytes so that any mixup in byte order or offset is detected. + const PATTERN: [u8; 16] = [ + 0x11, 0x48, 0x7f, 0xb6, 0xed, 0x24, 0x5b, 0x92, 0xc9, 0x00, 0x37, 0x6e, 0xa5, 0xdc, 0x13, + 0x4a, + ]; + + #[test] + fn uread() { + let buf = PATTERN; + for offset in 0..8 { + let b = &buf[offset..]; + let expected4 = u32::from_ne_bytes(*b.first_chunk::<4>().unwrap()); + let expected8 = u64::from_ne_bytes(*b.first_chunk::<8>().unwrap()); + unsafe { + assert_eq!(__aeabi_uread4(b.as_ptr()), expected4, "offset {offset}"); + assert_eq!(__aeabi_uread8(b.as_ptr()), expected8, "offset {offset}"); + } + } + } + + #[test] + fn uwrite() { + let value4 = 0x8765_4321_u32; + let value8 = 0x0f1e_2d3c_4b5a_6978_u64; + for offset in 0..8 { + let mut buf = PATTERN; + let mut expected = PATTERN; + expected[offset..offset + 4].copy_from_slice(&value4.to_ne_bytes()); + unsafe { + assert_eq!( + __aeabi_uwrite4(value4, buf.as_mut_ptr().add(offset)), + value4, + "offset {offset}" + ); + } + assert_eq!(buf, expected, "offset {offset}"); + + let mut buf = PATTERN; + let mut expected = PATTERN; + expected[offset..offset + 8].copy_from_slice(&value8.to_ne_bytes()); + unsafe { + assert_eq!( + __aeabi_uwrite8(value8, buf.as_mut_ptr().add(offset)), + value8, + "offset {offset}" + ); + } + assert_eq!(buf, expected, "offset {offset}"); + } + } +} diff --git a/library/compiler-builtins/compiler-builtins/README.md b/library/compiler-builtins/compiler-builtins/README.md index 63cbf33d2aea2..440e84f117805 100644 --- a/library/compiler-builtins/compiler-builtins/README.md +++ b/library/compiler-builtins/compiler-builtins/README.md @@ -39,6 +39,10 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md). - [x] arm/aeabi_memset.S - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S +- [x] arm/aeabi_uread4.S +- [x] arm/aeabi_uread8.S +- [x] arm/aeabi_uwrite4.S +- [x] arm/aeabi_uwrite8.S - [ ] arm/chkstk.S - [ ] arm/divmodsi4.S (generic version is done) - [ ] arm/divsi3.S (generic version is done) diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 8869add9f5ee4..e86c784b5c631 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -362,10 +362,6 @@ mod c { ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), ("__aeabi_frsub", "arm/aeabi_frsub.c"), - ("__aeabi_uread4", "arm/aeabi_uread4.S"), - ("__aeabi_uread8", "arm/aeabi_uread8.S"), - ("__aeabi_uwrite4", "arm/aeabi_uwrite4.S"), - ("__aeabi_uwrite8", "arm/aeabi_uwrite8.S"), ("__bswapdi2", "arm/bswapdi2.S"), ("__bswapsi2", "arm/bswapsi2.S"), ("__divmodsi4", "arm/divmodsi4.S"), diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index f26fce2d912b6..374eca7b2b679 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -313,4 +313,265 @@ intrinsics! { // SAFETY: memclr preconditions apply, less strict alignment. unsafe { __aeabi_memset4(dst, n, 0) }; } + + // ================================= + // Unaligned memory access functions + // see https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#533unaligned-memory-access + + // Read a `u32` from a possibly unaligned address. + // + // # Safety + // + // `address` must be valid for reading four bytes. + #[unsafe(naked)] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] + pub unsafe extern "aapcs" fn __aeabi_uread4(address: *const u8) -> u32 { + core::cfg_select! { + all(thumb1_only, target_endian = "little") => { + core::arch::naked_asm!( + "ldrb r1, [r0]", + "ldrb r2, [r0, #1]", + "lsls r2, r2, #8", + "adds r1, r2, r1", + "ldrb r2, [r0, #2]", + "lsls r2, r2, #16", + "ldrb r0, [r0, #3]", + "lsls r0, r0, #24", + "adds r0, r0, r2", + "adds r0, r0, r1", + "bx lr", + ); + } + all(thumb1_only, target_endian = "big") => { + core::arch::naked_asm!( + "ldrb r1, [r0, #3]", + "ldrb r2, [r0, #2]", + "lsls r2, r2, #8", + "adds r1, r2, r1", + "ldrb r2, [r0, #1]", + "lsls r2, r2, #16", + "ldrb r0, [r0]", + "lsls r0, r0, #24", + "adds r0, r0, r2", + "adds r0, r0, r1", + "bx lr", + ); + } + all(not(thumb1_only), target_endian = "little") => { + core::arch::naked_asm!( + "ldrb r1, [r0]", + "ldrb r2, [r0, #1]", + "ldrb r3, [r0, #2]", + "ldrb r0, [r0, #3]", + "orr r0, r3, r0, lsl #8", + "orr r1, r1, r2, lsl #8", + "orr r0, r1, r0, lsl #16", + "bx lr", + ); + } + all(not(thumb1_only), target_endian = "big") => { + core::arch::naked_asm!( + "ldrb r1, [r0]", + "ldrb r2, [r0, #1]", + "ldrb r3, [r0, #2]", + "ldrb r0, [r0, #3]", + "orr r1, r2, r1, lsl #8", + "orr r0, r0, r3, lsl #8", + "orr r0, r0, r1, lsl #16", + "bx lr", + ); + } + } + } + + // Read a `u64` from a possibly unaligned address. + // + // # Safety + // + // `address` must be valid for reading eight bytes. + #[unsafe(naked)] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] + pub unsafe extern "aapcs" fn __aeabi_uread8(address: *const u8) -> u64 { + core::cfg_select! { + all(thumb1_only, target_endian = "little") => { + core::arch::naked_asm!( + "ldrb r1, [r0]", + "ldrb r2, [r0, #1]", + "lsls r2, r2, #8", + "adds r1, r2, r1", + "ldrb r2, [r0, #2]", + "lsls r2, r2, #16", + "ldrb r3, [r0, #3]", + "lsls r3, r3, #24", + "adds r2, r3, r2", + "adds r2, r2, r1", + "ldrb r1, [r0, #4]", + "ldrb r3, [r0, #5]", + "lsls r3, r3, #8", + "adds r1, r3, r1", + "ldrb r3, [r0, #6]", + "lsls r3, r3, #16", + "ldrb r0, [r0, #7]", + "lsls r0, r0, #24", + "adds r0, r0, r3", + "adds r1, r0, r1", + "movs r0, r2", + "bx lr", + ); + } + all(thumb1_only, target_endian = "big") => { + core::arch::naked_asm!( + "ldrb r1, [r0, #3]", + "ldrb r2, [r0, #2]", + "lsls r2, r2, #8", + "adds r1, r2, r1", + "ldrb r2, [r0, #1]", + "lsls r2, r2, #16", + "ldrb r3, [r0]", + "lsls r3, r3, #24", + "adds r2, r3, r2", + "adds r2, r2, r1", + "ldrb r1, [r0, #7]", + "ldrb r3, [r0, #6]", + "lsls r3, r3, #8", + "adds r1, r3, r1", + "ldrb r3, [r0, #5]", + "lsls r3, r3, #16", + "ldrb r0, [r0, #4]", + "lsls r0, r0, #24", + "adds r0, r0, r3", + "adds r1, r0, r1", + "movs r0, r2", + "bx lr", + ); + } + all(not(thumb1_only), target_endian = "little") => { + core::arch::naked_asm!( + "ldrb r12, [r0]", + "ldrb r2, [r0, #1]", + "ldrb r3, [r0, #2]", + "ldrb r1, [r0, #3]", + "orr r1, r3, r1, lsl #8", + "orr r2, r12, r2, lsl #8", + "orr r2, r2, r1, lsl #16", + "ldrb r1, [r0, #5]", + "ldrb r3, [r0, #4]!", + "orr r1, r3, r1, lsl #8", + "ldrb r3, [r0, #2]", + "ldrb r0, [r0, #3]", + "orr r0, r3, r0, lsl #8", + "orr r1, r1, r0, lsl #16", + "mov r0, r2", + "bx lr", + ); + } + all(not(thumb1_only), target_endian = "big") => { + core::arch::naked_asm!( + "ldrb r12, [r0]", + "ldrb r2, [r0, #1]", + "ldrb r3, [r0, #2]", + "ldrb r1, [r0, #3]", + "orr r2, r2, r12, lsl #8", + "orr r1, r1, r3, lsl #8", + "orr r2, r1, r2, lsl #16", + "mov r1, r0", + "ldrb r0, [r0, #5]", + "ldrb r3, [r1, #4]!", + "orr r0, r0, r3, lsl #8", + "ldrb r3, [r1, #2]", + "ldrb r1, [r1, #3]", + "orr r1, r1, r3, lsl #8", + "orr r1, r1, r0, lsl #16", + "mov r0, r2", + "bx lr", + ); + } + } + } + + // Write a `u32` to a possibly unaligned address, returning the value written. + // + // # Safety + // + // `address` must be valid for writing four bytes. + #[unsafe(naked)] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] + pub unsafe extern "aapcs" fn __aeabi_uwrite4(value: u32, address: *mut u8) -> u32 { + core::cfg_select! { + target_endian = "little" => { + core::arch::naked_asm!( + "lsrs r2, r0, #24", + "strb r0, [r1]", + "strb r2, [r1, #3]", + "lsrs r2, r0, #16", + "strb r2, [r1, #2]", + "lsrs r2, r0, #8", + "strb r2, [r1, #1]", + "bx lr", + ); + } + target_endian = "big" => { + core::arch::naked_asm!( + "lsrs r2, r0, #8", + "strb r0, [r1, #3]", + "strb r2, [r1, #2]", + "lsrs r2, r0, #16", + "strb r2, [r1, #1]", + "lsrs r2, r0, #24", + "strb r2, [r1]", + "bx lr", + ); + } + } + } + + // Write a `u64` to a possibly unaligned address, returning the value written. + // + // # Safety + // + // `address` must be valid for writing eight bytes. + #[unsafe(naked)] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] + pub unsafe extern "aapcs" fn __aeabi_uwrite8(value: u64, address: *mut u8) -> u64 { + core::cfg_select! { + target_endian = "little" => { + core::arch::naked_asm!( + "strb r0, [r2, #0]", + "lsrs r3, r0, #8", + "strb r3, [r2, #1]", + "lsrs r3, r0, #16", + "strb r3, [r2, #2]", + "lsrs r3, r0, #24", + "strb r3, [r2, #3]", + "strb r1, [r2, #4]", + "lsrs r3, r1, #8", + "strb r3, [r2, #5]", + "lsrs r3, r1, #16", + "strb r3, [r2, #6]", + "lsrs r3, r1, #24", + "strb r3, [r2, #7]", + "bx lr", + ); + } + target_endian = "big" => { + core::arch::naked_asm!( + "lsrs r3, r0, #24", + "strb r3, [r2, #0]", + "lsrs r3, r0, #16", + "strb r3, [r2, #1]", + "lsrs r3, r0, #8", + "strb r3, [r2, #2]", + "strb r0, [r2, #3]", + "lsrs r3, r1, #24", + "strb r3, [r2, #4]", + "lsrs r3, r1, #16", + "strb r3, [r2, #5]", + "lsrs r3, r1, #8", + "strb r3, [r2, #6]", + "strb r1, [r2, #7]", + "bx lr", + ); + } + } + } } From 9e8e33c41f835ab1af74f58904742ed56e1c2ce1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 7 Sep 2026 21:51:40 +0200 Subject: [PATCH 10/10] build: Fix thumb_1 cfg to include all "thumb but not thumbv2" targets. (cherry picked from commit 192ea4f1f7a41a08a2fe58f7dec55bc582fa489a) --- library/compiler-builtins/libm/configure.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index de50de3497f92..3b0bb64a9e83c 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -112,10 +112,12 @@ pub fn emit(cfg: &Config) { // To compile builtins-test-intrinsics for thumb targets, where there is no libc let thumb = split[0].starts_with("thumb"); - // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because - // these targets do not have full Thumb-2 support but only original Thumb-1. - // We have to cfg our code accordingly. - let thumb1_only = split[0] == "thumbv6m" || split[0] == "thumbv8m.base"; + // compiler-rt `cfg`s away some intrinsics for targets that do not have full Thumb-2 support + // but only original Thumb-1. We have to cfg our code accordingly. + let thumb1_only = matches!( + split[0].as_str(), + "thumbv4t" | "thumbv5te" | "thumbv6" | "thumbv6m" | "thumbv8m.base" + ); // Shorthand to detect i586 targets let x86_no_sse2 = cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse2"); @@ -126,7 +128,6 @@ pub fn emit(cfg: &Config) { // Ensure that thumb is set when expected. We match on target name rather than using target // features directly, since `arm_target_feature` is unfortunately not yet stable. If any // target features are present, we are running on nightly and can do these checks. - /* FIXME: fails on targets such as thumbv5te-none-eabi if cfg.verbose_build && !cfg.target_features.is_empty() { if thumb { assert!(cfg.has_target_feature("thumb-mode")); @@ -138,7 +139,6 @@ pub fn emit(cfg: &Config) { assert!(cfg.has_target_feature("thumb2")); } } - */ // Arch shorthand config is used in most crates. set_cfg("thumb", thumb);