about summary refs log tree commit diff
diff options
context:
space:
mode:
authorZalathar <Zalathar@users.noreply.github.com>2023-10-06 23:53:23 +1100
committerZalathar <Zalathar@users.noreply.github.com>2023-10-22 23:17:15 +1100
commit6af9fef08590fd499370a2f6cbbae9ceacf15336 (patch)
tree1dfd7054f65f892d1864acfd2785ad567c259ceb
parentde4cfbca2ebec9c91037370146c518c069ece033 (diff)
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.
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs36
-rw-r--r--tests/run-make/coverage-llvmir/filecheck.testprog.txt6
2 files changed, 18 insertions, 24 deletions
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index daf5d06110a..274e0aeaaba 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -67,8 +67,22 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         function_coverage_entries.iter().flat_map(|(_, fn_cov)| fn_cov.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
-    let mut function_data = Vec::new();
     for (instance, function_coverage) in function_coverage_entries {
         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 {
             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_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.
diff --git a/tests/run-make/coverage-llvmir/filecheck.testprog.txt b/tests/run-make/coverage-llvmir/filecheck.testprog.txt
index 9d63fabd788..8ab18da21a2 100644
--- a/tests/run-make/coverage-llvmir/filecheck.testprog.txt
+++ b/tests/run-make/coverage-llvmir/filecheck.testprog.txt
@@ -3,12 +3,12 @@
 
 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-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
 
 CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global