Skip to content

Commit b58afc0

Browse files
committed
FunctionCoverage: improve type checking with newtype_index types
1 parent 20f55c1 commit b58afc0

File tree

2 files changed

+88
-40
lines changed

2 files changed

+88
-40
lines changed

src/librustc_codegen_ssa/coverageinfo/map.rs

+86-40
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_index::vec::IndexVec;
12
use rustc_middle::ty::Instance;
23
use rustc_middle::ty::TyCtxt;
34
use rustc_span::source_map::{Pos, SourceMap};
@@ -7,6 +8,34 @@ use std::cmp::{Ord, Ordering};
78
use std::fmt;
89
use std::path::PathBuf;
910

11+
rustc_index::newtype_index! {
12+
pub struct ExpressionOperandId {
13+
DEBUG_FORMAT = "ExpressionOperandId({})",
14+
MAX = 0xFFFF_FFFF,
15+
}
16+
}
17+
18+
rustc_index::newtype_index! {
19+
pub struct CounterValueReference {
20+
DEBUG_FORMAT = "CounterValueReference({})",
21+
MAX = 0xFFFF_FFFF,
22+
}
23+
}
24+
25+
rustc_index::newtype_index! {
26+
pub struct InjectedExpressionIndex {
27+
DEBUG_FORMAT = "InjectedExpressionIndex({})",
28+
MAX = 0xFFFF_FFFF,
29+
}
30+
}
31+
32+
rustc_index::newtype_index! {
33+
pub struct MappedExpressionIndex {
34+
DEBUG_FORMAT = "MappedExpressionIndex({})",
35+
MAX = 0xFFFF_FFFF,
36+
}
37+
}
38+
1039
/// 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)
1140
#[derive(Copy, Clone, Debug)]
1241
#[repr(C)]
@@ -38,12 +67,12 @@ impl Counter {
3867
Self { kind: CounterKind::Zero, id: 0 }
3968
}
4069

41-
pub fn counter_value_reference(counter_id: u32) -> Self {
42-
Self { kind: CounterKind::CounterValueReference, id: counter_id }
70+
pub fn counter_value_reference(counter_id: CounterValueReference) -> Self {
71+
Self { kind: CounterKind::CounterValueReference, id: counter_id.into() }
4372
}
4473

45-
pub fn expression(final_expression_index: u32) -> Self {
46-
Self { kind: CounterKind::Expression, id: final_expression_index }
74+
pub fn expression(mapped_expression_index: MappedExpressionIndex) -> Self {
75+
Self { kind: CounterKind::Expression, id: mapped_expression_index.into() }
4776
}
4877
}
4978

@@ -143,9 +172,9 @@ impl Region {
143172

144173
#[derive(Clone, Debug)]
145174
pub struct ExpressionRegion {
146-
lhs: u32,
175+
lhs: ExpressionOperandId,
147176
op: ExprKind,
148-
rhs: u32,
177+
rhs: ExpressionOperandId,
149178
region: Region,
150179
}
151180

@@ -203,8 +232,8 @@ pub struct ExpressionRegion {
203232
pub struct FunctionCoverage<'a> {
204233
source_map: &'a SourceMap,
205234
source_hash: u64,
206-
counters: Vec<Option<Region>>,
207-
expressions: Vec<Option<ExpressionRegion>>,
235+
counters: IndexVec<CounterValueReference, Option<Region>>,
236+
expressions: IndexVec<InjectedExpressionIndex, Option<ExpressionRegion>>,
208237
unreachable_regions: Vec<Region>,
209238
}
210239

@@ -214,8 +243,8 @@ impl<'a> FunctionCoverage<'a> {
214243
Self {
215244
source_map: tcx.sess.source_map(),
216245
source_hash: 0, // will be set with the first `add_counter()`
217-
counters: vec![None; coverageinfo.num_counters as usize],
218-
expressions: vec![None; coverageinfo.num_expressions as usize],
246+
counters: IndexVec::from_elem_n(None, coverageinfo.num_counters as usize),
247+
expressions: IndexVec::from_elem_n(None, coverageinfo.num_expressions as usize),
219248
unreachable_regions: Vec::new(),
220249
}
221250
}
@@ -235,7 +264,7 @@ impl<'a> FunctionCoverage<'a> {
235264
} else {
236265
debug_assert_eq!(source_hash, self.source_hash);
237266
}
238-
self.counters[id as usize]
267+
self.counters[CounterValueReference::from(id)]
239268
.replace(Region::new(self.source_map, start_byte_pos, end_byte_pos))
240269
.expect_none("add_counter called with duplicate `id`");
241270
}
@@ -263,7 +292,11 @@ impl<'a> FunctionCoverage<'a> {
263292
start_byte_pos: u32,
264293
end_byte_pos: u32,
265294
) {
266-
let expression_index = self.expression_index(id_descending_from_max);
295+
let expression_id = ExpressionOperandId::from(id_descending_from_max);
296+
let lhs = ExpressionOperandId::from(lhs);
297+
let rhs = ExpressionOperandId::from(rhs);
298+
299+
let expression_index = self.expression_index(expression_id);
267300
self.expressions[expression_index]
268301
.replace(ExpressionRegion {
269302
lhs,
@@ -294,19 +327,21 @@ impl<'a> FunctionCoverage<'a> {
294327
assert!(self.source_hash != 0);
295328

296329
let counter_regions = self.counter_regions();
297-
let (expressions, expression_regions) = self.expressions_with_regions();
330+
let (counter_expressions, expression_regions) = self.expressions_with_regions();
298331
let unreachable_regions = self.unreachable_regions();
299332

300333
let counter_regions =
301334
counter_regions.chain(expression_regions.into_iter().chain(unreachable_regions));
302-
(expressions, counter_regions)
335+
(counter_expressions, counter_regions)
303336
}
304337

305338
fn counter_regions(&'a self) -> impl Iterator<Item = (Counter, &'a Region)> {
306-
self.counters.iter().enumerate().filter_map(|(index, entry)| {
339+
self.counters.iter_enumerated().filter_map(|(index, entry)| {
307340
// Option::map() will return None to filter out missing counters. This may happen
308341
// if, for example, a MIR-instrumented counter is removed during an optimization.
309-
entry.as_ref().map(|region| (Counter::counter_value_reference(index as u32), region))
342+
entry.as_ref().map(|region| {
343+
(Counter::counter_value_reference(index as CounterValueReference), region)
344+
})
310345
})
311346
}
312347

@@ -315,32 +350,39 @@ impl<'a> FunctionCoverage<'a> {
315350
) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a Region)>) {
316351
let mut counter_expressions = Vec::with_capacity(self.expressions.len());
317352
let mut expression_regions = Vec::with_capacity(self.expressions.len());
318-
let mut new_indexes = vec![u32::MAX; self.expressions.len()];
353+
let mut new_indexes =
354+
IndexVec::from_elem_n(MappedExpressionIndex::from(u32::MAX), self.expressions.len());
355+
// Note, the initial value shouldn't matter since every index in use in `self.expressions`
356+
// will be set, and after that, `new_indexes` will only be accessed using those same
357+
// indexes.
319358

320359
// Note that an `ExpressionRegion`s at any given index can include other expressions as
321360
// operands, but expression operands can only come from the subset of expressions having
322361
// `expression_index`s lower than the referencing `ExpressionRegion`. Therefore, it is
323362
// reasonable to look up the new index of an expression operand while the `new_indexes`
324363
// vector is only complete up to the current `ExpressionIndex`.
325-
let id_to_counter = |new_indexes: &Vec<u32>, id| {
326-
if id < self.counters.len() as u32 {
327-
self.counters
328-
.get(id as usize)
329-
.expect("id is out of range")
330-
.as_ref()
331-
.map(|_| Counter::counter_value_reference(id))
332-
} else {
333-
let index = self.expression_index(id);
334-
self.expressions
335-
.get(index)
336-
.expect("id is out of range")
337-
.as_ref()
338-
.map(|_| Counter::expression(new_indexes[index]))
339-
}
340-
};
364+
let id_to_counter =
365+
|new_indexes: &IndexVec<InjectedExpressionIndex, MappedExpressionIndex>,
366+
id: ExpressionOperandId| {
367+
if id.index() < self.counters.len() {
368+
let index = CounterValueReference::from(id.index());
369+
self.counters
370+
.get(index)
371+
.unwrap() // pre-validated
372+
.as_ref()
373+
.map(|_| Counter::counter_value_reference(index))
374+
} else {
375+
let index = self.expression_index(id);
376+
self.expressions
377+
.get(index)
378+
.expect("expression id is out of range")
379+
.as_ref()
380+
.map(|_| Counter::expression(new_indexes[index]))
381+
}
382+
};
341383

342384
for (original_index, expression_region) in
343-
self.expressions.iter().enumerate().filter_map(|(original_index, entry)| {
385+
self.expressions.iter_enumerated().filter_map(|(original_index, entry)| {
344386
// Option::map() will return None to filter out missing expressions. This may happen
345387
// if, for example, a MIR-instrumented expression is removed during an optimization.
346388
entry.as_ref().map(|region| (original_index, region))
@@ -356,10 +398,11 @@ impl<'a> FunctionCoverage<'a> {
356398
{
357399
// Both operands exist. `Expression` operands exist in `self.expressions` and have
358400
// been assigned a `new_index`.
359-
let final_expression_index = counter_expressions.len() as u32;
401+
let mapped_expression_index =
402+
MappedExpressionIndex::from(counter_expressions.len());
360403
counter_expressions.push(CounterExpression::new(lhs_counter, op, rhs_counter));
361-
new_indexes[original_index] = final_expression_index;
362-
expression_regions.push((Counter::expression(final_expression_index), region));
404+
new_indexes[original_index] = mapped_expression_index;
405+
expression_regions.push((Counter::expression(mapped_expression_index), region));
363406
}
364407
}
365408
(counter_expressions, expression_regions.into_iter())
@@ -369,8 +412,11 @@ impl<'a> FunctionCoverage<'a> {
369412
self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
370413
}
371414

372-
fn expression_index(&self, id_descending_from_max: u32) -> usize {
373-
debug_assert!(id_descending_from_max as usize >= self.counters.len());
374-
(u32::MAX - id_descending_from_max) as usize
415+
fn expression_index(
416+
&self,
417+
id_descending_from_max: ExpressionOperandId,
418+
) -> InjectedExpressionIndex {
419+
debug_assert!(id_descending_from_max.index() >= self.counters.len());
420+
InjectedExpressionIndex::from(u32::MAX - u32::from(id_descending_from_max))
375421
}
376422
}

src/librustc_codegen_ssa/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#![feature(or_patterns)]
99
#![feature(trusted_len)]
1010
#![feature(associated_type_bounds)]
11+
#![feature(const_fn)] // for rustc_index::newtype_index
12+
#![feature(const_panic)] // for rustc_index::newtype_index
1113
#![recursion_limit = "256"]
1214

1315
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).

0 commit comments

Comments
 (0)