Skip to content

Commit

Permalink
Auto merge of rust-lang#52109 - michaelwoerister:ir-objs, r=alexcrichton
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Jul 7, 2018
2 parents 5a7e0f8 + 4a26964 commit e44906e
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 36 deletions.
11 changes: 4 additions & 7 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,14 @@ pub enum Lto {
pub enum CrossLangLto {
LinkerPlugin(PathBuf),
LinkerPluginAuto,
NoLink,
Disabled
}

impl CrossLangLto {
pub fn embed_bitcode(&self) -> bool {
pub fn enabled(&self) -> bool {
match *self {
CrossLangLto::LinkerPlugin(_) |
CrossLangLto::LinkerPluginAuto |
CrossLangLto::NoLink => true,
CrossLangLto::LinkerPluginAuto => true,
CrossLangLto::Disabled => false,
}
}
Expand Down Expand Up @@ -1031,8 +1029,7 @@ macro_rules! options {
}

*slot = match v {
None |
Some("no-link") => CrossLangLto::NoLink,
None => CrossLangLto::LinkerPluginAuto,
Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)),
};
true
Expand Down Expand Up @@ -3165,7 +3162,7 @@ mod tests {
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());

opts = reference.clone();
opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
opts.debugging_opts.cross_lang_lto = CrossLangLto::LinkerPluginAuto;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
}

Expand Down
3 changes: 1 addition & 2 deletions src/librustc_codegen_llvm/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,7 @@ impl<'a> Linker for GccLinker<'a> {

fn cross_lang_lto(&mut self) {
match self.sess.opts.debugging_opts.cross_lang_lto {
CrossLangLto::Disabled |
CrossLangLto::NoLink => {
CrossLangLto::Disabled => {
// Nothing to do
}
CrossLangLto::LinkerPluginAuto => {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_codegen_llvm/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,10 @@ impl ModuleConfig {
self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
self.time_passes = sess.time_passes();
self.inline_threshold = sess.opts.cg.inline_threshold;
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode ||
sess.opts.debugging_opts.cross_lang_lto.enabled();
let embed_bitcode = sess.target.target.options.embed_bitcode ||
sess.opts.debugging_opts.embed_bitcode ||
sess.opts.debugging_opts.cross_lang_lto.embed_bitcode();
sess.opts.debugging_opts.embed_bitcode;
if embed_bitcode {
match sess.opts.optimize {
config::OptLevel::No |
Expand Down Expand Up @@ -1365,7 +1365,7 @@ fn execute_work_item(cgcx: &CodegenContext,
// Don't run LTO passes when cross-lang LTO is enabled. The linker
// will do that for us in this case.
let needs_lto = needs_lto &&
!cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode();
!cgcx.opts.debugging_opts.cross_lang_lto.enabled();

if needs_lto {
Ok(WorkItemResult::NeedsLTO(module))
Expand Down
42 changes: 19 additions & 23 deletions src/test/run-make-fulldeps/cross-lang-lto/Makefile
Original file line number Diff line number Diff line change
@@ -1,53 +1,49 @@

# min-llvm-version 4.0
# ignore-mingw
# ignore-msvc

-include ../tools.mk

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

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

ifeq ($(UNAME),Darwin)
LLVMBC_SECTION_NAME=__bitcode
endif


OBJDUMP=llvm-objdump
SECTION_HEADERS=$(OBJDUMP) -section-headers

BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1

BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 --emit=obj
BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=on -Ccodegen-units=1
BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=on -Ccodegen-units=1 --emit=obj

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

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

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

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

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

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

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

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

0 comments on commit e44906e

Please sign in to comment.