@@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::{
1313use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
1414use rustc_llvm:: RustString ;
1515use rustc_middle:: bug;
16- use rustc_middle:: mir:: coverage:: CoverageKind ;
16+ use rustc_middle:: mir:: coverage:: { CoverageKind , FunctionCoverageInfo } ;
1717use rustc_middle:: ty:: layout:: HasTyCtxt ;
1818use rustc_middle:: ty:: Instance ;
1919use rustc_target:: abi:: Align ;
@@ -30,13 +30,15 @@ pub struct CrateCoverageContext<'ll, 'tcx> {
3030 pub ( crate ) function_coverage_map :
3131 RefCell < FxIndexMap < Instance < ' tcx > , FunctionCoverageCollector < ' tcx > > > ,
3232 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 > > ,
3334}
3435
3536impl < ' ll , ' tcx > CrateCoverageContext < ' ll , ' tcx > {
3637 pub fn new ( ) -> Self {
3738 Self {
3839 function_coverage_map : Default :: default ( ) ,
3940 pgo_func_name_var_map : Default :: default ( ) ,
41+ mcdc_condition_bitmap_map : Default :: default ( ) ,
4042 }
4143 }
4244
@@ -45,6 +47,12 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
4547 ) -> FxIndexMap < Instance < ' tcx > , FunctionCoverageCollector < ' tcx > > {
4648 self . function_coverage_map . replace ( FxIndexMap :: default ( ) )
4749 }
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+ }
4856}
4957
5058// These methods used to be part of trait `CoverageInfoMethods`, which no longer
@@ -90,6 +98,10 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
9098 return ;
9199 } ;
92100
101+ if function_coverage_info. mcdc_bitmap_bytes > 0 {
102+ ensure_mcdc_parameters ( bx, instance, function_coverage_info) ;
103+ }
104+
93105 let Some ( coverage_context) = bx. coverage_context ( ) else { return } ;
94106 let mut coverage_map = coverage_context. function_coverage_map . borrow_mut ( ) ;
95107 let func_coverage = coverage_map
@@ -131,10 +143,66 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
131143 CoverageKind :: ExpressionUsed { id } => {
132144 func_coverage. mark_expression_id_seen ( id) ;
133145 }
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+ }
134181 }
135182 }
136183}
137184
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+
138206/// Calls llvm::createPGOFuncNameVar() with the given function instance's
139207/// mangled function name. The LLVM API returns an llvm::GlobalVariable
140208/// containing the function name, with the specific variable name and linkage
0 commit comments