Rollup merge of #119885 - DianQK:revert-pr-113923, r=petrochenkov
Revert #113923 Per [#t-compiler/meetings > [weekly] 2024-01-11](https://rust-lang.zulipchat.com/#narrow/stream/238009-t-compiler.2Fmeetings/topic/.5Bweekly.5D.202024-01-11) discussion, revert #113923. Also revert associated #118568. The PR #113923 causes the regression issue #118609. We need more time to find a proper solution. Discussions start at [412365838](https://rust-lang.zulipchat.com/#narrow/stream/238009-t-compiler.2Fmeetings/topic/.5Bweekly.5D.202024-01-11/near/412365838) and continue to [412369643](https://rust-lang.zulipchat.com/#narrow/stream/238009-t-compiler.2Fmeetings/topic/.5Bweekly.5D.202024-01-11/near/412369643). Fixes #118609. r? compiler
This commit is contained in:
commit
dafbe17a02
@ -60,7 +60,7 @@ fn prepare_lto(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
|
let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
|
||||||
if info.level.is_below_threshold(export_threshold) || info.used || info.used_compiler {
|
if info.level.is_below_threshold(export_threshold) || info.used {
|
||||||
Some(CString::new(name.as_str()).unwrap())
|
Some(CString::new(name.as_str()).unwrap())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -569,6 +569,7 @@ pub(crate) unsafe fn llvm_optimize(
|
|||||||
unroll_loops,
|
unroll_loops,
|
||||||
config.vectorize_slp,
|
config.vectorize_slp,
|
||||||
config.vectorize_loop,
|
config.vectorize_loop,
|
||||||
|
config.no_builtins,
|
||||||
config.emit_lifetime_markers,
|
config.emit_lifetime_markers,
|
||||||
sanitizer_options.as_ref(),
|
sanitizer_options.as_ref(),
|
||||||
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||||
@ -677,6 +678,7 @@ pub(crate) unsafe fn codegen(
|
|||||||
unsafe fn with_codegen<'ll, F, R>(
|
unsafe fn with_codegen<'ll, F, R>(
|
||||||
tm: &'ll llvm::TargetMachine,
|
tm: &'ll llvm::TargetMachine,
|
||||||
llmod: &'ll llvm::Module,
|
llmod: &'ll llvm::Module,
|
||||||
|
no_builtins: bool,
|
||||||
f: F,
|
f: F,
|
||||||
) -> R
|
) -> R
|
||||||
where
|
where
|
||||||
@ -684,7 +686,7 @@ unsafe fn with_codegen<'ll, F, R>(
|
|||||||
{
|
{
|
||||||
let cpm = llvm::LLVMCreatePassManager();
|
let cpm = llvm::LLVMCreatePassManager();
|
||||||
llvm::LLVMAddAnalysisPasses(tm, cpm);
|
llvm::LLVMAddAnalysisPasses(tm, cpm);
|
||||||
llvm::LLVMRustAddLibraryInfo(cpm, llmod);
|
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
|
||||||
f(cpm)
|
f(cpm)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -785,7 +787,7 @@ extern "C" fn demangle_callback(
|
|||||||
} else {
|
} else {
|
||||||
llmod
|
llmod
|
||||||
};
|
};
|
||||||
with_codegen(tm, llmod, |cpm| {
|
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||||
write_output_file(
|
write_output_file(
|
||||||
dcx,
|
dcx,
|
||||||
tm,
|
tm,
|
||||||
@ -820,7 +822,7 @@ extern "C" fn demangle_callback(
|
|||||||
(_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
|
(_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
|
||||||
};
|
};
|
||||||
|
|
||||||
with_codegen(tm, llmod, |cpm| {
|
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||||
write_output_file(
|
write_output_file(
|
||||||
dcx,
|
dcx,
|
||||||
tm,
|
tm,
|
||||||
|
@ -2173,8 +2173,13 @@ pub fn LLVMRustCreateTargetMachine(
|
|||||||
ArgsCstrBuff: *const c_char,
|
ArgsCstrBuff: *const c_char,
|
||||||
ArgsCstrBuffLen: usize,
|
ArgsCstrBuffLen: usize,
|
||||||
) -> *mut TargetMachine;
|
) -> *mut TargetMachine;
|
||||||
|
|
||||||
pub fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
|
pub fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
|
||||||
pub fn LLVMRustAddLibraryInfo<'a>(PM: &PassManager<'a>, M: &'a Module);
|
pub fn LLVMRustAddLibraryInfo<'a>(
|
||||||
|
PM: &PassManager<'a>,
|
||||||
|
M: &'a Module,
|
||||||
|
DisableSimplifyLibCalls: bool,
|
||||||
|
);
|
||||||
pub fn LLVMRustWriteOutputFile<'a>(
|
pub fn LLVMRustWriteOutputFile<'a>(
|
||||||
T: &'a TargetMachine,
|
T: &'a TargetMachine,
|
||||||
PM: &PassManager<'a>,
|
PM: &PassManager<'a>,
|
||||||
@ -2196,6 +2201,7 @@ pub fn LLVMRustOptimize<'a>(
|
|||||||
UnrollLoops: bool,
|
UnrollLoops: bool,
|
||||||
SLPVectorize: bool,
|
SLPVectorize: bool,
|
||||||
LoopVectorize: bool,
|
LoopVectorize: bool,
|
||||||
|
DisableSimplifyLibCalls: bool,
|
||||||
EmitLifetimeMarkers: bool,
|
EmitLifetimeMarkers: bool,
|
||||||
SanitizerOptions: Option<&SanitizerOptions>,
|
SanitizerOptions: Option<&SanitizerOptions>,
|
||||||
PGOGenPath: *const c_char,
|
PGOGenPath: *const c_char,
|
||||||
|
@ -270,14 +270,8 @@ pub fn each_linked_rlib(
|
|||||||
|
|
||||||
for &cnum in crates {
|
for &cnum in crates {
|
||||||
match fmts.get(cnum.as_usize() - 1) {
|
match fmts.get(cnum.as_usize() - 1) {
|
||||||
Some(&Linkage::NotLinked | &Linkage::Dynamic) => continue,
|
Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
|
||||||
Some(&Linkage::IncludedFromDylib) => {
|
Some(_) => {}
|
||||||
// We always link crate `compiler_builtins` statically. When enabling LTO, we include it as well.
|
|
||||||
if info.compiler_builtins != Some(cnum) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(&Linkage::Static) => {}
|
|
||||||
None => return Err(errors::LinkRlibError::MissingFormat),
|
None => return Err(errors::LinkRlibError::MissingFormat),
|
||||||
}
|
}
|
||||||
let crate_name = info.crate_name[&cnum];
|
let crate_name = info.crate_name[&cnum];
|
||||||
@ -526,7 +520,8 @@ fn link_staticlib<'a>(
|
|||||||
&codegen_results.crate_info,
|
&codegen_results.crate_info,
|
||||||
Some(CrateType::Staticlib),
|
Some(CrateType::Staticlib),
|
||||||
&mut |cnum, path| {
|
&mut |cnum, path| {
|
||||||
let lto = are_upstream_rust_objects_already_included(sess);
|
let lto = are_upstream_rust_objects_already_included(sess)
|
||||||
|
&& !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
|
||||||
|
|
||||||
let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter();
|
let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter();
|
||||||
let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib));
|
let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib));
|
||||||
@ -1277,6 +1272,24 @@ fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a boolean indicating whether the specified crate should be ignored
|
||||||
|
/// during LTO.
|
||||||
|
///
|
||||||
|
/// Crates ignored during LTO are not lumped together in the "massive object
|
||||||
|
/// file" that we create and are linked in their normal rlib states. See
|
||||||
|
/// comments below for what crates do not participate in LTO.
|
||||||
|
///
|
||||||
|
/// It's unusual for a crate to not participate in LTO. Typically only
|
||||||
|
/// compiler-specific and unstable crates have a reason to not participate in
|
||||||
|
/// LTO.
|
||||||
|
pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool {
|
||||||
|
// If our target enables builtin function lowering in LLVM then the
|
||||||
|
// crates providing these functions don't participate in LTO (e.g.
|
||||||
|
// no_builtins or compiler builtins crates).
|
||||||
|
!sess.target.no_builtins
|
||||||
|
&& (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
|
||||||
|
}
|
||||||
|
|
||||||
/// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
|
/// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
|
||||||
pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
||||||
fn infer_from(
|
fn infer_from(
|
||||||
@ -2742,6 +2755,10 @@ fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf {
|
|||||||
// symbols). We must continue to include the rest of the rlib, however, as
|
// symbols). We must continue to include the rest of the rlib, however, as
|
||||||
// it may contain static native libraries which must be linked in.
|
// it may contain static native libraries which must be linked in.
|
||||||
//
|
//
|
||||||
|
// (*) Crates marked with `#![no_builtins]` don't participate in LTO and
|
||||||
|
// their bytecode wasn't included. The object files in those libraries must
|
||||||
|
// still be passed to the linker.
|
||||||
|
//
|
||||||
// Note, however, that if we're not doing LTO we can just pass the rlib
|
// Note, however, that if we're not doing LTO we can just pass the rlib
|
||||||
// blindly to the linker (fast) because it's fine if it's not actually
|
// blindly to the linker (fast) because it's fine if it's not actually
|
||||||
// included as we're at the end of the dependency chain.
|
// included as we're at the end of the dependency chain.
|
||||||
@ -2767,7 +2784,9 @@ fn add_static_crate<'a>(
|
|||||||
cmd.link_rlib(&rlib_path);
|
cmd.link_rlib(&rlib_path);
|
||||||
};
|
};
|
||||||
|
|
||||||
if !are_upstream_rust_objects_already_included(sess) {
|
if !are_upstream_rust_objects_already_included(sess)
|
||||||
|
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum)
|
||||||
|
{
|
||||||
link_upstream(cratepath);
|
link_upstream(cratepath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2781,6 +2800,8 @@ fn add_static_crate<'a>(
|
|||||||
let canonical_name = name.replace('-', "_");
|
let canonical_name = name.replace('-', "_");
|
||||||
let upstream_rust_objects_already_included =
|
let upstream_rust_objects_already_included =
|
||||||
are_upstream_rust_objects_already_included(sess);
|
are_upstream_rust_objects_already_included(sess);
|
||||||
|
let is_builtins =
|
||||||
|
sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
|
||||||
|
|
||||||
let mut archive = archive_builder_builder.new_archive_builder(sess);
|
let mut archive = archive_builder_builder.new_archive_builder(sess);
|
||||||
if let Err(error) = archive.add_archive(
|
if let Err(error) = archive.add_archive(
|
||||||
@ -2797,8 +2818,9 @@ fn add_static_crate<'a>(
|
|||||||
|
|
||||||
// If we're performing LTO and this is a rust-generated object
|
// If we're performing LTO and this is a rust-generated object
|
||||||
// file, then we don't need the object file as it's part of the
|
// file, then we don't need the object file as it's part of the
|
||||||
// LTO module.
|
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
|
||||||
if upstream_rust_objects_already_included && is_rust_object {
|
// though, so we let that object file slide.
|
||||||
|
if upstream_rust_objects_already_included && is_rust_object && is_builtins {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
|||||||
// export level, however, as they're just implementation details.
|
// export level, however, as they're just implementation details.
|
||||||
// Down below we'll hardwire all of the symbols to the `Rust` export
|
// Down below we'll hardwire all of the symbols to the `Rust` export
|
||||||
// level instead.
|
// level instead.
|
||||||
let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE);
|
let special_runtime_crate =
|
||||||
let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) || is_compiler_builtins;
|
tcx.is_panic_runtime(LOCAL_CRATE) || tcx.is_compiler_builtins(LOCAL_CRATE);
|
||||||
|
|
||||||
let mut reachable_non_generics: DefIdMap<_> = tcx
|
let mut reachable_non_generics: DefIdMap<_> = tcx
|
||||||
.reachable_set(())
|
.reachable_set(())
|
||||||
@ -105,14 +105,8 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|def_id| {
|
.map(|def_id| {
|
||||||
let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id());
|
|
||||||
// We won't link right if this symbol is stripped during LTO.
|
// We won't link right if this symbol is stripped during LTO.
|
||||||
let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name;
|
let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name;
|
||||||
// We have to preserve the symbols of the built-in functions during LTO.
|
|
||||||
let is_builtin_fn = is_compiler_builtins
|
|
||||||
&& symbol_export_level(tcx, def_id.to_def_id())
|
|
||||||
.is_below_threshold(SymbolExportLevel::C)
|
|
||||||
&& codegen_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE);
|
|
||||||
let used = name == "rust_eh_personality";
|
let used = name == "rust_eh_personality";
|
||||||
|
|
||||||
let export_level = if special_runtime_crate {
|
let export_level = if special_runtime_crate {
|
||||||
@ -120,6 +114,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
|||||||
} else {
|
} else {
|
||||||
symbol_export_level(tcx, def_id.to_def_id())
|
symbol_export_level(tcx, def_id.to_def_id())
|
||||||
};
|
};
|
||||||
|
let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id());
|
||||||
debug!(
|
debug!(
|
||||||
"EXPORTED SYMBOL (local): {} ({:?})",
|
"EXPORTED SYMBOL (local): {} ({:?})",
|
||||||
tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())),
|
tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())),
|
||||||
@ -139,7 +134,6 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
|||||||
used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||||
|| used,
|
|| used,
|
||||||
used_compiler: is_builtin_fn,
|
|
||||||
};
|
};
|
||||||
(def_id.to_def_id(), info)
|
(def_id.to_def_id(), info)
|
||||||
})
|
})
|
||||||
@ -152,7 +146,6 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
|||||||
level: SymbolExportLevel::C,
|
level: SymbolExportLevel::C,
|
||||||
kind: SymbolExportKind::Data,
|
kind: SymbolExportKind::Data,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -201,7 +194,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: info.level,
|
level: info.level,
|
||||||
kind: SymbolExportKind::Text,
|
kind: SymbolExportKind::Text,
|
||||||
used: info.used,
|
used: info.used,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -218,7 +210,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: SymbolExportLevel::C,
|
level: SymbolExportLevel::C,
|
||||||
kind: SymbolExportKind::Text,
|
kind: SymbolExportKind::Text,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -238,7 +229,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: SymbolExportLevel::Rust,
|
level: SymbolExportLevel::Rust,
|
||||||
kind: SymbolExportKind::Text,
|
kind: SymbolExportKind::Text,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -251,7 +241,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: SymbolExportLevel::Rust,
|
level: SymbolExportLevel::Rust,
|
||||||
kind: SymbolExportKind::Data,
|
kind: SymbolExportKind::Data,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -271,7 +260,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: SymbolExportLevel::C,
|
level: SymbolExportLevel::C,
|
||||||
kind: SymbolExportKind::Data,
|
kind: SymbolExportKind::Data,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
@ -297,7 +285,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: SymbolExportLevel::C,
|
level: SymbolExportLevel::C,
|
||||||
kind: SymbolExportKind::Data,
|
kind: SymbolExportKind::Data,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
@ -315,7 +302,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: SymbolExportLevel::C,
|
level: SymbolExportLevel::C,
|
||||||
kind: SymbolExportKind::Data,
|
kind: SymbolExportKind::Data,
|
||||||
used: true,
|
used: true,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -356,7 +342,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: SymbolExportLevel::Rust,
|
level: SymbolExportLevel::Rust,
|
||||||
kind: SymbolExportKind::Text,
|
kind: SymbolExportKind::Text,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -373,7 +358,6 @@ fn exported_symbols_provider_local(
|
|||||||
level: SymbolExportLevel::Rust,
|
level: SymbolExportLevel::Rust,
|
||||||
kind: SymbolExportKind::Text,
|
kind: SymbolExportKind::Text,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -148,12 +148,23 @@ macro_rules! if_regular {
|
|||||||
|
|
||||||
let emit_obj = if !should_emit_obj {
|
let emit_obj = if !should_emit_obj {
|
||||||
EmitObj::None
|
EmitObj::None
|
||||||
} else if sess.target.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled() {
|
} else if sess.target.obj_is_bitcode
|
||||||
|
|| (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins)
|
||||||
|
{
|
||||||
// This case is selected if the target uses objects as bitcode, or
|
// This case is selected if the target uses objects as bitcode, or
|
||||||
// if linker plugin LTO is enabled. In the linker plugin LTO case
|
// if linker plugin LTO is enabled. In the linker plugin LTO case
|
||||||
// the assumption is that the final link-step will read the bitcode
|
// the assumption is that the final link-step will read the bitcode
|
||||||
// and convert it to object code. This may be done by either the
|
// and convert it to object code. This may be done by either the
|
||||||
// native linker or rustc itself.
|
// native linker or rustc itself.
|
||||||
|
//
|
||||||
|
// Note, however, that the linker-plugin-lto requested here is
|
||||||
|
// explicitly ignored for `#![no_builtins]` crates. These crates are
|
||||||
|
// specifically ignored by rustc's LTO passes and wouldn't work if
|
||||||
|
// loaded into the linker. These crates define symbols that LLVM
|
||||||
|
// lowers intrinsics to, and these symbol dependencies aren't known
|
||||||
|
// until after codegen. As a result any crate marked
|
||||||
|
// `#![no_builtins]` is assumed to not participate in LTO and
|
||||||
|
// instead goes on to generate object code.
|
||||||
EmitObj::Bitcode
|
EmitObj::Bitcode
|
||||||
} else if need_bitcode_in_object(tcx) {
|
} else if need_bitcode_in_object(tcx) {
|
||||||
EmitObj::ObjectCode(BitcodeSection::Full)
|
EmitObj::ObjectCode(BitcodeSection::Full)
|
||||||
@ -1023,6 +1034,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||||||
|
|
||||||
let mut each_linked_rlib_for_lto = Vec::new();
|
let mut each_linked_rlib_for_lto = Vec::new();
|
||||||
drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| {
|
drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| {
|
||||||
|
if link::ignored_for_lto(sess, crate_info, cnum) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
|
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -859,6 +859,7 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
|
|||||||
local_crate_name,
|
local_crate_name,
|
||||||
compiler_builtins,
|
compiler_builtins,
|
||||||
profiler_runtime: None,
|
profiler_runtime: None,
|
||||||
|
is_no_builtins: Default::default(),
|
||||||
native_libraries: Default::default(),
|
native_libraries: Default::default(),
|
||||||
used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
|
used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
|
||||||
crate_name: Default::default(),
|
crate_name: Default::default(),
|
||||||
@ -885,6 +886,9 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
|
|||||||
if tcx.is_profiler_runtime(cnum) {
|
if tcx.is_profiler_runtime(cnum) {
|
||||||
info.profiler_runtime = Some(cnum);
|
info.profiler_runtime = Some(cnum);
|
||||||
}
|
}
|
||||||
|
if tcx.is_no_builtins(cnum) {
|
||||||
|
info.is_no_builtins.insert(cnum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle circular dependencies in the standard library.
|
// Handle circular dependencies in the standard library.
|
||||||
@ -892,7 +896,9 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
|
|||||||
// If global LTO is enabled then almost everything (*) is glued into a single object file,
|
// If global LTO is enabled then almost everything (*) is glued into a single object file,
|
||||||
// so this logic is not necessary and can cause issues on some targets (due to weak lang
|
// so this logic is not necessary and can cause issues on some targets (due to weak lang
|
||||||
// item symbols being "privatized" to that object file), so we disable it.
|
// item symbols being "privatized" to that object file), so we disable it.
|
||||||
// (*) Native libs are not glued, and we assume that they cannot define weak lang items.
|
// (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued,
|
||||||
|
// and we assume that they cannot define weak lang items. This is not currently enforced
|
||||||
|
// by the compiler, but that's ok because all this stuff is unstable anyway.
|
||||||
let target = &tcx.sess.target;
|
let target = &tcx.sess.target;
|
||||||
if !are_upstream_rust_objects_already_included(tcx.sess) {
|
if !are_upstream_rust_objects_already_included(tcx.sess) {
|
||||||
let missing_weak_lang_items: FxHashSet<Symbol> = info
|
let missing_weak_lang_items: FxHashSet<Symbol> = info
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
extern crate rustc_middle;
|
extern crate rustc_middle;
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_hir::def_id::CrateNum;
|
use rustc_hir::def_id::CrateNum;
|
||||||
use rustc_middle::dep_graph::WorkProduct;
|
use rustc_middle::dep_graph::WorkProduct;
|
||||||
@ -158,6 +158,7 @@ pub struct CrateInfo {
|
|||||||
pub local_crate_name: Symbol,
|
pub local_crate_name: Symbol,
|
||||||
pub compiler_builtins: Option<CrateNum>,
|
pub compiler_builtins: Option<CrateNum>,
|
||||||
pub profiler_runtime: Option<CrateNum>,
|
pub profiler_runtime: Option<CrateNum>,
|
||||||
|
pub is_no_builtins: FxHashSet<CrateNum>,
|
||||||
pub native_libraries: FxHashMap<CrateNum, Vec<NativeLib>>,
|
pub native_libraries: FxHashMap<CrateNum, Vec<NativeLib>>,
|
||||||
pub crate_name: FxHashMap<CrateNum, Symbol>,
|
pub crate_name: FxHashMap<CrateNum, Symbol>,
|
||||||
pub used_libraries: Vec<NativeLib>,
|
pub used_libraries: Vec<NativeLib>,
|
||||||
|
@ -531,9 +531,12 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
|
|||||||
|
|
||||||
// Unfortunately, the LLVM C API doesn't provide a way to create the
|
// Unfortunately, the LLVM C API doesn't provide a way to create the
|
||||||
// TargetLibraryInfo pass, so we use this method to do so.
|
// TargetLibraryInfo pass, so we use this method to do so.
|
||||||
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M) {
|
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
|
||||||
|
bool DisableSimplifyLibCalls) {
|
||||||
Triple TargetTriple(unwrap(M)->getTargetTriple());
|
Triple TargetTriple(unwrap(M)->getTargetTriple());
|
||||||
TargetLibraryInfoImpl TLII(TargetTriple);
|
TargetLibraryInfoImpl TLII(TargetTriple);
|
||||||
|
if (DisableSimplifyLibCalls)
|
||||||
|
TLII.disableAllFunctions();
|
||||||
unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII));
|
unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,7 +703,7 @@ LLVMRustOptimize(
|
|||||||
bool IsLinkerPluginLTO,
|
bool IsLinkerPluginLTO,
|
||||||
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
|
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
|
||||||
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
|
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
|
||||||
bool EmitLifetimeMarkers,
|
bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
|
||||||
LLVMRustSanitizerOptions *SanitizerOptions,
|
LLVMRustSanitizerOptions *SanitizerOptions,
|
||||||
const char *PGOGenPath, const char *PGOUsePath,
|
const char *PGOGenPath, const char *PGOUsePath,
|
||||||
bool InstrumentCoverage, const char *InstrProfileOutput,
|
bool InstrumentCoverage, const char *InstrProfileOutput,
|
||||||
@ -800,6 +803,8 @@ LLVMRustOptimize(
|
|||||||
|
|
||||||
Triple TargetTriple(TheModule->getTargetTriple());
|
Triple TargetTriple(TheModule->getTargetTriple());
|
||||||
std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple));
|
std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple));
|
||||||
|
if (DisableSimplifyLibCalls)
|
||||||
|
TLII->disableAllFunctions();
|
||||||
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
|
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
|
||||||
|
|
||||||
PB.registerModuleAnalyses(MAM);
|
PB.registerModuleAnalyses(MAM);
|
||||||
|
@ -35,12 +35,7 @@ pub enum SymbolExportKind {
|
|||||||
pub struct SymbolExportInfo {
|
pub struct SymbolExportInfo {
|
||||||
pub level: SymbolExportLevel,
|
pub level: SymbolExportLevel,
|
||||||
pub kind: SymbolExportKind,
|
pub kind: SymbolExportKind,
|
||||||
/// Used to mark these symbols not to be internalized by LTO. These symbols
|
|
||||||
/// are also added to `symbols.o` to avoid circular dependencies when linking.
|
|
||||||
pub used: bool,
|
pub used: bool,
|
||||||
/// Also used to mark these symbols not to be internalized by LTO. But will
|
|
||||||
/// not be added to `symbols.o`. Currently there are only builtin functions.
|
|
||||||
pub used_compiler: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
|
||||||
|
@ -165,7 +165,6 @@ fn config(&mut self, config: &mut Config) {
|
|||||||
level: SymbolExportLevel::C,
|
level: SymbolExportLevel::C,
|
||||||
kind: SymbolExportKind::Text,
|
kind: SymbolExportKind::Text,
|
||||||
used: false,
|
used: false,
|
||||||
used_compiler: false,
|
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}),
|
}),
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
include ../tools.mk
|
include ../tools.mk
|
||||||
|
|
||||||
# only-x86_64
|
|
||||||
|
|
||||||
# We want to check that `no_builtins` is correctly participating in LTO.
|
|
||||||
# First, verify that the `foo::foo` symbol can be found when linking.
|
|
||||||
# Next, verify that `memcpy` can be customized using `no_builtins` under LTO.
|
|
||||||
# Others will use the built-in memcpy.
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(RUSTC) -C linker-plugin-lto -C opt-level=2 -C debuginfo=0 foo.rs
|
# Compile a `#![no_builtins]` rlib crate
|
||||||
$(RUSTC) -C linker-plugin-lto -C opt-level=2 -C debuginfo=0 no_builtins.rs
|
$(RUSTC) no_builtins.rs
|
||||||
$(RUSTC) main.rs -C lto -C opt-level=2 -C debuginfo=0 -C save-temps -C metadata=1 -C codegen-units=1
|
# Build an executable that depends on that crate using LTO. The no_builtins crate doesn't
|
||||||
"$(LLVM_BIN_DIR)"/llvm-dis $(TMPDIR)/main.main.*-cgu.0.rcgu.lto.input.bc -o $(TMPDIR)/lto.ll
|
# participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by
|
||||||
cat "$(TMPDIR)"/lto.ll | "$(LLVM_FILECHECK)" filecheck.lto.txt
|
# grepping the linker arguments.
|
||||||
|
$(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib'
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
CHECK: define{{.*}} void @bar
|
|
||||||
CHECK-NEXT: call void @no_builtins
|
|
||||||
CHECK-NEXT: call void @llvm.memcpy
|
|
||||||
|
|
||||||
CHECK: define{{.*}} i32 @main
|
|
||||||
CHECK: call void @bar
|
|
||||||
|
|
||||||
CHECK: define{{.*}} void @foo
|
|
||||||
CHECK-NEXT: call void @llvm.memcpy
|
|
||||||
|
|
||||||
CHECK: define{{.*}} void @no_builtins
|
|
||||||
CHECK-SAME: #[[ATTR:[0-9]+]] {
|
|
||||||
CHECK: call void @foo
|
|
||||||
CHECK-NEXT: call{{.*}} @memcpy
|
|
||||||
|
|
||||||
CHECK: attributes #[[ATTR]]
|
|
||||||
CHECK-SAME: no-builtins
|
|
@ -1,33 +0,0 @@
|
|||||||
#![feature(lang_items, no_core)]
|
|
||||||
#![no_std]
|
|
||||||
#![no_core]
|
|
||||||
#![crate_type = "lib"]
|
|
||||||
|
|
||||||
#[inline(never)]
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn foo(dest: *mut u8, src: *const u8) {
|
|
||||||
// should call `@llvm.memcpy`.
|
|
||||||
memcpy(dest, src, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[inline(never)]
|
|
||||||
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, _n: usize) -> *mut u8 {
|
|
||||||
*dest = 0;
|
|
||||||
return src as *mut u8;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[lang = "sized"]
|
|
||||||
trait Sized {}
|
|
||||||
#[lang = "copy"]
|
|
||||||
trait Copy {}
|
|
||||||
impl Copy for *mut u8 {}
|
|
||||||
impl Copy for *const u8 {}
|
|
||||||
|
|
||||||
#[lang = "drop_in_place"]
|
|
||||||
#[allow(unconditional_recursion)]
|
|
||||||
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
|
||||||
// Code here does not matter - this is replaced by the
|
|
||||||
// real drop glue by the compiler.
|
|
||||||
drop_in_place(to_drop);
|
|
||||||
}
|
|
@ -1,29 +1,3 @@
|
|||||||
#![feature(no_core, start, lang_items)]
|
|
||||||
#![no_std]
|
|
||||||
// We use `no_core` to reduce the LTO products is small enough.
|
|
||||||
#![no_core]
|
|
||||||
|
|
||||||
extern crate no_builtins;
|
extern crate no_builtins;
|
||||||
extern crate foo;
|
|
||||||
|
|
||||||
#[cfg_attr(unix, link(name = "c"))]
|
fn main() {}
|
||||||
#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
|
|
||||||
extern "C" {}
|
|
||||||
|
|
||||||
#[start]
|
|
||||||
fn main(_: isize, p: *const *const u8) -> isize {
|
|
||||||
// Make sure the symbols are retained.
|
|
||||||
unsafe { bar(*p as *mut u8, *p); }
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[inline(never)]
|
|
||||||
pub unsafe extern "C" fn bar(dest: *mut u8, src: *const u8) {
|
|
||||||
no_builtins::no_builtins(dest, src);
|
|
||||||
// should call `@llvm.memcpy`
|
|
||||||
foo::memcpy(dest, src, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[lang = "eh_personality"]
|
|
||||||
fn eh_personality() {}
|
|
||||||
|
@ -1,15 +1,2 @@
|
|||||||
#![feature(lang_items, no_core)]
|
|
||||||
#![no_std]
|
|
||||||
#![no_core]
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![no_builtins]
|
#![no_builtins]
|
||||||
|
|
||||||
extern crate foo;
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn no_builtins(dest: *mut u8, src: *const u8) {
|
|
||||||
// There should be no "undefined reference to `foo::foo'".
|
|
||||||
foo::foo(dest, src);
|
|
||||||
// should call `@memcpy` instead of `@llvm.memcpy`.
|
|
||||||
foo::memcpy(dest, src, 1024);
|
|
||||||
}
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
include ../tools.mk
|
|
||||||
|
|
||||||
# only-x86_64-unknown-linux-gnu
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) main.rs -o $(TMPDIR)/main
|
|
||||||
[ "$$("$(LLVM_BIN_DIR)"/llvm-nm -U $(TMPDIR)/main | grep -c __fixunssfti)" -eq "0" ]
|
|
@ -1 +0,0 @@
|
|||||||
fn main() {}
|
|
@ -8,8 +8,7 @@ fn my_panic(_info: &core::panic::PanicInfo) -> ! {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn multer(a: i128, b: i128) -> i128 {
|
pub fn multer(a: i128, b: i128) -> i128 {
|
||||||
// Trigger usage of the __multi3 compiler intrinsic which then leads to an imported function
|
// Trigger usage of the __multi3 compiler intrinsic which then leads to an imported
|
||||||
// such as panic or __multi3 (externally defined) in case of a bug. We verify that
|
// panic function in case of a bug. We verify that no imports exist in our verifier.
|
||||||
// no imports exist in our verifier.
|
|
||||||
a * b
|
a * b
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user