Skip to content

Commit 27e634e

Browse files
author
zhuyunxing
committed
coverage. Add MCDCInfoBuilder to isolate all mcdc staff from BranchInfoBuilder
1 parent a76e250 commit 27e634e

File tree

1 file changed

+116
-87
lines changed

1 file changed

+116
-87
lines changed

compiler/rustc_mir_build/src/build/coverageinfo.rs

+116-87
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ pub(crate) struct BranchInfoBuilder {
2323
markers: BlockMarkerGen,
2424
branch_spans: Vec<BranchSpan>,
2525

26-
mcdc_branch_spans: Vec<MCDCBranchSpan>,
27-
mcdc_decision_spans: Vec<MCDCDecisionSpan>,
28-
mcdc_state: Option<MCDCState>,
26+
mcdc_info: Option<MCDCInfoBuilder>,
2927
}
3028

3129
#[derive(Clone, Copy)]
@@ -76,9 +74,7 @@ impl BranchInfoBuilder {
7674
nots: FxHashMap::default(),
7775
markers: BlockMarkerGen::default(),
7876
branch_spans: vec![],
79-
mcdc_branch_spans: vec![],
80-
mcdc_decision_spans: vec![],
81-
mcdc_state: MCDCState::new_if_enabled(tcx),
77+
mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new),
8278
})
8379
} else {
8480
None
@@ -125,48 +121,6 @@ impl BranchInfoBuilder {
125121
}
126122
}
127123

128-
fn fetch_mcdc_condition_info(
129-
&mut self,
130-
tcx: TyCtxt<'_>,
131-
true_marker: BlockMarkerId,
132-
false_marker: BlockMarkerId,
133-
) -> Option<(u16, ConditionInfo)> {
134-
let mcdc_state = self.mcdc_state.as_mut()?;
135-
let decision_depth = mcdc_state.decision_depth();
136-
let (mut condition_info, decision_result) =
137-
mcdc_state.take_condition(true_marker, false_marker);
138-
// take_condition() returns Some for decision_result when the decision stack
139-
// is empty, i.e. when all the conditions of the decision were instrumented,
140-
// and the decision is "complete".
141-
if let Some(decision) = decision_result {
142-
match decision.conditions_num {
143-
0 => {
144-
unreachable!("Decision with no condition is not expected");
145-
}
146-
1..=MAX_CONDITIONS_NUM_IN_DECISION => {
147-
self.mcdc_decision_spans.push(decision);
148-
}
149-
_ => {
150-
// Do not generate mcdc mappings and statements for decisions with too many conditions.
151-
let rebase_idx = self.mcdc_branch_spans.len() - decision.conditions_num + 1;
152-
for branch in &mut self.mcdc_branch_spans[rebase_idx..] {
153-
branch.condition_info = None;
154-
}
155-
156-
// ConditionInfo of this branch shall also be reset.
157-
condition_info = None;
158-
159-
tcx.dcx().emit_warn(MCDCExceedsConditionNumLimit {
160-
span: decision.span,
161-
conditions_num: decision.conditions_num,
162-
max_conditions_num: MAX_CONDITIONS_NUM_IN_DECISION,
163-
});
164-
}
165-
}
166-
}
167-
condition_info.map(|cond_info| (decision_depth, cond_info))
168-
}
169-
170124
fn add_two_way_branch<'tcx>(
171125
&mut self,
172126
cfg: &mut CFG<'tcx>,
@@ -185,16 +139,17 @@ impl BranchInfoBuilder {
185139
nots: _,
186140
markers: BlockMarkerGen { num_block_markers },
187141
branch_spans,
188-
mcdc_branch_spans,
189-
mcdc_decision_spans,
190-
mcdc_state: _,
142+
mcdc_info,
191143
} = self;
192144

193145
if num_block_markers == 0 {
194146
assert!(branch_spans.is_empty());
195147
return None;
196148
}
197149

150+
let (mcdc_decision_spans, mcdc_branch_spans) =
151+
mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default();
152+
198153
Some(Box::new(mir::coverage::BranchInfo {
199154
num_block_markers,
200155
branch_spans,
@@ -221,20 +176,23 @@ struct MCDCState {
221176
}
222177

223178
impl MCDCState {
224-
fn new_if_enabled(tcx: TyCtxt<'_>) -> Option<Self> {
225-
tcx.sess
226-
.instrument_coverage_mcdc()
227-
.then(|| Self { decision_ctx_stack: vec![MCDCDecisionCtx::default()] })
179+
fn new() -> Self {
180+
Self { decision_ctx_stack: vec![MCDCDecisionCtx::default()] }
228181
}
229182

230183
/// Decision depth is given as a u16 to reduce the size of the `CoverageKind`,
231184
/// as it is very unlikely that the depth ever reaches 2^16.
232185
#[inline]
233186
fn decision_depth(&self) -> u16 {
234-
u16::try_from(
235-
self.decision_ctx_stack.len().checked_sub(1).expect("Unexpected empty decision stack"),
236-
)
237-
.expect("decision depth did not fit in u16, this is likely to be an instrumentation error")
187+
match u16::try_from(self.decision_ctx_stack.len())
188+
.expect(
189+
"decision depth did not fit in u16, this is likely to be an instrumentation error",
190+
)
191+
.checked_sub(1)
192+
{
193+
Some(d) => d,
194+
None => bug!("Unexpected empty decision stack"),
195+
}
238196
}
239197

240198
// At first we assign ConditionIds for each sub expression.
@@ -343,8 +301,9 @@ impl MCDCState {
343301
true_marker: BlockMarkerId,
344302
false_marker: BlockMarkerId,
345303
) -> (Option<ConditionInfo>, Option<MCDCDecisionSpan>) {
346-
let decision_ctx =
347-
self.decision_ctx_stack.last_mut().expect("Unexpected empty decision_ctx_stack");
304+
let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else {
305+
bug!("Unexpected empty decision_ctx_stack")
306+
};
348307
let Some(condition_info) = decision_ctx.decision_stack.pop_back() else {
349308
return (None, None);
350309
};
@@ -366,6 +325,74 @@ impl MCDCState {
366325
}
367326
}
368327

328+
struct MCDCInfoBuilder {
329+
branch_spans: Vec<MCDCBranchSpan>,
330+
decision_spans: Vec<MCDCDecisionSpan>,
331+
state: MCDCState,
332+
}
333+
334+
impl MCDCInfoBuilder {
335+
fn new() -> Self {
336+
Self { branch_spans: vec![], decision_spans: vec![], state: MCDCState::new() }
337+
}
338+
339+
fn visit_evaluated_condition(
340+
&mut self,
341+
tcx: TyCtxt<'_>,
342+
source_info: SourceInfo,
343+
true_block: BasicBlock,
344+
false_block: BasicBlock,
345+
mut inject_block_marker: impl FnMut(SourceInfo, BasicBlock) -> BlockMarkerId,
346+
) {
347+
let true_marker = inject_block_marker(source_info, true_block);
348+
let false_marker = inject_block_marker(source_info, false_block);
349+
350+
let decision_depth = self.state.decision_depth();
351+
let (mut condition_info, decision_result) =
352+
self.state.take_condition(true_marker, false_marker);
353+
// take_condition() returns Some for decision_result when the decision stack
354+
// is empty, i.e. when all the conditions of the decision were instrumented,
355+
// and the decision is "complete".
356+
if let Some(decision) = decision_result {
357+
match decision.conditions_num {
358+
0 => {
359+
unreachable!("Decision with no condition is not expected");
360+
}
361+
1..=MAX_CONDITIONS_NUM_IN_DECISION => {
362+
self.decision_spans.push(decision);
363+
}
364+
_ => {
365+
// Do not generate mcdc mappings and statements for decisions with too many conditions.
366+
let rebase_idx = self.branch_spans.len() - decision.conditions_num + 1;
367+
for branch in &mut self.branch_spans[rebase_idx..] {
368+
branch.condition_info = None;
369+
}
370+
371+
// ConditionInfo of this branch shall also be reset.
372+
condition_info = None;
373+
374+
tcx.dcx().emit_warn(MCDCExceedsConditionNumLimit {
375+
span: decision.span,
376+
conditions_num: decision.conditions_num,
377+
max_conditions_num: MAX_CONDITIONS_NUM_IN_DECISION,
378+
});
379+
}
380+
}
381+
}
382+
self.branch_spans.push(MCDCBranchSpan {
383+
span: source_info.span,
384+
condition_info,
385+
true_marker,
386+
false_marker,
387+
decision_depth,
388+
});
389+
}
390+
391+
fn into_done(self) -> (Vec<MCDCDecisionSpan>, Vec<MCDCBranchSpan>) {
392+
(self.decision_spans, self.branch_spans)
393+
}
394+
}
395+
369396
impl Builder<'_, '_> {
370397
/// If branch coverage is enabled, inject marker statements into `then_block`
371398
/// and `else_block`, and record their IDs in the table of branch spans.
@@ -390,50 +417,52 @@ impl Builder<'_, '_> {
390417
let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
391418

392419
// Separate path for handling branches when MC/DC is enabled.
393-
if branch_info.mcdc_state.is_some() {
394-
let mut inject_block_marker =
395-
|block| branch_info.markers.inject_block_marker(&mut self.cfg, source_info, block);
396-
let true_marker = inject_block_marker(then_block);
397-
let false_marker = inject_block_marker(else_block);
398-
let (decision_depth, condition_info) = branch_info
399-
.fetch_mcdc_condition_info(self.tcx, true_marker, false_marker)
400-
.map_or((0, None), |(decision_depth, condition_info)| {
401-
(decision_depth, Some(condition_info))
402-
});
403-
branch_info.mcdc_branch_spans.push(MCDCBranchSpan {
404-
span: source_info.span,
405-
condition_info,
406-
true_marker,
407-
false_marker,
408-
decision_depth,
409-
});
420+
if let Some(mcdc_info) = branch_info.mcdc_info.as_mut() {
421+
let inject_block_marker = |source_info, block| {
422+
branch_info.markers.inject_block_marker(&mut self.cfg, source_info, block)
423+
};
424+
mcdc_info.visit_evaluated_condition(
425+
self.tcx,
426+
source_info,
427+
then_block,
428+
else_block,
429+
inject_block_marker,
430+
);
410431
return;
411432
}
412433

413434
branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block);
414435
}
415436

416437
pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) {
417-
if let Some(branch_info) = self.coverage_branch_info.as_mut()
418-
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
438+
if let Some(mcdc_info) = self
439+
.coverage_branch_info
440+
.as_mut()
441+
.and_then(|branch_info| branch_info.mcdc_info.as_mut())
419442
{
420-
mcdc_state.record_conditions(logical_op, span);
443+
mcdc_info.state.record_conditions(logical_op, span);
421444
}
422445
}
423446

424447
pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) {
425-
if let Some(branch_info) = self.coverage_branch_info.as_mut()
426-
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
448+
if let Some(mcdc_info) = self
449+
.coverage_branch_info
450+
.as_mut()
451+
.and_then(|branch_info| branch_info.mcdc_info.as_mut())
427452
{
428-
mcdc_state.decision_ctx_stack.push(MCDCDecisionCtx::default());
453+
mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default());
429454
};
430455
}
431456

432457
pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) {
433-
if let Some(branch_info) = self.coverage_branch_info.as_mut()
434-
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
458+
if let Some(mcdc_info) = self
459+
.coverage_branch_info
460+
.as_mut()
461+
.and_then(|branch_info| branch_info.mcdc_info.as_mut())
435462
{
436-
mcdc_state.decision_ctx_stack.pop().expect("Unexpected empty decision stack");
463+
if mcdc_info.state.decision_ctx_stack.pop().is_none() {
464+
bug!("Unexpected empty decision stack");
465+
}
437466
};
438467
}
439468
}

0 commit comments

Comments
 (0)