coverage: Consolidate creation of covmap/covfun records
There is no need for this code to be split across multiple functions in multiple files.
This commit is contained in:
parent
a93c1718c8
commit
9f8a6be221
@ -1,7 +1,10 @@
|
|||||||
use std::ffi::CStr;
|
use std::ffi::{CStr, CString};
|
||||||
|
|
||||||
use itertools::Itertools as _;
|
use itertools::Itertools as _;
|
||||||
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
|
use rustc_abi::Align;
|
||||||
|
use rustc_codegen_ssa::traits::{
|
||||||
|
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
|
||||||
|
};
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
@ -10,6 +13,7 @@
|
|||||||
use rustc_middle::{bug, mir};
|
use rustc_middle::{bug, mir};
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
use rustc_span::def_id::DefIdSet;
|
use rustc_span::def_id::DefIdSet;
|
||||||
|
use rustc_target::spec::HasTargetSpec;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::common::CodegenCx;
|
use crate::common::CodegenCx;
|
||||||
@ -78,8 +82,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||||||
|
|
||||||
// Generate the coverage map header, which contains the filenames used by
|
// Generate the coverage map header, which contains the filenames used by
|
||||||
// this CGU's coverage mappings, and store it in a well-known global.
|
// this CGU's coverage mappings, and store it in a well-known global.
|
||||||
let cov_data_val = generate_coverage_map(cx, covmap_version, filenames_size, filenames_val);
|
generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
|
||||||
coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
|
|
||||||
|
|
||||||
let mut unused_function_names = Vec::new();
|
let mut unused_function_names = Vec::new();
|
||||||
let covfun_section_name = coverageinfo::covfun_section_name(cx);
|
let covfun_section_name = coverageinfo::covfun_section_name(cx);
|
||||||
@ -111,7 +114,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||||||
unused_function_names.push(mangled_function_name);
|
unused_function_names.push(mangled_function_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
save_function_record(
|
generate_covfun_record(
|
||||||
cx,
|
cx,
|
||||||
&covfun_section_name,
|
&covfun_section_name,
|
||||||
mangled_function_name,
|
mangled_function_name,
|
||||||
@ -308,15 +311,15 @@ fn encode_mappings_for_function(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct coverage map header and the array of function records, and combine them into the
|
/// Generates the contents of the covmap record for this CGU, which mostly
|
||||||
/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
|
/// consists of a header and a list of filenames. The record is then stored
|
||||||
/// specific, well-known section and name.
|
/// as a global variable in the `__llvm_covmap` section.
|
||||||
fn generate_coverage_map<'ll>(
|
fn generate_covmap_record<'ll>(
|
||||||
cx: &CodegenCx<'ll, '_>,
|
cx: &CodegenCx<'ll, '_>,
|
||||||
version: u32,
|
version: u32,
|
||||||
filenames_size: usize,
|
filenames_size: usize,
|
||||||
filenames_val: &'ll llvm::Value,
|
filenames_val: &'ll llvm::Value,
|
||||||
) -> &'ll llvm::Value {
|
) {
|
||||||
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
|
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
|
||||||
|
|
||||||
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
|
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
|
||||||
@ -331,13 +334,35 @@ fn generate_coverage_map<'ll>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Create the complete LLVM coverage data value to add to the LLVM IR
|
// Create the complete LLVM coverage data value to add to the LLVM IR
|
||||||
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
|
let covmap_data =
|
||||||
|
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false);
|
||||||
|
|
||||||
|
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||||
|
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
debug!("covmap var name: {:?}", covmap_var_name);
|
||||||
|
|
||||||
|
let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||||
|
llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
|
||||||
|
}))
|
||||||
|
.expect("covmap section name should not contain NUL");
|
||||||
|
debug!("covmap section name: {:?}", covmap_section_name);
|
||||||
|
|
||||||
|
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &covmap_var_name);
|
||||||
|
llvm::set_initializer(llglobal, covmap_data);
|
||||||
|
llvm::set_global_constant(llglobal, true);
|
||||||
|
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||||
|
llvm::set_section(llglobal, &covmap_section_name);
|
||||||
|
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||||
|
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||||
|
cx.add_used_global(llglobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a function record and combine it with the function's coverage mapping data.
|
/// Generates the contents of the covfun record for this function, which
|
||||||
/// Save the function record into the LLVM IR as a static global using a
|
/// contains the function's coverage mapping data. The record is then stored
|
||||||
/// specific, well-known section and name.
|
/// as a global variable in the `__llvm_covfun` section.
|
||||||
fn save_function_record(
|
fn generate_covfun_record(
|
||||||
cx: &CodegenCx<'_, '_>,
|
cx: &CodegenCx<'_, '_>,
|
||||||
covfun_section_name: &CStr,
|
covfun_section_name: &CStr,
|
||||||
mangled_function_name: &str,
|
mangled_function_name: &str,
|
||||||
@ -366,13 +391,27 @@ fn save_function_record(
|
|||||||
/*packed=*/ true,
|
/*packed=*/ true,
|
||||||
);
|
);
|
||||||
|
|
||||||
coverageinfo::save_func_record_to_mod(
|
// Choose a variable name to hold this function's covfun data.
|
||||||
cx,
|
// Functions that are used have a suffix ("u") to distinguish them from
|
||||||
covfun_section_name,
|
// unused copies of the same function (from different CGUs), so that if a
|
||||||
func_name_hash,
|
// linker sees both it won't discard the used copy's data.
|
||||||
func_record_val,
|
let func_record_var_name =
|
||||||
is_used,
|
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
|
||||||
);
|
.unwrap();
|
||||||
|
debug!("function record var name: {:?}", func_record_var_name);
|
||||||
|
|
||||||
|
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
|
||||||
|
llvm::set_initializer(llglobal, func_record_val);
|
||||||
|
llvm::set_global_constant(llglobal, true);
|
||||||
|
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
|
||||||
|
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
|
||||||
|
llvm::set_section(llglobal, covfun_section_name);
|
||||||
|
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||||
|
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||||
|
if cx.target_spec().supports_comdat() {
|
||||||
|
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
||||||
|
}
|
||||||
|
cx.add_used_global(llglobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
|
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::CString;
|
||||||
|
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use rustc_codegen_ssa::traits::{
|
use rustc_codegen_ssa::traits::{
|
||||||
BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods,
|
BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
|
||||||
MiscCodegenMethods, StaticCodegenMethods,
|
|
||||||
};
|
};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||||
use rustc_llvm::RustString;
|
use rustc_llvm::RustString;
|
||||||
@ -12,8 +11,7 @@
|
|||||||
use rustc_middle::mir::coverage::CoverageKind;
|
use rustc_middle::mir::coverage::CoverageKind;
|
||||||
use rustc_middle::ty::Instance;
|
use rustc_middle::ty::Instance;
|
||||||
use rustc_middle::ty::layout::HasTyCtxt;
|
use rustc_middle::ty::layout::HasTyCtxt;
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::Size;
|
||||||
use rustc_target::spec::HasTargetSpec;
|
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
@ -290,67 +288,6 @@ pub(crate) fn mapping_version() -> u32 {
|
|||||||
unsafe { llvm::LLVMRustCoverageMappingVersion() }
|
unsafe { llvm::LLVMRustCoverageMappingVersion() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
|
|
||||||
cx: &CodegenCx<'ll, 'tcx>,
|
|
||||||
cov_data_val: &'ll llvm::Value,
|
|
||||||
) {
|
|
||||||
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
|
||||||
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
|
|
||||||
}))
|
|
||||||
.unwrap();
|
|
||||||
debug!("covmap var name: {:?}", covmap_var_name);
|
|
||||||
|
|
||||||
let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
|
||||||
llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
|
|
||||||
}))
|
|
||||||
.expect("covmap section name should not contain NUL");
|
|
||||||
debug!("covmap section name: {:?}", covmap_section_name);
|
|
||||||
|
|
||||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
|
|
||||||
llvm::set_initializer(llglobal, cov_data_val);
|
|
||||||
llvm::set_global_constant(llglobal, true);
|
|
||||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
|
||||||
llvm::set_section(llglobal, &covmap_section_name);
|
|
||||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
|
||||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
|
||||||
cx.add_used_global(llglobal);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
|
|
||||||
cx: &CodegenCx<'ll, 'tcx>,
|
|
||||||
covfun_section_name: &CStr,
|
|
||||||
func_name_hash: u64,
|
|
||||||
func_record_val: &'ll llvm::Value,
|
|
||||||
is_used: bool,
|
|
||||||
) {
|
|
||||||
// Assign a name to the function record. This is used to merge duplicates.
|
|
||||||
//
|
|
||||||
// In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that
|
|
||||||
// are included-but-not-used. If (or when) Rust generates functions that are
|
|
||||||
// included-but-not-used, note that a dummy description for a function included-but-not-used
|
|
||||||
// in a Crate can be replaced by full description provided by a different Crate. The two kinds
|
|
||||||
// of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
|
|
||||||
// appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
|
|
||||||
let func_record_var_name =
|
|
||||||
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
|
|
||||||
.unwrap();
|
|
||||||
debug!("function record var name: {:?}", func_record_var_name);
|
|
||||||
debug!("function record section name: {:?}", covfun_section_name);
|
|
||||||
|
|
||||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
|
|
||||||
llvm::set_initializer(llglobal, func_record_val);
|
|
||||||
llvm::set_global_constant(llglobal, true);
|
|
||||||
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
|
|
||||||
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
|
|
||||||
llvm::set_section(llglobal, covfun_section_name);
|
|
||||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
|
||||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
|
||||||
if cx.target_spec().supports_comdat() {
|
|
||||||
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
|
||||||
}
|
|
||||||
cx.add_used_global(llglobal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the section name string to pass through to the linker when embedding
|
/// Returns the section name string to pass through to the linker when embedding
|
||||||
/// per-function coverage information in the object file, according to the target
|
/// per-function coverage information in the object file, according to the target
|
||||||
/// platform's object file format.
|
/// platform's object file format.
|
||||||
|
Loading…
Reference in New Issue
Block a user