Rollup merge of #134208 - Zalathar:covmap-covfun, r=compiler-errors
coverage: Tidy up creation of covmap and covfun records This is a small follow-up to #134163 that mostly just inlines and renames some variables, and adds a few comments. It also slightly defers the creation of the LLVM value that holds the filename table, to just before the value is needed. --- try-job: x86_64-mingw-2 try-job: dist-x86_64-linux
This commit is contained in:
commit
704102c0f0
2 changed files with 59 additions and 63 deletions
|
@ -75,10 +75,10 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||||
|
|
||||||
// Encode all filenames referenced by coverage mappings in this CGU.
|
// Encode all filenames referenced by coverage mappings in this CGU.
|
||||||
let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
|
let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
|
||||||
|
// The `llvm-cov` tool uses this hash to associate each covfun record with
|
||||||
let filenames_size = filenames_buffer.len();
|
// its corresponding filenames table, since the final binary will typically
|
||||||
let filenames_val = cx.const_bytes(&filenames_buffer);
|
// contain multiple covmap records from different compilation units.
|
||||||
let filenames_ref = llvm_cov::hash_bytes(&filenames_buffer);
|
let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer);
|
||||||
|
|
||||||
let mut unused_function_names = Vec::new();
|
let mut unused_function_names = Vec::new();
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||||
for covfun in &covfun_records {
|
for covfun in &covfun_records {
|
||||||
unused_function_names.extend(covfun.mangled_function_name_if_unused());
|
unused_function_names.extend(covfun.mangled_function_name_if_unused());
|
||||||
|
|
||||||
covfun::generate_covfun_record(cx, filenames_ref, covfun)
|
covfun::generate_covfun_record(cx, filenames_hash, covfun)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For unused functions, we need to take their mangled names and store them
|
// For unused functions, we need to take their mangled names and store them
|
||||||
|
@ -126,7 +126,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||||
// Generate the coverage map header, which contains the filenames used by
|
// Generate the coverage map header, which contains the filenames used by
|
||||||
// this CGU's coverage mappings, and store it in a well-known global.
|
// this CGU's coverage mappings, and store it in a well-known global.
|
||||||
// (This is skipped if we returned early due to having no covfun records.)
|
// (This is skipped if we returned early due to having no covfun records.)
|
||||||
generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
|
generate_covmap_record(cx, covmap_version, &filenames_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
|
/// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
|
||||||
|
@ -225,38 +225,35 @@ fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
|
||||||
/// Generates the contents of the covmap record for this CGU, which mostly
|
/// Generates the contents of the covmap record for this CGU, which mostly
|
||||||
/// consists of a header and a list of filenames. The record is then stored
|
/// consists of a header and a list of filenames. The record is then stored
|
||||||
/// as a global variable in the `__llvm_covmap` section.
|
/// as a global variable in the `__llvm_covmap` section.
|
||||||
fn generate_covmap_record<'ll>(
|
fn generate_covmap_record<'ll>(cx: &CodegenCx<'ll, '_>, version: u32, filenames_buffer: &[u8]) {
|
||||||
cx: &CodegenCx<'ll, '_>,
|
// A covmap record consists of four target-endian u32 values, followed by
|
||||||
version: u32,
|
// the encoded filenames table. Two of the header fields are unused in
|
||||||
filenames_size: usize,
|
// modern versions of the LLVM coverage mapping format, and are always 0.
|
||||||
filenames_val: &'ll llvm::Value,
|
// <https://llvm.org/docs/CoverageMappingFormat.html#llvm-ir-representation>
|
||||||
) {
|
// See also `src/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp`.
|
||||||
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
|
let covmap_header = cx.const_struct(
|
||||||
|
&[
|
||||||
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
|
cx.const_u32(0), // (unused)
|
||||||
// as of `llvm::coverage::CovMapVersion::Version4`.)
|
cx.const_u32(filenames_buffer.len() as u32),
|
||||||
let zero_was_n_records_val = cx.const_u32(0);
|
cx.const_u32(0), // (unused)
|
||||||
let filenames_size_val = cx.const_u32(filenames_size as u32);
|
cx.const_u32(version),
|
||||||
let zero_was_coverage_size_val = cx.const_u32(0);
|
],
|
||||||
let version_val = cx.const_u32(version);
|
/* packed */ false,
|
||||||
let cov_data_header_val = cx.const_struct(
|
|
||||||
&[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
|
|
||||||
/*packed=*/ false,
|
|
||||||
);
|
);
|
||||||
|
let covmap_record = cx
|
||||||
|
.const_struct(&[covmap_header, cx.const_bytes(filenames_buffer)], /* packed */ false);
|
||||||
|
|
||||||
// Create the complete LLVM coverage data value to add to the LLVM IR
|
let covmap_global =
|
||||||
let covmap_data =
|
llvm::add_global(cx.llmod, cx.val_ty(covmap_record), &llvm_cov::covmap_var_name());
|
||||||
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false);
|
llvm::set_initializer(covmap_global, covmap_record);
|
||||||
|
llvm::set_global_constant(covmap_global, true);
|
||||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &llvm_cov::covmap_var_name());
|
llvm::set_linkage(covmap_global, llvm::Linkage::PrivateLinkage);
|
||||||
llvm::set_initializer(llglobal, covmap_data);
|
llvm::set_section(covmap_global, &llvm_cov::covmap_section_name(cx.llmod));
|
||||||
llvm::set_global_constant(llglobal, true);
|
|
||||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
|
||||||
llvm::set_section(llglobal, &llvm_cov::covmap_section_name(cx.llmod));
|
|
||||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||||
// <https://llvm.org/docs/CoverageMappingFormat.html>
|
// <https://llvm.org/docs/CoverageMappingFormat.html>
|
||||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
llvm::set_alignment(covmap_global, Align::EIGHT);
|
||||||
cx.add_used_global(llglobal);
|
|
||||||
|
cx.add_used_global(covmap_global);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
|
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
|
||||||
|
|
|
@ -136,7 +136,7 @@ fn fill_region_tables<'tcx>(
|
||||||
/// as a global variable in the `__llvm_covfun` section.
|
/// as a global variable in the `__llvm_covfun` section.
|
||||||
pub(crate) fn generate_covfun_record<'tcx>(
|
pub(crate) fn generate_covfun_record<'tcx>(
|
||||||
cx: &CodegenCx<'_, 'tcx>,
|
cx: &CodegenCx<'_, 'tcx>,
|
||||||
filenames_ref: u64,
|
filenames_hash: u64,
|
||||||
covfun: &CovfunRecord<'tcx>,
|
covfun: &CovfunRecord<'tcx>,
|
||||||
) {
|
) {
|
||||||
let &CovfunRecord {
|
let &CovfunRecord {
|
||||||
|
@ -155,46 +155,45 @@ pub(crate) fn generate_covfun_record<'tcx>(
|
||||||
regions,
|
regions,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Concatenate the encoded coverage mappings
|
// A covfun record consists of four target-endian integers, followed by the
|
||||||
let coverage_mapping_size = coverage_mapping_buffer.len();
|
// encoded mapping data in bytes. Note that the length field is 32 bits.
|
||||||
let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);
|
// <https://llvm.org/docs/CoverageMappingFormat.html#llvm-ir-representation>
|
||||||
|
// See also `src/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp` and
|
||||||
|
// `COVMAP_V3` in `src/llvm-project/llvm/include/llvm/ProfileData/InstrProfData.inc`.
|
||||||
let func_name_hash = llvm_cov::hash_bytes(mangled_function_name.as_bytes());
|
let func_name_hash = llvm_cov::hash_bytes(mangled_function_name.as_bytes());
|
||||||
let func_name_hash_val = cx.const_u64(func_name_hash);
|
let covfun_record = cx.const_struct(
|
||||||
let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32);
|
|
||||||
let source_hash_val = cx.const_u64(source_hash);
|
|
||||||
let filenames_ref_val = cx.const_u64(filenames_ref);
|
|
||||||
let func_record_val = cx.const_struct(
|
|
||||||
&[
|
&[
|
||||||
func_name_hash_val,
|
cx.const_u64(func_name_hash),
|
||||||
coverage_mapping_size_val,
|
cx.const_u32(coverage_mapping_buffer.len() as u32),
|
||||||
source_hash_val,
|
cx.const_u64(source_hash),
|
||||||
filenames_ref_val,
|
cx.const_u64(filenames_hash),
|
||||||
coverage_mapping_val,
|
cx.const_bytes(&coverage_mapping_buffer),
|
||||||
],
|
],
|
||||||
/*packed=*/ true,
|
// This struct needs to be packed, so that the 32-bit length field
|
||||||
|
// doesn't have unexpected padding.
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Choose a variable name to hold this function's covfun data.
|
// Choose a variable name to hold this function's covfun data.
|
||||||
// Functions that are used have a suffix ("u") to distinguish them from
|
// Functions that are used have a suffix ("u") to distinguish them from
|
||||||
// unused copies of the same function (from different CGUs), so that if a
|
// unused copies of the same function (from different CGUs), so that if a
|
||||||
// linker sees both it won't discard the used copy's data.
|
// linker sees both it won't discard the used copy's data.
|
||||||
let func_record_var_name =
|
let u = if is_used { "u" } else { "" };
|
||||||
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
|
let covfun_var_name = CString::new(format!("__covrec_{func_name_hash:X}{u}")).unwrap();
|
||||||
.unwrap();
|
debug!("function record var name: {covfun_var_name:?}");
|
||||||
debug!("function record var name: {:?}", func_record_var_name);
|
|
||||||
|
|
||||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
|
let covfun_global = llvm::add_global(cx.llmod, cx.val_ty(covfun_record), &covfun_var_name);
|
||||||
llvm::set_initializer(llglobal, func_record_val);
|
llvm::set_initializer(covfun_global, covfun_record);
|
||||||
llvm::set_global_constant(llglobal, true);
|
llvm::set_global_constant(covfun_global, true);
|
||||||
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
|
llvm::set_linkage(covfun_global, llvm::Linkage::LinkOnceODRLinkage);
|
||||||
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
|
llvm::set_visibility(covfun_global, llvm::Visibility::Hidden);
|
||||||
llvm::set_section(llglobal, cx.covfun_section_name());
|
llvm::set_section(covfun_global, cx.covfun_section_name());
|
||||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||||
// <https://llvm.org/docs/CoverageMappingFormat.html>
|
// <https://llvm.org/docs/CoverageMappingFormat.html>
|
||||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
llvm::set_alignment(covfun_global, Align::EIGHT);
|
||||||
if cx.target_spec().supports_comdat() {
|
if cx.target_spec().supports_comdat() {
|
||||||
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
llvm::set_comdat(cx.llmod, covfun_global, &covfun_var_name);
|
||||||
}
|
}
|
||||||
cx.add_used_global(llglobal);
|
|
||||||
|
cx.add_used_global(covfun_global);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue