Skip to content

Allow linking a prebuilt optimized compiler-rt builtins library #143689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion bootstrap.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,9 @@
# sources are available.
#
# Setting this to `false` generates slower code, but removes the requirement for a C toolchain in
# order to run `x check`.
# order to run `x check`. This may also be given a path to an existing build of the builtins
# runtime library from LLVM's compiler-rt. This option will override the same option under [build]
# section.
#optimized-compiler-builtins = build.optimized-compiler-builtins (bool)

# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator.
Expand Down
53 changes: 44 additions & 9 deletions library/compiler-builtins/compiler-builtins/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,20 +548,28 @@ mod c {
sources.extend(&[("__emutls_get_address", "emutls.c")]);
}

// Optionally, link against a prebuilt compiler-rt library to supply
// optimized intrinsics instead of compiling a subset of compiler-rt
// from source.
let link_against_prebuilt_rt = env::var_os("LLVM_BUILTIN_RT_LIB").is_some();

// When compiling the C code we require the user to tell us where the
// source code is, and this is largely done so when we're compiling as
// part of rust-lang/rust we can use the same llvm-project repository as
// rust-lang/rust.
let root = match env::var_os("RUST_COMPILER_RT_ROOT") {
Some(s) => PathBuf::from(s),
// If a prebuild libcompiler-rt is provided, set a valid
// path to simplify later logic. Nothing should be compiled.
None if link_against_prebuilt_rt => PathBuf::new(),
None => {
panic!(
"RUST_COMPILER_RT_ROOT is not set. You may need to run \
`ci/download-compiler-rt.sh`."
);
}
};
if !root.exists() {
if !link_against_prebuilt_rt && !root.exists() {
panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display());
}

Expand All @@ -577,7 +585,7 @@ mod c {
let src_dir = root.join("lib/builtins");
if target.arch == "aarch64" && target.env != "msvc" && target.os != "uefi" {
// See below for why we're building these as separate libraries.
build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg);
build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg, link_against_prebuilt_rt);

// Some run-time CPU feature detection is necessary, as well.
let cpu_model_src = if src_dir.join("cpu_model.c").exists() {
Expand All @@ -591,20 +599,43 @@ mod c {
let mut added_sources = HashSet::new();
for (sym, src) in sources.map.iter() {
let src = src_dir.join(src);
if added_sources.insert(src.clone()) {
if !link_against_prebuilt_rt && added_sources.insert(src.clone()) {
cfg.file(&src);
println!("cargo:rerun-if-changed={}", src.display());
}
println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
}

cfg.compile("libcompiler-rt.a");
if link_against_prebuilt_rt {
let rt_builtins_ext = PathBuf::from(env::var_os("LLVM_BUILTIN_RT_LIB").unwrap());
if !rt_builtins_ext.exists() {
panic!(
"LLVM_BUILTIN_RT_LIB={} does not exist",
rt_builtins_ext.display()
);
}
if let Some(dir) = rt_builtins_ext.parent() {
println!("cargo::rustc-link-search=native={}", dir.display());
}
println!(
"cargo::rustc-link-lib=static:+verbatim={}",
rt_builtins_ext.to_str().unwrap()
);
} else {
cfg.compile("libcompiler-rt.a");
}
}

fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) {
fn build_aarch64_out_of_line_atomics_libraries(
builtins_dir: &Path,
cfg: &mut cc::Build,
link_against_prebuilt_rt: bool,
) {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let outlined_atomics_file = builtins_dir.join("aarch64").join("lse.S");
println!("cargo:rerun-if-changed={}", outlined_atomics_file.display());
if !link_against_prebuilt_rt {
println!("cargo:rerun-if-changed={}", outlined_atomics_file.display());
}

cfg.include(&builtins_dir);

Expand All @@ -617,6 +648,13 @@ mod c {
for (model_number, model_name) in
&[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")]
{
let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name);
println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);

if link_against_prebuilt_rt {
continue;
}

// The original compiler-rt build system compiles the same
// source file multiple times with different compiler
// options. Here we do something slightly different: we
Expand All @@ -640,9 +678,6 @@ mod c {
.unwrap();
drop(file);
cfg.file(path);

let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name);
println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
}
}
}
Expand Down
42 changes: 23 additions & 19 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,25 +567,29 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
// `compiler-builtins` crate is enabled and it's configured to learn where
// `compiler-rt` is located.
let compiler_builtins_c_feature = if builder.config.optimized_compiler_builtins(target) {
// NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce `submodules = false`, so this is a no-op.
// But, the user could still decide to manually use an in-tree submodule.
//
// NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt` that doesn't match the LLVM we're linking to.
// That's probably ok? At least, the difference wasn't enforced before. There's a comment in
// the compiler_builtins build script that makes me nervous, though:
// https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579
builder.require_submodule(
"src/llvm-project",
Some(
"The `build.optimized-compiler-builtins` config option \
requires `compiler-rt` sources from LLVM.",
),
);
let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
assert!(compiler_builtins_root.exists());
// The path to `compiler-rt` is also used by `profiler_builtins` (above),
// so if you're changing something here please also change that as appropriate.
cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
if let Some(path) = builder.config.optimized_compiler_builtins_path(target) {
cargo.env("LLVM_BUILTIN_RT_LIB", path);
} else {
// NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce `submodules = false`, so this is a no-op.
// But, the user could still decide to manually use an in-tree submodule.
//
// NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt` that doesn't match the LLVM we're linking to.
// That's probably ok? At least, the difference wasn't enforced before. There's a comment in
// the compiler_builtins build script that makes me nervous, though:
// https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579
builder.require_submodule(
"src/llvm-project",
Some(
"The `build.optimized-compiler-builtins` config option \
requires `compiler-rt` sources from LLVM.",
),
);
let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
assert!(compiler_builtins_root.exists());
// The path to `compiler-rt` is also used by `profiler_builtins` (above),
// so if you're changing something here please also change that as appropriate.
cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
}
" compiler-builtins-c"
} else {
""
Expand Down
10 changes: 9 additions & 1 deletion src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1741,10 +1741,18 @@ impl Config {
pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool {
self.target_config
.get(&target)
.and_then(|t| t.optimized_compiler_builtins)
.and_then(|t| t.optimized_compiler_builtins.as_ref())
.map(StringOrBool::is_string_or_true)
.unwrap_or(self.optimized_compiler_builtins)
}

pub fn optimized_compiler_builtins_path(&self, target: TargetSelection) -> Option<&str> {
match self.target_config.get(&target)?.optimized_compiler_builtins.as_ref()? {
StringOrBool::String(s) => Some(s),
StringOrBool::Bool(_) => None,
}
}

pub fn llvm_enabled(&self, target: TargetSelection) -> bool {
self.codegen_backends(target).contains(&"llvm".to_owned())
}
Expand Down
4 changes: 2 additions & 2 deletions src/bootstrap/src/core/config/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order};
use crate::core::build_steps::llvm;
use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS;
use crate::core::config::toml::TomlConfig;
use crate::core::config::{LldMode, Target, TargetSelection};
use crate::core::config::{LldMode, StringOrBool, Target, TargetSelection};
use crate::utils::tests::git::git_test;

pub(crate) fn parse(config: &str) -> Config {
Expand Down Expand Up @@ -212,7 +212,7 @@ runner = "x86_64-runner"
let darwin = TargetSelection::from_user("aarch64-apple-darwin");
let darwin_values = Target {
runner: Some("apple".into()),
optimized_compiler_builtins: Some(false),
optimized_compiler_builtins: Some(StringOrBool::Bool(false)),
..Default::default()
};
assert_eq!(
Expand Down
4 changes: 2 additions & 2 deletions src/bootstrap/src/core/config/toml/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ define_config! {
no_std: Option<bool> = "no-std",
codegen_backends: Option<Vec<String>> = "codegen-backends",
runner: Option<String> = "runner",
optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
optimized_compiler_builtins: Option<StringOrBool> = "optimized-compiler-builtins",
jemalloc: Option<bool> = "jemalloc",
}
}
Expand Down Expand Up @@ -77,7 +77,7 @@ pub struct Target {
pub runner: Option<String>,
pub no_std: bool,
pub codegen_backends: Option<Vec<String>>,
pub optimized_compiler_builtins: Option<bool>,
pub optimized_compiler_builtins: Option<StringOrBool>,
pub jemalloc: Option<bool>,
}

Expand Down
Loading