Skip to content

Commit

Permalink
Merge #73
Browse files Browse the repository at this point in the history
73: aarch64: Support outline atomics on old nightly r=taiki-e a=taiki-e

Similar to 3f5d42f.

This also supports building for aarch64 linux-uclibc.

Co-authored-by: Taiki Endo <[email protected]>
  • Loading branch information
bors[bot] and taiki-e authored Feb 10, 2023
2 parents cdb7020 + a5b7722 commit 8e4de84
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 65 deletions.
17 changes: 13 additions & 4 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,6 @@ fn main() {
}
println!("cargo:rustc-cfg=portable_atomic_no_asm");
}
// aarch64_target_feature stabilized in Rust 1.61 (nightly-2022-03-16): https://github.com/rust-lang/rust/pull/90621
if !version.probe(61, 2022, 3, 15) {
println!("cargo:rustc-cfg=portable_atomic_no_aarch64_target_feature");
}
// https://github.com/rust-lang/rust/pull/98383 merged in Rust 1.64 (nightly-2022-07-19).
if !version.probe(64, 2022, 7, 18) {
println!("cargo:rustc-cfg=portable_atomic_no_stronger_failure_ordering");
Expand Down Expand Up @@ -176,6 +172,19 @@ fn main() {
}
}
"aarch64" => {
// aarch64_target_feature stabilized in Rust 1.61 (nightly-2022-03-16): https://github.com/rust-lang/rust/pull/90621
if !version.probe(61, 2022, 3, 15) {
if version.nightly && is_allowed_feature("aarch64_target_feature") {
// The part of this feature we use has not been changed since 1.27
// (https://github.com/rust-lang/rust/commit/1217d70465edb2079880347fea4baaac56895f51)
// until it was stabilized in nightly-2022-03-16, so it can be safely enabled in
// nightly, which is older than nightly-2022-03-16.
println!("cargo:rustc-cfg=portable_atomic_unstable_aarch64_target_feature");
} else {
println!("cargo:rustc-cfg=portable_atomic_no_aarch64_target_feature");
}
}

// aarch64 macos always support FEAT_LSE and FEAT_LSE2 because it is armv8.6: https://github.com/rust-lang/rust/blob/1.67.0/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs#L7
let is_macos = target_os == "macos";
// aarch64_target_feature stabilized in Rust 1.61.
Expand Down
7 changes: 5 additions & 2 deletions src/imp/atomic128/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,12 @@ unsafe fn atomic_compare_exchange(
#[cfg(any(
target_feature = "lse",
portable_atomic_target_feature = "lse",
not(portable_atomic_no_aarch64_target_feature),
all(not(portable_atomic_no_aarch64_target_feature), not(portable_atomic_no_outline_atomics)),
))]
#[cfg_attr(not(portable_atomic_no_aarch64_target_feature), target_feature(enable = "lse"))]
#[cfg_attr(
not(any(target_feature = "lse", portable_atomic_target_feature = "lse",)),
target_feature(enable = "lse")
)]
#[inline]
unsafe fn _atomic_compare_exchange_casp(
dst: *mut u128,
Expand Down
28 changes: 19 additions & 9 deletions src/imp/atomic128/detect/aarch64_linux.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
// Run-time feature detection on aarch64 Linux/Android by using getauxval.
//
// As of nightly-2023-01-23, is_aarch64_feature_detected always uses dlsym by default
// on aarch64 Linux/Android, but on the following platforms, so we can safely assume getauxval
// is linked to the binary.
// on aarch64 Linux/Android, but on the following platforms, so we can safely assume
// getauxval is linked to the binary.
//
// - On linux-gnu, [aarch64 support is available on glibc 2.17+](https://sourceware.org/legacy-ml/libc-announce/2012/msg00001.html)
// and is newer than [glibc 2.16 that getauxval was added](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html).
// and is newer than [glibc 2.16 that added getauxval](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html).
// - On Android, [64-bit architecture support is available on Android 5.0+ (API level 21+)](https://android-developers.googleblog.com/2014/10/whats-new-in-android-50-lollipop.html)
// and is newer than [Android 4.3 (API level 18) that getauxval was added](https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/include/sys/auxv.h#49).
// and is newer than [Android 4.3 (API level 18) that added getauxval](https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/include/sys/auxv.h#49).
//
// See also https://github.com/rust-lang/stdarch/pull/1375
// On other Linux targets, we cannot assume that getauxval is always available,
// so we use is_aarch64_feature_detected which uses dlsym (+io fallback) instead
// of this module.
//
// - On linux-musl, [aarch64 support is available on musl 1.1.7+](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.7#n1422)
// and is newer than [musl 1.1.0 that added getauxval](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197).
// However, it seems that getauxval is not always available, independent of version requirements: https://github.com/rust-lang/rust/issues/89626
// (That problem may have been fixed in https://github.com/rust-lang/rust/commit/9a04ae4997493e9260352064163285cddc43de3c,
// but even in the version containing that patch, [there is report](https://github.com/rust-lang/rust/issues/89626#issuecomment-1242636038)
// of the same error.)
// - On linux-uclibc, they [recently added getauxval](https://repo.or.cz/uclibc-ng.git/commitdiff/d869bb1600942c01a77539128f9ba5b5b55ad647)
// but have not released it yet (as of 2023-02-09).
//
// On other Linux targets, we cannot assume that getauxval is always available yet
// (see stdarch PR linked above for details), so we use is_aarch64_feature_detected
// which uses dlsym (+io fallback) instead of this module.
// See also https://github.com/rust-lang/stdarch/pull/1375

#![cfg_attr(
any(
Expand Down Expand Up @@ -50,7 +59,8 @@ mod ffi {

#[inline]
fn _detect(info: &mut CpuInfo) {
// SAFETY: getauxval is available in all versions on aarch64 linux-gnu. see also module level docs
// SAFETY: getauxval is available in all versions on aarch64 linux-gnu/android.
// See also the module level docs.
let hwcap = unsafe { ffi::getauxval(ffi::AT_HWCAP) };

// https://github.com/torvalds/linux/blob/HEAD/arch/arm64/include/uapi/asm/hwcap.h
Expand Down
7 changes: 5 additions & 2 deletions src/imp/atomic128/detect/aarch64_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ pub(crate) fn has_lse() -> bool {
#[allow(unreachable_code)]
{
#[cfg(all(
not(portable_atomic_no_aarch64_target_feature),
not(any(
portable_atomic_no_aarch64_target_feature,
portable_atomic_unstable_aarch64_target_feature
)),
// https://github.com/rust-lang/stdarch/blob/a0c30f3e3c75adcd6ee7efc94014ebcead61c507/crates/std_detect/src/detect/mod.rs
// It is fine to use std for targets that we know can be linked to std.
// Note: std may not be available on tier 3 such as aarch64 FreeBSD/OpenBSD.
any(
feature = "std",
target_os = "linux",
all(target_os = "linux", any(target_env = "gnu", target_env = "musl")),
target_os = "android",
target_os = "windows",
// target_os = "freebsd",
Expand Down
20 changes: 16 additions & 4 deletions src/imp/atomic128/detect/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,10 @@ mod tests_aarch64_common {
#[cfg(any(
target_feature = "lse",
portable_atomic_target_feature = "lse",
not(portable_atomic_no_aarch64_target_feature),
all(
not(portable_atomic_no_aarch64_target_feature),
not(portable_atomic_no_outline_atomics)
),
))]
unsafe {
use core::{cell::UnsafeCell, sync::atomic::Ordering};
Expand All @@ -265,7 +268,10 @@ mod tests_aarch64_common {
}
} else {
assert!(!detect().test(CpuInfo::HAS_LSE));
#[cfg(not(portable_atomic_no_aarch64_target_feature))]
#[cfg(not(any(
portable_atomic_no_aarch64_target_feature,
portable_atomic_unstable_aarch64_target_feature
)))]
{
assert!(!std::arch::is_aarch64_feature_detected!("lse"));
}
Expand All @@ -281,7 +287,10 @@ mod tests_aarch64_common {
}
} else {
assert!(!detect().test(CpuInfo::HAS_LSE2));
// #[cfg(not(portable_atomic_no_aarch64_target_feature))]
// #[cfg(not(any(
// portable_atomic_no_aarch64_target_feature,
// portable_atomic_unstable_aarch64_target_feature
// )))]
// {
// assert!(!std::arch::is_aarch64_feature_detected!("lse2"));
// }
Expand All @@ -295,7 +304,10 @@ mod tests_aarch64_common {
assert!(detect().test(CpuInfo::HAS_LSE128));
} else {
assert!(!detect().test(CpuInfo::HAS_LSE128));
// #[cfg(not(portable_atomic_no_aarch64_target_feature))]
// #[cfg(not(any(
// portable_atomic_no_aarch64_target_feature,
// portable_atomic_unstable_aarch64_target_feature
// )))]
// {
// assert!(!std::arch::is_aarch64_feature_detected!("lse128"));
// }
Expand Down
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,19 @@ See also [the `atomic128` module's readme](https://github.com/taiki-e/portable-a
// These features are already stabilized or have already been removed from compilers,
// and can safely be enabled for old nightly as long as version detection works.
// - cfg(target_has_atomic)
// - #[target_feature(enable = "lse")] on AArch64
// - asm! on ARM, AArch64, RISC-V, x86_64
// - llvm_asm! on AVR (tier 3) and MSP430 (tier 3)
// - #[instruction_set] on non-Linux pre-v6 ARM (tier 3)
#![cfg_attr(portable_atomic_unstable_cfg_target_has_atomic, feature(cfg_target_has_atomic))]
#![cfg_attr(
all(
target_arch = "aarch64",
portable_atomic_unstable_aarch64_target_feature,
not(portable_atomic_no_outline_atomics),
),
feature(aarch64_target_feature)
)]
#![cfg_attr(
all(
portable_atomic_unstable_asm,
Expand Down
18 changes: 18 additions & 0 deletions target-specs/aarch64-unknown-linux-uclibc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"arch": "aarch64",
"crt-static-respected": true,
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
"dynamic-linking": true,
"env": "uclibc",
"has-rpath": true,
"has-thread-local": true,
"llvm-target": "aarch64-unknown-linux-uclibc",
"max-atomic-width": 128,
"os": "linux",
"position-independent-executables": true,
"relro-level": "full",
"supported-split-debuginfo": ["packed", "unpacked", "off"],
"target-family": ["unix"],
"target-mcount": "\u0001_mcount",
"target-pointer-width": "64"
}
93 changes: 49 additions & 44 deletions tools/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ default_targets=(
aarch64-unknown-freebsd
aarch64-unknown-linux-gnu
aarch64-unknown-linux-musl
aarch64-unknown-linux-uclibc # custom target
aarch64-unknown-openbsd
# aarch64 always support lse & lse2
aarch64-apple-darwin
Expand Down Expand Up @@ -110,6 +111,13 @@ x_cargo() {
x cargo "$@"
echo
}
is_no_std() {
case "$1" in
# aarch64-unknown-linux-uclibc is a custom target and libc/std currently doesn't support it.
*-none* | *-uefi* | *-cuda* | avr-* | *-esp-espidf | aarch64-unknown-linux-uclibc) return 0 ;;
*) return 1 ;;
esac
}

pre_args=()
if [[ "${1:-}" == "+"* ]]; then
Expand Down Expand Up @@ -191,10 +199,11 @@ build() {
echo "-Z build-std not available on ${rustc_version} (skipped all checks for '${target}')"
return 0
fi
case "${target}" in
*-none* | *-uefi* | *-cuda* | avr-* | *-esp-espidf) args+=(-Z build-std="core,alloc") ;;
*) args+=(-Z build-std) ;;
esac
if is_no_std "${target}"; then
args+=(-Z build-std="core,alloc")
else
args+=(-Z build-std)
fi
else
echo "target '${target}' requires nightly compiler (skipped all checks)"
return 0
Expand Down Expand Up @@ -222,13 +231,11 @@ build() {
fi

if [[ "${TESTS:-}" == "1" ]]; then
case "${target}" in
if is_no_std "${target}"; then
# we use std in tests
*-none* | *-uefi* | *-cuda* | avr-* | *-esp-espidf)
echo "target '${target}' does not support 'std' required to build tests (skipped all checks)"
return 0
;;
esac
echo "target '${target}' does not support 'std' required to build tests (skipped all checks)"
return 0
fi
args+=(
--workspace --all-features
--exclude bench --exclude portable-atomic-internal-codegen
Expand Down Expand Up @@ -277,41 +284,39 @@ build() {
if [[ "${rustc_minor_version}" -lt 54 ]]; then
args+=(--exclude-features "critical-section")
fi
case "${target}" in
*-none* | *-uefi* | *-cuda* | avr-* | *-esp-espidf)
args+=(--exclude-features "std")
if [[ -z "${has_atomic_cas}" ]]; then
if [[ -n "${has_asm}" ]]; then
case "${target}" in
avr-* | msp430-*) ;; # always single-core
bpf*) args+=(--exclude portable-atomic-util) ;; # TODO, Arc can't be used here yet
*)
CARGO_TARGET_DIR="${target_dir}/assume-single-core" \
RUSTFLAGS="${target_rustflags} --cfg portable_atomic_unsafe_assume_single_core" \
x_cargo "${args[@]}" --exclude-features "critical-section" "$@"
case "${target}" in
thumbv[4-5]t* | armv[4-5]t*)
CARGO_TARGET_DIR="${target_dir}/assume-single-core-disable-fiq" \
RUSTFLAGS="${target_rustflags} --cfg portable_atomic_unsafe_assume_single_core --cfg portable_atomic_disable_fiq" \
x_cargo "${args[@]}" --exclude-features "critical-section" "$@"
;;
riscv*)
CARGO_TARGET_DIR="${target_dir}/assume-single-core-s-mode" \
RUSTFLAGS="${target_rustflags} --cfg portable_atomic_unsafe_assume_single_core --cfg portable_atomic_s_mode" \
x_cargo "${args[@]}" --exclude-features "critical-section" "$@"
;;
esac
;;
esac
else
echo "target '${target}' requires asm to implement atomic CAS (skipped build with --cfg portable_atomic_unsafe_assume_single_core)"
fi
# portable-atomic-util uses atomic CAS, so doesn't work on
# this target without portable_atomic_unsafe_assume_single_core cfg.
args+=(--exclude portable-atomic-util)
if is_no_std "${target}"; then
args+=(--exclude-features "std")
if [[ -z "${has_atomic_cas}" ]]; then
if [[ -n "${has_asm}" ]]; then
case "${target}" in
avr-* | msp430-*) ;; # always single-core
bpf*) args+=(--exclude portable-atomic-util) ;; # TODO, Arc can't be used here yet
*)
CARGO_TARGET_DIR="${target_dir}/assume-single-core" \
RUSTFLAGS="${target_rustflags} --cfg portable_atomic_unsafe_assume_single_core" \
x_cargo "${args[@]}" --exclude-features "critical-section" "$@"
case "${target}" in
thumbv[4-5]t* | armv[4-5]t*)
CARGO_TARGET_DIR="${target_dir}/assume-single-core-disable-fiq" \
RUSTFLAGS="${target_rustflags} --cfg portable_atomic_unsafe_assume_single_core --cfg portable_atomic_disable_fiq" \
x_cargo "${args[@]}" --exclude-features "critical-section" "$@"
;;
riscv*)
CARGO_TARGET_DIR="${target_dir}/assume-single-core-s-mode" \
RUSTFLAGS="${target_rustflags} --cfg portable_atomic_unsafe_assume_single_core --cfg portable_atomic_s_mode" \
x_cargo "${args[@]}" --exclude-features "critical-section" "$@"
;;
esac
;;
esac
else
echo "target '${target}' requires asm to implement atomic CAS (skipped build with --cfg portable_atomic_unsafe_assume_single_core)"
fi
;;
esac
# portable-atomic-util uses atomic CAS, so doesn't work on
# this target without portable_atomic_unsafe_assume_single_core cfg.
args+=(--exclude portable-atomic-util)
fi
fi
fi
RUSTFLAGS="${target_rustflags}" \
x_cargo "${args[@]}" "$@"
Expand Down

0 comments on commit 8e4de84

Please sign in to comment.