Skip to content

Commit 58440ea

Browse files
authored
Unrolled build for rust-lang#132124
Rollup merge of rust-lang#132124 - Zalathar:consolidate-covstar, r=jieyouxu coverage: Consolidate creation of covmap/covfun records This code for creating covmap/covfun records during codegen was split across multiple functions and files for dubious historical reasons. Having it all in one place makes it easier to follow. This PR also includes two semi-related cleanups: - Getting the codegen context's `coverage_cx` state is made infallible, since it should always exist when running the code paths that need it. - The value of `covfun_section_name` is saved in the codegen context, since it never changes at runtime, and the code that needs it has access to the context anyway. --- Background: Coverage instrumentation generates two kinds of metadata that are embedded in the final binary. There is per-CGU information that goes in the `__llvm_covmap` linker section, and per-function information that goes in the `__llvm_covfun` section (except on Windows, where slightly different section names are used).
2 parents 17f8215 + 0d653a5 commit 58440ea

File tree

3 files changed

+102
-144
lines changed

3 files changed

+102
-144
lines changed

compiler/rustc_codegen_llvm/src/context.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub(crate) struct CodegenCx<'ll, 'tcx> {
8080

8181
pub isize_ty: &'ll Type,
8282

83+
/// Extra codegen state needed when coverage instrumentation is enabled.
8384
pub coverage_cx: Option<coverageinfo::CrateCoverageContext<'ll, 'tcx>>,
8485
pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>,
8586

@@ -592,11 +593,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
592593
&self.statics_to_rauw
593594
}
594595

596+
/// Extra state that is only available when coverage instrumentation is enabled.
595597
#[inline]
596-
pub(crate) fn coverage_context(
597-
&self,
598-
) -> Option<&coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
599-
self.coverage_cx.as_ref()
598+
pub(crate) fn coverage_cx(&self) -> &coverageinfo::CrateCoverageContext<'ll, 'tcx> {
599+
self.coverage_cx.as_ref().expect("only called when coverage instrumentation is enabled")
600600
}
601601

602602
pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

+65-35
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
use std::ffi::CStr;
1+
use std::ffi::CString;
22

33
use itertools::Itertools as _;
4-
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
4+
use rustc_abi::Align;
5+
use rustc_codegen_ssa::traits::{
6+
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
7+
};
58
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
69
use rustc_hir::def_id::{DefId, LocalDefId};
710
use rustc_index::IndexVec;
@@ -10,6 +13,7 @@ use rustc_middle::ty::{self, TyCtxt};
1013
use rustc_middle::{bug, mir};
1114
use rustc_span::Symbol;
1215
use rustc_span::def_id::DefIdSet;
16+
use rustc_target::spec::HasTargetSpec;
1317
use tracing::debug;
1418

1519
use crate::common::CodegenCx;
@@ -50,11 +54,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
5054
add_unused_functions(cx);
5155
}
5256

53-
let function_coverage_map = match cx.coverage_context() {
54-
Some(ctx) => ctx.take_function_coverage_map(),
55-
None => return,
56-
};
57-
57+
let function_coverage_map = cx.coverage_cx().take_function_coverage_map();
5858
if function_coverage_map.is_empty() {
5959
// This module has no functions with coverage instrumentation
6060
return;
@@ -78,11 +78,9 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
7878

7979
// Generate the coverage map header, which contains the filenames used by
8080
// this CGU's coverage mappings, and store it in a well-known global.
81-
let cov_data_val = generate_coverage_map(cx, covmap_version, filenames_size, filenames_val);
82-
coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
81+
generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
8382

8483
let mut unused_function_names = Vec::new();
85-
let covfun_section_name = coverageinfo::covfun_section_name(cx);
8684

8785
// Encode coverage mappings and generate function records
8886
for (instance, function_coverage) in function_coverage_entries {
@@ -111,9 +109,8 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
111109
unused_function_names.push(mangled_function_name);
112110
}
113111

114-
save_function_record(
112+
generate_covfun_record(
115113
cx,
116-
&covfun_section_name,
117114
mangled_function_name,
118115
source_hash,
119116
filenames_ref,
@@ -308,15 +305,15 @@ fn encode_mappings_for_function(
308305
})
309306
}
310307

311-
/// Construct coverage map header and the array of function records, and combine them into the
312-
/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
313-
/// specific, well-known section and name.
314-
fn generate_coverage_map<'ll>(
308+
/// Generates the contents of the covmap record for this CGU, which mostly
309+
/// consists of a header and a list of filenames. The record is then stored
310+
/// as a global variable in the `__llvm_covmap` section.
311+
fn generate_covmap_record<'ll>(
315312
cx: &CodegenCx<'ll, '_>,
316313
version: u32,
317314
filenames_size: usize,
318315
filenames_val: &'ll llvm::Value,
319-
) -> &'ll llvm::Value {
316+
) {
320317
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
321318

322319
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
@@ -331,15 +328,37 @@ fn generate_coverage_map<'ll>(
331328
);
332329

333330
// Create the complete LLVM coverage data value to add to the LLVM IR
334-
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
331+
let covmap_data =
332+
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false);
333+
334+
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
335+
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
336+
}))
337+
.unwrap();
338+
debug!("covmap var name: {:?}", covmap_var_name);
339+
340+
let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
341+
llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
342+
}))
343+
.expect("covmap section name should not contain NUL");
344+
debug!("covmap section name: {:?}", covmap_section_name);
345+
346+
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &covmap_var_name);
347+
llvm::set_initializer(llglobal, covmap_data);
348+
llvm::set_global_constant(llglobal, true);
349+
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
350+
llvm::set_section(llglobal, &covmap_section_name);
351+
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
352+
// <https://llvm.org/docs/CoverageMappingFormat.html>
353+
llvm::set_alignment(llglobal, Align::EIGHT);
354+
cx.add_used_global(llglobal);
335355
}
336356

337-
/// Construct a function record and combine it with the function's coverage mapping data.
338-
/// Save the function record into the LLVM IR as a static global using a
339-
/// specific, well-known section and name.
340-
fn save_function_record(
357+
/// Generates the contents of the covfun record for this function, which
358+
/// contains the function's coverage mapping data. The record is then stored
359+
/// as a global variable in the `__llvm_covfun` section.
360+
fn generate_covfun_record(
341361
cx: &CodegenCx<'_, '_>,
342-
covfun_section_name: &CStr,
343362
mangled_function_name: &str,
344363
source_hash: u64,
345364
filenames_ref: u64,
@@ -366,13 +385,28 @@ fn save_function_record(
366385
/*packed=*/ true,
367386
);
368387

369-
coverageinfo::save_func_record_to_mod(
370-
cx,
371-
covfun_section_name,
372-
func_name_hash,
373-
func_record_val,
374-
is_used,
375-
);
388+
// Choose a variable name to hold this function's covfun data.
389+
// Functions that are used have a suffix ("u") to distinguish them from
390+
// unused copies of the same function (from different CGUs), so that if a
391+
// linker sees both it won't discard the used copy's data.
392+
let func_record_var_name =
393+
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
394+
.unwrap();
395+
debug!("function record var name: {:?}", func_record_var_name);
396+
397+
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
398+
llvm::set_initializer(llglobal, func_record_val);
399+
llvm::set_global_constant(llglobal, true);
400+
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
401+
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
402+
llvm::set_section(llglobal, cx.covfun_section_name());
403+
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
404+
// <https://llvm.org/docs/CoverageMappingFormat.html>
405+
llvm::set_alignment(llglobal, Align::EIGHT);
406+
if cx.target_spec().supports_comdat() {
407+
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
408+
}
409+
cx.add_used_global(llglobal);
376410
}
377411

378412
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
@@ -504,9 +538,5 @@ fn add_unused_function_coverage<'tcx>(
504538
// zero, because none of its counters/expressions are marked as seen.
505539
let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info);
506540

507-
if let Some(coverage_context) = cx.coverage_context() {
508-
coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);
509-
} else {
510-
bug!("Could not get the `coverage_context`");
511-
}
541+
cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage);
512542
}

0 commit comments

Comments
 (0)