Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c564f81
rustdoc: align stability badge to baseline instead of bottom
notriddle Dec 13, 2022
193fec6
Preparing for merge from rustc
Oct 22, 2023
1f09dd2
Merge from rustc
Oct 22, 2023
8cbac82
clippy
RalfJung Oct 22, 2023
f6be93f
Auto merge of #3133 - rust-lang:rustup-2023-10-22, r=RalfJung
bors Oct 22, 2023
b53c34f
avoid AtomicU64 when a Cell is enough
RalfJung Oct 22, 2023
f35c36a
Auto merge of #3135 - RalfJung:nonatomic-clock, r=RalfJung
bors Oct 22, 2023
371883a
coverage: Split `FunctionCoverage` into distinct collector/finished p…
Zalathar Oct 6, 2023
86b55cc
coverage: Fetch expressions and mappings separately
Zalathar Oct 6, 2023
e985ae5
coverage: Build the global file table ahead of time
Zalathar Oct 3, 2023
88159ca
coverage: Encapsulate local-to-global file mappings
Zalathar Sep 28, 2023
de4cfbc
coverage: Encode function mappings without re-sorting them
Zalathar Sep 28, 2023
6af9fef
coverage: Emit the filenames section before encoding per-function map…
Zalathar Oct 6, 2023
dc00d03
add target csky-unknown-linux-gnuabiv2hf
Dirreke Oct 22, 2023
5454797
tidy docs
Dirreke Oct 22, 2023
bb67e0f
fix broken link: update incremental compilation url
gvozdvmozgu Oct 22, 2023
1f9f041
x.ps1: remove the check for Python from Windows Store
xobs Oct 23, 2023
e86f9b6
Rollup merge of #105666 - notriddle:notriddle/stab-baseline, r=Guilla…
matthiaskrgr Oct 23, 2023
dde77f7
Rollup merge of #117042 - Zalathar:file-table, r=cjgillot
matthiaskrgr Oct 23, 2023
fe4fde2
Rollup merge of #117044 - RalfJung:miri, r=RalfJung
matthiaskrgr Oct 23, 2023
9acb775
Rollup merge of #117049 - Dirreke:csky-unknown-linux-gunabiv2, r=bjorn3
matthiaskrgr Oct 23, 2023
2636745
Rollup merge of #117051 - gvozdvmozgu:fix-incremental-compilation-lin…
matthiaskrgr Oct 23, 2023
cec7d4a
Rollup merge of #117069 - xobs:x.ps1-remove-windows-store-check, r=al…
matthiaskrgr Oct 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
coverage: Split FunctionCoverage into distinct collector/finished p…
…hases

This gives us a clearly-defined place to run code after the instance's MIR has
been traversed by codegen, but before we emit its `__llvm_covfun` record.
  • Loading branch information
Zalathar committed Oct 22, 2023
commit 371883a05acf04be9fb8d3c0766990ba56cd22e3
48 changes: 30 additions & 18 deletions compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_middle::ty::Instance;
/// Holds all of the coverage mapping data associated with a function instance,
/// collected during traversal of `Coverage` statements in the function's MIR.
#[derive(Debug)]
pub struct FunctionCoverage<'tcx> {
pub struct FunctionCoverageCollector<'tcx> {
/// Coverage info that was attached to this function by the instrumentor.
function_coverage_info: &'tcx FunctionCoverageInfo,
is_used: bool,
Expand All @@ -26,7 +26,7 @@ pub struct FunctionCoverage<'tcx> {
expressions_seen: BitSet<ExpressionId>,
}

impl<'tcx> FunctionCoverage<'tcx> {
impl<'tcx> FunctionCoverageCollector<'tcx> {
/// Creates a new set of coverage data for a used (called) function.
pub fn new(
instance: Instance<'tcx>,
Expand Down Expand Up @@ -76,11 +76,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
}
}

/// Returns true for a used (called) function, and false for an unused function.
pub fn is_used(&self) -> bool {
self.is_used
}

/// Marks a counter ID as having been seen in a counter-increment statement.
#[instrument(level = "debug", skip(self))]
pub(crate) fn mark_counter_id_seen(&mut self, id: CounterId) {
Expand Down Expand Up @@ -165,6 +160,28 @@ impl<'tcx> FunctionCoverage<'tcx> {
ZeroExpressions(zero_expressions)
}

pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> {
let zero_expressions = self.identify_zero_expressions();
let FunctionCoverageCollector { function_coverage_info, is_used, counters_seen, .. } = self;

FunctionCoverage { function_coverage_info, is_used, counters_seen, zero_expressions }
}
}

pub(crate) struct FunctionCoverage<'tcx> {
function_coverage_info: &'tcx FunctionCoverageInfo,
is_used: bool,

counters_seen: BitSet<CounterId>,
zero_expressions: ZeroExpressions,
}

impl<'tcx> FunctionCoverage<'tcx> {
/// Returns true for a used (called) function, and false for an unused function.
pub(crate) fn is_used(&self) -> bool {
self.is_used
}

/// Return the source hash, generated from the HIR node structure, and used to indicate whether
/// or not the source code structure changed between different compilations.
pub fn source_hash(&self) -> u64 {
Expand All @@ -177,29 +194,27 @@ impl<'tcx> FunctionCoverage<'tcx> {
pub fn get_expressions_and_counter_regions(
&self,
) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) {
let zero_expressions = self.identify_zero_expressions();

let counter_expressions = self.counter_expressions(&zero_expressions);
let counter_expressions = self.counter_expressions();
// Expression IDs are indices into `self.expressions`, and on the LLVM
// side they will be treated as indices into `counter_expressions`, so
// the two vectors should correspond 1:1.
assert_eq!(self.function_coverage_info.expressions.len(), counter_expressions.len());

let counter_regions = self.counter_regions(zero_expressions);
let counter_regions = self.counter_regions();

(counter_expressions, counter_regions)
}

/// Convert this function's coverage expression data into a form that can be
/// passed through FFI to LLVM.
fn counter_expressions(&self, zero_expressions: &ZeroExpressions) -> Vec<CounterExpression> {
fn counter_expressions(&self) -> Vec<CounterExpression> {
// We know that LLVM will optimize out any unused expressions before
// producing the final coverage map, so there's no need to do the same
// thing on the Rust side unless we're confident we can do much better.
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)

let counter_from_operand = |operand: CovTerm| match operand {
CovTerm::Expression(id) if zero_expressions.contains(id) => Counter::ZERO,
CovTerm::Expression(id) if self.zero_expressions.contains(id) => Counter::ZERO,
_ => Counter::from_term(operand),
};

Expand All @@ -219,18 +234,15 @@ impl<'tcx> FunctionCoverage<'tcx> {

/// Converts this function's coverage mappings into an intermediate form
/// that will be used by `mapgen` when preparing for FFI.
fn counter_regions(
&self,
zero_expressions: ZeroExpressions,
) -> impl Iterator<Item = (Counter, &CodeRegion)> {
fn counter_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
// Historically, mappings were stored directly in counter/expression
// statements in MIR, and MIR optimizations would sometimes remove them.
// That's mostly no longer true, so now we detect cases where that would
// have happened, and zero out the corresponding mappings here instead.
let counter_for_term = move |term: CovTerm| {
let force_to_zero = match term {
CovTerm::Counter(id) => !self.counters_seen.contains(id),
CovTerm::Expression(id) => zero_expressions.contains(id),
CovTerm::Expression(id) => self.zero_expressions.contains(id),
CovTerm::Zero => false,
};
if force_to_zero { Counter::ZERO } else { Counter::from_term(term) }
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common::CodegenCx;
use crate::coverageinfo;
use crate::coverageinfo::ffi::CounterMappingRegion;
use crate::coverageinfo::map_data::FunctionCoverage;
use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
use crate::llvm;

use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods};
Expand Down Expand Up @@ -62,6 +62,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
// Encode coverage mappings and generate function records
let mut function_data = Vec::new();
for (instance, function_coverage) in function_coverage_map {
let function_coverage = function_coverage.into_finished();
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);

let mangled_function_name = tcx.symbol_name(instance).name;
Expand Down Expand Up @@ -419,7 +420,7 @@ fn add_unused_function_coverage<'tcx>(
) {
// An unused function's mappings will automatically be rewritten to map to
// zero, because none of its counters/expressions are marked as seen.
let function_coverage = FunctionCoverage::unused(instance, function_coverage_info);
let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info);

if let Some(coverage_context) = cx.coverage_context() {
coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);
Expand Down
11 changes: 7 additions & 4 deletions compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::llvm;
use crate::builder::Builder;
use crate::common::CodegenCx;
use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
use crate::coverageinfo::map_data::FunctionCoverage;
use crate::coverageinfo::map_data::FunctionCoverageCollector;

use libc::c_uint;
use rustc_codegen_ssa::traits::{
Expand All @@ -29,7 +29,8 @@ const VAR_ALIGN_BYTES: usize = 8;
/// A context object for maintaining all state needed by the coverageinfo module.
pub struct CrateCoverageContext<'ll, 'tcx> {
/// Coverage data for each instrumented function identified by DefId.
pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>>>,
pub(crate) function_coverage_map:
RefCell<FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
}

Expand All @@ -41,7 +42,9 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
}
}

pub fn take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>> {
pub fn take_function_coverage_map(
&self,
) -> FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> {
self.function_coverage_map.replace(FxHashMap::default())
}
}
Expand Down Expand Up @@ -93,7 +96,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
let func_coverage = coverage_map
.entry(instance)
.or_insert_with(|| FunctionCoverage::new(instance, function_coverage_info));
.or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info));

let Coverage { kind } = coverage;
match *kind {
Expand Down