@@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::{
13
13
use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
14
14
use rustc_llvm:: RustString ;
15
15
use rustc_middle:: bug;
16
- use rustc_middle:: mir:: coverage:: CoverageKind ;
16
+ use rustc_middle:: mir:: coverage:: { CoverageKind , FunctionCoverageInfo } ;
17
17
use rustc_middle:: ty:: layout:: HasTyCtxt ;
18
18
use rustc_middle:: ty:: Instance ;
19
19
use rustc_target:: abi:: Align ;
@@ -30,13 +30,15 @@ pub struct CrateCoverageContext<'ll, 'tcx> {
30
30
pub ( crate ) function_coverage_map :
31
31
RefCell < FxIndexMap < Instance < ' tcx > , FunctionCoverageCollector < ' tcx > > > ,
32
32
pub ( crate ) pgo_func_name_var_map : RefCell < FxHashMap < Instance < ' tcx > , & ' ll llvm:: Value > > ,
33
+ pub ( crate ) mcdc_condition_bitmap_map : RefCell < FxHashMap < Instance < ' tcx > , & ' ll llvm:: Value > > ,
33
34
}
34
35
35
36
impl < ' ll , ' tcx > CrateCoverageContext < ' ll , ' tcx > {
36
37
pub fn new ( ) -> Self {
37
38
Self {
38
39
function_coverage_map : Default :: default ( ) ,
39
40
pgo_func_name_var_map : Default :: default ( ) ,
41
+ mcdc_condition_bitmap_map : Default :: default ( ) ,
40
42
}
41
43
}
42
44
@@ -45,6 +47,12 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
45
47
) -> FxIndexMap < Instance < ' tcx > , FunctionCoverageCollector < ' tcx > > {
46
48
self . function_coverage_map . replace ( FxIndexMap :: default ( ) )
47
49
}
50
+
51
+ /// LLVM use a temp value to record evaluated mcdc test vector of each decision, which is called condition bitmap.
52
+ /// This value is named `mcdc.addr` (same as clang) and is a 32-bit integer.
53
+ fn try_get_mcdc_condition_bitmap ( & self , instance : & Instance < ' tcx > ) -> Option < & ' ll llvm:: Value > {
54
+ self . mcdc_condition_bitmap_map . borrow ( ) . get ( instance) . copied ( )
55
+ }
48
56
}
49
57
50
58
// These methods used to be part of trait `CoverageInfoMethods`, which no longer
@@ -90,6 +98,10 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
90
98
return ;
91
99
} ;
92
100
101
+ if function_coverage_info. mcdc_bitmap_bytes > 0 {
102
+ ensure_mcdc_parameters ( bx, instance, function_coverage_info) ;
103
+ }
104
+
93
105
let Some ( coverage_context) = bx. coverage_context ( ) else { return } ;
94
106
let mut coverage_map = coverage_context. function_coverage_map . borrow_mut ( ) ;
95
107
let func_coverage = coverage_map
@@ -131,10 +143,66 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
131
143
CoverageKind :: ExpressionUsed { id } => {
132
144
func_coverage. mark_expression_id_seen ( id) ;
133
145
}
146
+ CoverageKind :: CondBitmapUpdate { id, value, .. } => {
147
+ drop ( coverage_map) ;
148
+ assert_ne ! (
149
+ id. as_u32( ) ,
150
+ 0 ,
151
+ "ConditionId of evaluated conditions should never be zero"
152
+ ) ;
153
+ let cond_bitmap = coverage_context
154
+ . try_get_mcdc_condition_bitmap ( & instance)
155
+ . expect ( "mcdc cond bitmap should have been allocated for updating" ) ;
156
+ let cond_loc = bx. const_i32 ( id. as_u32 ( ) as i32 - 1 ) ;
157
+ let bool_value = bx. const_bool ( value) ;
158
+ let fn_name = bx. get_pgo_func_name_var ( instance) ;
159
+ let hash = bx. const_u64 ( function_coverage_info. function_source_hash ) ;
160
+ bx. mcdc_condbitmap_update ( fn_name, hash, cond_loc, cond_bitmap, bool_value) ;
161
+ }
162
+ CoverageKind :: TestVectorBitmapUpdate { bitmap_idx } => {
163
+ drop ( coverage_map) ;
164
+ let cond_bitmap = coverage_context
165
+ . try_get_mcdc_condition_bitmap ( & instance)
166
+ . expect ( "mcdc cond bitmap should have been allocated for merging into the global bitmap" ) ;
167
+ let bitmap_bytes = bx. tcx ( ) . coverage_ids_info ( instance. def ) . mcdc_bitmap_bytes ;
168
+ assert ! ( bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range" ) ;
169
+ assert ! (
170
+ bitmap_bytes <= function_coverage_info. mcdc_bitmap_bytes,
171
+ "bitmap length disagreement: query says {bitmap_bytes} but function info only has {}" ,
172
+ function_coverage_info. mcdc_bitmap_bytes
173
+ ) ;
174
+
175
+ let fn_name = bx. get_pgo_func_name_var ( instance) ;
176
+ let hash = bx. const_u64 ( function_coverage_info. function_source_hash ) ;
177
+ let bitmap_bytes = bx. const_u32 ( bitmap_bytes) ;
178
+ let bitmap_index = bx. const_u32 ( bitmap_idx) ;
179
+ bx. mcdc_tvbitmap_update ( fn_name, hash, bitmap_bytes, bitmap_index, cond_bitmap) ;
180
+ }
134
181
}
135
182
}
136
183
}
137
184
185
+ fn ensure_mcdc_parameters < ' ll , ' tcx > (
186
+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
187
+ instance : Instance < ' tcx > ,
188
+ function_coverage_info : & FunctionCoverageInfo ,
189
+ ) {
190
+ let Some ( cx) = bx. coverage_context ( ) else { return } ;
191
+ if cx. mcdc_condition_bitmap_map . borrow ( ) . contains_key ( & instance) {
192
+ return ;
193
+ }
194
+
195
+ let fn_name = bx. get_pgo_func_name_var ( instance) ;
196
+ let hash = bx. const_u64 ( function_coverage_info. function_source_hash ) ;
197
+ let bitmap_bytes = bx. const_u32 ( function_coverage_info. mcdc_bitmap_bytes ) ;
198
+ let cond_bitmap = bx. mcdc_parameters ( fn_name, hash, bitmap_bytes) ;
199
+ bx. coverage_context ( )
200
+ . expect ( "already checked above" )
201
+ . mcdc_condition_bitmap_map
202
+ . borrow_mut ( )
203
+ . insert ( instance, cond_bitmap) ;
204
+ }
205
+
138
206
/// Calls llvm::createPGOFuncNameVar() with the given function instance's
139
207
/// mangled function name. The LLVM API returns an llvm::GlobalVariable
140
208
/// containing the function name, with the specific variable name and linkage
0 commit comments