@@ -11,7 +11,9 @@ use rustc_codegen_ssa::traits::{
11
11
BaseTypeCodegenMethods , ConstCodegenMethods , StaticCodegenMethods ,
12
12
} ;
13
13
use rustc_middle:: bug;
14
- use rustc_middle:: mir:: coverage:: MappingKind ;
14
+ use rustc_middle:: mir:: coverage:: {
15
+ CoverageIdsInfo , Expression , FunctionCoverageInfo , MappingKind , Op ,
16
+ } ;
15
17
use rustc_middle:: ty:: { Instance , TyCtxt } ;
16
18
use rustc_target:: spec:: HasTargetSpec ;
17
19
use tracing:: debug;
@@ -49,12 +51,17 @@ pub(crate) fn prepare_covfun_record<'tcx>(
49
51
instance : Instance < ' tcx > ,
50
52
function_coverage : & FunctionCoverage < ' tcx > ,
51
53
) -> Option < CovfunRecord < ' tcx > > {
54
+ let fn_cov_info = tcx. instance_mir ( instance. def ) . function_coverage_info . as_deref ( ) ?;
55
+ let ids_info = tcx. coverage_ids_info ( instance. def ) ;
56
+
57
+ let expressions = prepare_expressions ( fn_cov_info, ids_info, function_coverage. is_used ( ) ) ;
58
+
52
59
let mut covfun = CovfunRecord {
53
60
mangled_function_name : tcx. symbol_name ( instance) . name ,
54
61
source_hash : function_coverage. source_hash ( ) ,
55
62
is_used : function_coverage. is_used ( ) ,
56
63
virtual_file_mapping : VirtualFileMapping :: default ( ) ,
57
- expressions : function_coverage . counter_expressions ( ) . collect :: < Vec < _ > > ( ) ,
64
+ expressions,
58
65
regions : ffi:: Regions :: default ( ) ,
59
66
} ;
60
67
@@ -72,6 +79,40 @@ pub(crate) fn prepare_covfun_record<'tcx>(
72
79
Some ( covfun)
73
80
}
74
81
82
+ /// Convert the function's coverage-counter expressions into a form suitable for FFI.
83
+ fn prepare_expressions (
84
+ fn_cov_info : & FunctionCoverageInfo ,
85
+ ids_info : & CoverageIdsInfo ,
86
+ is_used : bool ,
87
+ ) -> Vec < ffi:: CounterExpression > {
88
+ // If any counters or expressions were removed by MIR opts, replace their
89
+ // terms with zero.
90
+ let counter_for_term = |term| {
91
+ if !is_used || ids_info. is_zero_term ( term) {
92
+ ffi:: Counter :: ZERO
93
+ } else {
94
+ ffi:: Counter :: from_term ( term)
95
+ }
96
+ } ;
97
+
98
+ // We know that LLVM will optimize out any unused expressions before
99
+ // producing the final coverage map, so there's no need to do the same
100
+ // thing on the Rust side unless we're confident we can do much better.
101
+ // (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
102
+ fn_cov_info
103
+ . expressions
104
+ . iter ( )
105
+ . map ( move |& Expression { lhs, op, rhs } | ffi:: CounterExpression {
106
+ lhs : counter_for_term ( lhs) ,
107
+ kind : match op {
108
+ Op :: Add => ffi:: ExprKind :: Add ,
109
+ Op :: Subtract => ffi:: ExprKind :: Subtract ,
110
+ } ,
111
+ rhs : counter_for_term ( rhs) ,
112
+ } )
113
+ . collect :: < Vec < _ > > ( )
114
+ }
115
+
75
116
/// Populates the mapping region tables in the current function's covfun record.
76
117
fn fill_region_tables < ' tcx > (
77
118
tcx : TyCtxt < ' tcx > ,
0 commit comments