From 5edaec6c970c92f5613021032790ea65037014ca Mon Sep 17 00:00:00 2001 From: George Burgess IV Date: Tue, 2 Mar 2021 15:50:09 -0800 Subject: [PATCH] add support for building outlined aarch64 intrinsics llvm/llvm-project@a4ac434c47434d80bca54bab96f295ed4e972cc6 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. --- library/compiler-builtins/build.rs | 71 +++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 701c4d4950b0..2ff6443d7dea 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -81,7 +81,7 @@ mod c { use std::collections::BTreeMap; use std::env; - use std::path::PathBuf; + use std::path::{Path, PathBuf}; struct Sources { // SYMBOL -> PATH TO SOURCE @@ -489,7 +489,20 @@ mod c { // use of that macro in lib/builtins/int_util.h in compiler-rt. cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); + // Include out-of-line atomics for aarch64, which are all generated by supplying different + // sets of flags to the same source file. let src_dir = root.join("lib/builtins"); + if target_arch == "aarch64" { + let atomics_libs = build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); + if !atomics_libs.is_empty() { + for library in atomics_libs { + cfg.object(library); + } + // Some run-time CPU feature detection is necessary, as well. + sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); + } + } + for (sym, src) in sources.map.iter() { let src = src_dir.join(src); cfg.file(&src); @@ -499,4 +512,60 @@ mod c { cfg.compile("libcompiler-rt.a"); } + + fn build_aarch64_out_of_line_atomics_libraries( + builtins_dir: &Path, + cfg: &cc::Build, + ) -> Vec { + // NOTE: because we're recompiling the same source file in N different ways, building + // serially is necessary. If we want to lift this restriction, we can either: + // - create symlinks to lse.S and build those_(though we'd still need to pass special + // #define-like flags to each of these), or + // - synthesizing tiny .S files in out/ with the proper #defines, which ultimately #include + // lse.S. + // That said, it's unclear how useful this added complexity will be, so just do the simple + // thing for now. + let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); + + // A stable release hasn't been made with lse.S yet. Until we pick that up, do nothing. + if !outlined_atomics_file.exists() { + return vec![]; + } + + println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); + + // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* + // trivial to build an individual object. + let mut atomics_libraries = Vec::new(); + for instruction_type in &["cas", "cwp", "ldadd", "ldclr", "ldeor", "ldset"] { + for size in &[1, 2, 4, 8, 16] { + if *size == 16 && *instruction_type != "cas" { + continue; + } + + for (model_number, model_name) in + &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] + { + let library_name = format!( + "liboutline_atomic_helper_{}_{}_{}.a", + instruction_type, size, model_name + ); + let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); + let mut cfg = cfg.clone(); + + cfg.include(&builtins_dir) + .define(&format!("L_{}", instruction_type), None) + .define("SIZE", size.to_string().as_str()) + .define("MODEL", model_number.to_string().as_str()) + .file(&outlined_atomics_file); + cfg.compile(&library_name); + + atomics_libraries.push(out_dir.join(library_name)); + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); + } + } + } + atomics_libraries + } }