1
Fork 0

coverage. Generate Mappings of decisions and conditions for MC/DC

This commit is contained in:
zhuyunxing 2024-04-19 10:53:04 +08:00
parent 68f86381ee
commit cf6b6cb2b4
10 changed files with 779 additions and 41 deletions

View file

@ -100,9 +100,12 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
&coverage_counters,
);
inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans);
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,
}));
@ -136,20 +139,33 @@ fn create_mappings<'tcx>(
.as_term()
};
coverage_spans
.all_bcb_mappings()
.filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| {
let kind = match bcb_mapping_kind {
let mut mappings = Vec::new();
mappings.extend(coverage_spans.all_bcb_mappings().filter_map(
|BcbMapping { kind: bcb_mapping_kind, span }| {
let kind = match *bcb_mapping_kind {
BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
BcbMappingKind::Branch { true_bcb, false_bcb } => MappingKind::Branch {
true_term: term_for_bcb(true_bcb),
false_term: term_for_bcb(false_bcb),
},
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
MappingKind::MCDCBranch {
true_term: term_for_bcb(true_bcb),
false_term: term_for_bcb(false_bcb),
mcdc_params: condition_info,
}
}
BcbMappingKind::MCDCDecision { bitmap_idx, conditions_num, .. } => {
MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num })
}
};
let code_region = make_code_region(source_map, file_name, span, body_span)?;
let code_region = make_code_region(source_map, file_name, *span, body_span)?;
Some(Mapping { kind, code_region })
})
.collect::<Vec<_>>()
},
));
mappings
}
/// For each BCB node or BCB edge that has an associated coverage counter,
@ -204,6 +220,55 @@ fn inject_coverage_statements<'tcx>(
}
}
/// For each conditions inject statements to update condition bitmap after it has been evaluated.
/// For each decision inject statements to update test vector bitmap after it has been evaluated.
fn inject_mcdc_statements<'tcx>(
mir_body: &mut mir::Body<'tcx>,
basic_coverage_blocks: &CoverageGraph,
coverage_spans: &CoverageSpans,
) {
if coverage_spans.test_vector_bitmap_bytes() == 0 {
return;
}
// Inject test vector update first because `inject_statement` always insert new statement at head.
for (end_bcbs, bitmap_idx) in
coverage_spans.all_bcb_mappings().filter_map(|mapping| match &mapping.kind {
BcbMappingKind::MCDCDecision { end_bcbs, bitmap_idx, .. } => {
Some((end_bcbs, *bitmap_idx))
}
_ => 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);
}
}
for (true_bcb, false_bcb, condition_id) in
coverage_spans.all_bcb_mappings().filter_map(|mapping| match mapping.kind {
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
Some((true_bcb, false_bcb, condition_info.condition_id))
}
_ => None,
})
{
let true_bb = basic_coverage_blocks[true_bcb].leader_bb();
inject_statement(
mir_body,
CoverageKind::CondBitmapUpdate { id: condition_id, value: true },
true_bb,
);
let false_bb = basic_coverage_blocks[false_bcb].leader_bb();
inject_statement(
mir_body,
CoverageKind::CondBitmapUpdate { id: condition_id, value: false },
false_bb,
);
}
}
/// Given two basic blocks that have a control-flow edge between them, creates
/// and returns a new block that sits between those blocks.
fn inject_edge_counter_basic_block(