summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_llvm/src/coverageinfo
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_llvm/src/coverageinfo')
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs204
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs89
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs47
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs87
4 files changed, 303 insertions, 124 deletions
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 1791ce4b3..7a82d05ce 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -1,4 +1,4 @@
-use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
+use rustc_middle::mir::coverage::{CounterId, MappedExpressionIndex};
/// Must match the layout of `LLVMRustCounterKind`.
#[derive(Copy, Clone, Debug)]
@@ -36,11 +36,9 @@ impl Counter {
Self { kind: CounterKind::Zero, id: 0 }
}
- /// Constructs a new `Counter` of kind `CounterValueReference`, and converts
- /// the given 1-based counter_id to the required 0-based equivalent for
- /// the `Counter` encoding.
- pub fn counter_value_reference(counter_id: CounterValueReference) -> Self {
- Self { kind: CounterKind::CounterValueReference, id: counter_id.zero_based_index() }
+ /// Constructs a new `Counter` of kind `CounterValueReference`.
+ pub fn counter_value_reference(counter_id: CounterId) -> Self {
+ Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() }
}
/// Constructs a new `Counter` of kind `Expression`.
@@ -87,3 +85,197 @@ impl CounterExpression {
Self { kind, lhs, rhs }
}
}
+
+/// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`.
+///
+/// Must match the layout of `LLVMRustCounterMappingRegionKind`.
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub enum RegionKind {
+ /// A CodeRegion associates some code with a counter
+ CodeRegion = 0,
+
+ /// An ExpansionRegion represents a file expansion region that associates
+ /// a source range with the expansion of a virtual source file, such as
+ /// for a macro instantiation or #include file.
+ ExpansionRegion = 1,
+
+ /// A SkippedRegion represents a source range with code that was skipped
+ /// by a preprocessor or similar means.
+ SkippedRegion = 2,
+
+ /// A GapRegion is like a CodeRegion, but its count is only set as the
+ /// line execution count when its the only region in the line.
+ GapRegion = 3,
+
+ /// A BranchRegion represents leaf-level boolean expressions and is
+ /// associated with two counters, each representing the number of times the
+ /// expression evaluates to true or false.
+ BranchRegion = 4,
+}
+
+/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
+/// coverage map, in accordance with the
+/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+/// The struct composes fields representing the `Counter` type and value(s) (injected counter
+/// ID, or expression type and operands), the source file (an indirect index into a "filenames
+/// array", encoded separately), and source location (start and end positions of the represented
+/// code region).
+///
+/// Corresponds to struct `llvm::coverage::CounterMappingRegion`.
+///
+/// Must match the layout of `LLVMRustCounterMappingRegion`.
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct CounterMappingRegion {
+ /// The counter type and type-dependent counter data, if any.
+ counter: Counter,
+
+ /// If the `RegionKind` is a `BranchRegion`, this represents the counter
+ /// for the false branch of the region.
+ false_counter: Counter,
+
+ /// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
+ /// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
+ /// that, in turn, are used to look up the filename for this region.
+ file_id: u32,
+
+ /// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find
+ /// the mapping regions created as a result of macro expansion, by checking if their file id
+ /// matches the expanded file id.
+ expanded_file_id: u32,
+
+ /// 1-based starting line of the mapping region.
+ start_line: u32,
+
+ /// 1-based starting column of the mapping region.
+ start_col: u32,
+
+ /// 1-based ending line of the mapping region.
+ end_line: u32,
+
+ /// 1-based ending column of the mapping region. If the high bit is set, the current
+ /// mapping region is a gap area.
+ end_col: u32,
+
+ kind: RegionKind,
+}
+
+impl CounterMappingRegion {
+ pub(crate) fn code_region(
+ counter: Counter,
+ file_id: u32,
+ start_line: u32,
+ start_col: u32,
+ end_line: u32,
+ end_col: u32,
+ ) -> Self {
+ Self {
+ counter,
+ false_counter: Counter::zero(),
+ file_id,
+ expanded_file_id: 0,
+ start_line,
+ start_col,
+ end_line,
+ end_col,
+ kind: RegionKind::CodeRegion,
+ }
+ }
+
+ // This function might be used in the future; the LLVM API is still evolving, as is coverage
+ // support.
+ #[allow(dead_code)]
+ pub(crate) fn branch_region(
+ counter: Counter,
+ false_counter: Counter,
+ file_id: u32,
+ start_line: u32,
+ start_col: u32,
+ end_line: u32,
+ end_col: u32,
+ ) -> Self {
+ Self {
+ counter,
+ false_counter,
+ file_id,
+ expanded_file_id: 0,
+ start_line,
+ start_col,
+ end_line,
+ end_col,
+ kind: RegionKind::BranchRegion,
+ }
+ }
+
+ // This function might be used in the future; the LLVM API is still evolving, as is coverage
+ // support.
+ #[allow(dead_code)]
+ pub(crate) fn expansion_region(
+ file_id: u32,
+ expanded_file_id: u32,
+ start_line: u32,
+ start_col: u32,
+ end_line: u32,
+ end_col: u32,
+ ) -> Self {
+ Self {
+ counter: Counter::zero(),
+ false_counter: Counter::zero(),
+ file_id,
+ expanded_file_id,
+ start_line,
+ start_col,
+ end_line,
+ end_col,
+ kind: RegionKind::ExpansionRegion,
+ }
+ }
+
+ // This function might be used in the future; the LLVM API is still evolving, as is coverage
+ // support.
+ #[allow(dead_code)]
+ pub(crate) fn skipped_region(
+ file_id: u32,
+ start_line: u32,
+ start_col: u32,
+ end_line: u32,
+ end_col: u32,
+ ) -> Self {
+ Self {
+ counter: Counter::zero(),
+ false_counter: Counter::zero(),
+ file_id,
+ expanded_file_id: 0,
+ start_line,
+ start_col,
+ end_line,
+ end_col,
+ kind: RegionKind::SkippedRegion,
+ }
+ }
+
+ // This function might be used in the future; the LLVM API is still evolving, as is coverage
+ // support.
+ #[allow(dead_code)]
+ pub(crate) fn gap_region(
+ counter: Counter,
+ file_id: u32,
+ start_line: u32,
+ start_col: u32,
+ end_line: u32,
+ end_col: u32,
+ ) -> Self {
+ Self {
+ counter,
+ false_counter: Counter::zero(),
+ file_id,
+ expanded_file_id: 0,
+ start_line,
+ start_col,
+ end_line,
+ end_col: (1_u32 << 31) | end_col,
+ kind: RegionKind::GapRegion,
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 06844afd6..f1e68af25 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -1,26 +1,24 @@
-pub use super::ffi::*;
+use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::bug;
use rustc_middle::mir::coverage::{
- CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId,
- InjectedExpressionIndex, MappedExpressionIndex, Op,
+ CodeRegion, CounterId, ExpressionId, MappedExpressionIndex, Op, Operand,
};
use rustc_middle::ty::Instance;
use rustc_middle::ty::TyCtxt;
#[derive(Clone, Debug, PartialEq)]
pub struct Expression {
- lhs: ExpressionOperandId,
+ lhs: Operand,
op: Op,
- rhs: ExpressionOperandId,
+ rhs: Operand,
region: Option<CodeRegion>,
}
/// Collects all of the coverage regions associated with (a) injected counters, (b) counter
/// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero),
-/// for a given Function. Counters and counter expressions have non-overlapping `id`s because they
-/// can both be operands in an expression. This struct also stores the `function_source_hash`,
+/// for a given Function. This struct also stores the `function_source_hash`,
/// computed during instrumentation, and forwarded with counters.
///
/// Note, it may be important to understand LLVM's definitions of `unreachable` regions versus "gap
@@ -34,8 +32,8 @@ pub struct FunctionCoverage<'tcx> {
instance: Instance<'tcx>,
source_hash: u64,
is_used: bool,
- counters: IndexVec<CounterValueReference, Option<CodeRegion>>,
- expressions: IndexVec<InjectedExpressionIndex, Option<Expression>>,
+ counters: IndexVec<CounterId, Option<CodeRegion>>,
+ expressions: IndexVec<ExpressionId, Option<Expression>>,
unreachable_regions: Vec<CodeRegion>,
}
@@ -82,48 +80,36 @@ impl<'tcx> FunctionCoverage<'tcx> {
}
/// Adds a code region to be counted by an injected counter intrinsic.
- pub fn add_counter(&mut self, id: CounterValueReference, region: CodeRegion) {
+ pub fn add_counter(&mut self, id: CounterId, region: CodeRegion) {
if let Some(previous_region) = self.counters[id].replace(region.clone()) {
assert_eq!(previous_region, region, "add_counter: code region for id changed");
}
}
/// Both counters and "counter expressions" (or simply, "expressions") can be operands in other
- /// expressions. Expression IDs start from `u32::MAX` and go down, so the range of expression
- /// IDs will not overlap with the range of counter IDs. Counters and expressions can be added in
- /// any order, and expressions can still be assigned contiguous (though descending) IDs, without
- /// knowing what the last counter ID will be.
- ///
- /// When storing the expression data in the `expressions` vector in the `FunctionCoverage`
- /// struct, its vector index is computed, from the given expression ID, by subtracting from
- /// `u32::MAX`.
- ///
- /// Since the expression operands (`lhs` and `rhs`) can reference either counters or
- /// expressions, an operand that references an expression also uses its original ID, descending
- /// from `u32::MAX`. Theses operands are translated only during code generation, after all
- /// counters and expressions have been added.
+ /// expressions. These are tracked as separate variants of `Operand`, so there is no ambiguity
+ /// between operands that are counter IDs and operands that are expression IDs.
pub fn add_counter_expression(
&mut self,
- expression_id: InjectedExpressionId,
- lhs: ExpressionOperandId,
+ expression_id: ExpressionId,
+ lhs: Operand,
op: Op,
- rhs: ExpressionOperandId,
+ rhs: Operand,
region: Option<CodeRegion>,
) {
debug!(
"add_counter_expression({:?}, lhs={:?}, op={:?}, rhs={:?} at {:?}",
expression_id, lhs, op, rhs, region
);
- let expression_index = self.expression_index(u32::from(expression_id));
debug_assert!(
- expression_index.as_usize() < self.expressions.len(),
- "expression_index {} is out of range for expressions.len() = {}
+ expression_id.as_usize() < self.expressions.len(),
+ "expression_id {} is out of range for expressions.len() = {}
for {:?}",
- expression_index.as_usize(),
+ expression_id.as_usize(),
self.expressions.len(),
self,
);
- if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
+ if let Some(previous_expression) = self.expressions[expression_id].replace(Expression {
lhs,
op,
rhs,
@@ -186,14 +172,11 @@ impl<'tcx> FunctionCoverage<'tcx> {
// This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or
// `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type
- // and value. Operand ID value `0` maps to `CounterKind::Zero`; values in the known range
- // of injected LLVM counters map to `CounterKind::CounterValueReference` (and the value
- // matches the injected counter index); and any other value is converted into a
- // `CounterKind::Expression` with the expression's `new_index`.
+ // and value.
//
// Expressions will be returned from this function in a sequential vector (array) of
// `CounterExpression`, so the expression IDs must be mapped from their original,
- // potentially sparse set of indexes, originally in reverse order from `u32::MAX`.
+ // potentially sparse set of indexes.
//
// An `Expression` as an operand will have already been encountered as an `Expression` with
// operands, so its new_index will already have been generated (as a 1-up index value).
@@ -206,34 +189,19 @@ impl<'tcx> FunctionCoverage<'tcx> {
// `expression_index`s lower than the referencing `Expression`. Therefore, it is
// reasonable to look up the new index of an expression operand while the `new_indexes`
// vector is only complete up to the current `ExpressionIndex`.
- let id_to_counter = |new_indexes: &IndexSlice<
- InjectedExpressionIndex,
- Option<MappedExpressionIndex>,
- >,
- id: ExpressionOperandId| {
- if id == ExpressionOperandId::ZERO {
- Some(Counter::zero())
- } else if id.index() < self.counters.len() {
- debug_assert!(
- id.index() > 0,
- "ExpressionOperandId indexes for counters are 1-based, but this id={}",
- id.index()
- );
- // Note: Some codegen-injected Counters may be only referenced by `Expression`s,
- // and may not have their own `CodeRegion`s,
- let index = CounterValueReference::from(id.index());
- // Note, the conversion to LLVM `Counter` adjusts the index to be zero-based.
- Some(Counter::counter_value_reference(index))
- } else {
- let index = self.expression_index(u32::from(id));
+ type NewIndexes = IndexSlice<ExpressionId, Option<MappedExpressionIndex>>;
+ let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand {
+ Operand::Zero => Some(Counter::zero()),
+ Operand::Counter(id) => Some(Counter::counter_value_reference(id)),
+ Operand::Expression(id) => {
self.expressions
- .get(index)
+ .get(id)
.expect("expression id is out of range")
.as_ref()
// If an expression was optimized out, assume it would have produced a count
// of zero. This ensures that expressions dependent on optimized-out
// expressions are still valid.
- .map_or(Some(Counter::zero()), |_| new_indexes[index].map(Counter::expression))
+ .map_or(Some(Counter::zero()), |_| new_indexes[id].map(Counter::expression))
}
};
@@ -340,9 +308,4 @@ impl<'tcx> FunctionCoverage<'tcx> {
fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
}
-
- fn expression_index(&self, id_descending_from_max: u32) -> InjectedExpressionIndex {
- debug_assert!(id_descending_from_max >= self.counters.len() as u32);
- InjectedExpressionIndex::from(u32::MAX - id_descending_from_max)
- }
}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index a1ff2aa66..97a99e510 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,9 +1,8 @@
use crate::common::CodegenCx;
use crate::coverageinfo;
-use crate::coverageinfo::map_data::{Counter, CounterExpression};
+use crate::coverageinfo::ffi::{Counter, CounterExpression, CounterMappingRegion};
use crate::llvm;
-use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::traits::ConstMethods;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def::DefKind;
@@ -13,8 +12,7 @@ use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::CodeRegion;
use rustc_middle::ty::TyCtxt;
-
-use std::ffi::CString;
+use rustc_span::Symbol;
/// Generates and exports the Coverage Map.
///
@@ -63,7 +61,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
let mut function_data = Vec::new();
for (instance, function_coverage) in function_coverage_map {
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
- let mangled_function_name = tcx.symbol_name(instance).to_string();
+ let mangled_function_name = tcx.symbol_name(instance).name;
let source_hash = function_coverage.source_hash();
let is_used = function_coverage.is_used();
let (expressions, counter_regions) =
@@ -90,19 +88,24 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
// Encode all filenames referenced by counters/expressions in this module
let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
- coverageinfo::write_filenames_section_to_buffer(&mapgen.filenames, filenames_buffer);
+ coverageinfo::write_filenames_section_to_buffer(
+ mapgen.filenames.iter().map(Symbol::as_str),
+ filenames_buffer,
+ );
});
let filenames_size = filenames_buffer.len();
let filenames_val = cx.const_bytes(&filenames_buffer);
- let filenames_ref = coverageinfo::hash_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 = mapgen.generate_coverage_map(cx, version, filenames_size, filenames_val);
+ let covfun_section_name = coverageinfo::covfun_section_name(cx);
for (mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
save_function_record(
cx,
+ &covfun_section_name,
mangled_function_name,
source_hash,
filenames_ref,
@@ -116,7 +119,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
}
struct CoverageMapGenerator {
- filenames: FxIndexSet<CString>,
+ filenames: FxIndexSet<Symbol>,
}
impl CoverageMapGenerator {
@@ -127,11 +130,10 @@ impl CoverageMapGenerator {
// Since rustc generates coverage maps with relative paths, the
// compilation directory can be combined with the relative paths
// to get absolute paths, if needed.
- let working_dir =
- tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy().to_string();
- let c_filename =
- CString::new(working_dir).expect("null error converting filename to C string");
- filenames.insert(c_filename);
+ let working_dir = Symbol::intern(
+ &tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy(),
+ );
+ filenames.insert(working_dir);
Self { filenames }
}
@@ -169,10 +171,8 @@ impl CoverageMapGenerator {
current_file_id += 1;
}
current_file_name = Some(file_name);
- let c_filename = CString::new(file_name.to_string())
- .expect("null error converting filename to C string");
- debug!(" file_id: {} = '{:?}'", current_file_id, c_filename);
- let (filenames_index, _) = self.filenames.insert_full(c_filename);
+ debug!(" file_id: {} = '{:?}'", current_file_id, file_name);
+ let (filenames_index, _) = self.filenames.insert_full(file_name);
virtual_file_mapping.push(filenames_index as u32);
}
debug!("Adding counter {:?} to map for {:?}", counter, region);
@@ -228,7 +228,8 @@ impl CoverageMapGenerator {
/// specific, well-known section and name.
fn save_function_record(
cx: &CodegenCx<'_, '_>,
- mangled_function_name: String,
+ covfun_section_name: &str,
+ mangled_function_name: &str,
source_hash: u64,
filenames_ref: u64,
coverage_mapping_buffer: Vec<u8>,
@@ -238,7 +239,7 @@ fn save_function_record(
let coverage_mapping_size = coverage_mapping_buffer.len();
let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);
- let func_name_hash = coverageinfo::hash_str(&mangled_function_name);
+ let func_name_hash = coverageinfo::hash_bytes(mangled_function_name.as_bytes());
let func_name_hash_val = cx.const_u64(func_name_hash);
let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32);
let source_hash_val = cx.const_u64(source_hash);
@@ -254,7 +255,13 @@ fn save_function_record(
/*packed=*/ true,
);
- coverageinfo::save_func_record_to_mod(cx, func_name_hash, func_record_val, is_used);
+ coverageinfo::save_func_record_to_mod(
+ cx,
+ covfun_section_name,
+ func_name_hash,
+ func_record_val,
+ is_used,
+ );
}
/// When finalizing the coverage map, `FunctionCoverage` only has the `CodeRegion`s and counters for
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 42fdbd786..621fd36b2 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -3,10 +3,10 @@ use crate::llvm;
use crate::abi::Abi;
use crate::builder::Builder;
use crate::common::CodegenCx;
-use crate::coverageinfo::map_data::{CounterExpression, FunctionCoverage};
+use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
+use crate::coverageinfo::map_data::FunctionCoverage;
use libc::c_uint;
-use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::traits::{
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods,
StaticMethods,
@@ -16,24 +16,21 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_llvm::RustString;
use rustc_middle::bug;
-use rustc_middle::mir::coverage::{
- CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op,
-};
+use rustc_middle::mir::coverage::{CodeRegion, CounterId, CoverageKind, ExpressionId, Op, Operand};
use rustc_middle::mir::Coverage;
use rustc_middle::ty;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
-use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::Instance;
use rustc_middle::ty::Ty;
use std::cell::RefCell;
-use std::ffi::CString;
-mod ffi;
+pub(crate) mod ffi;
pub(crate) mod map_data;
pub mod mapgen;
-const UNUSED_FUNCTION_COUNTER_ID: CounterValueReference = CounterValueReference::START;
+const UNUSED_FUNCTION_COUNTER_ID: CounterId = CounterId::START;
const VAR_ALIGN_BYTES: usize = 8;
@@ -125,7 +122,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_source_hash);
let num_counters = bx.const_u32(coverageinfo.num_counters);
- let index = bx.const_u32(id.zero_based_index());
+ let index = bx.const_u32(id.as_u32());
debug!(
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
fn_name, hash, num_counters, index,
@@ -178,7 +175,7 @@ impl<'tcx> Builder<'_, '_, 'tcx> {
fn add_coverage_counter(
&mut self,
instance: Instance<'tcx>,
- id: CounterValueReference,
+ id: CounterId,
region: CodeRegion,
) -> bool {
if let Some(coverage_context) = self.coverage_context() {
@@ -202,10 +199,10 @@ impl<'tcx> Builder<'_, '_, 'tcx> {
fn add_coverage_counter_expression(
&mut self,
instance: Instance<'tcx>,
- id: InjectedExpressionId,
- lhs: ExpressionOperandId,
+ id: ExpressionId,
+ lhs: Operand,
op: Op,
- rhs: ExpressionOperandId,
+ rhs: Operand,
region: Option<CodeRegion>,
) -> bool {
if let Some(coverage_context) = self.coverage_context() {
@@ -250,7 +247,7 @@ fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<
let instance = Instance::new(
def_id,
- InternalSubsts::for_item(tcx, def_id, |param, _| {
+ GenericArgs::for_item(tcx, def_id, |param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {
tcx.lifetimes.re_erased.into()
} else {
@@ -334,21 +331,32 @@ fn create_pgo_func_name_var<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
instance: Instance<'tcx>,
) -> &'ll llvm::Value {
- let mangled_fn_name = CString::new(cx.tcx.symbol_name(instance).name)
- .expect("error converting function name to C string");
+ let mangled_fn_name: &str = cx.tcx.symbol_name(instance).name;
let llfn = cx.get_fn(instance);
- unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar(llfn, mangled_fn_name.as_ptr()) }
+ unsafe {
+ llvm::LLVMRustCoverageCreatePGOFuncNameVar(
+ llfn,
+ mangled_fn_name.as_ptr().cast(),
+ mangled_fn_name.len(),
+ )
+ }
}
pub(crate) fn write_filenames_section_to_buffer<'a>(
- filenames: impl IntoIterator<Item = &'a CString>,
+ filenames: impl IntoIterator<Item = &'a str>,
buffer: &RustString,
) {
- let c_str_vec = filenames.into_iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
+ let (pointers, lengths) = filenames
+ .into_iter()
+ .map(|s: &str| (s.as_ptr().cast(), s.len()))
+ .unzip::<_, _, Vec<_>, Vec<_>>();
+
unsafe {
llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
- c_str_vec.as_ptr(),
- c_str_vec.len(),
+ pointers.as_ptr(),
+ pointers.len(),
+ lengths.as_ptr(),
+ lengths.len(),
buffer,
);
}
@@ -373,12 +381,7 @@ pub(crate) fn write_mapping_to_buffer(
}
}
-pub(crate) fn hash_str(strval: &str) -> u64 {
- let strval = CString::new(strval).expect("null error converting hashable str to C string");
- unsafe { llvm::LLVMRustCoverageHashCString(strval.as_ptr()) }
-}
-
-pub(crate) fn hash_bytes(bytes: Vec<u8>) -> u64 {
+pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 {
unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) }
}
@@ -413,6 +416,7 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
+ covfun_section_name: &str,
func_name_hash: u64,
func_record_val: &'ll llvm::Value,
is_used: bool,
@@ -428,20 +432,33 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
let func_record_var_name =
format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" });
debug!("function record var name: {:?}", func_record_var_name);
-
- let func_record_section_name = llvm::build_string(|s| unsafe {
- llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s);
- })
- .expect("Rust Coverage function record section name failed UTF-8 conversion");
- debug!("function record section name: {:?}", func_record_section_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, &func_record_section_name);
+ llvm::set_section(llglobal, covfun_section_name);
llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
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
+/// per-function coverage information in the object file, according to the target
+/// platform's object file format.
+///
+/// LLVM's coverage tools read coverage mapping details from this section when
+/// producing coverage reports.
+///
+/// Typical values are:
+/// - `__llvm_covfun` on Linux
+/// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
+/// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
+pub(crate) fn covfun_section_name(cx: &CodegenCx<'_, '_>) -> String {
+ llvm::build_string(|s| unsafe {
+ llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s);
+ })
+ .expect("Rust Coverage function record section name failed UTF-8 conversion")
+}