Skip to content

Commit 83a528d

Browse files
authored
Unrolled build for rust-lang#118929
Rollup merge of rust-lang#118929 - Zalathar:look-hir, r=cjgillot coverage: Tidy up early parts of the instrumentor pass This is extracted from rust-lang#118237, which needed to be manually rebased anyway. Unlike that PR, this one only affects the coverage instrumentor, and doesn't attempt to move any code into the MIR builder. That can be left to a future version of rust-lang#118305, which can still benefit from these improvements. So this is now mostly a refactoring of some internal parts of the instrumentor.
2 parents 1559dd2 + 684b9ea commit 83a528d

File tree

1 file changed

+77
-70
lines changed
  • compiler/rustc_mir_transform/src/coverage

1 file changed

+77
-70
lines changed

compiler/rustc_mir_transform/src/coverage/mod.rs

+77-70
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use self::spans::CoverageSpans;
1313

1414
use crate::MirPass;
1515

16-
use rustc_data_structures::sync::Lrc;
1716
use rustc_middle::hir;
1817
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1918
use rustc_middle::mir::coverage::*;
@@ -22,9 +21,9 @@ use rustc_middle::mir::{
2221
TerminatorKind,
2322
};
2423
use rustc_middle::ty::TyCtxt;
25-
use rustc_span::def_id::DefId;
24+
use rustc_span::def_id::LocalDefId;
2625
use rustc_span::source_map::SourceMap;
27-
use rustc_span::{ExpnKind, SourceFile, Span, Symbol};
26+
use rustc_span::{ExpnKind, Span, Symbol};
2827

2928
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
3029
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
@@ -39,31 +38,19 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
3938
fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
4039
let mir_source = mir_body.source;
4140

42-
// If the InstrumentCoverage pass is called on promoted MIRs, skip them.
43-
// See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
44-
if mir_source.promoted.is_some() {
45-
trace!(
46-
"InstrumentCoverage skipped for {:?} (already promoted for Miri evaluation)",
47-
mir_source.def_id()
48-
);
49-
return;
50-
}
41+
// This pass runs after MIR promotion, but before promoted MIR starts to
42+
// be transformed, so it should never see promoted MIR.
43+
assert!(mir_source.promoted.is_none());
44+
45+
let def_id = mir_source.def_id().expect_local();
5146

52-
let is_fn_like =
53-
tcx.hir_node_by_def_id(mir_source.def_id().expect_local()).fn_kind().is_some();
54-
55-
// Only instrument functions, methods, and closures (not constants since they are evaluated
56-
// at compile time by Miri).
57-
// FIXME(#73156): Handle source code coverage in const eval, but note, if and when const
58-
// expressions get coverage spans, we will probably have to "carve out" space for const
59-
// expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
60-
// be tricky if const expressions have no corresponding statements in the enclosing MIR.
61-
// Closures are carved out by their initial `Assign` statement.)
62-
if !is_fn_like {
63-
trace!("InstrumentCoverage skipped for {:?} (not an fn-like)", mir_source.def_id());
47+
if !is_eligible_for_coverage(tcx, def_id) {
48+
trace!("InstrumentCoverage skipped for {def_id:?} (not eligible)");
6449
return;
6550
}
6651

52+
// An otherwise-eligible function is still skipped if its start block
53+
// is known to be unreachable.
6754
match mir_body.basic_blocks[mir::START_BLOCK].terminator().kind {
6855
TerminatorKind::Unreachable => {
6956
trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`");
@@ -72,21 +59,15 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
7259
_ => {}
7360
}
7461

75-
let codegen_fn_attrs = tcx.codegen_fn_attrs(mir_source.def_id());
76-
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
77-
return;
78-
}
79-
80-
trace!("InstrumentCoverage starting for {:?}", mir_source.def_id());
62+
trace!("InstrumentCoverage starting for {def_id:?}");
8163
Instrumentor::new(tcx, mir_body).inject_counters();
82-
trace!("InstrumentCoverage done for {:?}", mir_source.def_id());
64+
trace!("InstrumentCoverage done for {def_id:?}");
8365
}
8466
}
8567

8668
struct Instrumentor<'a, 'tcx> {
8769
tcx: TyCtxt<'tcx>,
8870
mir_body: &'a mut mir::Body<'tcx>,
89-
source_file: Lrc<SourceFile>,
9071
fn_sig_span: Span,
9172
body_span: Span,
9273
function_source_hash: u64,
@@ -96,37 +77,17 @@ struct Instrumentor<'a, 'tcx> {
9677

9778
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
9879
fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
99-
let source_map = tcx.sess.source_map();
100-
let def_id = mir_body.source.def_id();
101-
let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id);
80+
let hir_info @ ExtractedHirInfo { function_source_hash, fn_sig_span, body_span } =
81+
extract_hir_info(tcx, mir_body.source.def_id().expect_local());
10282

103-
let body_span = get_body_span(tcx, hir_body, mir_body);
83+
debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());
10484

105-
let source_file = source_map.lookup_source_file(body_span.lo());
106-
let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
107-
fn_sig.span.eq_ctxt(body_span)
108-
&& Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo()))
109-
}) {
110-
Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()),
111-
None => body_span.shrink_to_lo(),
112-
};
113-
114-
debug!(
115-
"instrumenting {}: {:?}, fn sig span: {:?}, body span: {:?}",
116-
if tcx.is_closure(def_id) { "closure" } else { "function" },
117-
def_id,
118-
fn_sig_span,
119-
body_span
120-
);
121-
122-
let function_source_hash = hash_mir_source(tcx, hir_body);
12385
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
12486
let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);
12587

12688
Self {
12789
tcx,
12890
mir_body,
129-
source_file,
13091
fn_sig_span,
13192
body_span,
13293
function_source_hash,
@@ -136,15 +97,12 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
13697
}
13798

13899
fn inject_counters(&'a mut self) {
139-
let fn_sig_span = self.fn_sig_span;
140-
let body_span = self.body_span;
141-
142100
////////////////////////////////////////////////////
143101
// Compute coverage spans from the `CoverageGraph`.
144102
let coverage_spans = CoverageSpans::generate_coverage_spans(
145103
self.mir_body,
146-
fn_sig_span,
147-
body_span,
104+
self.fn_sig_span,
105+
self.body_span,
148106
&self.basic_coverage_blocks,
149107
);
150108

@@ -177,9 +135,10 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
177135
let source_map = self.tcx.sess.source_map();
178136
let body_span = self.body_span;
179137

138+
let source_file = source_map.lookup_source_file(body_span.lo());
180139
use rustc_session::RemapFileNameExt;
181140
let file_name =
182-
Symbol::intern(&self.source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
141+
Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
183142

184143
let mut mappings = Vec::new();
185144

@@ -325,27 +284,75 @@ fn make_code_region(
325284
}
326285
}
327286

328-
fn fn_sig_and_body(
329-
tcx: TyCtxt<'_>,
330-
def_id: DefId,
331-
) -> (Option<&rustc_hir::FnSig<'_>>, &rustc_hir::Body<'_>) {
287+
fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
288+
// Only instrument functions, methods, and closures (not constants since they are evaluated
289+
// at compile time by Miri).
290+
// FIXME(#73156): Handle source code coverage in const eval, but note, if and when const
291+
// expressions get coverage spans, we will probably have to "carve out" space for const
292+
// expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
293+
// be tricky if const expressions have no corresponding statements in the enclosing MIR.
294+
// Closures are carved out by their initial `Assign` statement.)
295+
if !tcx.def_kind(def_id).is_fn_like() {
296+
trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)");
297+
return false;
298+
}
299+
300+
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
301+
return false;
302+
}
303+
304+
true
305+
}
306+
307+
/// Function information extracted from HIR by the coverage instrumentor.
308+
#[derive(Debug)]
309+
struct ExtractedHirInfo {
310+
function_source_hash: u64,
311+
fn_sig_span: Span,
312+
body_span: Span,
313+
}
314+
315+
fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo {
332316
// FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
333317
// to HIR for it.
334-
let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
318+
319+
let hir_node = tcx.hir_node_by_def_id(def_id);
335320
let (_, fn_body_id) =
336321
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
337-
(hir_node.fn_sig(), tcx.hir().body(fn_body_id))
322+
let hir_body = tcx.hir().body(fn_body_id);
323+
324+
let body_span = get_body_span(tcx, hir_body, def_id);
325+
326+
// The actual signature span is only used if it has the same context and
327+
// filename as the body, and precedes the body.
328+
let maybe_fn_sig_span = hir_node.fn_sig().map(|fn_sig| fn_sig.span);
329+
let fn_sig_span = maybe_fn_sig_span
330+
.filter(|&fn_sig_span| {
331+
let source_map = tcx.sess.source_map();
332+
let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo());
333+
334+
fn_sig_span.eq_ctxt(body_span)
335+
&& fn_sig_span.hi() <= body_span.lo()
336+
&& file_idx(fn_sig_span) == file_idx(body_span)
337+
})
338+
// If so, extend it to the start of the body span.
339+
.map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()))
340+
// Otherwise, create a dummy signature span at the start of the body.
341+
.unwrap_or_else(|| body_span.shrink_to_lo());
342+
343+
let function_source_hash = hash_mir_source(tcx, hir_body);
344+
345+
ExtractedHirInfo { function_source_hash, fn_sig_span, body_span }
338346
}
339347

340348
fn get_body_span<'tcx>(
341349
tcx: TyCtxt<'tcx>,
342350
hir_body: &rustc_hir::Body<'tcx>,
343-
mir_body: &mut mir::Body<'tcx>,
351+
def_id: LocalDefId,
344352
) -> Span {
345353
let mut body_span = hir_body.value.span;
346-
let def_id = mir_body.source.def_id();
347354

348-
if tcx.is_closure(def_id) {
355+
if tcx.is_closure(def_id.to_def_id()) {
349356
// If the MIR function is a closure, and if the closure body span
350357
// starts from a macro, but it's content is not in that macro, try
351358
// to find a non-macro callsite, and instrument the spans there

0 commit comments

Comments
 (0)