Skip to content

Commit 01c1ffd

Browse files
committed
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.
1 parent 474bee7 commit 01c1ffd

File tree

9 files changed

+85
-11
lines changed

9 files changed

+85
-11
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

+4
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 {

compiler/rustc_codegen_llvm/src/back/lto.rs

+8
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,14 @@ impl ThinBufferMethods for ThinBuffer {
687687
slice::from_raw_parts(ptr, len)
688688
}
689689
}
690+
691+
fn thin_link_data(&self) -> &[u8] {
692+
unsafe {
693+
let ptr = llvm::LLVMRustThinLTOBufferThinLinkDataPtr(self.0) as *const _;
694+
let len = llvm::LLVMRustThinLTOBufferThinLinkDataLen(self.0);
695+
slice::from_raw_parts(ptr, len)
696+
}
697+
}
690698
}
691699

692700
impl Drop for ThinBuffer {

compiler/rustc_codegen_llvm/src/back/write.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,8 @@ pub(crate) unsafe fn codegen(
708708
// asm from LLVM and use `gcc` to create the object file.
709709

710710
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
711+
let bc_index_out =
712+
cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name);
711713
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
712714

713715
if config.bitcode_needed() {
@@ -716,6 +718,7 @@ pub(crate) unsafe fn codegen(
716718
.generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name);
717719
let thin = ThinBuffer::new(llmod, config.emit_thin_lto);
718720
let data = thin.data();
721+
let index_data = thin.thin_link_data();
719722

720723
if let Some(bitcode_filename) = bc_out.file_name() {
721724
cgcx.prof.artifact_size(
@@ -725,12 +728,31 @@ pub(crate) unsafe fn codegen(
725728
);
726729
}
727730

731+
if let Some(thin_link_bitcode_filename) = bc_index_out.file_name() {
732+
cgcx.prof.artifact_size(
733+
"llvm_bitcode_summary",
734+
thin_link_bitcode_filename.to_string_lossy(),
735+
index_data.len() as u64,
736+
);
737+
738+
let _timer = cgcx.prof.generic_activity_with_arg(
739+
"LLVM_module_codegen_emit_bitcode_index",
740+
&*module.name,
741+
);
742+
if let Err(err) = fs::write(&bc_index_out, index_data) {
743+
dcx.emit_err(WriteBytecode { path: &bc_index_out, err });
744+
}
745+
}
746+
728747
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
729-
let _timer = cgcx
730-
.prof
731-
.generic_activity_with_arg("LLVM_module_codegen_emit_bitcode", &*module.name);
732-
if let Err(err) = fs::write(&bc_out, data) {
733-
dcx.emit_err(WriteBytecode { path: &bc_out, err });
748+
{
749+
let _timer = cgcx.prof.generic_activity_with_arg(
750+
"LLVM_module_codegen_emit_bitcode",
751+
&*module.name,
752+
);
753+
if let Err(err) = fs::write(&bc_out, data) {
754+
dcx.emit_err(WriteBytecode { path: &bc_out, err });
755+
}
734756
}
735757
}
736758

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2354,6 +2354,8 @@ extern "C" {
23542354
pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
23552355
pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
23562356
pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t;
2357+
pub fn LLVMRustThinLTOBufferThinLinkDataPtr(M: &ThinLTOBuffer) -> *const c_char;
2358+
pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t;
23572359
pub fn LLVMRustCreateThinLTOData(
23582360
Modules: *const ThinLTOModule,
23592361
NumModules: c_uint,

compiler/rustc_codegen_ssa/src/back/write.rs

+9
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ pub struct ModuleConfig {
107107
pub emit_asm: bool,
108108
pub emit_obj: EmitObj,
109109
pub emit_thin_lto: bool,
110+
pub emit_thin_lto_index: bool,
110111
pub bc_cmdline: String,
111112

112113
// Miscellaneous flags. These are mostly copied from command-line
@@ -231,6 +232,10 @@ impl ModuleConfig {
231232
),
232233
emit_obj,
233234
emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto,
235+
emit_thin_lto_index: if_regular!(
236+
sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode),
237+
false
238+
),
234239
bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(),
235240

236241
verify_llvm_ir: sess.verify_llvm_ir(),
@@ -282,6 +287,7 @@ impl ModuleConfig {
282287

283288
pub fn bitcode_needed(&self) -> bool {
284289
self.emit_bc
290+
|| self.emit_thin_lto_index
285291
|| self.emit_obj == EmitObj::Bitcode
286292
|| self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full)
287293
}
@@ -629,6 +635,9 @@ fn produce_final_output_artifacts(
629635
// them for making an rlib.
630636
copy_if_one_unit(OutputType::Bitcode, true);
631637
}
638+
OutputType::ThinLinkBitcode => {
639+
copy_if_one_unit(OutputType::ThinLinkBitcode, false);
640+
}
632641
OutputType::LlvmAssembly => {
633642
copy_if_one_unit(OutputType::LlvmAssembly, false);
634643
}

compiler/rustc_codegen_ssa/src/traits/write.rs

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
6262

6363
pub trait ThinBufferMethods: Send + Sync {
6464
fn data(&self) -> &[u8];
65+
fn thin_link_data(&self) -> &[u8];
6566
}
6667

6768
pub trait ModuleBufferMethods: Send + Sync {

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+13-1
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*
14941495
LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
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,7 @@ 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+
MPM.addPass(ThinLTOBitcodeWriterPass(OS, &ThinLinkOS));
15121514
MPM.run(*unwrap(M), MAM);
15131515
} else {
15141516
WriteBitcodeToFile(*unwrap(M), OS);
@@ -1533,6 +1535,16 @@ LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
15331535
return Buffer->data.length();
15341536
}
15351537

1538+
extern "C" const void*
1539+
LLVMRustThinLTOBufferThinLinkDataPtr(const LLVMRustThinLTOBuffer *Buffer) {
1540+
return Buffer->thin_link_data.data();
1541+
}
1542+
1543+
extern "C" size_t
1544+
LLVMRustThinLTOBufferThinLinkDataLen(const LLVMRustThinLTOBuffer *Buffer) {
1545+
return Buffer->thin_link_data.length();
1546+
}
1547+
15361548
// This is what we used to parse upstream bitcode for actual ThinLTO
15371549
// processing. We'll call this once per module optimized through ThinLTO, and
15381550
// 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)