Rollup merge of #149241 - thejpster:fix-armv4t-armv5te-bare-metal, r=davidtwco

Fix armv4t- and armv5te- bare metal targets

These two targets currently force on the LLVM feature `+atomics-32`. LLVM doesn't appear to actually be able to emit 32-bit load/store atomics for these targets despite this feature, and emits calls to a shim function called `__sync_lock_test_and_set_4`, which nothing in the Rust standard library supplies.

See [#t-compiler/arm > __sync_lock_test_and_set_4 on Armv5TE](https://rust-lang.zulipchat.com/#narrow/channel/242906-t-compiler.2Farm/topic/__sync_lock_test_and_set_4.20on.20Armv5TE/with/553724827) for more details.

Experimenting with clang and gcc (as logged in that zulip thread) shows that C code cannot do atomic load/stores on that architecture either (at least, not without a library call inserted).

So, the safest thing to do is probably turn off `+atomics-32` for these two Tier 3 targets.

I asked `@Lokathor` and he said he didn't even use atomics on the `armv4t-none-eabi`/`thumbv4t-none-eabi` target he maintains.

I was unable to reach `@QuinnPainter` for comment for `armv5te-none-eabi`/`thumbv5te-none-eabi`.

The second commit renames the base target spec `spec::base::thumb` to `spec::base::arm_none` and changes `armv4t-none-eabi`/`thumbv4t-none-eabi` and `armv5te-none-eabi`/`thumbv5te-none-eabi` to use it. This harmonises the frame-pointer and linker options across the bare-metal Arm EABI and EABIHF targets.

You could make an argument for harmonising `armv7a-none-*`, `armv7r-none*` and `armv8r-none-*` as well, but that can be another PR.
This commit is contained in:
Stuart Cook 2025-12-02 13:56:30 +11:00 committed by GitHub
commit c539f3ffe1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 54 additions and 173 deletions

View file

@ -1,31 +1,4 @@
// These `thumbv*` targets cover the ARM Cortex-M family of processors which are widely used in
// microcontrollers. Namely, all these processors:
//
// - Cortex-M0
// - Cortex-M0+
// - Cortex-M1
// - Cortex-M3
// - Cortex-M4(F)
// - Cortex-M7(F)
// - Cortex-M23
// - Cortex-M33
//
// We have opted for these instead of one target per processor (e.g., `cortex-m0`, `cortex-m3`,
// etc) because the differences between some processors like the cortex-m0 and cortex-m1 are almost
// nonexistent from the POV of codegen so it doesn't make sense to have separate targets for them.
// And if differences exist between two processors under the same target, rustc flags can be used to
// optimize for one processor or the other.
//
// Also, we have not chosen a single target (`arm-none-eabi`) like GCC does because this makes
// difficult to integrate Rust code and C code. Targeting the Cortex-M4 requires different gcc flags
// than the ones you would use for the Cortex-M0 and with a single target it'd be impossible to
// differentiate one processor from the other.
//
// About arm vs thumb in the name. The Cortex-M devices only support the Thumb instruction set,
// which is more compact (higher code density), and not the ARM instruction set. That's why LLVM
// triples use thumb instead of arm. We follow suit because having thumb in the name let us
// differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of
// build scripts / gcc flags.
// These are the baseline settings for 32-bit bare-metal Arm targets using the EABI or EABIHF ABI.
use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, PanicStrategy, RelocModel, TargetOptions};

View file

@ -1,6 +1,7 @@
pub(crate) mod aix;
pub(crate) mod android;
pub mod apple;
pub(crate) mod arm_none;
pub(crate) mod avr;
pub(crate) mod bpf;
pub(crate) mod cygwin;
@ -31,7 +32,6 @@ pub(crate) mod redox;
pub(crate) mod solaris;
pub(crate) mod solid;
pub(crate) mod teeos;
pub(crate) mod thumb;
pub(crate) mod uefi_msvc;
pub(crate) mod unikraft_linux_musl;
pub(crate) mod vxworks;

View file

@ -9,10 +9,7 @@
//! The default link script is very likely wrong, so you should use
//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
use crate::spec::{
Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
TargetOptions, cvs,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
@ -25,35 +22,16 @@ pub(crate) fn target() -> Target {
},
pointer_width: 32,
arch: Arch::Arm,
/* Data layout args are '-' separated:
* little endian
* stack is 64-bit aligned (EABI)
* pointers are 32-bit
* i64 must be 64-bit aligned (EABI)
* mangle names with ELF style
* native integers are 32-bit
* All other elements are default
*/
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),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],
// Force-enable 32-bit atomics, which allows the use of atomic load/store only.
// The resulting atomics are ABI incompatible with atomics backed by libatomic.
features: "+soft-float,+strict-align,+atomics-32".into(),
main_needs_argc_argv: false,
features: "+soft-float,+strict-align".into(),
atomic_cas: false,
max_atomic_width: Some(0),
has_thumb_interworking: true,
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
// From thumb_base, rust-lang/rust#44993.
emit_debug_gdb_scripts: false,
// From thumb_base, GCC gives enums a minimum of 8 bits on no-os targets.
c_enum_min_bits: Some(8),
..Default::default()
..base::arm_none::opts()
},
}
}

View file

@ -1,8 +1,6 @@
//! Targets the ARMv5TE, with code as `a32` code by default.
use crate::spec::{
Abi, Arch, FloatAbi, FramePointer, Target, TargetMetadata, TargetOptions, base, cvs,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
@ -15,36 +13,16 @@ pub(crate) fn target() -> Target {
},
pointer_width: 32,
arch: Arch::Arm,
/* Data layout args are '-' separated:
* little endian
* stack is 64-bit aligned (EABI)
* pointers are 32-bit
* i64 must be 64-bit aligned (EABI)
* mangle names with ELF style
* native integers are 32-bit
* All other elements are default
*/
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),
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
// * activate t32/a32 interworking
// * use arch ARMv5TE
// * use little-endian
asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",],
// minimum extra features, these cannot be disabled via -C
// Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
// The resulting atomics are ABI incompatible with atomics backed by libatomic.
features: "+soft-float,+strict-align,+atomics-32".into(),
frame_pointer: FramePointer::MayOmit,
main_needs_argc_argv: false,
// don't have atomic compare-and-swap
features: "+soft-float,+strict-align".into(),
atomic_cas: false,
max_atomic_width: Some(0),
has_thumb_interworking: true,
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -9,10 +9,7 @@
//! The default link script is very likely wrong, so you should use
//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
use crate::spec::{
Abi, Arch, FloatAbi, FramePointer, PanicStrategy, RelocModel, Target, TargetMetadata,
TargetOptions, base, cvs,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
@ -25,44 +22,16 @@ pub(crate) fn target() -> Target {
},
pointer_width: 32,
arch: Arch::Arm,
/* Data layout args are '-' separated:
* little endian
* stack is 64-bit aligned (EABI)
* pointers are 32-bit
* i64 must be 64-bit aligned (EABI)
* mangle names with ELF style
* native integers are 32-bit
* All other elements are default
*/
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),
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
// * activate t32/a32 interworking
// * use arch ARMv4T
// * use little-endian
asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],
// minimum extra features, these cannot be disabled via -C
// Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
// The resulting atomics are ABI incompatible with atomics backed by libatomic.
features: "+soft-float,+strict-align,+atomics-32".into(),
panic_strategy: PanicStrategy::Abort,
relocation_model: RelocModel::Static,
// suggested from thumb_base, rust-lang/rust#44993.
emit_debug_gdb_scripts: false,
frame_pointer: FramePointer::MayOmit,
main_needs_argc_argv: false,
// don't have atomic compare-and-swap
features: "+soft-float,+strict-align".into(),
atomic_cas: false,
max_atomic_width: Some(0),
has_thumb_interworking: true,
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -1,8 +1,6 @@
//! Targets the ARMv5TE, with code as `t32` code by default.
use crate::spec::{
Abi, Arch, FloatAbi, FramePointer, Target, TargetMetadata, TargetOptions, base, cvs,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
@ -15,36 +13,16 @@ pub(crate) fn target() -> Target {
},
pointer_width: 32,
arch: Arch::Arm,
/* Data layout args are '-' separated:
* little endian
* stack is 64-bit aligned (EABI)
* pointers are 32-bit
* i64 must be 64-bit aligned (EABI)
* mangle names with ELF style
* native integers are 32-bit
* All other elements are default
*/
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),
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
// * activate t32/a32 interworking
// * use arch ARMv5TE
// * use little-endian
asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",],
// minimum extra features, these cannot be disabled via -C
// Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
// The resulting atomics are ABI incompatible with atomics backed by libatomic.
features: "+soft-float,+strict-align,+atomics-32".into(),
frame_pointer: FramePointer::MayOmit,
main_needs_argc_argv: false,
// don't have atomic compare-and-swap
features: "+soft-float,+strict-align".into(),
atomic_cas: false,
max_atomic_width: Some(0),
has_thumb_interworking: true,
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -26,7 +26,7 @@ pub(crate) fn target() -> Target {
// There are no atomic CAS instructions available in the instruction set of the ARMv6-M
// architecture
atomic_cas: false,
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -25,7 +25,7 @@ pub(crate) fn target() -> Target {
// The ARMv6-M doesn't support hardware atomic operations, use atomic builtins instead.
features: "+strict-align".into(),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -27,7 +27,7 @@ pub(crate) fn target() -> Target {
// Cortex-A7/A8/A9 with software floating point
features: "+soft-float,-neon".into(),
max_atomic_width: Some(64),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -31,7 +31,7 @@ pub(crate) fn target() -> Target {
// and NEON SIMD instructions
features: "+vfp3,+neon".into(),
max_atomic_width: Some(64),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -28,7 +28,7 @@ pub(crate) fn target() -> Target {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -36,7 +36,7 @@ pub(crate) fn target() -> Target {
// ARMv7-M Architecture Reference Manual - A2.5 The optional floating-point extension
features: "+vfp4d16sp".into(),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -30,7 +30,7 @@ pub(crate) fn target() -> Target {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -38,7 +38,7 @@ pub(crate) fn target() -> Target {
// ARMv7-M Architecture Reference Manual - A2.5 The optional floating-point extension
features: "+vfp4d16sp".into(),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -19,7 +19,7 @@ pub(crate) fn target() -> Target {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -21,7 +21,7 @@ pub(crate) fn target() -> Target {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -22,7 +22,7 @@ pub(crate) fn target() -> Target {
// with +strict-align.
features: "+strict-align".into(),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -24,7 +24,7 @@ pub(crate) fn target() -> Target {
// with +strict-align.
features: "+strict-align".into(),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -20,7 +20,7 @@ pub(crate) fn target() -> Target {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -25,7 +25,7 @@ pub(crate) fn target() -> Target {
// and 16 D registers.
features: "+fp-armv8d16sp".into(),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -22,7 +22,7 @@ pub(crate) fn target() -> Target {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -27,7 +27,7 @@ pub(crate) fn target() -> Target {
// and 16 D registers.
features: "+fp-armv8d16sp".into(),
max_atomic_width: Some(32),
..base::thumb::opts()
..base::arm_none::opts()
},
}
}

View file

@ -130,16 +130,18 @@
//!
//! * PowerPC and MIPS platforms with 32-bit pointers do not have `AtomicU64` or
//! `AtomicI64` types.
//! * ARM platforms like `armv5te` that aren't for Linux only provide `load`
//! and `store` operations, and do not support Compare and Swap (CAS)
//! operations, such as `swap`, `fetch_add`, etc. Additionally on Linux,
//! these CAS operations are implemented via [operating system support], which
//! may come with a performance penalty.
//! * ARM targets with `thumbv6m` only provide `load` and `store` operations,
//! and do not support Compare and Swap (CAS) operations, such as `swap`,
//! `fetch_add`, etc.
//! * Legacy ARM platforms like ARMv4T and ARMv5TE have very limited hardware
//! support for atomics. The bare-metal targets disable this module
//! entirely, but the Linux targets [use the kernel] to assist (which comes
//! with a performance penalty). It's not until ARMv6K onwards that ARM CPUs
//! have support for load/store and Compare and Swap (CAS) atomics in hardware.
//! * ARMv6-M and ARMv8-M baseline targets (`thumbv6m-*` and
//! `thumbv8m.base-*`) only provide `load` and `store` operations, and do
//! not support Compare and Swap (CAS) operations, such as `swap`,
//! `fetch_add`, etc. Full CAS support is available on ARMv7-M and ARMv8-M
//! Mainline (`thumbv7m-*`, `thumbv7em*` and `thumbv8m.main-*`).
//!
//! [operating system support]: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt
//! [use the kernel]: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt
//!
//! Note that future platforms may be added that also do not have support for
//! some atomic operations. Maximally portable code will want to be careful

View file

@ -54,8 +54,8 @@
- [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md)
- [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md)
- [arm-none-eabi](platform-support/arm-none-eabi.md)
- [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
- [armv5te-none-eabi](platform-support/armv5te-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)
- [armv7a-none-eabi{,hf}](platform-support/armv7a-none-eabi.md)
- [armv7r-none-eabi{,hf}](platform-support/armv7r-none-eabi.md)
- [armebv7r-none-eabi{,hf}](platform-support/armebv7r-none-eabi.md)

View file

@ -8,7 +8,8 @@ group, and all the information there applies.
Both of these targets can be used on the Game Boy Advance (GBA), among other
things. On the GBA, one should usually use the `thumb` target to get the best
overall performance.
overall performance. Note that this architecture only supports the old
Thumb-1 instruction set, not the later Thumb-2 instruction set.
## Target Maintainers

View file

@ -4,10 +4,12 @@
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for any cpu in the Armv5TE architecture family, supporting
ARM/Thumb code interworking (aka `A32`/`T32`), with `A32` code as the default code
generation.
ARM/Thumb code interworking (aka `Arm`/`Thumb`), with `Arm` code as the
default code generation.
The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `T32`.
The `thumbv5te-none-eabi` target is the same as this one, but the instruction
set defaults to `Thumb`. Note that this architecture only supports the old
Thumb-1 instruction set, not the later Thumb-2 instruction set.
See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
`arm-none-eabi` targets.