1
+ use crate :: builder:: Builder ;
1
2
use crate :: common:: CodegenCx ;
2
3
use log:: debug;
3
- use rustc_codegen_ssa:: traits:: CoverageInfoMethods ;
4
- use rustc_hir:: def_id:: LOCAL_CRATE ;
4
+ use rustc_codegen_ssa:: coverageinfo:: map:: * ;
5
+ use rustc_codegen_ssa:: traits:: { CoverageInfoBuilderMethods , CoverageInfoMethods } ;
6
+ use rustc_data_structures:: fx:: FxHashMap ;
7
+ use rustc_middle:: ty:: Instance ;
5
8
6
- // FIXME(richkadel): This might not be where I put the coverage map generation, but it's a
7
- // placeholder for now.
8
- //
9
- // I need to inject the coverage map into the LLVM IR. This is one possible place to do it.
10
- //
11
- // The code below is here, at least temporarily, to verify that the `CoverageRegion`s are
12
- // available, to produce the coverage map.
9
+ use std:: cell:: RefCell ;
10
+
11
+ /// A context object for maintaining all state needed by the coverageinfo module.
12
+ pub struct CrateCoverageContext < ' tcx > {
13
+ // Coverage region data for each instrumented function identified by DefId.
14
+ pub ( crate ) coverage_regions : RefCell < FxHashMap < Instance < ' tcx > , FunctionCoverageRegions > > ,
15
+ }
16
+
17
+ impl < ' tcx > CrateCoverageContext < ' tcx > {
18
+ pub fn new ( ) -> Self {
19
+ Self { coverage_regions : Default :: default ( ) }
20
+ }
21
+ }
13
22
14
23
/// Generates and exports the Coverage Map.
24
+ // FIXME(richkadel): Actually generate and export the coverage map to LLVM.
25
+ // The current implementation is actually just debug messages to show the data is available.
15
26
pub fn finalize ( cx : & CodegenCx < ' _ , ' _ > ) {
16
- let instances = & * cx. instances . borrow ( ) ;
17
- for instance in instances. keys ( ) {
18
- if instance. def_id ( ) . krate == LOCAL_CRATE {
19
- // FIXME(richkadel): Is this check `krate == LOCAL_CRATE` right?
20
- //
21
- // NOTE: I'm considering at least one alternative to this loop on `instances`,
22
- // But if I do go with this, make sure the check on LOCAL_CRATE works for all cases.
23
- //
24
- //
25
- // Without it, I was crashing on some of the instances, with:
26
- //
27
- // src/librustc_metadata/rmeta/decoder.rs:1127:17: get_optimized_mir: missing MIR for `DefId(1:2867 ~ std[70cc]::io[0]::stdio[0]::_print[0])`
28
- //
29
- // This check avoids it, but still works for the very limited testing I've done so far.
30
- let coverageinfo = cx. tcx . coverageinfo ( instance. def_id ( ) ) ;
31
- if coverageinfo. num_counters > 0 {
32
- debug ! (
33
- "Generate coverage map for: {}, hash: {:?}, num_counters: {}\n {}" ,
34
- instance,
35
- coverageinfo. hash,
36
- coverageinfo. num_counters,
37
- {
38
- let regions = & coverageinfo. coverage_regions;
39
- ( 0 ..regions. len( ) as u32 )
40
- . map( |counter_index| {
41
- let region = & regions[ counter_index] ;
42
- format!(
43
- " counter_index {} byte range: {}..{}" ,
44
- counter_index, region. start_byte_pos, region. end_byte_pos
45
- )
46
- } )
47
- . collect:: <Vec <String >>( )
48
- . join( "\n " )
49
- }
50
- ) ;
27
+ let coverage_regions = & * cx. coverage_context ( ) . coverage_regions . borrow ( ) ;
28
+ for instance in coverage_regions. keys ( ) {
29
+ let coverageinfo = cx. tcx . coverageinfo ( instance. def_id ( ) ) ;
30
+ debug_assert ! ( coverageinfo. num_counters > 0 ) ;
31
+ debug ! (
32
+ "Generate coverage map for: {:?}, hash: {}, num_counters: {}" ,
33
+ instance, coverageinfo. hash, coverageinfo. num_counters
34
+ ) ;
35
+ let function_coverage_regions = & coverage_regions[ instance] ;
36
+ for ( index, region) in function_coverage_regions. indexed_regions ( ) {
37
+ match region. kind {
38
+ CoverageKind :: Counter => debug ! (
39
+ " Counter {}, for {}..{}" ,
40
+ index, region. coverage_span. start_byte_pos, region. coverage_span. end_byte_pos
41
+ ) ,
42
+ CoverageKind :: CounterExpression ( lhs, op, rhs) => debug ! (
43
+ " CounterExpression {} = {} {:?} {}, for {}..{}" ,
44
+ index,
45
+ lhs,
46
+ op,
47
+ rhs,
48
+ region. coverage_span. start_byte_pos,
49
+ region. coverage_span. end_byte_pos
50
+ ) ,
51
51
}
52
52
}
53
+ for unreachable in function_coverage_regions. unreachable_regions ( ) {
54
+ debug ! (
55
+ " Unreachable code region: {}..{}" ,
56
+ unreachable. start_byte_pos, unreachable. end_byte_pos
57
+ ) ;
58
+ }
53
59
}
54
60
}
55
61
@@ -58,3 +64,49 @@ impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> {
58
64
finalize ( self )
59
65
}
60
66
}
67
+
68
+ impl CoverageInfoBuilderMethods < ' tcx > for Builder < ' a , ' ll , ' tcx > {
69
+ fn new_counter_region (
70
+ & mut self ,
71
+ instance : Instance < ' tcx > ,
72
+ index : u32 ,
73
+ start_byte_pos : u32 ,
74
+ end_byte_pos : u32 ,
75
+ ) {
76
+ let mut coverage_regions = self . coverage_context ( ) . coverage_regions . borrow_mut ( ) ;
77
+ coverage_regions
78
+ . entry ( instance)
79
+ . or_insert_with ( || FunctionCoverageRegions :: new ( ) )
80
+ . new_counter ( index, start_byte_pos, end_byte_pos) ;
81
+ }
82
+
83
+ fn new_counter_expression_region (
84
+ & mut self ,
85
+ instance : Instance < ' tcx > ,
86
+ index : u32 ,
87
+ lhs : u32 ,
88
+ op : CounterOp ,
89
+ rhs : u32 ,
90
+ start_byte_pos : u32 ,
91
+ end_byte_pos : u32 ,
92
+ ) {
93
+ let mut coverage_regions = self . coverage_context ( ) . coverage_regions . borrow_mut ( ) ;
94
+ coverage_regions
95
+ . entry ( instance)
96
+ . or_insert_with ( || FunctionCoverageRegions :: new ( ) )
97
+ . new_counter_expression ( index, lhs, op, rhs, start_byte_pos, end_byte_pos) ;
98
+ }
99
+
100
+ fn new_unreachable_region (
101
+ & mut self ,
102
+ instance : Instance < ' tcx > ,
103
+ start_byte_pos : u32 ,
104
+ end_byte_pos : u32 ,
105
+ ) {
106
+ let mut coverage_regions = self . coverage_context ( ) . coverage_regions . borrow_mut ( ) ;
107
+ coverage_regions
108
+ . entry ( instance)
109
+ . or_insert_with ( || FunctionCoverageRegions :: new ( ) )
110
+ . new_unreachable ( start_byte_pos, end_byte_pos) ;
111
+ }
112
+ }
0 commit comments