1
Fork 0

coverage: Reify CovfunRecord as an intermediate step

This commit is contained in:
Zalathar 2024-12-11 15:03:31 +11:00
parent 7c4ac71ad1
commit 6a8c016266
2 changed files with 45 additions and 36 deletions

View file

@ -19,6 +19,7 @@ use tracing::debug;
use crate::common::CodegenCx; use crate::common::CodegenCx;
use crate::coverageinfo::llvm_cov; use crate::coverageinfo::llvm_cov;
use crate::coverageinfo::map_data::FunctionCoverage; use crate::coverageinfo::map_data::FunctionCoverage;
use crate::coverageinfo::mapgen::covfun::prepare_covfun_record;
use crate::llvm; use crate::llvm;
mod covfun; mod covfun;
@ -85,16 +86,17 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
let mut unused_function_names = Vec::new(); let mut unused_function_names = Vec::new();
// Encode coverage mappings and generate function records let covfun_records = function_coverage_map
for (instance, function_coverage) in function_coverage_map { .into_iter()
covfun::prepare_and_generate_covfun_record( .filter_map(|(instance, function_coverage)| {
cx, prepare_covfun_record(tcx, &global_file_table, instance, &function_coverage)
&global_file_table, })
filenames_ref, .collect::<Vec<_>>();
&mut unused_function_names,
instance, for covfun in &covfun_records {
&function_coverage, unused_function_names.extend(covfun.mangled_function_name_if_unused());
);
covfun::generate_covfun_record(cx, filenames_ref, 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

View file

@ -22,16 +22,30 @@ use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, span_file
use crate::coverageinfo::{ffi, llvm_cov}; use crate::coverageinfo::{ffi, llvm_cov};
use crate::llvm; use crate::llvm;
pub(crate) fn prepare_and_generate_covfun_record<'ll, 'tcx>( /// Intermediate coverage metadata for a single function, used to help build
cx: &CodegenCx<'ll, 'tcx>, /// the final record that will be embedded in the `__llvm_covfun` section.
#[derive(Debug)]
pub(crate) struct CovfunRecord<'tcx> {
mangled_function_name: &'tcx str,
source_hash: u64,
is_used: bool,
coverage_mapping_buffer: Vec<u8>,
}
impl<'tcx> CovfunRecord<'tcx> {
/// FIXME(Zalathar): Make this the responsibility of the code that determines
/// which functions are unused.
pub(crate) fn mangled_function_name_if_unused(&self) -> Option<&'tcx str> {
(!self.is_used).then_some(self.mangled_function_name)
}
}
pub(crate) fn prepare_covfun_record<'tcx>(
tcx: TyCtxt<'tcx>,
global_file_table: &GlobalFileTable, global_file_table: &GlobalFileTable,
filenames_ref: u64,
unused_function_names: &mut Vec<&'tcx str>,
instance: Instance<'tcx>, instance: Instance<'tcx>,
function_coverage: &FunctionCoverage<'tcx>, function_coverage: &FunctionCoverage<'tcx>,
) { ) -> Option<CovfunRecord<'tcx>> {
let tcx = cx.tcx;
let mangled_function_name = tcx.symbol_name(instance).name; let mangled_function_name = tcx.symbol_name(instance).name;
let source_hash = function_coverage.source_hash(); let source_hash = function_coverage.source_hash();
let is_used = function_coverage.is_used(); let is_used = function_coverage.is_used();
@ -47,22 +61,11 @@ pub(crate) fn prepare_and_generate_covfun_record<'ll, 'tcx>(
); );
} else { } else {
debug!("unused function had no coverage mapping data: {}", mangled_function_name); debug!("unused function had no coverage mapping data: {}", mangled_function_name);
return; return None;
} }
} }
if !is_used { Some(CovfunRecord { mangled_function_name, source_hash, is_used, coverage_mapping_buffer })
unused_function_names.push(mangled_function_name);
}
generate_covfun_record(
cx,
mangled_function_name,
source_hash,
filenames_ref,
coverage_mapping_buffer,
is_used,
);
} }
/// Using the expressions and counter regions collected for a single function, /// Using the expressions and counter regions collected for a single function,
@ -145,14 +148,18 @@ fn encode_mappings_for_function(
/// Generates the contents of the covfun record for this function, which /// Generates the contents of the covfun record for this function, which
/// contains the function's coverage mapping data. The record is then stored /// contains the function's coverage mapping data. The record is then stored
/// as a global variable in the `__llvm_covfun` section. /// as a global variable in the `__llvm_covfun` section.
fn generate_covfun_record( pub(crate) fn generate_covfun_record<'tcx>(
cx: &CodegenCx<'_, '_>, cx: &CodegenCx<'_, 'tcx>,
mangled_function_name: &str,
source_hash: u64,
filenames_ref: u64, filenames_ref: u64,
coverage_mapping_buffer: Vec<u8>, covfun: &CovfunRecord<'tcx>,
is_used: bool,
) { ) {
let &CovfunRecord {
mangled_function_name,
source_hash,
is_used,
ref coverage_mapping_buffer, // Previously-encoded coverage mappings
} = covfun;
// Concatenate the encoded coverage mappings // Concatenate the encoded coverage mappings
let coverage_mapping_size = coverage_mapping_buffer.len(); let coverage_mapping_size = coverage_mapping_buffer.len();
let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer); let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);