@@ -13,7 +13,7 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
13
13
use rustc_middle:: hir:: map:: Map ;
14
14
use rustc_middle:: hir:: nested_filter;
15
15
use rustc_middle:: mir:: coverage:: {
16
- CoverageKind , DecisionInfo , FunctionCoverageInfo , Mapping , MappingKind , SourceRegion ,
16
+ CoverageKind , DecisionInfo , FunctionCoverageInfo , Mapping , MappingKind , Op , SourceRegion ,
17
17
} ;
18
18
use rustc_middle:: mir:: {
19
19
self , BasicBlock , BasicBlockData , SourceInfo , Statement , StatementKind , Terminator ,
@@ -27,7 +27,7 @@ use tracing::{debug, debug_span, instrument, trace};
27
27
28
28
use crate :: coverage:: counters:: { CounterIncrementSite , CoverageCounters } ;
29
29
use crate :: coverage:: graph:: CoverageGraph ;
30
- use crate :: coverage:: mappings:: ExtractedMappings ;
30
+ use crate :: coverage:: mappings:: { BranchArm , ExtractedMappings } ;
31
31
32
32
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
33
33
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
@@ -95,10 +95,10 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
95
95
}
96
96
97
97
let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings. contains ( bcb) ;
98
- let coverage_counters =
98
+ let mut coverage_counters =
99
99
CoverageCounters :: make_bcb_counters ( & basic_coverage_blocks, bcb_has_counter_mappings) ;
100
100
101
- let mappings = create_mappings ( tcx, & hir_info, & extracted_mappings, & coverage_counters) ;
101
+ let mappings = create_mappings ( tcx, & hir_info, & extracted_mappings, & mut coverage_counters) ;
102
102
if mappings. is_empty ( ) {
103
103
// No spans could be converted into valid mappings, so skip this function.
104
104
debug ! ( "no spans could be converted into valid mappings; skipping" ) ;
@@ -140,7 +140,7 @@ fn create_mappings<'tcx>(
140
140
tcx : TyCtxt < ' tcx > ,
141
141
hir_info : & ExtractedHirInfo ,
142
142
extracted_mappings : & ExtractedMappings ,
143
- coverage_counters : & CoverageCounters ,
143
+ coverage_counters : & mut CoverageCounters ,
144
144
) -> Vec < Mapping > {
145
145
let source_map = tcx. sess . source_map ( ) ;
146
146
let body_span = hir_info. body_span ;
@@ -153,25 +153,67 @@ fn create_mappings<'tcx>(
153
153
& source_file. name . for_scope ( tcx. sess , RemapPathScopeComponents :: MACRO ) . to_string_lossy ( ) ,
154
154
) ;
155
155
156
- let term_for_bcb = |bcb| {
157
- coverage_counters
158
- . bcb_counter ( bcb)
159
- . expect ( "all BCBs with spans were given counters" )
160
- . as_term ( )
161
- } ;
162
156
let region_for_span = |span : Span | make_source_region ( source_map, file_name, span, body_span) ;
163
157
164
158
// Fully destructure the mappings struct to make sure we don't miss any kinds.
165
159
let ExtractedMappings {
166
160
num_bcbs : _,
167
161
code_mappings,
168
- branch_pairs ,
162
+ branch_arm_lists ,
169
163
mcdc_bitmap_bytes : _,
170
164
mcdc_branches,
171
165
mcdc_decisions,
172
166
} = extracted_mappings;
173
167
let mut mappings = Vec :: new ( ) ;
174
168
169
+ // Process branch arms first, because they might need to mutate `coverage_counters`
170
+ // to create new expressions.
171
+ for arm_list in branch_arm_lists {
172
+ let mut arms_rev = arm_list. iter ( ) . rev ( ) ;
173
+
174
+ let mut rest_counter = {
175
+ // The last arm's span is ignored, because its BCB is only used as the
176
+ // false branch of the second-last arm; it's not a branch of its own.
177
+ let Some ( & BranchArm { span : _, pre_guard_bcb, arm_taken_bcb } ) = arms_rev. next ( ) else {
178
+ continue ;
179
+ } ;
180
+ debug_assert_eq ! ( pre_guard_bcb, arm_taken_bcb, "last arm should not have a guard" ) ;
181
+ coverage_counters. bcb_counter ( pre_guard_bcb) . expect ( "all relevant BCBs have counters" )
182
+ } ;
183
+
184
+ // All relevant BCBs should have counters, so we can `.unwrap()` them.
185
+ for & BranchArm { span, pre_guard_bcb, arm_taken_bcb } in arms_rev {
186
+ // Number of times the pattern matched.
187
+ let matched_counter = coverage_counters. bcb_counter ( pre_guard_bcb) . unwrap ( ) ;
188
+ // Number of times the pattern matched and the guard succeeded.
189
+ let arm_taken_counter = coverage_counters. bcb_counter ( arm_taken_bcb) . unwrap ( ) ;
190
+ // Total number of times execution logically reached this pattern.
191
+ let reached_counter =
192
+ coverage_counters. make_expression ( rest_counter, Op :: Add , arm_taken_counter) ;
193
+ // Number of times execution reached this pattern, but didn't match it.
194
+ let unmatched_counter =
195
+ coverage_counters. make_expression ( reached_counter, Op :: Subtract , matched_counter) ;
196
+
197
+ let kind = MappingKind :: Branch {
198
+ true_term : matched_counter. as_term ( ) ,
199
+ false_term : unmatched_counter. as_term ( ) ,
200
+ } ;
201
+
202
+ if let Some ( source_region) = region_for_span ( span) {
203
+ mappings. push ( Mapping { kind, source_region } ) ;
204
+ }
205
+
206
+ rest_counter = reached_counter;
207
+ }
208
+ }
209
+
210
+ let term_for_bcb = |bcb| {
211
+ coverage_counters
212
+ . bcb_counter ( bcb)
213
+ . expect ( "all BCBs with spans were given counters" )
214
+ . as_term ( )
215
+ } ;
216
+
175
217
mappings. extend ( code_mappings. iter ( ) . filter_map (
176
218
// Ordinary code mappings are the simplest kind.
177
219
|& mappings:: CodeMapping { span, bcb } | {
@@ -181,16 +223,6 @@ fn create_mappings<'tcx>(
181
223
} ,
182
224
) ) ;
183
225
184
- mappings. extend ( branch_pairs. iter ( ) . filter_map (
185
- |& mappings:: BranchPair { span, true_bcb, false_bcb } | {
186
- let true_term = term_for_bcb ( true_bcb) ;
187
- let false_term = term_for_bcb ( false_bcb) ;
188
- let kind = MappingKind :: Branch { true_term, false_term } ;
189
- let source_region = region_for_span ( span) ?;
190
- Some ( Mapping { kind, source_region } )
191
- } ,
192
- ) ) ;
193
-
194
226
mappings. extend ( mcdc_branches. iter ( ) . filter_map (
195
227
|& mappings:: MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth : _ } | {
196
228
let source_region = region_for_span ( span) ?;
0 commit comments