Skip to content

Commit 6fe4467

Browse files
committed
rollup merge of #17358 : epdtry/pcg-lto
2 parents a116c72 + ed476b0 commit 6fe4467

File tree

4 files changed

+120
-107
lines changed

4 files changed

+120
-107
lines changed

src/librustc/back/link.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -659,19 +659,18 @@ fn link_rlib<'a>(sess: &'a Session,
659659
ab.add_file(&metadata).unwrap();
660660
remove(sess, &metadata);
661661

662-
if sess.opts.cg.codegen_units == 1 {
663-
// For LTO purposes, the bytecode of this library is also
664-
// inserted into the archive. We currently do this only when
665-
// codegen_units == 1, so we don't have to deal with multiple
666-
// bitcode files per crate.
667-
//
662+
// For LTO purposes, the bytecode of this library is also inserted
663+
// into the archive. If codegen_units > 1, we insert each of the
664+
// bitcode files.
665+
for i in range(0, sess.opts.cg.codegen_units) {
668666
// Note that we make sure that the bytecode filename in the
669667
// archive is never exactly 16 bytes long by adding a 16 byte
670668
// extension to it. This is to work around a bug in LLDB that
671669
// would cause it to crash if the name of a file in an archive
672670
// was exactly 16 bytes.
673-
let bc_filename = obj_filename.with_extension("bc");
674-
let bc_deflated_filename = obj_filename.with_extension("bytecode.deflate");
671+
let bc_filename = obj_filename.with_extension(format!("{}.bc", i).as_slice());
672+
let bc_deflated_filename = obj_filename.with_extension(
673+
format!("{}.bytecode.deflate", i).as_slice());
675674

676675
let bc_data = match fs::File::open(&bc_filename).read_to_end() {
677676
Ok(buffer) => buffer,
@@ -705,8 +704,13 @@ fn link_rlib<'a>(sess: &'a Session,
705704

706705
ab.add_file(&bc_deflated_filename).unwrap();
707706
remove(sess, &bc_deflated_filename);
708-
if !sess.opts.cg.save_temps &&
709-
!sess.opts.output_types.contains(&OutputTypeBitcode) {
707+
708+
// See the bottom of back::write::run_passes for an explanation
709+
// of when we do and don't keep .0.bc files around.
710+
let user_wants_numbered_bitcode =
711+
sess.opts.output_types.contains(&OutputTypeBitcode) &&
712+
sess.opts.cg.codegen_units > 1;
713+
if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
710714
remove(sess, &bc_filename);
711715
}
712716
}

src/librustc/back/lto.rs

Lines changed: 72 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use util::common::time;
2121
use libc;
2222
use flate;
2323

24+
use std::iter;
2425
use std::mem;
2526

2627
pub fn run(sess: &session::Session, llmod: ModuleRef,
@@ -60,78 +61,84 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
6061
let file = path.filename_str().unwrap();
6162
let file = file.slice(3, file.len() - 5); // chop off lib/.rlib
6263
debug!("reading {}", file);
63-
let bc_encoded = time(sess.time_passes(),
64-
format!("read {}.bytecode.deflate", name).as_slice(),
65-
(),
66-
|_| {
67-
archive.read(format!("{}.bytecode.deflate",
68-
file).as_slice())
69-
});
70-
let bc_encoded = match bc_encoded {
71-
Some(data) => data,
72-
None => {
73-
sess.fatal(format!("missing compressed bytecode in {} \
74-
(perhaps it was compiled with -C codegen-units > 1)",
75-
path.display()).as_slice());
76-
},
77-
};
78-
let bc_extractor = if is_versioned_bytecode_format(bc_encoded) {
79-
|_| {
80-
// Read the version
81-
let version = extract_bytecode_format_version(bc_encoded);
82-
83-
if version == 1 {
84-
// The only version existing so far
85-
let data_size = extract_compressed_bytecode_size_v1(bc_encoded);
86-
let compressed_data = bc_encoded.slice(
87-
link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET,
88-
link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as uint);
89-
90-
match flate::inflate_bytes(compressed_data) {
91-
Some(inflated) => inflated,
64+
for i in iter::count(0u, 1) {
65+
let bc_encoded = time(sess.time_passes(),
66+
format!("check for {}.{}.bytecode.deflate", name, i).as_slice(),
67+
(),
68+
|_| {
69+
archive.read(format!("{}.{}.bytecode.deflate",
70+
file, i).as_slice())
71+
});
72+
let bc_encoded = match bc_encoded {
73+
Some(data) => data,
74+
None => {
75+
if i == 0 {
76+
// No bitcode was found at all.
77+
sess.fatal(format!("missing compressed bytecode in {}",
78+
path.display()).as_slice());
79+
}
80+
// No more bitcode files to read.
81+
break;
82+
},
83+
};
84+
let bc_extractor = if is_versioned_bytecode_format(bc_encoded) {
85+
|_| {
86+
// Read the version
87+
let version = extract_bytecode_format_version(bc_encoded);
88+
89+
if version == 1 {
90+
// The only version existing so far
91+
let data_size = extract_compressed_bytecode_size_v1(bc_encoded);
92+
let compressed_data = bc_encoded.slice(
93+
link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET,
94+
link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as uint);
95+
96+
match flate::inflate_bytes(compressed_data) {
97+
Some(inflated) => inflated,
98+
None => {
99+
sess.fatal(format!("failed to decompress bc of `{}`",
100+
name).as_slice())
101+
}
102+
}
103+
} else {
104+
sess.fatal(format!("Unsupported bytecode format version {}",
105+
version).as_slice())
106+
}
107+
}
108+
} else {
109+
// the object must be in the old, pre-versioning format, so simply
110+
// inflate everything and let LLVM decide if it can make sense of it
111+
|_| {
112+
match flate::inflate_bytes(bc_encoded) {
113+
Some(bc) => bc,
92114
None => {
93115
sess.fatal(format!("failed to decompress bc of `{}`",
94116
name).as_slice())
95117
}
96118
}
97-
} else {
98-
sess.fatal(format!("Unsupported bytecode format version {}",
99-
version).as_slice())
100119
}
101-
}
102-
} else {
103-
// the object must be in the old, pre-versioning format, so simply
104-
// inflate everything and let LLVM decide if it can make sense of it
105-
|_| {
106-
match flate::inflate_bytes(bc_encoded) {
107-
Some(bc) => bc,
108-
None => {
109-
sess.fatal(format!("failed to decompress bc of `{}`",
110-
name).as_slice())
111-
}
120+
};
121+
122+
let bc_decoded = time(sess.time_passes(),
123+
format!("decode {}.{}.bc", file, i).as_slice(),
124+
(),
125+
bc_extractor);
126+
127+
let ptr = bc_decoded.as_slice().as_ptr();
128+
debug!("linking {}, part {}", name, i);
129+
time(sess.time_passes(),
130+
format!("ll link {}.{}", name, i).as_slice(),
131+
(),
132+
|()| unsafe {
133+
if !llvm::LLVMRustLinkInExternalBitcode(llmod,
134+
ptr as *const libc::c_char,
135+
bc_decoded.len() as libc::size_t) {
136+
write::llvm_err(sess.diagnostic().handler(),
137+
format!("failed to load bc of `{}`",
138+
name.as_slice()));
112139
}
113-
}
114-
};
115-
116-
let bc_decoded = time(sess.time_passes(),
117-
format!("decode {}.bc", file).as_slice(),
118-
(),
119-
bc_extractor);
120-
121-
let ptr = bc_decoded.as_slice().as_ptr();
122-
debug!("linking {}", name);
123-
time(sess.time_passes(),
124-
format!("ll link {}", name).as_slice(),
125-
(),
126-
|()| unsafe {
127-
if !llvm::LLVMRustLinkInExternalBitcode(llmod,
128-
ptr as *const libc::c_char,
129-
bc_decoded.len() as libc::size_t) {
130-
write::llvm_err(sess.diagnostic().handler(),
131-
format!("failed to load bc of `{}`",
132-
name.as_slice()));
133-
}
134-
});
140+
});
141+
}
135142
}
136143

137144
// Internalize everything but the reachable symbols of the current module

src/librustc/back/write.rs

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -540,13 +540,12 @@ pub fn run_passes(sess: &Session,
540540
metadata_config.emit_bc = true;
541541
}
542542

543-
// Emit a bitcode file for the crate if we're emitting an rlib.
543+
// Emit bitcode files for the crate if we're emitting an rlib.
544544
// Whenever an rlib is created, the bitcode is inserted into the
545545
// archive in order to allow LTO against it.
546546
let needs_crate_bitcode =
547547
sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
548-
sess.opts.output_types.contains(&OutputTypeExe) &&
549-
sess.opts.cg.codegen_units == 1;
548+
sess.opts.output_types.contains(&OutputTypeExe);
550549
if needs_crate_bitcode {
551550
modules_config.emit_bc = true;
552551
}
@@ -602,19 +601,8 @@ pub fn run_passes(sess: &Session,
602601
// Process the work items, optionally using worker threads.
603602
if sess.opts.cg.codegen_units == 1 {
604603
run_work_singlethreaded(sess, trans.reachable.as_slice(), work_items);
605-
606-
if needs_crate_bitcode {
607-
// The only bitcode file produced (aside from metadata) was
608-
// "crate.0.bc". Rename to "crate.bc" since that's what
609-
// `link_rlib` expects to find.
610-
fs::copy(&crate_output.with_extension("0.bc"),
611-
&crate_output.temp_path(OutputTypeBitcode)).unwrap();
612-
}
613604
} else {
614605
run_work_multithreaded(sess, work_items, sess.opts.cg.codegen_units);
615-
616-
assert!(!needs_crate_bitcode,
617-
"can't produce a crate bitcode file from multiple compilation units");
618606
}
619607

620608
// All codegen is finished.
@@ -624,14 +612,14 @@ pub fn run_passes(sess: &Session,
624612

625613
// Produce final compile outputs.
626614

627-
let copy_if_one_unit = |ext: &str, output_type: OutputType| {
615+
let copy_if_one_unit = |ext: &str, output_type: OutputType, keep_numbered: bool| {
628616
// Three cases:
629617
if sess.opts.cg.codegen_units == 1 {
630618
// 1) Only one codegen unit. In this case it's no difficulty
631619
// to copy `foo.0.x` to `foo.x`.
632620
fs::copy(&crate_output.with_extension(ext),
633621
&crate_output.path(output_type)).unwrap();
634-
if !sess.opts.cg.save_temps {
622+
if !sess.opts.cg.save_temps && !keep_numbered {
635623
// The user just wants `foo.x`, not `foo.0.x`.
636624
remove(sess, &crate_output.with_extension(ext));
637625
}
@@ -716,17 +704,18 @@ pub fn run_passes(sess: &Session,
716704
// Flag to indicate whether the user explicitly requested bitcode.
717705
// Otherwise, we produced it only as a temporary output, and will need
718706
// to get rid of it.
719-
// FIXME: Since we don't support LTO anyway, maybe we can avoid
720-
// producing the temporary .0.bc's in the first place?
721-
let mut save_bitcode = false;
707+
let mut user_wants_bitcode = false;
722708
for output_type in output_types.iter() {
723709
match *output_type {
724710
OutputTypeBitcode => {
725-
save_bitcode = true;
726-
copy_if_one_unit("0.bc", OutputTypeBitcode);
711+
user_wants_bitcode = true;
712+
// Copy to .bc, but always keep the .0.bc. There is a later
713+
// check to figure out if we should delete .0.bc files, or keep
714+
// them for making an rlib.
715+
copy_if_one_unit("0.bc", OutputTypeBitcode, true);
727716
},
728-
OutputTypeLlvmAssembly => { copy_if_one_unit("0.ll", OutputTypeLlvmAssembly); },
729-
OutputTypeAssembly => { copy_if_one_unit("0.s", OutputTypeAssembly); },
717+
OutputTypeLlvmAssembly => { copy_if_one_unit("0.ll", OutputTypeLlvmAssembly, false); },
718+
OutputTypeAssembly => { copy_if_one_unit("0.s", OutputTypeAssembly, false); },
730719
OutputTypeObject => { link_obj(&crate_output.path(OutputTypeObject)); },
731720
OutputTypeExe => {
732721
// If OutputTypeObject is already in the list, then
@@ -739,7 +728,7 @@ pub fn run_passes(sess: &Session,
739728
},
740729
}
741730
}
742-
let save_bitcode = save_bitcode;
731+
let user_wants_bitcode = user_wants_bitcode;
743732

744733
// Clean up unwanted temporary files.
745734

@@ -755,22 +744,36 @@ pub fn run_passes(sess: &Session,
755744

756745
if !sess.opts.cg.save_temps {
757746
// Remove the temporary .0.o objects. If the user didn't
758-
// explicitly request bitcode (with --emit=bc), we must remove
759-
// .0.bc as well. (We don't touch the crate.bc that may have been
760-
// produced earlier.)
747+
// explicitly request bitcode (with --emit=bc), and the bitcode is not
748+
// needed for building an rlib, then we must remove .0.bc as well.
749+
750+
// Specific rules for keeping .0.bc:
751+
// - If we're building an rlib (`needs_crate_bitcode`), then keep
752+
// it.
753+
// - If the user requested bitcode (`user_wants_bitcode`), and
754+
// codegen_units > 1, then keep it.
755+
// - If the user requested bitcode but codegen_units == 1, then we
756+
// can toss .0.bc because we copied it to .bc earlier.
757+
// - If we're not building an rlib and the user didn't request
758+
// bitcode, then delete .0.bc.
759+
// If you change how this works, also update back::link::link_rlib,
760+
// where .0.bc files are (maybe) deleted after making an rlib.
761+
let keep_numbered_bitcode = needs_crate_bitcode ||
762+
(user_wants_bitcode && sess.opts.cg.codegen_units > 1);
763+
761764
for i in range(0, trans.modules.len()) {
762765
if modules_config.emit_obj {
763766
let ext = format!("{}.o", i);
764767
remove(sess, &crate_output.with_extension(ext.as_slice()));
765768
}
766769

767-
if modules_config.emit_bc && !save_bitcode {
770+
if modules_config.emit_bc && !keep_numbered_bitcode {
768771
let ext = format!("{}.bc", i);
769772
remove(sess, &crate_output.with_extension(ext.as_slice()));
770773
}
771774
}
772775

773-
if metadata_config.emit_bc && !save_bitcode {
776+
if metadata_config.emit_bc && !user_wants_bitcode {
774777
remove(sess, &crate_output.with_extension("metadata.bc"));
775778
}
776779
}

src/test/compile-fail/sepcomp-lib-lto.rs renamed to src/test/run-pass/sepcomp-lib-lto.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// Make sure we give a sane error message when the user requests LTO with a
12-
// library built with -C codegen-units > 1.
11+
// Check that we can use `-Z lto` when linking against libraries that were
12+
// separately compiled.
1313

1414
// aux-build:sepcomp_lib.rs
1515
// compile-flags: -Z lto
16-
// error-pattern:missing compressed bytecode
1716
// no-prefer-dynamic
1817

1918
extern crate sepcomp_lib;

0 commit comments

Comments
 (0)