Skip to content

Commit 7669154

Browse files
committed
mcdc-coverage: Generate mcdc.parameters intrinsic call at the beginning of a function
1 parent e8b9b7c commit 7669154

File tree

4 files changed

+79
-3
lines changed

4 files changed

+79
-3
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,18 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
106106
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
107107
),
108108
CoverageKind::MCDCBitmapRequire { needed_bytes } => {
109-
// FIXME(dprn): TODO
110-
let _ = needed_bytes;
111-
warn!("call to correct intrinsic");
109+
// We need to explicitly drop the `RefMut` before calling into `instrprof_mcdc_parameters`,
110+
// as that needs an exclusive borrow.
111+
drop(coverage_map);
112+
113+
let fn_name = bx.get_pgo_func_name_var(instance);
114+
let hash = bx.const_u64(function_coverage_info.function_source_hash);
115+
let num_bitmap_bytes = bx.const_u32(needed_bytes);
116+
debug!(
117+
"codegen intrinsic instrprof.mcdc.parameters(fn_name={:?}, hash={:?}, bitmap_bytes={:?})",
118+
fn_name, hash, num_bitmap_bytes,
119+
);
120+
bx.instrprof_mcdc_parameters(fn_name, hash, num_bitmap_bytes);
112121
}
113122
CoverageKind::CounterIncrement { id } => {
114123
func_coverage.mark_counter_id_seen(id);

compiler/rustc_mir_transform/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constr
3434
mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
3535
mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
3636
mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
37+
mir_transform_mcdc_too_many_conditions = Unsupported MCDC Decision: Number of conditions ({$num_conditions}) exceeds max ({$max_conditions}). Expression will be skipped.
38+
3739
mir_transform_operation_will_panic = this operation will panic at runtime
3840
3941
mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use rustc_macros::Diagnostic;
2+
use rustc_middle::{
3+
mir::{
4+
self,
5+
coverage::{CoverageKind, DecisionSpan},
6+
Statement,
7+
},
8+
ty::TyCtxt,
9+
};
10+
use rustc_span::Span;
11+
12+
#[derive(Diagnostic)]
13+
#[diag(mir_transform_mcdc_too_many_conditions)]
14+
pub(crate) struct MCDCTooManyConditions {
15+
#[primary_span]
16+
pub span: Span,
17+
pub num_conditions: u32,
18+
pub max_conditions: u32,
19+
}
20+
21+
const MAX_COND_DECISION: u32 = 6;
22+
23+
/// If MCDC coverage is enabled, add MCDC instrumentation to the function.
24+
/// Will do the following things :
25+
/// 1. Add an instruction in the first basic block for the codegen to call
26+
/// the `instrprof.mcdc.parameters` instrinsic.
27+
pub fn instrument_function_mcdc<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
28+
if !tcx.sess.instrument_coverage_mcdc() {
29+
return;
30+
}
31+
32+
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else {
33+
return;
34+
};
35+
36+
// Compute the total sum of needed bytes for the current body.
37+
let needed_bytes: u32 = branch_info
38+
.decision_spans
39+
.iter()
40+
.filter_map(|DecisionSpan { span, num_conditions }| {
41+
if *num_conditions > MAX_COND_DECISION {
42+
tcx.dcx().emit_warn(MCDCTooManyConditions {
43+
span: *span,
44+
num_conditions: *num_conditions,
45+
max_conditions: MAX_COND_DECISION,
46+
});
47+
None
48+
} else {
49+
Some(1 << num_conditions)
50+
}
51+
})
52+
.sum();
53+
54+
let entry_bb = &mut mir_body.basic_blocks_mut()[mir::START_BLOCK];
55+
let mcdc_parameters_statement = Statement {
56+
source_info: entry_bb.terminator().source_info,
57+
kind: mir::StatementKind::Coverage(CoverageKind::MCDCBitmapRequire { needed_bytes }),
58+
};
59+
entry_bb.statements.insert(0, mcdc_parameters_statement);
60+
}

compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod query;
33
mod counters;
44
mod graph;
55
mod spans;
6+
mod mcdc;
67

78
#[cfg(test)]
89
mod tests;
@@ -100,6 +101,10 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
100101
&coverage_counters,
101102
);
102103

104+
////////////////////////////////////////////////////
105+
// Add the MCDC instrumentation. This is a no-op if MCDC coverage is disabled.
106+
mcdc::instrument_function_mcdc(tcx, mir_body);
107+
103108
mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
104109
function_source_hash: hir_info.function_source_hash,
105110
num_counters: coverage_counters.num_counters(),

0 commit comments

Comments
 (0)