Skip to content

Commit 973f111

Browse files
authored
Unrolled build for rust-lang#125345
Rollup merge of rust-lang#125345 - durin42:thin-link-bitcode, r=bjorn3 rustc_codegen_llvm: add support for writing summary bitcode Typical uses of ThinLTO don't have any use for this as a standalone file, but distributed ThinLTO uses this to make the linker phase more efficient. With clang you'd do something like `clang -flto=thin -fthin-link-bitcode=foo.indexing.o -c foo.c` and then get both foo.o (full of bitcode) and foo.indexing.o (just the summary or index part of the bitcode). That's then usable by a two-stage linking process that's more friendly to distributed build systems like bazel, which is why I'm working on this area. I talked some to `@teresajohnson` about naming in this area, as things seem to be a little confused between various blog posts and build systems. "bitcode index" and "bitcode summary" tend to be a little too ambiguous, and she tends to use "thin link bitcode" and "minimized bitcode" (which matches the descriptions in LLVM). Since the clang option is thin-link-bitcode, I went with that to try and not add a new spelling in the world. Per `@dtolnay,` you can work around the lack of this by using `lld --thinlto-index-only` to do the indexing on regular .o files of bitcode, but that is a bit wasteful on actions when we already have all the information in rustc and could just write out the matching minimized bitcode. I didn't test that at all in our infrastructure, because by the time I learned that I already had this patch largely written.
2 parents 78dd504 + cfe3f77 commit 973f111

File tree

10 files changed

+107
-18
lines changed

10 files changed

+107
-18
lines changed

compiler/rustc_codegen_cranelift/src/driver/aot.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ fn produce_final_output_artifacts(
200200
// to get rid of it.
201201
for output_type in crate_output.outputs.keys() {
202202
match *output_type {
203-
OutputType::Bitcode => {
203+
OutputType::Bitcode | OutputType::ThinLinkBitcode => {
204204
// Cranelift doesn't have bitcode
205205
// user_wants_bitcode = true;
206206
// // Copy to .bc, but always keep the .0.bc. There is a later

compiler/rustc_codegen_gcc/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ impl ThinBufferMethods for ThinBuffer {
335335
fn data(&self) -> &[u8] {
336336
unimplemented!();
337337
}
338+
339+
fn thin_link_data(&self) -> &[u8] {
340+
unimplemented!();
341+
}
338342
}
339343

340344
pub struct GccContext {
@@ -414,7 +418,7 @@ impl WriteBackendMethods for GccCodegenBackend {
414418
back::write::codegen(cgcx, dcx, module, config)
415419
}
416420

417-
fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
421+
fn prepare_thin(_module: ModuleCodegen<Self::Module>, _emit_summary: bool) -> (String, Self::ThinBuffer) {
418422
unimplemented!();
419423
}
420424

compiler/rustc_codegen_llvm/src/back/lto.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,12 @@ pub(crate) fn run_thin(
230230
thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold)
231231
}
232232

233-
pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) {
233+
pub(crate) fn prepare_thin(
234+
module: ModuleCodegen<ModuleLlvm>,
235+
emit_summary: bool,
236+
) -> (String, ThinBuffer) {
234237
let name = module.name;
235-
let buffer = ThinBuffer::new(module.module_llvm.llmod(), true);
238+
let buffer = ThinBuffer::new(module.module_llvm.llmod(), true, emit_summary);
236239
(name, buffer)
237240
}
238241

@@ -672,9 +675,9 @@ unsafe impl Send for ThinBuffer {}
672675
unsafe impl Sync for ThinBuffer {}
673676

674677
impl ThinBuffer {
675-
pub fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer {
678+
pub fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer {
676679
unsafe {
677-
let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin);
680+
let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin, emit_summary);
678681
ThinBuffer(buffer)
679682
}
680683
}
@@ -688,6 +691,14 @@ impl ThinBufferMethods for ThinBuffer {
688691
slice::from_raw_parts(ptr, len)
689692
}
690693
}
694+
695+
fn thin_link_data(&self) -> &[u8] {
696+
unsafe {
697+
let ptr = llvm::LLVMRustThinLTOBufferThinLinkDataPtr(self.0) as *const _;
698+
let len = llvm::LLVMRustThinLTOBufferThinLinkDataLen(self.0);
699+
slice::from_raw_parts(ptr, len)
700+
}
701+
}
691702
}
692703

693704
impl Drop for ThinBuffer {

compiler/rustc_codegen_llvm/src/back/write.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -709,13 +709,15 @@ pub(crate) unsafe fn codegen(
709709
// asm from LLVM and use `gcc` to create the object file.
710710

711711
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
712+
let bc_summary_out =
713+
cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name);
712714
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
713715

714716
if config.bitcode_needed() {
715717
let _timer = cgcx
716718
.prof
717719
.generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name);
718-
let thin = ThinBuffer::new(llmod, config.emit_thin_lto);
720+
let thin = ThinBuffer::new(llmod, config.emit_thin_lto, config.emit_thin_lto_summary);
719721
let data = thin.data();
720722

721723
if let Some(bitcode_filename) = bc_out.file_name() {
@@ -726,6 +728,25 @@ pub(crate) unsafe fn codegen(
726728
);
727729
}
728730

731+
if config.emit_thin_lto_summary
732+
&& let Some(thin_link_bitcode_filename) = bc_summary_out.file_name()
733+
{
734+
let summary_data = thin.thin_link_data();
735+
cgcx.prof.artifact_size(
736+
"llvm_bitcode_summary",
737+
thin_link_bitcode_filename.to_string_lossy(),
738+
summary_data.len() as u64,
739+
);
740+
741+
let _timer = cgcx.prof.generic_activity_with_arg(
742+
"LLVM_module_codegen_emit_bitcode_summary",
743+
&*module.name,
744+
);
745+
if let Err(err) = fs::write(&bc_summary_out, summary_data) {
746+
dcx.emit_err(WriteBytecode { path: &bc_summary_out, err });
747+
}
748+
}
749+
729750
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
730751
let _timer = cgcx
731752
.prof

compiler/rustc_codegen_llvm/src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,11 @@ impl WriteBackendMethods for LlvmCodegenBackend {
237237
) -> Result<CompiledModule, FatalError> {
238238
back::write::codegen(cgcx, dcx, module, config)
239239
}
240-
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
241-
back::lto::prepare_thin(module)
240+
fn prepare_thin(
241+
module: ModuleCodegen<Self::Module>,
242+
emit_summary: bool,
243+
) -> (String, Self::ThinBuffer) {
244+
back::lto::prepare_thin(module, emit_summary)
242245
}
243246
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
244247
(module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -2350,10 +2350,16 @@ extern "C" {
23502350
#[allow(improper_ctypes)]
23512351
pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
23522352

2353-
pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer;
2353+
pub fn LLVMRustThinLTOBufferCreate(
2354+
M: &Module,
2355+
is_thin: bool,
2356+
emit_summary: bool,
2357+
) -> &'static mut ThinLTOBuffer;
23542358
pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
23552359
pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
23562360
pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t;
2361+
pub fn LLVMRustThinLTOBufferThinLinkDataPtr(M: &ThinLTOBuffer) -> *const c_char;
2362+
pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t;
23572363
pub fn LLVMRustCreateThinLTOData(
23582364
Modules: *const ThinLTOModule,
23592365
NumModules: c_uint,

compiler/rustc_codegen_ssa/src/back/write.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ pub struct ModuleConfig {
108108
pub emit_asm: bool,
109109
pub emit_obj: EmitObj,
110110
pub emit_thin_lto: bool,
111+
pub emit_thin_lto_summary: bool,
111112
pub bc_cmdline: String,
112113

113114
// Miscellaneous flags. These are mostly copied from command-line
@@ -232,6 +233,10 @@ impl ModuleConfig {
232233
),
233234
emit_obj,
234235
emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto,
236+
emit_thin_lto_summary: if_regular!(
237+
sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode),
238+
false
239+
),
235240
bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(),
236241

237242
verify_llvm_ir: sess.verify_llvm_ir(),
@@ -283,6 +288,7 @@ impl ModuleConfig {
283288

284289
pub fn bitcode_needed(&self) -> bool {
285290
self.emit_bc
291+
|| self.emit_thin_lto_summary
286292
|| self.emit_obj == EmitObj::Bitcode
287293
|| self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full)
288294
}
@@ -630,6 +636,9 @@ fn produce_final_output_artifacts(
630636
// them for making an rlib.
631637
copy_if_one_unit(OutputType::Bitcode, true);
632638
}
639+
OutputType::ThinLinkBitcode => {
640+
copy_if_one_unit(OutputType::ThinLinkBitcode, false);
641+
}
633642
OutputType::LlvmAssembly => {
634643
copy_if_one_unit(OutputType::LlvmAssembly, false);
635644
}
@@ -883,7 +892,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
883892
match lto_type {
884893
ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
885894
ComputedLtoType::Thin => {
886-
let (name, thin_buffer) = B::prepare_thin(module);
895+
let (name, thin_buffer) = B::prepare_thin(module, false);
887896
if let Some(path) = bitcode {
888897
fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| {
889898
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);

compiler/rustc_codegen_ssa/src/traits/write.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,16 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
5656
module: ModuleCodegen<Self::Module>,
5757
config: &ModuleConfig,
5858
) -> Result<CompiledModule, FatalError>;
59-
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer);
59+
fn prepare_thin(
60+
module: ModuleCodegen<Self::Module>,
61+
want_summary: bool,
62+
) -> (String, Self::ThinBuffer);
6063
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
6164
}
6265

6366
pub trait ThinBufferMethods: Send + Sync {
6467
fn data(&self) -> &[u8];
68+
fn thin_link_data(&self) -> &[u8];
6569
}
6670

6771
pub trait ModuleBufferMethods: Send + Sync {

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+17-2
Original file line numberDiff line numberDiff line change
@@ -1488,13 +1488,15 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
14881488
// a ThinLTO summary attached.
14891489
struct LLVMRustThinLTOBuffer {
14901490
std::string data;
1491+
std::string thin_link_data;
14911492
};
14921493

14931494
extern "C" LLVMRustThinLTOBuffer*
1494-
LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
1495+
LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) {
14951496
auto Ret = std::make_unique<LLVMRustThinLTOBuffer>();
14961497
{
14971498
auto OS = raw_string_ostream(Ret->data);
1499+
auto ThinLinkOS = raw_string_ostream(Ret->thin_link_data);
14981500
{
14991501
if (is_thin) {
15001502
PassBuilder PB;
@@ -1508,7 +1510,10 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
15081510
PB.registerLoopAnalyses(LAM);
15091511
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
15101512
ModulePassManager MPM;
1511-
MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr));
1513+
// We only pass ThinLinkOS to be filled in if we want the summary,
1514+
// because otherwise LLVM does extra work and may double-emit some
1515+
// errors or warnings.
1516+
MPM.addPass(ThinLTOBitcodeWriterPass(OS, emit_summary ? &ThinLinkOS : nullptr));
15121517
MPM.run(*unwrap(M), MAM);
15131518
} else {
15141519
WriteBitcodeToFile(*unwrap(M), OS);
@@ -1533,6 +1538,16 @@ LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
15331538
return Buffer->data.length();
15341539
}
15351540

1541+
extern "C" const void*
1542+
LLVMRustThinLTOBufferThinLinkDataPtr(const LLVMRustThinLTOBuffer *Buffer) {
1543+
return Buffer->thin_link_data.data();
1544+
}
1545+
1546+
extern "C" size_t
1547+
LLVMRustThinLTOBufferThinLinkDataLen(const LLVMRustThinLTOBuffer *Buffer) {
1548+
return Buffer->thin_link_data.length();
1549+
}
1550+
15361551
// This is what we used to parse upstream bitcode for actual ThinLTO
15371552
// processing. We'll call this once per module optimized through ThinLTO, and
15381553
// it'll be called concurrently on many threads.

compiler/rustc_session/src/config.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ impl FromStr for SplitDwarfKind {
465465
#[derive(Encodable, Decodable)]
466466
pub enum OutputType {
467467
Bitcode,
468+
ThinLinkBitcode,
468469
Assembly,
469470
LlvmAssembly,
470471
Mir,
@@ -492,6 +493,7 @@ impl OutputType {
492493
match *self {
493494
OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
494495
OutputType::Bitcode
496+
| OutputType::ThinLinkBitcode
495497
| OutputType::Assembly
496498
| OutputType::LlvmAssembly
497499
| OutputType::Mir
@@ -502,6 +504,7 @@ impl OutputType {
502504
pub fn shorthand(&self) -> &'static str {
503505
match *self {
504506
OutputType::Bitcode => "llvm-bc",
507+
OutputType::ThinLinkBitcode => "thin-link-bitcode",
505508
OutputType::Assembly => "asm",
506509
OutputType::LlvmAssembly => "llvm-ir",
507510
OutputType::Mir => "mir",
@@ -518,6 +521,7 @@ impl OutputType {
518521
"llvm-ir" => OutputType::LlvmAssembly,
519522
"mir" => OutputType::Mir,
520523
"llvm-bc" => OutputType::Bitcode,
524+
"thin-link-bitcode" => OutputType::ThinLinkBitcode,
521525
"obj" => OutputType::Object,
522526
"metadata" => OutputType::Metadata,
523527
"link" => OutputType::Exe,
@@ -528,8 +532,9 @@ impl OutputType {
528532

529533
fn shorthands_display() -> String {
530534
format!(
531-
"`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
535+
"`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
532536
OutputType::Bitcode.shorthand(),
537+
OutputType::ThinLinkBitcode.shorthand(),
533538
OutputType::Assembly.shorthand(),
534539
OutputType::LlvmAssembly.shorthand(),
535540
OutputType::Mir.shorthand(),
@@ -543,6 +548,7 @@ impl OutputType {
543548
pub fn extension(&self) -> &'static str {
544549
match *self {
545550
OutputType::Bitcode => "bc",
551+
OutputType::ThinLinkBitcode => "indexing.o",
546552
OutputType::Assembly => "s",
547553
OutputType::LlvmAssembly => "ll",
548554
OutputType::Mir => "mir",
@@ -559,9 +565,11 @@ impl OutputType {
559565
| OutputType::LlvmAssembly
560566
| OutputType::Mir
561567
| OutputType::DepInfo => true,
562-
OutputType::Bitcode | OutputType::Object | OutputType::Metadata | OutputType::Exe => {
563-
false
564-
}
568+
OutputType::Bitcode
569+
| OutputType::ThinLinkBitcode
570+
| OutputType::Object
571+
| OutputType::Metadata
572+
| OutputType::Exe => false,
565573
}
566574
}
567575
}
@@ -644,6 +652,7 @@ impl OutputTypes {
644652
pub fn should_codegen(&self) -> bool {
645653
self.0.keys().any(|k| match *k {
646654
OutputType::Bitcode
655+
| OutputType::ThinLinkBitcode
647656
| OutputType::Assembly
648657
| OutputType::LlvmAssembly
649658
| OutputType::Mir
@@ -657,6 +666,7 @@ impl OutputTypes {
657666
pub fn should_link(&self) -> bool {
658667
self.0.keys().any(|k| match *k {
659668
OutputType::Bitcode
669+
| OutputType::ThinLinkBitcode
660670
| OutputType::Assembly
661671
| OutputType::LlvmAssembly
662672
| OutputType::Mir
@@ -1769,6 +1779,12 @@ fn parse_output_types(
17691779
display = OutputType::shorthands_display(),
17701780
))
17711781
});
1782+
if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options {
1783+
early_dcx.early_fatal(format!(
1784+
"{} requested but -Zunstable-options not specified",
1785+
OutputType::ThinLinkBitcode.shorthand()
1786+
));
1787+
}
17721788
output_types.insert(output_type, path);
17731789
}
17741790
}

0 commit comments

Comments
 (0)