Skip to content

Commit 9f8a6be

Browse files
committed
coverage: Consolidate creation of covmap/covfun records
There is no need for this code to be split across multiple functions in multiple files.
1 parent a93c171 commit 9f8a6be

File tree

2 files changed

+64
-88
lines changed

2 files changed

+64
-88
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

+61-22
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
use std::ffi::CStr;
1+
use std::ffi::{CStr, 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;
@@ -78,8 +82,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
7882

7983
// Generate the coverage map header, which contains the filenames used by
8084
// 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);
85+
generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
8386

8487
let mut unused_function_names = Vec::new();
8588
let covfun_section_name = coverageinfo::covfun_section_name(cx);
@@ -111,7 +114,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
111114
unused_function_names.push(mangled_function_name);
112115
}
113116

114-
save_function_record(
117+
generate_covfun_record(
115118
cx,
116119
&covfun_section_name,
117120
mangled_function_name,
@@ -308,15 +311,15 @@ fn encode_mappings_for_function(
308311
})
309312
}
310313

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>(
314+
/// Generates the contents of the covmap record for this CGU, which mostly
315+
/// consists of a header and a list of filenames. The record is then stored
316+
/// as a global variable in the `__llvm_covmap` section.
317+
fn generate_covmap_record<'ll>(
315318
cx: &CodegenCx<'ll, '_>,
316319
version: u32,
317320
filenames_size: usize,
318321
filenames_val: &'ll llvm::Value,
319-
) -> &'ll llvm::Value {
322+
) {
320323
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
321324

322325
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
@@ -331,13 +334,35 @@ fn generate_coverage_map<'ll>(
331334
);
332335

333336
// 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)
337+
let covmap_data =
338+
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false);
339+
340+
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
341+
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
342+
}))
343+
.unwrap();
344+
debug!("covmap var name: {:?}", covmap_var_name);
345+
346+
let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
347+
llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
348+
}))
349+
.expect("covmap section name should not contain NUL");
350+
debug!("covmap section name: {:?}", covmap_section_name);
351+
352+
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &covmap_var_name);
353+
llvm::set_initializer(llglobal, covmap_data);
354+
llvm::set_global_constant(llglobal, true);
355+
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
356+
llvm::set_section(llglobal, &covmap_section_name);
357+
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
358+
llvm::set_alignment(llglobal, Align::EIGHT);
359+
cx.add_used_global(llglobal);
335360
}
336361

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(
362+
/// Generates the contents of the covfun record for this function, which
363+
/// contains the function's coverage mapping data. The record is then stored
364+
/// as a global variable in the `__llvm_covfun` section.
365+
fn generate_covfun_record(
341366
cx: &CodegenCx<'_, '_>,
342367
covfun_section_name: &CStr,
343368
mangled_function_name: &str,
@@ -366,13 +391,27 @@ fn save_function_record(
366391
/*packed=*/ true,
367392
);
368393

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-
);
394+
// Choose a variable name to hold this function's covfun data.
395+
// Functions that are used have a suffix ("u") to distinguish them from
396+
// unused copies of the same function (from different CGUs), so that if a
397+
// linker sees both it won't discard the used copy's data.
398+
let func_record_var_name =
399+
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
400+
.unwrap();
401+
debug!("function record var name: {:?}", func_record_var_name);
402+
403+
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
404+
llvm::set_initializer(llglobal, func_record_val);
405+
llvm::set_global_constant(llglobal, true);
406+
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
407+
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
408+
llvm::set_section(llglobal, covfun_section_name);
409+
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
410+
llvm::set_alignment(llglobal, Align::EIGHT);
411+
if cx.target_spec().supports_comdat() {
412+
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
413+
}
414+
cx.add_used_global(llglobal);
376415
}
377416

378417
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.

compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

+3-66
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
use std::cell::RefCell;
2-
use std::ffi::{CStr, CString};
2+
use std::ffi::CString;
33

44
use libc::c_uint;
55
use rustc_codegen_ssa::traits::{
6-
BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods,
7-
MiscCodegenMethods, StaticCodegenMethods,
6+
BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
87
};
98
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
109
use rustc_llvm::RustString;
1110
use rustc_middle::bug;
1211
use rustc_middle::mir::coverage::CoverageKind;
1312
use rustc_middle::ty::Instance;
1413
use rustc_middle::ty::layout::HasTyCtxt;
15-
use rustc_target::abi::{Align, Size};
16-
use rustc_target::spec::HasTargetSpec;
14+
use rustc_target::abi::Size;
1715
use tracing::{debug, instrument};
1816

1917
use crate::builder::Builder;
@@ -290,67 +288,6 @@ pub(crate) fn mapping_version() -> u32 {
290288
unsafe { llvm::LLVMRustCoverageMappingVersion() }
291289
}
292290

293-
pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
294-
cx: &CodegenCx<'ll, 'tcx>,
295-
cov_data_val: &'ll llvm::Value,
296-
) {
297-
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
298-
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
299-
}))
300-
.unwrap();
301-
debug!("covmap var name: {:?}", covmap_var_name);
302-
303-
let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
304-
llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
305-
}))
306-
.expect("covmap section name should not contain NUL");
307-
debug!("covmap section name: {:?}", covmap_section_name);
308-
309-
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
310-
llvm::set_initializer(llglobal, cov_data_val);
311-
llvm::set_global_constant(llglobal, true);
312-
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
313-
llvm::set_section(llglobal, &covmap_section_name);
314-
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
315-
llvm::set_alignment(llglobal, Align::EIGHT);
316-
cx.add_used_global(llglobal);
317-
}
318-
319-
pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
320-
cx: &CodegenCx<'ll, 'tcx>,
321-
covfun_section_name: &CStr,
322-
func_name_hash: u64,
323-
func_record_val: &'ll llvm::Value,
324-
is_used: bool,
325-
) {
326-
// Assign a name to the function record. This is used to merge duplicates.
327-
//
328-
// In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that
329-
// are included-but-not-used. If (or when) Rust generates functions that are
330-
// included-but-not-used, note that a dummy description for a function included-but-not-used
331-
// in a Crate can be replaced by full description provided by a different Crate. The two kinds
332-
// of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
333-
// appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
334-
let func_record_var_name =
335-
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
336-
.unwrap();
337-
debug!("function record var name: {:?}", func_record_var_name);
338-
debug!("function record section name: {:?}", covfun_section_name);
339-
340-
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
341-
llvm::set_initializer(llglobal, func_record_val);
342-
llvm::set_global_constant(llglobal, true);
343-
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
344-
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
345-
llvm::set_section(llglobal, covfun_section_name);
346-
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
347-
llvm::set_alignment(llglobal, Align::EIGHT);
348-
if cx.target_spec().supports_comdat() {
349-
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
350-
}
351-
cx.add_used_global(llglobal);
352-
}
353-
354291
/// Returns the section name string to pass through to the linker when embedding
355292
/// per-function coverage information in the object file, according to the target
356293
/// platform's object file format.

0 commit comments

Comments
 (0)