Skip to content

Commit e44906e

Browse files
committed
Auto merge of #52109 - michaelwoerister:ir-objs, r=alexcrichton
When doing linker-plugin based LTO, write LLVM bitcode obj-files instead of embedding the bitcode into the regular object file. This PR makes the compiler emit LLVM bitcode object files instead of regular object files with the IR embed when compiling for linker-plugin-based LTO. The reasoning for switching the strategy is this: - Embedding bitcode in a section of the object file actually makes us save bitcode twice in rlibs and Rust dylibs, once for linker-based LTO and once for rustc-based LTO. That's a waste of space. - When compiling for plugin-based LTO, one usually has no use for the machine code also present in the object file. Generating it is a waste of time. - When compiling for plugin-based LTO, `rustc` will skip running ThinLTO because the linker will do that anyway. This has the side effect of then generating poorly optimized machine code, which makes it even less useful (and may lead to users not knowing why their code is slow instead of getting an error). - Not having machine code available makes it impossible for the linker to silently fall back to not inlining stuff across language boundaries. - This is what Clang does and according to [the documentation](https://llvm.org/docs/BitCodeFormat.html#native-object-file-wrapper-format) is the better supported option. - The current behavior (minus the runtime performance problems) is still available via `-Z embed-bitcode` (we might want to do this for `libstd` at some point). r? @alexcrichton
2 parents 5a7e0f8 + 4a26964 commit e44906e

File tree

4 files changed

+28
-36
lines changed

4 files changed

+28
-36
lines changed

src/librustc/session/config.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,14 @@ pub enum Lto {
9999
pub enum CrossLangLto {
100100
LinkerPlugin(PathBuf),
101101
LinkerPluginAuto,
102-
NoLink,
103102
Disabled
104103
}
105104

106105
impl CrossLangLto {
107-
pub fn embed_bitcode(&self) -> bool {
106+
pub fn enabled(&self) -> bool {
108107
match *self {
109108
CrossLangLto::LinkerPlugin(_) |
110-
CrossLangLto::LinkerPluginAuto |
111-
CrossLangLto::NoLink => true,
109+
CrossLangLto::LinkerPluginAuto => true,
112110
CrossLangLto::Disabled => false,
113111
}
114112
}
@@ -1031,8 +1029,7 @@ macro_rules! options {
10311029
}
10321030

10331031
*slot = match v {
1034-
None |
1035-
Some("no-link") => CrossLangLto::NoLink,
1032+
None => CrossLangLto::LinkerPluginAuto,
10361033
Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)),
10371034
};
10381035
true
@@ -3165,7 +3162,7 @@ mod tests {
31653162
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
31663163

31673164
opts = reference.clone();
3168-
opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
3165+
opts.debugging_opts.cross_lang_lto = CrossLangLto::LinkerPluginAuto;
31693166
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
31703167
}
31713168

src/librustc_codegen_llvm/back/linker.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -471,8 +471,7 @@ impl<'a> Linker for GccLinker<'a> {
471471

472472
fn cross_lang_lto(&mut self) {
473473
match self.sess.opts.debugging_opts.cross_lang_lto {
474-
CrossLangLto::Disabled |
475-
CrossLangLto::NoLink => {
474+
CrossLangLto::Disabled => {
476475
// Nothing to do
477476
}
478477
CrossLangLto::LinkerPluginAuto => {

src/librustc_codegen_llvm/back/write.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,10 @@ impl ModuleConfig {
288288
self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
289289
self.time_passes = sess.time_passes();
290290
self.inline_threshold = sess.opts.cg.inline_threshold;
291-
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
291+
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode ||
292+
sess.opts.debugging_opts.cross_lang_lto.enabled();
292293
let embed_bitcode = sess.target.target.options.embed_bitcode ||
293-
sess.opts.debugging_opts.embed_bitcode ||
294-
sess.opts.debugging_opts.cross_lang_lto.embed_bitcode();
294+
sess.opts.debugging_opts.embed_bitcode;
295295
if embed_bitcode {
296296
match sess.opts.optimize {
297297
config::OptLevel::No |
@@ -1365,7 +1365,7 @@ fn execute_work_item(cgcx: &CodegenContext,
13651365
// Don't run LTO passes when cross-lang LTO is enabled. The linker
13661366
// will do that for us in this case.
13671367
let needs_lto = needs_lto &&
1368-
!cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode();
1368+
!cgcx.opts.debugging_opts.cross_lang_lto.enabled();
13691369

13701370
if needs_lto {
13711371
Ok(WorkItemResult::NeedsLTO(module))
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,49 @@
11

22
# min-llvm-version 4.0
3-
# ignore-mingw
3+
# ignore-msvc
44

55
-include ../tools.mk
66

7-
# This test makes sure that the expected .llvmbc sections for use by
8-
# linker-based LTO are available in object files when compiling with
9-
# -Z cross-lang-lto
7+
# This test makes sure that the object files we generate are actually
8+
# LLVM bitcode files (as used by linker LTO plugins) when compiling with
9+
# -Z cross-lang-lto.
1010

11-
LLVMBC_SECTION_NAME=\\.llvmbc
11+
ASSERT_IS_BITCODE_OBJ=llvm-bcanalyzer # this only succeeds for bitcode files
12+
EXTRACT_OBJS=(cd $(TMPDIR); rm -f ./*.o; llvm-ar x $(1))
1213

13-
ifeq ($(UNAME),Darwin)
14-
LLVMBC_SECTION_NAME=__bitcode
15-
endif
16-
17-
18-
OBJDUMP=llvm-objdump
19-
SECTION_HEADERS=$(OBJDUMP) -section-headers
20-
21-
BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1
22-
23-
BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 --emit=obj
14+
BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=on -Ccodegen-units=1
15+
BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=on -Ccodegen-units=1 --emit=obj
2416

2517
all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib
2618

2719
staticlib: lib.rs
2820
$(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib.a
29-
[ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
21+
$(call EXTRACT_OBJS, liblib.a)
22+
$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib.lib0.rcgu.o
3023

3124
staticlib-fat-lto: lib.rs
3225
$(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-fat-lto.a -Clto=fat
33-
[ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib-fat-lto.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
26+
$(call EXTRACT_OBJS, liblib-fat-lto.a)
27+
$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib-fat-lto.lib0.rcgu.o
3428

3529
staticlib-thin-lto: lib.rs
3630
$(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-thin-lto.a -Clto=thin
37-
[ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib-thin-lto.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
31+
$(call EXTRACT_OBJS, liblib-thin-lto.a)
32+
$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib-thin-lto.lib0.rcgu.o
3833

3934
rlib: lib.rs
4035
$(BUILD_LIB) --crate-type=rlib -o $(TMPDIR)/liblib.rlib
41-
[ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib.rlib | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
36+
$(call EXTRACT_OBJS, liblib.rlib)
37+
$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib.lib0.rcgu.o
4238

4339
cdylib: lib.rs
4440
$(BUILD_LIB) --crate-type=cdylib --emit=obj -o $(TMPDIR)/cdylib.o
45-
[ "$$($(SECTION_HEADERS) $(TMPDIR)/cdylib.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
41+
$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/cdylib.o
4642

4743
rdylib: lib.rs
4844
$(BUILD_LIB) --crate-type=dylib --emit=obj -o $(TMPDIR)/rdylib.o
49-
[ "$$($(SECTION_HEADERS) $(TMPDIR)/rdylib.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
45+
$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/rdylib.o
5046

5147
exe: lib.rs
5248
$(BUILD_EXE) -o $(TMPDIR)/exe.o
53-
[ "$$($(SECTION_HEADERS) $(TMPDIR)/exe.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
49+
$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/exe.o

0 commit comments

Comments
 (0)