Skip to content

Commit fef9c63

Browse files
committed
Rust coverage before splitting instrument_coverage.rs
1 parent b202532 commit fef9c63

File tree

214 files changed

+9821
-1243
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

214 files changed

+9821
-1243
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl CoverageMapGenerator {
129129
let (filenames_index, _) = self.filenames.insert_full(c_filename);
130130
virtual_file_mapping.push(filenames_index as u32);
131131
}
132-
debug!("Adding counter {:?} to map for {:?}", counter, region,);
132+
debug!("Adding counter {:?} to map for {:?}", counter, region);
133133
mapping_regions.push(CounterMappingRegion::code_region(
134134
counter,
135135
current_file_id,

compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_codegen_ssa::traits::{
1212
use rustc_data_structures::fx::FxHashMap;
1313
use rustc_llvm::RustString;
1414
use rustc_middle::mir::coverage::{
15-
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionIndex, Op,
15+
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
1616
};
1717
use rustc_middle::ty::Instance;
1818

@@ -27,16 +27,16 @@ const COVMAP_VAR_ALIGN_BYTES: usize = 8;
2727

2828
/// A context object for maintaining all state needed by the coverageinfo module.
2929
pub struct CrateCoverageContext<'tcx> {
30-
// Coverage region data for each instrumented function identified by DefId.
31-
pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage>>,
30+
// Coverage data for each instrumented function identified by DefId.
31+
pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>>>,
3232
}
3333

3434
impl<'tcx> CrateCoverageContext<'tcx> {
3535
pub fn new() -> Self {
3636
Self { function_coverage_map: Default::default() }
3737
}
3838

39-
pub fn take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage> {
39+
pub fn take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>> {
4040
self.function_coverage_map.replace(FxHashMap::default())
4141
}
4242
}
@@ -58,7 +58,23 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
5858
unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar(llfn, mangled_fn_name.as_ptr()) }
5959
}
6060

61-
fn add_counter_region(
61+
fn set_function_source_hash(&mut self, instance: Instance<'tcx>, function_source_hash: u64) -> bool {
62+
if let Some(coverage_context) = self.coverage_context() {
63+
debug!(
64+
"ensuring function source hash is set for instance={:?}; function_source_hash={}",
65+
instance, function_source_hash,
66+
);
67+
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
68+
coverage_map
69+
.entry(instance)
70+
.or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
71+
.set_function_source_hash(function_source_hash);
72+
} else {
73+
false
74+
}
75+
}
76+
77+
fn add_coverage_counter(
6278
&mut self,
6379
instance: Instance<'tcx>,
6480
function_source_hash: u64,
@@ -67,59 +83,53 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
6783
) -> bool {
6884
if let Some(coverage_context) = self.coverage_context() {
6985
debug!(
70-
"adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={:?}, \
86+
"adding counter to coverage_map: instance={:?}, function_source_hash={}, id={:?}, \
7187
at {:?}",
7288
instance, function_source_hash, id, region,
7389
);
74-
let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut();
75-
coverage_regions
90+
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
91+
coverage_map
7692
.entry(instance)
7793
.or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
7894
.add_counter(function_source_hash, id, region);
79-
true
8095
} else {
8196
false
8297
}
8398
}
8499

85-
fn add_counter_expression_region(
100+
fn add_coverage_counter_expression(
86101
&mut self,
87102
instance: Instance<'tcx>,
88-
id: InjectedExpressionIndex,
103+
id: InjectedExpressionId,
89104
lhs: ExpressionOperandId,
90105
op: Op,
91106
rhs: ExpressionOperandId,
92-
region: CodeRegion,
93-
) -> bool {
94-
if let Some(coverage_context) = self.coverage_context() {
107+
region: Option<CodeRegion>,
108+
) {
109+
if let Some(coverage_context) = self.coverage_context() -> bool {
95110
debug!(
96-
"adding counter expression to coverage_regions: instance={:?}, id={:?}, {:?} {:?} {:?}, \
97-
at {:?}",
111+
"adding counter expression to coverage_map: instance={:?}, id={:?}, {:?} {:?} {:?}; \
112+
region: {:?}",
98113
instance, id, lhs, op, rhs, region,
99114
);
100-
let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut();
101-
coverage_regions
115+
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
116+
coverage_map
102117
.entry(instance)
103118
.or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
104119
.add_counter_expression(id, lhs, op, rhs, region);
105-
true
106120
} else {
107121
false
108122
}
109123
}
110124

111-
fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool {
125+
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool {
112126
if let Some(coverage_context) = self.coverage_context() {
113-
debug!(
114-
"adding unreachable code to coverage_regions: instance={:?}, at {:?}",
115-
instance, region,
116-
);
117-
let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut();
118-
coverage_regions
127+
debug!("adding unreachable code to coverage_map: instance={:?}, at {:?}", instance, region,);
128+
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
129+
coverage_map
119130
.entry(instance)
120131
.or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
121132
.add_unreachable_region(region);
122-
true
123133
} else {
124134
false
125135
}

compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
33
/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L91)
44
#[derive(Copy, Clone, Debug)]
55
#[repr(C)]
6-
enum CounterKind {
6+
pub enum CounterKind {
77
Zero = 0,
88
CounterValueReference = 1,
99
Expression = 2,
@@ -23,8 +23,8 @@ enum CounterKind {
2323
#[repr(C)]
2424
pub struct Counter {
2525
// Important: The layout (order and types of fields) must match its C++ counterpart.
26-
kind: CounterKind,
27-
id: u32,
26+
pub kind: CounterKind,
27+
pub id: u32,
2828
}
2929

3030
impl Counter {
@@ -55,9 +55,9 @@ pub enum ExprKind {
5555
#[derive(Copy, Clone, Debug)]
5656
#[repr(C)]
5757
pub struct CounterExpression {
58-
kind: ExprKind,
59-
lhs: Counter,
60-
rhs: Counter,
58+
pub kind: ExprKind,
59+
pub lhs: Counter,
60+
pub rhs: Counter,
6161
}
6262

6363
impl CounterExpression {

compiler/rustc_codegen_ssa/src/coverageinfo/map.rs

Lines changed: 76 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ pub use super::ffi::*;
22

33
use rustc_index::vec::IndexVec;
44
use rustc_middle::mir::coverage::{
5-
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionIndex,
6-
MappedExpressionIndex, Op,
5+
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId,
6+
InjectedExpressionIndex, MappedExpressionIndex, Op,
77
};
88
use rustc_middle::ty::Instance;
99
use rustc_middle::ty::TyCtxt;
1010

1111
#[derive(Clone, Debug)]
12-
pub struct ExpressionRegion {
12+
pub struct Expression {
1313
lhs: ExpressionOperandId,
1414
op: Op,
1515
rhs: ExpressionOperandId,
16-
region: CodeRegion,
16+
region: Option<CodeRegion>,
1717
}
1818

1919
/// Collects all of the coverage regions associated with (a) injected counters, (b) counter
@@ -28,24 +28,43 @@ pub struct ExpressionRegion {
2828
/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
2929
/// for a gap area is only used as the line execution count if there are no other regions on a
3030
/// line."
31-
pub struct FunctionCoverage {
31+
pub struct FunctionCoverage<'tcx> {
32+
instance: Instance<'tcx>,
3233
source_hash: u64,
3334
counters: IndexVec<CounterValueReference, Option<CodeRegion>>,
34-
expressions: IndexVec<InjectedExpressionIndex, Option<ExpressionRegion>>,
35+
expressions: IndexVec<InjectedExpressionIndex, Option<Expression>>,
3536
unreachable_regions: Vec<CodeRegion>,
3637
}
3738

38-
impl FunctionCoverage {
39-
pub fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
39+
impl<'tcx> FunctionCoverage<'tcx> {
40+
pub fn new(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
4041
let coverageinfo = tcx.coverageinfo(instance.def_id());
42+
debug!(
43+
"FunctionCoverage::new(instance={:?}) has coverageinfo={:?}",
44+
instance, coverageinfo
45+
);
4146
Self {
47+
instance,
4248
source_hash: 0, // will be set with the first `add_counter()`
4349
counters: IndexVec::from_elem_n(None, coverageinfo.num_counters as usize),
4450
expressions: IndexVec::from_elem_n(None, coverageinfo.num_expressions as usize),
4551
unreachable_regions: Vec::new(),
4652
}
4753
}
4854

55+
/// Although every function should have at least one `Counter`, the `Counter` isn't required to
56+
/// have a `CodeRegion`. (The `CodeRegion` may be associated only with `Expressions`.) This
57+
/// method supports the ability to ensure the `function_source_hash` is set from `Counters` that
58+
/// do not trigger the call to `add_counter()` because they don't have an associated
59+
/// `CodeRegion` to add.
60+
pub fn set_function_source_hash(&mut self, source_hash: u64) {
61+
if self.source_hash == 0 {
62+
self.source_hash = source_hash;
63+
} else {
64+
debug_assert_eq!(source_hash, self.source_hash);
65+
}
66+
}
67+
4968
/// Adds a code region to be counted by an injected counter intrinsic.
5069
/// The source_hash (computed during coverage instrumentation) should also be provided, and
5170
/// should be the same for all counters in a given function.
@@ -74,15 +93,19 @@ impl FunctionCoverage {
7493
/// counters and expressions have been added.
7594
pub fn add_counter_expression(
7695
&mut self,
77-
expression_id: InjectedExpressionIndex,
96+
expression_id: InjectedExpressionId,
7897
lhs: ExpressionOperandId,
7998
op: Op,
8099
rhs: ExpressionOperandId,
81-
region: CodeRegion,
100+
region: Option<CodeRegion>,
82101
) {
102+
debug!(
103+
"add_counter_expression({:?}, lhs={:?}, op={:?}, rhs={:?} at {:?}",
104+
expression_id, lhs, op, rhs, region
105+
);
83106
let expression_index = self.expression_index(u32::from(expression_id));
84107
self.expressions[expression_index]
85-
.replace(ExpressionRegion { lhs, op, rhs, region })
108+
.replace(Expression { lhs, op, rhs, region })
86109
.expect_none("add_counter_expression called with duplicate `id_descending_from_max`");
87110
}
88111

@@ -103,7 +126,11 @@ impl FunctionCoverage {
103126
pub fn get_expressions_and_counter_regions<'a>(
104127
&'a self,
105128
) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a CodeRegion)>) {
106-
assert!(self.source_hash != 0);
129+
assert!(
130+
self.source_hash != 0,
131+
"No counters provided the source_hash for function: {:?}",
132+
self.instance
133+
);
107134

108135
let counter_regions = self.counter_regions();
109136
let (counter_expressions, expression_regions) = self.expressions_with_regions();
@@ -129,54 +156,60 @@ impl FunctionCoverage {
129156
) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a CodeRegion)>) {
130157
let mut counter_expressions = Vec::with_capacity(self.expressions.len());
131158
let mut expression_regions = Vec::with_capacity(self.expressions.len());
132-
let mut new_indexes =
133-
IndexVec::from_elem_n(MappedExpressionIndex::from(u32::MAX), self.expressions.len());
134-
// Note, the initial value shouldn't matter since every index in use in `self.expressions`
135-
// will be set, and after that, `new_indexes` will only be accessed using those same
136-
// indexes.
137-
138-
// Note that an `ExpressionRegion`s at any given index can include other expressions as
159+
let mut new_indexes = IndexVec::from_elem_n(None, self.expressions.len());
160+
// Note that an `Expression`s at any given index can include other expressions as
139161
// operands, but expression operands can only come from the subset of expressions having
140-
// `expression_index`s lower than the referencing `ExpressionRegion`. Therefore, it is
162+
// `expression_index`s lower than the referencing `Expression`. Therefore, it is
141163
// reasonable to look up the new index of an expression operand while the `new_indexes`
142164
// vector is only complete up to the current `ExpressionIndex`.
143165
let id_to_counter =
144-
|new_indexes: &IndexVec<InjectedExpressionIndex, MappedExpressionIndex>,
166+
|new_indexes: &IndexVec<InjectedExpressionIndex, Option<MappedExpressionIndex>>,
145167
id: ExpressionOperandId| {
146168
if id == ExpressionOperandId::ZERO {
147169
Some(Counter::zero())
148170
} else if id.index() < self.counters.len() {
171+
// Note: Some codegen-injected Counters may be only referenced by `Expression`s,
172+
// and may not have their own `CodeRegion`s,
149173
let index = CounterValueReference::from(id.index());
150-
self.counters
151-
.get(index)
152-
.unwrap() // pre-validated
153-
.as_ref()
154-
.map(|_| Counter::counter_value_reference(index))
174+
Some(Counter::counter_value_reference(index))
155175
} else {
156176
let index = self.expression_index(u32::from(id));
157177
self.expressions
158178
.get(index)
159179
.expect("expression id is out of range")
160180
.as_ref()
161-
.map(|_| Counter::expression(new_indexes[index]))
181+
// If an expression was optimized out, assume it would have produced a count
182+
// of zero. This ensures that expressions dependent on optimized-out
183+
// expressions are still valid.
184+
.map_or(Some(Counter::zero()), |_| {
185+
new_indexes[index].map(|new_index| Counter::expression(new_index))
186+
})
162187
}
163188
};
164189

165-
for (original_index, expression_region) in
190+
for (original_index, expression) in
166191
self.expressions.iter_enumerated().filter_map(|(original_index, entry)| {
167192
// Option::map() will return None to filter out missing expressions. This may happen
168193
// if, for example, a MIR-instrumented expression is removed during an optimization.
169-
entry.as_ref().map(|region| (original_index, region))
194+
entry.as_ref().map(|expression| (original_index, expression))
170195
})
171196
{
172-
let region = &expression_region.region;
173-
let ExpressionRegion { lhs, op, rhs, .. } = *expression_region;
197+
let optional_region = &expression.region;
198+
let Expression { lhs, op, rhs, .. } = *expression;
174199

175200
if let Some(Some((lhs_counter, rhs_counter))) =
176201
id_to_counter(&new_indexes, lhs).map(|lhs_counter| {
177202
id_to_counter(&new_indexes, rhs).map(|rhs_counter| (lhs_counter, rhs_counter))
178203
})
179204
{
205+
debug_assert!(
206+
(lhs_counter.id as usize)
207+
< usize::max(self.counters.len(), self.expressions.len())
208+
);
209+
debug_assert!(
210+
(rhs_counter.id as usize)
211+
< usize::max(self.counters.len(), self.expressions.len())
212+
);
180213
// Both operands exist. `Expression` operands exist in `self.expressions` and have
181214
// been assigned a `new_index`.
182215
let mapped_expression_index =
@@ -190,12 +223,20 @@ impl FunctionCoverage {
190223
rhs_counter,
191224
);
192225
debug!(
193-
"Adding expression {:?} = {:?} at {:?}",
194-
mapped_expression_index, expression, region
226+
"Adding expression {:?} = {:?}, region: {:?}",
227+
mapped_expression_index, expression, optional_region
195228
);
196229
counter_expressions.push(expression);
197-
new_indexes[original_index] = mapped_expression_index;
198-
expression_regions.push((Counter::expression(mapped_expression_index), region));
230+
new_indexes[original_index] = Some(mapped_expression_index);
231+
if let Some(region) = optional_region {
232+
expression_regions.push((Counter::expression(mapped_expression_index), region));
233+
}
234+
} else {
235+
debug!(
236+
"Ignoring expression with one or more missing operands: \
237+
original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}",
238+
original_index, lhs, op, rhs, optional_region,
239+
)
199240
}
200241
}
201242
(counter_expressions, expression_regions.into_iter())

0 commit comments

Comments
 (0)