Skip to content

Commit 0a3bd80

Browse files
gburgessivjoshtriplett
authored andcommitted
add support for building outlined aarch64 intrinsics
llvm/llvm-project@a4ac434 saw the addition of out-of-line aarch64 atomic intrinsics. LLVM will sometimes emit these, so we need to ensure they're included in Rust's compiler-rt.
1 parent 4af6bc7 commit 0a3bd80

File tree

1 file changed

+70
-1
lines changed

1 file changed

+70
-1
lines changed

build.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ mod c {
8181

8282
use std::collections::BTreeMap;
8383
use std::env;
84-
use std::path::PathBuf;
84+
use std::path::{Path, PathBuf};
8585

8686
struct Sources {
8787
// SYMBOL -> PATH TO SOURCE
@@ -489,7 +489,20 @@ mod c {
489489
// use of that macro in lib/builtins/int_util.h in compiler-rt.
490490
cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display()));
491491

492+
// Include out-of-line atomics for aarch64, which are all generated by supplying different
493+
// sets of flags to the same source file.
492494
let src_dir = root.join("lib/builtins");
495+
if target_arch == "aarch64" {
496+
let atomics_libs = build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg);
497+
if !atomics_libs.is_empty() {
498+
for library in atomics_libs {
499+
cfg.object(library);
500+
}
501+
// Some run-time CPU feature detection is necessary, as well.
502+
sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]);
503+
}
504+
}
505+
493506
for (sym, src) in sources.map.iter() {
494507
let src = src_dir.join(src);
495508
cfg.file(&src);
@@ -499,4 +512,60 @@ mod c {
499512

500513
cfg.compile("libcompiler-rt.a");
501514
}
515+
516+
fn build_aarch64_out_of_line_atomics_libraries(
517+
builtins_dir: &Path,
518+
cfg: &cc::Build,
519+
) -> Vec<PathBuf> {
520+
// NOTE: because we're recompiling the same source file in N different ways, building
521+
// serially is necessary. If we want to lift this restriction, we can either:
522+
// - create symlinks to lse.S and build those_(though we'd still need to pass special
523+
// #define-like flags to each of these), or
524+
// - synthesizing tiny .S files in out/ with the proper #defines, which ultimately #include
525+
// lse.S.
526+
// That said, it's unclear how useful this added complexity will be, so just do the simple
527+
// thing for now.
528+
let outlined_atomics_file = builtins_dir.join("aarch64/lse.S");
529+
530+
// A stable release hasn't been made with lse.S yet. Until we pick that up, do nothing.
531+
if !outlined_atomics_file.exists() {
532+
return vec![];
533+
}
534+
535+
println!("cargo:rerun-if-changed={}", outlined_atomics_file.display());
536+
let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into();
537+
538+
// Ideally, this would be a Vec of object files, but cc doesn't make it *entirely*
539+
// trivial to build an individual object.
540+
let mut atomics_libraries = Vec::new();
541+
for instruction_type in &["cas", "cwp", "ldadd", "ldclr", "ldeor", "ldset"] {
542+
for size in &[1, 2, 4, 8, 16] {
543+
if *size == 16 && *instruction_type != "cas" {
544+
continue;
545+
}
546+
547+
for (model_number, model_name) in
548+
&[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")]
549+
{
550+
let library_name = format!(
551+
"liboutline_atomic_helper_{}_{}_{}.a",
552+
instruction_type, size, model_name
553+
);
554+
let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name);
555+
let mut cfg = cfg.clone();
556+
557+
cfg.include(&builtins_dir)
558+
.define(&format!("L_{}", instruction_type), None)
559+
.define("SIZE", size.to_string().as_str())
560+
.define("MODEL", model_number.to_string().as_str())
561+
.file(&outlined_atomics_file);
562+
cfg.compile(&library_name);
563+
564+
atomics_libraries.push(out_dir.join(library_name));
565+
println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
566+
}
567+
}
568+
}
569+
atomics_libraries
570+
}
502571
}

0 commit comments

Comments
 (0)