Skip to content

Commit e198c51

Browse files
author
zhuyunxing
committedApr 30, 2024
coverage. Add MCDCInfoBuilder to isolate all mcdc stuff from BranchInfoBuilder
1 parent a76e250 commit e198c51

File tree

1 file changed

+110
-86
lines changed

1 file changed

+110
-86
lines changed
 

‎compiler/rustc_mir_build/src/build/coverageinfo.rs

+110-86
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.
@@ -279,8 +237,9 @@ impl MCDCState {
279237
// - If the op is OR, the "true_next" of LHS and RHS should be the parent's "true_next". While "false_next" of the LHS is the RHS, the "false next" of RHS is the parent's "false_next".
280238
fn record_conditions(&mut self, op: LogicalOp, span: Span) {
281239
let decision_depth = self.decision_depth();
282-
let decision_ctx =
283-
self.decision_ctx_stack.last_mut().expect("Unexpected empty decision_ctx_stack");
240+
let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else {
241+
bug!("Unexpected empty decision_ctx_stack")
242+
};
284243
let decision = match decision_ctx.processing_decision.as_mut() {
285244
Some(decision) => {
286245
decision.span = decision.span.to(span);
@@ -343,8 +302,9 @@ impl MCDCState {
343302
true_marker: BlockMarkerId,
344303
false_marker: BlockMarkerId,
345304
) -> (Option<ConditionInfo>, Option<MCDCDecisionSpan>) {
346-
let decision_ctx =
347-
self.decision_ctx_stack.last_mut().expect("Unexpected empty decision_ctx_stack");
305+
let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else {
306+
bug!("Unexpected empty decision_ctx_stack")
307+
};
348308
let Some(condition_info) = decision_ctx.decision_stack.pop_back() else {
349309
return (None, None);
350310
};
@@ -366,6 +326,74 @@ impl MCDCState {
366326
}
367327
}
368328

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

392420
// 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-
});
421+
if let Some(mcdc_info) = branch_info.mcdc_info.as_mut() {
422+
let inject_block_marker = |source_info, block| {
423+
branch_info.markers.inject_block_marker(&mut self.cfg, source_info, block)
424+
};
425+
mcdc_info.visit_evaluated_condition(
426+
self.tcx,
427+
source_info,
428+
then_block,
429+
else_block,
430+
inject_block_marker,
431+
);
410432
return;
411433
}
412434

@@ -415,25 +437,27 @@ impl Builder<'_, '_> {
415437

416438
pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) {
417439
if let Some(branch_info) = self.coverage_branch_info.as_mut()
418-
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
440+
&& let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
419441
{
420-
mcdc_state.record_conditions(logical_op, span);
442+
mcdc_info.state.record_conditions(logical_op, span);
421443
}
422444
}
423445

424446
pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) {
425447
if let Some(branch_info) = self.coverage_branch_info.as_mut()
426-
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
448+
&& let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
427449
{
428-
mcdc_state.decision_ctx_stack.push(MCDCDecisionCtx::default());
450+
mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default());
429451
};
430452
}
431453

432454
pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) {
433455
if let Some(branch_info) = self.coverage_branch_info.as_mut()
434-
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
456+
&& let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
435457
{
436-
mcdc_state.decision_ctx_stack.pop().expect("Unexpected empty decision stack");
458+
if mcdc_info.state.decision_ctx_stack.pop().is_none() {
459+
bug!("Unexpected empty decision stack");
460+
}
437461
};
438462
}
439463
}

0 commit comments

Comments
 (0)
Please sign in to comment.