coverage: Emit the filenames section before encoding per-function mappings
Most coverage metadata is encoded into two sections in the final executable. The `__llvm_covmap` section mostly just contains a list of filenames, while the `__llvm_covfun` section contains encoded coverage maps for each instrumented function. The catch is that each per-function record also needs to contain a hash of the filenames list that it refers to. Historically this was handled by assembling most of the per-function data into a temporary list, then assembling the filenames buffer, then using the filenames hash to emit the per-function data, and then finally emitting the filenames table itself. However, now that we build the filenames table up-front (via a separate traversal of the per-function data), we can hash and emit that part first, and then emit each of the per-function records immediately after building. This removes the awkwardness of having to temporarily store nearly-complete per-function records.
This commit is contained in:
parent
de4cfbca2e
commit
6af9fef085
@ -67,8 +67,22 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||||||
function_coverage_entries.iter().flat_map(|(_, fn_cov)| fn_cov.all_file_names());
|
function_coverage_entries.iter().flat_map(|(_, fn_cov)| fn_cov.all_file_names());
|
||||||
let global_file_table = GlobalFileTable::new(all_file_names);
|
let global_file_table = GlobalFileTable::new(all_file_names);
|
||||||
|
|
||||||
|
// Encode all filenames referenced by coverage mappings in this CGU.
|
||||||
|
let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
|
||||||
|
|
||||||
|
let filenames_size = filenames_buffer.len();
|
||||||
|
let filenames_val = cx.const_bytes(&filenames_buffer);
|
||||||
|
let filenames_ref = coverageinfo::hash_bytes(&filenames_buffer);
|
||||||
|
|
||||||
|
// Generate the coverage map header, which contains the filenames used by
|
||||||
|
// this CGU's coverage mappings, and store it in a well-known global.
|
||||||
|
let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val);
|
||||||
|
coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
|
||||||
|
|
||||||
|
let mut unused_function_names = Vec::new();
|
||||||
|
let covfun_section_name = coverageinfo::covfun_section_name(cx);
|
||||||
|
|
||||||
// Encode coverage mappings and generate function records
|
// Encode coverage mappings and generate function records
|
||||||
let mut function_data = Vec::new();
|
|
||||||
for (instance, function_coverage) in function_coverage_entries {
|
for (instance, function_coverage) in function_coverage_entries {
|
||||||
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
|
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
|
||||||
|
|
||||||
@ -91,23 +105,6 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function_data.push((mangled_function_name, source_hash, is_used, coverage_mapping_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode all filenames referenced by counters/expressions in this module
|
|
||||||
let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
|
|
||||||
|
|
||||||
let filenames_size = filenames_buffer.len();
|
|
||||||
let filenames_val = cx.const_bytes(&filenames_buffer);
|
|
||||||
let filenames_ref = coverageinfo::hash_bytes(&filenames_buffer);
|
|
||||||
|
|
||||||
// Generate the LLVM IR representation of the coverage map and store it in a well-known global
|
|
||||||
let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val);
|
|
||||||
|
|
||||||
let mut unused_function_names = Vec::new();
|
|
||||||
|
|
||||||
let covfun_section_name = coverageinfo::covfun_section_name(cx);
|
|
||||||
for (mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
|
|
||||||
if !is_used {
|
if !is_used {
|
||||||
unused_function_names.push(mangled_function_name);
|
unused_function_names.push(mangled_function_name);
|
||||||
}
|
}
|
||||||
@ -141,9 +138,6 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||||||
llvm::set_linkage(array, llvm::Linkage::InternalLinkage);
|
llvm::set_linkage(array, llvm::Linkage::InternalLinkage);
|
||||||
llvm::set_initializer(array, initializer);
|
llvm::set_initializer(array, initializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the coverage data value to LLVM IR
|
|
||||||
coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
|
/// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
WINDOWS: $__llvm_profile_runtime_user = comdat any
|
WINDOWS: $__llvm_profile_runtime_user = comdat any
|
||||||
|
|
||||||
CHECK: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant
|
|
||||||
CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
|
|
||||||
|
|
||||||
CHECK: @__llvm_coverage_mapping = private constant
|
CHECK: @__llvm_coverage_mapping = private constant
|
||||||
CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8
|
CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8
|
||||||
|
|
||||||
|
CHECK: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant
|
||||||
|
CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
|
||||||
|
|
||||||
WINDOWS: @__llvm_profile_runtime = external{{.*}}global i32
|
WINDOWS: @__llvm_profile_runtime = external{{.*}}global i32
|
||||||
|
|
||||||
CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
|
CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
|
||||||
|
Loading…
Reference in New Issue
Block a user