|
@@ -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,55 @@ mod c {
|
|
|
|
|
|
cfg.compile("libcompiler-rt.a");
|
|
|
}
|
|
|
+
|
|
|
+ fn build_aarch64_out_of_line_atomics_libraries(
|
|
|
+ builtins_dir: &Path,
|
|
|
+ cfg: &cc::Build,
|
|
|
+ ) -> Vec<PathBuf> {
|
|
|
+ // 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");
|
|
|
+ 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", "swp", "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
|
|
|
+ }
|
|
|
}
|