Skip to content

Commit 8ef05df

Browse files
committed
aarch64: Support FEAT_LSFE
1 parent 582a915 commit 8ef05df

File tree

10 files changed

+396
-18
lines changed

10 files changed

+396
-18
lines changed

.github/.cspell/project-dictionary.txt

+4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ lcgr
7272
ldar
7373
ldaxp
7474
ldclrp
75+
ldfadd
76+
ldfmax
77+
ldfmin
7578
ldiapp
7679
ldrexd
7780
ldsetp
@@ -188,6 +191,7 @@ versatilepb
188191
virt
189192
vmlinux
190193
vmovdqa
194+
vreg
191195
vtable
192196
vtables
193197
wokwi

build.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,18 @@ fn main() {
4747

4848
if version.minor >= 80 {
4949
println!(
50-
r#"cargo:rustc-check-cfg=cfg(target_feature,values("experimental-zacas","fast-serialization","load-store-on-cond","distinct-ops","miscellaneous-extensions-3"))"#
50+
r#"cargo:rustc-check-cfg=cfg(target_feature,values("lsfe","experimental-zacas","fast-serialization","load-store-on-cond","distinct-ops","miscellaneous-extensions-3"))"#
5151
);
5252

5353
// Custom cfgs set by build script. Not public API.
5454
// grep -F 'cargo:rustc-cfg=' build.rs | grep -Ev '^ *//' | sed -E 's/^.*cargo:rustc-cfg=//; s/(=\\)?".*$//' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
5555
println!(
56-
"cargo:rustc-check-cfg=cfg(portable_atomic_disable_fiq,portable_atomic_force_amo,portable_atomic_ll_sc_rmw,portable_atomic_new_atomic_intrinsics,portable_atomic_no_asm,portable_atomic_no_asm_maybe_uninit,portable_atomic_no_atomic_64,portable_atomic_no_atomic_cas,portable_atomic_no_atomic_load_store,portable_atomic_no_atomic_min_max,portable_atomic_no_cfg_target_has_atomic,portable_atomic_no_cmpxchg16b_intrinsic,portable_atomic_no_cmpxchg16b_target_feature,portable_atomic_no_const_mut_refs,portable_atomic_no_const_raw_ptr_deref,portable_atomic_no_const_transmute,portable_atomic_no_core_unwind_safe,portable_atomic_no_diagnostic_namespace,portable_atomic_no_offset_of,portable_atomic_no_strict_provenance,portable_atomic_no_stronger_failure_ordering,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_pre_llvm_15,portable_atomic_pre_llvm_16,portable_atomic_pre_llvm_18,portable_atomic_s_mode,portable_atomic_sanitize_thread,portable_atomic_target_feature,portable_atomic_unsafe_assume_single_core,portable_atomic_unstable_asm,portable_atomic_unstable_asm_experimental_arch,portable_atomic_unstable_cfg_target_has_atomic,portable_atomic_unstable_isa_attribute)"
56+
"cargo:rustc-check-cfg=cfg(portable_atomic_disable_fiq,portable_atomic_force_amo,portable_atomic_ll_sc_rmw,portable_atomic_new_atomic_intrinsics,portable_atomic_no_asm,portable_atomic_no_asm_maybe_uninit,portable_atomic_no_atomic_64,portable_atomic_no_atomic_cas,portable_atomic_no_atomic_load_store,portable_atomic_no_atomic_min_max,portable_atomic_no_cfg_target_has_atomic,portable_atomic_no_cmpxchg16b_intrinsic,portable_atomic_no_cmpxchg16b_target_feature,portable_atomic_no_const_mut_refs,portable_atomic_no_const_raw_ptr_deref,portable_atomic_no_const_transmute,portable_atomic_no_core_unwind_safe,portable_atomic_no_diagnostic_namespace,portable_atomic_no_offset_of,portable_atomic_no_strict_provenance,portable_atomic_no_stronger_failure_ordering,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_pre_llvm_15,portable_atomic_pre_llvm_16,portable_atomic_pre_llvm_18,portable_atomic_pre_llvm_20,portable_atomic_s_mode,portable_atomic_sanitize_thread,portable_atomic_target_feature,portable_atomic_unsafe_assume_single_core,portable_atomic_unstable_asm,portable_atomic_unstable_asm_experimental_arch,portable_atomic_unstable_cfg_target_has_atomic,portable_atomic_unstable_isa_attribute)"
5757
);
5858
// TODO: handle multi-line target_feature_fallback
5959
// grep -F 'target_feature_fallback("' build.rs | grep -Ev '^ *//' | sed -E 's/^.*target_feature_fallback\(//; s/",.*$/"/' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
6060
println!(
61-
r#"cargo:rustc-check-cfg=cfg(portable_atomic_target_feature,values("cmpxchg16b","distinct-ops","experimental-zacas","fast-serialization","load-store-on-cond","lse","lse128","lse2","mclass","miscellaneous-extensions-3","quadword-atomics","rcpc3","v6","zaamo","zabha"))"#
61+
r#"cargo:rustc-check-cfg=cfg(portable_atomic_target_feature,values("cmpxchg16b","distinct-ops","experimental-zacas","fast-serialization","load-store-on-cond","lse","lse128","lse2","lsfe","mclass","miscellaneous-extensions-3","quadword-atomics","rcpc3","v6","zaamo","zabha"))"#
6262
);
6363
}
6464

@@ -206,12 +206,15 @@ fn main() {
206206
println!("cargo:rustc-cfg=portable_atomic_no_atomic_load_store");
207207
}
208208

209-
if version.llvm < 18 {
210-
println!("cargo:rustc-cfg=portable_atomic_pre_llvm_18");
211-
if version.llvm < 16 {
212-
println!("cargo:rustc-cfg=portable_atomic_pre_llvm_16");
213-
if version.llvm < 15 {
214-
println!("cargo:rustc-cfg=portable_atomic_pre_llvm_15");
209+
if version.llvm < 20 {
210+
println!("cargo:rustc-cfg=portable_atomic_pre_llvm_20");
211+
if version.llvm < 18 {
212+
println!("cargo:rustc-cfg=portable_atomic_pre_llvm_18");
213+
if version.llvm < 16 {
214+
println!("cargo:rustc-cfg=portable_atomic_pre_llvm_16");
215+
if version.llvm < 15 {
216+
println!("cargo:rustc-cfg=portable_atomic_pre_llvm_15");
217+
}
215218
}
216219
}
217220
}
@@ -282,6 +285,9 @@ fn main() {
282285
target_feature_fallback("lse", lse);
283286
}
284287
}
288+
// As of rustc 1.84, target_feature "lsfe" is not available on rustc side:
289+
// https://github.com/rust-lang/rust/blob/1.84.0/compiler/rustc_target/src/target_features.rs
290+
target_feature_fallback("lsfe", false);
285291

286292
// As of Apple M1/M1 Pro, on Apple hardware, CAS-loop-based RMW is much slower than
287293
// LL/SC-loop-based RMW: https://github.com/taiki-e/portable-atomic/pull/89

src/imp/atomic128/aarch64.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,10 @@ macro_rules! atomic_rmw_inst {
435435
};
436436
($op:ident, $order:ident, write = $write:ident) => {
437437
match $order {
438-
Ordering::Relaxed => $op!("2", ""),
439-
Ordering::Acquire => $op!("a", ""),
440-
Ordering::Release => $op!("6", ""),
441-
Ordering::AcqRel => $op!("e", ""),
438+
Ordering::Relaxed => $op!("2", ""), // ""
439+
Ordering::Acquire => $op!("a", ""), // "a"
440+
Ordering::Release => $op!("6", ""), // "l"
441+
Ordering::AcqRel => $op!("e", ""), // "al"
442442
// In MSVC environments, SeqCst stores/writes needs fences after writes.
443443
// https://reviews.llvm.org/D141748
444444
#[cfg(target_env = "msvc")]

src/imp/detect/aarch64_aa64reg.rs

+48-4
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,20 @@ include!("common.rs");
4444
struct AA64Reg {
4545
aa64isar0: u64,
4646
aa64isar1: u64,
47+
#[cfg(test)]
48+
aa64isar3: u64,
4749
aa64mmfr2: u64,
4850
}
4951

5052
#[cold]
5153
fn _detect(info: &mut CpuInfo) {
52-
let AA64Reg { aa64isar0, aa64isar1, aa64mmfr2 } = imp::aa64reg();
54+
let AA64Reg {
55+
aa64isar0,
56+
aa64isar1,
57+
#[cfg(test)]
58+
aa64isar3,
59+
aa64mmfr2,
60+
} = imp::aa64reg();
5361

5462
// ID_AA64ISAR0_EL1, AArch64 Instruction Set Attribute Register 0
5563
// https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Registers/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0
@@ -65,6 +73,12 @@ fn _detect(info: &mut CpuInfo) {
6573
if extract(aa64isar1, 23, 20) >= 0b0011 {
6674
info.set(CpuInfo::HAS_RCPC3);
6775
}
76+
#[cfg(test)]
77+
// ID_AA64ISAR3_EL1, AArch64 Instruction Set Attribute Register 3
78+
// https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Registers/ID-AA64ISAR3-EL1--AArch64-Instruction-Set-Attribute-Register-3
79+
if extract(aa64isar3, 19, 16) >= 0b0001 {
80+
info.set(CpuInfo::HAS_LSFE);
81+
}
6882
// ID_AA64MMFR2_EL1, AArch64 Memory Model Feature Register 2
6983
// https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Registers/ID-AA64MMFR2-EL1--AArch64-Memory-Model-Feature-Register-2
7084
if extract(aa64mmfr2, 35, 32) >= 0b0001 {
@@ -102,13 +116,27 @@ mod imp {
102116
out(reg) aa64isar1,
103117
options(pure, nomem, nostack, preserves_flags),
104118
);
119+
#[cfg(test)]
120+
let aa64isar3: u64;
121+
#[cfg(test)]
122+
asm!(
123+
"mrs {0}, ID_AA64ISAR3_EL1",
124+
out(reg) aa64isar3,
125+
options(pure, nomem, nostack, preserves_flags),
126+
);
105127
let aa64mmfr2: u64;
106128
asm!(
107129
"mrs {0}, ID_AA64MMFR2_EL1",
108130
out(reg) aa64mmfr2,
109131
options(pure, nomem, nostack, preserves_flags),
110132
);
111-
AA64Reg { aa64isar0, aa64isar1, aa64mmfr2 }
133+
AA64Reg {
134+
aa64isar0,
135+
aa64isar1,
136+
#[cfg(test)]
137+
aa64isar3,
138+
aa64mmfr2,
139+
}
112140
}
113141
}
114142
}
@@ -200,6 +228,8 @@ mod imp {
200228
Some(AA64Reg {
201229
aa64isar0: buf.ac_aa64isar0,
202230
aa64isar1: buf.ac_aa64isar1,
231+
#[cfg(test)]
232+
aa64isar3: 0,
203233
aa64mmfr2: buf.ac_aa64mmfr2,
204234
})
205235
}
@@ -273,7 +303,13 @@ mod imp {
273303
let aa64isar0 = sysctl64(&[ffi::CTL_MACHDEP, ffi::CPU_ID_AA64ISAR0]).unwrap_or(0);
274304
let aa64isar1 = sysctl64(&[ffi::CTL_MACHDEP, ffi::CPU_ID_AA64ISAR1]).unwrap_or(0);
275305
let aa64mmfr2 = sysctl64(&[ffi::CTL_MACHDEP, ffi::CPU_ID_AA64MMFR2]).unwrap_or(0);
276-
AA64Reg { aa64isar0, aa64isar1, aa64mmfr2 }
306+
AA64Reg {
307+
aa64isar0,
308+
aa64isar1,
309+
#[cfg(test)]
310+
aa64isar3: 0,
311+
aa64mmfr2,
312+
}
277313
}
278314

279315
fn sysctl64(mib: &[ffi::c_int]) -> Option<u64> {
@@ -322,9 +358,10 @@ mod tests {
322358

323359
#[test]
324360
fn test_aa64reg() {
325-
let AA64Reg { aa64isar0, aa64isar1, aa64mmfr2 } = imp::aa64reg();
361+
let AA64Reg { aa64isar0, aa64isar1, aa64isar3, aa64mmfr2 } = imp::aa64reg();
326362
std::eprintln!("aa64isar0={}", aa64isar0);
327363
std::eprintln!("aa64isar1={}", aa64isar1);
364+
std::eprintln!("aa64isar3={}", aa64isar3);
328365
std::eprintln!("aa64mmfr2={}", aa64mmfr2);
329366
if cfg!(target_os = "openbsd") {
330367
let output = Command::new("sysctl").arg("machdep").output().unwrap();
@@ -361,6 +398,12 @@ mod tests {
361398
} else {
362399
assert!(lrcpc < 0b0011, "{}", lrcpc);
363400
}
401+
let lsfe = extract(aa64isar3, 19, 16);
402+
if detect().test(CpuInfo::HAS_LSFE) {
403+
assert_eq!(lsfe, 0b0001);
404+
} else {
405+
assert_eq!(lsfe, 0b0000);
406+
}
364407
let at = extract(aa64mmfr2, 35, 32);
365408
if detect().test(CpuInfo::HAS_LSE2) {
366409
assert_eq!(at, 0b0001);
@@ -496,6 +539,7 @@ mod tests {
496539
Ok(AA64Reg {
497540
aa64isar0: buf.ac_aa64isar0,
498541
aa64isar1: buf.ac_aa64isar1,
542+
aa64isar3: 0,
499543
aa64mmfr2: buf.ac_aa64mmfr2,
500544
})
501545
}

src/imp/detect/aarch64_apple.rs

+7
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ fn _detect(info: &mut CpuInfo) {
8585
if sysctlbyname32(c!("hw.optional.arm.FEAT_LSE128")).unwrap_or(0) != 0 {
8686
info.set(CpuInfo::HAS_LSE128);
8787
}
88+
#[cfg(test)]
89+
if sysctlbyname32(c!("hw.optional.arm.FEAT_LSFE")).unwrap_or(0) != 0 {
90+
info.set(CpuInfo::HAS_LSFE);
91+
}
8892
if sysctlbyname32(c!("hw.optional.arm.FEAT_LRCPC3")).unwrap_or(0) != 0 {
8993
info.set(CpuInfo::HAS_RCPC3);
9094
}
@@ -108,6 +112,8 @@ mod tests {
108112
assert_eq!(sysctlbyname32(c!("hw.optional.arm.FEAT_LSE2")), Some(1));
109113
assert_eq!(sysctlbyname32(c!("hw.optional.arm.FEAT_LSE128")), None);
110114
assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::NotFound);
115+
assert_eq!(sysctlbyname32(c!("hw.optional.arm.FEAT_LSFE")), None);
116+
assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::NotFound);
111117
assert_eq!(sysctlbyname32(c!("hw.optional.arm.FEAT_LRCPC")), Some(1));
112118
assert_eq!(sysctlbyname32(c!("hw.optional.arm.FEAT_LRCPC2")), Some(1));
113119
assert_eq!(sysctlbyname32(c!("hw.optional.arm.FEAT_LRCPC3")), None);
@@ -234,6 +240,7 @@ mod tests {
234240
c!("hw.optional.arm.FEAT_LSE"),
235241
c!("hw.optional.arm.FEAT_LSE2"),
236242
c!("hw.optional.arm.FEAT_LSE128"),
243+
c!("hw.optional.arm.FEAT_LSFE"),
237244
c!("hw.optional.arm.FEAT_LRCPC"),
238245
c!("hw.optional.arm.FEAT_LRCPC2"),
239246
c!("hw.optional.arm.FEAT_LRCPC3"),

src/imp/detect/common.rs

+12
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ flags! {
104104
// > If FEAT_LSE128 is implemented, then FEAT_LSE is implemented.
105105
#[cfg_attr(not(test), allow(dead_code))]
106106
HAS_LSE128(has_lse128, "lse128", any(target_feature, portable_atomic_target_feature)),
107+
// FEAT_LSFE, Large System Float Extension
108+
// https://developer.arm.com/documentation/109697/2024_12/Feature-descriptions/The-Armv9-6-architecture-extension
109+
// > This feature is supported in AArch64 state only.
110+
// > FEAT_LSFE is OPTIONAL from Armv9.3.
111+
// > If FEAT_LSFE is implemented, then FEAT_FP is implemented.
112+
#[cfg(test)]
113+
HAS_LSFE(has_lsfe, "lsfe", any(target_feature, portable_atomic_target_feature)),
107114
}
108115

109116
#[cfg(target_arch = "powerpc64")]
@@ -398,6 +405,11 @@ mod tests_common {
398405
assert!(!lse128);
399406
}
400407
}
408+
if detect().has_lsfe() {
409+
assert!(detect().test(CpuInfo::HAS_LSFE));
410+
} else {
411+
assert!(!detect().test(CpuInfo::HAS_LSFE));
412+
}
401413
if detect().has_rcpc3() {
402414
assert!(detect().test(CpuInfo::HAS_RCPC3));
403415
if let Ok(test_helper::cpuinfo::ProcCpuinfo { rcpc3: Some(rcpc3), .. }) = proc_cpuinfo {

0 commit comments

Comments
 (0)