Skip to content

Commit 9eea580

Browse files
committed
Auto merge of rust-lang#136804 - Zalathar:rollup-o3nyapl, r=Zalathar
Rollup of 6 pull requests Successful merges: - rust-lang#134626 (Add Four Codegen Tests) - rust-lang#136053 (coverage: Defer part of counter-creation until codegen) - rust-lang#136228 (Simplify Rc::as_ptr docs + typo fix) - rust-lang#136487 (ci: stop mysql before removing it) - rust-lang#136790 (Git blame ignore recent formatting commit) - rust-lang#136803 (Subtree update of `rust-analyzer`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents c03c38d + 1417031 commit 9eea580

File tree

241 files changed

+6184
-4562
lines changed

Some content is hidden

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

241 files changed

+6184
-4562
lines changed

.git-blame-ignore-revs

+2
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8
2929
99cb0c6bc399fb94a0ddde7e9b38e9c00d523bad
3030
# reformat with rustfmt edition 2024
3131
c682aa162b0d41e21cc6748f4fecfe01efb69d1f
32+
# reformat with updated edition 2024
33+
1fcae03369abb4c2cc180cd5a49e1f4440a81300

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs

+24-31
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use rustc_codegen_ssa::traits::{
1111
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
1212
};
1313
use rustc_middle::mir::coverage::{
14-
CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op,
14+
BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping,
15+
MappingKind, Op,
1516
};
1617
use rustc_middle::ty::{Instance, TyCtxt};
1718
use rustc_span::Span;
@@ -53,7 +54,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
5354
let fn_cov_info = tcx.instance_mir(instance.def).function_coverage_info.as_deref()?;
5455
let ids_info = tcx.coverage_ids_info(instance.def)?;
5556

56-
let expressions = prepare_expressions(fn_cov_info, ids_info, is_used);
57+
let expressions = prepare_expressions(ids_info);
5758

5859
let mut covfun = CovfunRecord {
5960
mangled_function_name: tcx.symbol_name(instance).name,
@@ -75,26 +76,14 @@ pub(crate) fn prepare_covfun_record<'tcx>(
7576
}
7677

7778
/// Convert the function's coverage-counter expressions into a form suitable for FFI.
78-
fn prepare_expressions(
79-
fn_cov_info: &FunctionCoverageInfo,
80-
ids_info: &CoverageIdsInfo,
81-
is_used: bool,
82-
) -> Vec<ffi::CounterExpression> {
83-
// If any counters or expressions were removed by MIR opts, replace their
84-
// terms with zero.
85-
let counter_for_term = |term| {
86-
if !is_used || ids_info.is_zero_term(term) {
87-
ffi::Counter::ZERO
88-
} else {
89-
ffi::Counter::from_term(term)
90-
}
91-
};
79+
fn prepare_expressions(ids_info: &CoverageIdsInfo) -> Vec<ffi::CounterExpression> {
80+
let counter_for_term = ffi::Counter::from_term;
9281

9382
// We know that LLVM will optimize out any unused expressions before
9483
// producing the final coverage map, so there's no need to do the same
9584
// thing on the Rust side unless we're confident we can do much better.
9685
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
97-
fn_cov_info
86+
ids_info
9887
.expressions
9988
.iter()
10089
.map(move |&Expression { lhs, op, rhs }| ffi::CounterExpression {
@@ -136,11 +125,16 @@ fn fill_region_tables<'tcx>(
136125

137126
// For each counter/region pair in this function+file, convert it to a
138127
// form suitable for FFI.
139-
let is_zero_term = |term| !covfun.is_used || ids_info.is_zero_term(term);
140128
for &Mapping { ref kind, span } in &fn_cov_info.mappings {
141-
// If the mapping refers to counters/expressions that were removed by
142-
// MIR opts, replace those occurrences with zero.
143-
let kind = kind.map_terms(|term| if is_zero_term(term) { CovTerm::Zero } else { term });
129+
// If this function is unused, replace all counters with zero.
130+
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
131+
let term = if covfun.is_used {
132+
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
133+
} else {
134+
CovTerm::Zero
135+
};
136+
ffi::Counter::from_term(term)
137+
};
144138

145139
// Convert the `Span` into coordinates that we can pass to LLVM, or
146140
// discard the span if conversion fails. In rare, cases _all_ of a
@@ -154,23 +148,22 @@ fn fill_region_tables<'tcx>(
154148
continue;
155149
}
156150

157-
match kind {
158-
MappingKind::Code(term) => {
159-
code_regions
160-
.push(ffi::CodeRegion { cov_span, counter: ffi::Counter::from_term(term) });
151+
match *kind {
152+
MappingKind::Code { bcb } => {
153+
code_regions.push(ffi::CodeRegion { cov_span, counter: counter_for_bcb(bcb) });
161154
}
162-
MappingKind::Branch { true_term, false_term } => {
155+
MappingKind::Branch { true_bcb, false_bcb } => {
163156
branch_regions.push(ffi::BranchRegion {
164157
cov_span,
165-
true_counter: ffi::Counter::from_term(true_term),
166-
false_counter: ffi::Counter::from_term(false_term),
158+
true_counter: counter_for_bcb(true_bcb),
159+
false_counter: counter_for_bcb(false_bcb),
167160
});
168161
}
169-
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
162+
MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params } => {
170163
mcdc_branch_regions.push(ffi::MCDCBranchRegion {
171164
cov_span,
172-
true_counter: ffi::Counter::from_term(true_term),
173-
false_counter: ffi::Counter::from_term(false_term),
165+
true_counter: counter_for_bcb(true_bcb),
166+
false_counter: counter_for_bcb(false_bcb),
174167
mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
175168
});
176169
}

compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

+6-17
Original file line numberDiff line numberDiff line change
@@ -160,32 +160,21 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
160160
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
161161
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
162162
),
163-
CoverageKind::CounterIncrement { id } => {
164-
// The number of counters passed to `llvm.instrprof.increment` might
165-
// be smaller than the number originally inserted by the instrumentor,
166-
// if some high-numbered counters were removed by MIR optimizations.
167-
// If so, LLVM's profiler runtime will use fewer physical counters.
168-
let num_counters = ids_info.num_counters_after_mir_opts();
169-
assert!(
170-
num_counters as usize <= function_coverage_info.num_counters,
171-
"num_counters disagreement: query says {num_counters} but function info only has {}",
172-
function_coverage_info.num_counters
173-
);
174-
163+
CoverageKind::VirtualCounter { bcb }
164+
if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
165+
{
175166
let fn_name = bx.get_pgo_func_name_var(instance);
176167
let hash = bx.const_u64(function_coverage_info.function_source_hash);
177-
let num_counters = bx.const_u32(num_counters);
168+
let num_counters = bx.const_u32(ids_info.num_counters);
178169
let index = bx.const_u32(id.as_u32());
179170
debug!(
180171
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
181172
fn_name, hash, num_counters, index,
182173
);
183174
bx.instrprof_increment(fn_name, hash, num_counters, index);
184175
}
185-
CoverageKind::ExpressionUsed { id: _ } => {
186-
// Expression-used statements are markers that are handled by
187-
// `coverage_ids_info`, so there's nothing to codegen here.
188-
}
176+
// If a BCB doesn't have an associated physical counter, there's nothing to codegen.
177+
CoverageKind::VirtualCounter { .. } => {}
189178
CoverageKind::CondBitmapUpdate { index, decision_depth } => {
190179
let cond_bitmap = coverage_cx
191180
.try_get_mcdc_condition_bitmap(&instance, decision_depth)

compiler/rustc_codegen_llvm/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![feature(extern_types)]
1414
#![feature(file_buffered)]
1515
#![feature(hash_raw_entry)]
16+
#![feature(if_let_guard)]
1617
#![feature(impl_trait_in_assoc_type)]
1718
#![feature(iter_intersperse)]
1819
#![feature(let_chains)]

compiler/rustc_middle/src/mir/coverage.rs

+66-73
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
33
use std::fmt::{self, Debug, Formatter};
44

5-
use rustc_index::IndexVec;
6-
use rustc_index::bit_set::DenseBitSet;
5+
use rustc_data_structures::fx::FxIndexMap;
6+
use rustc_index::{Idx, IndexVec};
77
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
88
use rustc_span::Span;
99

@@ -103,23 +103,12 @@ pub enum CoverageKind {
103103
/// Should be erased before codegen (at some point after `InstrumentCoverage`).
104104
BlockMarker { id: BlockMarkerId },
105105

106-
/// Marks the point in MIR control flow represented by a coverage counter.
106+
/// Marks its enclosing basic block with the ID of the coverage graph node
107+
/// that it was part of during the `InstrumentCoverage` MIR pass.
107108
///
108-
/// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR.
109-
///
110-
/// If this statement does not survive MIR optimizations, any mappings that
111-
/// refer to this counter can have those references simplified to zero.
112-
CounterIncrement { id: CounterId },
113-
114-
/// Marks the point in MIR control-flow represented by a coverage expression.
115-
///
116-
/// If this statement does not survive MIR optimizations, any mappings that
117-
/// refer to this expression can have those references simplified to zero.
118-
///
119-
/// (This is only inserted for expression IDs that are directly used by
120-
/// mappings. Intermediate expressions with no direct mappings are
121-
/// retained/zeroed based on whether they are transitively used.)
122-
ExpressionUsed { id: ExpressionId },
109+
/// During codegen, this might be lowered to `llvm.instrprof.increment` or
110+
/// to a no-op, depending on the outcome of counter-creation.
111+
VirtualCounter { bcb: BasicCoverageBlock },
123112

124113
/// Marks the point in MIR control flow represented by a evaluated condition.
125114
///
@@ -138,8 +127,7 @@ impl Debug for CoverageKind {
138127
match self {
139128
SpanMarker => write!(fmt, "SpanMarker"),
140129
BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()),
141-
CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()),
142-
ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()),
130+
VirtualCounter { bcb } => write!(fmt, "VirtualCounter({bcb:?})"),
143131
CondBitmapUpdate { index, decision_depth } => {
144132
write!(fmt, "CondBitmapUpdate(index={:?}, depth={:?})", index, decision_depth)
145133
}
@@ -179,34 +167,19 @@ pub struct Expression {
179167
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
180168
pub enum MappingKind {
181169
/// Associates a normal region of code with a counter/expression/zero.
182-
Code(CovTerm),
170+
Code { bcb: BasicCoverageBlock },
183171
/// Associates a branch region with separate counters for true and false.
184-
Branch { true_term: CovTerm, false_term: CovTerm },
172+
Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock },
185173
/// Associates a branch region with separate counters for true and false.
186-
MCDCBranch { true_term: CovTerm, false_term: CovTerm, mcdc_params: ConditionInfo },
174+
MCDCBranch {
175+
true_bcb: BasicCoverageBlock,
176+
false_bcb: BasicCoverageBlock,
177+
mcdc_params: ConditionInfo,
178+
},
187179
/// Associates a decision region with a bitmap and number of conditions.
188180
MCDCDecision(DecisionInfo),
189181
}
190182

191-
impl MappingKind {
192-
/// Returns a copy of this mapping kind, in which all coverage terms have
193-
/// been replaced with ones returned by the given function.
194-
pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self {
195-
match *self {
196-
Self::Code(term) => Self::Code(map_fn(term)),
197-
Self::Branch { true_term, false_term } => {
198-
Self::Branch { true_term: map_fn(true_term), false_term: map_fn(false_term) }
199-
}
200-
Self::MCDCBranch { true_term, false_term, mcdc_params } => Self::MCDCBranch {
201-
true_term: map_fn(true_term),
202-
false_term: map_fn(false_term),
203-
mcdc_params,
204-
},
205-
Self::MCDCDecision(param) => Self::MCDCDecision(param),
206-
}
207-
}
208-
}
209-
210183
#[derive(Clone, Debug)]
211184
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
212185
pub struct Mapping {
@@ -222,10 +195,15 @@ pub struct Mapping {
222195
pub struct FunctionCoverageInfo {
223196
pub function_source_hash: u64,
224197
pub body_span: Span,
225-
pub num_counters: usize,
226-
pub mcdc_bitmap_bits: usize,
227-
pub expressions: IndexVec<ExpressionId, Expression>,
198+
199+
/// Used in conjunction with `priority_list` to create physical counters
200+
/// and counter expressions, after MIR optimizations.
201+
pub node_flow_data: NodeFlowData<BasicCoverageBlock>,
202+
pub priority_list: Vec<BasicCoverageBlock>,
203+
228204
pub mappings: Vec<Mapping>,
205+
206+
pub mcdc_bitmap_bits: usize,
229207
/// The depth of the deepest decision is used to know how many
230208
/// temp condbitmaps should be allocated for the function.
231209
pub mcdc_num_condition_bitmaps: usize,
@@ -292,40 +270,55 @@ pub struct MCDCDecisionSpan {
292270
pub num_conditions: usize,
293271
}
294272

295-
/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
296-
/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
297-
/// have had a chance to potentially remove some of them.
273+
/// Contains information needed during codegen, obtained by inspecting the
274+
/// function's MIR after MIR optimizations.
298275
///
299-
/// Used by the `coverage_ids_info` query.
276+
/// Returned by the `coverage_ids_info` query.
300277
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
301278
pub struct CoverageIdsInfo {
302-
pub counters_seen: DenseBitSet<CounterId>,
303-
pub zero_expressions: DenseBitSet<ExpressionId>,
279+
pub num_counters: u32,
280+
pub phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>,
281+
pub term_for_bcb: IndexVec<BasicCoverageBlock, Option<CovTerm>>,
282+
pub expressions: IndexVec<ExpressionId, Expression>,
304283
}
305284

306-
impl CoverageIdsInfo {
307-
/// Coverage codegen needs to know how many coverage counters are ever
308-
/// incremented within a function, so that it can set the `num-counters`
309-
/// argument of the `llvm.instrprof.increment` intrinsic.
285+
rustc_index::newtype_index! {
286+
/// During the `InstrumentCoverage` MIR pass, a BCB is a node in the
287+
/// "coverage graph", which is a refinement of the MIR control-flow graph
288+
/// that merges or omits some blocks that aren't relevant to coverage.
310289
///
311-
/// This may be less than the highest counter ID emitted by the
312-
/// InstrumentCoverage MIR pass, if the highest-numbered counter increments
313-
/// were removed by MIR optimizations.
314-
pub fn num_counters_after_mir_opts(&self) -> u32 {
315-
// FIXME(Zalathar): Currently this treats an unused counter as "used"
316-
// if its ID is less than that of the highest counter that really is
317-
// used. Fixing this would require adding a renumbering step somewhere.
318-
self.counters_seen.last_set_in(..).map_or(0, |max| max.as_u32() + 1)
290+
/// After that pass is complete, the coverage graph no longer exists, so a
291+
/// BCB is effectively an opaque ID.
292+
#[derive(HashStable)]
293+
#[encodable]
294+
#[orderable]
295+
#[debug_format = "bcb{}"]
296+
pub struct BasicCoverageBlock {
297+
const START_BCB = 0;
319298
}
299+
}
320300

321-
/// Returns `true` if the given term is known to have a value of zero, taking
322-
/// into account knowledge of which counters are unused and which expressions
323-
/// are always zero.
324-
pub fn is_zero_term(&self, term: CovTerm) -> bool {
325-
match term {
326-
CovTerm::Zero => true,
327-
CovTerm::Counter(id) => !self.counters_seen.contains(id),
328-
CovTerm::Expression(id) => self.zero_expressions.contains(id),
329-
}
330-
}
301+
/// Data representing a view of some underlying graph, in which each node's
302+
/// successors have been merged into a single "supernode".
303+
///
304+
/// The resulting supernodes have no obvious meaning on their own.
305+
/// However, merging successor nodes means that a node's out-edges can all
306+
/// be combined into a single out-edge, whose flow is the same as the flow
307+
/// (execution count) of its corresponding node in the original graph.
308+
///
309+
/// With all node flows now in the original graph now represented as edge flows
310+
/// in the merged graph, it becomes possible to analyze the original node flows
311+
/// using techniques for analyzing edge flows.
312+
#[derive(Clone, Debug)]
313+
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
314+
pub struct NodeFlowData<Node: Idx> {
315+
/// Maps each node to the supernode that contains it, indicated by some
316+
/// arbitrary "root" node that is part of that supernode.
317+
pub supernodes: IndexVec<Node, Node>,
318+
/// For each node, stores the single supernode that all of its successors
319+
/// have been merged into.
320+
///
321+
/// (Note that each node in a supernode can potentially have a _different_
322+
/// successor supernode from its peers.)
323+
pub succ_supernodes: IndexVec<Node, Node>,
331324
}

compiler/rustc_middle/src/mir/pretty.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -619,13 +619,9 @@ fn write_function_coverage_info(
619619
function_coverage_info: &coverage::FunctionCoverageInfo,
620620
w: &mut dyn io::Write,
621621
) -> io::Result<()> {
622-
let coverage::FunctionCoverageInfo { body_span, expressions, mappings, .. } =
623-
function_coverage_info;
622+
let coverage::FunctionCoverageInfo { body_span, mappings, .. } = function_coverage_info;
624623

625624
writeln!(w, "{INDENT}coverage body span: {body_span:?}")?;
626-
for (id, expression) in expressions.iter_enumerated() {
627-
writeln!(w, "{INDENT}coverage {id:?} => {expression:?};")?;
628-
}
629625
for coverage::Mapping { kind, span } in mappings {
630626
writeln!(w, "{INDENT}coverage {kind:?} => {span:?};")?;
631627
}

compiler/rustc_middle/src/query/mod.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -614,9 +614,16 @@ rustc_queries! {
614614
feedable
615615
}
616616

617-
/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
618-
/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
619-
/// have had a chance to potentially remove some of them.
617+
/// Scans through a function's MIR after MIR optimizations, to prepare the
618+
/// information needed by codegen when `-Cinstrument-coverage` is active.
619+
///
620+
/// This includes the details of where to insert `llvm.instrprof.increment`
621+
/// intrinsics, and the expression tables to be embedded in the function's
622+
/// coverage metadata.
623+
///
624+
/// FIXME(Zalathar): This query's purpose has drifted a bit and should
625+
/// probably be renamed, but that can wait until after the potential
626+
/// follow-ups to #136053 have settled down.
620627
///
621628
/// Returns `None` for functions that were not instrumented.
622629
query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> Option<&'tcx mir::coverage::CoverageIdsInfo> {

0 commit comments

Comments
 (0)