Skip to content

Commit aa78b4c

Browse files
authored
Rollup merge of #115358 - durin42:compress-debuginfo, r=oli-obk
debuginfo: add compiler option to allow compressed debuginfo sections LLVM already supports emitting compressed debuginfo. In debuginfo=full builds, the debug section is often a large amount of data, and it typically compresses very well (3x is not unreasonable.) We add a new knob to allow debuginfo to be compressed when the matching LLVM functionality is present. Like clang, if a known-but-disabled compression mechanism is requested, we disable compression and emit uncompressed debuginfo sections. The API is different enough on older LLVMs we just pretend the support is missing on LLVM older than 16.
2 parents 6b65d37 + 78d805c commit aa78b4c

File tree

10 files changed

+132
-6
lines changed

10 files changed

+132
-6
lines changed

compiler/rustc_codegen_llvm/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ codegen_llvm_unknown_ctarget_feature_prefix =
8383
unknown feature specified for `-Ctarget-feature`: `{$feature}`
8484
.note = features must begin with a `+` to enable or `-` to disable it
8585
86+
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
87+
8688
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
8789
8890
codegen_llvm_write_ir = failed to write LLVM IR to {$path}

compiler/rustc_codegen_llvm/src/back/write.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ use crate::back::profiling::{
55
use crate::base;
66
use crate::common;
77
use crate::errors::{
8-
CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode,
8+
CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
9+
WithLlvmError, WriteBytecode,
910
};
1011
use crate::llvm::{self, DiagnosticInfo, PassManager};
1112
use crate::llvm_util;
1213
use crate::type_::Type;
1314
use crate::LlvmCodegenBackend;
1415
use crate::ModuleLlvm;
16+
use llvm::{
17+
LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
18+
};
1519
use rustc_codegen_ssa::back::link::ensure_removed;
1620
use rustc_codegen_ssa::back::write::{
1721
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
@@ -234,6 +238,22 @@ pub fn target_machine_factory(
234238
args_cstr_buff
235239
};
236240

241+
let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
242+
match sess.opts.debuginfo_compression {
243+
rustc_session::config::DebugInfoCompression::Zlib => {
244+
if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } {
245+
sess.emit_warning(UnknownCompression { algorithm: "zlib" });
246+
}
247+
}
248+
rustc_session::config::DebugInfoCompression::Zstd => {
249+
if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } {
250+
sess.emit_warning(UnknownCompression { algorithm: "zstd" });
251+
}
252+
}
253+
rustc_session::config::DebugInfoCompression::None => {}
254+
};
255+
let debuginfo_compression = SmallCStr::new(&debuginfo_compression);
256+
237257
Arc::new(move |config: TargetMachineFactoryConfig| {
238258
let split_dwarf_file =
239259
path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
@@ -259,6 +279,7 @@ pub fn target_machine_factory(
259279
relax_elf_relocations,
260280
use_init_array,
261281
split_dwarf_file.as_ptr(),
282+
debuginfo_compression.as_ptr(),
262283
force_emulated_tls,
263284
args_cstr_buff.as_ptr() as *const c_char,
264285
args_cstr_buff.len(),

compiler/rustc_codegen_llvm/src/errors.rs

+6
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,9 @@ pub(crate) struct WriteBytecode<'a> {
226226
pub(crate) struct CopyBitcode {
227227
pub err: std::io::Error,
228228
}
229+
230+
#[derive(Diagnostic)]
231+
#[diag(codegen_llvm_unknown_debuginfo_compression)]
232+
pub struct UnknownCompression {
233+
pub algorithm: &'static str,
234+
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2131,6 +2131,7 @@ extern "C" {
21312131
RelaxELFRelocations: bool,
21322132
UseInitArray: bool,
21332133
SplitDwarfFile: *const c_char,
2134+
DebugInfoCompression: *const c_char,
21342135
ForceEmulatedTls: bool,
21352136
ArgsCstrBuff: *const c_char,
21362137
ArgsCstrBuffLen: usize,
@@ -2366,6 +2367,10 @@ extern "C" {
23662367

23672368
pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool;
23682369

2370+
pub fn LLVMRustLLVMHasZlibCompressionForDebugSymbols() -> bool;
2371+
2372+
pub fn LLVMRustLLVMHasZstdCompressionForDebugSymbols() -> bool;
2373+
23692374
pub fn LLVMRustGetSymbols(
23702375
buf_ptr: *const u8,
23712376
buf_len: usize,

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
410410
bool RelaxELFRelocations,
411411
bool UseInitArray,
412412
const char *SplitDwarfFile,
413+
const char *DebugInfoCompression,
413414
bool ForceEmulatedTls,
414415
const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
415416

@@ -441,6 +442,16 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
441442
if (SplitDwarfFile) {
442443
Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
443444
}
445+
#if LLVM_VERSION_GE(16, 0)
446+
if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) {
447+
Options.CompressDebugSections = DebugCompressionType::Zlib;
448+
} else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) {
449+
Options.CompressDebugSections = DebugCompressionType::Zstd;
450+
} else if (!strcmp("none", DebugInfoCompression)) {
451+
Options.CompressDebugSections = DebugCompressionType::None;
452+
}
453+
#endif
454+
444455
Options.RelaxELFRelocations = RelaxELFRelocations;
445456
Options.UseInitArray = UseInitArray;
446457

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -2044,3 +2044,19 @@ extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) {
20442044
}
20452045
return false;
20462046
}
2047+
2048+
extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() {
2049+
#if LLVM_VERSION_GE(16, 0)
2050+
return llvm::compression::zlib::isAvailable();
2051+
#else
2052+
return false;
2053+
#endif
2054+
}
2055+
2056+
extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
2057+
#if LLVM_VERSION_GE(16, 0)
2058+
return llvm::compression::zstd::isAvailable();
2059+
#else
2060+
return false;
2061+
#endif
2062+
}

compiler/rustc_session/src/config.rs

+35-5
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,24 @@ pub enum DebugInfo {
381381
Full,
382382
}
383383

384+
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
385+
pub enum DebugInfoCompression {
386+
None,
387+
Zlib,
388+
Zstd,
389+
}
390+
391+
impl ToString for DebugInfoCompression {
392+
fn to_string(&self) -> String {
393+
match self {
394+
DebugInfoCompression::None => "none",
395+
DebugInfoCompression::Zlib => "zlib",
396+
DebugInfoCompression::Zstd => "zstd",
397+
}
398+
.to_owned()
399+
}
400+
}
401+
384402
/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
385403
/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
386404
/// uses DWARF for debug-information.
@@ -1015,6 +1033,7 @@ impl Default for Options {
10151033
crate_types: Vec::new(),
10161034
optimize: OptLevel::No,
10171035
debuginfo: DebugInfo::None,
1036+
debuginfo_compression: DebugInfoCompression::None,
10181037
lint_opts: Vec::new(),
10191038
lint_cap: None,
10201039
describe_lints: false,
@@ -2277,6 +2296,13 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
22772296
if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
22782297
}
22792298

2299+
fn select_debuginfo_compression(
2300+
_handler: &EarlyErrorHandler,
2301+
unstable_opts: &UnstableOptions,
2302+
) -> DebugInfoCompression {
2303+
unstable_opts.debuginfo_compression
2304+
}
2305+
22802306
pub(crate) fn parse_assert_incr_state(
22812307
handler: &EarlyErrorHandler,
22822308
opt_assertion: &Option<String>,
@@ -2752,6 +2778,8 @@ pub fn build_session_options(
27522778
// for more details.
27532779
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
27542780
let debuginfo = select_debuginfo(matches, &cg);
2781+
let debuginfo_compression: DebugInfoCompression =
2782+
select_debuginfo_compression(handler, &unstable_opts);
27552783

27562784
let mut search_paths = vec![];
27572785
for s in &matches.opt_strs("L") {
@@ -2828,6 +2856,7 @@ pub fn build_session_options(
28282856
crate_types,
28292857
optimize: opt_level,
28302858
debuginfo,
2859+
debuginfo_compression,
28312860
lint_opts,
28322861
lint_cap,
28332862
describe_lints,
@@ -3113,11 +3142,11 @@ impl PpMode {
31133142
/// how the hash should be calculated when adding a new command-line argument.
31143143
pub(crate) mod dep_tracking {
31153144
use super::{
3116-
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
3117-
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
3118-
OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
3119-
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
3120-
TraitSolver, TrimmedDefPaths,
3145+
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
3146+
ErrorOutputType, InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto,
3147+
LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
3148+
Passes, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
3149+
SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
31213150
};
31223151
use crate::lint;
31233152
use crate::options::WasiExecModel;
@@ -3195,6 +3224,7 @@ pub(crate) mod dep_tracking {
31953224
OptLevel,
31963225
LtoCli,
31973226
DebugInfo,
3227+
DebugInfoCompression,
31983228
UnstableFeatures,
31993229
NativeLib,
32003230
NativeLibKind,

compiler/rustc_session/src/options.rs

+17
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ top_level_options!(
139139
/// can influence whether overflow checks are done or not.
140140
debug_assertions: bool [TRACKED],
141141
debuginfo: DebugInfo [TRACKED],
142+
debuginfo_compression: DebugInfoCompression [TRACKED],
142143
lint_opts: Vec<(String, lint::Level)> [TRACKED_NO_CRATE_HASH],
143144
lint_cap: Option<lint::Level> [TRACKED_NO_CRATE_HASH],
144145
describe_lints: bool [UNTRACKED],
@@ -376,6 +377,7 @@ mod desc {
376377
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
377378
pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
378379
pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
380+
pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
379381
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
380382
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
381383
pub const parse_optimization_fuel: &str = "crate=integer";
@@ -782,6 +784,19 @@ mod parse {
782784
true
783785
}
784786

787+
pub(crate) fn parse_debuginfo_compression(
788+
slot: &mut DebugInfoCompression,
789+
v: Option<&str>,
790+
) -> bool {
791+
match v {
792+
Some("none") => *slot = DebugInfoCompression::None,
793+
Some("zlib") => *slot = DebugInfoCompression::Zlib,
794+
Some("zstd") => *slot = DebugInfoCompression::Zstd,
795+
_ => return false,
796+
};
797+
true
798+
}
799+
785800
pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
786801
match v.and_then(LinkerFlavorCli::from_str) {
787802
Some(lf) => *slot = Some(lf),
@@ -1424,6 +1439,8 @@ options! {
14241439
"emit discriminators and other data necessary for AutoFDO"),
14251440
debug_macros: bool = (false, parse_bool, [TRACKED],
14261441
"emit line numbers debug info inside macros (default: no)"),
1442+
debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
1443+
"compress debug info sections (none, zlib, zstd, default: none)"),
14271444
deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
14281445
"deduplicate identical diagnostics (default: yes)"),
14291446
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# ignore-cross-compile
2+
include ../tools.mk
3+
4+
# only-linux
5+
# min-llvm-version: 16.0
6+
#
7+
# This tests debuginfo-compression.
8+
9+
all: zlib zstandard
10+
11+
zlib:
12+
test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zlib foo.rs 2>&1 | sed 's/.*unknown.*zlib.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZLIB
13+
14+
zstandard:
15+
test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zstd foo.rs 2>&1 | sed 's/.*unknown.*zstd.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZST
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub fn foo() -> i32 {
2+
42
3+
}

0 commit comments

Comments
 (0)