Eliminate build.rs-generated Aarch64 atomic macros (#951)

Replace `build.rs` Rust generation with macros, using the unstable
`${concat(...)}`.

Fixes: https://github.com/rust-lang/compiler-builtins/issues/947
This commit is contained in:
qinghon 2025-06-13 13:27:47 +08:00 committed by GitHub
parent b5fafd9816
commit 013e06c5ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 75 additions and 65 deletions

View file

@ -1,4 +1,5 @@
#![feature(decl_macro)] // so we can use pub(super)
#![feature(macro_metavar_expr_concat)]
#![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))]
/// Translate a byte size to a Rust type.
@ -87,7 +88,7 @@ test_op!(add, |left, right| left.wrapping_add(right));
test_op!(clr, |left, right| left & !right);
test_op!(xor, std::ops::BitXor::bitxor);
test_op!(or, std::ops::BitOr::bitor);
use compiler_builtins::{foreach_bytes, foreach_ordering};
compiler_builtins::foreach_cas!(cas::test);
compiler_builtins::foreach_cas16!(test_cas16);
compiler_builtins::foreach_swp!(swap::test);

View file

@ -1,9 +1,6 @@
mod configure;
use std::collections::BTreeMap;
use std::env;
use std::path::PathBuf;
use std::sync::atomic::Ordering;
use configure::{Target, configure_aliases, configure_f16_f128};
@ -85,10 +82,6 @@ fn main() {
{
println!("cargo:rustc-cfg=kernel_user_helpers")
}
if llvm_target[0].starts_with("aarch64") {
generate_aarch64_outlined_atomics();
}
}
/// Run configuration for `libm` since it is included directly.
@ -131,61 +124,6 @@ fn configure_libm(target: &Target) {
println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\"");
}
fn aarch64_symbol(ordering: Ordering) -> &'static str {
match ordering {
Ordering::Relaxed => "relax",
Ordering::Acquire => "acq",
Ordering::Release => "rel",
Ordering::AcqRel => "acq_rel",
_ => panic!("unknown symbol for {ordering:?}"),
}
}
/// The `concat_idents` macro is extremely annoying and doesn't allow us to define new items.
/// Define them from the build script instead.
/// Note that the majority of the code is still defined in `aarch64.rs` through inline macros.
fn generate_aarch64_outlined_atomics() {
use std::fmt::Write;
// #[macro_export] so that we can use this in tests
let gen_macro =
|name| format!("#[macro_export] macro_rules! foreach_{name} {{ ($macro:path) => {{\n");
// Generate different macros for add/clr/eor/set so that we can test them separately.
let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"];
let mut macros = BTreeMap::new();
for sym in sym_names {
macros.insert(sym, gen_macro(sym));
}
// Only CAS supports 16 bytes, and it has a different implementation that uses a different macro.
let mut cas16 = gen_macro("cas16");
for ordering in [
Ordering::Relaxed,
Ordering::Acquire,
Ordering::Release,
Ordering::AcqRel,
] {
let sym_ordering = aarch64_symbol(ordering);
for size in [1, 2, 4, 8] {
for (sym, macro_) in &mut macros {
let name = format!("__aarch64_{sym}{size}_{sym_ordering}");
writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap();
}
}
let name = format!("__aarch64_cas16_{sym_ordering}");
writeln!(cas16, "$macro!( {ordering:?}, {name} );").unwrap();
}
let mut buf = String::new();
for macro_def in macros.values().chain(std::iter::once(&cas16)) {
buf += macro_def;
buf += "}; }\n";
}
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
std::fs::write(out_dir.join("outlined_atomics.rs"), buf).unwrap();
}
/// Emit directives for features we expect to support that aren't in `Cargo.toml`.
///
/// These are mostly cfg elements emitted by this `build.rs`.

View file

@ -262,8 +262,78 @@ macro_rules! or {
};
}
// See `generate_aarch64_outlined_atomics` in build.rs.
include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs"));
#[macro_export]
macro_rules! foreach_ordering {
($macro:path, $bytes:tt, $name:ident) => {
$macro!( Relaxed, $bytes, ${concat($name, _relax)} );
$macro!( Acquire, $bytes, ${concat($name, _acq)} );
$macro!( Release, $bytes, ${concat($name, _rel)} );
$macro!( AcqRel, $bytes, ${concat($name, _acq_rel)} );
};
($macro:path, $name:ident) => {
$macro!( Relaxed, ${concat($name, _relax)} );
$macro!( Acquire, ${concat($name, _acq)} );
$macro!( Release, ${concat($name, _rel)} );
$macro!( AcqRel, ${concat($name, _acq_rel)} );
};
}
#[macro_export]
macro_rules! foreach_bytes {
($macro:path, $name:ident) => {
foreach_ordering!( $macro, 1, ${concat(__aarch64_, $name, "1")} );
foreach_ordering!( $macro, 2, ${concat(__aarch64_, $name, "2")} );
foreach_ordering!( $macro, 4, ${concat(__aarch64_, $name, "4")} );
foreach_ordering!( $macro, 8, ${concat(__aarch64_, $name, "8")} );
};
}
/// Generate different macros for cas/swp/add/clr/eor/set so that we can test them separately.
#[macro_export]
macro_rules! foreach_cas {
($macro:path) => {
foreach_bytes!($macro, cas);
};
}
/// Only CAS supports 16 bytes, and it has a different implementation that uses a different macro.
#[macro_export]
macro_rules! foreach_cas16 {
($macro:path) => {
foreach_ordering!($macro, __aarch64_cas16);
};
}
#[macro_export]
macro_rules! foreach_swp {
($macro:path) => {
foreach_bytes!($macro, swp);
};
}
#[macro_export]
macro_rules! foreach_ldadd {
($macro:path) => {
foreach_bytes!($macro, ldadd);
};
}
#[macro_export]
macro_rules! foreach_ldclr {
($macro:path) => {
foreach_bytes!($macro, ldclr);
};
}
#[macro_export]
macro_rules! foreach_ldeor {
($macro:path) => {
foreach_bytes!($macro, ldeor);
};
}
#[macro_export]
macro_rules! foreach_ldset {
($macro:path) => {
foreach_bytes!($macro, ldset);
};
}
foreach_cas!(compare_and_swap);
foreach_cas16!(compare_and_swap_i128);
foreach_swp!(swap);

View file

@ -8,6 +8,7 @@
#![feature(linkage)]
#![feature(naked_functions)]
#![feature(repr_simd)]
#![feature(macro_metavar_expr_concat)]
#![cfg_attr(f16_enabled, feature(f16))]
#![cfg_attr(f128_enabled, feature(f128))]
#![no_builtins]