diff options
| author | zhuyunxing <zhuyunxing.zyx@alibaba-inc.com> | 2024-07-25 15:23:35 +0800 |
|---|---|---|
| committer | zhuyunxing <zhuyunxing.zyx@alibaba-inc.com> | 2024-10-08 11:15:24 +0800 |
| commit | 6e3e19f714d0ff938c24901195f2c1be6e6e7f6f (patch) | |
| tree | 97145e813de4926b8c55742776a1616dbad2038c /compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs | |
| parent | 99bd601df5f65331b4751217eb533abeca7914cb (diff) | |
| download | rust-6e3e19f714d0ff938c24901195f2c1be6e6e7f6f.tar.gz rust-6e3e19f714d0ff938c24901195f2c1be6e6e7f6f.zip | |
coverage. Adapt to mcdc mapping formats introduced by llvm 19
Diffstat (limited to 'compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs')
| -rw-r--r-- | compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs | 88 |
1 files changed, 51 insertions, 37 deletions
diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 5c45a7a33a2..343d4000043 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -12,16 +12,16 @@ use rustc_span::Span; use crate::build::Builder; use crate::errors::MCDCExceedsConditionLimit; -/// The MCDC bitmap scales exponentially (2^n) based on the number of conditions seen, -/// So llvm sets a maximum value prevents the bitmap footprint from growing too large without the user's knowledge. -/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged. -const MAX_CONDITIONS_IN_DECISION: usize = 6; +/// LLVM uses `i16` to represent condition id. Hence `i16::MAX` is the hard limit for number of +/// conditions in a decision. +const MAX_CONDITIONS_IN_DECISION: usize = i16::MAX as usize; #[derive(Default)] struct MCDCDecisionCtx { /// To construct condition evaluation tree. decision_stack: VecDeque<ConditionInfo>, processing_decision: Option<MCDCDecisionSpan>, + conditions: Vec<MCDCBranchSpan>, } struct MCDCState { @@ -155,16 +155,29 @@ impl MCDCState { decision_ctx.decision_stack.push_back(lhs); } - fn take_condition( + fn try_finish_decision( &mut self, + span: Span, true_marker: BlockMarkerId, false_marker: BlockMarkerId, - ) -> (Option<ConditionInfo>, Option<MCDCDecisionSpan>) { + degraded_branches: &mut Vec<MCDCBranchSpan>, + ) -> Option<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)> { let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else { bug!("Unexpected empty decision_ctx_stack") }; let Some(condition_info) = decision_ctx.decision_stack.pop_back() else { - return (None, None); + let branch = MCDCBranchSpan { + span, + condition_info: ConditionInfo { + condition_id: ConditionId::START, + true_next_id: None, + false_next_id: None, + }, + true_marker, + false_marker, + }; + degraded_branches.push(branch); + return None; }; let Some(decision) = decision_ctx.processing_decision.as_mut() else { bug!("Processing decision should have been created before any conditions are taken"); @@ -175,24 +188,31 @@ impl MCDCState { if condition_info.false_next_id.is_none() { decision.end_markers.push(false_marker); } + decision_ctx.conditions.push(MCDCBranchSpan { + span, + condition_info, + true_marker, + false_marker, + }); if decision_ctx.decision_stack.is_empty() { - (Some(condition_info), decision_ctx.processing_decision.take()) + let conditions = std::mem::take(&mut decision_ctx.conditions); + decision_ctx.processing_decision.take().map(|decision| (decision, conditions)) } else { - (Some(condition_info), None) + None } } } pub(crate) struct MCDCInfoBuilder { - branch_spans: Vec<MCDCBranchSpan>, - decision_spans: Vec<MCDCDecisionSpan>, + degraded_spans: Vec<MCDCBranchSpan>, + mcdc_spans: Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, state: MCDCState, } impl MCDCInfoBuilder { pub(crate) fn new() -> Self { - Self { branch_spans: vec![], decision_spans: vec![], state: MCDCState::new() } + Self { degraded_spans: vec![], mcdc_spans: vec![], state: MCDCState::new() } } pub(crate) fn visit_evaluated_condition( @@ -206,50 +226,44 @@ impl MCDCInfoBuilder { let true_marker = inject_block_marker(source_info, true_block); let false_marker = inject_block_marker(source_info, false_block); - let decision_depth = self.state.decision_depth(); - let (mut condition_info, decision_result) = - self.state.take_condition(true_marker, false_marker); // take_condition() returns Some for decision_result when the decision stack // is empty, i.e. when all the conditions of the decision were instrumented, // and the decision is "complete". - if let Some(decision) = decision_result { - match decision.num_conditions { + if let Some((decision, conditions)) = self.state.try_finish_decision( + source_info.span, + true_marker, + false_marker, + &mut self.degraded_spans, + ) { + let num_conditions = conditions.len(); + assert_eq!( + num_conditions, decision.num_conditions, + "final number of conditions is not correct" + ); + match num_conditions { 0 => { unreachable!("Decision with no condition is not expected"); } 1..=MAX_CONDITIONS_IN_DECISION => { - self.decision_spans.push(decision); + self.mcdc_spans.push((decision, conditions)); } _ => { - // Do not generate mcdc mappings and statements for decisions with too many conditions. - // Therefore, first erase the condition info of the (N-1) previous branch spans. - let rebase_idx = self.branch_spans.len() - (decision.num_conditions - 1); - for branch in &mut self.branch_spans[rebase_idx..] { - branch.condition_info = None; - } - - // Then, erase this last branch span's info too, for a total of N. - condition_info = None; + self.degraded_spans.extend(conditions); tcx.dcx().emit_warn(MCDCExceedsConditionLimit { span: decision.span, - num_conditions: decision.num_conditions, + num_conditions, max_conditions: MAX_CONDITIONS_IN_DECISION, }); } } } - self.branch_spans.push(MCDCBranchSpan { - span: source_info.span, - condition_info, - true_marker, - false_marker, - decision_depth, - }); } - pub(crate) fn into_done(self) -> (Vec<MCDCDecisionSpan>, Vec<MCDCBranchSpan>) { - (self.decision_spans, self.branch_spans) + pub(crate) fn into_done( + self, + ) -> (Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, Vec<MCDCBranchSpan>) { + (self.mcdc_spans, self.degraded_spans) } } |
