Auto merge of #124255 - RenjiSann:renji/mcdc-nested-expressions, r=Zalathar
MCDC coverage: support nested decision coverage #123409 provided the initial MCDC coverage implementation. As referenced in #124144, it does not currently support "nested" decisions, like the following example : ```rust fn nested_if_in_condition(a: bool, b: bool, c: bool) { if a && if b || c { true } else { false } { say("yes"); } else { say("no"); } } ``` Note that there is an if-expression (`if b || c ...`) embedded inside a boolean expression in the decision of an outer if-expression. This PR proposes a workaround for this cases, by introducing a Decision context stack, and by handing several `temporary condition bitmaps` instead of just one. When instrumenting boolean expressions, if the current node is a leaf condition (i.e. not a `||`/`&&` logical operator nor a `!` not operator), we insert a new decision context, such that if there are more boolean expressions inside the condition, they are handled as separate expressions. On the codegen LLVM side, we allocate as many `temp_cond_bitmap`s as necessary to handle the maximum encountered decision depth.
This commit is contained in:
commit
7a58674259
12 changed files with 699 additions and 70 deletions
|
@ -102,12 +102,23 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
|||
|
||||
inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans);
|
||||
|
||||
let mcdc_max_decision_depth = coverage_spans
|
||||
.mappings
|
||||
.iter()
|
||||
.filter_map(|bcb_mapping| match bcb_mapping.kind {
|
||||
BcbMappingKind::MCDCDecision { decision_depth, .. } => Some(decision_depth),
|
||||
_ => None,
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
||||
function_source_hash: hir_info.function_source_hash,
|
||||
num_counters: coverage_counters.num_counters(),
|
||||
mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(),
|
||||
expressions: coverage_counters.into_expressions(),
|
||||
mappings,
|
||||
mcdc_max_decision_depth,
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -145,16 +156,17 @@ fn create_mappings<'tcx>(
|
|||
|BcbMapping { kind: bcb_mapping_kind, span }| {
|
||||
let kind = match *bcb_mapping_kind {
|
||||
BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
|
||||
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info: None } => {
|
||||
MappingKind::Branch {
|
||||
true_term: term_for_bcb(true_bcb),
|
||||
false_term: term_for_bcb(false_bcb),
|
||||
}
|
||||
}
|
||||
BcbMappingKind::MCDCBranch {
|
||||
true_bcb, false_bcb, condition_info: None, ..
|
||||
} => MappingKind::Branch {
|
||||
true_term: term_for_bcb(true_bcb),
|
||||
false_term: term_for_bcb(false_bcb),
|
||||
},
|
||||
BcbMappingKind::MCDCBranch {
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
condition_info: Some(mcdc_params),
|
||||
..
|
||||
} => MappingKind::MCDCBranch {
|
||||
true_term: term_for_bcb(true_bcb),
|
||||
false_term: term_for_bcb(false_bcb),
|
||||
|
@ -246,24 +258,28 @@ fn inject_mcdc_statements<'tcx>(
|
|||
}
|
||||
|
||||
// Inject test vector update first because `inject_statement` always insert new statement at head.
|
||||
for (end_bcbs, bitmap_idx) in
|
||||
for (end_bcbs, bitmap_idx, decision_depth) in
|
||||
coverage_spans.mappings.iter().filter_map(|mapping| match &mapping.kind {
|
||||
BcbMappingKind::MCDCDecision { end_bcbs, bitmap_idx, .. } => {
|
||||
Some((end_bcbs, *bitmap_idx))
|
||||
BcbMappingKind::MCDCDecision { end_bcbs, bitmap_idx, decision_depth, .. } => {
|
||||
Some((end_bcbs, *bitmap_idx, *decision_depth))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
for end in end_bcbs {
|
||||
let end_bb = basic_coverage_blocks[*end].leader_bb();
|
||||
inject_statement(mir_body, CoverageKind::TestVectorBitmapUpdate { bitmap_idx }, end_bb);
|
||||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth },
|
||||
end_bb,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (true_bcb, false_bcb, condition_id) in
|
||||
for (true_bcb, false_bcb, condition_id, decision_depth) in
|
||||
coverage_spans.mappings.iter().filter_map(|mapping| match mapping.kind {
|
||||
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
|
||||
Some((true_bcb, false_bcb, condition_info?.condition_id))
|
||||
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info, decision_depth } => {
|
||||
Some((true_bcb, false_bcb, condition_info?.condition_id, decision_depth))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
|
@ -271,13 +287,13 @@ fn inject_mcdc_statements<'tcx>(
|
|||
let true_bb = basic_coverage_blocks[true_bcb].leader_bb();
|
||||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::CondBitmapUpdate { id: condition_id, value: true },
|
||||
CoverageKind::CondBitmapUpdate { id: condition_id, value: true, decision_depth },
|
||||
true_bb,
|
||||
);
|
||||
let false_bb = basic_coverage_blocks[false_bcb].leader_bb();
|
||||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::CondBitmapUpdate { id: condition_id, value: false },
|
||||
CoverageKind::CondBitmapUpdate { id: condition_id, value: false, decision_depth },
|
||||
false_bb,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,9 +26,15 @@ pub(super) enum BcbMappingKind {
|
|||
/// If `None`, this actually represents a normal branch mapping inserted
|
||||
/// for code that was too complex for MC/DC.
|
||||
condition_info: Option<ConditionInfo>,
|
||||
decision_depth: u16,
|
||||
},
|
||||
/// Associates a mcdc decision with its join BCB.
|
||||
MCDCDecision { end_bcbs: BTreeSet<BasicCoverageBlock>, bitmap_idx: u32, conditions_num: u16 },
|
||||
MCDCDecision {
|
||||
end_bcbs: BTreeSet<BasicCoverageBlock>,
|
||||
bitmap_idx: u32,
|
||||
conditions_num: u16,
|
||||
decision_depth: u16,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -453,15 +453,25 @@ pub(super) fn extract_mcdc_mappings(
|
|||
Some((span, true_bcb, false_bcb))
|
||||
};
|
||||
|
||||
let mcdc_branch_filter_map =
|
||||
|&MCDCBranchSpan { span: raw_span, true_marker, false_marker, condition_info }| {
|
||||
check_branch_bcb(raw_span, true_marker, false_marker).map(
|
||||
|(span, true_bcb, false_bcb)| BcbMapping {
|
||||
kind: BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info },
|
||||
span,
|
||||
let mcdc_branch_filter_map = |&MCDCBranchSpan {
|
||||
span: raw_span,
|
||||
true_marker,
|
||||
false_marker,
|
||||
condition_info,
|
||||
decision_depth,
|
||||
}| {
|
||||
check_branch_bcb(raw_span, true_marker, false_marker).map(|(span, true_bcb, false_bcb)| {
|
||||
BcbMapping {
|
||||
kind: BcbMappingKind::MCDCBranch {
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
condition_info,
|
||||
decision_depth,
|
||||
},
|
||||
)
|
||||
};
|
||||
span,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let mut next_bitmap_idx = 0;
|
||||
|
||||
|
@ -482,6 +492,7 @@ pub(super) fn extract_mcdc_mappings(
|
|||
end_bcbs,
|
||||
bitmap_idx,
|
||||
conditions_num: decision.conditions_num as u16,
|
||||
decision_depth: decision.decision_depth,
|
||||
},
|
||||
span,
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue