Skip to content

Commit cfbbe70

Browse files
committed
Auto merge of rust-lang#113923 - DianQK:restore-no-builtins-lto, r=pnkfelix
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 09df610 + 665da1e commit cfbbe70

File tree

14 files changed

+219
-79
lines changed

14 files changed

+219
-79
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,6 @@ pub(crate) unsafe fn llvm_optimize(
563563
unroll_loops,
564564
config.vectorize_slp,
565565
config.vectorize_loop,
566-
config.no_builtins,
567566
config.emit_lifetime_markers,
568567
sanitizer_options.as_ref(),
569568
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
@@ -678,15 +677,14 @@ pub(crate) unsafe fn codegen(
678677
unsafe fn with_codegen<'ll, F, R>(
679678
tm: &'ll llvm::TargetMachine,
680679
llmod: &'ll llvm::Module,
681-
no_builtins: bool,
682680
f: F,
683681
) -> R
684682
where
685683
F: FnOnce(&'ll mut PassManager<'ll>) -> R,
686684
{
687685
let cpm = llvm::LLVMCreatePassManager();
688686
llvm::LLVMAddAnalysisPasses(tm, cpm);
689-
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
687+
llvm::LLVMRustAddLibraryInfo(cpm, llmod);
690688
f(cpm)
691689
}
692690

@@ -789,7 +787,7 @@ pub(crate) unsafe fn codegen(
789787
} else {
790788
llmod
791789
};
792-
with_codegen(tm, llmod, config.no_builtins, |cpm| {
790+
with_codegen(tm, llmod, |cpm| {
793791
write_output_file(
794792
diag_handler,
795793
tm,
@@ -824,7 +822,7 @@ pub(crate) unsafe fn codegen(
824822
(_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
825823
};
826824

827-
with_codegen(tm, llmod, config.no_builtins, |cpm| {
825+
with_codegen(tm, llmod, |cpm| {
828826
write_output_file(
829827
diag_handler,
830828
tm,

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -2139,13 +2139,8 @@ extern "C" {
21392139
ArgsCstrBuff: *const c_char,
21402140
ArgsCstrBuffLen: usize,
21412141
) -> *mut TargetMachine;
2142-
21432142
pub fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
2144-
pub fn LLVMRustAddLibraryInfo<'a>(
2145-
PM: &PassManager<'a>,
2146-
M: &'a Module,
2147-
DisableSimplifyLibCalls: bool,
2148-
);
2143+
pub fn LLVMRustAddLibraryInfo<'a>(PM: &PassManager<'a>, M: &'a Module);
21492144
pub fn LLVMRustWriteOutputFile<'a>(
21502145
T: &'a TargetMachine,
21512146
PM: &PassManager<'a>,
@@ -2167,7 +2162,6 @@ extern "C" {
21672162
UnrollLoops: bool,
21682163
SLPVectorize: bool,
21692164
LoopVectorize: bool,
2170-
DisableSimplifyLibCalls: bool,
21712165
EmitLifetimeMarkers: bool,
21722166
SanitizerOptions: Option<&SanitizerOptions>,
21732167
PGOGenPath: *const c_char,

compiler/rustc_codegen_ssa/src/back/link.rs

+4-32
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,7 @@ fn link_staticlib<'a>(
518518
&codegen_results.crate_info,
519519
Some(CrateType::Staticlib),
520520
&mut |cnum, path| {
521-
let lto = are_upstream_rust_objects_already_included(sess)
522-
&& !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
521+
let lto = are_upstream_rust_objects_already_included(sess);
523522

524523
let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter();
525524
let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, &lib));
@@ -1258,24 +1257,6 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
12581257
}
12591258
}
12601259

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

2773-
if !are_upstream_rust_objects_already_included(sess)
2774-
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum)
2775-
{
2750+
if !are_upstream_rust_objects_already_included(sess) {
27762751
link_upstream(cratepath);
27772752
return;
27782753
}
@@ -2786,8 +2761,6 @@ fn add_static_crate<'a>(
27862761
let canonical_name = name.replace('-', "_");
27872762
let upstream_rust_objects_already_included =
27882763
are_upstream_rust_objects_already_included(sess);
2789-
let is_builtins =
2790-
sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
27912764

27922765
let mut archive = archive_builder_builder.new_archive_builder(sess);
27932766
if let Err(error) = archive.add_archive(
@@ -2804,9 +2777,8 @@ fn add_static_crate<'a>(
28042777

28052778
// If we're performing LTO and this is a rust-generated object
28062779
// file, then we don't need the object file as it's part of the
2807-
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
2808-
// though, so we let that object file slide.
2809-
if upstream_rust_objects_already_included && is_rust_object && is_builtins {
2780+
// LTO module.
2781+
if upstream_rust_objects_already_included && is_rust_object {
28102782
return true;
28112783
}
28122784

compiler/rustc_codegen_ssa/src/back/write.rs

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

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

10381027
let mut each_linked_rlib_for_lto = Vec::new();
10391028
drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| {
1040-
if link::ignored_for_lto(sess, crate_info, cnum) {
1041-
return;
1042-
}
10431029
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
10441030
}));
10451031

compiler/rustc_codegen_ssa/src/base.rs

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

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+105-8
Original file line numberDiff line numberDiff line change
@@ -535,12 +535,9 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
535535

536536
// Unfortunately, the LLVM C API doesn't provide a way to create the
537537
// TargetLibraryInfo pass, so we use this method to do so.
538-
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
539-
bool DisableSimplifyLibCalls) {
538+
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M) {
540539
Triple TargetTriple(unwrap(M)->getTargetTriple());
541540
TargetLibraryInfoImpl TLII(TargetTriple);
542-
if (DisableSimplifyLibCalls)
543-
TLII.disableAllFunctions();
544541
unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII));
545542
}
546543

@@ -707,7 +704,7 @@ LLVMRustOptimize(
707704
bool IsLinkerPluginLTO,
708705
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
709706
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
710-
bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
707+
bool EmitLifetimeMarkers,
711708
LLVMRustSanitizerOptions *SanitizerOptions,
712709
const char *PGOGenPath, const char *PGOUsePath,
713710
bool InstrumentCoverage, const char *InstrProfileOutput,
@@ -813,8 +810,6 @@ LLVMRustOptimize(
813810

814811
Triple TargetTriple(TheModule->getTargetTriple());
815812
std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple));
816-
if (DisableSimplifyLibCalls)
817-
TLII->disableAllFunctions();
818813
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
819814

820815
PB.registerModuleAnalyses(MAM);
@@ -1125,6 +1120,102 @@ extern "C" void LLVMRustPrintPasses() {
11251120
PB.printPassNames(outs());
11261121
}
11271122

1123+
// from https://github.com/llvm/llvm-project/blob/7021182d6b43de9488ab70de626192ce70b3a4a6/llvm/lib/Object/IRSymtab.cpp#L48-L57
1124+
static const char *PreservedLibcallSymbols[] = {
1125+
#define HANDLE_LIBCALL(code, name) name,
1126+
#include "llvm/IR/RuntimeLibcalls.def"
1127+
#undef HANDLE_LIBCALL
1128+
// RuntimeLibcalls.def missing symbols.
1129+
"__ctzsi2",
1130+
"__ctzdi2",
1131+
"__ctzti2",
1132+
"__ffssi2",
1133+
"__ffsdi2",
1134+
"__ffsti2",
1135+
"__paritysi2",
1136+
"__paritydi2",
1137+
"__parityti2",
1138+
"__popcountsi2",
1139+
"__popcountdi2",
1140+
"__popcountti2",
1141+
"__bswapsi2",
1142+
"__bswapdi2",
1143+
"__negti2",
1144+
"__udivmoddi4",
1145+
"__udivmodti4",
1146+
"__udivmodsi4",
1147+
"__divmodsi4",
1148+
"__divmoddi4",
1149+
"__divmodti4",
1150+
"__absvsi2",
1151+
"__absvdi2",
1152+
"__absvti2",
1153+
"__negvsi2",
1154+
"__negvdi2",
1155+
"__negvti2",
1156+
"__addvsi3",
1157+
"__addvdi3",
1158+
"__addvti3",
1159+
"__subvsi3",
1160+
"__subvdi3",
1161+
"__subvti3",
1162+
"__mulvsi3",
1163+
"__mulvdi3",
1164+
"__mulvti3",
1165+
"__cmpdi2",
1166+
"__cmpti2",
1167+
"__ucmpdi2",
1168+
"__ucmpti2",
1169+
"__mulsc3",
1170+
"__muldc3",
1171+
"__mulxc3",
1172+
"__multc3",
1173+
"__divsc3",
1174+
"__divdc3",
1175+
"__divxc3",
1176+
"__divtc3",
1177+
"__clear_cache",
1178+
"__enable_execute_stack",
1179+
"__gcc_personality_v0",
1180+
"__eprintf",
1181+
"__emutls_get_address",
1182+
"__trampoline_setup",
1183+
"__addsf3vfp",
1184+
"__adddf3vfp",
1185+
"__divsf3vfp",
1186+
"__divdf3vfp",
1187+
"__eqsf2vfp",
1188+
"__eqdf2vfp",
1189+
"__extendsfdf2vfp",
1190+
"__fixdfsivfp",
1191+
"__fixsfsivfp",
1192+
"__fixunssfsivfp",
1193+
"__fixunsdfsivfp",
1194+
"__floatsidfvfp",
1195+
"__floatsisfvfp",
1196+
"__floatunssidfvfp",
1197+
"__floatunssisfvfp",
1198+
"__gedf2vfp",
1199+
"__gesf2vfp",
1200+
"__gtdf2vfp",
1201+
"__gtsf2vfp",
1202+
"__ledf2vfp",
1203+
"__lesf2vfp",
1204+
"__ltdf2vfp",
1205+
"__ltsf2vfp",
1206+
"__muldf3vfp",
1207+
"__mulsf3vfp",
1208+
"__nedf2vfp",
1209+
"__negdf2vfp",
1210+
"__negsf2vfp",
1211+
"__negsf2vfp",
1212+
"__subdf3vfp",
1213+
"__subsf3vfp",
1214+
"__truncdfsf2vfp",
1215+
"__unorddf2vfp",
1216+
"__unordsf2vfp",
1217+
};
1218+
11281219
extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
11291220
size_t Len) {
11301221
auto PreserveFunctions = [=](const GlobalValue &GV) {
@@ -1140,7 +1231,7 @@ extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
11401231
return true;
11411232
}
11421233
}
1143-
return false;
1234+
return llvm::is_contained(PreservedLibcallSymbols, GV.getName());
11441235
};
11451236

11461237
internalizeModule(*unwrap(M), PreserveFunctions);
@@ -1298,6 +1389,12 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
12981389
auto GUID = GlobalValue::getGUID(preserved_symbols[i]);
12991390
Ret->GUIDPreservedSymbols.insert(GUID);
13001391
}
1392+
for (int i = 0; i < sizeof(PreservedLibcallSymbols) / sizeof(PreservedLibcallSymbols[0]); i++) {
1393+
if (auto *PreservedLibcallSymbol = PreservedLibcallSymbols[i]) {
1394+
auto GUID = GlobalValue::getGUID(PreservedLibcallSymbol);
1395+
Ret->GUIDPreservedSymbols.insert(GUID);
1396+
}
1397+
}
13011398

13021399
// Collect the import/export lists for all modules from the call-graph in the
13031400
// combined index
+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 @no_builtins
3+
CHECK-NEXT: call void @llvm.memcpy
4+
5+
CHECK: define{{.*}} i32 @main
6+
CHECK: call void @bar
7+
8+
CHECK: define{{.*}} void @foo
9+
CHECK-NEXT: call void @llvm.memcpy
10+
11+
CHECK: define{{.*}} void @no_builtins
12+
CHECK-SAME: #[[ATTR:[0-9]+]] {
13+
CHECK: call void @foo
14+
CHECK-NEXT: call{{.*}} @memcpy
15+
16+
CHECK: attributes #[[ATTR]]
17+
CHECK-SAME: no-builtins

0 commit comments

Comments
 (0)