Skip to content

Commit 807017a

Browse files
committed
Auto merge of rust-lang#113923 - DianQK:restore-no-builtins-lto, r=<try>
Restore `#![no_builtins]` crates participation in LTO. After rust-lang#113716, we can make `#![no_builtins]` crates participate in LTO again. `#![no_builtins]` with LTO does not result in undefined references to the error. I believe this type of issue won't happen again. \(^▽^)/ I will test the following issues later to verify. The task format is `Fixes {issue} {nightly-2023-07-20 result} {PR rust-lang#113923 result}`. - [x] Fixes rust-lang#72140. ❌ ✅ - [x] Fixes rust-lang#112245. ❌ ✅ - [x] Fixes rust-lang#110606. ❌ ✅ - [ ] Fixes rust-lang#105734. - [ ] Fixes rust-lang#96486. - [ ] Fixes rust-lang#108853. - [x] Fixes rust-lang/compiler-builtins#347. ❌ ✅ - [ ] Fixes rust-lang#108893. - [ ] Fixes rust-lang#78744. Fixes rust-lang#91158. Fixes rust-lang/cargo#10118. The `nightly-2023-07-20` version does not always reproduce problems due to changes in compiler-builtins, core, and user code. That's why this issue recurs and disappears. Some issues were not tested due to the difficulty of reproducing them. r? pnkfelix cc `@bjorn3` `@japaric` `@alexcrichton` `@Amanieu`
2 parents df63c5f + f7751fa commit 807017a

File tree

15 files changed

+152
-78
lines changed

15 files changed

+152
-78
lines changed

compiler/rustc_codegen_llvm/src/back/lto.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,24 @@ pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
4141
}
4242
}
4343

44+
fn get_llvm_preserved_symbols() -> Vec<String> {
45+
let mut len = 0;
46+
unsafe {
47+
let symbols = llvm::LLVMRustPreservedSymbols(&mut len);
48+
let symbols: &[*const _] = slice::from_raw_parts(symbols, len);
49+
symbols
50+
.iter()
51+
.filter_map(|&symbol| {
52+
if symbol.is_null() {
53+
None
54+
} else {
55+
Some(String::from_utf8(CStr::from_ptr(symbol).to_bytes().to_vec()).unwrap())
56+
}
57+
})
58+
.collect()
59+
}
60+
}
61+
4462
fn prepare_lto(
4563
cgcx: &CodegenContext<LlvmCodegenBackend>,
4664
diag_handler: &Handler,
@@ -55,8 +73,13 @@ fn prepare_lto(
5573
Lto::No => panic!("didn't request LTO but we're doing LTO"),
5674
};
5775

76+
let llvm_reserved_symbols = get_llvm_preserved_symbols();
77+
5878
let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
59-
if info.level.is_below_threshold(export_threshold) || info.used {
79+
if info.level.is_below_threshold(export_threshold)
80+
|| info.used
81+
|| llvm_reserved_symbols.contains(name)
82+
{
6083
Some(CString::new(name.as_str()).unwrap())
6184
} else {
6285
None

compiler/rustc_codegen_llvm/src/back/write.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,6 @@ pub(crate) unsafe fn llvm_optimize(
558558
unroll_loops,
559559
config.vectorize_slp,
560560
config.vectorize_loop,
561-
config.no_builtins,
562561
config.emit_lifetime_markers,
563562
sanitizer_options.as_ref(),
564563
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
@@ -673,15 +672,14 @@ pub(crate) unsafe fn codegen(
673672
unsafe fn with_codegen<'ll, F, R>(
674673
tm: &'ll llvm::TargetMachine,
675674
llmod: &'ll llvm::Module,
676-
no_builtins: bool,
677675
f: F,
678676
) -> R
679677
where
680678
F: FnOnce(&'ll mut PassManager<'ll>) -> R,
681679
{
682680
let cpm = llvm::LLVMCreatePassManager();
683681
llvm::LLVMAddAnalysisPasses(tm, cpm);
684-
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
682+
llvm::LLVMRustAddLibraryInfo(cpm, llmod);
685683
f(cpm)
686684
}
687685

@@ -784,7 +782,7 @@ pub(crate) unsafe fn codegen(
784782
} else {
785783
llmod
786784
};
787-
with_codegen(tm, llmod, config.no_builtins, |cpm| {
785+
with_codegen(tm, llmod, |cpm| {
788786
write_output_file(
789787
diag_handler,
790788
tm,
@@ -819,7 +817,7 @@ pub(crate) unsafe fn codegen(
819817
(_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
820818
};
821819

822-
with_codegen(tm, llmod, config.no_builtins, |cpm| {
820+
with_codegen(tm, llmod, |cpm| {
823821
write_output_file(
824822
diag_handler,
825823
tm,

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -2138,11 +2138,7 @@ extern "C" {
21382138
) -> Option<&'static mut TargetMachine>;
21392139

21402140
pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
2141-
pub fn LLVMRustAddLibraryInfo<'a>(
2142-
PM: &PassManager<'a>,
2143-
M: &'a Module,
2144-
DisableSimplifyLibCalls: bool,
2145-
);
2141+
pub fn LLVMRustAddLibraryInfo<'a>(PM: &PassManager<'a>, M: &'a Module);
21462142
pub fn LLVMRustWriteOutputFile<'a>(
21472143
T: &'a TargetMachine,
21482144
PM: &PassManager<'a>,
@@ -2164,7 +2160,6 @@ extern "C" {
21642160
UnrollLoops: bool,
21652161
SLPVectorize: bool,
21662162
LoopVectorize: bool,
2167-
DisableSimplifyLibCalls: bool,
21682163
EmitLifetimeMarkers: bool,
21692164
SanitizerOptions: Option<&SanitizerOptions>,
21702165
PGOGenPath: *const c_char,
@@ -2190,6 +2185,7 @@ extern "C" {
21902185
pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
21912186
pub fn LLVMRustPrintPasses();
21922187
pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
2188+
pub fn LLVMRustPreservedSymbols(len: *mut usize) -> *const *const c_char;
21932189
pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
21942190

21952191
pub fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;

compiler/rustc_codegen_ssa/src/back/link.rs

+4-32
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,7 @@ fn link_staticlib<'a>(
516516
&codegen_results.crate_info,
517517
Some(CrateType::Staticlib),
518518
&mut |cnum, path| {
519-
let lto = are_upstream_rust_objects_already_included(sess)
520-
&& !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
519+
let lto = are_upstream_rust_objects_already_included(sess);
521520

522521
let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter();
523522
let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, &lib));
@@ -1256,24 +1255,6 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
12561255
}
12571256
}
12581257

1259-
/// Returns a boolean indicating whether the specified crate should be ignored
1260-
/// during LTO.
1261-
///
1262-
/// Crates ignored during LTO are not lumped together in the "massive object
1263-
/// file" that we create and are linked in their normal rlib states. See
1264-
/// comments below for what crates do not participate in LTO.
1265-
///
1266-
/// It's unusual for a crate to not participate in LTO. Typically only
1267-
/// compiler-specific and unstable crates have a reason to not participate in
1268-
/// LTO.
1269-
pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool {
1270-
// If our target enables builtin function lowering in LLVM then the
1271-
// crates providing these functions don't participate in LTO (e.g.
1272-
// no_builtins or compiler builtins crates).
1273-
!sess.target.no_builtins
1274-
&& (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
1275-
}
1276-
12771258
/// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
12781259
pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
12791260
fn infer_from(
@@ -2739,10 +2720,6 @@ fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf {
27392720
// symbols). We must continue to include the rest of the rlib, however, as
27402721
// it may contain static native libraries which must be linked in.
27412722
//
2742-
// (*) Crates marked with `#![no_builtins]` don't participate in LTO and
2743-
// their bytecode wasn't included. The object files in those libraries must
2744-
// still be passed to the linker.
2745-
//
27462723
// Note, however, that if we're not doing LTO we can just pass the rlib
27472724
// blindly to the linker (fast) because it's fine if it's not actually
27482725
// included as we're at the end of the dependency chain.
@@ -2768,9 +2745,7 @@ fn add_static_crate<'a>(
27682745
cmd.link_rlib(&rlib_path);
27692746
};
27702747

2771-
if !are_upstream_rust_objects_already_included(sess)
2772-
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum)
2773-
{
2748+
if !are_upstream_rust_objects_already_included(sess) {
27742749
link_upstream(cratepath);
27752750
return;
27762751
}
@@ -2784,8 +2759,6 @@ fn add_static_crate<'a>(
27842759
let canonical_name = name.replace('-', "_");
27852760
let upstream_rust_objects_already_included =
27862761
are_upstream_rust_objects_already_included(sess);
2787-
let is_builtins =
2788-
sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
27892762

27902763
let mut archive = archive_builder_builder.new_archive_builder(sess);
27912764
if let Err(error) = archive.add_archive(
@@ -2802,9 +2775,8 @@ fn add_static_crate<'a>(
28022775

28032776
// If we're performing LTO and this is a rust-generated object
28042777
// file, then we don't need the object file as it's part of the
2805-
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
2806-
// though, so we let that object file slide.
2807-
if upstream_rust_objects_already_included && is_rust_object && is_builtins {
2778+
// LTO module.
2779+
if upstream_rust_objects_already_included && is_rust_object {
28082780
return true;
28092781
}
28102782

compiler/rustc_codegen_ssa/src/back/write.rs

+1-15
Original file line numberDiff line numberDiff line change
@@ -149,23 +149,12 @@ impl ModuleConfig {
149149

150150
let emit_obj = if !should_emit_obj {
151151
EmitObj::None
152-
} else if sess.target.obj_is_bitcode
153-
|| (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins)
154-
{
152+
} else if sess.target.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled() {
155153
// This case is selected if the target uses objects as bitcode, or
156154
// if linker plugin LTO is enabled. In the linker plugin LTO case
157155
// the assumption is that the final link-step will read the bitcode
158156
// and convert it to object code. This may be done by either the
159157
// native linker or rustc itself.
160-
//
161-
// Note, however, that the linker-plugin-lto requested here is
162-
// explicitly ignored for `#![no_builtins]` crates. These crates are
163-
// specifically ignored by rustc's LTO passes and wouldn't work if
164-
// loaded into the linker. These crates define symbols that LLVM
165-
// lowers intrinsics to, and these symbol dependencies aren't known
166-
// until after codegen. As a result any crate marked
167-
// `#![no_builtins]` is assumed to not participate in LTO and
168-
// instead goes on to generate object code.
169158
EmitObj::Bitcode
170159
} else if need_bitcode_in_object(tcx) {
171160
EmitObj::ObjectCode(BitcodeSection::Full)
@@ -1033,9 +1022,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
10331022

10341023
let mut each_linked_rlib_for_lto = Vec::new();
10351024
drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| {
1036-
if link::ignored_for_lto(sess, crate_info, cnum) {
1037-
return;
1038-
}
10391025
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
10401026
}));
10411027

compiler/rustc_codegen_ssa/src/base.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -870,9 +870,7 @@ impl CrateInfo {
870870
// If global LTO is enabled then almost everything (*) is glued into a single object file,
871871
// so this logic is not necessary and can cause issues on some targets (due to weak lang
872872
// item symbols being "privatized" to that object file), so we disable it.
873-
// (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued,
874-
// and we assume that they cannot define weak lang items. This is not currently enforced
875-
// by the compiler, but that's ok because all this stuff is unstable anyway.
873+
// (*) Native libs are not glued, and we assume that they cannot define weak lang items.
876874
let target = &tcx.sess.target;
877875
if !are_upstream_rust_objects_already_included(tcx.sess) {
878876
let missing_weak_lang_items: FxHashSet<Symbol> = info

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+16-7
Original file line numberDiff line numberDiff line change
@@ -525,12 +525,9 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
525525

526526
// Unfortunately, the LLVM C API doesn't provide a way to create the
527527
// TargetLibraryInfo pass, so we use this method to do so.
528-
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
529-
bool DisableSimplifyLibCalls) {
528+
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M) {
530529
Triple TargetTriple(unwrap(M)->getTargetTriple());
531530
TargetLibraryInfoImpl TLII(TargetTriple);
532-
if (DisableSimplifyLibCalls)
533-
TLII.disableAllFunctions();
534531
unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII));
535532
}
536533

@@ -689,7 +686,7 @@ LLVMRustOptimize(
689686
bool IsLinkerPluginLTO,
690687
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
691688
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
692-
bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
689+
bool EmitLifetimeMarkers,
693690
LLVMRustSanitizerOptions *SanitizerOptions,
694691
const char *PGOGenPath, const char *PGOUsePath,
695692
bool InstrumentCoverage, const char *InstrProfileOutput,
@@ -781,8 +778,6 @@ LLVMRustOptimize(
781778

782779
Triple TargetTriple(TheModule->getTargetTriple());
783780
std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple));
784-
if (DisableSimplifyLibCalls)
785-
TLII->disableAllFunctions();
786781
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
787782

788783
PB.registerModuleAnalyses(MAM);
@@ -1107,6 +1102,20 @@ extern "C" void LLVMRustPrintPasses() {
11071102
PB.printPassNames(outs());
11081103
}
11091104

1105+
// from https://github.com/llvm/llvm-project/blob/7021182d6b43de9488ab70de626192ce70b3a4a6/llvm/lib/Object/IRSymtab.cpp#L48-L57
1106+
static const char *PreservedSymbols[] = {
1107+
#define HANDLE_LIBCALL(code, name) name,
1108+
#include "llvm/IR/RuntimeLibcalls.def"
1109+
#undef HANDLE_LIBCALL
1110+
"__ssp_canary_word",
1111+
"__stack_chk_guard",
1112+
};
1113+
1114+
extern "C" const char **LLVMRustPreservedSymbols(size_t *len) {
1115+
*len = sizeof(PreservedSymbols) / sizeof(PreservedSymbols[0]);
1116+
return PreservedSymbols;
1117+
}
1118+
11101119
extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
11111120
size_t Len) {
11121121
auto PreserveFunctions = [=](const GlobalValue &GV) {
+12-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
include ../tools.mk
22

3+
# only-x86_64
4+
5+
# We want to check that `no_builtins` is correctly participating in LTO.
6+
# First, verify that the `foo::foo` symbol can be found when linking.
7+
# Next, verify that `memcpy` can be customized using `no_builtins` under LTO.
8+
# Others will use the built-in memcpy.
9+
310
all:
4-
# Compile a `#![no_builtins]` rlib crate
5-
$(RUSTC) no_builtins.rs
6-
# Build an executable that depends on that crate using LTO. The no_builtins crate doesn't
7-
# participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by
8-
# grepping the linker arguments.
9-
$(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib'
11+
$(RUSTC) -C linker-plugin-lto -C opt-level=2 -C debuginfo=0 foo.rs
12+
$(RUSTC) -C linker-plugin-lto -C opt-level=2 -C debuginfo=0 no_builtins.rs
13+
$(RUSTC) main.rs -C lto -C opt-level=2 -C debuginfo=0 -C save-temps -C metadata=1 -C codegen-units=1
14+
$(LLVM_BIN_DIR)/llvm-dis $(TMPDIR)/main.main.*-cgu.0.rcgu.lto.input.bc -o $(TMPDIR)/lto.ll
15+
cat "$(TMPDIR)"/lto.ll | "$(LLVM_FILECHECK)" filecheck.lto.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CHECK: define{{.*}} void @bar
2+
CHECK-NEXT: call void @_ZN11no_builtins11no_builtins17hcda8eeb3c587012fE
3+
CHECK-NEXT: call void @llvm.memcpy
4+
5+
CHECK: define{{.*}} i32 @main
6+
CHECK: call void @bar
7+
8+
CHECK: define{{.*}} void @_ZN3foo3foo17hfad400915e51b713E
9+
CHECK-NEXT: call void @llvm.memcpy
10+
11+
CHECK: define{{.*}} void @_ZN11no_builtins11no_builtins17hcda8eeb3c587012fE
12+
CHECK-SAME: #[[ATTR:[0-9]+]] {
13+
CHECK: call void @_ZN3foo3foo17hfad400915e51b713E
14+
CHECK-NEXT: call{{.*}} @memcpy
15+
16+
CHECK: attributes #[[ATTR]]
17+
CHECK-SAME: no-builtins

tests/run-make/no-builtins-lto/foo.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![feature(lang_items, no_core)]
2+
#![no_std]
3+
#![no_core]
4+
#![crate_type = "lib"]
5+
6+
#[inline(never)]
7+
pub unsafe fn foo(dest: *mut u8, src: *const u8) {
8+
// should call `@llvm.memcpy`.
9+
memcpy(dest, src, 1024);
10+
}
11+
12+
#[no_mangle]
13+
#[inline(never)]
14+
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, _n: usize) -> *mut u8 {
15+
*dest = 0;
16+
return src as *mut u8;
17+
}
18+
19+
#[lang = "sized"]
20+
trait Sized {}
21+
#[lang = "copy"]
22+
trait Copy {}
23+
impl Copy for *mut u8 {}
24+
impl Copy for *const u8 {}
25+
26+
#[lang = "drop_in_place"]
27+
#[allow(unconditional_recursion)]
28+
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
29+
// Code here does not matter - this is replaced by the
30+
// real drop glue by the compiler.
31+
drop_in_place(to_drop);
32+
}
+26-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
1+
#![feature(no_core, start, lang_items)]
2+
#![no_std]
3+
// We use `no_core` to reduce the LTO products is small enough.
4+
#![no_core]
5+
16
extern crate no_builtins;
7+
extern crate foo;
8+
9+
#[link(name = "c")]
10+
extern "C" {}
11+
12+
#[start]
13+
fn main(_: isize, p: *const *const u8) -> isize {
14+
// Make sure the symbols are retained.
15+
unsafe { bar(*p as *mut u8, *p); }
16+
0
17+
}
18+
19+
#[no_mangle]
20+
#[inline(never)]
21+
pub unsafe extern "C" fn bar(dest: *mut u8, src: *const u8) {
22+
no_builtins::no_builtins(dest, src);
23+
// should call `@llvm.memcpy`
24+
foo::memcpy(dest, src, 1024);
25+
}
226

3-
fn main() {}
27+
#[lang = "eh_personality"]
28+
fn eh_personality() {}

0 commit comments

Comments
 (0)