Skip to content

Commit 87e1430

Browse files
committed
Auto merge of #119556 - onur-ozkan:optimized-compiler-builtins, r=onur-ozkan
Reland optimized-compiler-builtins config Copy of #102579 PR. From #102579: > No concerns on my side. Currently, Jyn isn't actively working on the project. I will close this PR; open another one to cherry-pick the commits, resolve conflicts, and then r+ it. > Fixes #102560. Fixes #101172. Helps with #105065 (although there's some weirdness there - it's still broken when optimized-compiler-builtins is set to true). Fixes #102560. Fixes #101172. Helps with #105065 r? ghost
2 parents 9522993 + 6a409dd commit 87e1430

File tree

10 files changed

+99
-31
lines changed

10 files changed

+99
-31
lines changed

config.example.toml

+8
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@
339339
# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
340340
#profiler = false
341341

342+
# Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics.
343+
# Requires the LLVM submodule to be managed by bootstrap (i.e. not external) so that `compiler-rt`
344+
# sources are available.
345+
#
346+
# Setting this to `false` generates slower code, but removes the requirement for a C toolchain in
347+
# order to run `x check`.
348+
#optimized-compiler-builtins = if rust.channel == "dev" { false } else { true }
349+
342350
# Indicates whether the native libraries linked into Cargo will be statically
343351
# linked or not.
344352
#cargo-native-static = false

src/bootstrap/src/core/build_steps/compile.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,7 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
406406

407407
// Determine if we're going to compile in optimized C intrinsics to
408408
// the `compiler-builtins` crate. These intrinsics live in LLVM's
409-
// `compiler-rt` repository, but our `src/llvm-project` submodule isn't
410-
// always checked out, so we need to conditionally look for this. (e.g. if
411-
// an external LLVM is used we skip the LLVM submodule checkout).
409+
// `compiler-rt` repository.
412410
//
413411
// Note that this shouldn't affect the correctness of `compiler-builtins`,
414412
// but only its speed. Some intrinsics in C haven't been translated to Rust
@@ -419,8 +417,21 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
419417
// If `compiler-rt` is available ensure that the `c` feature of the
420418
// `compiler-builtins` crate is enabled and it's configured to learn where
421419
// `compiler-rt` is located.
422-
let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
423-
let compiler_builtins_c_feature = if compiler_builtins_root.exists() {
420+
let compiler_builtins_c_feature = if builder.config.optimized_compiler_builtins {
421+
// NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce `submodules = false`, so this is a no-op.
422+
// But, the user could still decide to manually use an in-tree submodule.
423+
//
424+
// 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.
425+
// That's probably ok? At least, the difference wasn't enforced before. There's a comment in
426+
// the compiler_builtins build script that makes me nervous, though:
427+
// https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579
428+
builder.update_submodule(&Path::new("src").join("llvm-project"));
429+
let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
430+
if !compiler_builtins_root.exists() {
431+
panic!(
432+
"need LLVM sources available to build `compiler-rt`, but they weren't present; consider enabling `build.submodules = true` or disabling `optimized-compiler-builtins`"
433+
);
434+
}
424435
// Note that `libprofiler_builtins/build.rs` also computes this so if
425436
// you're changing something here please also change that.
426437
cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);

src/bootstrap/src/core/build_steps/dist.rs

+18-17
Original file line numberDiff line numberDiff line change
@@ -2032,23 +2032,24 @@ fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
20322032
///
20332033
/// Returns whether the files were actually copied.
20342034
fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
2035-
if let Some(config) = builder.config.target_config.get(&target) {
2036-
if config.llvm_config.is_some() && !builder.config.llvm_from_ci {
2037-
// If the LLVM was externally provided, then we don't currently copy
2038-
// artifacts into the sysroot. This is not necessarily the right
2039-
// choice (in particular, it will require the LLVM dylib to be in
2040-
// the linker's load path at runtime), but the common use case for
2041-
// external LLVMs is distribution provided LLVMs, and in that case
2042-
// they're usually in the standard search path (e.g., /usr/lib) and
2043-
// copying them here is going to cause problems as we may end up
2044-
// with the wrong files and isn't what distributions want.
2045-
//
2046-
// This behavior may be revisited in the future though.
2047-
//
2048-
// If the LLVM is coming from ourselves (just from CI) though, we
2049-
// still want to install it, as it otherwise won't be available.
2050-
return false;
2051-
}
2035+
// If the LLVM was externally provided, then we don't currently copy
2036+
// artifacts into the sysroot. This is not necessarily the right
2037+
// choice (in particular, it will require the LLVM dylib to be in
2038+
// the linker's load path at runtime), but the common use case for
2039+
// external LLVMs is distribution provided LLVMs, and in that case
2040+
// they're usually in the standard search path (e.g., /usr/lib) and
2041+
// copying them here is going to cause problems as we may end up
2042+
// with the wrong files and isn't what distributions want.
2043+
//
2044+
// This behavior may be revisited in the future though.
2045+
//
2046+
// NOTE: this intentionally doesn't use `is_rust_llvm`; whether this is patched or not doesn't matter,
2047+
// we only care if the shared object itself is managed by bootstrap.
2048+
//
2049+
// If the LLVM is coming from ourselves (just from CI) though, we
2050+
// still want to install it, as it otherwise won't be available.
2051+
if builder.is_system_llvm(target) {
2052+
return false;
20522053
}
20532054

20542055
// On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib

src/bootstrap/src/core/build_steps/test.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1850,6 +1850,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
18501850
llvm_components_passed = true;
18511851
}
18521852
if !builder.is_rust_llvm(target) {
1853+
// FIXME: missing Rust patches is not the same as being system llvm; we should rename the flag at some point.
1854+
// Inspecting the tests with `// no-system-llvm` in src/test *looks* like this is doing the right thing, though.
18531855
cmd.arg("--system-llvm");
18541856
}
18551857

src/bootstrap/src/core/config/config.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ pub struct Config {
178178
pub patch_binaries_for_nix: Option<bool>,
179179
pub stage0_metadata: Stage0Metadata,
180180
pub android_ndk: Option<PathBuf>,
181+
/// Whether to use the `c` feature of the `compiler_builtins` crate.
182+
pub optimized_compiler_builtins: bool,
181183

182184
pub stdout_is_tty: bool,
183185
pub stderr_is_tty: bool,
@@ -848,6 +850,7 @@ define_config! {
848850
// NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally
849851
metrics: Option<bool> = "metrics",
850852
android_ndk: Option<PathBuf> = "android-ndk",
853+
optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
851854
}
852855
}
853856

@@ -1396,6 +1399,7 @@ impl Config {
13961399
// This field is only used by bootstrap.py
13971400
metrics: _,
13981401
android_ndk,
1402+
optimized_compiler_builtins,
13991403
} = toml.build.unwrap_or_default();
14001404

14011405
if let Some(file_build) = build {
@@ -1810,7 +1814,14 @@ impl Config {
18101814
}
18111815
target.llvm_config = Some(config.src.join(s));
18121816
}
1813-
target.llvm_has_rust_patches = cfg.llvm_has_rust_patches;
1817+
if let Some(patches) = cfg.llvm_has_rust_patches {
1818+
assert_eq!(
1819+
config.submodules,
1820+
Some(false),
1821+
"cannot set `llvm-has-rust-patches` for a managed submodule (set `build.submodules = false` if you want to apply patches)"
1822+
);
1823+
target.llvm_has_rust_patches = Some(patches);
1824+
}
18141825
if let Some(ref s) = cfg.llvm_filecheck {
18151826
target.llvm_filecheck = Some(config.src.join(s));
18161827
}
@@ -1909,6 +1920,8 @@ impl Config {
19091920
config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std);
19101921
config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
19111922
config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None);
1923+
config.optimized_compiler_builtins =
1924+
optimized_compiler_builtins.unwrap_or(config.channel != "dev");
19121925

19131926
let download_rustc = config.download_rustc_commit.is_some();
19141927
// See https://github.com/rust-lang/compiler-team/issues/326

src/bootstrap/src/lib.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -823,18 +823,34 @@ impl Build {
823823
INTERNER.intern_path(self.out.join(&*target.triple).join("md-doc"))
824824
}
825825

826-
/// Returns `true` if no custom `llvm-config` is set for the specified target.
826+
/// Returns `true` if this is an external version of LLVM not managed by bootstrap.
827+
/// In particular, we expect llvm sources to be available when this is false.
827828
///
828-
/// If no custom `llvm-config` was specified then Rust's llvm will be used.
829+
/// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set.
830+
fn is_system_llvm(&self, target: TargetSelection) -> bool {
831+
match self.config.target_config.get(&target) {
832+
Some(Target { llvm_config: Some(_), .. }) => {
833+
let ci_llvm = self.config.llvm_from_ci && target == self.config.build;
834+
!ci_llvm
835+
}
836+
// We're building from the in-tree src/llvm-project sources.
837+
Some(Target { llvm_config: None, .. }) => false,
838+
None => false,
839+
}
840+
}
841+
842+
/// Returns `true` if this is our custom, patched, version of LLVM.
843+
///
844+
/// This does not necessarily imply that we're managing the `llvm-project` submodule.
829845
fn is_rust_llvm(&self, target: TargetSelection) -> bool {
830846
match self.config.target_config.get(&target) {
847+
// We're using a user-controlled version of LLVM. The user has explicitly told us whether the version has our patches.
848+
// (They might be wrong, but that's not a supported use-case.)
849+
// In particular, this tries to support `submodules = false` and `patches = false`, for using a newer version of LLVM that's not through `rust-lang/llvm-project`.
831850
Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched,
832-
Some(Target { llvm_config, .. }) => {
833-
// If the user set llvm-config we assume Rust is not patched,
834-
// but first check to see if it was configured by llvm-from-ci.
835-
(self.config.llvm_from_ci && target == self.config.build) || llvm_config.is_none()
836-
}
837-
None => true,
851+
// The user hasn't promised the patches match.
852+
// This only has our patches if it's downloaded from CI or built from source.
853+
_ => !self.is_system_llvm(target),
838854
}
839855
}
840856

src/bootstrap/src/utils/change_tracker.rs

+5
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
106106
severity: ChangeSeverity::Info,
107107
summary: "The dist.missing-tools config option was deprecated, as it was unused. If you are using it, remove it from your config, it will be removed soon.",
108108
},
109+
ChangeInfo {
110+
change_id: 102579,
111+
severity: ChangeSeverity::Warning,
112+
summary: "A new `optimized-compiler-builtins` option has been introduced. Whether to build llvm's `compiler-rt` from source is no longer implicitly controlled by git state. See the PR for more details.",
113+
},
109114
];

src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile

+2
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,6 @@ ENV RUST_CONFIGURE_ARGS --disable-jemalloc \
4747
--set=$TARGET.cc=x86_64-unknown-haiku-gcc \
4848
--set=$TARGET.cxx=x86_64-unknown-haiku-g++ \
4949
--set=$TARGET.llvm-config=/bin/llvm-config-haiku
50+
ENV EXTERNAL_LLVM 1
51+
5052
ENV SCRIPT python3 ../x.py dist --host=$HOST --target=$HOST

src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ RUN sh /scripts/sccache.sh
4040
# We are disabling CI LLVM since this builder is intentionally using a host
4141
# LLVM, rather than the typical src/llvm-project LLVM.
4242
ENV NO_DOWNLOAD_CI_LLVM 1
43+
ENV EXTERNAL_LLVM 1
4344

4445
# Using llvm-link-shared due to libffi issues -- see #34486
4546
ENV RUST_CONFIGURE_ARGS \

src/ci/run.sh

+9
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ fi
8585
# space required for CI artifacts.
8686
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz"
8787

88+
# Enable the `c` feature for compiler_builtins, but only when the `compiler-rt` source is available
89+
# (to avoid spending a lot of time cloning llvm)
90+
if [ "$EXTERNAL_LLVM" = "" ]; then
91+
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.optimized-compiler-builtins"
92+
elif [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
93+
echo "error: dist builds should always use optimized compiler-rt!" >&2
94+
exit 1
95+
fi
96+
8897
if [ "$DIST_SRC" = "" ]; then
8998
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src"
9099
fi

0 commit comments

Comments
 (0)