Skip to content

Commit b326953

Browse files
committed
Auto merge of rust-lang#72020 - alexcrichton:fix-incremental-linker-plugin-lto, r=oli-obk
Fix disagreeement about CGU reuse and LTO This commit fixes an issue where the codegen backend's selection of LTO disagreed with what the codegen later thought was being done. Discovered in rust-lang#72006 we have a longstanding issue where if `-Clinker-plugin-lto` in optimized mode is compiled incrementally it will always panic on the second compilation. The underlying issue turned out to be that the production of the original artifact determined that LTO should not be done (because it's being postponed to the linker) but the CGU reuse selection thought that LTO was done so it was trying to load pre-LTO artifacts which were never generated. The fix here is to ensure that the logic when generating code which determines what kind of LTO is being done is shared amongst the CGU reuse decision and the backend actually doing LTO. This means that they'll both be in agreement about whether the previous compilation did indeed produce incremental pre-LTO artifacts. Closes rust-lang#72006
2 parents 6f5c782 + c7bd5a6 commit b326953

File tree

4 files changed

+71
-35
lines changed

4 files changed

+71
-35
lines changed

Diff for: src/librustc_codegen_ssa/back/write.rs

+39-30
Original file line numberDiff line numberDiff line change
@@ -709,38 +709,34 @@ fn execute_work_item<B: ExtraBackendMethods>(
709709
}
710710

711711
// Actual LTO type we end up choosing based on multiple factors.
712-
enum ComputedLtoType {
712+
pub enum ComputedLtoType {
713713
No,
714714
Thin,
715715
Fat,
716716
}
717717

718-
fn execute_optimize_work_item<B: ExtraBackendMethods>(
719-
cgcx: &CodegenContext<B>,
720-
module: ModuleCodegen<B::Module>,
721-
module_config: &ModuleConfig,
722-
) -> Result<WorkItemResult<B>, FatalError> {
723-
let diag_handler = cgcx.create_diag_handler();
724-
725-
unsafe {
726-
B::optimize(cgcx, &diag_handler, &module, module_config)?;
718+
pub fn compute_per_cgu_lto_type(
719+
sess_lto: &Lto,
720+
opts: &config::Options,
721+
sess_crate_types: &[CrateType],
722+
module_kind: ModuleKind,
723+
) -> ComputedLtoType {
724+
// Metadata modules never participate in LTO regardless of the lto
725+
// settings.
726+
if module_kind == ModuleKind::Metadata {
727+
return ComputedLtoType::No;
727728
}
728729

729-
// After we've done the initial round of optimizations we need to
730-
// decide whether to synchronously codegen this module or ship it
731-
// back to the coordinator thread for further LTO processing (which
732-
// has to wait for all the initial modules to be optimized).
733-
734730
// If the linker does LTO, we don't have to do it. Note that we
735731
// keep doing full LTO, if it is requested, as not to break the
736732
// assumption that the output will be a single module.
737-
let linker_does_lto = cgcx.opts.cg.linker_plugin_lto.enabled();
733+
let linker_does_lto = opts.cg.linker_plugin_lto.enabled();
738734

739735
// When we're automatically doing ThinLTO for multi-codegen-unit
740736
// builds we don't actually want to LTO the allocator modules if
741737
// it shows up. This is due to various linker shenanigans that
742738
// we'll encounter later.
743-
let is_allocator = module.kind == ModuleKind::Allocator;
739+
let is_allocator = module_kind == ModuleKind::Allocator;
744740

745741
// We ignore a request for full crate grath LTO if the cate type
746742
// is only an rlib, as there is no full crate graph to process,
@@ -750,20 +746,33 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
750746
// require LTO so the request for LTO is always unconditionally
751747
// passed down to the backend, but we don't actually want to do
752748
// anything about it yet until we've got a final product.
753-
let is_rlib = cgcx.crate_types.len() == 1 && cgcx.crate_types[0] == CrateType::Rlib;
749+
let is_rlib = sess_crate_types.len() == 1 && sess_crate_types[0] == CrateType::Rlib;
754750

755-
// Metadata modules never participate in LTO regardless of the lto
756-
// settings.
757-
let lto_type = if module.kind == ModuleKind::Metadata {
758-
ComputedLtoType::No
759-
} else {
760-
match cgcx.lto {
761-
Lto::ThinLocal if !linker_does_lto && !is_allocator => ComputedLtoType::Thin,
762-
Lto::Thin if !linker_does_lto && !is_rlib => ComputedLtoType::Thin,
763-
Lto::Fat if !is_rlib => ComputedLtoType::Fat,
764-
_ => ComputedLtoType::No,
765-
}
766-
};
751+
match sess_lto {
752+
Lto::ThinLocal if !linker_does_lto && !is_allocator => ComputedLtoType::Thin,
753+
Lto::Thin if !linker_does_lto && !is_rlib => ComputedLtoType::Thin,
754+
Lto::Fat if !is_rlib => ComputedLtoType::Fat,
755+
_ => ComputedLtoType::No,
756+
}
757+
}
758+
759+
fn execute_optimize_work_item<B: ExtraBackendMethods>(
760+
cgcx: &CodegenContext<B>,
761+
module: ModuleCodegen<B::Module>,
762+
module_config: &ModuleConfig,
763+
) -> Result<WorkItemResult<B>, FatalError> {
764+
let diag_handler = cgcx.create_diag_handler();
765+
766+
unsafe {
767+
B::optimize(cgcx, &diag_handler, &module, module_config)?;
768+
}
769+
770+
// After we've done the initial round of optimizations we need to
771+
// decide whether to synchronously codegen this module or ship it
772+
// back to the coordinator thread for further LTO processing (which
773+
// has to wait for all the initial modules to be optimized).
774+
775+
let lto_type = compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts, &cgcx.crate_types, module.kind);
767776

768777
// If we're doing some form of incremental LTO then we need to be sure to
769778
// save our module to disk first.

Diff for: src/librustc_codegen_ssa/base.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
//! int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
1515
1616
use crate::back::write::{
17-
start_async_codegen, submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm,
18-
submit_pre_lto_module_to_llvm, OngoingCodegen,
17+
compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
18+
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
1919
};
2020
use crate::common::{IntPredicate, RealPredicate, TypeKind};
2121
use crate::meth;
@@ -43,7 +43,7 @@ use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
4343
use rustc_middle::ty::query::Providers;
4444
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
4545
use rustc_session::cgu_reuse_tracker::CguReuse;
46-
use rustc_session::config::{self, EntryFnType, Lto};
46+
use rustc_session::config::{self, EntryFnType};
4747
use rustc_session::Session;
4848
use rustc_span::Span;
4949
use rustc_symbol_mangling::test as symbol_names_test;
@@ -941,8 +941,18 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR
941941
);
942942

943943
if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() {
944-
// We can re-use either the pre- or the post-thinlto state
945-
if tcx.sess.lto() != Lto::No { CguReuse::PreLto } else { CguReuse::PostLto }
944+
// We can re-use either the pre- or the post-thinlto state. If no LTO is
945+
// being performed then we can use post-LTO artifacts, otherwise we must
946+
// reuse pre-LTO artifacts
947+
match compute_per_cgu_lto_type(
948+
&tcx.sess.lto(),
949+
&tcx.sess.opts,
950+
&tcx.sess.crate_types.borrow(),
951+
ModuleKind::Regular,
952+
) {
953+
ComputedLtoType::No => CguReuse::PostLto,
954+
_ => CguReuse::PreLto,
955+
}
946956
} else {
947957
CguReuse::No
948958
}

Diff for: src/test/incremental/lto-in-linker.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// revisions:cfail1 cfail2
2+
// compile-flags: -Z query-dep-graph --crate-type rlib -C linker-plugin-lto -O
3+
// no-prefer-dynamic
4+
// build-pass
5+
6+
#![feature(rustc_attrs)]
7+
#![rustc_partition_reused(module = "lto_in_linker", cfg = "cfail2")]
8+
9+
pub fn foo() {}

Diff for: src/test/incremental/rlib-lto.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// revisions:cfail1 cfail2
2+
// compile-flags: -Z query-dep-graph --crate-type rlib -C lto
3+
// build-pass
4+
5+
#![feature(rustc_attrs)]
6+
#![rustc_partition_reused(module = "rlib_lto", cfg = "cfail2")]
7+
8+
pub fn foo() {}

0 commit comments

Comments
 (0)