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.
This commit is contained in:
commit
aa78b4c368
@ -83,6 +83,8 @@ codegen_llvm_unknown_ctarget_feature_prefix =
|
||||
unknown feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = features must begin with a `+` to enable or `-` to disable it
|
||||
|
||||
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
|
||||
|
||||
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
|
||||
|
||||
codegen_llvm_write_ir = failed to write LLVM IR to {$path}
|
||||
|
@ -5,13 +5,17 @@
|
||||
use crate::base;
|
||||
use crate::common;
|
||||
use crate::errors::{
|
||||
CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode,
|
||||
CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
|
||||
WithLlvmError, WriteBytecode,
|
||||
};
|
||||
use crate::llvm::{self, DiagnosticInfo, PassManager};
|
||||
use crate::llvm_util;
|
||||
use crate::type_::Type;
|
||||
use crate::LlvmCodegenBackend;
|
||||
use crate::ModuleLlvm;
|
||||
use llvm::{
|
||||
LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
|
||||
};
|
||||
use rustc_codegen_ssa::back::link::ensure_removed;
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
|
||||
@ -234,6 +238,22 @@ pub fn target_machine_factory(
|
||||
args_cstr_buff
|
||||
};
|
||||
|
||||
let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
|
||||
match sess.opts.debuginfo_compression {
|
||||
rustc_session::config::DebugInfoCompression::Zlib => {
|
||||
if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } {
|
||||
sess.emit_warning(UnknownCompression { algorithm: "zlib" });
|
||||
}
|
||||
}
|
||||
rustc_session::config::DebugInfoCompression::Zstd => {
|
||||
if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } {
|
||||
sess.emit_warning(UnknownCompression { algorithm: "zstd" });
|
||||
}
|
||||
}
|
||||
rustc_session::config::DebugInfoCompression::None => {}
|
||||
};
|
||||
let debuginfo_compression = SmallCStr::new(&debuginfo_compression);
|
||||
|
||||
Arc::new(move |config: TargetMachineFactoryConfig| {
|
||||
let split_dwarf_file =
|
||||
path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
|
||||
@ -259,6 +279,7 @@ pub fn target_machine_factory(
|
||||
relax_elf_relocations,
|
||||
use_init_array,
|
||||
split_dwarf_file.as_ptr(),
|
||||
debuginfo_compression.as_ptr(),
|
||||
force_emulated_tls,
|
||||
args_cstr_buff.as_ptr() as *const c_char,
|
||||
args_cstr_buff.len(),
|
||||
|
@ -226,3 +226,9 @@ pub(crate) struct WriteBytecode<'a> {
|
||||
pub(crate) struct CopyBitcode {
|
||||
pub err: std::io::Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_unknown_debuginfo_compression)]
|
||||
pub struct UnknownCompression {
|
||||
pub algorithm: &'static str,
|
||||
}
|
||||
|
@ -2131,6 +2131,7 @@ pub fn LLVMRustCreateTargetMachine(
|
||||
RelaxELFRelocations: bool,
|
||||
UseInitArray: bool,
|
||||
SplitDwarfFile: *const c_char,
|
||||
DebugInfoCompression: *const c_char,
|
||||
ForceEmulatedTls: bool,
|
||||
ArgsCstrBuff: *const c_char,
|
||||
ArgsCstrBuffLen: usize,
|
||||
@ -2366,6 +2367,10 @@ pub fn LLVMRustContextConfigureDiagnosticHandler(
|
||||
|
||||
pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool;
|
||||
|
||||
pub fn LLVMRustLLVMHasZlibCompressionForDebugSymbols() -> bool;
|
||||
|
||||
pub fn LLVMRustLLVMHasZstdCompressionForDebugSymbols() -> bool;
|
||||
|
||||
pub fn LLVMRustGetSymbols(
|
||||
buf_ptr: *const u8,
|
||||
buf_len: usize,
|
||||
|
@ -410,6 +410,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
||||
bool RelaxELFRelocations,
|
||||
bool UseInitArray,
|
||||
const char *SplitDwarfFile,
|
||||
const char *DebugInfoCompression,
|
||||
bool ForceEmulatedTls,
|
||||
const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
|
||||
|
||||
@ -441,6 +442,16 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
||||
if (SplitDwarfFile) {
|
||||
Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
|
||||
}
|
||||
#if LLVM_VERSION_GE(16, 0)
|
||||
if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) {
|
||||
Options.CompressDebugSections = DebugCompressionType::Zlib;
|
||||
} else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) {
|
||||
Options.CompressDebugSections = DebugCompressionType::Zstd;
|
||||
} else if (!strcmp("none", DebugInfoCompression)) {
|
||||
Options.CompressDebugSections = DebugCompressionType::None;
|
||||
}
|
||||
#endif
|
||||
|
||||
Options.RelaxELFRelocations = RelaxELFRelocations;
|
||||
Options.UseInitArray = UseInitArray;
|
||||
|
||||
|
@ -2044,3 +2044,19 @@ extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() {
|
||||
#if LLVM_VERSION_GE(16, 0)
|
||||
return llvm::compression::zlib::isAvailable();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
|
||||
#if LLVM_VERSION_GE(16, 0)
|
||||
return llvm::compression::zstd::isAvailable();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
@ -381,6 +381,24 @@ pub enum DebugInfo {
|
||||
Full,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
|
||||
pub enum DebugInfoCompression {
|
||||
None,
|
||||
Zlib,
|
||||
Zstd,
|
||||
}
|
||||
|
||||
impl ToString for DebugInfoCompression {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
DebugInfoCompression::None => "none",
|
||||
DebugInfoCompression::Zlib => "zlib",
|
||||
DebugInfoCompression::Zstd => "zstd",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
|
||||
/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
|
||||
/// uses DWARF for debug-information.
|
||||
@ -1015,6 +1033,7 @@ fn default() -> Options {
|
||||
crate_types: Vec::new(),
|
||||
optimize: OptLevel::No,
|
||||
debuginfo: DebugInfo::None,
|
||||
debuginfo_compression: DebugInfoCompression::None,
|
||||
lint_opts: Vec::new(),
|
||||
lint_cap: None,
|
||||
describe_lints: false,
|
||||
@ -2277,6 +2296,13 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
|
||||
if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
|
||||
}
|
||||
|
||||
fn select_debuginfo_compression(
|
||||
_handler: &EarlyErrorHandler,
|
||||
unstable_opts: &UnstableOptions,
|
||||
) -> DebugInfoCompression {
|
||||
unstable_opts.debuginfo_compression
|
||||
}
|
||||
|
||||
pub(crate) fn parse_assert_incr_state(
|
||||
handler: &EarlyErrorHandler,
|
||||
opt_assertion: &Option<String>,
|
||||
@ -2752,6 +2778,8 @@ pub fn build_session_options(
|
||||
// for more details.
|
||||
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
|
||||
let debuginfo = select_debuginfo(matches, &cg);
|
||||
let debuginfo_compression: DebugInfoCompression =
|
||||
select_debuginfo_compression(handler, &unstable_opts);
|
||||
|
||||
let mut search_paths = vec![];
|
||||
for s in &matches.opt_strs("L") {
|
||||
@ -2828,6 +2856,7 @@ pub fn build_session_options(
|
||||
crate_types,
|
||||
optimize: opt_level,
|
||||
debuginfo,
|
||||
debuginfo_compression,
|
||||
lint_opts,
|
||||
lint_cap,
|
||||
describe_lints,
|
||||
@ -3113,11 +3142,11 @@ pub fn needs_analysis(&self) -> bool {
|
||||
/// how the hash should be calculated when adding a new command-line argument.
|
||||
pub(crate) mod dep_tracking {
|
||||
use super::{
|
||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
|
||||
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
|
||||
OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
|
||||
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
|
||||
TraitSolver, TrimmedDefPaths,
|
||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
|
||||
ErrorOutputType, InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto,
|
||||
LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
|
||||
Passes, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
|
||||
SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
|
||||
};
|
||||
use crate::lint;
|
||||
use crate::options::WasiExecModel;
|
||||
@ -3195,6 +3224,7 @@ fn hash(
|
||||
OptLevel,
|
||||
LtoCli,
|
||||
DebugInfo,
|
||||
DebugInfoCompression,
|
||||
UnstableFeatures,
|
||||
NativeLib,
|
||||
NativeLibKind,
|
||||
|
@ -139,6 +139,7 @@ pub struct Options {
|
||||
/// can influence whether overflow checks are done or not.
|
||||
debug_assertions: bool [TRACKED],
|
||||
debuginfo: DebugInfo [TRACKED],
|
||||
debuginfo_compression: DebugInfoCompression [TRACKED],
|
||||
lint_opts: Vec<(String, lint::Level)> [TRACKED_NO_CRATE_HASH],
|
||||
lint_cap: Option<lint::Level> [TRACKED_NO_CRATE_HASH],
|
||||
describe_lints: bool [UNTRACKED],
|
||||
@ -376,6 +377,7 @@ mod desc {
|
||||
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
|
||||
pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
|
||||
pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
|
||||
pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
|
||||
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
|
||||
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
|
||||
pub const parse_optimization_fuel: &str = "crate=integer";
|
||||
@ -782,6 +784,19 @@ pub(crate) fn parse_debuginfo(slot: &mut DebugInfo, v: Option<&str>) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn parse_debuginfo_compression(
|
||||
slot: &mut DebugInfoCompression,
|
||||
v: Option<&str>,
|
||||
) -> bool {
|
||||
match v {
|
||||
Some("none") => *slot = DebugInfoCompression::None,
|
||||
Some("zlib") => *slot = DebugInfoCompression::Zlib,
|
||||
Some("zstd") => *slot = DebugInfoCompression::Zstd,
|
||||
_ => return false,
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
|
||||
match v.and_then(LinkerFlavorCli::from_str) {
|
||||
Some(lf) => *slot = Some(lf),
|
||||
@ -1424,6 +1439,8 @@ pub(crate) fn parse_dump_solver_proof_tree(
|
||||
"emit discriminators and other data necessary for AutoFDO"),
|
||||
debug_macros: bool = (false, parse_bool, [TRACKED],
|
||||
"emit line numbers debug info inside macros (default: no)"),
|
||||
debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
|
||||
"compress debug info sections (none, zlib, zstd, default: none)"),
|
||||
deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
|
||||
"deduplicate identical diagnostics (default: yes)"),
|
||||
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
|
||||
|
15
tests/run-make/compressed-debuginfo/Makefile
Normal file
15
tests/run-make/compressed-debuginfo/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
# ignore-cross-compile
|
||||
include ../tools.mk
|
||||
|
||||
# only-linux
|
||||
# min-llvm-version: 16.0
|
||||
#
|
||||
# This tests debuginfo-compression.
|
||||
|
||||
all: zlib zstandard
|
||||
|
||||
zlib:
|
||||
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
|
||||
|
||||
zstandard:
|
||||
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
|
3
tests/run-make/compressed-debuginfo/foo.rs
Normal file
3
tests/run-make/compressed-debuginfo/foo.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub fn foo() -> i32 {
|
||||
42
|
||||
}
|
Loading…
Reference in New Issue
Block a user